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('') | str = type('') | ||||||
|  |  | ||||||
| import cmath | import cmath | ||||||
|  | import collections | ||||||
|  | import operator | ||||||
|  | import functools | ||||||
|  |  | ||||||
|  |  | ||||||
| # Back-ported from python 3.5; see | # Back-ported from python 3.5; see | ||||||
| @@ -51,3 +54,30 @@ def median(data): | |||||||
|         i = n // 2 |         i = n // 2 | ||||||
|         return (data[i - 1] + data[i]) / 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, |     GPIOPinInUse, | ||||||
|     GPIODeviceClosed, |     GPIODeviceClosed, | ||||||
|     ) |     ) | ||||||
|  | from .compat import frozendict | ||||||
|  |  | ||||||
| # Get a pin implementation to use as the default; we prefer RPi.GPIO's here | # 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 | # 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): |     def __init__(self, *args, **kwargs): | ||||||
|         self._all = () |         self._all = () | ||||||
|         self._named = {} |         self._named = frozendict({}) | ||||||
|         self._namedtuple = None |         self._namedtuple = None | ||||||
|         self._order = kwargs.pop('_order', None) |         self._order = kwargs.pop('_order', None) | ||||||
|         if self._order is None: |         if self._order is None: | ||||||
| @@ -278,7 +279,7 @@ class CompositeDevice(Device): | |||||||
|         for dev in self._all: |         for dev in self._all: | ||||||
|             if not isinstance(dev, Device): |             if not isinstance(dev, Device): | ||||||
|                 raise CompositeDeviceBadDevice("%s doesn't inherit from Device" % dev) |                 raise CompositeDeviceBadDevice("%s doesn't inherit from Device" % dev) | ||||||
|         self._named = kwargs |         self._named = frozendict(kwargs) | ||||||
|         self._namedtuple = namedtuple('%sValue' % self.__class__.__name__, chain( |         self._namedtuple = namedtuple('%sValue' % self.__class__.__name__, chain( | ||||||
|             (str(i) for i in range(len(args))), self._order), |             (str(i) for i in range(len(args))), self._order), | ||||||
|             rename=True) |             rename=True) | ||||||
| @@ -286,7 +287,7 @@ class CompositeDevice(Device): | |||||||
|     def __getattr__(self, name): |     def __getattr__(self, name): | ||||||
|         # if _named doesn't exist yet, pretend it's an empty dict |         # if _named doesn't exist yet, pretend it's an empty dict | ||||||
|         if name == '_named': |         if name == '_named': | ||||||
|             return {} |             return frozendict({}) | ||||||
|         try: |         try: | ||||||
|             return self._named[name] |             return self._named[name] | ||||||
|         except KeyError: |         except KeyError: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user