Skip to main content
Code Review

Return to Question

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link
  1. Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
  2. Did I choose the right design?
    1. 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 from shelve.open.
    2. 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
  3. 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)?
  4. 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?
  5. Should I be defining my own exception classes, identical with Exception beyond the class name, as I did?
  6. 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
  1. Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
  2. Did I choose the right design?
    1. 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 from shelve.open.
    2. 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
  3. 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)?
  4. 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?
  5. Should I be defining my own exception classes, identical with Exception beyond the class name, as I did?
  6. 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
  1. Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
  2. Did I choose the right design?
    1. 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 from shelve.open.
    2. 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
  3. 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)?
  4. 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?
  5. Should I be defining my own exception classes, identical with Exception beyond the class name, as I did?
  6. 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
Swapped /instance/class/ which were backwards at one point in the text
Source Link
kuzzooroo
  • 369
  • 2
  • 10
  1. Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
  2. Did I choose the right design?
    1. 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 from shelve.open.
    2. 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
  3. 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)?
  4. 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?
  5. Should I be defining my own exception classes, identical with Exception beyond the class name, as I did?
  6. Is making _check_special_keys a class method, rather than a static method, the correct approach?
  1. Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
  2. Did I choose the right design?
    1. 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 from shelve.open.
    2. 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
  3. 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)?
  4. 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?
  5. Should I be defining my own exception classes, identical with Exception beyond the class name, as I did?
  6. Is making _check_special_keys a class method, rather than a static method, the correct approach?
  1. Is there an easier way I could have accomplished this using built-in stuff or widely used libraries?
  2. Did I choose the right design?
    1. 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 from shelve.open.
    2. 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
  3. 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)?
  4. 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?
  5. Should I be defining my own exception classes, identical with Exception beyond the class name, as I did?
  6. Is making _check_special_keys a class method, rather than a static method, the correct approach?
edited tags
Link
200_success
  • 145.5k
  • 22
  • 190
  • 478
Moved check on _SPECIAL_KEYS to a class method that is run only once, at import time
Source Link
kuzzooroo
  • 369
  • 2
  • 10
Loading
deleted 1 character in body
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238
Loading
Source Link
kuzzooroo
  • 369
  • 2
  • 10
Loading
lang-py

AltStyle によって変換されたページ (->オリジナル) /