Skip to content

Avoid monkey-patching an object from an external module. #79

Description

@danielballan

As @ronpandolfi just reminded me, this package monkey-patches an object in databroker

from databroker import catalog
catalog.controller = SearchingCatalogController(catalog)
catalog.view = QListView()
catalog.name = 'Bluesky Databroker'

This might violate the expectations of another part of the code that is also using that object. In general I think we should try to avoid monkey-patching objects that we import. One possible way to forward is to make plugins via composition instead of inheritance. Xi-cam plugins are expected to have a certain interface, and the names in this interface may sometimes collide with the names of the attributes of the objects they want to "wrap". Composition avoids this problem.

This touches on a larger issue in Xi-cam: the widespread use of singletons enforced at the metaclass (__new__) level. It came up in conversation (but hasn't been recorded to my knowledge) that this makes it difficult to write unit tests.

One alternative is to implement a pattern like this one, which I have seen recur in several libraries, where there is one special instance, but still the ability to make distinct instances in a testing context.

In [12]: from traitlets.config import SingletonConfigurable                                                                                                                                   

In [13]: class A(SingletonConfigurable): 
    ...:     ... 
    ...:                                                                                                                                                                                      

In [14]: A.instance() is A.instance()

In [15]: A() is A()                                                                                                                                                                           
Out[15]: False

I don't know the details of Xi-cam well enough to know whether this pattern is an exact fit, but a classmethod that returns a special instance might be a useful direction to explore.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions