3

SQLAlchemy backrefs tend to cause circular imports as they get complex, so I came up with a way to "re-open" a Python class like in Ruby:

def reopen(cls):
    """
    Moves the contents of the decorated class into an existing class and returns that.

    Usage::

        from .other_module import ExistingClass

        @reopen(ExistingClass)
        class ExistingClass:
            @property
            def new_property(self):
                pass

    This is equivalent to::

        def new_property(self):
            pass

        ExistingClass.new_property = property(new_property)
    """

    def decorator(temp_cls):
        for attr, value in temp_cls.__dict__.items():
            # Skip the standard Python attributes, process the rest
            if attr not in ('__dict__', '__doc__', '__module__', '__weakref__'):
                setattr(cls, attr, value)
        return cls

    return decorator

This is a simplified version; the full implementation has more safety checks and tests.

This code works fairly well for inserting bi-directional SQLAlchemy relationships and helper methods wherever SQLAlchemy's existing relationship+backref mechanism doesn't suffice.

However:

  1. mypy raises error "name 'ExistingClass' already defined (possibly by an import)"
  2. pylint raises E0102 "class already defined"

I could ignore both errors by having an annotation on the line (# type: ignore and # skipcq), but overuse of those annotations can let bugs slip through. It'll be nice to tell mypy and pylint that this use is okay.

How can I do that?

Kiran Jonnalagadda
  • 2,476
  • 1
  • 28
  • 28
  • Does this answer your question? [How do I disable a Pylint warning?](https://stackoverflow.com/questions/4341746/how-do-i-disable-a-pylint-warning) – RMPR Oct 20 '20 at 11:50
  • I'd prefer to not do a blanket disable as it'll reduce the utility for catching actual bugs. Inline per-instance disabling is my current solution, but it feels like I'm training myself to simply ignore all errors and warnings. – Kiran Jonnalagadda Oct 20 '20 at 12:08
  • You can import classes that are only used for type annotations in a `if typing.TYPE_CHECKING:` block to prevent circular imports. – Wombatz Oct 20 '20 at 22:34
  • The circular import problem is from SQLAlchemy relationships, not type checking. – Kiran Jonnalagadda Oct 20 '20 at 22:41

0 Answers0