adding initial version
commit
a425964e4a
|
@ -0,0 +1,32 @@
|
||||||
|
web interface for accessing Hackerspace electronic parts information stored on
|
||||||
|
`inventory system`_
|
||||||
|
|
||||||
|
.. _inventory system: https://wiki.hackerspace.pl/members:services:inventory
|
||||||
|
|
||||||
|
Status
|
||||||
|
------
|
||||||
|
There is only one webpage listing SMD resistors in `BOXALL`_ container. Other functionality is not
|
||||||
|
there yet.
|
||||||
|
|
||||||
|
.. _BOXALL: http://aidetek.com/mm5/merchant.mvc?Screen=PROD&Store_Code=A&Product_Code=BOXALL&Category_Code=Encl
|
||||||
|
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
|
||||||
|
* form for adding new resistor (requires access token)
|
||||||
|
* generating pdf version
|
||||||
|
* toggle between metric and imperial units
|
||||||
|
* other component types
|
||||||
|
* integration into inventory (module?)
|
||||||
|
|
||||||
|
Running
|
||||||
|
-------
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
# prepare virtual environment
|
||||||
|
python3 -m venv venv
|
||||||
|
./venv/bin/pip install "${PATH_TO_REPO}"
|
||||||
|
./venv/bin/pip install gunicorn
|
||||||
|
|
||||||
|
# run application
|
||||||
|
./venv/bin/gunicorn 'electronics_inventory.webapp:app()'
|
|
@ -0,0 +1,16 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
|
||||||
|
pkgs.python3Packages.buildPythonPackage {
|
||||||
|
pname = "hs-electronics-inventory";
|
||||||
|
version = "1.0";
|
||||||
|
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
propagatedBuildInputs = with pkgs; [
|
||||||
|
python3Packages.jinja2
|
||||||
|
python3Packages.requests
|
||||||
|
python3Packages.setuptools
|
||||||
|
python3Packages.flask
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
import decimal
|
||||||
|
import re
|
||||||
|
import enum
|
||||||
|
import collections
|
||||||
|
|
||||||
|
from . import si
|
||||||
|
|
||||||
|
unit_ord = ("full", "utf", "ascii")
|
||||||
|
UnitDef = collections.namedtuple("UnitDef", unit_ord)
|
||||||
|
unit_defs = {
|
||||||
|
UnitDef("ohm", "Ω", "R"),
|
||||||
|
UnitDef("volt", "V", "V"),
|
||||||
|
UnitDef("amper", "A", "A"),
|
||||||
|
}
|
||||||
|
|
||||||
|
units_dicts = []
|
||||||
|
for r in unit_ord:
|
||||||
|
d = dict()
|
||||||
|
for u in unit_defs:
|
||||||
|
d[getattr(u, r)] = u
|
||||||
|
units_dicts.append(d)
|
||||||
|
|
||||||
|
|
||||||
|
def symbol_to_unitdef(symbol):
|
||||||
|
for ud in units_dicts:
|
||||||
|
if symbol in ud:
|
||||||
|
return ud[symbol]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Component:
|
||||||
|
class Unit:
|
||||||
|
def __init__(self, unit):
|
||||||
|
if isinstance(unit, type(self)):
|
||||||
|
self.u = unit.u
|
||||||
|
elif isinstance(unit, UnitDef):
|
||||||
|
self.u = unit
|
||||||
|
else:
|
||||||
|
self.u = symbol_to_unitdef(unit)
|
||||||
|
if self.u is None:
|
||||||
|
raise ValueError("invalid unit")
|
||||||
|
|
||||||
|
def __str__(self, _ord="utf"):
|
||||||
|
return getattr(self.u, _ord)
|
||||||
|
|
||||||
|
class Value:
|
||||||
|
def __init__(self, value, unit=None):
|
||||||
|
self.unit = Component.Unit(unit)
|
||||||
|
if isinstance(value, str):
|
||||||
|
self.value = decode_infix(value)
|
||||||
|
else:
|
||||||
|
self.value = decimal.Decimal(value)
|
||||||
|
|
||||||
|
def prefixed(self, replace_separator=True):
|
||||||
|
return si.prefix(self.value, replace_separator=replace_separator)
|
||||||
|
|
||||||
|
def __str__(self, unit_repr="utf8"):
|
||||||
|
if self.unit is None:
|
||||||
|
unit = None
|
||||||
|
elif unit_repr == "utf8":
|
||||||
|
unit = self.unit.u.utf
|
||||||
|
elif unit_repr == "ascii":
|
||||||
|
unit = self.unit.u.ascii
|
||||||
|
elif unit_repr == "full":
|
||||||
|
unit = self.unit.u.full
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid unit_repr: {!r:s}".format(unit_repr))
|
||||||
|
s = "{!s:s}".format(si.prefix(self.value))
|
||||||
|
if unit is not None:
|
||||||
|
s += " {:s}".format(unit)
|
||||||
|
return s
|
||||||
|
|
||||||
|
def __init__(self, value=None, package=None):
|
||||||
|
self.value = value
|
||||||
|
self.package = package
|
||||||
|
|
||||||
|
def to_item():
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_item(cls, item):
|
||||||
|
if re.match("rezystor", item.name):
|
||||||
|
return Resistor.from_item(item)
|
||||||
|
|
||||||
|
|
||||||
|
class Resistor(Component):
|
||||||
|
def __init__(self, resistance, package, tolerance):
|
||||||
|
if isinstance(resistance, str):
|
||||||
|
self.resistance = si.decode_infix(resistance)
|
||||||
|
else:
|
||||||
|
self.resistance = decimal.Decimal(value)
|
||||||
|
self.tolerance = str(tolerance)
|
||||||
|
self.package = str(package)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self):
|
||||||
|
return self.Value(self.resistance, "ohm")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_item(cls, item):
|
||||||
|
m = re.match("rezystor ([^ ]+) ([^ ]+)", item.name)
|
||||||
|
tolerance = item.props.get("tolerance", "unknown")
|
||||||
|
return cls(m.group(1), m.group(2), tolerance)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return """<Resistor('{!s:s}', '{!s:s}', '{:s}')>""".format(
|
||||||
|
self.value, self.package, self.tolerance
|
||||||
|
)
|
|
@ -0,0 +1,40 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>title</title>
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||||
|
<style type="text/css">
|
||||||
|
.compartment {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container"><div class="row">
|
||||||
|
{% for rt in columns %}
|
||||||
|
<div class="col-sm">
|
||||||
|
<table class="table table-sm table-bordered table-striped" style="width: auto;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"></th>
|
||||||
|
<th scope="col">resistance [Ω]</th>
|
||||||
|
<th scope="col">package</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for r in rt %}
|
||||||
|
<tr class='text-right'>
|
||||||
|
<th scope="row" class="compartment">{{ r.compartment }}</th>
|
||||||
|
<td>{{ r.resistance }}</td>
|
||||||
|
<td>{{ r.package }}</td>
|
||||||
|
<td>{{ r.tolerance }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div> </div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,85 @@
|
||||||
|
import collections
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
from typing import List, Tuple
|
||||||
|
from jinja2 import Template
|
||||||
|
from pkg_resources import resource_string
|
||||||
|
|
||||||
|
from . import si
|
||||||
|
from .spaceventory import Inventory
|
||||||
|
from .components import Component
|
||||||
|
|
||||||
|
|
||||||
|
RESISTORS_BOXALL = "28f37f99-45b1-4e85-940e-06273f786e59"
|
||||||
|
TEMPLATE = Template(resource_string(__name__, "resistors_boxall.html.jinja2").decode())
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_container(inventory: Inventory, uuid) -> Tuple[str, Component]:
|
||||||
|
"""fetch boxall resistors from inventory"""
|
||||||
|
l = []
|
||||||
|
for c in inventory.get_children(uuid):
|
||||||
|
try:
|
||||||
|
item = Component.from_item(c)
|
||||||
|
except Exception:
|
||||||
|
logging.exception(f"parsing component {c} failed")
|
||||||
|
continue
|
||||||
|
l.append((item, c.props["compartment"]))
|
||||||
|
return sorted(l, key=lambda r: r[0].resistance)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ResistorCompartment:
|
||||||
|
compartment: str
|
||||||
|
resistance: str
|
||||||
|
package: str
|
||||||
|
tolerance: str
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_resistors(inventory: Inventory) -> List[ResistorCompartment]:
|
||||||
|
rs = fetch_container(inventory, RESISTORS_BOXALL)
|
||||||
|
compartments = []
|
||||||
|
for resistor, compartment in rs:
|
||||||
|
value, prefix = si.prefix_tuple(resistor.value.value)
|
||||||
|
# unit = resistor.value.unit.u.utf
|
||||||
|
resistance = f"{value:.2f} {prefix}"
|
||||||
|
if resistor.tolerance != "unknown":
|
||||||
|
tolerance = resistor.tolerance
|
||||||
|
else:
|
||||||
|
tolerance = ""
|
||||||
|
compartments.append(
|
||||||
|
ResistorCompartment(
|
||||||
|
compartment=compartment,
|
||||||
|
resistance=resistance,
|
||||||
|
package=resistor.package,
|
||||||
|
tolerance=tolerance,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return compartments
|
||||||
|
|
||||||
|
|
||||||
|
def render(compartments: List[ResistorCompartment], column_count: int = 3) -> str:
|
||||||
|
# divide resistor list into columns
|
||||||
|
rows_count = math.ceil(len(compartments) / column_count)
|
||||||
|
columns = [
|
||||||
|
compartments[i : i + rows_count]
|
||||||
|
for i in range(0, len(compartments), rows_count)
|
||||||
|
]
|
||||||
|
|
||||||
|
return TEMPLATE.render(columns=columns)
|
||||||
|
|
||||||
|
|
||||||
|
def print_resistors():
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
token = os.environ.get("INVENTORY_TOKEN", getpass.getpass("Inventory token: "))
|
||||||
|
compartments = fetch_resistors(Inventory(token=token))
|
||||||
|
for cp in compartments:
|
||||||
|
print(
|
||||||
|
f"{cp.compartment:>4s} {cp.resistance:>8s} {cp.package:>4s} {cp.tolerance:>4s}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print_resistors()
|
|
@ -0,0 +1,99 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import math
|
||||||
|
import re
|
||||||
|
import decimal
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
|
si_table = {
|
||||||
|
-8: ("yocto", "y", "y", 10e-24),
|
||||||
|
-7: ("zepto", "z", "z", 10e-21),
|
||||||
|
-6: ("atto", "a", "a", 10e-18),
|
||||||
|
-5: ("femto", "f", "f", 10e-15),
|
||||||
|
-4: ("pico", "p", "p", 10e-12),
|
||||||
|
-3: ("nano", "n", "n", 10e-9),
|
||||||
|
-2: ("micro", "u", "μ", 10e-6),
|
||||||
|
-1: ("milli", "m", "m", 10e-3),
|
||||||
|
0: ("", "", "", 0),
|
||||||
|
1: ("kilo", "k", "k", 10e3),
|
||||||
|
2: ("mega", "M", "M", 10e6),
|
||||||
|
3: ("giga", "G", "G", 10e9),
|
||||||
|
4: ("tera", "T", "T", 10e12),
|
||||||
|
5: ("peta", "P", "P", 10e15),
|
||||||
|
6: ("exa", "E", "E", 10e18),
|
||||||
|
7: ("zetta", "Z", "Z", 10e21),
|
||||||
|
8: ("yotta", "Y", "Y", 10e24),
|
||||||
|
}
|
||||||
|
|
||||||
|
_si_letters_set: Set[str] = set()
|
||||||
|
for n in si_table:
|
||||||
|
_si_letters_set.add(si_table[n][1])
|
||||||
|
_si_letters_set.add(si_table[n][2])
|
||||||
|
|
||||||
|
si_letters = "".join(sorted(_si_letters_set))
|
||||||
|
|
||||||
|
|
||||||
|
def prefix_tuple(value, utf=True):
|
||||||
|
value = float(value)
|
||||||
|
ex = math.log(abs(value * 1.0000001), 10)
|
||||||
|
nex = math.floor(ex) // 3
|
||||||
|
nval = value / 10 ** (nex * 3)
|
||||||
|
if nex not in si_table:
|
||||||
|
raise ValueError("No suitable SI prefix found")
|
||||||
|
if utf == True:
|
||||||
|
px = si_table[nex][2]
|
||||||
|
else:
|
||||||
|
px = si_table[nex][1]
|
||||||
|
return (nval, px)
|
||||||
|
|
||||||
|
|
||||||
|
def prefix(value, utf=True, replace_separator=True):
|
||||||
|
v, px = prefix_tuple(value, utf)
|
||||||
|
if px == "":
|
||||||
|
return "{:1.2f}".format(v).rstrip("0").rstrip(".")
|
||||||
|
elif replace_separator == True:
|
||||||
|
s = "{:1.2f}".format(v).replace(".", px).rstrip("0").rstrip(".")
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
s = "{:1.2f}".format(v).rstrip("0").rstrip(".")
|
||||||
|
return s + " {:s}".format(px)
|
||||||
|
|
||||||
|
|
||||||
|
def power_by_prefix(string):
|
||||||
|
for v in si_table:
|
||||||
|
if string in si_table[v]:
|
||||||
|
return v
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
|
def decode_infix(string):
|
||||||
|
np = "^(([1-9][0-9]*)?[0-9](\.[0-9]+)?) ?([{:s}])?$".format(si_letters)
|
||||||
|
ni = "^(([1-9][0-9]*)?[0-9](([{:s}])[0-9]+)?)$".format(si_letters)
|
||||||
|
rp = re.match(np, string)
|
||||||
|
ri = re.match(ni, string)
|
||||||
|
if rp is not None:
|
||||||
|
if rp.groups()[3] is not None:
|
||||||
|
power = power_by_prefix(rp.groups()[3])
|
||||||
|
else:
|
||||||
|
power = 0
|
||||||
|
base = decimal.Decimal(rp.groups()[0])
|
||||||
|
return base * decimal.Decimal("10") ** (power * 3)
|
||||||
|
elif ri is not None:
|
||||||
|
base = decimal.Decimal(str(ri.groups()[0]).replace(ri.groups()[3], "."))
|
||||||
|
power = power_by_prefix(ri.groups()[3])
|
||||||
|
return base * decimal.Decimal("10") ** (power * 3)
|
||||||
|
else:
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(prefix(1.5632e11))
|
||||||
|
print(prefix(12.32e-9))
|
||||||
|
print(prefix(47000))
|
||||||
|
print(prefix(4700))
|
||||||
|
print(prefix(470))
|
||||||
|
|
||||||
|
print(si_letters)
|
||||||
|
print(decode_infix("0.23"))
|
||||||
|
print(decode_infix("470M"))
|
||||||
|
print(prefix(float(decode_infix("0k23"))))
|
|
@ -0,0 +1,153 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import enum
|
||||||
|
import os
|
||||||
|
from typing import List, Dict, Union, Optional
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Item:
|
||||||
|
class State(enum.Enum):
|
||||||
|
PRESENT = "present"
|
||||||
|
MISSING = "missing"
|
||||||
|
TAKEN = "taken"
|
||||||
|
|
||||||
|
description: str
|
||||||
|
parent: str
|
||||||
|
uuid: str
|
||||||
|
labels: List[str]
|
||||||
|
state: State
|
||||||
|
props: Dict[str, str]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
description=None,
|
||||||
|
parent=None,
|
||||||
|
uuid=None,
|
||||||
|
state=State.PRESENT,
|
||||||
|
labels=None,
|
||||||
|
props={},
|
||||||
|
):
|
||||||
|
self.name = str(name)
|
||||||
|
|
||||||
|
self.description = None
|
||||||
|
self.parent = None
|
||||||
|
self.uuid = None
|
||||||
|
self.labels = None
|
||||||
|
|
||||||
|
if description is not None:
|
||||||
|
self.description = str(description)
|
||||||
|
if parent is not None:
|
||||||
|
self.parent = str(parent)
|
||||||
|
if uuid is not None:
|
||||||
|
self.uuid = str(uuid)
|
||||||
|
if labels is not None:
|
||||||
|
self.labels = [str(label) for label in labels]
|
||||||
|
|
||||||
|
self.state = self.State(state)
|
||||||
|
self.props = dict(props)
|
||||||
|
|
||||||
|
# def __repr__(self):
|
||||||
|
# return f"<{self.__class__.__name__!s}(id='{self.uuid[:8]!s}', name='{self.name}')>"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, _dict: Dict[str, str]):
|
||||||
|
name = _dict["name"]
|
||||||
|
description = _dict["description"]
|
||||||
|
parent = _dict["parent"]
|
||||||
|
_uuid = _dict["uuid"]
|
||||||
|
state = _dict.get("state", cls.State.PRESENT)
|
||||||
|
props = _dict.get("props", dict())
|
||||||
|
labels = _dict.get("labels", [])
|
||||||
|
return cls(
|
||||||
|
name=name,
|
||||||
|
description=description,
|
||||||
|
parent=parent,
|
||||||
|
uuid=_uuid,
|
||||||
|
state=state,
|
||||||
|
labels=labels,
|
||||||
|
props=props,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
API_URL = "https://inventory.waw.hackerspace.pl/api/1/"
|
||||||
|
|
||||||
|
|
||||||
|
class Inventory:
|
||||||
|
def __init__(self, token: Optional[str] = None, api_url: str = API_URL):
|
||||||
|
self.token = token
|
||||||
|
self.headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
}
|
||||||
|
if token is not None:
|
||||||
|
self.headers["Authorization"] = f"Token {token}"
|
||||||
|
self.api_url = api_url
|
||||||
|
|
||||||
|
def _check_response(self, r):
|
||||||
|
if not r.ok:
|
||||||
|
raise Exception(str(r.text))
|
||||||
|
|
||||||
|
def get(self, path):
|
||||||
|
ret = requests.get(
|
||||||
|
self.api_url + str(path) + "?format=json", headers=self.headers
|
||||||
|
)
|
||||||
|
self._check_response(ret)
|
||||||
|
return ret.json()
|
||||||
|
|
||||||
|
def post(self, path, data):
|
||||||
|
ret = requests.post(
|
||||||
|
self.api_url + str(path), data=json.dumps(data), headers=self.headers
|
||||||
|
)
|
||||||
|
self._check_response(ret)
|
||||||
|
return ret.json()
|
||||||
|
|
||||||
|
def put(self, path, data):
|
||||||
|
ret = requests.put(
|
||||||
|
self.api_url + str(path), data=json.dumps(data), headers=self.headers
|
||||||
|
)
|
||||||
|
self._check_response(ret)
|
||||||
|
return ret.json()
|
||||||
|
|
||||||
|
def patch(self, path, data):
|
||||||
|
ret = requests.patch(
|
||||||
|
self.api_url + str(path), data=json.dumps(data), headers=self.headers
|
||||||
|
)
|
||||||
|
self._check_response(ret)
|
||||||
|
return ret.json()
|
||||||
|
|
||||||
|
def delete(self, path):
|
||||||
|
ret = requests.delete(self.api_url + str(path), headers=self.headers)
|
||||||
|
self._check_response(ret)
|
||||||
|
|
||||||
|
def delete_item(self, uuid):
|
||||||
|
ret = self.delete("items/{:s}".format(uuid))
|
||||||
|
self._check_response(ret)
|
||||||
|
|
||||||
|
def _get_uuid(self, i):
|
||||||
|
if isinstance(i, Item):
|
||||||
|
_uuid = i.uuid
|
||||||
|
elif isinstance(i, str):
|
||||||
|
_uuid = str(i)
|
||||||
|
else:
|
||||||
|
raise ValueError()
|
||||||
|
UUID(_uuid)
|
||||||
|
return _uuid
|
||||||
|
|
||||||
|
def get_item(self, item: Union[str, Item]):
|
||||||
|
_uuid = self._get_uuid(item)
|
||||||
|
r = self.get("items/{:s}".format(_uuid))
|
||||||
|
return Item.from_dict(r)
|
||||||
|
|
||||||
|
def get_children(self, parent: Union[str, Item]):
|
||||||
|
"""return list of children of item"""
|
||||||
|
_uuid = self._get_uuid(parent)
|
||||||
|
r = self.get("items/{:s}/children".format(_uuid))
|
||||||
|
cs = []
|
||||||
|
for c in r:
|
||||||
|
cs.append(Item.from_dict(c))
|
||||||
|
return cs
|
|
@ -0,0 +1,16 @@
|
||||||
|
from flask import Flask, Response, jsonify
|
||||||
|
from .spaceventory import Inventory
|
||||||
|
from .resistors_boxall import fetch_resistors, render
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def app():
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route("/index.html")
|
||||||
|
def resistors():
|
||||||
|
token = os.environ.get("INVENTORY_TOKEN", None)
|
||||||
|
compartments = fetch_resistors(Inventory(token=token))
|
||||||
|
return render(compartments)
|
||||||
|
|
||||||
|
return app
|
|
@ -0,0 +1,22 @@
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="hs-electronics-inventory",
|
||||||
|
version="1.0",
|
||||||
|
description="simple interface for electronic components backed by spacestore api",
|
||||||
|
author="Jan Wiśniewski",
|
||||||
|
author_email="vuko@hackerspace.pl",
|
||||||
|
classifiers=[
|
||||||
|
"License :: OSI Approved :: zlib/libpng License",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
],
|
||||||
|
packages=["electronics_inventory"],
|
||||||
|
python_requires=">=3.7,",
|
||||||
|
package_data={"electronics_inventory": ["resistors_boxall.html.jinja2"]},
|
||||||
|
install_requires=["jinja2", "setuptools", "requests", "flask"],
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
|
"hs-boxall=electronics_inventory.resistors_boxall:print_resistors"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
Loading…
Reference in New Issue