PK ! h class_settings/__init__.py__version__ = "0.1.2"
from .env import Env, env
from .settings import Settings
def setup():
import importlib
import os
import sys
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from .importers import SettingsImporter
from .utils import patch_settings_setup
global _setup
if _setup:
return
# Prevent DJANGO_SETTINGS_MODULE getting mutated twice via the autoreloader
if os.environ.get("RUN_MAIN") != "true":
try:
settings_module = os.environ["DJANGO_SETTINGS_MODULE"]
settings_class = os.environ["DJANGO_SETTINGS_CLASS"]
except KeyError as error:
raise ImproperlyConfigured(
"Settings could not be setup. The environment variable {!r} "
"is not defined.".format(error.args[0])
) from None
os.environ["DJANGO_SETTINGS_MODULE"] = "{}:{}".format(
settings_module, settings_class
)
sys.meta_path.append(SettingsImporter())
@patch_settings_setup # Needed for manage.py --settings support
def settings_setup():
module_path = os.environ["DJANGO_SETTINGS_MODULE"]
module = importlib.import_module(module_path)
# Prevent manage.py from swallowing exceptions arising from
# settings._setup and make sure to call settings.configure first to
# allow it to error on multiple calls.
old = settings._wrapped
settings.configure(module, SETTINGS_MODULE=module_path)
new = settings._wrapped
settings._wrapped = old
settings._setup()
settings._wrapped = new
_setup = True
_setup = False
PK ! I class_settings/env.pyimport contextlib
import functools
import os
import sys
import types
from django.core.exceptions import ImproperlyConfigured
from . import parsers
from .options import Options
class Missing:
def __bool__(self):
return False
missing = Missing()
class Env:
def __init__(self):
self._prefix = None
self._parsers = {}
# Populate with default parsers
for name, parser in vars(parsers).items():
if name.startswith("_"):
continue
if callable(parser):
self.parser(parser)
def __call__(self, name=None, *, prefix=None, default=missing):
frame = sys._getframe(1)
while frame is not None:
options = frame.f_locals.get("__meta__")
if isinstance(options, Options):
break
frame = frame.f_back
else:
if name is None:
raise TypeError("'name' is required outside of Settings subclasses")
meta = types.SimpleNamespace(env_prefix=None)
options = Options(meta)
if name is None:
return DeferredEnv(self, prefix=prefix, default=default)
prefix = (
prefix
if prefix is not None
else self._prefix
if self._prefix is not None
else options.env_prefix
)
if prefix.islower() and not prefix.endswith("_"):
prefix += "_"
name = prefix + name if prefix is not None else name
if default is not missing:
return os.environ.get(name, default)
try:
return os.environ[name]
except KeyError:
raise ImproperlyConfigured(
"Environment variable {!r} not set".format(name.upper())
) from None
def __getattr__(self, name):
try:
return self._parsers[name]
except KeyError:
cls_name = type(self).__name__
raise AttributeError(
"{!r} object has no attribute {!r}".format(cls_name, name)
) from None
@contextlib.contextmanager
def prefixed(self, prefix):
if prefix.islower() and not prefix.endswith("_"):
prefix += "_"
old_prefix = self._prefix
if old_prefix is None:
self._prefix = prefix
else:
self._prefix += prefix
yield
self._prefix = old_prefix
def parser(self, _func=None, *, name=None, parse_default=False):
def decorator(func):
@functools.wraps(func)
def parser(name=None, *, prefix=None, default=missing, **kwargs):
try:
value = self(name, prefix=prefix)
except ImproperlyConfigured:
if default is not missing:
if parse_default:
default = func(default, **kwargs)
return default
raise
if isinstance(value, DeferredEnv):
value._parser = functools.partial(parser, **kwargs)
else:
value = func(value, **kwargs)
return value
parser_name = name if name is not None else func.__name__
self._parsers[parser_name] = parser
return func
return decorator if _func is None else decorator(_func)
class DeferredEnv:
def __init__(self, env, *, prefix=None, default=missing):
self._env = env
self._prefix = prefix
self._default = default
self._parser = None
def _parse(self, name):
if self._parser is not None:
return self._parser(name, prefix=self._prefix, default=self._default)
else:
return self._env(name, prefix=self._prefix, default=self._default)
env = Env()
PK ! Alw class_settings/importers.pyimport importlib.machinery
import types
from django.core.exceptions import ImproperlyConfigured
from .settings import Settings
class SettingsModule(types.ModuleType):
def __init__(self, name, cls):
super().__init__(name, cls.__doc__)
self.SETTINGS_CLASS = cls
def __dir__(self):
return set(super().__dir__() + dir(self.SETTINGS_CLASS))
def __getattr__(self, name):
return getattr(self.SETTINGS_CLASS, name)
class SettingsImporter:
def find_spec(self, fullname, path=None, target=None):
if ":" not in fullname.rpartition(".")[2]:
return None
settings_module = fullname.rsplit(":", maxsplit=1)[0]
return importlib.machinery.ModuleSpec(fullname, self, origin=settings_module)
def create_module(self, spec):
settings_module, settings_class = spec.name.rsplit(":", maxsplit=1)
module = importlib.import_module(settings_module)
try:
cls = getattr(module, settings_class)
except AttributeError:
raise ImproperlyConfigured(
"Module {!r} has no Settings subclass named {!r}".format(
settings_module, settings_class
)
) from None
if not (isinstance(cls, type) and issubclass(cls, Settings)):
raise ImproperlyConfigured(
"{!r} is not a Settings subclass".format(settings_class)
)
return SettingsModule(spec.name, cls())
def exec_module(self, module):
pass
PK ! } class_settings/options.pyfrom django.conf import global_settings
class Options:
def __init__(self, meta):
self.default_settings = getattr(meta, "default_settings", global_settings)
self.env_prefix = getattr(meta, "env_prefix", "DJANGO_")
PK ! 6F F class_settings/parsers.pyimport builtins
import functools
def _get_parser(parser):
is_builtin = parser in vars(builtins).values()
is_class = isinstance(parser, type)
if is_builtin and is_class and parser.__name__ in globals():
parser = globals()[parser.__name__]
return parser
def _sequence_parser(type):
@functools.wraps(type)
def parser(value, separator=",", subparser=None):
items = map(builtins.str.strip, value.split(separator))
if subparser is not None:
subparser = _get_parser(subparser)
items = map(subparser, items)
return type(items)
return parser
# Numeric types
int = int
float = float
complex = complex
# Sequence types
list = _sequence_parser(list)
tuple = _sequence_parser(tuple)
# Text sequence types
str = str
# Binary sequence types
bytes = bytes
bytearray = bytearray
# Set types
set = _sequence_parser(set)
frozenset = _sequence_parser(frozenset)
# Mapping types
def dict(value, separator=",", itemseparator="=", keyparser=None, valueparser=None):
items = map(builtins.str.strip, value.split(separator))
keys, values = zip(
*(map(builtins.str.strip, item.split(itemseparator)) for item in items)
)
if keyparser is not None:
keyparser = _get_parser(keyparser)
keys = map(keyparser, keys)
if valueparser is not None:
valueparser = _get_parser(valueparser)
values = map(valueparser, values)
return builtins.dict(zip(keys, values))
# Other types
def bool(value):
if value.lower() in ["true", "t", "yes", "y", "on", "1"]:
return True
elif value.lower() in ["false", "f", "no", "n", "off", "0"]:
return False
else:
raise ValueError("Could not convert {!r} to bool".format(value))
# Custom
def json(value):
import json
return json.loads(value)
PK ! VF_
_
class_settings/settings.pyimport __future__
import ast
import inspect
import sys
import textwrap
import tokenize
from .env import DeferredEnv
from .options import Options
class SettingsDict(dict):
def __setitem__(self, key, value):
if isinstance(value, DeferredEnv):
value = value._parse(key)
super().__setitem__(key, value)
class SettingsMeta(type):
def __prepare__(name, bases):
frame = sys._getframe(1)
filename = inspect.getsourcefile(frame)
with tokenize.open(filename) as file:
lines = file.readlines()[frame.f_lineno - 1 :]
source = "".join(inspect.getblock(lines))
source = textwrap.dedent(source.expandtabs())
cls_node = ast.parse(source).body[0]
for node in reversed(list(ast.iter_child_nodes(cls_node))):
if isinstance(node, ast.ClassDef) and node.name == "Meta":
cf_mask = sum(
getattr(__future__, feature).compiler_flag
for feature in __future__.all_feature_names
)
code = compile(
ast.Module(body=[node]),
filename="",
mode="exec",
flags=frame.f_code.co_flags & cf_mask,
dont_inherit=True,
)
globals = frame.f_globals
locals = {}
exec(code, globals, locals)
meta = locals["Meta"]
break
else:
for base in bases:
if hasattr(base, "Meta"):
meta = base.Meta
break
else:
meta = None
return SettingsDict(__meta__=Options(meta))
def __new__(meta, name, bases, namespace):
options = namespace.pop("__meta__", None)
if not isinstance(options, Options):
raise RuntimeError("__meta__ is not an Options object")
namespace["_meta"] = options
return super().__new__(meta, name, bases, namespace)
class Settings(metaclass=type("Meta", (type,), {})): # Hack for __class__ assignment
def __dir__(self):
default_settings = self._meta.default_settings
return set(super().__dir__() + dir(default_settings))
def __getattr__(self, name):
default_settings = self._meta.default_settings
return getattr(default_settings, name)
def is_overridden(self, setting):
try:
self.__getattribute__(setting) # Avoids __getattr__
except AttributeError:
return False
else:
return True
Settings.__class__ = SettingsMeta
PK ! Z> > class_settings/utils.pyimport functools
from django.conf import settings
def patch_settings_setup(func):
@functools.wraps(settings._setup)
def setup(*args, **kwargs):
object.__delattr__(settings, "_setup")
func()
# Circumvent any custom logic
object.__setattr__(settings, "_setup", setup)
return func
PK ! ӡn* * - django_class_settings-0.1.2.dist-info/LICENSEMIT License
Copyright (c) 2018 orlnub123
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
PK !HڽT U + django_class_settings-0.1.2.dist-info/WHEEL
A
н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK !H]/x ) . django_class_settings-0.1.2.dist-info/METADATAVmS6_6xJiIB;Ld[vtȖ* ]q^hCb]˳$/4E%9
qbN45FkѸsT(éָֈ n0⮳?EN=I2x Ș<e:{0`1-4'B%qƢHYV*b].\$ [3+djoXB¿8Pzq} 3Dሸ
S\3$E.Jk1$>73ךE c0\^gԛ<|ʇNq!))&\ӿOڃA :*XZsX ^ T
;hSרM;wq^ɺ} >vǟ6~=:c>5oc[RW>p^Gz
WZ
/ardrf,tE?G r&Oړܲ prdZA🜛#EbKLw|8X}`an>8<{1b'-,|=g'g"H5"N']^dt2ɣETA6_
\;;Y[o1j8ߨ D*"X80OU 4ݎ{^.RGi\;