forked from ungleich-public/cdist
		
	completely rewrite file based property handling
Signed-off-by: Steven Armstrong <steven@icarus.ethz.ch>
This commit is contained in:
		
					parent
					
						
							
								be02dc5ff1
							
						
					
				
			
			
				commit
				
					
						ede35ffd73
					
				
			
		
					 1 changed files with 76 additions and 149 deletions
				
			
		|  | @ -98,55 +98,6 @@ class FileList(collections.MutableSequence): | ||||||
|         self.__write(lines) |         self.__write(lines) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class FileListProperty(FileList): |  | ||||||
| 
 |  | ||||||
|     def __init__(self, path): |  | ||||||
|         """ |  | ||||||
|         :param path: string or callable |  | ||||||
| 
 |  | ||||||
|         Usage: |  | ||||||
| 
 |  | ||||||
|         class Foo(object): |  | ||||||
|             parameters = DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) |  | ||||||
|             other_dict = DirectoryDictProperty('/tmp/folder') |  | ||||||
| 
 |  | ||||||
|             def __init__(self): |  | ||||||
|                 self.absolute_path = '/tmp/foo' |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self.path = None |  | ||||||
|         self.__path = path |  | ||||||
| 
 |  | ||||||
|     def _set_path(self, *args, **kwargs): |  | ||||||
|         if self.path is None: |  | ||||||
|             path = self.__path |  | ||||||
|             if callable(path): |  | ||||||
|                 path = path(*args, **kwargs) |  | ||||||
|             if not os.path.isabs(path): |  | ||||||
|                 raise AbsolutePathRequiredError(path) |  | ||||||
|             self.path = path |  | ||||||
| 
 |  | ||||||
|     # Descriptor Protocol |  | ||||||
|     def __get__(self, obj, objtype=None): |  | ||||||
|         if obj is None: |  | ||||||
|             return self.__class__ |  | ||||||
|         self._set_path(obj) |  | ||||||
|         return self |  | ||||||
| 
 |  | ||||||
|     def __set__(self, obj, value): |  | ||||||
|         self._set_path(obj) |  | ||||||
|         try: |  | ||||||
|             os.unlink(self.path) |  | ||||||
|         except EnvironmentError: |  | ||||||
|             # ignored |  | ||||||
|             pass |  | ||||||
|         for item in value: |  | ||||||
|             self.append(item) |  | ||||||
| 
 |  | ||||||
|     def __delete__(self, obj): |  | ||||||
|         raise AttributeError("can't delete attribute") |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DirectoryDict(collections.MutableMapping): | class DirectoryDict(collections.MutableMapping): | ||||||
|     """A dict that stores it's items as files in a directory. |     """A dict that stores it's items as files in a directory. | ||||||
| 
 | 
 | ||||||
|  | @ -178,7 +129,10 @@ class DirectoryDict(collections.MutableMapping): | ||||||
|             fd.write(str(value))         |             fd.write(str(value))         | ||||||
| 
 | 
 | ||||||
|     def __delitem__(self, key): |     def __delitem__(self, key): | ||||||
|  |         try: | ||||||
|             os.remove(os.path.join(self.path, key)) |             os.remove(os.path.join(self.path, key)) | ||||||
|  |         except EnvironmentError: | ||||||
|  |             raise KeyError(key) | ||||||
| 
 | 
 | ||||||
|     def __iter__(self): |     def __iter__(self): | ||||||
|         return iter(os.listdir(self.path)) |         return iter(os.listdir(self.path)) | ||||||
|  | @ -187,95 +141,98 @@ class DirectoryDict(collections.MutableMapping): | ||||||
|         return len(os.listdir(self.path)) |         return len(os.listdir(self.path)) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class DirectoryDictProperty(DirectoryDict): | class FileBasedProperty(object): | ||||||
|  |     attribute_class = None | ||||||
| 
 | 
 | ||||||
|     def __init__(self, path): |     def __init__(self, path): | ||||||
|         """ |         """ | ||||||
|         :param path: string or callable |         :param path: string or callable | ||||||
| 
 | 
 | ||||||
|         Usage: |         Abstract super class. Subclass and set the class member attribute_class accordingly. | ||||||
|  | 
 | ||||||
|  |         Usage with a sublcass: | ||||||
| 
 | 
 | ||||||
|         class Foo(object): |         class Foo(object): | ||||||
|             parameters = DirectoryDictProperty(lambda obj: os.path.join(obj.absolute_path, 'parameter')) |             # note that the actual DirectoryDict is stored as __parameters on the instance | ||||||
|             other_dict = DirectoryDictProperty('/tmp/folder') |             parameters = DirectoryDictProperty(lambda instance: os.path.join(instance.absolute_path, 'parameter')) | ||||||
|  |             # note that the actual DirectoryDict is stored as __other_dict on the instance | ||||||
|  |             other_dict = DirectoryDictProperty('/tmp/other_dict') | ||||||
| 
 | 
 | ||||||
