Best practices for placing common enumeration/constants in a python package?

Let’s say you are writing a python package. That package contains

You want to enumerate clearly all options for different arguments and want that to be statically type checked. One possibility for this is to use string enumerations


class UsageStatus(StrEnum):
    FAIL = auto()
    SUCCESS = auto()
    UNDEFINED = auto()

class FirstThingy(StrEnum):
   FOO = auto()
   BAR = auto()
   BAZ = auto()
   QUX = auto()

def somefunc(thingy: FirstThingy, status: UsageStatus):

Since FirstThingy has name which resembles “first”, it feels natural to put the enum definition to Your project grows and you have lot of different constants defined in lot of modules. All goes well until you get ImportErrors since imports Second from, which imports Third from which imports Fourth from which imports FirstThingy from The FirstThingy constant/enum definition is needed in also.

I’m tempted to create separate and just dump all the StrEnums there as this will eliminate all possibilities for import loops as will never need anything from anywhere. The second approach would be to put the violating import statements somewhere out from module-level, inside a def or class definition, but that feels a bit dirty. Third approach would be to put all “shared” (=needed in more than one file) constants in and keep the rest in their respective modules.

What is the best practice for handle this kind of situation and how do you tend to solve this kind of problems?

I have used a circular import where I had no other choice, but I do not recommend it.

I would go with the third solution:


I would advise to get to the bottom of what causes the circular imports, and break (get rid of) the mutual dependencies that cause them. The mutual dependency is almost always caused by flawed design.

  • If module A depends on B and B on A, and if that dependency is pervasive (occurs in lots of places) then the modules need to be merged into one
  • If A only depends on B inside a particular function, and only depends on particular other parts of B, you could also consider make the import inline (not at global level); that is not ideal but could work

A separate is a fairly common strategy. It would be fast to import (all it has is some little enums, no major work) and can be a dependency of everything else, but has no dependencies of its own. Yes, “First” is associated with, but “constants” applies to the entire package.

1 Like

from ... import ...
is the usual way to avoid circular dependencies (at the module level)
The is a solid approach because similar to the tradition, it is setting-up project/library globals.
Per @hansgeunsmeyer recommend stepping-back to take a look at the structure of the data, where it comes-from (unless global) and where it is actually needed (rather than import-ing everything in-case it is needed).

1 Like

Not to be a pain in the ass, but, why are we using Enums to hold constants that will most likely never use the Enum functionality? I’ve recently started using just normal classes for 95% of constants and it seems to save an awful lot .value, but maybe I’m missing something. I think were missing something like “class for constants” which its purpose would only be to add a namespace for constants and maybe make them pseudo-immutable and thats it, no more functionality. And yes, I know named tuple, just use a dict, but for everyone who uses VScode or PyCharm, it is way more comfortable to use classes.

If your constants are not actually related to each other (in particular, alternate legal options for a particular value elsewhere) then sure, go ahead and represent them in whatever way makes sense. However, I think the previous discussion was really more about the organization of the code into files.