mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	Make CompositeDevice._named a frozendict (and add frozendict to compat.py)
This prevents it being modified post-construction (just like the way CompositeDevice._all and CompositeDevice._order are already 'frozen' by being tuples)
This commit is contained in:
		| @@ -9,6 +9,9 @@ from __future__ import ( | ||||
| str = type('') | ||||
|  | ||||
| import cmath | ||||
| import collections | ||||
| import operator | ||||
| import functools | ||||
|  | ||||
|  | ||||
| # Back-ported from python 3.5; see | ||||
| @@ -51,3 +54,30 @@ def median(data): | ||||
|         i = n // 2 | ||||
|         return (data[i - 1] + data[i]) / 2 | ||||
|  | ||||
|  | ||||
| # Copied from the MIT-licensed https://github.com/slezica/python-frozendict | ||||
| class frozendict(collections.Mapping): | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         self.__dict = dict(*args, **kwargs) | ||||
|         self.__hash = None | ||||
|  | ||||
|     def __getitem__(self, key): | ||||
|         return self.__dict[key] | ||||
|  | ||||
|     def copy(self, **add_or_replace): | ||||
|         return frozendict(self, **add_or_replace) | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return iter(self.__dict) | ||||
|  | ||||
|     def __len__(self): | ||||
|         return len(self.__dict) | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return '<frozendict %s>' % repr(self.__dict) | ||||
|  | ||||
|     def __hash__(self): | ||||
|         if self.__hash is None: | ||||
|             hashes = map(hash, self.items()) | ||||
|             self.__hash = functools.reduce(operator.xor, hashes, 0) | ||||
|         return self.__hash | ||||
|   | ||||
| @@ -28,6 +28,7 @@ from .exc import ( | ||||
|     GPIOPinInUse, | ||||
|     GPIODeviceClosed, | ||||
|     ) | ||||
| from .compat import frozendict | ||||
|  | ||||
| # Get a pin implementation to use as the default; we prefer RPi.GPIO's here | ||||
| # as it supports PWM, and all Pi revisions. If no third-party libraries are | ||||
| @@ -263,7 +264,7 @@ class CompositeDevice(Device): | ||||
|     """ | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         self._all = () | ||||
|         self._named = {} | ||||
|         self._named = frozendict({}) | ||||
|         self._namedtuple = None | ||||
|         self._order = kwargs.pop('_order', None) | ||||
|         if self._order is None: | ||||
| @@ -278,7 +279,7 @@ class CompositeDevice(Device): | ||||
|         for dev in self._all: | ||||
|             if not isinstance(dev, Device): | ||||
|                 raise CompositeDeviceBadDevice("%s doesn't inherit from Device" % dev) | ||||
|         self._named = kwargs | ||||
|         self._named = frozendict(kwargs) | ||||
|         self._namedtuple = namedtuple('%sValue' % self.__class__.__name__, chain( | ||||
|             (str(i) for i in range(len(args))), self._order), | ||||
|             rename=True) | ||||
| @@ -286,7 +287,7 @@ class CompositeDevice(Device): | ||||
|     def __getattr__(self, name): | ||||
|         # if _named doesn't exist yet, pretend it's an empty dict | ||||
|         if name == '_named': | ||||
|             return {} | ||||
|             return frozendict({}) | ||||
|         try: | ||||
|             return self._named[name] | ||||
|         except KeyError: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user