|             def __init__(self): |             def __init__(self): | ||||||
|                 self.absolute_path = '/tmp/foo' |                 self.absolute_path = '/tmp/foo' | ||||||
| 
 | 
 | ||||||
|         """ |         """ | ||||||
|         self.path = None |  | ||||||
|         self.__path = path |  | ||||||
| 
 |  | ||||||
|     def _set_path(self, *args, **kwargs): |  | ||||||
|         #print("_set_path: self: %s" % self) |  | ||||||
|         print("_set_path: args: %s" % args) |  | ||||||
|         print("_set_path: kwargs: %s" % kwargs) |  | ||||||
|         print("_set_path: self.path: %s" % self.path) |  | ||||||
|         if self.path is None: |  | ||||||
|             path = self.__path |  | ||||||
|             if callable(path): |  | ||||||
|                 path = path(*args, **kwargs) |  | ||||||
|             print("_set_path: %s" % path) |  | ||||||
|             if not os.path.isabs(path): |  | ||||||
|                 raise AbsolutePathRequiredError(path) |  | ||||||
|             # create directory if it doesn't exist |  | ||||||
|             print("os.path.isdir(%s): %s" % (path, os.path.isdir(path))) |  | ||||||
|             if not os.path.isdir(path): |  | ||||||
|                 os.mkdir(path) |  | ||||||
|         self.path = path |         self.path = path | ||||||
| 
 | 
 | ||||||
|     # Descriptor Protocol |     def _get_path(self, instance): | ||||||
|     def __get__(self, obj, objtype=None): |         path = self.path | ||||||
|         if obj is None: |         if callable(path): | ||||||
|             return self.__class__ |             path = path(instance) | ||||||
|         self._set_path(obj) |         return path | ||||||
|  | 
 | ||||||
|  |     def _get_property_name(self, owner): | ||||||
|  |         for name, prop in owner.__dict__.items(): | ||||||
|  |             if self == prop: | ||||||
|  |                 return name | ||||||
|  | 
 | ||||||
|  |     def _get_attribute(self, instance, owner): | ||||||
|  |         name = self._get_property_name(owner) | ||||||
|  |         attribute_name = '__%s' % name | ||||||
|  |         if not hasattr(instance, attribute_name): | ||||||
|  |             path = self._get_path(instance) | ||||||
|  |             attribute_instance = self.attribute_class(path) | ||||||
|  |             setattr(instance, attribute_name, attribute_instance) | ||||||
|  |         return getattr(instance, attribute_name) | ||||||
|  | 
 | ||||||
|  |     def __get__(self, instance, owner): | ||||||
|  |         if instance is None: | ||||||
|             return self |             return self | ||||||
|  |         return self._get_attribute(instance, owner) | ||||||
| 
 | 
 | ||||||
|     def __set__(self, obj, value): |     def __delete__(self, instance): | ||||||
|         self._set_path(obj) |  | ||||||
|         if value is not None: |  | ||||||
|             for name in self.keys(): |  | ||||||
|                 del self[name] |  | ||||||
|             self.update(value) |  | ||||||
| 
 |  | ||||||
|     def __delete__(self, obj): |  | ||||||
|         raise AttributeError("can't delete attribute") |         raise AttributeError("can't delete attribute") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class FileBooleanProperty(object): | class DirectoryDictProperty(FileBasedProperty): | ||||||
|     def __init__(self, path): |     attribute_class = DirectoryDict | ||||||
|  | 
 | ||||||
|  |     def __set__(self, instance, value): | ||||||
|  |         attribute_instance = self._get_attribute(instance, instance.__class__) | ||||||
|  |         for name in attribute_instance.keys(): | ||||||
|  |             del attribute_instance[name] | ||||||
|  |         attribute_instance.update(value) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class FileListProperty(FileBasedProperty): | ||||||
|  |     attribute_class = FileList | ||||||
|  | 
 | ||||||
