Skip to content

Commit

Permalink
Merge pull request #198 from pepkit/dev
Browse files Browse the repository at this point in the history
Interpreter representations
  • Loading branch information
vreuter authored Nov 17, 2017
2 parents 32f5853 + 23fe128 commit c3edce3
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 55 deletions.
2 changes: 1 addition & 1 deletion pep/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.8.0"
__version__ = "0.8.1"
50 changes: 34 additions & 16 deletions pep/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
__all__ = __functions__ + __classes__


MAX_PROJECT_SAMPLES_REPR = 12
ATTRDICT_METADATA = {"_force_nulls": False, "_attribute_identity": False}

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -200,9 +201,15 @@ def include_in_repr(attr, klazz):
:return bool: whether to include attribute in an object's
text representation
"""
# TODO: try to leverage the class hierarchy to determine these exclusions.
ad_metadata = list(ATTRDICT_METADATA.keys())
exclusions_by_class = {
AttributeDict.__name__: ad_metadata,
Project.__name__: ["_samples", "merge_table", "sheet",
"interfaces_by_protocol"] + ad_metadata,
Sample.__name__: ["sheet", "prj", "merged_cols"] + ad_metadata}
classname = klazz.__name__ if isinstance(klazz, type) else klazz
return attr not in \
{"Project": ["sheet", "interfaces_by_protocol"]}[classname]
return attr not in exclusions_by_class.get(classname, [])



Expand Down Expand Up @@ -437,6 +444,13 @@ def __exit__(self, *args):



class IFilteredRepr(object):
def __repr__(self):
return




@copy
class AttributeDict(MutableMapping):
"""
Expand Down Expand Up @@ -608,7 +622,8 @@ def __len__(self):
return sum(1 for _ in iter(self))

def __repr__(self):
return repr(self.__dict__)
return repr({k: v for k, v in self.__dict__.items()
if include_in_repr(k, klazz=self.__class__)})

def __str__(self):
return "{}: {}".format(self.__class__.__name__, repr(self))
Expand Down Expand Up @@ -718,11 +733,11 @@ def __init__(self, config_file, subproject=None,
else:
_LOGGER.debug("Compute: %s", str(self.compute))

# optional configs
# Optional behavioral parameters
self.permissive = permissive
self.file_checks = file_checks

# include the path to the config file
# Include the path to the config file.
self.config_file = _os.path.abspath(config_file)

# Parse config file
Expand Down Expand Up @@ -790,11 +805,19 @@ def __init__(self, config_file, subproject=None,


def __repr__(self):
""" Self-represent in the interpreter. """
# First, parameterize the attribute filtration function by the class.
include = partial(include_in_repr, klazz=self.__class__)
# Then iterate over items, filtering what to include in representation.
return repr({k: v for k, v in self.__dict__.items() if include(k)})
""" Representation in interpreter. """
samples_message = "{} (from '{}')".\
format(self.__class__.__name__, self.config_file)
try:
num_samples = len(self._samples)
except AttributeError:
pass
else:
samples_message += " with {} sample(s)".format(num_samples)
if num_samples <= MAX_PROJECT_SAMPLES_REPR:
samples_message += ": {}".format(repr(self._samples))
meta_text = super(Project, self).__repr__()
return "{} -- {}".format(samples_message, meta_text)


@property
Expand Down Expand Up @@ -1446,8 +1469,7 @@ def parse_config_file(self, subproject=None):
# Relative to environment config file.
self.compute.submission_template = _os.path.join(
_os.path.dirname(self.environment_file),
self.compute.submission_template
)
self.compute.submission_template)

# Required variables check
if not hasattr(self.metadata, SAMPLE_ANNOTATIONS_KEY):
Expand Down Expand Up @@ -1668,10 +1690,6 @@ def __ne__(self, other):
return not self == other


def __repr__(self):
return "Sample '{}': {}".format(self.name, self.__dict__)


def __str__(self):
return "Sample '{}'".format(self.name)

Expand Down
38 changes: 0 additions & 38 deletions tests/models/test_models_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,6 @@ def test_Project_representations_smoke(self, proj, funcname):
getattr(proj, funcname).__call__()


def test_project_repr_name_inclusion(self, proj, funcname):
""" Test Project text representation. """
func = getattr(proj, funcname)
result = func.__call__()
assert type(result) is str
classname = proj.__class__.__name__
if funcname == "__str__":
assert classname in result
elif funcname == "__repr__":
assert classname not in result
else:
raise ValueError("Unexpected representation function: {}".
format(funcname))



class ModelCreationSmokeTests:
""" Smoketests for creation of various types of project-related models. """
Expand All @@ -72,29 +57,6 @@ def test_empty_project(self, path_empty_project):
class ModelRepresentationSmokeTests:
""" Tests for the text representation of important ADTs. """

# NOTE: similar parameterization, but Project construction needs
# to be handled with greater care when testing the actual call.

@pytest.mark.parametrize(
argnames="class_name", argvalues=pep.models.__classes__)
def test_implements_repr_smoke(self, class_name):
""" Each important ADT must implement a representation method. """

funcname = "__repr__"

# Attempt a control assertion, that a subclass that doesn't override
# the given method of its superclass, uses the superclass version of
# the function in question.
class ObjectSubclass(object):
def __init__(self):
super(ObjectSubclass, self).__init__()
assert getattr(ObjectSubclass, funcname) is getattr(object, funcname)

# Make the actual assertion of interest.
adt = getattr(pep.models, class_name)
assert getattr(adt, funcname) != \
getattr(adt.__bases__[0], funcname)


@pytest.mark.parametrize(
argnames="class_name",
Expand Down

0 comments on commit c3edce3

Please sign in to comment.