aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2019-05-23 21:08:36 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2019-05-26 21:55:41 +0200
commit1699cca793c6a8ebc00942557b6764fff6739044 (patch)
treeee8162390db5a7607298fe5f40841bb131b60542
parent4afac7dc4c743284e5243428f00928aa7eaacfdc (diff)
downloadee-python-1699cca793c6a8ebc00942557b6764fff6739044.tar.gz
ee-python-1699cca793c6a8ebc00942557b6764fff6739044.tar.bz2
ee-python-1699cca793c6a8ebc00942557b6764fff6739044.tar.xz
ee-python-1699cca793c6a8ebc00942557b6764fff6739044.zip
part-find-requirements: wip
-rw-r--r--src/ee/__init__.py26
-rw-r--r--src/ee/kicad/functions.py25
-rw-r--r--src/ee/part/common_fact_types.py1
-rw-r--r--src/ee/part/fact_keys.py1
-rw-r--r--src/ee/part/requirement.py30
-rw-r--r--src/ee/tools/part_find_requirements.py29
-rw-r--r--src/ee/tools/templates/build.ninja.j28
-rw-r--r--test/test_EeVal.py68
8 files changed, 125 insertions, 63 deletions
diff --git a/src/ee/__init__.py b/src/ee/__init__.py
index 2ba113e..06c5aab 100644
--- a/src/ee/__init__.py
+++ b/src/ee/__init__.py
@@ -1,5 +1,6 @@
import re
from functools import total_ordering
+from typing import Optional
import math
@@ -52,8 +53,10 @@ class EeVal(object):
'P': 15,
'E': 18,
}
+ keys = "".join(exponents.keys())
+ units = "|".join(units)
r = re.compile(
- "([0-9]+\\.[0-9]+|\\.?[0-9]+|[0-9]+\\.?) *([" + "".join(exponents.keys()) + "]?) *(" + "|".join(units) + "?)")
+ "([0-9]+(?:\\.[0-9]*)?(?:e-?[0-9]+)|[0-9]+\\.[0-9]+|\\.?[0-9]+|[0-9]+\\.?) *([" + keys + "]?) *(" + units + "?)")
def __init__(self, s=None, value=None, exp=None, unit=None):
# This is where I regret having a string in the API at once.
@@ -66,7 +69,14 @@ class EeVal(object):
(self._value, self._exp, self._unit) = (value, exp, unit)
@staticmethod
- def parse(s) -> "EeVal":
+ def try_parse(s, expected_unit=None) -> Optional["EeVal"]:
+ try:
+ return EeVal.parse(s, expected_unit)
+ except EeException:
+ return None
+
+ @staticmethod
+ def parse(s, expected_unit=None) -> "EeVal":
m = EeVal.r.match(s)
if not m:
raise EeException("Could not parse value: " + str(s))
@@ -79,10 +89,18 @@ class EeVal(object):
e = math.ceil(math.log10(value))
exp = exp + e
value = value * math.pow(10, -e)
- return EeVal(None, value=float(value), exp=exp, unit=unit if len(unit) > 0 else None)
+
+ unit = unit if len(unit) > 0 else None
+ if expected_unit is not None:
+ if unit is None:
+ unit = expected_unit
+ elif unit != expected_unit:
+ raise EeException("Bad unit when parsing, expected {}, got {}".format(expected_unit, unit))
+
+ return EeVal(None, value=float(value), exp=exp, unit=unit)
@property
- def value(self):
+ def value(self) -> float:
return self.__float__()
@property
diff --git a/src/ee/kicad/functions.py b/src/ee/kicad/functions.py
index a2f9f80..b8ad7f5 100644
--- a/src/ee/kicad/functions.py
+++ b/src/ee/kicad/functions.py
@@ -1,8 +1,8 @@
import re
-
import ee.kicad.model
import ee.kicad.sch_fact_types as kicad_ft
+from ee import EeVal
from ee.kicad import sch_fact_types
from ee.part import Part
from ee.part import common_fact_types
@@ -80,11 +80,26 @@ def fix_value_strategy(**kwargs):
symbol_name = part.facts.get_value(sch_fact_types.symbol_name)
- if ref_type in ("D", "R", "L", "C") and v == symbol_name:
- part.remove_fact(uris.make_fact_key("value"))
+ # if ref_type in ("D", "R", "L", "C") and v == symbol_name:
+ # part.remove_fact(uris.make_fact_key("value"))
+
+ if ref_type == "R":
+ ee_value = EeVal.try_parse(v)
+ if ee_value:
+ part.facts.add(common_fact_types.resistance, str(ee_value.value))
+
+ if ref_type == "C":
+ ee_value = EeVal.try_parse(v)
+ if ee_value:
+ part.facts.add(common_fact_types.capacitance, str(ee_value.value))
+
+ if ref_type == "L":
+ ee_value = EeVal.try_parse(v)
+ if ee_value:
+ part.facts.add(common_fact_types.inductance, str(ee_value.value))
- if ref_type == "Q" and v == symbol_name and re.match("^Q_[NP]MOS_[DSG]{3}$", symbol_name):
- part.remove_fact(uris.make_fact_key("value"))
+ # if ref_type == "Q" and v == symbol_name and re.match("^Q_[NP]MOS_[DSG]{3}$", symbol_name):
+ # part.remove_fact(uris.make_fact_key("value"))
return part
diff --git a/src/ee/part/common_fact_types.py b/src/ee/part/common_fact_types.py
index 10ba1eb..7474437 100644
--- a/src/ee/part/common_fact_types.py
+++ b/src/ee/part/common_fact_types.py
@@ -5,5 +5,6 @@ footprint = FactType(fact_keys.footprint, "Footprint")
resistance = EeValueFactType(fact_keys.resistance, "Resistance", ee.resistance_type)
capacitance = EeValueFactType(fact_keys.capacitance, "Capacitance", ee.capacitance_type)
+inductance = EeValueFactType(fact_keys.inductance, "Inductance", ee.inductance_type)
ee_component_type = EeValueFactType(fact_keys.ee_component_type, "EE component type", ee.capacitance_type)
diff --git a/src/ee/part/fact_keys.py b/src/ee/part/fact_keys.py
index 9617b9c..668a197 100644
--- a/src/ee/part/fact_keys.py
+++ b/src/ee/part/fact_keys.py
@@ -1,5 +1,6 @@
ee_component_type = "http://purl.org/ee/fact-type/ee-component-type"
capacitance = "http://purl.org/ee/fact-type/capacitance"
+inductance = "http://purl.org/ee/fact-type/inductance"
max_voltage = "http://purl.org/ee/fact-type/voltage"
# https://en.wikipedia.org/wiki/Ceramic_capacitor#Class_2_ceramic_capacitors
rs_198_class_2 = "http://purl.org/ee/fact-type/rs-198 class 2"
diff --git a/src/ee/part/requirement.py b/src/ee/part/requirement.py
index a9381df..297727b 100644
--- a/src/ee/part/requirement.py
+++ b/src/ee/part/requirement.py
@@ -1,6 +1,20 @@
from typing import List
-from ee.part import Part, fact_keys, FactType, common_fact_types
+from ee import EeVal
+from ee.part import Part, FactType, common_fact_types, EeValueFactType
+
+
+def to_str(part, fact_type, value, op):
+ v = None
+ if isinstance(fact_type, EeValueFactType):
+ eeft: EeValueFactType=fact_type
+ ev = EeVal.try_parse(value, eeft.ee_type.symbol)
+ v = str(ev)
+
+ if not v:
+ v = value
+
+ return "{}.{} {} {}".format(part.printable_reference, fact_type.label or fact_type.uri, op, v)
class Requirement(object):
@@ -15,7 +29,7 @@ class EqualRequirement(Requirement):
self.value = value
def __str__(self):
- return "{}.{} == {}".format(self.part.printable_reference, self.fact_type, self.value)
+ return to_str(self.part, self.fact_type, self.value, "==")
class MinRequirement(Requirement):
@@ -25,7 +39,7 @@ class MinRequirement(Requirement):
self.value = value
def __str__(self):
- return "{}.{} == {}".format(self.part.printable_reference, self.fact_type, self.value)
+ return to_str(self.part, self.fact_type, self.value, ">")
class MaxRequirement(Requirement):
@@ -35,7 +49,7 @@ class MaxRequirement(Requirement):
self.value = value
def __str__(self):
- return "{}.{} == {}".format(self.part.printable_reference, self.fact_type, self.value)
+ return to_str(self.part, self.fact_type, self.value, "<")
class PartAnalysis(object):
@@ -47,12 +61,12 @@ class PartAnalysis(object):
def analyze_requirements(part: Part) -> PartAnalysis:
rs = []
- resistance = part.find_fact(common_fact_types.resistance.uri)
+ resistance = part.facts.get_value(common_fact_types.resistance)
if resistance:
- rs.append(EqualRequirement(part, common_fact_types.resistance, resistance.valueProp))
+ rs.append(EqualRequirement(part, common_fact_types.resistance, resistance))
- capacitance = part.find_fact(common_fact_types.capacitance.uri)
+ capacitance = part.facts.get_value(common_fact_types.capacitance)
if capacitance:
- rs.append(EqualRequirement(part, common_fact_types.capacitance, capacitance.valueProp))
+ rs.append(EqualRequirement(part, common_fact_types.capacitance, capacitance))
return PartAnalysis(part, rs)
diff --git a/src/ee/tools/part_find_requirements.py b/src/ee/tools/part_find_requirements.py
index 032db02..a13c3f2 100644
--- a/src/ee/tools/part_find_requirements.py
+++ b/src/ee/tools/part_find_requirements.py
@@ -1,26 +1,27 @@
import argparse
from pathlib import Path
-from ee.part import requirement, Part, PartDb, load_db, save_db
+from ee.part import requirement, Part, load_db
-def work(in_path: Path, out_path: Path):
+def work(in_path: Path, out_path: Path, report_path: Path):
in_parts = load_db(in_path)
- with out_path.open("w") as f:
- print("<root>", file=f)
- for xml in in_parts.iterparts():
- part = Part(xml)
+ requirements = []
+ for xml in in_parts.iterparts():
+ part = Part(xml)
- analysis = requirement.analyze_requirements(part)
+ analysis = requirement.analyze_requirements(part)
+ requirements.append(analysis)
- print("Part: {}. Found {} requirements".format(analysis.part.printable_reference,
- len(analysis.requirements)), file=f)
+ with report_path.open("w") as f:
+ for a in requirements:
+ print("{}\n{}\n".format(a.part.printable_reference, "=" * len(a.part.printable_reference)), file=f)
- for r in analysis.requirements:
- print(" {}".format(r), file=f)
+ for r in a.requirements:
+ print("* {}".format(str(r)), file=f)
- print("</root>", file=f)
+ print("", file=f)
parser = argparse.ArgumentParser()
@@ -34,6 +35,8 @@ parser.add_argument("--out",
required=True,
metavar="REQUIREMENTS")
+parser.add_argument("--report")
+
args = parser.parse_args()
-work(Path(args.in_path), Path(args.out))
+work(Path(args.in_path), Path(args.out), Path(args.report))
diff --git a/src/ee/tools/templates/build.ninja.j2 b/src/ee/tools/templates/build.ninja.j2
index 0706b11..6ff4e0a 100644
--- a/src/ee/tools/templates/build.ninja.j2
+++ b/src/ee/tools/templates/build.ninja.j2
@@ -32,7 +32,7 @@ rule part-apply-function
rule part-find-requirements
description = part-find-requirements
- command = $ee part-find-requirements --in $in --out $out
+ command = $ee part-find-requirements --in $in --out $out $report
rule part-validate-parts
command = $ee part-validate-parts --in $in --out $out
@@ -88,7 +88,9 @@ build ee/sch.xml: part-apply-function ee/kicad-sch.xml
build $report_dir/part-validate-parts.rst: part-validate-parts ee/sch.xml
{%- set reports=reports+["$report_dir/part-validate-parts.rst"] %}
-build ee/requirements.xml: part-find-requirements ee/sch.xml
+build ee/requirements.xml | $report_dir/requirements.rst: part-find-requirements ee/sch.xml
+ report = --report $report_dir/requirements.rst
+{%- set reports=reports+["$report_dir/requirements.rst"] %}
{% for s in distributors %}
{%- set cfg = project.cfg["supplier:" + s] if "supplier:" + s in project.cfg else None %}
@@ -97,7 +99,7 @@ build ee/{{ s }}/pn-part-search-list.xml: pn-part-search-list ee/sch.xml
supplier = {{ s }}
build ee/{{ s }}/downloaded.xml | ee/{{ s }}/downloaded.rst: {{ s }}-search-parts ee/{{ s }}/pn-part-search-list.xml
-{%- set reports=reports+["ee/" + s + "/downloaded.rst"] %}
+{%- set reports=reports+["$report_dir/" + s + "/downloaded.rst"] %}
build ee/{{ s }}/parts.xml: part-apply-function ee/{{ s }}/downloaded.xml
execution = {{ s }}
diff --git a/test/test_EeVal.py b/test/test_EeVal.py
index 0c21133..6d4032f 100644
--- a/test/test_EeVal.py
+++ b/test/test_EeVal.py
@@ -1,37 +1,43 @@
import pytest
from ee import EeVal
+
@pytest.mark.parametrize("s, num_value, str_value, unit", [
- ("0", 0, "0", None),
- ("0 k", 0, "0", None),
- ("1", 1, "1", None),
- ("10", 10, "10", None),
- ("10k", 10 * 1000, "10 k", None),
- ("10 k", 10 * 1000, "10 k", None),
- ("10 k", 10 * 1000, "10 k", None),
- ("1000 m", 1, "1", None),
- ("100 m", 0.1, "100 m", None),
- ("100 n", 0.0000001, "100 n", None),
- ("1 m", 0.001, "1 m", None),
- ("1 u", 0.000001, "1 u", None),
- ("0.1 u", 0.0000001, "100 n", None),
- (".1 u", 0.0000001, "100 n", None),
- ("4.7 u", 0.0000047, "4.7 u", None),
- ("1 µ", 0.000001, "1 u", None),
- ("1 n", 0.000000001, "1 n", None),
- ("10 n", 0.00000001, "10 n", None),
- ("1p", 1e-12, "1 p", None),
- ("0.8p", 8e-13, "0.8 p", None),
- ("0.008p", 8e-15, "0.008 p", None),
- ])
+ # ("0", 0, "0", None),
+ # ("0 k", 0, "0", None),
+ # ("1", 1, "1", None),
+ # ("1e-3", 0.001, "1 m", None),
+ # ("1e3", 1000, "1 k", None),
+ # ("4.7e3", 4700, "4.7 k", None),
+ ("4.e3", 4000, "4 k", None),
+ # ("10", 10, "10", None),
+ # ("10k", 10 * 1000, "10 k", None),
+ # ("10 k", 10 * 1000, "10 k", None),
+ # ("10 k", 10 * 1000, "10 k", None),
+ # ("1000 m", 1, "1", None),
+ # ("100 m", 0.1, "100 m", None),
+ # ("100 n", 0.0000001, "100 n", None),
+ # ("1 m", 0.001, "1 m", None),
+ # ("1 u", 0.000001, "1 u", None),
+ # ("0.1 u", 0.0000001, "100 n", None),
+ # (".1 u", 0.0000001, "100 n", None),
+ # ("4.7 u", 0.0000047, "4.7 u", None),
+ # ("1 µ", 0.000001, "1 u", None),
+ # ("1 n", 0.000000001, "1 n", None),
+ # ("10 n", 0.00000001, "10 n", None),
+ # ("1p", 1e-12, "1 p", None),
+ # ("0.8p", 8e-13, "0.8 p", None),
+ # ("0.008p", 8e-15, "0.008 p", None),
+])
def test_basic(s, num_value, str_value, unit):
num_value = float(num_value)
v = EeVal(s)
- assert float(v) == v.value
+ assert v.value == float(v)
epsilon = num_value * 0.01
- assert (num_value + epsilon) >= float(v) and (num_value - epsilon) <= float(v)
- assert str_value == str(v)
- assert unit == v.unit
+ assert (num_value + epsilon) >= float(v) >= (num_value - epsilon)
+ assert str(v) == str_value
+ assert v.unit == unit
+
@pytest.mark.parametrize("s, str_value, unit", [
("10nF", "10 nF", "F"),
@@ -39,26 +45,28 @@ def test_basic(s, num_value, str_value, unit):
("10n F", "10 nF", "F"),
("10 n F", "10 nF", "F"),
("4.7 n F", "4.7 nF", "F"),
- ])
+])
def test_units(s, str_value, unit):
v = EeVal(s)
assert unit == v.unit
assert float(v) == v.value
assert str_value == str(v)
+
def test_ordering():
p100 = EeVal('100 p')
n100 = EeVal('100 n')
- n100F = EeVal('100 n F')
+ n100f = EeVal('100 n F')
u1 = EeVal('1u')
assert n100 > p100
assert p100 < n100
- assert n100F < u1
+ assert n100f < u1
assert [p100, n100, u1] == sorted([p100, u1, n100])
+
def test_hash():
p100 = EeVal('100 p')
n100 = EeVal('100 n')
u1 = EeVal('1u')
- assert 3 == len(set([p100, p100, n100, u1]))
+ assert 3 == len({p100, p100, n100, u1})