Skip to content

Commit d87e46e

Browse files
authored
Set up pre-commit (#289)
* Add pre-commit config * Fix codespell warnings * Add mypy as pre-commit hook * Fix remaining mypy errors * Run pre-commit in github CI * Run linters before setting up OpenModelica in CI This should make workflow runs with linter errors fail faster. * Fix mypy warning on Windows
1 parent a5c8a83 commit d87e46e

File tree

7 files changed

+100
-50
lines changed

7 files changed

+100
-50
lines changed

.github/workflows/Test.yml

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@ jobs:
1919
steps:
2020
- uses: actions/checkout@v4
2121

22-
- name: "Set up OpenModelica Compiler"
23-
uses: OpenModelica/[email protected]
24-
with:
25-
version: ${{ matrix.omc-version }}
26-
packages: |
27-
omc
28-
libraries: |
29-
'Modelica 4.0.0'
30-
- run: "omc --version"
31-
3222
- name: Set up Python ${{ matrix.python-version }}
3323
uses: actions/setup-python@v5
3424
with:
@@ -38,16 +28,25 @@ jobs:
3828
- name: Install dependencies
3929
run: |
4030
python -m pip install --upgrade pip
41-
pip install . pytest pytest-md pytest-emoji flake8
31+
pip install . pytest pytest-md pytest-emoji pre-commit
4232
4333
- name: Set timezone
4434
uses: szenius/[email protected]
4535
with:
4636
timezoneLinux: 'Europe/Berlin'
4737

48-
- name: Lint with flake8
49-
run: |
50-
flake8 . --count --statistics
38+
- name: Run pre-commit linters
39+
run: 'pre-commit run --all-files'
40+
41+
- name: "Set up OpenModelica Compiler"
42+
uses: OpenModelica/[email protected]
43+
with:
44+
version: ${{ matrix.omc-version }}
45+
packages: |
46+
omc
47+
libraries: |
48+
'Modelica 4.0.0'
49+
- run: "omc --version"
5150

5251
- name: Run pytest
5352
uses: pavelzw/pytest-action@v2

.pre-commit-config.yaml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/pre-commit-hooks
3+
rev: v5.0.0
4+
hooks:
5+
- id: trailing-whitespace
6+
- id: end-of-file-fixer
7+
- id: check-case-conflict
8+
- id: check-docstring-first
9+
- id: check-executables-have-shebangs
10+
- id: check-shebang-scripts-are-executable
11+
- id: mixed-line-ending
12+
- id: debug-statements
13+
- id: destroyed-symlinks
14+
- id: fix-byte-order-marker
15+
- id: check-merge-conflict
16+
- id: name-tests-test
17+
args: [--pytest-test-first]
18+
19+
- repo: https://github.com/pycqa/flake8
20+
rev: '7.2.0'
21+
hooks:
22+
- id: flake8
23+
24+
- repo: https://github.com/codespell-project/codespell
25+
rev: v2.4.1
26+
hooks:
27+
- id: codespell
28+
29+
- repo: https://github.com/pre-commit/mirrors-mypy.git
30+
rev: "v1.15.0"
31+
hooks:
32+
- id: mypy
33+
args: []
34+
exclude: tests/
35+
additional_dependencies:
36+
- pyparsing
37+
- types-psutil
38+
- pyzmq
39+
- numpy

OMPython/ModelicaSystem.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
import subprocess
4646
import tempfile
4747
import textwrap
48-
from typing import Optional
48+
from typing import Optional, Any
4949
import warnings
5050
import xml.etree.ElementTree as ET
5151

@@ -369,20 +369,23 @@ def __init__(
369369
if modelName is None:
370370
raise ModelicaSystemError("A modelname must be provided (argument modelName)!")
371371

372-
self.quantitiesList = []
373-
self.paramlist = {}
374-
self.inputlist = {}
375-
self.outputlist = {}
376-
self.continuouslist = {}
377-
self.simulateOptions = {}
378-
self.overridevariables = {}
379-
self.simoptionsoverride = {}
372+
self.quantitiesList: list[dict[str, Any]] = []
373+
self.paramlist: dict[str, str] = {} # even numerical values are stored as str
374+
self.inputlist: dict[str, list | None] = {}
375+
# outputlist values are str before simulate(), but they can be
376+
# np.float64 after simulate().
377+
self.outputlist: dict[str, Any] = {}
378+
# same for continuouslist
379+
self.continuouslist: dict[str, Any] = {}
380+
self.simulateOptions: dict[str, str] = {}
381+
self.overridevariables: dict[str, str] = {}
382+
self.simoptionsoverride: dict[str, str] = {}
380383
self.linearOptions = {'startTime': 0.0, 'stopTime': 1.0, 'stepSize': 0.002, 'tolerance': 1e-8}
381384
self.optimizeOptions = {'startTime': 0.0, 'stopTime': 1.0, 'numberOfIntervals': 500, 'stepSize': 0.002,
382385
'tolerance': 1e-8}
383-
self.linearinputs = [] # linearization input list
384-
self.linearoutputs = [] # linearization output list
385-
self.linearstates = [] # linearization states list
386+
self.linearinputs: list[str] = [] # linearization input list
387+
self.linearoutputs: list[str] = [] # linearization output list
388+
self.linearstates: list[str] = [] # linearization states list
386389

387390
if session is not None:
388391
if not isinstance(session, OMCSessionZMQ):

OMPython/OMCSession.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,9 @@ def _getuid() -> int:
643643
On Windows, volumes are mapped with all files are chmod ugo+rwx,
644644
so uid does not matter as long as it is not the root user.
645645
"""
646-
return 1000 if sys.platform == 'win32' else os.getuid()
646+
# mypy complained about os.getuid() not being available on
647+
# Windows, hence the type: ignore comment.
648+
return 1000 if sys.platform == 'win32' else os.getuid() # type: ignore
647649

648650
def get_server_address(self) -> Optional[str]:
649651
if self._dockerNetwork == "separate" and isinstance(self._dockerCid, str):

OMPython/OMParser.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -468,15 +468,13 @@ def make_elements(strings):
468468
skip_start = index + 1
469469
if strings[skip_start] == "{":
470470
skip_brace += 1
471-
indx = skip_start
472-
while indx < len(strings):
473-
char = strings[indx]
471+
for i in range(skip_start, len(strings)):
472+
char = strings[i]
474473
if char == "}":
475474
skip_brace -= 1
476475
if skip_brace == 0:
477-
index = indx + 1
476+
index = i + 1
478477
break
479-
indx += 1
480478

481479
index += 1
482480

@@ -523,21 +521,21 @@ def make_elements(strings):
523521

524522

525523
def check_for_next_string(next_string):
526-
anchorr = 0
527-
positionn = 0
528-
stopp = 0
524+
anchor = 0
525+
position = 0
526+
stop = 0
529527

530528
# remove braces & keep only the SET's values
531-
while positionn < len(next_string):
532-
check_str = next_string[positionn]
529+
while position < len(next_string):
530+
check_str = next_string[position]
533531
if check_str == "{":
534-
anchorr = positionn
532+
anchor = position
535533
elif check_str == "}":
536-
stopp = positionn
537-
delStr = next_string[anchorr:stopp + 1]
534+
stop = position
535+
delStr = next_string[anchor:stop + 1]
538536
next_string = next_string.replace(delStr, '')
539-
positionn = -1
540-
positionn += 1
537+
position = -1
538+
position += 1
541539

542540
if isinstance(next_string, str):
543541
if len(next_string) == 0:
@@ -616,16 +614,14 @@ def skip_all_inner_sets(position):
616614
if brace_count == 0:
617615
break
618616
elif s == "=" and string[position + 1] == "{":
619-
indx = position + 2
620617
skip_brace = 1
621-
while indx < end_of_main_set:
622-
char = string[indx]
618+
for i in range(position + 2, end_of_main_set):
619+
char = string[i]
623620
if char == "}":
624621
skip_brace -= 1
625622
if skip_brace == 0:
626-
position = indx + 1
623+
position = i + 1
627624
break
628-
indx += 1
629625
position += 1
630626
position += 1
631627
elif char == "{" and string[position + 1] == "{":

OMPython/OMTypedParser.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,11 @@ def evaluateExpression(s, loc, toks):
107107
omcRecord = Forward()
108108
omcValue = Forward()
109109

110-
TRUE = Keyword("true").setParseAction(replaceWith(True))
111-
FALSE = Keyword("false").setParseAction(replaceWith(False))
112-
NONE = (Keyword("NONE") + Suppress("(") + Suppress(")")).setParseAction(replaceWith(None))
110+
# pyparsing's replace_with (and thus replaceWith) has incorrect type
111+
# annotation: https://github.com/pyparsing/pyparsing/issues/602
112+
TRUE = Keyword("true").setParseAction(replaceWith(True)) # type: ignore
113+
FALSE = Keyword("false").setParseAction(replaceWith(False)) # type: ignore
114+
NONE = (Keyword("NONE") + Suppress("(") + Suppress(")")).setParseAction(replaceWith(None)) # type: ignore
113115
SOME = (Suppress(Keyword("SOME")) + Suppress("(") + omcValue + Suppress(")"))
114116

115117
omcString = QuotedString(quoteChar='"', escChar='\\', multiline=True).setParseAction(convertString)

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ online.
5353
- Submit bugs through the [OpenModelica GitHub issues](https://github.com/OpenModelica/OMPython/issues/new).
5454
- [Pull requests](https://github.com/OpenModelica/OMPython/pulls) are welcome.
5555

56+
57+
## Development
58+
It is recommended to set up [`pre-commit`](https://pre-commit.com/) to
59+
automatically run linters:
60+
```sh
61+
# cd to the root of the repository
62+
pre-commit install
63+
```
64+
5665
## Contact
5766

5867
- Adeel Asghar, <[email protected]>

0 commit comments

Comments
 (0)