Python one class produces two types

91 Views Asked by At

I have a src directory containing a helpers directory. Inside of the modules inside of the helpers directory, I use

import os
import sys
sys.path.append(os.path.dirname(__file__))

to make relative imports work.

I have a command dataclass in one of the helpers, but there seem to be two types depending from where it's called.

I have a function like this:

@dataclass
class Command:
    name: str
    description: str
    # ...

class CommandClass():
    commands: list[Command] = []
    def attach_command(self, command: Command) -> None:
        self.commands.append(command)

But somehow the type for a manually constructed Command inside of attach_command is not the same as the one of the command argument.

       # ...
       assert type(command) == type(Command("my_name", "my_description")) # false
       # type(command): <class 'command.Command'>
       # type(Command("my_name", "my_description")): <class 'helpers.command.Command'>

I was expecting both to at least be evaluated to be the same.

Minimal reproducible example

A minimal reproducible example can be found here. It's not small, but it shows my issue. It also made me realize, that I should have added more information above.

1

There are 1 best solutions below

0
On BEST ANSWER

It looks like a Path problem. As you change sys.path to allow relative imports, you managed to load 2 instances of the command module, one with a path (relative to the current sys.path at the time of loading) being helpers.command, the latter with a path being command.

That is the reason why relative imports are normally restricted inside packages, and why a package is a module having a __path__ attribute. The goal of that machinery is to make sure that a module should never have 2 distinct paths.

Workaround:

A simple workaround would be to always include a module from the same path. In your example, it is enough to change import command with from helpers import command in plugin.py:

import os
import sys

from helpers import command

plugins = []


class Plugin():
    ...

But IMHO the real solution would be to stop playing with sys.path and properly convert src to a neat and clean package.