#!/usr/bin/env python3 import urllib.parse import owlready2 as owl import re import shutil import types from collections import defaultdict from jinja2 import Environment, FileSystemLoader, select_autoescape from openpyxl import load_workbook from pathlib import Path from itertools import groupby env = Environment( loader=FileSystemLoader("."), trim_blocks=True, lstrip_blocks=True, autoescape=select_autoescape(['html', 'xml']) ) files = [ ("STM32 High Performance MCUs.xlsx", "High Performance"), ("STM32 Mainstream MCUs.xlsx", "Mainstream"), ("STM32 Ultra Low Power MCUs.xlsx", "Ultra Low Power"), ("STM32 Wireless MCUs.xlsx", "Wireless"), ] series_r = r"^(STM32F.|STM32H.|STM32L[012356789]|STM32L4[RS]|STM32L4|STM32WB).*" def load_file(filename, line): wb = load_workbook(filename=filename) ws = wb.active header = ws[6] fields = [cell.value for cell in header] data_properties = {} for field in fields: class_name = field class_name = class_name.lower() class_name = class_name.replace(" ", "-") class_name = class_name.replace("/", "") class_name = class_name.replace("(", "") class_name = class_name.replace(")", "") cls = types.new_class(class_name, (owl.DataProperty,)) cls.label = "Has {}".format(field) cls.domain = [Chip] data_properties[field] = cls # print("Header") # print(fields) parts = {} split_set = set([ "Package", "Other timer functions", "Parallel Interfaces", "Additional Serial Interfaces", "Crypto-HASH", "USB Type", "Connectivity supported", "Operating Temperature (°C) min", "Operating Temperature (°C) max", "Supply Current (µA) (Lowest power mode) typ", "Display controller", ]) field_re = r" +" for row in ws.iter_rows(min_row=7): part_number = row[0].value parts[part_number] = part = {} for idx, cell in enumerate(row): v = cell.value v = None if v == "-" else v if v is None: continue field = fields[idx] field = field.strip() field = re.sub(field_re, " ", field) if field in split_set: v = list(v.split(",")) try: if isinstance(v, list): v = [int(x) for x in v] else: v = int(v) except ValueError: pass part[field] = v part["Line"] = line part["Series"] = re.findall(series_r, part["Part Number"])[0] part["00 FLASH"] = part["FLASH Size (kB) (Prog)"] # This is probably a bug in the spreadsheet. part["00 RAM"] = part["RAM Size (kB)"] if "RAM Size (kB)" in part else None if False: for part in parts.values(): for k, v in part.items(): if isinstance(v, list): print(k) for item in v: print(" {}".format(item)) else: print("{}: {}".format(k, v)) return parts, data_properties def process_parts(parts, data_properties): r = r"^(STM32F.|STM32H.|STM32L[012356789]|STM32L4[RS]|STM32L4|STM32WB).*" subfamily = lambda p: p["Part Number"][0:9] # for p in parts.values(): # x = subfamily(p) # print("{} => {}".format(p["Part Number"], x)) for subfamily, values in groupby(sorted(parts.values(), key=subfamily), key=subfamily): write_parts(subfamily, list(values), data_properties) def write_parts(subfamily, parts, data_properties): fields = list(next(parts.__iter__()).keys()) # [print("fieldXXX:{}".format(f)) for f in fields] print("subfamily: {}".format(subfamily)) chip = Chip(subfamily) chip.label = subfamily distinct_fields = set() shared_fields = {} for field in fields: if field in distinct_fields: # chip.setattr(data_properties[field]()) continue first = True for part in parts: part_number = part["Part Number"] if first: value = part[field] shared_fields[field] = value first = False else: field_value = part[field] if field in part else None if field_value != value: distinct_fields.add(field) del shared_fields[field] break # print("shared_fields={}".format(shared_fields)) # print("distinct_fields={}".format(list(distinct_fields))) # parts = sorted(parts, key=lambda p: (p["00 FLASH"], p["00 RAM"])) path = out_dir / "Chip:{}.mw".format(subfamily) with open(path, "w") as out: template = env.get_template("mw.j2") out.write(template.render( fields=fields, shared_fields=shared_fields, distinct_fields=sorted(distinct_fields), parts=parts)) out_dir = Path("mw") owl_dir = Path("owl") for d in [out_dir, owl_dir]: if d.exists(): shutil.rmtree(d) d.mkdir() base_url = "https://trygvis.io/owl/stm32" onto = owl.get_ontology("{}/stm32-shared.owl".format(base_url)) shared_url = onto.base_iri with onto: class Chip(owl.Thing): pass Chip.label = "Chip" class Line(owl.DataProperty): domain = [Chip] range = [str] Line.label = "Line" with open(owl_dir / Path(onto.base_iri).name[0:-1], "wb") as f: onto.save(f) for filename, line in files: owl_file = "stm32-{}.owl".format(filename[:-5]) url = "{}/{}".format(base_url, urllib.parse.quote(owl_file)) onto = owl.get_ontology(url) with onto: parts, data_properties = load_file(filename, line) process_parts(parts, data_properties) with open(owl_dir / owl_file, "wb") as f: onto.save(f)