- Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
- Did I choose the right design?
- I could have tried to inherit from one of the existing shelf classes, though the
shelve
module decides at runtime what sort of shelf you should get back fromshelve.open
. - I could have tried to use descriptors to create my own pseudo-properties, sort of like what's done here here, but I don't see a need to decide which fields to include at the class, rather than instance, level
- I could have tried to inherit from one of the existing shelf classes, though the
- Is there any less gross for me to use
__getattr__
and__setattr__
(without having to store a list of fields to be handled as special)? - Did I handle the nested context managers (shelf within
RestrictedShelf
) correctly? Do I need a bunch of try/except logic in__exit__
, as in the fourth example in this answer this answer? - Should I be defining my own exception classes, identical with
Exception
beyond the class name, as I did? - Is making _check_special_keys a class method, rather than a static method, the correct approach?
import shelve
import os
import sys
class UnexpectedKeyError(Exception):
pass
class BadSpecialKey(Exception):
pass
class RestrictedShelf(object):
_SPECIAL_KEYS = ["_filepath", "_keys", "_shelf"]
@classmethod
def _check_special_keys(cls):
for key in cls._SPECIAL_KEYS:
if not key.startswith("_"):
raise BadSpecialKey("Special key does not start with underscore: '{}'".format(key))
def __init__(self, filepath, keys):
self._filepath = filepath
self._keys = list(keys) # Make a copy in case someone modifies the original list
for key in keys:
if not isinstance(key, str):
raise TypeError("String object expected for key, {} found".format(key.__class__.__name__))
# The keys in _SPECIAL_KEYS can't be used, but let's just rule out all keys that start with underscore for good measure
if key.startswith("_"):
raise ValueError("Key illegally starts with underscore: '{}'".format(key))
def __enter__(self):
self._shelf = shelve.open(self._filepath)
for key in self._shelf.keys():
if key not in self._keys:
# This is not quite the same thing as a regular KeyError
raise UnexpectedKeyError(key, "Shelf at '{}' contains unexpected key '{}'".format(self._filepath, key))
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if sys.version_info[0] <= 2:
self._shelf.close()
else:
self._shelf.__exit__(exc_type, exc_val, exc_tb)
def __getattr__(self, key):
self.check_key(key)
return self._shelf.get(key)
def __setattr__(self, key, value):
if key in self._SPECIAL_KEYS:
# httphttps://stackoverflow.com/a/7042247/2829764
super(RestrictedShelf, self).__setattr__(key, value)
else:
self.check_key(key)
self._shelf[key] = value
def check_key(self, key):
if key not in self._keys:
raise KeyError(key)
RestrictedShelf._check_special_keys()
if __name__ == "__main__":
with RestrictedShelf(os.path.expanduser("~/tmp/test.shelf"), "a b c".split()) as rs:
print(rs.a) # `None` the first time you run this; `10` thereafter
rs.a = 10
print(rs.a) # 10
print(rs.b) # None
- Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
- Did I choose the right design?
- I could have tried to inherit from one of the existing shelf classes, though the
shelve
module decides at runtime what sort of shelf you should get back fromshelve.open
. - I could have tried to use descriptors to create my own pseudo-properties, sort of like what's done here, but I don't see a need to decide which fields to include at the class, rather than instance, level
- I could have tried to inherit from one of the existing shelf classes, though the
- Is there any less gross for me to use
__getattr__
and__setattr__
(without having to store a list of fields to be handled as special)? - Did I handle the nested context managers (shelf within
RestrictedShelf
) correctly? Do I need a bunch of try/except logic in__exit__
, as in the fourth example in this answer? - Should I be defining my own exception classes, identical with
Exception
beyond the class name, as I did? - Is making _check_special_keys a class method, rather than a static method, the correct approach?
import shelve
import os
import sys
class UnexpectedKeyError(Exception):
pass
class BadSpecialKey(Exception):
pass
class RestrictedShelf(object):
_SPECIAL_KEYS = ["_filepath", "_keys", "_shelf"]
@classmethod
def _check_special_keys(cls):
for key in cls._SPECIAL_KEYS:
if not key.startswith("_"):
raise BadSpecialKey("Special key does not start with underscore: '{}'".format(key))
def __init__(self, filepath, keys):
self._filepath = filepath
self._keys = list(keys) # Make a copy in case someone modifies the original list
for key in keys:
if not isinstance(key, str):
raise TypeError("String object expected for key, {} found".format(key.__class__.__name__))
# The keys in _SPECIAL_KEYS can't be used, but let's just rule out all keys that start with underscore for good measure
if key.startswith("_"):
raise ValueError("Key illegally starts with underscore: '{}'".format(key))
def __enter__(self):
self._shelf = shelve.open(self._filepath)
for key in self._shelf.keys():
if key not in self._keys:
# This is not quite the same thing as a regular KeyError
raise UnexpectedKeyError(key, "Shelf at '{}' contains unexpected key '{}'".format(self._filepath, key))
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if sys.version_info[0] <= 2:
self._shelf.close()
else:
self._shelf.__exit__(exc_type, exc_val, exc_tb)
def __getattr__(self, key):
self.check_key(key)
return self._shelf.get(key)
def __setattr__(self, key, value):
if key in self._SPECIAL_KEYS:
# http://stackoverflow.com/a/7042247/2829764
super(RestrictedShelf, self).__setattr__(key, value)
else:
self.check_key(key)
self._shelf[key] = value
def check_key(self, key):
if key not in self._keys:
raise KeyError(key)
RestrictedShelf._check_special_keys()
if __name__ == "__main__":
with RestrictedShelf(os.path.expanduser("~/tmp/test.shelf"), "a b c".split()) as rs:
print(rs.a) # `None` the first time you run this; `10` thereafter
rs.a = 10
print(rs.a) # 10
print(rs.b) # None
- Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
- Did I choose the right design?
- I could have tried to inherit from one of the existing shelf classes, though the
shelve
module decides at runtime what sort of shelf you should get back fromshelve.open
. - I could have tried to use descriptors to create my own pseudo-properties, sort of like what's done here, but I don't see a need to decide which fields to include at the class, rather than instance, level
- I could have tried to inherit from one of the existing shelf classes, though the
- Is there any less gross for me to use
__getattr__
and__setattr__
(without having to store a list of fields to be handled as special)? - Did I handle the nested context managers (shelf within
RestrictedShelf
) correctly? Do I need a bunch of try/except logic in__exit__
, as in the fourth example in this answer? - Should I be defining my own exception classes, identical with
Exception
beyond the class name, as I did? - Is making _check_special_keys a class method, rather than a static method, the correct approach?
import shelve
import os
import sys
class UnexpectedKeyError(Exception):
pass
class BadSpecialKey(Exception):
pass
class RestrictedShelf(object):
_SPECIAL_KEYS = ["_filepath", "_keys", "_shelf"]
@classmethod
def _check_special_keys(cls):
for key in cls._SPECIAL_KEYS:
if not key.startswith("_"):
raise BadSpecialKey("Special key does not start with underscore: '{}'".format(key))
def __init__(self, filepath, keys):
self._filepath = filepath
self._keys = list(keys) # Make a copy in case someone modifies the original list
for key in keys:
if not isinstance(key, str):
raise TypeError("String object expected for key, {} found".format(key.__class__.__name__))
# The keys in _SPECIAL_KEYS can't be used, but let's just rule out all keys that start with underscore for good measure
if key.startswith("_"):
raise ValueError("Key illegally starts with underscore: '{}'".format(key))
def __enter__(self):
self._shelf = shelve.open(self._filepath)
for key in self._shelf.keys():
if key not in self._keys:
# This is not quite the same thing as a regular KeyError
raise UnexpectedKeyError(key, "Shelf at '{}' contains unexpected key '{}'".format(self._filepath, key))
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if sys.version_info[0] <= 2:
self._shelf.close()
else:
self._shelf.__exit__(exc_type, exc_val, exc_tb)
def __getattr__(self, key):
self.check_key(key)
return self._shelf.get(key)
def __setattr__(self, key, value):
if key in self._SPECIAL_KEYS:
# https://stackoverflow.com/a/7042247/2829764
super(RestrictedShelf, self).__setattr__(key, value)
else:
self.check_key(key)
self._shelf[key] = value
def check_key(self, key):
if key not in self._keys:
raise KeyError(key)
RestrictedShelf._check_special_keys()
if __name__ == "__main__":
with RestrictedShelf(os.path.expanduser("~/tmp/test.shelf"), "a b c".split()) as rs:
print(rs.a) # `None` the first time you run this; `10` thereafter
rs.a = 10
print(rs.a) # 10
print(rs.b) # None
kuzzooroo
- 369
- 2
- 10
- Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
- Did I choose the right design?
- I could have tried to inherit from one of the existing shelf classes, though the
shelve
module decides at runtime what sort of shelf you should get back fromshelve.open
. - I could have tried to use descriptors to create my own pseudo-properties, sort of like what's done here, but I don't see a need to decide which fields to include at the instanceclass, rather than classinstance, level
- I could have tried to inherit from one of the existing shelf classes, though the
- Is there any less gross for me to use
__getattr__
and__setattr__
(without having to store a list of fields to be handled as special)? - Did I handle the nested context managers (shelf within
RestrictedShelf
) correctly? Do I need a bunch of try/except logic in__exit__
, as in the fourth example in this answer? - Should I be defining my own exception classes, identical with
Exception
beyond the class name, as I did? - Is making _check_special_keys a class method, rather than a static method, the correct approach?
- Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
- Did I choose the right design?
- I could have tried to inherit from one of the existing shelf classes, though the
shelve
module decides at runtime what sort of shelf you should get back fromshelve.open
. - I could have tried to use descriptors to create my own pseudo-properties, sort of like what's done here, but I don't see a need to decide which fields to include at the instance, rather than class, level
- I could have tried to inherit from one of the existing shelf classes, though the
- Is there any less gross for me to use
__getattr__
and__setattr__
(without having to store a list of fields to be handled as special)? - Did I handle the nested context managers (shelf within
RestrictedShelf
) correctly? Do I need a bunch of try/except logic in__exit__
, as in the fourth example in this answer? - Should I be defining my own exception classes, identical with
Exception
beyond the class name, as I did? - Is making _check_special_keys a class method, rather than a static method, the correct approach?
- Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
- Did I choose the right design?
- I could have tried to inherit from one of the existing shelf classes, though the
shelve
module decides at runtime what sort of shelf you should get back fromshelve.open
. - I could have tried to use descriptors to create my own pseudo-properties, sort of like what's done here, but I don't see a need to decide which fields to include at the class, rather than instance, level
- I could have tried to inherit from one of the existing shelf classes, though the
- Is there any less gross for me to use
__getattr__
and__setattr__
(without having to store a list of fields to be handled as special)? - Did I handle the nested context managers (shelf within
RestrictedShelf
) correctly? Do I need a bunch of try/except logic in__exit__
, as in the fourth example in this answer? - Should I be defining my own exception classes, identical with
Exception
beyond the class name, as I did? - Is making _check_special_keys a class method, rather than a static method, the correct approach?
Moved check on _SPECIAL_KEYS to a class method that is run only once, at import time
kuzzooroo
- 369
- 2
- 10
Loading
lang-py