Python environment setup and runner execution.
python-runner is a framework for building modular command-line applications. It provides a structured way to execute different tasks (called "runners") while sharing a common infrastructure for:
- Configuration Management: Unified handling of application profiles and YAML/JSON configuration files.
- Argument Parsing: A centralized registry for command-line arguments.
- Logging: Pre-configured logging setup.
- Dynamic Module Loading: Runners and arguments can be registered and loaded dynamically based on command-line inputs.
This modularity makes it useful for projects that require multiple related scripts or tools to be bundled into a single entry point with consistent behavior and environment setup.
# Win
py -3.14 -m venv ./.venv
# *nix
python -m venv ./.venv
# Win
.\.venv\Scripts\activate
# *nix
source ./.venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txtFor developing depending on the project / module, dependency can be added into requirements.txt as:
python-commons @ file:///C:/sources/setmy.info/submodules/python-commons
pip install --upgrade behave wheel twine pip_audit bandit"File" -> "Settings" -> Python Integrated Tools -> Default test runner: Unittest
Running tests has a problem: a working directory has to be set for tests.
python -m unittest discover -s ./testpython -m unittest discover -s ./test -p it_*.pypython -m unittest discover -s ./test && python -m unittest discover -s ./test -p it_*.pyThe project uses popular Python security tools to ensure dependency safety and code quality.
This tool checks installed packages against known vulnerability databases (PyPI Advisory Database). It is the Python equivalent of Java's dependency check.
Run check:
pip-audit -r requirements.txtBandit is a tool designed to find common security issues in Python code.
Run check:
bandit -r smi_python_runner# Win
set NAME=smi_python_runner
set VERSION=1.4.0
# *nix
NAME=smi_python_runner
VERSION=1.4.0
# Win
python -m smi_python_commons.scm_version %NAME% %VERSION%
# *nix
python -m smi_python_commons.scm_version ${NAME} ${VERSION}
git add ./${NAME}/project.py
git commit -m "project.py updated"
git pushsetup.py is the package distribution configuration file. It makes this project an installable Python package that
can be:
- Built into a distributable artifact (
.whl/.tar.gz) - Installed locally via
pip install . - Published to PyPI (or a private registry)
| Field | Value | Meaning |
|---|---|---|
name |
NAME from project.py |
Package name on PyPI |
version |
VERSION from project.py |
Package version |
packages=find_packages() |
auto-detected | Includes all sub-packages |
install_requires |
smi-python-commons |
Runtime dependency |
extras_require[dev] |
bandit, behave, pip_audit, wheel, twine |
Dev/build tools (from requirements.txt) |
Build the package:
python setup.py sdist bdist_wheel
# or with modern tooling:
pip install build && python -m buildInstall locally (editable/dev mode):
pip install -e .Install locally with dev dependencies:
pip install -e .[dev]Install normally:
pip install .Publish to PyPI:
twine upload dist/*Note:
setup.pyis the legacy way (pre-PEP 517). Modern projects usepyproject.tomlwith[build-system]+[project]sections instead, butsetup.pystill works fine and is widely supported.
python setup.py sdist bdist_wheel
twine upload dist/*
git tag -a ${VERSION} -m "${VERSION}"
git push --tags- Update version info
- Deploy
python setup.py sdist bdist_wheel && twine upload dist/*application.py
from smi_python_commons.arguments.argument import Argument
from smi_python_runner.services.arguments_register_service import arguments_register_service
from smi_python_runner.services.runner_register_service import runner_register_service
from test.empty_runner import EmptyRunner
def register():
arguments_register_service.register(Argument('example', 'e', str, 'Example', True))
empty_runner = EmptyRunner()
runner_register_service.register(empty_runner)empty_runner.py
from smi_python_commons.config.application import Application
class EmptyRunner:
def __init__(self):
self.name = "empty-runner"
def get_name(self):
return self.name
def execute(self, app: Application, sub_command: str):
return 0runner-x_sub-x.py
import logging
from smi_python_commons.config.application import Application
from smi_python_runner.services.runner_register_service import runner_register_service
log = logging.getLogger(__name__)
logging.info("Loaded module")
class RunnerAbc:
def __init__(self):
self.name = "runner-abc"
def get_name(self):
return self.name
def execute(self, app: Application, sub_command: str):
return 0
def init():
logging.info("Init module")
runner_register_service.register(RunnerAbc())