Skip to content

Commit

Permalink
Merge pull request #263 from sebastian-echeverria/feature/extending-p…
Browse files Browse the repository at this point in the history
…roperties

Modified Property so it can load properties from any module
  • Loading branch information
turingcompl33t authored Sep 28, 2023
2 parents 02722d2 + 17b5a3b commit df7c3ed
Show file tree
Hide file tree
Showing 25 changed files with 120 additions and 65 deletions.
10 changes: 4 additions & 6 deletions demo/requirements.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,10 @@
"source": [
"from mlte.spec.spec import Spec\n",
"\n",
"from mlte.property.costs import (\n",
" StorageCost,\n",
" TrainingComputeCost,\n",
" TrainingMemoryCost\n",
")\n",
"from mlte.property.functionality import TaskEfficacy\n",
"from mlte.property.costs.storage_cost import StorageCost\n",
"from mlte.property.costs.training_memory_cost import TrainingMemoryCost\n",
"from mlte.property.costs.training_compute_cost import TrainingComputeCost\n",
"from mlte.property.functionality.task_efficacy import TaskEfficacy\n",
"\n",
"\n",
"from mlte.measurement.storage import LocalObjectSize\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,15 @@
"default": {},
"title": "Conditions",
"type": "object"
},
"module": {
"title": "Module",
"type": "string"
}
},
"required": [
"name"
"name",
"module"
],
"title": "PropertyModel",
"type": "object"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@
"title": "Conditions",
"type": "object"
},
"module": {
"title": "Module",
"type": "string"
},
"results": {
"additionalProperties": {
"$ref": "#/$defs/ResultModel"
Expand All @@ -118,7 +122,8 @@
}
},
"required": [
"name"
"name",
"module"
],
"title": "PropertyAndResultsModel",
"type": "object"
Expand Down
3 changes: 0 additions & 3 deletions mlte/property/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
from .property import Property

__all__ = ["Property"]
5 changes: 0 additions & 5 deletions mlte/property/costs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
from .storage_cost import StorageCost
from .training_compute_cost import TrainingComputeCost
from .training_memory_cost import TrainingMemoryCost

__all__ = ["StorageCost", "TrainingMemoryCost", "TrainingComputeCost"]
5 changes: 3 additions & 2 deletions mlte/property/costs/storage_cost.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
StorageCost property definition.
"""

from ..._private.text import cleantext
from ..property import Property
from mlte._private.text import cleantext
from mlte.property.property import Property


class StorageCost(Property):
Expand All @@ -26,4 +26,5 @@ def __init__(self, rationale: str):
"""
),
rationale,
__name__,
)
5 changes: 3 additions & 2 deletions mlte/property/costs/training_compute_cost.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
TrainingComputeCost property definition.
"""

from ..._private.text import cleantext
from ..property import Property
from mlte._private.text import cleantext
from mlte.property.property import Property


class TrainingComputeCost(Property):
Expand All @@ -31,4 +31,5 @@ def __init__(self, rationale: str):
"""
),
rationale,
__name__,
)
5 changes: 3 additions & 2 deletions mlte/property/costs/training_memory_cost.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
TrainingMemoryCost property definition.
"""

from ..._private.text import cleantext
from ..property import Property
from mlte._private.text import cleantext
from mlte.property.property import Property


class TrainingMemoryCost(Property):
Expand All @@ -31,4 +31,5 @@ def __init__(self, rationale: str):
"""
),
rationale,
__name__,
)
3 changes: 0 additions & 3 deletions mlte/property/functionality/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
from .task_efficacy import TaskEfficacy

__all__ = ["TaskEfficacy"]
3 changes: 2 additions & 1 deletion mlte/property/functionality/task_efficacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

from mlte._private.text import cleantext
from mlte.property import Property
from mlte.property.property import Property


