Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
KOLANICH committed Sep 30, 2023
0 parents commit 5555cea
Show file tree
Hide file tree
Showing 42 changed files with 7,712 additions and 0 deletions.
Empty file added .ci/aptPackagesToInstall.txt
Empty file.
Empty file.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
charset = utf-8
indent_style = tab
indent_size = 4
insert_final_newline = true
end_of_line = lf

[*.{yml,yaml,yug}]
indent_style = space
indent_size = 2
1 change: 1 addition & 0 deletions .github/.templateMarker
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
KOLANICH/python_project_boilerplate.py
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
allow:
- dependency-type: "all"
15 changes: 15 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
build:
runs-on: ubuntu-22.04
steps:
- name: typical python workflow
uses: KOLANICH-GHActions/typical-python-workflow@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
*.log
*.pdf

__pycache__
*.py[co]
/*.egg-info
*.srctrlbm
*.srctrldb
build
dist
.eggs
monkeytype.sqlite3
/.ipynb_checkpoints
51 changes: 51 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
image: registry.gitlab.com/kolanich-subgroups/docker-images/fixed_python:latest

variables:
DOCKER_DRIVER: overlay2
SAST_ANALYZER_IMAGE_TAG: latest
SAST_DISABLE_DIND: "true"
SAST_CONFIDENCE_LEVEL: 5
CODECLIMATE_VERSION: latest

include:
- template: SAST.gitlab-ci.yml
- template: Code-Quality.gitlab-ci.yml
- template: License-Management.gitlab-ci.yml

build:
tags:
- shared
- linux
stage: build
variables:
GIT_DEPTH: "1"
PYTHONUSERBASE: ${CI_PROJECT_DIR}/python_user_packages

before_script:
- export PATH="$PATH:$PYTHONUSERBASE/bin" # don't move into `variables`
- apt-get update
# todo:
#- apt-get -y install
#- pip3 install --upgrade
#- python3 ./fix_python_modules_paths.py

script:
- python3 -m build -nw bdist_wheel
- mv ./dist/*.whl ./dist/FullingMotorModelDecoder-0.CI-py3-none-any.whl
- pip3 install --upgrade ./dist/*.whl
- coverage run --source=FullingMotorModelDecoder -m --branch pytest --junitxml=./rspec.xml ./tests/test.py
- coverage report -m
- coverage xml

coverage: "/^TOTAL(?:\\s+\\d+){4}\\s+(\\d+%).+/"

cache:
paths:
- $PYTHONUSERBASE

artifacts:
paths:
- dist
reports:
junit: ./rspec.xml
cobertura: ./coverage.xml
1 change: 1 addition & 0 deletions Code_Of_Conduct.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No codes of conduct!
141 changes: 141 additions & 0 deletions FullingMotorModelDecoder/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
from pathlib import Path
from warnings import warn
import typing

from UniGrammarRuntime.ParserBundle import ParserBundle

_thisDir = Path(__file__).parent

bundleDir = _thisDir / "parserBundle"
bundle = ParserBundle(bundleDir)
grammar = bundle.grammars["fulling_motor_name"]
wrapper = grammar.getWrapper("antlr4")


def decodeShaftsCount(letter: str) -> int:
return ord(letter.upper()) - ord("A") + 1

from icecream import ic

def _decodeParsed(p) -> dict:
res = {}
res["size"] = int(p.size)
tpd = p.typed
series = tpd.__class__.__name__[:-2]
res["type"] = series
#
m = tpd.type_marker

def processSuffix(stepsLower: typing.Optional[int] = None):
sfx = tpd.suffix
if sfx:
sb = sfx.suffix_body
try:
# current_rated current_peak_max current_per_phase current_unloaded
res["current_per_phase"] = int(sb.current) / 10 ** (len(sb.current) - 1)
except AttributeError:
st = sb
else:
st = sb.tail

res["variant"] = int(st.variant)
res["encoder"] = bool(st.encoder)
res["key_way"] = bool(st.key_way)
res["screwed_shaft"] = bool(st.screwed_shaft)
res["unknown_F"] = bool(st.unknown_F)
res["hollow"] = bool(st.hollow)

scsr = st.shafts_count_and_step_rate_any_order
if scsr.shafts_count:
res["shafts_count"] = decodeShaftsCount(scsr.shafts_count)
if stepsLower is not None:
res["steps_per_revolution"] = stepsLower * 2 if scsr.step_rate else stepsLower

if st.gearbox:
res["gearbox"] = float(st.gearbox.ratio)
else:
res["gearbox"] = None

#res[series] = True
if series == "brushless":
for k in m.__slots__:
if getattr(m, k):
res[k[3:]] = True

modifier = tpd.modifier

try:
res["motor_body_length"] = int(modifier.motor_body_length)
except AttributeError:
res["poles_or_other"] = modifier.poles_or_other # usually determines count of poles, A models have more poles (usually 10) than non-lettered models (usually 8), B models have more poles (usually 6) than non-lettered models, but some B models have no A analogues and have 8 poles and C models usually have no analogues and also have 8 poles.
res["variant"] = int(modifier.variant)
else:
if modifier.tail: # ToDo: from the parsed ones I see no tail
try:
res['electronics'] = bool(modifier.tail.has_electronics)
except AttributeError:
cfg = modifier.tail
else:
cfg = modifier.tail.cfg
else:
cfg = None

if cfg:
unit2Name = {
"V": 'voltage',
"A": "current"
}

quantityKeyName = unit2Name[cfg.unit] + "_rated"
res[quantityKeyName] = int(cfg.number)

elif series == "stepper":
res["motor_body_length"] = int(tpd.motor_body_length)
markers = {
None: "standard",
"T": "standard",
'H': "hybrid"
}
res["series"] = markers[m.series]

if tpd.stepper_modifiers:
modifiers = {
'H': {"high_torque": True},
'C': {"hyper_torque": True},
}
res.update(modifiers[tpd.stepper_modifiers])

processSuffix(200)

elif series == "permanent":
res["motor_body_length"] = int(tpd.motor_body_length)
processSuffix(None) # usually stepsLower=20, but not always
elif series == "three_phase":
res["motor_body_length"] = int(tpd.motor_body_length)
sfx = tpd.suffix
if sfx:
res["current_per_phase"] = int(sfx.current_per_phase_over_ten) / 10
if sfx.leads:
res["input_count"] = int(sfx.leads)
if sfx.shafts_count:
res["shafts_count"] = decodeShaftsCount(sfx.shafts_count)

else:
raise ValueError(series)


steps = res.get("steps_per_revolution", None)
if steps:
res['angle_step'] = 360 / steps

for shapeType in ("round", "square"):
if res.get(shapeType, None):
del res[shapeType]
res["shape"] = shapeType

return res

def decodeModel(s: str) -> dict:
p = wrapper(s)
#print(p)
return _decodeParsed(p)
95 changes: 95 additions & 0 deletions FullingMotorModelDecoder/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import sys, json, re
from . import decodeModel
from collections import OrderedDict
#from .utils import makeSerializeable

import importlib.util


def ifModExists(modName):
return importlib.util.find_spec(modName) is not None


useML = ifModExists("numpy") and ifModExists("pandas") and ifModExists("xgboost") and ifModExists("Chassis") and ifModExists("AutoXGBoost")

try:
from RichConsole import groups, rsjoin

styles = {
"prefix": groups.Fore.lightcyanEx,
"cli": groups.Fore.lightgreenEx,
"help": groups.Fore.lightmagentaEx,
}
except:
styles = {
"prefix": lambda x: x,
"cli": lambda x: x,
"help": lambda x: x,
}

def rsjoin(self, *args, **kwargs):
return self.join(*args, **kwargs)


endMainRx = re.compile("\.__main__$")
wsRx = re.compile("\s")


def splitByWhitespaces(file):
for l in file:
yield from wsRx.split(l)


def showHelp():
if sys.platform == "win32":
try:
import colorama

colorama.init()
except:
pass
prefix = styles["prefix"](rsjoin(" ", ("python -m", endMainRx.sub("", __spec__.name))))
print(rsjoin("\n", (styles["cli"](rsjoin(" ", (prefix, cliArg))) + styles["help"](" - " + par[1]) for cliArg, par in singleArgLUT.items())))


def getModelObj(mn):
#return makeSerializeable(decodeModel(mn, useML, True))
return decodeModel(mn)


def whole(modelNames):
json.dump(OrderedDict(((el, getModelObj(el)) for el in modelNames)), sys.stdout, indent="\t")


def fromStdinByOne():
for el in filter(None, splitByWhitespaces(sys.stdin)):
json.dump(getModelObj(el), sys.stdout, indent="\t")
sys.stdout.write("\n")
sys.stdout.flush()


def fromStdinWhole():
whole(filter(None, splitByWhitespaces(sys.stdin)))


singleArgLUT = OrderedDict((
("model_name_1, model_name_2, ...", (None, "to pass models namebers as parameters")),
("--", (fromStdinByOne, "to pipe models namebers into stdin and get the results as JSON one by one")),
("-", (fromStdinWhole, "to pipe models namebers file into stdin and get the results as a JSON array")),
("-h", (showHelp, "shows help")),
("--help", (showHelp, "shows help")),
))


def main():
if len(sys.argv) < 2:
showHelp()
elif len(sys.argv) == 2 and sys.argv[1] in singleArgLUT:
singleArgLUT[sys.argv[1]][0]()
else:
whole(sys.argv[1:])
sys.stdout.write("\n")


if __name__ == "__main__":
main()
Empty file.
Loading

0 comments on commit 5555cea

Please sign in to comment.