4

Is it possible to create a "stupid" dummy object in Python that will always no-op and never throw an error, no matter how is called or otherwise manipulated?

The use case for this is when there's an object that is used to create side effects in the normal case, but if run in a different environment (suppose, during development) should not do anything and fail silently.

try:
    o = Obj()
except ImportError:
    # we're in development mode
    o = DummyObj()

o.doStuff()  # should work or fail silently
0

2 Answers 2

9

Try using Mock objects. Any call made on a Mock object will return another Mock object.

For example:

>>> from mock import Mock
>>> test = Mock()
>>> test.doStuff()
<Mock name='mock.doStuff()' id='4373729360'>
>>> test2 = test.doStuff
>>> test2
<Mock name='mock.doStuff' id='4373693712'>
>>> test2()
<Mock name='mock.doStuff()' id='4373729360'>

As shown here, it is consistent - calling doStuff() multiple times returns the same Mock, and if you call the Mock created by mock.doStuff it will return the same Mock as doStuff().

Mock objects are commonly used in unit tests, so there is a lot more that you can do with them than what I've shown here. Read more here if you are interested.

Sign up to request clarification or add additional context in comments.

4 Comments

Yep, this is what I was looking for :) I thought there's a simpler way to get this done without using mock, but this method takes care of every single scenario. Thanks!
Please do not use Mock in production!
@holdenweb Can you expand why?
Well, this answer lists a number of reasons. Mostly I suggested avoiding them in production because their behaviour is counter-intuitive. If you feel you have a use that other techniques (stubbing, etc.) then feel free to ignore the advice - but document it well!
0

I know I'm a few years late to the party... but regarding "is there's a simpler way to get this done without using mock" and as i hat the same problem recently: This object will be quite resistant to a lot of things, is is small and doesn't use dependencies. It is a kind of "null object design pattern"

class Dummy():
    '''
    Dummy that can be called and is also a context manager.
    It will always return itself, so that you can chain calls.
    '''
    # Accessing attributes
    def __getattr__(self, name):
        return self
    # Callable
    def __call__(self, *args, **kwargs):
        return self
    # Context manager
    def __enter__(self):
        return self
    def __exit__(self, *args, **kwargs):
        pass
    # Indexing, Subscripting, Slicing
    def __getitem__(self, *args, **kwargs):
        return self
    def __setitem__(self, key, value):
        self
    # String representation
    def __str__(self) -> str:
        return '<Just a Dummy>'

It can then be used for example:

logger = Dummy()
logger.info('Black hole for logging', stacklevel=1)

open = Dummy()
with open("file.txt", "r") as f: # fake context manager
    print(f.read()) # <Just a Dummy>

mlflow = Dummy()
with mlflow.start_run(): # chaining works also
    mlflow.log_param("param1", 5)
    mlflow.a.b().c.d() # multiple chaining

# indexing and subscripting
df = Dummy()
df['col']
df[7]
df.iloc[2:42, ['col1', 'col2']]

Of course, it does not return meaningful values, this would need to be implemented for every attribute/function e.g.

    def get_count(self):
        return 0

All suggestions for improvement are welcome

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.