Skip to content

Commit

Permalink
Merge pull request #128 from nbes4/add-part-attributes
Browse files Browse the repository at this point in the history
Add Attribute support for Part
  • Loading branch information
rnestler authored May 8, 2024
2 parents 3e4398a + ba28cbb commit 1cf8542
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 3 deletions.
139 changes: 139 additions & 0 deletions entities/attribute.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
from typing import Optional, Union

from entities.common import EnumValue, Value


class AttributeUnit(EnumValue):
def get_name(self) -> str:
return 'unit'


class UnitlessUnit(AttributeUnit):
NONE = "none"


class AttributeType(EnumValue):
VOLTAGE = 'voltage'
STRING = 'string'
CURRENT = 'current'
RESISTANCE = 'resistance'
CAPACITANCE = 'capacitance'
POWER = 'power'
INDUCTANCE = 'inductance'
FREQUENCY = 'frequency'

def get_name(self) -> str:
return 'type'


class Attribute():
def __init__(self, name: str, value: Union[Value, str], attribute_type: AttributeType, unit: Optional[AttributeUnit]) -> None:
self.name = name

self.value = Value(value) if isinstance(value, str) else value
self.unit = unit or UnitlessUnit.NONE
self.attribute_type = attribute_type

def __str__(self) -> str:
return '(attribute "{}" {} {} {})'.format(self.name, self.attribute_type, self.unit, self.value)


class CapacitanceUnit(AttributeUnit):
PICOFARAD = 'picofarad'
NANOFARAD = 'nanofarad'
MICROFARAD = 'microfarad'
MILLIFARAD = 'millifarad'
FARAD = 'farad'


class CapacitanceAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str], unit: CapacitanceUnit) -> None:
super().__init__(name, value, AttributeType.CAPACITANCE, unit)


class CurrentUnit(AttributeUnit):
PICOAMPERE = 'picoampere'
NANOAMPERE = 'nanoampere'
MICROAMPERE = 'microampere'
MILLIAMPERE = 'milliampere'
AMPERE = 'ampere'
KILOAMPERE = 'kiloampere'
MEGAAMPERE = 'megaampere'


class CurrentAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str], unit: CurrentUnit) -> None:
super().__init__(name, value, AttributeType.CURRENT, unit)


class FrequencyUnit(AttributeUnit):
MICROHERTZ = 'microhertz'
MILLIHERTZ = 'millihertz'
HERTZ = 'hertz'
KILOHERTZ = 'kilohertz'
MEGAHERTZ = 'megahertz'
GIGAHERTZ = 'gigahertz'


class FrequencyAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str], unit: FrequencyUnit) -> None:
super().__init__(name, value, AttributeType.FREQUENCY, unit)


class InductanceUnit(AttributeUnit):
NANOHENRY = 'nanohenry'
MICROHENRY = 'microhenry'
MILLIHENRY = 'millihenry'
HENRY = 'henry'


class InductanceAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str], unit: InductanceUnit) -> None:
super().__init__(name, value, AttributeType.INDUCTANCE, unit)


class PowerUnit(AttributeUnit):
NANOWATT = 'nanowatt'
MICROWATT = 'microwatt'
MILLIWATT = 'milliwatt'
WATT = 'watt'
KILOWATT = 'kilowatt'
MEGAWATT = 'megawatt'
GIGAWATT = 'gigawatt'


class PowerAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str], unit: PowerUnit) -> None:
super().__init__(name, value, AttributeType.POWER, unit)


class ResistanceUnit(AttributeUnit):
MICROOHM = 'microohm'
MILLIOHM = 'milliohm'
OHM = 'ohm'
KILOOHM = 'kiloohm'
MEGAOHM = 'megaohm'


class ResistanceAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str], unit: ResistanceUnit) -> None:
super().__init__(name, value, AttributeType.RESISTANCE, unit)


class VoltageUnit(AttributeUnit):
NANOVOLT = 'nanovolt'
MICROVOLT = 'microvolt'
MILLIVOLT = 'millivolt'
VOLT = 'volt'
KILOVOLT = 'kilovolt'
MEGAVOLT = 'megavolt'


class VoltageAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str], unit: VoltageUnit) -> None:
super().__init__(name, value, AttributeType.VOLTAGE, unit)


class StringAttribute(Attribute):
def __init__(self, name: str, value: Union[Value, str]) -> None:
super().__init__(name, value, AttributeType.STRING, None)
14 changes: 11 additions & 3 deletions entities/device.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from os import makedirs, path

from typing import Iterable, List
from typing import Iterable, List, Optional

from common import escape_string
from entities.attribute import Attribute

from .common import (
Author, Category, Created, Deprecated, Description, GeneratedBy, Keywords, Name, StringValue, UUIDValue, Version
Expand Down Expand Up @@ -36,12 +37,19 @@ def __init__(self, manufacturer: str):


class Part():
def __init__(self, mpn: str, manufacturer: Manufacturer):
def __init__(self, mpn: str, manufacturer: Manufacturer, attributes: Optional[List[Attribute]] = None):
self.mpn = mpn
self.manufacturer = manufacturer
self.attributes = attributes or []

def __str__(self) -> str:
return '(part "{}" {}\n)'.format(escape_string(self.mpn), self.manufacturer)
ret = '(part "{}" {}\n'.format(escape_string(self.mpn), self.manufacturer)
ret += indent_entities(self.attributes)
ret += ')'
return ret

def add_attribute(self, attr: Attribute) -> None:
self.attributes.append(attr)


class Device():
Expand Down
72 changes: 72 additions & 0 deletions test_attribute.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from typing import Optional

import pytest

from entities.attribute import (
Attribute, AttributeType, AttributeUnit, CapacitanceAttribute, CapacitanceUnit, CurrentAttribute, CurrentUnit,
FrequencyAttribute, FrequencyUnit, InductanceAttribute, InductanceUnit, PowerAttribute, PowerUnit,
ResistanceAttribute, ResistanceUnit, StringAttribute, UnitlessUnit, VoltageAttribute, VoltageUnit
)


@pytest.mark.parametrize(['name', 'value', 'attribute_type', 'unit', 'output'], [
("n", "vvv", AttributeType.STRING, None, '(attribute "n" (type string) (unit none) (value "vvv"))'),
("n", "vvv", AttributeType.STRING, UnitlessUnit.NONE, '(attribute "n" (type string) (unit none) (value "vvv"))'),
("n", "0.1", AttributeType.CURRENT, CurrentUnit.MILLIAMPERE, '(attribute "n" (type current) (unit milliampere) (value "0.1"))'),
("n", "0.1", AttributeType.CAPACITANCE, CapacitanceUnit.MILLIFARAD, '(attribute "n" (type capacitance) (unit millifarad) (value "0.1"))'),
("n", "0.1", AttributeType.FREQUENCY, FrequencyUnit.KILOHERTZ, '(attribute "n" (type frequency) (unit kilohertz) (value "0.1"))'),
("n", "0.1", AttributeType.INDUCTANCE, InductanceUnit.MICROHENRY, '(attribute "n" (type inductance) (unit microhenry) (value "0.1"))'),
("n", "0.1", AttributeType.POWER, PowerUnit.WATT, '(attribute "n" (type power) (unit watt) (value "0.1"))'),
("n", "0.1", AttributeType.RESISTANCE, ResistanceUnit.MEGAOHM, '(attribute "n" (type resistance) (unit megaohm) (value "0.1"))'),
("n", "0.1", AttributeType.VOLTAGE, VoltageUnit.KILOVOLT, '(attribute "n" (type voltage) (unit kilovolt) (value "0.1"))'),
# add more for new types
])
def test_attribute(name: str, value: str, attribute_type: AttributeType, unit: Optional[AttributeUnit], output: str) -> None:
attribute_s_exp = str(Attribute(name, value, attribute_type, unit))
assert attribute_s_exp == output


@pytest.mark.parametrize(['attr', 'attribute_type'], [
(StringAttribute("s", "a"), AttributeType.STRING),
(CurrentAttribute("c", "1", CurrentUnit.AMPERE), AttributeType.CURRENT),
(CapacitanceAttribute("c", "1", CapacitanceUnit.FARAD), AttributeType.CAPACITANCE),
(FrequencyAttribute("f", "1", FrequencyUnit.HERTZ), AttributeType.FREQUENCY),
(InductanceAttribute("i", "1", InductanceUnit.HENRY), AttributeType.INDUCTANCE),
(PowerAttribute("p", "1", PowerUnit.WATT), AttributeType.POWER),
(ResistanceAttribute("r", "1", ResistanceUnit.OHM), AttributeType.RESISTANCE),
(VoltageAttribute("v", "1", VoltageUnit.VOLT), AttributeType.VOLTAGE),
# add more for new types
])
def test_typed_attribute_has_correct_type(attr: Attribute, attribute_type: AttributeType) -> None:
assert attr.attribute_type == attribute_type


@pytest.mark.parametrize('attr', [
StringAttribute("s", "a"),
# add more for new unitless types
])
def test_unitless_typed_types_have_unit_none(attr: Attribute) -> None:
assert attr.unit == UnitlessUnit.NONE


def test_none_unit_evaluates_to_unitless_none() -> None:
# we pass None as unit
a = Attribute("n", "v", AttributeType.STRING, None)
# check if it gets set to UnitlessUnit.NONE internally
assert a.unit == UnitlessUnit.NONE


@pytest.mark.parametrize(['typed', 'general'], [
(StringAttribute("s", "a"), Attribute("s", "a", AttributeType.STRING, None)),
(StringAttribute("s", "a"), Attribute("s", "a", AttributeType.STRING, UnitlessUnit.NONE)),
(CurrentAttribute("c", "1", CurrentUnit.AMPERE), Attribute("c", "1", AttributeType.CURRENT, CurrentUnit.AMPERE)),
(CapacitanceAttribute("c", "1", CapacitanceUnit.FARAD), Attribute("c", "1", AttributeType.CAPACITANCE, CapacitanceUnit.FARAD)),
(FrequencyAttribute("f", "1", FrequencyUnit.HERTZ), Attribute("f", "1", AttributeType.FREQUENCY, FrequencyUnit.HERTZ)),
(InductanceAttribute("i", "1", InductanceUnit.HENRY), Attribute("i", "1", AttributeType.INDUCTANCE, InductanceUnit.HENRY)),
(PowerAttribute("p", "1", PowerUnit.WATT), Attribute("p", "1", AttributeType.POWER, PowerUnit.WATT)),
(ResistanceAttribute("r", "1", ResistanceUnit.OHM), Attribute("r", "1", AttributeType.RESISTANCE, ResistanceUnit.OHM)),
(VoltageAttribute("v", "1", VoltageUnit.VOLT), Attribute("v", "1", AttributeType.VOLTAGE, VoltageUnit.VOLT)),
# add more for new types
])
def test_typed_vs_general_attribute_equivalence(typed: Attribute, general: Attribute) -> None:
assert str(typed) == str(general)

0 comments on commit 1cf8542

Please sign in to comment.