Source code for zero.datasheet.parts

"""Electronic parts and datasheets"""

import os
import sys
import subprocess
import re
import datetime
import logging
import dateutil.parser
from click import launch

from ..misc import Downloadable

LOGGER = logging.getLogger(__name__)


[docs]class Part: def __init__(self, part_info, path=None, timeout=None, progress=False): self.path = path self.timeout = timeout self.progress = progress self.brand = None self.brand_url = None self.manufacturer = None self.manufacturer_url = None self.mpn = None self.url = None self.datasheets = [] self._parse(part_info) def _parse(self, part_info): if part_info.get("brand"): if part_info["brand"].get("name"): self.brand = part_info["brand"]["name"] if part_info["brand"].get("homepage_url"): self.brand_url = part_info["brand"]["homepage_url"] if part_info.get("manufacturer"): if part_info["manufacturer"].get("name"): self.manufacturer = part_info["manufacturer"]["name"] if part_info["manufacturer"].get("homepage_url"): self.manufacturer_url = part_info["manufacturer"]["homepage_url"] if part_info.get("mpn"): self.mpn = part_info["mpn"] if part_info.get("octopart_url"): self.url = part_info["octopart_url"] if part_info.get("datasheets"): self.datasheets = [Datasheet(datasheet, part_name=self.mpn, path=self.path, timeout=self.timeout, progress=self.progress) for datasheet in part_info["datasheets"]] @property def n_datasheets(self): return len(self.datasheets) @property def sorted_datasheets(self): # order datasheets return sorted(self.datasheets, reverse=True, key=nonesorter) @property def latest_datasheet(self): return next(iter(self.sorted_datasheets), None) def __repr__(self): return f"{self.brand} / {self.manufacturer} {self.mpn}"
[docs]class Datasheet(Downloadable): def __init__(self, datasheet_data, part_name=None, path=None, **kwargs): """Datasheet. Parameters ---------- path : :class:`str` or file Path to store downloaded file. If a directory is specified, the downloaded part name is used. """ super().__init__(**kwargs) self.part_name = part_name self.path = path self.created = None self.n_pages = None self.url = None # flag for whether datasheet PDF has been downloaded self._downloaded = False self._parse(datasheet_data) def _parse(self, datasheet_data): if datasheet_data.get("metadata"): if datasheet_data["metadata"].get("date_created"): self.created = dateutil.parser.parse(datasheet_data["metadata"]["date_created"]) if datasheet_data["metadata"].get("num_pages"): self.n_pages = int(datasheet_data["metadata"]["num_pages"]) self.url = datasheet_data["url"] @property def full_path(self): """Get path to store datasheet including filename, or None if no path is set""" path = self.path if os.path.isdir(path): # add filename path = os.path.join(path, self.safe_filename) return path @property def safe_part_name(self): """Sanitise part name, generating one if one doesn't exist""" part_name = self.part_name if self.part_name is None: part_name = "unknown" return part_name @property def safe_filename(self): """Sanitise filename for storing on the file system""" filename = self.safe_part_name filename = str(filename).strip().replace(' ', '_') filename = re.sub(r'(?u)[^-\w.]', '', filename) # add extension filename = filename + os.path.extsep + "pdf" return filename
[docs] def download(self, force=False): if self._downloaded and not force: # already downloaded return filename, _ = self.fetch_file(url=self.url, filename=self.path, label=f"Downloading {self.part_name}") # update path, if necessary self.path = filename self._downloaded = True
[docs] def display(self): self.download() launch(self.path)
def __str__(self): if self.created is not None: created = self.created.strftime("%Y-%m-%d") else: created = "?" if self.n_pages is not None: pages = self.n_pages else: pages = "unknown" return f"Datasheet (created {created}, {pages} pages)"
[docs]def nonesorter(datasheet): """Return datasheet creation date, or minimum time, for the purposes of sorting.""" if getattr(datasheet, "created", None) is None: # use minimum date zero = datetime.datetime.min zero.replace(tzinfo=None) return zero return datasheet.created.replace(tzinfo=None)