Skip to content

Commit

Permalink
add docs and unit test for _resolve_type
Browse files Browse the repository at this point in the history
  • Loading branch information
braingram committed Nov 22, 2023
1 parent d0a3b2a commit af27436
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 4 deletions.
65 changes: 65 additions & 0 deletions asdf/_tests/test_extension.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import fractions
import sys

import pytest
from packaging.specifiers import SpecifierSet
Expand All @@ -18,6 +19,7 @@
Validator,
get_cached_extension_manager,
)
from asdf.extension._manager import _resolve_type
from asdf.testing.helpers import roundtrip_object


Expand Down Expand Up @@ -941,3 +943,66 @@ class FractionWithInverseExtension:

read_f1 = roundtrip_object(f1)
assert read_f1.inverse.inverse is read_f1


def test_resolve_type_not_imported():
path = "mailbox.Mailbox"

if "mailbox" in sys.modules:
del sys.modules["mailbox"]

Check warning on line 952 in asdf/_tests/test_extension.py

View check run for this annotation

Codecov / codecov/patch

asdf/_tests/test_extension.py#L952

Added line #L952 was not covered by tests

assert _resolve_type(path) is None

import mailbox

assert _resolve_type(path) is mailbox.Mailbox


@pytest.mark.parametrize(
"path, obj", (("sys", sys), ("asdf.AsdfFile", AsdfFile), ("asdf.Missing", None), ("not_a_module", None))
)
def test_resolve_type(path, obj):
assert _resolve_type(path) is obj


def test_extension_converter_by_class_path():
class MailboxConverter:
tags = ["asdf://example.com/tags/mailbox-1.0.0"]
types = ["mailbox.Mailbox"]

def to_yaml_tree(self, obj, tag, ctx):
return {}

Check warning on line 974 in asdf/_tests/test_extension.py

View check run for this annotation

Codecov / codecov/patch

asdf/_tests/test_extension.py#L974

Added line #L974 was not covered by tests

def from_yaml_tree(self, node, tag, ctx):
return None

Check warning on line 977 in asdf/_tests/test_extension.py

View check run for this annotation

Codecov / codecov/patch

asdf/_tests/test_extension.py#L977

Added line #L977 was not covered by tests

class MailboxExtension:
tags = MailboxConverter.tags
converters = [MailboxConverter()]
extension_uri = "asdf://example.com/extensions/mailbox-1.0.0"

# grab the type so we can use it for extension_manager.get_converter_for_type
import mailbox

typ = mailbox.Mailbox
del sys.modules["mailbox"], mailbox

with config_context() as cfg:
cfg.add_extension(MailboxExtension())
extension_manager = AsdfFile().extension_manager

# make sure that registering the extension did not load the module
assert "mailbox" not in sys.modules

# as the module hasn't been loaded, the converter shouldn't be found
with pytest.raises(KeyError, match="No support available for Python type 'mailbox.Mailbox'"):
extension_manager.get_converter_for_type(typ)

# make sure inspecting the type didn't import the module
assert "mailbox" not in sys.modules

# finally, import the module and check that the converter can now be found
import mailbox

converter = extension_manager.get_converter_for_type(mailbox.Mailbox)
assert isinstance(converter.delegate, MailboxConverter)
23 changes: 19 additions & 4 deletions asdf/extension/_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,26 @@


def _resolve_type(path):
"""
Convert a class path (like the string "asdf.AsdfFile") to a
class (``asdf.AsdfFile``) only if the module implementing the
class has already been imported.
Parameters
----------
path : str
Path/name of class (for example, "asdf.AsdfFile")
Returns
-------
typ : class or None
The class (if it's already been imported) or None
"""
if "." not in path:
# this path does not appear to include a module
if path in globals():
return globals()[path]
elif path in sys.modules:
# check if this path is a module
if path in sys.modules:
return sys.modules[path]
return None
# this type is part of a module
Expand Down

0 comments on commit af27436

Please sign in to comment.