Skip to content
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-25153: Remove _ components from class path name when determining full type name #294

Merged
merged 2 commits into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 11 additions & 6 deletions python/lsst/daf/butler/core/fileTemplates.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,14 +553,15 @@ def format(self, ref: DatasetRef) -> str:

return path

def validateTemplate(self, entity: Union[DatasetRef, DatasetType, StorageClass]) -> None:
def validateTemplate(self, entity: Union[DatasetRef, DatasetType, StorageClass, None]) -> None:
"""Compare the template against a representative entity that would
like to use template.

Parameters
----------
entity : `DatasetType`, `DatasetRef`, or `StorageClass`
Entity to compare against template.
Entity to compare against template. If `None` is given only
very basic validation of templates will be performed.

Raises
------
Expand Down Expand Up @@ -596,7 +597,9 @@ def validateTemplate(self, entity: Union[DatasetRef, DatasetType, StorageClass])
# is present in the template. If the entity is not a component
# make sure that component is not mandatory.
try:
if entity.isComponent():
# mypy does not see the except block so complains about
# StorageClass not supporting isComponent
if entity.isComponent(): # type: ignore
if "component" not in withSpecials:
raise FileTemplateValidationError(f"Template '{self}' has no component but "
f"{entity} refers to a component.")
Expand All @@ -611,12 +614,14 @@ def validateTemplate(self, entity: Union[DatasetRef, DatasetType, StorageClass])
# Get the dimension links to get the full set of available field names
# Fall back to dataId keys if we have them but no links.
# dataId keys must still be present in the template
# Ignore warnings from mypy concerning StorageClass and DatasetType
# not supporting the full API.
try:
minimal = set(entity.dimensions.required.names)
maximal = set(entity.dimensions.names)
minimal = set(entity.dimensions.required.names) # type: ignore
maximal = set(entity.dimensions.names) # type: ignore
except AttributeError:
try:
minimal = set(entity.dataId.keys())
minimal = set(entity.dataId.keys()) # type: ignore
maximal = minimal
except AttributeError:
return
Expand Down
26 changes: 24 additions & 2 deletions python/lsst/daf/butler/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,37 @@ def getFullTypeName(cls: Any) -> str:
Notes
-----
Builtins are returned without the ``builtins`` specifier included. This
allows `str` to be returned as "str" rather than "builtins.str".
allows `str` to be returned as "str" rather than "builtins.str". Any
parts of the path that start with a leading underscore are removed
on the assumption that they are an implementation detail and the
entity will be hoisted into the parent namespace.
"""
# If we have an instance we need to convert to a type
if not hasattr(cls, "__qualname__"):
cls = type(cls)
if hasattr(builtins, cls.__qualname__):
# Special case builtins such as str and dict
return cls.__qualname__
return cls.__module__ + "." + cls.__qualname__

real_name = cls.__module__ + "." + cls.__qualname__

# Remove components with leading underscores
cleaned_name = ".".join(c for c in real_name.split(".") if not c.startswith("_"))

# Consistency check
if real_name != cleaned_name:
try:
test = doImport(cleaned_name)
except Exception:
# Could not import anything so return the real name
return real_name

# The thing we imported should match the class we started with
# despite the clean up. If it does not we return the real name
if test is not cls:
return real_name

return cleaned_name


def getClassOf(typeOrName: Union[Type, str]) -> Type:
Expand Down
3 changes: 0 additions & 3 deletions python/mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ warn_unused_ignores = True
[mypy-lsst.daf.butler.core.config]
ignore_errors = True

[mypy-lsst.daf.butler.core.fileTemplates]
ignore_errors = True

# Check registry subpackage.

[mypy-lsst.daf.butler.registry.*]
Expand Down
5 changes: 3 additions & 2 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from collections import namedtuple

from lsst.daf.butler.core.utils import iterable, getFullTypeName, Singleton
from lsst.daf.butler.core.formatter import Formatter
from lsst.daf.butler import Formatter, Registry
from lsst.daf.butler import NamedKeyDict, StorageClass


Expand Down Expand Up @@ -157,7 +157,8 @@ def testTypeNames(self):
tests = [(Formatter, "lsst.daf.butler.core.formatter.Formatter"),
(int, "int"),
(StorageClass, "lsst.daf.butler.core.storageClass.StorageClass"),
(StorageClass(None), "lsst.daf.butler.core.storageClass.StorageClass")]
(StorageClass(None), "lsst.daf.butler.core.storageClass.StorageClass"),
(Registry, "lsst.daf.butler.registry.Registry")]

for item, typeName in tests:
self.assertEqual(getFullTypeName(item), typeName)
Expand Down