Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazily load default value of environment variable #185

Open
konoufo opened this issue May 31, 2018 · 12 comments
Open

Lazily load default value of environment variable #185

konoufo opened this issue May 31, 2018 · 12 comments
Labels
enhancement New feature or request

Comments

@konoufo
Copy link

konoufo commented May 31, 2018

Would you accept a pull request to enable lazy evaluation of default value ? I think there are several use cases where you want to generate the default on-demand. For example, creating a new temporary directory and use it as a default value when a env var doesn't exist in environment.

@thomasf
Copy link

thomasf commented Jun 27, 2018

Please describe how you suggest it will work! Allowing the value to be just a plain function?

I use a pattern like this when I want to have that feature and it's not very verbose and easy to follow:

env = environ.Env(
    SOMETHING=(str),
)

SOMETHING = env("SOMETHING",default=None)
if not SOMETHING:
    ... calculate and assign value of something

I think it's maybe not a good idea to allow lazy evaluation of values after settings.py has been loaded, it's good to have the settings at least somewhat validated when the file is loaded..

@konoufo
Copy link
Author

konoufo commented Jun 30, 2018

Yeah I think being able to pass a plain function that's evaluated when env("SOMETHING", fun) is called. This wouldn't make a difference timing-wise compared to what we're doing right now.

@thomasf
Copy link

thomasf commented Jul 1, 2018

So something like this then.. I wonder if it clashes with other features or not, I cant think of anything from the top of my head..

def create_something():
    return "SOMETHING"

env = environ.Env(
    SOMETHING=(str, create_something),
)

SOMETHING = env('SOMETHING')

OTHER_THING=env('OTHER_THING', default_value=create_something, cast_to=str)

Note that the amount of code isn't shorter than the code I posted earlier, the only benifit I can see is that the type str can be validated by django-environ after being returned from the function.. I still think that the settings file becomes harder to read and I wonder if it's worth it.

@konoufo
Copy link
Author

konoufo commented Jul 1, 2018 via email

@thomasf
Copy link

thomasf commented Jul 1, 2018

I am not a maintainer. I just wanted to understand what you were requesting (for the benefit of everyone) , it looks clear to me now..

@konoufo
Copy link
Author

konoufo commented Jul 1, 2018 via email

@Jafnee
Copy link

Jafnee commented Jul 2, 2018

I haven't tested this, but would creating your own lazy class work?

def create_something():
    return "SOMETHING"

class LazyString:
    def __init__(self, value, fn):
        self.value = value
        self.fn = fn

    def __str__(self):
        if self.value is not None:
            return self.value
        return self.fn()


OTHER_THING=LazyString(env('OTHERTHING', default=None), create_something)


# someotherfile.py
from django.conf import settings

other_thing = str(settings.OTHER_THING)

@konoufo
Copy link
Author

konoufo commented Jul 2, 2018 via email

@Jafnee
Copy link

Jafnee commented Jul 2, 2018

Shouldn't need to replace everything to settings.OTHER_THING.value, the example above is meant to evaluated lazily whenever the setting is used.
The value will either be the string set via env var or the return value of the function provided. The function is also called each time the setting is used, e.g if it returned the timestamp now, it will always return the latest value.

@thomasf
Copy link

thomasf commented Jul 2, 2018

Remember that if you are using it for creating a new temporary directory and use it as a default value and don't return a static value the value will probably be different for each django process in a uwsgi server. If possible you should normally always prefer a deterministic way to create the settings even if it's lazily set.

@joke2k
Copy link
Owner

joke2k commented Jul 2, 2018

Hi, I think this feature could be useful.
As @konoufo said, callable defaults are ubiquitous in Python, and we could implement it as easy.
Here https://github.com/joke2k/django-environ/blob/develop/environ/environ.py#L279 we could handle this, without side effects.

@konoufo
Copy link
Author

konoufo commented Jul 2, 2018

@Jafnee that is if you assume that the setting will be used in some way as a string or coerced to a string.
@thomasf I realize that and the temporary directory setting is just a specific use case; but yeah I'm aware that it has to be deterministic if I want a single unique directory for every process.
@joke2k Right, I could submit a PR.

@sergeyklay sergeyklay added the enhancement New feature or request label Sep 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants