New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DM-13349: Define storage classes in config yaml #11
Conversation
timj
commented
Jan 31, 2018
- Moved the formatter factory registry to a new class MappingFactory.
- Allow the factory registry to take classes as well as string definitions.
- Replace StorageClass definitions in code with a new registry and ability to dynamically create them from strings.
- Update posix data store to dynamically generate storage classes from the YAML.
- Update tests to read storage classes from factory.
* Moved the formatter factory registry to a new class MappingFactory. * Allow the factory registry to take classes as well as string definitions. * Replace StorageClass definitions in code with a new registry and ability to dynamically create them from strings. * Update posix data store to dynamically generate storage classes from the YAML. * Update tests to read storage classes from factory.
pass | ||
typeName = self._registry[self._getName(storageClass)] | ||
return self._getInstanceOf(typeName) | ||
return self.getFromRegistry(storageClass, override=datasetType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can switch this to using composition if you prefer since the get and put methods do not have the same names as the base class implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that way we can also get rid of my other gripe (having refType
specified) and move that to an argument (e.g. self.mappingFactory = MappingFactory(Formatter)
).
Originally in python/lsst/daf/persistence/utils.py
I've also relocated |
We are using one of the functions and core daf_butler should not directly depend on daf_persistence. Transferring the whole file for now since we might use a function.
053674c
to
6560499
Compare
""" | ||
|
||
refType = None | ||
"""Type of instances expected to be returned from factory.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be documented in the attributes
section of the class documentation instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I spent ten minutes reading numpydoc documentation and this seemed to be the way they wanted me to document class attributes. I admit it was somewhat unclear to me (and I'm about to delete that line anyhow).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I read the numpydoc docs again I see the attributes
section (as opposed to parameters
for __init__
).
tests/config/basic/butler.yaml
Outdated
photoCalib: "TablePersistable" | ||
visitInfo: "TablePersistable" | ||
apCorr: "TablePersistable" | ||
coaddInputs: "TablePersistable" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the quotes needed for the component storage classes? I'd like to specify them without quotes (or as YAML
references), since they are internal references. Oh, and we better hope they don't become circular ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can remove the quotes. Making them YAML references is something I'd have to look at (currently I need them to be strings to look up in the registry rather than items to look up from the YAML tree).
tests/test_formatter.py
Outdated
storageClassName = "Image" | ||
self.factory.registerFormatter(storageClassName, formatterName) | ||
f = self.factory.getFormatter(storageClassName) | ||
self.assertIsInstance(f, formatter.Formatter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also test the explicit subclass type?
tests/test_formatter.py
Outdated
|
||
with self.assertRaises(ValueError): | ||
# Try to store something that is not a Formatter but is a class | ||
self.factory.registerFormatter("NotFormatter", "lsst.daf.butler.core.formatter.FormatterFactory") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be misleading if a value error is raised on the first argument instead of the second. Better reuse the same working identifier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean the cases where "NotFormatter" is in the registry already? Shame I can't use KeyError
for the "key already in use" error. What do you mean by "same working identifier"?
tests/test_formatter.py
Outdated
self.factory.registerFormatter("NotFormatter", "lsst.daf.butler") | ||
|
||
with self.assertRaises(ValueError): | ||
# Try to store something that is not a Formatter but does not exist |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and does not exist.
tests/test_storageClass.py
Outdated
self.assertIsInstance(sc, storageClass.StorageClass) | ||
self.assertEqual(sc.name, className) | ||
self.assertIsNone(sc.components) | ||
self.assertEqual(sc.type, dict) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ptype
/ pytype
here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did change all the type
attributes to pytype
at one point but then changed them back because I wasn't entirely sure that type
was a bad name for the attribute (and keeping it meant changing less code). I'm fine with making it explicitly pytype
so there is no confusion as to what the storage class is referring to.
tests/test_storageClass.py
Outdated
self.assertEqual(sc.type, dict) | ||
|
||
# Check that this class is listed in the subclasses | ||
self.assertIn(className, newclass.subclasses) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we moved the registry to an explicit factory, I don't think we need StorageClass
's 'fancy' metaclass registration anymore (so subclasses
and components dict
can go I think).
It used to be responsible for mapping names to instances, but non-configurable and without overrides.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might leave it in for a little just in case I have a problem where I need a storage class that has been made concrete somewhere else but is not in this registry.
tests/test_storageClass.py
Outdated
|
||
|
||
class PythonType: | ||
"""A dummy class to test the registory of Python types.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
registry
?
pass | ||
typeName = self._registry[self._getName(storageClass)] | ||
return self._getInstanceOf(typeName) | ||
return self.getFromRegistry(storageClass, override=datasetType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that way we can also get rid of my other gripe (having refType
specified) and move that to an argument (e.g. self.mappingFactory = MappingFactory(Formatter)
).
Get item from registry associated with this target class, unless | ||
override : `str` or object supporting `.name` attribute, optional | ||
If given, look if an override has been specified for this and, | ||
if so return that instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps make it slightly more generic? By taking *targetClasses
and thus allowing for multiple overrides?