class TaskEfficacy(Property):
Expand All @@ -28,4 +28,5 @@ def __init__(self, rationale: str):
"""
),
rationale,
__name__,
)
44 changes: 19 additions & 25 deletions mlte/property/property.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import abc
import importlib
import pkgutil
from typing import Type

import mlte._private.meta as meta
Expand All @@ -23,16 +22,15 @@ def __subclasshook__(cls, subclass):
"""Define the interface for all concrete properties."""
return meta.has_callables(subclass, "__init__")

def __init__(self, name: str, description: str, rationale: str):
def __init__(
self, name: str, description: str, rationale: str, module: str
):
"""
Initialize a Property instance.
:param name: The name of the property
:type name: str
:param description: The description of the property
:type description: str
:param rationale: The rationale for using the property
:type rationale: str
"""
self.name: str = name
"""The name of the property."""
Expand All @@ -43,17 +41,20 @@ def __init__(self, name: str, description: str, rationale: str):
self.rationale: str = rationale
"""The rationale for using the property."""

self.module: str = module
"""The name of the module the property is defined in."""

def to_model(self) -> PropertyModel:
"""
Return a Property as a model.
:return: The property as its model.
:rtype: PropertyModel
"""
return PropertyModel(
name=self.name,
description=self.description,
rationale=self.rationale,
module=self.module,
)

@classmethod
Expand All @@ -62,10 +63,8 @@ def from_model(cls, model: PropertyModel) -> Property:
Load a Property instance from a model.
:param model: The model with the Property info.
:type model: PropertyModel
:return: The loaded property
:rtype: Property
"""
if model.name == "":
raise RuntimeError(
Expand All @@ -74,22 +73,17 @@ def from_model(cls, model: PropertyModel) -> Property:
classname = model.name

# Load the class type from the module
properties_package_name = "mlte.property"
properties_module = importlib.import_module(
properties_package_name, package="mlte"
)
for submodule_info in pkgutil.iter_modules(
properties_module.__path__, properties_module.__name__ + "."
):
submodule = importlib.import_module(
submodule_info.name, package=properties_package_name
module_path = model.module
try:
properties_module = importlib.import_module(module_path)
except Exception:
raise RuntimeError(f"Module {module_path} not found")
try:
class_: Type[Property] = getattr(properties_module, classname)
except AttributeError:
raise RuntimeError(
f"Property {model.name} in module {module_path} not found"
)
try:
class_: Type[Property] = getattr(submodule, classname)
except AttributeError:
continue

# Instantiate the property
return class_(model.rationale) # type: ignore

raise RuntimeError(f"Property {model.name} not found")
# Instantiate the property
return class_(model.rationale) # type: ignore
7 changes: 6 additions & 1 deletion mlte/schema/artifact/spec/v0.0.1/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,15 @@
"default": {},
"title": "Conditions",
"type": "object"
},
"module": {
"title": "Module",
"type": "string"
}
},
"required": [
"name"
"name",
"module"
],
"title": "PropertyModel",
"type": "object"
Expand Down
7 changes: 6 additions & 1 deletion mlte/schema/artifact/validated/v0.0.1/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@
"title": "Conditions",
"type": "object"
},
"module": {
"title": "Module",
"type": "string"
},
"results": {
"additionalProperties": {
"$ref": "#/$defs/ResultModel"
Expand All @@ -118,7 +122,8 @@
}
},
"required": [
"name"
"name",
"module"
],
"title": "PropertyAndResultsModel",
"type": "object"
Expand Down
3 changes: 3 additions & 0 deletions mlte/spec/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class PropertyModel(BaseModel):
conditions: Dict[str, ConditionModel] = {}
"""A dictionary of conditions, keyed by measurement id, to be validated for this property."""

module: str
"""The full package and module path of the Property class."""


class SpecModel(BaseModel):
"""The model implementation for the Spec artifact."""
Expand Down
2 changes: 1 addition & 1 deletion mlte/spec/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from mlte.artifact.artifact import Artifact
from mlte.artifact.model import ArtifactModel
from mlte.artifact.type import ArtifactType
from mlte.property import Property
from mlte.property.property import Property
from mlte.spec.condition import Condition
from mlte.spec.model import PropertyModel, SpecModel

Expand Down
1 change: 1 addition & 0 deletions mlte/validation/validated_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def to_model(self) -> ArtifactModel:
description=property_model.description,
rationale=property_model.rationale,
conditions=property_model.conditions,
module=property_model.module,
results=res_model[property_model.name],
)
for property_model in spec_model.properties
Expand Down
10 changes: 4 additions & 6 deletions test/property/test_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
Unit tests for model properties.
"""

from mlte.property.costs import (
StorageCost,
TrainingComputeCost,
TrainingMemoryCost,
)
from mlte.property.functionality import TaskEfficacy
from mlte.property.costs.storage_cost import StorageCost
from mlte.property.costs.training_compute_cost import TrainingComputeCost
from mlte.property.costs.training_memory_cost import TrainingMemoryCost
from mlte.property.functionality.task_efficacy import TaskEfficacy


def test_storage_cost():
Expand Down
2 changes: 1 addition & 1 deletion test/schema/test_spec_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Unit tests for Spec schema.
"""

from mlte.property.costs import StorageCost
from mlte.property.costs.storage_cost import StorageCost
from mlte.spec.spec import Spec
from mlte.value.types.integer import Integer

Expand Down
2 changes: 1 addition & 1 deletion test/schema/test_validatedspec_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


from mlte.evidence.metadata import EvidenceMetadata, Identifier
from mlte.property.costs import StorageCost
from mlte.property.costs.storage_cost import StorageCost
from mlte.spec.spec import Spec
from mlte.validation.spec_validator import SpecValidator
from mlte.value.types.integer import Integer
Expand Down
27 changes: 27 additions & 0 deletions test/spec/extended_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
test/spec/test_model.py
ExtendedProperty definition, for testing purposes.
"""

from mlte._private.text import cleantext
from mlte.property.property import Property


class ExtendedProperty(Property):
"""
The ExtendedProperty property is a property not defined in the default property package.
"""

def __init__(self, rationale: str):
"""Initialize a ExtendedProperty instance."""
super().__init__(
self.__class__.__name__,
cleantext(
"""
The ExtendedProperty property is just for testing purposes.
"""
),
rationale,
__name__,
)
1 change: 1 addition & 0 deletions test/spec/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def test_spec_body() -> None:
name="TaskEfficacy",
description="Property for useful things.",
rationale="Because I say so",
module="mlte.properties.functionality.task_efficacy",
conditions={
"accuracy": model.ConditionModel(
name="less_than",
Expand Down
Loading

0 comments on commit df7c3ed

Please sign in to comment.