From 552c867a57b91043f496ca9834bb563d20e82b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonard=20G=C3=B6hrs?= Date: Fri, 8 Mar 2024 15:23:26 +0100 Subject: [PATCH] lxa_iobus: move the project from setup.py to pyproject.toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pyproject.toml format is the new and modern way to package python projects. We still use setuptools under the hood to do the packaging, but configure it in the pyproject.toml. This change also moves the executable scripts from the bin folder, where they were e.g. not caught by ruff by default, into the python project folder itself. Signed-off-by: Leonard Göhrs --- Makefile | 20 -- REQUIREMENTS.packaging.txt | 2 - bin/lxa-iobus-can-setup | 34 ---- bin/lxa-iobus-server | 184 ----------------- lxa_iobus/__init__.py | 2 - lxa_iobus/cli/__init__.py | 0 .../cli/lpc11xxcanisp_invoke.py | 4 +- .../cli/lpc11xxcanisp_program.py | 0 lxa_iobus/cli/server.py | 188 ++++++++++++++++++ pyproject.toml | 37 ++++ setup.cfg | 4 - setup.py | 40 ---- 12 files changed, 227 insertions(+), 288 deletions(-) delete mode 100644 REQUIREMENTS.packaging.txt delete mode 100755 bin/lxa-iobus-can-setup delete mode 100755 bin/lxa-iobus-server create mode 100644 lxa_iobus/cli/__init__.py rename bin/lxa-iobus-lpc11xxcanisp-invoke => lxa_iobus/cli/lpc11xxcanisp_invoke.py (95%) mode change 100755 => 100644 rename bin/lxa-iobus-lpc11xxcanisp-program => lxa_iobus/cli/lpc11xxcanisp_program.py (100%) mode change 100755 => 100644 create mode 100644 lxa_iobus/cli/server.py delete mode 100644 setup.cfg delete mode 100755 setup.py diff --git a/Makefile b/Makefile index 387319b..3ead5e0 100644 --- a/Makefile +++ b/Makefile @@ -25,26 +25,6 @@ server: env --lss-address-cache-file=$(LSS_ADDRESS_CACHE_FILE) \ $(args) -# packaging environment ####################################################### -$(PYTHON_PACKAGING_VENV)/.created: REQUIREMENTS.packaging.txt - rm -rf $(PYTHON_PACKAGING_VENV) && \ - $(PYTHON) -m venv $(PYTHON_PACKAGING_VENV) && \ - . $(PYTHON_PACKAGING_VENV)/bin/activate && \ - pip install --upgrade pip && \ - pip install -r REQUIREMENTS.packaging.txt - date > $(PYTHON_PACKAGING_VENV)/.created - -packaging-env: $(PYTHON_PACKAGING_VENV)/.created - -sdist: packaging-env - . $(PYTHON_PACKAGING_VENV)/bin/activate && \ - rm -rf dist *.egg-info && \ - ./setup.py sdist - -_release: sdist - . $(PYTHON_PACKAGING_VENV)/bin/activate && \ - twine upload dist/* - # testing ##################################################################### $(PYTHON_TESTING_ENV)/.created: rm -rf $(PYTHON_TESTING_ENV) && \ diff --git a/REQUIREMENTS.packaging.txt b/REQUIREMENTS.packaging.txt deleted file mode 100644 index 69c408a..0000000 --- a/REQUIREMENTS.packaging.txt +++ /dev/null @@ -1,2 +0,0 @@ -setuptools>=36.5.0 -twine diff --git a/bin/lxa-iobus-can-setup b/bin/lxa-iobus-can-setup deleted file mode 100755 index 4ab935a..0000000 --- a/bin/lxa-iobus-can-setup +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -interface=can0 -bitrate=100000 - -usage="$(basename "$0") [-i interface] [-b bitrate]" - -while getopts :hi:b: flag -do - case "${flag}" in - h) - echo $usage - exit - ;; - - i) - interface=${OPTARG} - ;; - - b) - bitrate=${OPTARG} - ;; - - \?) - exit - ;; - esac -done - -set -e -set -x - -sudo ip link set $interface type can bitrate $bitrate -sudo ip link set up dev $interface diff --git a/bin/lxa-iobus-server b/bin/lxa-iobus-server deleted file mode 100755 index 47aeddb..0000000 --- a/bin/lxa-iobus-server +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import asyncio -import errno -import logging -import os -import signal -import sys -import threading -import traceback -from argparse import ArgumentParser - -from aiohttp.web import Application, run_app - -from lxa_iobus.network import LxaNetwork -from lxa_iobus.server.server import LXAIOBusServer - - -def trace_handler(num, frame): - print("\nDumping all stacks:\n") - - for th in threading.enumerate(): - print(th) - traceback.print_stack(sys._current_frames()[th.ident]) - print() - - for task in asyncio.all_tasks(): - if not task.done(): - task.print_stack() - print() - - -signal.signal(signal.SIGQUIT, trace_handler) - - -def exit_handler(num, frame): - print("\nExiting...\n") - - os.kill(os.getpid(), signal.SIGKILL) - - -signal.signal(signal.SIGINT, exit_handler) - -# parse command line arguments -parser = ArgumentParser() - -parser.add_argument("interface") -parser.add_argument( - "--port", - type=int, - default=8080, - help="Port to serve on. Defaults to 8080", -) -parser.add_argument( - "--host", - type=str, - default="localhost", - help="Host to bind to. Defaults to 'localhost'", -) -parser.add_argument( - "--shell", - action="store_true", - help="Embeds an ipython shell for easy debugging", -) -parser.add_argument( - "--firmware-directory", - type=str, - default="firmware", - help="Directory where uploaded firmware is stored. " "Only used when --allow-custom-firmware is set.", -) -parser.add_argument( - "--allow-custom-firmware", - action="store_true", - help="Allows to upload and flash own (arbitrary) firmware " "into the program section of the nodes.", -) -parser.add_argument( - "--lss-address-cache-file", - type=str, - default="", - help="LSS addresses cache as json. Reduces startup time for known nodes.", -) - -parser.add_argument( - "-l", - "--log-level", - choices=["DEBUG", "INFO", "WARN", "ERROR", "FATAL"], - default="WARN", -) - -args = parser.parse_args() - -# setup logging -log_level = { - "DEBUG": logging.DEBUG, - "INFO": logging.INFO, - "WARN": logging.WARN, - "ERROR": logging.ERROR, - "FATAL": logging.FATAL, -}[args.log_level] - -logging.basicConfig(level=log_level) - -# setup server -loop = asyncio.new_event_loop() -asyncio.set_event_loop(loop) -app = Application() - -# setup lxa network -network = LxaNetwork( - loop=loop, - interface=args.interface, - lss_address_cache_file=args.lss_address_cache_file, -) - -app["network"] = network - - -async def shutdown_network(app): - await app["network"].shutdown() - - -app.on_shutdown.append(shutdown_network) -loop.create_task(network.run()) - -# start server -try: - server = LXAIOBusServer( - app, - loop, - network, - args.firmware_directory, - args.allow_custom_firmware, - ) - -except OSError as e: - if e.errno == errno.ENODEV: # can interface not available - exit("interface {} not available".format(args.interface)) - -loop.create_task(server.flush_state_periodically()) - -if args.shell: - - def _start_shell(): - import IPython - from traitlets.config import Config - - config = Config() - - IPython.embed(config=config) - - # shutdown server - os.kill(os.getpid(), signal.SIGTERM) - - loop.create_task(server.rpc.worker_pool.run(_start_shell)) - -print("starting server on http://{}:{}/".format(args.host, args.port)) - -try: - kwargs = {} - if args.log_level != "DEBUG": - kwargs["access_log"] = None - run_app( - app=app, - host=args.host, - port=args.port, - handle_signals=False, - print=lambda *args, **kwargs: None, - loop=loop, - **kwargs, - ) - -except KeyboardInterrupt: - server.shutdown() - os.kill(os.getpid(), signal.SIGTERM) - -except OSError: - server.shutdown() - exit("ERROR: can not bind to port {}".format(args.port)) - -print("\rshutting down server") - -server.shutdown() -os.kill(os.getpid(), signal.SIGTERM) diff --git a/lxa_iobus/__init__.py b/lxa_iobus/__init__.py index a53c75a..e69de29 100644 --- a/lxa_iobus/__init__.py +++ b/lxa_iobus/__init__.py @@ -1,2 +0,0 @@ -VERSION = (0, 4, 2) -VERSION_STRING = "{}".format(".".join([str(i) for i in VERSION])) diff --git a/lxa_iobus/cli/__init__.py b/lxa_iobus/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bin/lxa-iobus-lpc11xxcanisp-invoke b/lxa_iobus/cli/lpc11xxcanisp_invoke.py old mode 100755 new mode 100644 similarity index 95% rename from bin/lxa-iobus-lpc11xxcanisp-invoke rename to lxa_iobus/cli/lpc11xxcanisp_invoke.py index 897f8cb..8af3fc3 --- a/bin/lxa-iobus-lpc11xxcanisp-invoke +++ b/lxa_iobus/cli/lpc11xxcanisp_invoke.py @@ -29,7 +29,7 @@ def invoke_isp(self): self.node.sdo.download(0x2B07, 0, struct.pack("I", 0x12345678)) -def invoke_rom_loader(): +def main(): can = CanOpen() can.setup() @@ -38,4 +38,4 @@ def invoke_rom_loader(): if __name__ == "__main__": - invoke_rom_loader() + main() diff --git a/bin/lxa-iobus-lpc11xxcanisp-program b/lxa_iobus/cli/lpc11xxcanisp_program.py old mode 100755 new mode 100644 similarity index 100% rename from bin/lxa-iobus-lpc11xxcanisp-program rename to lxa_iobus/cli/lpc11xxcanisp_program.py diff --git a/lxa_iobus/cli/server.py b/lxa_iobus/cli/server.py new file mode 100644 index 0000000..2a10e16 --- /dev/null +++ b/lxa_iobus/cli/server.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import asyncio +import errno +import logging +import os +import signal +import sys +import threading +import traceback +from argparse import ArgumentParser + +from aiohttp.web import Application, run_app + +from lxa_iobus.network import LxaNetwork +from lxa_iobus.server.server import LXAIOBusServer + + +def trace_handler(num, frame): + print("\nDumping all stacks:\n") + + for th in threading.enumerate(): + print(th) + traceback.print_stack(sys._current_frames()[th.ident]) + print() + + for task in asyncio.all_tasks(): + if not task.done(): + task.print_stack() + print() + + +signal.signal(signal.SIGQUIT, trace_handler) + + +def exit_handler(num, frame): + print("\nExiting...\n") + + os.kill(os.getpid(), signal.SIGKILL) + + +signal.signal(signal.SIGINT, exit_handler) + + +def main(): + # parse command line arguments + parser = ArgumentParser() + + parser.add_argument("interface") + parser.add_argument( + "--port", + type=int, + default=8080, + help="Port to serve on. Defaults to 8080", + ) + parser.add_argument( + "--host", + type=str, + default="localhost", + help="Host to bind to. Defaults to 'localhost'", + ) + parser.add_argument( + "--shell", + action="store_true", + help="Embeds an ipython shell for easy debugging", + ) + parser.add_argument( + "--firmware-directory", + type=str, + default="firmware", + help="Directory where uploaded firmware is stored. " "Only used when --allow-custom-firmware is set.", + ) + parser.add_argument( + "--allow-custom-firmware", + action="store_true", + help="Allows to upload and flash own (arbitrary) firmware " "into the program section of the nodes.", + ) + parser.add_argument( + "--lss-address-cache-file", + type=str, + default="", + help="LSS addresses cache as json. Reduces startup time for known nodes.", + ) + + parser.add_argument( + "-l", + "--log-level", + choices=["DEBUG", "INFO", "WARN", "ERROR", "FATAL"], + default="WARN", + ) + + args = parser.parse_args() + + # setup logging + log_level = { + "DEBUG": logging.DEBUG, + "INFO": logging.INFO, + "WARN": logging.WARN, + "ERROR": logging.ERROR, + "FATAL": logging.FATAL, + }[args.log_level] + + logging.basicConfig(level=log_level) + + # setup server + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + app = Application() + + # setup lxa network + network = LxaNetwork( + loop=loop, + interface=args.interface, + lss_address_cache_file=args.lss_address_cache_file, + ) + + app["network"] = network + + async def shutdown_network(app): + await app["network"].shutdown() + + app.on_shutdown.append(shutdown_network) + loop.create_task(network.run()) + + # start server + try: + server = LXAIOBusServer( + app, + loop, + network, + args.firmware_directory, + args.allow_custom_firmware, + ) + + except OSError as e: + if e.errno == errno.ENODEV: # can interface not available + exit("interface {} not available".format(args.interface)) + + loop.create_task(server.flush_state_periodically()) + + if args.shell: + + def _start_shell(): + import IPython + from traitlets.config import Config + + config = Config() + + IPython.embed(config=config) + + # shutdown server + os.kill(os.getpid(), signal.SIGTERM) + + loop.create_task(server.rpc.worker_pool.run(_start_shell)) + + print("starting server on http://{}:{}/".format(args.host, args.port)) + + try: + kwargs = {} + if args.log_level != "DEBUG": + kwargs["access_log"] = None + run_app( + app=app, + host=args.host, + port=args.port, + handle_signals=False, + print=lambda *args, **kwargs: None, + loop=loop, + **kwargs, + ) + + except KeyboardInterrupt: + server.shutdown() + os.kill(os.getpid(), signal.SIGTERM) + + except OSError: + server.shutdown() + exit("ERROR: can not bind to port {}".format(args.port)) + + print("\rshutting down server") + + server.shutdown() + os.kill(os.getpid(), signal.SIGTERM) + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index ed7e54e..dd0b914 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,40 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "lxa-iobus" +description = "Linux Automation IOBus Server" +version = "0.4.2" +authors = [ + { name = "Linux Automation GmbH", email = "info@linux-automation.com" }, +] +readme = "README.rst" +license = { file = "LICENSE.txt" } +dependencies = [ + "aiohttp~=3.8", + "aiohttp-json-rpc==0.13.3", + "canopen", + "python-can", + "janus", +] + +[project.scripts] +lxa-iobus-server = "lxa_iobus.cli.server:main" +lxa-iobus-lpc11xxcanisp-invoke = "lxa_iobus.cli.lpc11xxcanisp_invoke:main" +lxa-iobus-lpc11xxcanisp-program = "lxa_iobus.cli.lpc11xxcanisp_program:main" + +[tool.setuptools] +packages = [ + "lxa_iobus", + "lxa_iobus.cli", + "lxa_iobus.lpc11xxcanisp", + "lxa_iobus.lpc11xxcanisp.firmware", + "lxa_iobus.lpc11xxcanisp.loader", + "lxa_iobus.server", +] +include-package-data = true + [tool.ruff] line-length = 119 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 521ad5b..0000000 --- a/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[metadata] -description = Linux Automation iobus -long_description = file: README.rst -license_file = LICENSE.txt diff --git a/setup.py b/setup.py deleted file mode 100755 index 73b7d67..0000000 --- a/setup.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from setuptools import find_packages, setup - -import lxa_iobus - -EXTRAS_REQUIRE = { - "server": [ - "aiohttp~=3.8", - "aiohttp-json-rpc==0.13.3", - ], - "shell": [ - "ipython<7", - ], -} - -EXTRAS_REQUIRE["full"] = sum([v for k, v in EXTRAS_REQUIRE.items()], []) - -setup( - include_package_data=True, - name="lxa-iobus", - version=lxa_iobus.VERSION_STRING, - author="Linux Automation GmbH", - url="https://github.com/linux-automation/lxa-iobus", - author_email="python@pengutronix.de", - license="Apache License 2.0", - packages=find_packages(), - install_requires=[ - "python-can", - "janus", - ], - extras_require=EXTRAS_REQUIRE, - scripts=[ - "bin/lxa-iobus-server", - "bin/lxa-iobus-can-setup", - "bin/lxa-iobus-lpc11xxcanisp-invoke", - "bin/lxa-iobus-lpc11xxcanisp-program", - ], -)