This error has a bit of a story to give further context: I made this bit of code because if I create a SQLAlchemy Relationship with a lambda function inside, it will only initialize the Relationship after all the models have been created. What it does is basically fill all models in a dictionary (self._all_models) and the lambda function will then later get the model by accessing (self._all_models[table_name]['model']). So when I do a session.add(Model), this lambda function will be called and try to get the model from the dictionary.
I executed it just fine, but my colleagues had a weird problem: The self instance was "old", and what I mean by that is that the dictionary self._all_models had only the models that were created so far, and not all the models. For example, if it had to create 3 models (a,b,c), when the lambda inside b's Relationship were to be called, the self._all_models would only have {'a': ...} instead of having all 3 ({'a': ..., 'b': ..., 'c': ...}).
The only difference between me and my colleagues is that I run Python 3.9, and they run Python 3.8. And when one of my colleagues – "Jack" – upgraded his Python to 3.9, it ran smoothly (even after changing back to his 3.8 venv); but my other colleague – "Mark" – didn't have as much luck: it still didn't work for him even after upgrading.
Comparing their libs with pip freeze didn't reveal anything different, and it's very unlikely that the problem lies in SQLAlchemy.
Code:
class ORM:
    def __init__(self, source_name: str, ..., address_http_protocol: str):
        self._all_models = defaultdict(lambda: {})
        ...
        self._create_all_models()
        ...
    def _create_all_models(self) -> None:
        base = declarative_base()
        base.metadata.reflect(self._get_engine())
        all_tables = base.metadata.tables
        for table in all_tables.values():
            current_table_name = table.name
            relationships = self._get_parents(table)
            obj = type(current_table_name, (object,), dict())
            mapper(obj, table,
                   properties={table_name: relationship(lambda table_name=table_name:
                                                        self._get_model_by_table_name(table_name), lazy='select')
                               for table_name in relationships})
            self._all_models[current_table_name]['model'] = obj
            self._all_models[current_table_name]['table'] = table
    @staticmethod
    def _get_parents(table: Table) -> set:
        parents = set()
        if table.foreign_keys:
            for fk in table.foreign_keys:
                parent_name = fk.column.table.name
                parents.add(parent_name) if parent_name != table.name else None
        return parents
    def _get_model_by_table_name(self, table_name: str) -> type:
        if isinstance(table_name, str):
            return self._all_models[table_name]['model']
I'm talking about the lambda function inside _create_all_models: lambda table_name=table_name: self._get_model_by_table_name(table_name).
