amitu / importd

django based mini framework inspired from sinatra. fully compatible with django.
http://amitu.com/importd/
BSD 3-Clause "New" or "Revised" License
510 stars 30 forks source link

"settings framework" #71

Closed amitu closed 9 years ago

amitu commented 9 years ago

importd gets a "settings framework" now.

amitu commented 9 years ago

CC: @juancarlospaco, @alendit, @jezdez, @lukaszb, @jcugat, @if1live.

What do you think?

ghost commented 9 years ago

Build failing complaining:

  do_dp("TEMPLATE_CONTEXT_PROCESSORS")
KeyError: 'TEMPLATE_CONTEXT_PROCESSORS'

:sob:

Nice ideas :grey_exclamation: , needs another twist of the bolt... :smiley_cat:

ghost commented 9 years ago

This looks a lot better now :grey_exclamation: :ship: :it: :grey_exclamation: :smiley_cat:

d-( ʘ‿ʘ )_m

if1live commented 9 years ago

I suggest three modifications. I think that if modify env method, it will be more convenient.

default value + strip

If key is not in environment variables and default value is defined, importd should use default value. But currently, not works.

env("SOME_BOOL_ENV", False)

If SOME_BOOL_ENV not exist, importd use False as val. bool doesn't have strip method. It will raise exception. Call strip method only if value is string.

pass return type

Assume that SOME_NUMBER_ENV is defined as 123

num_attr = env("SOME_NUMBER_ENV", 0)

It will return string 123. If num_attr = env("SOME_NUMBER_ENV", 0, int) is possible, we can get integer 123.

bool("False") != False

if IS_PROD=False, what is not env("IS_PROD", False)? Somebody think thiat IS_PROD is False and not operator exists. Final value is True. Wrong. because bool("False") != False. Only bool("") == False.

summary

I think that first suggestion (default value + strip) should be applied to execute DEBUG=not env("IS_PROD", False),

Other suggestions(pass return type, bool("False") != False) are optional. Apply or not, selection is @amitu role.

test code

# Run from shell
# SOME_NUMBER_ENV=123 IS_PROD=False python test.py

import os

def env(key, default=""):
    if default is None and key not in os.environ:
        raise KeyError

    val = os.environ.get(key, default).strip()
    return val

def env_alternative(key, default="", ret_type=unicode):
    if default is None and key not in os.environ:
        raise KeyError

    val = os.environ.get(key, default)
    # if key is not in env, importd will use default
    # if default is not string (ex: True), strip() is not exist
    if isinstance(val, basestring):
        val = val.strip()

    # bool("False") != False
    # bool("") == False
    if ret_type == bool:
        return val not in ("False", "")
    else:
        return ret_type(val)

try:
    bool_attr = env("SOME_BOOL_ENV", False)
    print("{} : {}".format(type(bool_attr), bool_attr))
except AttributeError:
    print("cannot get value from env()")

bool_attr = env_alternative("IS_PROD", False)
print("{} : {}".format(type(bool_attr), bool_attr))

num_attr = env("SOME_NUMBER_ENV", 0)
print("{} : {}".format(type(num_attr), num_attr))
# if SOME_NUMBER_ENV defined
# <type 'str'> : 123

num_attr = env_alternative("SOME_NUMBER_ENV", 0, int)
print("{} : {}".format(type(num_attr), num_attr))
# if SOME_NUMBER_ENV defined
# <type 'int'> : 123

DEBUG = not env("IS_PROD", False)
print("env() : {} : {}".format(type(DEBUG), DEBUG))

DEBUG = not env_alternative("IS_PROD", False, bool)
print("env_alternative() : {} : {}".format(type(DEBUG), DEBUG))

output

$ SOME_NUMBER_ENV=123 IS_PROD=False python test.py
cannot get value from env()
<type 'unicode'> : False
<type 'str'> : 123
<type 'int'> : 123
env() : <type 'bool'> : False
env_alternative() : <type 'bool'> : True
ghost commented 9 years ago

:-1: to pass return type.

Better to do something like this which is now built-in: https://gist.github.com/juancarlospaco/94f98cff7f9accd8d618#gistcomment-1476439

I have tested to do that on https://github.com/juancarlospaco/websktop#websktop and works ok.

Its on Production at https://github.com/juancarlospaco/unicodemoticon/blob/master/unicodemoticon.py#L666

We are 2015, by 2020 python2 will be dead anyways, better prepare for future than re-wrote from scratch on less than 4 years.

if1live commented 9 years ago

@juancarlospaco how do you think about this code?

import os

def env_alternative(key, default=""):
    if default is None and key not in os.environ:
        raise KeyError

    val = os.environ.get(key, default)
    # if key is not in env, importd will use default
    # if default is not string (ex: True), strip() is not exist
    if isinstance(val, basestring):
        val = val.strip()

    ret_type = type(default)

    # bool("False") != False
    # bool("") == False
    if ret_type == bool:
        return val not in ("False", "")
    else:
        return ret_type(val)

I didnt' use python3. I can't understant how to apply type_check decorator to env method. Could you show me code, env method type_check version? If it exists, I can understand advantage of your suggestion.

ghost commented 9 years ago

Going off topic,
...but add typecheck() function (with imports) from here https://gist.github.com/juancarlospaco/94f98cff7f9accd8d618#file-static_typing_python3-py

then decorate with @typecheck the function or method you want to static type. You may need Annotations too.

Anyways if Python2 does not support the feature, just dont make it available there, better than weird hacks, more reason to move to Python3.

amitu commented 9 years ago

Hey @juancarlospaco, we still have to support python2, almost all my projects in prod are python2 :-p

@if1live, what do you think of the latest commit?

amitu commented 9 years ago

Can you add some more tests in EnvTest to check for anything else that may be a corner case?

ghost commented 9 years ago

:+1: Ok.

¯|_(҂⌣̀‿⌣́)/¯

if1live commented 9 years ago

:+1: looks good.

ghost commented 9 years ago

:+1: