pymodaq_plugins_owis 5.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. pymodaq_plugins_owis-5.3.0/.gitattributes +2 -0
  2. pymodaq_plugins_owis-5.3.0/.github/dependabot.yml +7 -0
  3. pymodaq_plugins_owis-5.3.0/.github/scripts/check_template_versions.py +112 -0
  4. pymodaq_plugins_owis-5.3.0/.github/workflows/check-versions.yml +30 -0
  5. pymodaq_plugins_owis-5.3.0/.github/workflows/compatibility.yml +15 -0
  6. pymodaq_plugins_owis-5.3.0/.github/workflows/python-publish.yml +11 -0
  7. pymodaq_plugins_owis-5.3.0/.github/workflows/reusable-compatibility.yml +57 -0
  8. pymodaq_plugins_owis-5.3.0/.github/workflows/reusable-publish.yml +41 -0
  9. pymodaq_plugins_owis-5.3.0/.github/workflows/reusable-tests.yml +50 -0
  10. pymodaq_plugins_owis-5.3.0/.github/workflows/tests.yml +8 -0
  11. pymodaq_plugins_owis-5.3.0/.gitignore +117 -0
  12. pymodaq_plugins_owis-5.3.0/AGENTS.md +270 -0
  13. pymodaq_plugins_owis-5.3.0/CLAUDE.md +3 -0
  14. pymodaq_plugins_owis-5.3.0/LICENSE +21 -0
  15. pymodaq_plugins_owis-5.3.0/PKG-INFO +131 -0
  16. pymodaq_plugins_owis-5.3.0/README.rst +79 -0
  17. pymodaq_plugins_owis-5.3.0/hatch_build.py +10 -0
  18. pymodaq_plugins_owis-5.3.0/icon.ico +0 -0
  19. pymodaq_plugins_owis-5.3.0/pyproject.toml +61 -0
  20. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/__init__.py +13 -0
  21. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/app/__init__.py +0 -0
  22. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/daq_move_plugins/__init__.py +13 -0
  23. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/daq_move_plugins/daq_move_OWIS_PS10.py +135 -0
  24. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/daq_viewer_plugins/__init__.py +3 -0
  25. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/daq_viewer_plugins/plugins_0D/__init__.py +13 -0
  26. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/daq_viewer_plugins/plugins_1D/__init__.py +13 -0
  27. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/daq_viewer_plugins/plugins_2D/__init__.py +14 -0
  28. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/daq_viewer_plugins/plugins_ND/__init__.py +13 -0
  29. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/exporters/__init__.py +6 -0
  30. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/extensions/__init__.py +6 -0
  31. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/hardware/__init__.py +0 -0
  32. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/hardware/ps10.py +257 -0
  33. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/models/__init__.py +6 -0
  34. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/resources/__init__.py +0 -0
  35. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/resources/config_template.toml +29 -0
  36. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/scanners/__init__.py +6 -0
  37. pymodaq_plugins_owis-5.3.0/src/pymodaq_plugins_owis/utils.py +15 -0
  38. pymodaq_plugins_owis-5.3.0/tests/example_mock_plugins.py +115 -0
  39. pymodaq_plugins_owis-5.3.0/tests/test_owis_ps10.py +90 -0
  40. pymodaq_plugins_owis-5.3.0/tests/test_plugin_behaviour.py +94 -0
  41. pymodaq_plugins_owis-5.3.0/tests/test_plugin_package_structure.py +28 -0
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -0,0 +1,7 @@
1
+ # Template repository only: keeps the pinned versions of the GitHub actions up to date (as pull requests).
2
+ version: 2
3
+ updates:
4
+ - package-ecosystem: github-actions
5
+ directory: /
6
+ schedule:
7
+ interval: monthly
@@ -0,0 +1,112 @@
1
+ """Warn when the versions written in the template have drifted from PyMoDAQ's.
2
+
3
+ Run weekly by .github/workflows/check-versions.yml (only in the template repository, not in plugins).
4
+ Single source of truth: the ``pymodaq>=X.Y.Z`` floor of pyproject.toml. Everything else is compared to it and to what
5
+ PyPI says about the latest pymodaq. Standard library only. Exit code 1 if something needs a human.
6
+
7
+ When a new PyMoDAQ minor (say 5.4.0) is released
8
+ ------------------------------------------------
9
+ 1. Create the ``5.4.x`` branch from ``5.3.x`` and make it the default branch of the template repository.
10
+ 2. On it, raise the floors in pyproject.toml (``pymodaq>=5.4.0``...), the "PyMoDAQ 5.3.x" wording in README.rst and
11
+ AGENTS.md, requires-python and the matrix of reusable-compatibility.yml if they changed.
12
+ 3. Point the three caller workflows (``@5.3.x`` in tests.yml, compatibility.yml, python-publish.yml) to ``@5.4.x``.
13
+ 4. Run this script: it must print OK. Keep ``5.3.x`` for hotfixes.
14
+ """
15
+ import json
16
+ import re
17
+ import sys
18
+ import tomllib
19
+ import urllib.request
20
+ from pathlib import Path
21
+
22
+ ROOT = Path(__file__).resolve().parents[2]
23
+ PYPI = 'https://pypi.org/pypi/{}/json'
24
+
25
+
26
+ def pypi_info(name: str) -> dict:
27
+ with urllib.request.urlopen(PYPI.format(name), timeout=30) as response:
28
+ return json.load(response)
29
+
30
+
31
+ def minor(version: str) -> tuple:
32
+ return tuple(int(p) for p in version.split('.')[:2])
33
+
34
+
35
+ def is_release(version: str) -> bool:
36
+ return re.fullmatch(r'\d+\.\d+\.\d+', version) is not None
37
+
38
+
39
+ def python_minors(classifiers: list) -> list:
40
+ found = [re.fullmatch(r'Programming Language :: Python :: 3\.(\d+)', c) for c in classifiers]
41
+ return sorted(int(m.group(1)) for m in found if m)
42
+
43
+
44
+ def main() -> int:
45
+ problems = []
46
+ project = tomllib.loads((ROOT / 'pyproject.toml').read_text())['project']
47
+
48
+ floors = {}
49
+ for dep in project['dependencies']:
50
+ match = re.match(r'(pymodaq(?:_utils|_gui|_data)?)>=(\d+\.\d+\.\d+)', dep)
51
+ if match:
52
+ floors[match.group(1)] = match.group(2)
53
+ if 'pymodaq' not in floors:
54
+ problems.append('pyproject.toml has no "pymodaq>=X.Y.Z" dependency: nothing to compare to')
55
+ return report(problems)
56
+ branch_minor = minor(floors['pymodaq'])
57
+ branch = '{}.{}'.format(*branch_minor)
58
+
59
+ # 1. the floors of the PyMoDAQ packages exist and belong to the branch's minor
60
+ for name, floor in floors.items():
61
+ releases = [v for v in pypi_info(name)['releases'] if is_release(v)]
62
+ if floor not in releases:
63
+ problems.append(f'{name}>={floor} was never released on PyPI')
64
+ elif name == 'pymodaq' and minor(floor) != branch_minor:
65
+ problems.append(f'{name} floor {floor} is not in {branch}')
66
+ elif minor(floor) > branch_minor:
67
+ problems.append(f'{name}>={floor} is newer than the branch ({branch}.x)')
68
+
69
+ # 2. a new PyMoDAQ minor means a new template branch
70
+ latest = pypi_info('pymodaq')
71
+ versions = sorted((v for v in latest['releases'] if is_release(v)), key=lambda v: tuple(map(int, v.split('.'))))
72
+ newest = versions[-1]
73
+ if minor(newest) > branch_minor:
74
+ problems.append(f'PyMoDAQ {newest} is out but this template targets {branch}.x: create the {"{}.{}".format(*minor(newest))}.x '
75
+ f'branch (checklist in the docstring of .github/scripts/check_template_versions.py)')
76
+
77
+ # 3. supported Python versions: ours vs the latest pymodaq of the branch's minor
78
+ same_minor = [v for v in versions if minor(v) == branch_minor][-1]
79
+ with urllib.request.urlopen(f'https://pypi.org/pypi/pymodaq/{same_minor}/json', timeout=30) as response:
80
+ data = json.load(response)['info']
81
+ # the Python classifiers of a plugin are computed from requires-python when it is built (dynamic classifiers)
82
+ ours = theirs = python_minors(data['classifiers'])
83
+ requires = data.get('requires_python') or ''
84
+ if requires and requires != project.get('requires-python'):
85
+ problems.append(f'requires-python is {project.get("requires-python")!r}, pymodaq {same_minor} has {requires!r}')
86
+
87
+ # 4. the compatibility matrix covers both Python extremes
88
+ matrix = (ROOT / '.github/workflows/reusable-compatibility.yml').read_text()
89
+ used = sorted({int(m) for m in re.findall(r"python-version: '3\.(\d+)'", matrix)})
90
+ if ours and used and (used[0], used[-1]) != (ours[0], ours[-1]):
91
+ problems.append(f'compatibility matrix spans Python 3.{used[0]}-3.{used[-1]}, supported is 3.{ours[0]}-3.{ours[-1]}')
92
+
93
+ # 5. prose that names the branch
94
+ for name in ('README.rst', 'AGENTS.md'):
95
+ for number, line in enumerate((ROOT / name).read_text().splitlines(), 1):
96
+ for found in re.findall(r'PyMoDAQ\s+(\d+\.\d+)\.x', line):
97
+ if found != branch:
98
+ problems.append(f'{name}:{number} says PyMoDAQ {found}.x, the branch is {branch}.x')
99
+ return report(problems, branch)
100
+
101
+
102
+ def report(problems: list, branch: str = '?') -> int:
103
+ if not problems:
104
+ print(f'OK: template versions are consistent with PyMoDAQ {branch}.x')
105
+ return 0
106
+ for problem in problems:
107
+ print(f'::warning::{problem}')
108
+ return 1
109
+
110
+
111
+ if __name__ == '__main__':
112
+ sys.exit(main())
@@ -0,0 +1,30 @@
1
+ # Template repository only: warns (failed run, e-mail to the watchers) when the versions written in the template drift
2
+ # from PyMoDAQ's, for instance after a new PyMoDAQ minor release. Plugins copied from the template skip it.
3
+ name: Check template versions
4
+
5
+ on:
6
+ schedule:
7
+ - cron: '0 6 * * 1'
8
+ workflow_dispatch:
9
+ pull_request:
10
+ paths:
11
+ - pyproject.toml
12
+ - README.rst
13
+ - AGENTS.md
14
+ - .github/workflows/**
15
+ - .github/scripts/**
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ check:
22
+ if: github.repository == 'PyMoDAQ/pymodaq_plugins_template'
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 5
25
+ steps:
26
+ - uses: actions/checkout@v7.0.1
27
+ - uses: actions/setup-python@v6.2.0
28
+ with:
29
+ python-version: '3.12'
30
+ - run: python .github/scripts/check_template_versions.py
@@ -0,0 +1,15 @@
1
+ # Everything is defined once in PyMoDAQ/pymodaq_plugins_template (reusable-*.yml). The template is never released, so the ref after @ is its 5.3.x branch.
2
+ name: Compatibility with pymodaq (latest release)
3
+
4
+ on:
5
+ pull_request:
6
+ push:
7
+ branches: [main, master, '[0-9]*.x']
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ compatibility:
15
+ uses: PyMoDAQ/pymodaq_plugins_template/.github/workflows/reusable-compatibility.yml@5.3.x
@@ -0,0 +1,11 @@
1
+ # Everything is defined once in PyMoDAQ/pymodaq_plugins_template (reusable-*.yml). The template is never released, so the ref after @ is its 5.3.x branch.
2
+ name: Upload Python Package
3
+
4
+ on:
5
+ release:
6
+ types: [created]
7
+
8
+ jobs:
9
+ publish:
10
+ uses: PyMoDAQ/pymodaq_plugins_template/.github/workflows/reusable-publish.yml@5.3.x
11
+ secrets: inherit
@@ -0,0 +1,57 @@
1
+ # Shared by all plugins: the plugin tests on the latest PyMoDAQ release over Python versions, Qt backends and OS.
2
+ # Called from the small `compatibility.yml` of a plugin, do not copy this file into a plugin.
3
+ name: Reusable compatibility
4
+
5
+ on:
6
+ workflow_call:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ tests:
13
+ name: ${{ matrix.os }} / Python ${{ matrix.python-version }} / ${{ matrix.qt-backend }}
14
+ runs-on: ${{ matrix.os }}
15
+ timeout-minutes: 30
16
+ strategy:
17
+ fail-fast: false
18
+ # This matrix is a deliberate subset, not every combination of OS x Python x Qt backend (2 x 4 x 3 = 24 jobs).
19
+ # It follows the usual practice of testing the extremes instead of the full cross product:
20
+ # - the oldest (3.10) and the newest (3.13) supported Python versions, on Linux,
21
+ # - each Qt backend at least once (pyqt5, pyqt6, pyside6), PySide6 on both Python extremes,
22
+ # - Windows once, with an intermediate Python version (3.12).
23
+ # Not tested on purpose: Python 3.11 and 3.12 on Linux, Windows with pyqt5 or pyside6, PyQt5 with Python 3.13,
24
+ # PyQt6 with Python 3.10. The plugin tests are fast, so if a plugin needs more coverage, replace `include` by the
25
+ # three lists `os`, `python-version` and `qt-backend`: GitHub then builds the 24 combinations.
26
+ # When a Python version is added or dropped (follow pymodaq), update the extremes here.
27
+ matrix:
28
+ include:
29
+ - {os: ubuntu-latest, python-version: '3.10', qt-backend: pyqt5}
30
+ - {os: ubuntu-latest, python-version: '3.10', qt-backend: pyside6}
31
+ - {os: ubuntu-latest, python-version: '3.13', qt-backend: pyqt6}
32
+ - {os: ubuntu-latest, python-version: '3.13', qt-backend: pyside6}
33
+ - {os: windows-latest, python-version: '3.12', qt-backend: pyqt6}
34
+ env:
35
+ QT_DEBUG_PLUGINS: 1
36
+ steps:
37
+ - uses: actions/checkout@v7.0.1
38
+ with:
39
+ fetch-depth: 0 # history and tags, needed by hatch-vcs: without them the version is 0.1.dev and e.g. pymodaq_plugins_mock cannot satisfy pymodaq's own requirement
40
+ - uses: actions/setup-python@v6.2.0
41
+ with:
42
+ python-version: ${{ matrix.python-version }}
43
+ - name: Install system libraries for Qt
44
+ if: runner.os == 'Linux'
45
+ run: |
46
+ sudo apt-get update
47
+ sudo apt-get install -y libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-cursor0 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils libgl1 libegl1
48
+ sudo mkdir -p /etc/.pymodaq
49
+ sudo chmod uo+rw /etc/.pymodaq
50
+ - name: Install the plugin with the latest PyMoDAQ release
51
+ # PySide6 6.12.0 aborts (garbage collector) after the tests that open PyMoDAQ's Dashboard, see PyMoDAQ issue #1275
52
+ run: |
53
+ python -m pip install --upgrade pip
54
+ pip install pytest pytest-qt pytest-xvfb ${{ matrix.qt-backend == 'pyside6' && 'pyside6!=6.12.0' || matrix.qt-backend }}
55
+ pip install -e .
56
+ - name: Tests
57
+ run: pytest -vv tests
@@ -0,0 +1,41 @@
1
+ # Shared by all plugins: build the package and upload it to PyPI.
2
+ # The repository secrets PYPI_USERNAME (`__token__`) and PYPI_PASSWORD (the PyPI API token) are passed by the caller.
3
+ # Called from the small `python-publish.yml` of a plugin, do not copy this file into a plugin.
4
+ name: Reusable publish
5
+
6
+ on:
7
+ workflow_call:
8
+ secrets:
9
+ PYPI_USERNAME:
10
+ required: true
11
+ PYPI_PASSWORD:
12
+ required: true
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ deploy:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v7.0.1
22
+ with:
23
+ fetch-depth: 0 # history and tags, needed by hatch-vcs for the version
24
+ - uses: actions/setup-python@v6.2.0
25
+ with:
26
+ python-version: '3.x'
27
+ - name: Install build tools
28
+ run: |
29
+ python -m pip install --upgrade pip
30
+ pip install hatch hatchling toml twine
31
+ - name: Show the version
32
+ run: hatch version
33
+ - name: Build
34
+ run: hatch build
35
+ - name: Check the build
36
+ run: twine check dist/*
37
+ - name: Publish
38
+ env:
39
+ HATCH_INDEX_USER: ${{ secrets.PYPI_USERNAME }}
40
+ HATCH_INDEX_AUTH: ${{ secrets.PYPI_PASSWORD }}
41
+ run: hatch publish
@@ -0,0 +1,50 @@
1
+ # Shared by all plugins: flake8 gate and unit tests on one Python version and one Qt backend.
2
+ # Deliberately a single configuration (Linux, Python 3.11, PySide6 by default): this is the fast gate that gives an
3
+ # answer in about a minute. The spread over OS, Python versions and Qt backends is tested by reusable-compatibility.yml
4
+ # (a subset that skips Python 3.11, which is thus covered here).
5
+ # Called from the small `tests.yml` of a plugin, do not copy this file into a plugin.
6
+ name: Reusable tests
7
+
8
+ on:
9
+ workflow_call:
10
+ inputs:
11
+ python-version:
12
+ type: string
13
+ default: '3.11'
14
+ qt-backend:
15
+ type: string
16
+ default: pyside6
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ tests:
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 30
25
+ env:
26
+ QT_DEBUG_PLUGINS: 1
27
+ steps:
28
+ - uses: actions/checkout@v7.0.1
29
+ with:
30
+ fetch-depth: 0 # history and tags, needed by hatch-vcs: without them the version is 0.1.dev and e.g. pymodaq_plugins_mock cannot satisfy pymodaq's own requirement
31
+ - uses: actions/setup-python@v6.2.0
32
+ with:
33
+ python-version: ${{ inputs.python-version }}
34
+ - name: Install system libraries for Qt
35
+ run: |
36
+ sudo apt-get update
37
+ sudo apt-get install -y libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-cursor0 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils libgl1 libegl1
38
+ sudo mkdir -p /etc/.pymodaq
39
+ sudo chmod uo+rw /etc/.pymodaq
40
+ - name: Install the plugin
41
+ # PySide6 6.12.0 aborts (garbage collector) after the tests that open PyMoDAQ's Dashboard, see PyMoDAQ issue #1275
42
+ run: |
43
+ python -m pip install --upgrade pip
44
+ pip install flake8 pytest pytest-qt pytest-xvfb ${{ inputs.qt-backend == 'pyside6' && 'pyside6!=6.12.0' || inputs.qt-backend }}
45
+ pip install -e .
46
+ - name: Lint (syntax errors and undefined names only)
47
+ run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
48
+ - name: Tests
49
+ # no xdist: parallel workers race to create the PyMoDAQ config folder on a fresh runner
50
+ run: pytest tests
@@ -0,0 +1,8 @@
1
+ # Everything is defined once in PyMoDAQ/pymodaq_plugins_template (reusable-*.yml). The template is never released, so the ref after @ is its 5.3.x branch.
2
+ name: Tests
3
+
4
+ on: [push, pull_request]
5
+
6
+ jobs:
7
+ tests:
8
+ uses: PyMoDAQ/pymodaq_plugins_template/.github/workflows/reusable-tests.yml@5.3.x
@@ -0,0 +1,117 @@
1
+ # Compiled python modules.
2
+ *.pyc
3
+
4
+ # Byte-compiled / optimized / DLL files
5
+ __pycache__/
6
+ _version.py
7
+
8
+ *.py[cod]
9
+ *$py.class
10
+
11
+ # C extensions
12
+ *.so
13
+
14
+ # Distribution / packaging
15
+ .Python
16
+ build/
17
+ develop-eggs/
18
+ dist/
19
+ downloads/
20
+ eggs/
21
+ .eggs/
22
+ lib/
23
+ lib64/
24
+ parts/
25
+ sdist/
26
+ var/
27
+ wheels/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+ MANIFEST
32
+
33
+ # PyInstaller
34
+ # Usually these files are written by a python script from a template
35
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
36
+ *.manifest
37
+ *.spec
38
+
39
+ # Installer logs
40
+ pip-log.txt
41
+ pip-delete-this-directory.txt
42
+
43
+ # Unit test / coverage reports
44
+ htmlcov/
45
+ .tox/
46
+ .coverage
47
+ .coverage.*
48
+ .cache
49
+ nosetests.xml
50
+ coverage.xml
51
+ *.cover
52
+ .hypothesis/
53
+ .pytest_cache/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # pyenv
81
+ .python-version
82
+
83
+ # celery beat schedule file
84
+ celerybeat-schedule
85
+
86
+ # SageMath parsed files
87
+ *.sage.py
88
+
89
+ # Environments
90
+ .env
91
+ .venv
92
+ env/
93
+ venv/
94
+ ENV/
95
+ env.bak/
96
+ venv.bak/
97
+
98
+ # Spyder project settings
99
+ .spyderproject
100
+ .spyproject
101
+
102
+ # Rope project settings
103
+ .ropeproject
104
+
105
+ # mkdocs documentation
106
+ /site
107
+
108
+ # mypy
109
+ .mypy_cache/
110
+
111
+ # pycharm
112
+ .idea/
113
+ .idea/*
114
+
115
+ *yacctab.py
116
+ *lextab.py
117
+ STATUS_AI_DEV.md