def __init__(self, name, default=Unconfigurable, optional=False, readonly=None): # freeze Unconfigurables by default readonly = default is Unconfigurable if readonly is None else readonly if not is_string(name): raise ValueError("'name' must be a string (got %r)" % name) if not isinstance(optional, bool): raise ValueError("'optional' must be boolean (got %r)" % optional) if not isinstance(readonly, bool): raise ValueError("'readonly' must be boolean (got %r)" % readonly) self.name = name self.default = default self.optional = optional self.readonly = readonly # default values set by config system self._defaults = WeakKeyIDDictionary() # param values set on objects self.data = WeakKeyIDDictionary()
def test_weakkeydict_delitem(): d = WeakKeyIDDictionary() o1 = C() o2 = C() d[o1] = 'something' d[o2] = 'something' assert len(d) == 2 del d[o1] assert len(d) == 1 assert list(d.keys()) == [o2]
def test_weakkeyiddictionary_init(): obj = C() val = 364 # construct from dictionary d = WeakKeyIDDictionary({obj: val}) assert d[obj] == val # construct from another WeakKeyIDDictionary d2 = WeakKeyIDDictionary(d) assert d2[obj] == val
def test_weakkeydict_popitem(key1=C(), key2=C(), val1="v1", val2="v2"): d = WeakKeyIDDictionary() d[key1] = val1 d[key2] = val2 assert len(d) == 2 k1, v1 = d.popitem() assert len(d) == 1 assert k1 in (key1, key2) and v1 is (val1 if k1 is key1 else val2) k2, v2 = d.popitem() assert len(d) == 0 assert k2 is (key2 if k1 is key1 else key1) and v2 is (val1 if k2 is key1 else val2)
def test_weakkeydict_setdefault(key=C(), value1="v1", value2="v2"): d = WeakKeyIDDictionary() o = d.setdefault(key, value1) assert o is value1 assert key in d assert d.get(key) is value1 assert d[key] is value1 o = d.setdefault(key, value2) assert o is value1 assert key in d assert d.get(key) is value1 assert d[key] is value1
def __init__(self, default=Unconfigurable, optional=False, readonly=None): self.default = default self.optional = optional if readonly is None: # freeze Unconfigurables by default readonly = default is Unconfigurable self.readonly = readonly # default values set by config system self._defaults = WeakKeyIDDictionary() # param values set on objects self.data = WeakKeyIDDictionary()
def test_weakkeydict_popitem(key1=C(), key2=C(), value1="v1", value2="v2"): d = WeakKeyIDDictionary() d[key1] = value1 d[key2] = value2 assert len(d) == 2 k, v = d.popitem() assert len(d) == 1 if k is key1: assert v is value1 else: assert v is value2 k, v = d.popitem() assert len(d) == 0 if k is key1: assert v is value1 else: assert v is value2
def test_weakkeydict_frees_values(): d = WeakKeyIDDictionary() k = C() v = C() d[k] = v weak_v = weakref.ref(v) del v assert sys.getrefcount(weak_v()) > 1 # function argument might make it > 1 del k v = weak_v() assert v is None, "Value in WeakKeyIDDictionary not garbage collected."
def test_weakkeyiddict_iter_functions(): """Tests iterkeys and iteritems""" in_d = {C(): 1, C(): 2, C(): 3} d = WeakKeyIDDictionary(in_d) keys = list(in_d) for key in d.iterkeys(): assert key in keys, "WeakKeyIDDictionary has extra key %d" % (key, ) keys.remove(key) assert len( keys) == 0, "Keys not found in WeakKeyIDDictionary: %r" % (keys, ) # copy, otherwise `d` will change size during iteration as references are removed in_d2 = dict(in_d) for k, v in d.iteritems(): assert k in in_d assert in_d2.pop(k) == v assert len( in_d2) == 0, "Keys not found in WeakKeyIDDictionary: %r" % (in_d2, )
def test_weakkeydict_bad_delitem(): d = WeakKeyIDDictionary() o = C() # An attempt to delete an object that isn't there should raise KeyError. with pytest.raises(KeyError): del d[o] with pytest.raises(KeyError): d[o] # If a key isn't of a weakly referencable type, __getitem__ and # __setitem__ raise TypeError. __delitem__ should too. with pytest.raises(TypeError): del d[13] with pytest.raises(TypeError): d[13] with pytest.raises(TypeError): d[13] = 13
def test_weakkeydict_update(in_d={C(): 1, C(): 2, C(): 3}): """This exercises d.update(), len(d), d.keys(), in d, d.get(), d[].""" d = WeakKeyIDDictionary() d.update(in_d) assert len(d) == len(in_d) for k in d.keys(): assert k in in_d, "mysterious new key appeared in weak dict" v = in_d.get(k) assert v is d[k] assert v is d.get(k) for k in in_d.keys(): assert k in d, "original key disappeared in weak dict" v = in_d[k] assert v is d[k] assert v is d.get(k)
class Parameter: """Simple descriptor for storing configuration parameters. Parameters ---------- name : str Name of the parameter. default : object The value returned if the parameter hasn't been explicitly set. optional : bool, optional Whether this parameter accepts the value None. By default, parameters are not optional (i.e., cannot be set to ``None``). readonly : bool, optional If true, the parameter can only be set once. By default, parameters can be set multiple times. Attributes ---------- coerce_defaults : bool If True, validate values for this parameter when they are set in a `.Config` object. Setting a parameter directly on an object will always be validated. equatable : bool If True, parameter values can be compared for equality (``a==b``); otherwise equality checks will just compare object identity (``a is b``). """ coerce_defaults = True equatable = False def __init__(self, name, default=Unconfigurable, optional=False, readonly=None): # freeze Unconfigurables by default readonly = default is Unconfigurable if readonly is None else readonly if not isinstance(name, str): raise ValueError("'name' must be a string (got %r)" % name) if not isinstance(optional, bool): raise ValueError("'optional' must be boolean (got %r)" % optional) if not isinstance(readonly, bool): raise ValueError("'readonly' must be boolean (got %r)" % readonly) self.name = name self.default = default self.optional = optional self.readonly = readonly # default values set by config system self._defaults = WeakKeyIDDictionary() # param values set on objects self.data = WeakKeyIDDictionary() def __getstate__(self): state = {} state.update(self.__dict__) state["_defaults"] = dict(state["_defaults"].items()) state["data"] = dict(state["data"].items()) return state def __setstate__(self, state): for k, v in state.items(): if k in ["_defaults", "data"]: v = WeakKeyIDDictionary(v) setattr(self, k, v) def __contains__(self, key): return key in self.data or key in self._defaults def __delete__(self, instance): del self.data[instance] def __get__(self, instance, type_): if instance is None: # Return self so default can be inspected return self if not self.configurable and instance not in self.data: raise ValidationError( "Unconfigurable parameters have no defaults. Please ensure the" " value of the parameter is set before trying to access it.", attr=self.name, obj=instance, ) return self.data.get(instance, self.default) def __set__(self, instance, value): self.data[instance] = self.coerce(instance, value) def __repr__(self): return "%s(%r, default=%s, optional=%s, readonly=%s)" % ( type(self).__name__, self.name, self.default, self.optional, self.readonly, ) @property def configurable(self): return self.default is not Unconfigurable def del_default(self, obj): del self._defaults[obj] def get_default(self, obj): return self._defaults.get(obj, self.default) def set_default(self, obj, value): if not self.configurable: raise ConfigError("Parameter '%s' is not configurable" % self) self._defaults[obj] = self.coerce( obj, value) if self.coerce_defaults else value def check_type(self, instance, value, type_): if value is not None and not isinstance(value, type_): if isinstance(type_, tuple): type_str = " or ".join((t.__name__ for t in type_)) else: type_str = type_.__name__ raise ValidationError( "Must be of type %r (got type %r)." % (type_str, type(value).__name__), attr=self.name, obj=instance, ) def coerce(self, instance, value): if isinstance(value, DefaultType): raise ValidationError( "Default is not a valid value. To reset a parameter, use 'del'.", attr=self.name, obj=instance, ) if self.readonly and instance in self.data: raise ReadonlyError(attr=self.name, obj=instance) if not self.optional and value is None: raise ValidationError( "Parameter is not optional; cannot set to None", attr=self.name, obj=instance, ) return value def equal(self, instance_a, instance_b): a = self.__get__(instance_a, None) b = self.__get__(instance_b, None) if self.equatable: return equal(a, b) else: return a is b def hashvalue(self, instance): """Returns a hashable value (`hash` can be called on the output).""" value = self.__get__(instance, None) if self.equatable: return value else: return id(value)
class Parameter(object): """Simple descriptor for storing configuration parameters. Parameters ---------- default : object The value returned if the parameter hasn't been explicitly set. optional : bool, optional Whether this parameter accepts the value None. By default, parameters are not optional (i.e., cannot be set to ``None``). readonly : bool, optional If true, the parameter can only be set once. By default, parameters can be set multiple times. """ equatable = False def __init__(self, name, default=Unconfigurable, optional=False, readonly=None): # freeze Unconfigurables by default readonly = default is Unconfigurable if readonly is None else readonly if not is_string(name): raise ValueError("'name' must be a string (got %r)" % name) if not isinstance(optional, bool): raise ValueError("'optional' must be boolean (got %r)" % optional) if not isinstance(readonly, bool): raise ValueError("'readonly' must be boolean (got %r)" % readonly) self.name = name self.default = default self.optional = optional self.readonly = readonly # default values set by config system self._defaults = WeakKeyIDDictionary() # param values set on objects self.data = WeakKeyIDDictionary() def __contains__(self, key): return key in self.data or key in self._defaults def __delete__(self, instance): del self.data[instance] def __get__(self, instance, type_): if instance is None: # Return self so default can be inspected return self if not self.configurable and instance not in self.data: raise ValidationError( "Unconfigurable parameters have no defaults. Please ensure the" " value of the parameter is set before trying to access it.", attr=self.name, obj=instance) return self.data.get(instance, self.default) def __set__(self, instance, value): self.validate(instance, value) self.data[instance] = value def __repr__(self): return "%s(default=%s, optional=%s, readonly=%s)" % ( self.__class__.__name__, self.default, self.optional, self.readonly) @property def configurable(self): return self.default is not Unconfigurable def del_default(self, obj): del self._defaults[obj] def get_default(self, obj): return self._defaults.get(obj, self.default) def set_default(self, obj, value): if not self.configurable: raise ConfigError("Parameter '%s' is not configurable" % self) self.validate(obj, value) self._defaults[obj] = value def equal(self, instance_a, instance_b): a = self.__get__(instance_a, None) b = self.__get__(instance_b, None) if self.equatable: # always use array_equal, in case one argument is an array return np.array_equal(a, b) else: return a is b def hashvalue(self, instance): """Returns a hashable value (`hash` can be called on the output).""" value = self.__get__(instance, None) if self.equatable: return value else: return id(value) def validate(self, instance, value): if isinstance(value, DefaultType): raise ValidationError( "Default is not a valid value. To reset a " "parameter, use 'del'.", attr=self.name, obj=instance) if self.readonly and instance in self.data: raise ReadonlyError(attr=self.name, obj=instance) if not self.optional and value is None: raise ValidationError( "Parameter is not optional; cannot set to " "None", attr=self.name, obj=instance)
class Parameter(object): """Simple descriptor for storing configuration parameters. Parameters ---------- default : object The value returned if the parameter hasn't been explicitly set. optional : bool, optional Whether this parameter accepts the value None. By default, parameters are not optional (i.e., cannot be set to ``None``). readonly : bool, optional If true, the parameter can only be set once. By default, parameters can be set multiple times. """ equatable = False def __init__(self, default=Unconfigurable, optional=False, readonly=None): self.default = default self.optional = optional if readonly is None: # freeze Unconfigurables by default readonly = default is Unconfigurable self.readonly = readonly # default values set by config system self._defaults = WeakKeyIDDictionary() # param values set on objects self.data = WeakKeyIDDictionary() def __contains__(self, key): return key in self.data or key in self._defaults def __delete__(self, instance): del self.data[instance] def __get__(self, instance, type_): if instance is None: # Return self so default can be inspected return self if not self.configurable and instance not in self.data: raise ValueError( "Unconfigurable parameters have no defaults. " "Please ensure the value of the parameter is " "set before trying to access it." ) return self.data.get(instance, self.default) def __set__(self, instance, value): self.validate(instance, value) self.data[instance] = value def __repr__(self): return "%s(default=%s, optional=%s, readonly=%s)" % ( self.__class__.__name__, self.default, self.optional, self.readonly, ) @property def configurable(self): return self.default is not Unconfigurable def get_default(self, obj): return self._defaults.get(obj, self.default) def set_default(self, obj, value): if not self.configurable: raise ValueError("Parameter '%s' is not configurable" % self) self.validate(obj, value) self._defaults[obj] = value def del_default(self, obj): del self._defaults[obj] def validate(self, instance, value): if isinstance(value, DefaultType): raise ValueError("Default is not a valid value. To reset a " "parameter, use `del`.") if self.readonly and instance in self.data: raise ValueError("Parameter is read-only; cannot be changed.") if not self.optional and value is None: raise ValueError("Parameter is not optional; cannot set to None") def equal(self, instance_a, instance_b): a = self.__get__(instance_a, None) b = self.__get__(instance_b, None) if self.equatable: # always use array_equal, in case one argument is an array return np.array_equal(a, b) else: return a is b def hashvalue(self, instance): """Returns a hashable value (`hash` can be called on the output).""" value = self.__get__(instance, None) if self.equatable: return value else: return id(value)
def __setstate__(self, state): for k, v in state.items(): if k in ['_defaults', 'data']: v = WeakKeyIDDictionary(v) setattr(self, k, v)
def test_weakkeyiddict_contains_none(): assert (None in WeakKeyIDDictionary()) is False
class Parameter: """Simple descriptor for storing configuration parameters. Parameters ---------- name : str Name of the parameter. default : object The value returned if the parameter hasn't been explicitly set. optional : bool, optional Whether this parameter accepts the value None. By default, parameters are not optional (i.e., cannot be set to ``None``). readonly : bool, optional If true, the parameter can only be set once. By default, parameters can be set multiple times. Attributes ---------- coerce_defaults : bool (Default: True) If True, validate values for this parameter when they are set in a `.Config` object. Setting a parameter directly on an object will always be validated. equatable : bool (Default: False) If True, parameter values can be compared for equality (``a==b``); otherwise equality checks will just compare object identity (``a is b``). """ coerce_defaults = True equatable = False def __init__(self, name, default=Unconfigurable, optional=False, readonly=None): # freeze Unconfigurables by default readonly = default is Unconfigurable if readonly is None else readonly if not isinstance(name, str): raise ValueError("'name' must be a string (got %r)" % name) if not isinstance(optional, bool): raise ValueError("'optional' must be boolean (got %r)" % optional) if not isinstance(readonly, bool): raise ValueError("'readonly' must be boolean (got %r)" % readonly) self.name = name self.default = default self.optional = optional self.readonly = readonly # default values set by config system self._defaults = WeakKeyIDDictionary() # param values set on objects self.data = WeakKeyIDDictionary() def __getstate__(self): state = {} state.update(self.__dict__) state['_defaults'] = dict(state['_defaults'].items()) state['data'] = dict(state['data'].items()) return state def __setstate__(self, state): for k, v in state.items(): if k in ['_defaults', 'data']: v = WeakKeyIDDictionary(v) setattr(self, k, v) def __contains__(self, key): return key in self.data or key in self._defaults def __delete__(self, instance): del self.data[instance] def __get__(self, instance, type_): if instance is None: # Return self so default can be inspected return self if not self.configurable and instance not in self.data: raise ValidationError( "Unconfigurable parameters have no defaults. Please ensure the" " value of the parameter is set before trying to access it.", attr=self.name, obj=instance) return self.data.get(instance, self.default) def __set__(self, instance, value): self.data[instance] = self.coerce(instance, value) def __repr__(self): return "%s(%r, default=%s, optional=%s, readonly=%s)" % ( type(self).__name__, self.name, self.default, self.optional, self.readonly) @property def configurable(self): return self.default is not Unconfigurable def del_default(self, obj): del self._defaults[obj] def get_default(self, obj): return self._defaults.get(obj, self.default) def set_default(self, obj, value): if not self.configurable: raise ConfigError("Parameter '%s' is not configurable" % self) self._defaults[obj] = (self.coerce(obj, value) if self.coerce_defaults else value) def check_type(self, instance, value, type_): if value is not None and not isinstance(value, type_): if isinstance(type_, tuple): type_str = " or ".join((t.__name__ for t in type_)) else: type_str = type_.__name__ raise ValidationError("Must be of type %r (got type %r)." % (type_str, type(value).__name__), attr=self.name, obj=instance) def coerce(self, instance, value): if isinstance(value, DefaultType): raise ValidationError("Default is not a valid value. To reset a " "parameter, use 'del'.", attr=self.name, obj=instance) if self.readonly and instance in self.data: raise ReadonlyError(attr=self.name, obj=instance) if not self.optional and value is None: raise ValidationError("Parameter is not optional; cannot set to " "None", attr=self.name, obj=instance) return value def equal(self, instance_a, instance_b): a = self.__get__(instance_a, None) b = self.__get__(instance_b, None) if self.equatable: return equal(a, b) else: return a is b def hashvalue(self, instance): """Returns a hashable value (`hash` can be called on the output).""" value = self.__get__(instance, None) if self.equatable: return value else: return id(value)
def test_make_weakkeydict_from_dict(): o = C() d = WeakKeyIDDictionary({o: 364}) assert d[o] == 364
def test_make_weakkeydict_from_weakkeydict(): o = C() d1 = WeakKeyIDDictionary({o: 364}) d2 = WeakKeyIDDictionary(d1) assert d1[o] == 364 assert d2[o] == 364