Search code examples
pythonattrpython-attrs

How to set default for attr.s at initiation?


Using python attrs library and trying to set directory path in Settings object. This works great when environment variable are set from the shell itself. But when in case when TEST_TMPDIR is not set from shell and I try to set the value in python code itself the default is initialised to None.

   @attr.s(frozen=True)
    class Settings(object):
      test_tmpdir = attr.ib(default=os.environ.get("TEST_TMPDIR"))

Example for code below code the default is None.

os.environ["TEST_TMPDIR"] = '/tmp/'
setting = Settings()

The code is currently working only if environment variable is set at shell level. So doing export TEST_TMPDIR="/tmp/" in terminal and then reading Settings() works.

Tried reading os.environ["TEST_TMPDIR"] in __attrs_post_init__ it does return the value set by python code.

Any links on why defaults are not set on initiation will be helpful.


Solution

  • Use an attr.Factory. It’s an callable that’s called while instantiating. In your case, you can use functools.partial to create the factory, since the arguments are fixed.

    Something like this should work (sorry, I’m on a phone):

    import attr
    from functools import partial
    
    @attr.frozen
    class C:
        test_tmpdir = attr.ib(factory=partial(os.environ.get, "TEST_TMPDIR"))
    

    (factory=x is syntactic sugar for default=attr.Factory(x))