|  |     def __set__(self, instance, value): | ||||||
|  |         path = self._get_path(instance) | ||||||
|  |         try: | ||||||
|  |             os.unlink(path) | ||||||
|  |         except EnvironmentError: | ||||||
|  |             # ignored | ||||||
|  |             pass | ||||||
|  |         attribute_instance = self._get_attribute(instance, instance.__class__) | ||||||
|  |         for item in value: | ||||||
|  |             attribute_instance.append(item) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class FileBooleanProperty(FileBasedProperty): | ||||||
|  |     """A boolean property which uses a file to represent its value. | ||||||
|  | 
 | ||||||
|  |     File exists -> True | ||||||
|  |     File does not exists -> False | ||||||
|     """ |     """ | ||||||
|         :param path: string or callable |  | ||||||
| 
 |  | ||||||
|         Usage: |  | ||||||
| 
 |  | ||||||
|         class Foo(object): |  | ||||||
|             changed = FileBoolean(lambda obj: os.path.join(obj.absolute_path, 'changed')) |  | ||||||
|             other_boolean = FileBoolean('/tmp/other_boolean') |  | ||||||
| 
 |  | ||||||
|             def __init__(self): |  | ||||||
|                 self.absolute_path = '/tmp/foo_boolean' |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self._path = path |  | ||||||
| 
 |  | ||||||
|     def _get_path(self, *args, **kwargs): |  | ||||||
|         path = self._path |  | ||||||
|         if callable(path): |  | ||||||
|             return path(*args, **kwargs) |  | ||||||
|         if not os.path.isabs(path): |  | ||||||
|             raise AbsolutePathRequiredError(path) |  | ||||||
|         return path |  | ||||||
| 
 |  | ||||||
|     # Descriptor Protocol |     # Descriptor Protocol | ||||||
|     def __get__(self, obj, objtype=None): |     def __get__(self, instance, owner): | ||||||
|         if obj is None: |         if instance is None: | ||||||
|             return self.__class__ |             return self | ||||||
|         path = self._get_path(obj) |         path = self._get_path(instance) | ||||||
|         return os.path.isfile(path) |         return os.path.isfile(path) | ||||||
| 
 | 
 | ||||||
|     def __set__(self, obj, value): |     def __set__(self, instance, value): | ||||||
|         path = self._get_path(obj) |         path = self._get_path(instance) | ||||||
|         if value: |         if value: | ||||||
|             open(path, "w").close() |             open(path, "w").close() | ||||||
|         else: |         else: | ||||||
|  | @ -285,42 +242,15 @@ class FileBooleanProperty(object): | ||||||
|                 # ignore |                 # ignore | ||||||
|                 pass |                 pass | ||||||
| 
 | 
 | ||||||
|     def __delete__(self, obj): |  | ||||||
|         raise AttributeError("can't delete attribute") |  | ||||||
| 
 | 
 | ||||||
| 
 | class FileStringProperty(FileBasedProperty): | ||||||
| class FileStringProperty(object): |  | ||||||
|     """A string property which stores its value in a file. |     """A string property which stores its value in a file. | ||||||
|     """ |     """ | ||||||
|     def __init__(self, path): |  | ||||||
|         """ |  | ||||||
|         :param path: string or callable |  | ||||||
| 
 |  | ||||||
|         Usage: |  | ||||||
| 
 |  | ||||||
|         class Foo(object): |  | ||||||
|             source = FileStringProperty(lambda obj: os.path.join(obj.absolute_path, 'source')) |  | ||||||
|             other = FileStringProperty('/tmp/other') |  | ||||||
| 
 |  | ||||||
|             def __init__(self): |  | ||||||
|                 self.absolute_path = '/tmp/foo_boolean' |  | ||||||
| 
 |  | ||||||
|         """ |  | ||||||
|         self._path = path |  | ||||||
| 
 |  | ||||||
|     def _get_path(self, *args, **kwargs): |  | ||||||
|         path = self._path |  | ||||||
|         if callable(path): |  | ||||||
|             return path(*args, **kwargs) |  | ||||||
|         if not os.path.isabs(path): |  | ||||||
|             raise AbsolutePathRequiredError(path) |  | ||||||
|         return path |  | ||||||
| 
 |  | ||||||
|     # Descriptor Protocol |     # Descriptor Protocol | ||||||
|     def __get__(self, obj, objtype=None): |     def __get__(self, instance, owner): | ||||||
|         if obj is None: |         if instance is None: | ||||||
|             return self.__class__ |             return self | ||||||
|         path = self._get_path(obj) |         path = self._get_path(instance) | ||||||
|         value = "" |         value = "" | ||||||
|         try: |         try: | ||||||
|             with open(path, "r") as fd: |             with open(path, "r") as fd: | ||||||
|  | @ -329,16 +259,13 @@ class FileStringProperty(object): | ||||||
|             pass |             pass | ||||||
|         return value |         return value | ||||||
| 
 | 
 | ||||||
|     def __set__(self, obj, value): |     def __set__(self, instance, value): | ||||||
|         path = self._get_path(obj) |         path = self._get_path(instance) | ||||||
|         if value: |         if value: | ||||||
|             with open(path, "w") as fd: |             with open(path, "w") as fd: | ||||||
|                 fd.write(str(value)) |                 fd.write(str(value)) | ||||||
|         else: |         else: | ||||||
|             try: |             try: | ||||||
|                 os.unlink(path) |                 os.remove(path) | ||||||
|             except EnvironmentError: |             except EnvironmentError: | ||||||
|                 pass |                 pass | ||||||
| 
 |  | ||||||
|     def __delete__(self, obj): |  | ||||||
|         raise AttributeError("Can't delete attribute. Set it's value to an empty string to remove the underlying file.") |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue