Skip to content

Commit

Permalink
feat: rename 'param' to 'attr'
Browse files Browse the repository at this point in the history
  • Loading branch information
kalekundert committed Jan 14, 2022
1 parent 0ca13b9 commit 30a37e7
Show file tree
Hide file tree
Showing 27 changed files with 803 additions and 775 deletions.
6 changes: 3 additions & 3 deletions byoc/__init__.py
Expand Up @@ -13,9 +13,9 @@
append_configs, prepend_config, prepend_configs, share_configs,
get_meta,
)
from .params.param import param
from .params.toggle import toggle_param, pick_toggled, Toggle as toggle
from .params.inherited import inherited_param
from .attrs.attr import attr
from .attrs.toggle import toggle_attr, pick_toggled, Toggle as toggle
from .attrs.inherited import inherited_attr
from .configs.configs import *
from .configs.layers import Layer, DictLayer, FileNotFoundLayer, dict_like
from .configs.attrs import config_attr
Expand Down
8 changes: 4 additions & 4 deletions byoc/app.py
Expand Up @@ -6,18 +6,18 @@ class AppMeta(type):
"""
A metaclass that allows a class to be instantiated either in the usual way,
or without calling the constructor. The latter is useful if the object
will be initialized in another way, e.g. `byoc.param()` parameters that
will be initialized in another way, e.g. `byoc.attr()` attributes that
read from the command line.
"""

def from_params(cls):
def from_bare(cls):
self = super(cls, cls).__new__(cls)
if hasattr(self, '__bareinit__'):
self.__bareinit__()
return self

def __call__(cls, *args, **kwargs):
self = cls.from_params()
self = cls.from_bare()
self.__init__(*args, **kwargs)
return self

Expand All @@ -28,7 +28,7 @@ def __bareinit__(self):

@classmethod
def entry_point(cls):
app = cls.from_params()
app = cls.from_bare()
app.main()

def main(self):
Expand Down
File renamed without changes.
12 changes: 6 additions & 6 deletions byoc/params/param.py → byoc/attrs/attr.py
Expand Up @@ -9,7 +9,7 @@
from ..errors import ApiError, NoValueFound, Log
from math import inf

class param:
class attr:

class _State:

Expand Down Expand Up @@ -92,7 +92,7 @@ def _override(self, args, kwargs, skip=frozenset()):

def _load_state(self, obj):
model.init(obj)
states = model.get_param_states(obj)
states = model.get_attr_states(obj)

if self._name not in states:
default = self._default_factory()
Expand All @@ -116,9 +116,9 @@ def _load_value(self, obj):
state.meta = values_iter.meta
state.dynamic = values_iter.dynamic

# Cache the exception indicating that this parameter is
# missing, since that is likely to be raised several times (and
# unlikely to terminate the program).
# Cache the exception indicating that this attribute is missing,
# since that is likely to be raised several times (and unlikely to
# terminate the program).
#
# Note that other exceptions will not update the cache, and
# therefore may need to be calculated on each access. I could
Expand Down Expand Up @@ -151,7 +151,7 @@ def _load_default(self, obj):

def _calc_value(self, obj):
log = Log()
log.info("getting {param!r} parameter for {obj!r}", obj=obj, param=self._name)
log.info("getting {attr!r} attribute for {obj!r}", obj=obj, attr=self._name)

bound_getters = self._load_bound_getters(obj)
default = self._load_default(obj)
Expand Down
12 changes: 6 additions & 6 deletions byoc/params/inherited.py → byoc/attrs/inherited.py
Expand Up @@ -2,7 +2,7 @@

from copy import copy

class inherited_param:
class inherited_attr:

