From e63dcea270051410f8e31fb7a90c6f96c6a211db Mon Sep 17 00:00:00 2001 From: root Date: Fri, 28 Nov 2025 08:04:38 +0000 Subject: [PATCH 1/2] Fix: Invalid script entry point in setup.py - Fix console_scripts entry point in setup.py to point to pynetinstall.__main__:main - Encapsulate main execution logic into main() function in pynetinstall/__main__.py - Update README.md Usage section to reflect correct command line usage --- README.md | 2 +- pynetinstall/__main__.py | 74 +++++++++++++++++++++------------------- setup.py | 2 +- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 6c02dd6..d3c615d 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ with RouterOS. ## Usage -`python -m pynetinstall [-c CONFIG] [-i INTERFACE] [-v]` +`pynetinstall [-c CONFIG] [-i INTERFACE] [-v]` *-c CONFIG*: Path to the configuration file. Defaults to `/etc/pynetinstall.ini`. *-i INTERFACE*: MAC address or name of network interface. Defaults to `eth0`. diff --git a/pynetinstall/__main__.py b/pynetinstall/__main__.py index 3894434..34ec95f 100644 --- a/pynetinstall/__main__.py +++ b/pynetinstall/__main__.py @@ -10,38 +10,42 @@ signal.signal(signal.SIGTERM, lambda sig, _: sys.exit(0)) -parser = argparse.ArgumentParser(__package__) -parser.add_argument("-c", "--config", default="/etc/pynetinstall.ini", help="set location of configuration file") -parser.add_argument("-i", "--interface", default="eth0", help="MAC or name of ethernet interface (name supported on Linux only)") -parser.add_argument("-l", "--logging", default=None, help="python logging configuration") -parser.add_argument("-v", "--verbose", action="count", default=0, help="enable verbose output") -parser.add_argument("-1", "--oneshot", action="store_true", help="exit after flashing once") -args = parser.parse_args() - -# default to ERROR+WARNING, each -v increases the verbosity (INFO, DEBUG). must not set to NOTSET (0), or logger gets disabled. -levels = sorted([e for e in logging._levelToName.keys() if e > 0], reverse=True) -verbosity = levels[min(len(levels)-1, levels.index(logging.WARNING) + args.verbose)] -if not args.logging: - args.logging = os.path.join(os.path.dirname(__file__), "logging.ini") -logging.config.fileConfig(args.logging) - -is_mac = re.fullmatch(r"([0-9a-f]{2}[:]?){6}", args.interface, re.I) -argdict = { - 'mac_address' if is_mac else 'interface_name': args.interface, - 'config_file': args.config, - 'log_level': verbosity, -} - -try: - fl_dev = FlashInterface(**argdict) - - if args.oneshot: - fl_dev.flash_once() - else: - fl_dev.flash_until_stopped() -except FatalError as e: - parser.error(e) -except AbortFlashing as e: - sys.exit(1) -except KeyboardInterrupt as e: - sys.exit(130) +def main(): + parser = argparse.ArgumentParser(__package__) + parser.add_argument("-c", "--config", default="/etc/pynetinstall.ini", help="set location of configuration file") + parser.add_argument("-i", "--interface", default="eth0", help="MAC or name of ethernet interface (name supported on Linux only)") + parser.add_argument("-l", "--logging", default=None, help="python logging configuration") + parser.add_argument("-v", "--verbose", action="count", default=0, help="enable verbose output") + parser.add_argument("-1", "--oneshot", action="store_true", help="exit after flashing once") + args = parser.parse_args() + + # default to ERROR+WARNING, each -v increases the verbosity (INFO, DEBUG). must not set to NOTSET (0), or logger gets disabled. + levels = sorted([e for e in logging._levelToName.keys() if e > 0], reverse=True) + verbosity = levels[min(len(levels)-1, levels.index(logging.WARNING) + args.verbose)] + if not args.logging: + args.logging = os.path.join(os.path.dirname(__file__), "logging.ini") + logging.config.fileConfig(args.logging) + + is_mac = re.fullmatch(r"([0-9a-f]{2}[:]?){6}", args.interface, re.I) + argdict = { + 'mac_address' if is_mac else 'interface_name': args.interface, + 'config_file': args.config, + 'log_level': verbosity, + } + + try: + fl_dev = FlashInterface(**argdict) + + if args.oneshot: + fl_dev.flash_once() + else: + fl_dev.flash_until_stopped() + except FatalError as e: + parser.error(e) + except AbortFlashing as e: + sys.exit(1) + except KeyboardInterrupt as e: + sys.exit(130) + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 29f9917..cf40423 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,6 @@ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", ], entry_points={ - "console_scripts": ["pynetinstall = pynetinstall.__main__"] + "console_scripts": ["pynetinstall = pynetinstall.__main__:main"] } ) From 69ab10e442a73bd8e0c49fb6b17b3306b5196e2a Mon Sep 17 00:00:00 2001 From: root Date: Fri, 28 Nov 2025 08:04:46 +0000 Subject: [PATCH 2/2] Fix: TypeError in version comparison (map to tuple conversion) - Convert map object to tuple before comparison to fix TypeError - This prevents '>' not supported between instances of 'map' and 'tuple' error - Affects NPK version comparison in Python 3 --- pynetinstall/flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynetinstall/flash.py b/pynetinstall/flash.py index 67c99ad..d81b899 100644 --- a/pynetinstall/flash.py +++ b/pynetinstall/flash.py @@ -173,7 +173,7 @@ def verify_npk(self, info: InterfaceInfo) -> None: # extract version number. release_type is lowercase ASCII letter 'a'=alpha, 'b'=beta, 'c'=candidate, 'f'=final, other values are plain uint8 patch, release_type, minor, major = header[0x24:0x28] - if map(int, info.min_os.split(".")) > (major, minor, patch): + if tuple(map(int, info.min_os.split("."))) > (major, minor, patch): release = {97: 'alpha', 98: 'beta', 99: 'rc', 102: ''}.get(release_type, '') raise AbortFlashing(f"Verification failed: Tried to install RouterOS {major}.{minor}.{release}{patch}, but device requires at least {info.min_os}.")