def __init__(self, *args, **kwargs):
self._args = args
Expand All @@ -20,8 +20,8 @@ def __set_name__(self, cls, name):
cls=cls,
name=name,
)
err.brief = "no superclass parameter to inherit from"
err.info += "attempting to create `inherited_param`:\n{cls.__name__}.{name}"
err.brief = "no superclass attribute to inherit from"
err.info += "attempting to create `inherited_attr`:\n{cls.__name__}.{name}"
err.blame += lambda e: "\n".join(
"none of the following exist:", *(
f'{x.__qualname__}.{e.name}'
Expand All @@ -30,8 +30,8 @@ def __set_name__(self, cls, name):
)
raise err

param = copy(parent)
param._override(self._args, self._kwargs)
attr = copy(parent)
attr._override(self._args, self._kwargs)

setattr(cls, name, param)
setattr(cls, name, attr)

4 changes: 2 additions & 2 deletions byoc/params/toggle.py → byoc/attrs/toggle.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3

from .. import model
from .param import param, UNSPECIFIED
from .attr import attr, UNSPECIFIED
from ..utils import noop
from ..errors import NoValueFound
from more_itertools import partition, first
Expand All @@ -26,7 +26,7 @@ def pick_toggled(values):

return toggle.value != base

class toggle_param(param):
class toggle_attr(attr):

def __init__(
self,
Expand Down
12 changes: 12 additions & 0 deletions byoc/configs/configs.py
Expand Up @@ -170,6 +170,18 @@ class AppDirsConfig(Config):
root_key = None
stem = 'conf'

def __init__(self, obj, **kwargs):
self.name = kwargs.pop('name', self.name)
self.config_cls = kwargs.pop('format', self.config_cls)
self.slug = kwargs.pop('slug', self.slug)
self.author = kwargs.pop('author', self.author)
self.version = kwargs.pop('version', self.version)
self.schema = kwargs.pop('schema', unbind_method(self.schema))
self.root_key = kwargs.pop('root_key', self.root_key)
self.stem = kwargs.pop('stem', self.stem)

super().__init__(obj, **kwargs)

def load(self):
for path, config_cls in self.config_map.items():
yield from config_cls.load_from_path(
Expand Down
8 changes: 4 additions & 4 deletions byoc/errors.py
Expand Up @@ -14,17 +14,17 @@ class ApiError(Error):

class NoValueFound(AttributeError):
"""
The default exception raised when no value can be found for a parameter.
The default exception raised when no value can be found for an attribute.
BYOC tries to avoid raising or interpreting any exceptions relating to
accessing parameter values. Instead, user-provided callbacks are expected
accessing attribute values. Instead, user-provided callbacks are expected
to raise if they notice something wrong. This puts the user in control of
exception handling and error messages, both good things for a
general-purpose framework like this.
`NoValueFound` is a bit of an exception to this philosophy. It's raised by
the default picker (`first`) in the event that no values were found for a
parameter. It's interpreted by some parts of BYOC (specifically the
the default picker (`first`) in the event that no values were found for an
attribute. It's interpreted by some parts of BYOC (specifically the
`Method` and `Function` getters) to mean that an attempt to get a value
should be silently skipped. Both of these behaviors can be overridden, but
they're useful defaults.
Expand Down
60 changes: 30 additions & 30 deletions byoc/getters.py
Expand Up @@ -20,7 +20,7 @@ def __repr__(self):
def __reprargs__(self):
return []

def bind(self, obj, param):
def bind(self, obj, attr):
raise NotImplementedError

class Key(Getter):
Expand All @@ -36,12 +36,12 @@ def __reprargs__(self):
else:
return [self.config_cls.__name__, repr(self.key)]

def bind(self, obj, param):
def bind(self, obj, attr):
wrapped_configs = [
wc for wc in model.get_wrapped_configs(obj)
if isinstance(wc.config, self.config_cls)
]
return BoundKey(self, obj, param, wrapped_configs)
return BoundKey(self, obj, attr, wrapped_configs)

class ImplicitKey(Getter):

Expand All @@ -53,8 +53,8 @@ def __init__(self, wrapped_config, key):
def __reprargs__(self):
return [repr(self.key), repr(self.wrapped_config)]

def bind(self, obj, param):
return BoundKey(self, obj, param, [self.wrapped_config])
def bind(self, obj, attr):
return BoundKey(self, obj, attr, [self.wrapped_config])

class Func(Getter):

Expand All @@ -74,9 +74,9 @@ def partial(self, *args, **kwargs):
self.partial_kwargs = kwargs
return self

def bind(self, obj, param):
def bind(self, obj, attr):
return BoundCallable(
self, obj, param,
self, obj, attr,
self.callable,
self.partial_args,
self.partial_kwargs,
Expand All @@ -89,15 +89,15 @@ class Method(Func):
def __init__(self, *args, dynamic=True, **kwargs):
super().__init__(*args, dynamic=dynamic, **kwargs)

def bind(self, obj, param):
def bind(self, obj, attr):
# Methods used with this getter this will typically attempt to
# calculate a value based on other parameters. In most cases, a
# NoValueFound exception will be raised if any of those parameters is
# missing a value. The most sensible thing to do when this happens is
# to silently skip this getter, allowing the parameter to continue
# searching other getters for a value.
# calculate a value based on other BYOC-managed attributes. In most
# cases, a NoValueFound exception will be raised if any of those
# attributes is missing a value. The most sensible thing to do when
# this happens is to silently skip this getter, allowing the attribute
# that invoked it to continue searching other getters for a value.

bc = super().bind(obj, param)
bc = super().bind(obj, attr)
bc.partial_args = (obj, *bc.partial_args)
bc.exceptions = bc.exceptions or (NoValueFound,)
return bc
Expand All @@ -111,48 +111,48 @@ def __init__(self, value, **kwargs):
def __reprargs__(self):
return [repr(self.value)]

def bind(self, obj, param):
return BoundValue(self, obj, param, self.value)
def bind(self, obj, attr):
return BoundValue(self, obj, attr, self.value)



class BoundGetter:

def __init__(self, parent, obj, param):
def __init__(self, parent, obj, attr):
self.parent = parent
self.obj = obj
self.param = param
self.attr = attr

# The following attributes are public and may be accessed or modified
# by `param` subclasses (e.g. `toggle_param`). Be careful when making
# by `attr` subclasses (e.g. `toggle_attr`). Be careful when making
# modifications, though, because any modifications will need to be
# re-applied each time the cache expires (because the getters are
# re-bound when this happens).
self.kwargs = parent.kwargs
self.cast_funcs = list(value_chain(
self.kwargs.get('cast', []),
param._get_default_cast()
attr._get_default_cast()
))

self._check_kwargs()

def _check_kwargs(self):
given_kwargs = set(self.kwargs.keys())
known_kwargs = self.param._get_known_getter_kwargs()
known_kwargs = self.attr._get_known_getter_kwargs()
unknown_kwargs = given_kwargs - known_kwargs

if unknown_kwargs:
err = ApiError(
getter=self.parent,
obj=self.obj,
param=self.param,
attr=self.attr,
given_kwargs=given_kwargs,
known_kwargs=known_kwargs,
unknown_kwargs=unknown_kwargs,
)
err.brief = f'unexpected keyword argument'
err.info += lambda e: '\n'.join([
f"{e.param.__class__.__name__}() allows the following kwargs:",
f"{e.attr.__class__.__name__}() allows the following kwargs:",
*e.known_kwargs,
])
err.blame += lambda e: '\n'.join([
Expand All @@ -171,13 +171,13 @@ def cast_value(self, x):

class BoundKey(BoundGetter):

def __init__(self, parent, obj, param, wrapped_configs):
super().__init__(parent, obj, param)
def __init__(self, parent, obj, attr, wrapped_configs):
super().__init__(parent, obj, attr)
self.key = parent.key
self.wrapped_configs = wrapped_configs

if self.key is UNSPECIFIED:
self.key = param._get_default_key()
self.key = attr._get_default_key()

def iter_values(self, log):
assert self.key is not UNSPECIFIED
Expand Down Expand Up @@ -213,8 +213,8 @@ def iter_values(self, log):

class BoundCallable(BoundGetter):

def __init__(self, parent, obj, param, callable, args, kwargs, dynamic, exc=()):
super().__init__(parent, obj, param)
def __init__(self, parent, obj, attr, callable, args, kwargs, dynamic, exc=()):
super().__init__(parent, obj, attr)
self.callable = callable
self.partial_args = args
self.partial_kwargs = kwargs
Expand All @@ -234,8 +234,8 @@ def iter_values(self, log):

class BoundValue(BoundGetter):

def __init__(self, parent, obj, param, value):
super().__init__(parent, obj, param)
def __init__(self, parent, obj, attr, value):
super().__init__(parent, obj, attr)
self.value = value

def iter_values(self, log):
Expand Down
8 changes: 4 additions & 4 deletions byoc/meta.py
Expand Up @@ -54,12 +54,12 @@ def __get__(self, obj, cls=None):
class meta_view:
# This class will never refresh the cache, so the results it returns may
# change if the value is accessed immediately afterwards. For this reason,
# it is recommended to always access any parameters of interest before
# accessing the metadata associated with those parameters.
# it is recommended to always access any attributes of interest before
# accessing the metadata associated with those attributes.

def __init__(self, obj):
self.__obj = obj

def __getattr__(self, param):
return get_meta(self.__obj, param)
def __getattr__(self, attr):
return get_meta(self.__obj, attr)

12 changes: 6 additions & 6 deletions byoc/model.py
Expand Up @@ -14,7 +14,7 @@ def __init__(self, obj):
WrappedConfig(cf(obj))
for cf in get_config_factories(obj)
]
self.param_states = {}
self.attr_states = {}
self.cache_version = 0
self.load_callbacks = get_load_callbacks(obj).values()

Expand Down Expand Up @@ -163,19 +163,19 @@ def get_load_callbacks(obj):

return hits

def get_param_states(obj):
return get_state(obj).param_states
def get_attr_states(obj):
return get_state(obj).attr_states

def get_meta(obj, param):
def get_meta(obj, attr):
from .meta import NeverAccessedMeta

try:
states = get_param_states(obj)
states = get_attr_states(obj)
except AttributeError:
return NeverAccessedMeta()

try:
state = states[param]
state = states[attr]
except KeyError:
return NeverAccessedMeta()

Expand Down
2 changes: 1 addition & 1 deletion byoc/pickers.py
Expand Up @@ -49,5 +49,5 @@ def first(values):
values.meta = meta
return value
except StopIteration as err:
raise NoValueFound("can't find value for parameter", values.log)
raise NoValueFound("can't find value for attribute", values.log)

0 comments on commit 30a37e7

Please sign in to comment.