From 435d86dc449111bad74ed41aad34ac9ee0d81df4 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 20:12:06 +0100 Subject: [PATCH 01/34] Add basic implementation for can bridge --- can/bridge.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 1 + 2 files changed, 48 insertions(+) create mode 100644 can/bridge.py diff --git a/can/bridge.py b/can/bridge.py new file mode 100644 index 000000000..0a5921e0b --- /dev/null +++ b/can/bridge.py @@ -0,0 +1,47 @@ +""" +Creates a bridge between two CAN busses. + +This will connect to two CAN busses. Messages received on one +bus will be sent to the other bus and vice versa. +""" + +import argparse +import errno +import sys +from datetime import datetime + +from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config + + +def main() -> None: + parser = argparse.ArgumentParser(description="Bridge two CAN busses.") + + _create_base_argument_parser(parser) + + parser.add_argument( + "--error-frames", + help="Also send error frames to the interface.", + action="store_true", + ) + + # print help message when no arguments were given + if len(sys.argv) < 2: + parser.print_help(sys.stderr) + raise SystemExit(errno.EINVAL) + + results, unknown_args = parser.parse_known_args() + additional_config = _parse_additional_config([*results.extra_args, *unknown_args]) + + verbosity = results.verbosity + + error_frames = results.error_frames + + with _create_bus(results, **additional_config) as bus_a + with _create_bus(results, **additional_config) as bus_b + print(f"CAN Bridge (Started on {datetime.now()})") + + print(f"CAN Bridge (Stopped on {datetime.now()})") + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index d41bf6e22..fd4461d61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ can_logconvert = "can.logconvert:main" can_logger = "can.logger:main" can_player = "can.player:main" can_viewer = "can.viewer:main" +can_bridge = "can.bridge:main" [project.urls] homepage = "https://github.com/hardbyte/python-can" From 7ec1f52cf5493da8b4271215eec9aa01b4c94cf9 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 21:16:54 +0100 Subject: [PATCH 02/34] Implement basic configuration parsing --- can/bridge.py | 80 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 14 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 0a5921e0b..3c6709876 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -8,36 +8,88 @@ import argparse import errno import sys +import logging from datetime import datetime from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config -def main() -> None: - parser = argparse.ArgumentParser(description="Bridge two CAN busses.") +LOG = logging.getLogger(__name__) + + +def get_config_list(it, separator, conf): + while True: + el = next(it) + if el == separator: + break + else: + conf.append(el) + + +def split_configurations(arg_list, separator='--'): + general = [] + conf_a = [] + conf_b = [] + + it = iter(arg_list) + try: + get_config_list(it, separator, conf_a) + get_config_list(it, separator, conf_b) + + # When we reached this point we found two separators so we have + # a general config. We will treate the first config as general + general = conf_a + conf_a = conf_b + get_config_list(it, separator, conf_b) - _create_base_argument_parser(parser) + # When we reached this point we found three separators so this is + # an error. + raise Exception("To many configurations") + except StopIteration: + LOG.debug("All configurations were split") - parser.add_argument( - "--error-frames", - help="Also send error frames to the interface.", - action="store_true", + return general, conf_a, conf_b + + +def main() -> None: + general_parser = argparse.ArgumentParser() + general_parser.add_argument( + "-v", + action="count", + dest="verbosity", + help="""How much information do you want to see at the command line? + You can add several of these e.g., -vv is DEBUG""", + default=2, ) + bus_parser = argparse.ArgumentParser(description="Bridge two CAN busses.") + + _create_base_argument_parser(bus_parser) + + parser = argparse.ArgumentParser(description="Bridge two CAN busses.") + parser.add_argument('configs', nargs=argparse.REMAINDER) + # print help message when no arguments were given if len(sys.argv) < 2: - parser.print_help(sys.stderr) + bus_parser.print_help(sys.stderr) raise SystemExit(errno.EINVAL) - results, unknown_args = parser.parse_known_args() - additional_config = _parse_additional_config([*results.extra_args, *unknown_args]) + args = sys.argv[1:] + general, conf_a, conf_b = split_configurations(args) + + g_results = general_parser.parse_args(general) + verbosity = g_results.verbosity - verbosity = results.verbosity + a_results, a_unknown_args = bus_parser.parse_known_args(conf_a) + a_additional_config = _parse_additional_config([*a_results.extra_args, *a_unknown_args]) + a_results.__dict__['verbosity'] = verbosity - error_frames = results.error_frames + b_results, b_unknown_args = bus_parser.parse_known_args(conf_b) + b_additional_config = _parse_additional_config([*b_results.extra_args, *b_unknown_args]) + b_results.__dict__['verbosity'] = verbosity - with _create_bus(results, **additional_config) as bus_a - with _create_bus(results, **additional_config) as bus_b + with _create_bus(a_results, **a_additional_config) as bus_a: + with _create_bus(b_results, **b_additional_config) as bus_b: print(f"CAN Bridge (Started on {datetime.now()})") print(f"CAN Bridge (Stopped on {datetime.now()})") From 441c4da0e238ef5ab7ca2b49dd2bb4aadd211cf9 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 21:25:11 +0100 Subject: [PATCH 03/34] Add implementation for bridge --- can/bridge.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/can/bridge.py b/can/bridge.py index 3c6709876..cb957f0db 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -8,11 +8,14 @@ import argparse import errno import sys +import time import logging from datetime import datetime from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config +import can + LOG = logging.getLogger(__name__) @@ -90,7 +93,13 @@ def main() -> None: with _create_bus(a_results, **a_additional_config) as bus_a: with _create_bus(b_results, **b_additional_config) as bus_b: + reader_a = can.RedirectReader(bus_b) + reader_b = can.RedirectReader(bus_a) + notifier_a = can.Notifier(bus_a, [reader_a]) + notifier_b = can.Notifier(bus_b, [reader_b]) print(f"CAN Bridge (Started on {datetime.now()})") + while True: + time.sleep(1) print(f"CAN Bridge (Stopped on {datetime.now()})") From e599f0e4dcf1a87cde8fef37cda33eecdb199bb8 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 21:26:15 +0100 Subject: [PATCH 04/34] Improve exit handling --- can/bridge.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index cb957f0db..057813bef 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -98,8 +98,11 @@ def main() -> None: notifier_a = can.Notifier(bus_a, [reader_a]) notifier_b = can.Notifier(bus_b, [reader_b]) print(f"CAN Bridge (Started on {datetime.now()})") - while True: - time.sleep(1) + try: + while True: + time.sleep(1) + except KeyboardInterrupt: + pass print(f"CAN Bridge (Stopped on {datetime.now()})") From 7b18bc676c3c2ae3593515af16d94620dc6ecd0a Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 21:35:01 +0100 Subject: [PATCH 05/34] Add debug logging --- can/bridge.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/can/bridge.py b/can/bridge.py index 057813bef..24f4f0e20 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -80,6 +80,9 @@ def main() -> None: args = sys.argv[1:] general, conf_a, conf_b = split_configurations(args) + LOG.debug("General configuration: %s", general) + LOG.debug("Bus A configuration: %s", conf_a) + LOG.debug("Bus B configuration: %s", conf_b) g_results = general_parser.parse_args(general) verbosity = g_results.verbosity @@ -91,6 +94,11 @@ def main() -> None: b_additional_config = _parse_additional_config([*b_results.extra_args, *b_unknown_args]) b_results.__dict__['verbosity'] = verbosity + LOG.debug("General configuration results: %s", g_results) + LOG.debug("Bus A configuration results: %s", a_results) + LOG.debug("Bus A additional configuration results: %s", a_additional_config) + LOG.debug("Bus B configuration results: %s", b_results) + LOG.debug("Bus B additional configuration results: %s", b_additional_config) with _create_bus(a_results, **a_additional_config) as bus_a: with _create_bus(b_results, **b_additional_config) as bus_b: reader_a = can.RedirectReader(bus_b) From 9e3c66631189765908c0d7678ac8193c27e3d622 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 21:50:12 +0100 Subject: [PATCH 06/34] Add error handling for wrong arguments --- can/bridge.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 24f4f0e20..3d17faa2e 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -20,6 +20,10 @@ LOG = logging.getLogger(__name__) +class UserError(Exception): + pass + + def get_config_list(it, separator, conf): while True: el = next(it) @@ -34,9 +38,11 @@ def split_configurations(arg_list, separator='--'): conf_a = [] conf_b = [] + found_sep = False it = iter(arg_list) try: get_config_list(it, separator, conf_a) + found_sep = True get_config_list(it, separator, conf_b) # When we reached this point we found two separators so we have @@ -47,9 +53,11 @@ def split_configurations(arg_list, separator='--'): # When we reached this point we found three separators so this is # an error. - raise Exception("To many configurations") + raise UserError("To many configurations") except StopIteration: LOG.debug("All configurations were split") + if not found_sep: + raise UserError("Missing separator") return general, conf_a, conf_b @@ -78,7 +86,13 @@ def main() -> None: raise SystemExit(errno.EINVAL) args = sys.argv[1:] - general, conf_a, conf_b = split_configurations(args) + try: + general, conf_a, conf_b = split_configurations(args) + except UserError as exc: + print("Error while processing arguments:") + print(exc) + print("") + raise SystemExit(errno.EINVAL) LOG.debug("General configuration: %s", general) LOG.debug("Bus A configuration: %s", conf_a) From 8e4bd93d18adffd3932ad03ce7edd18965ef3164 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 21:54:07 +0100 Subject: [PATCH 07/34] Use stderr --- can/bridge.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 3d17faa2e..10ee9bd88 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -89,9 +89,8 @@ def main() -> None: try: general, conf_a, conf_b = split_configurations(args) except UserError as exc: - print("Error while processing arguments:") - print(exc) - print("") + print(f"Error while processing arguments: {exc}", + file=sys.stderr) raise SystemExit(errno.EINVAL) LOG.debug("General configuration: %s", general) From 52703d7c94687f4540e8fdf78a50d066d678ba85 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 22:03:35 +0100 Subject: [PATCH 08/34] Add custom usage --- can/bridge.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/can/bridge.py b/can/bridge.py index 10ee9bd88..e40c3f0b3 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -17,6 +17,23 @@ import can +USAGE = """ +usage: can_bridge [{general config} --] {can A config} -- {can B config} + +Bridge two CAN busses. + +Both can busses will be connected so that messages from bus A will be sent on bus B and messages on bus B will be sent to bus A. The busses are separated by a `--` + +positional arguments: + {general config} The configuration for this program excluding the config for each bus. Can be omitted + {can A config} The configuration for the first bus + {can B config} The configuration for the second bus + +Example usage: + can_bridge -i socketcan -c can0 -- -i socketcan can1 + can_bridge -vvv -- -i socketcan -c can0 -- -i socketcan can1 +""" + LOG = logging.getLogger(__name__) @@ -82,7 +99,7 @@ def main() -> None: # print help message when no arguments were given if len(sys.argv) < 2: - bus_parser.print_help(sys.stderr) + print(USAGE, file=sys.stderr) raise SystemExit(errno.EINVAL) args = sys.argv[1:] From 0435e17cf7a3b98ead4725a7267608c6ea6e08ea Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sat, 22 Feb 2025 22:07:36 +0100 Subject: [PATCH 09/34] Add bus configuration info --- can/bridge.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index e40c3f0b3..8e0ee40e1 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -32,6 +32,8 @@ Example usage: can_bridge -i socketcan -c can0 -- -i socketcan can1 can_bridge -vvv -- -i socketcan -c can0 -- -i socketcan can1 + +Type `can_bridge help_bus` for information about single bus configuration. """ LOG = logging.getLogger(__name__) @@ -106,8 +108,11 @@ def main() -> None: try: general, conf_a, conf_b = split_configurations(args) except UserError as exc: - print(f"Error while processing arguments: {exc}", - file=sys.stderr) + if len(args) == 1 and args[0] == 'help_bus': + bus_parser.print_help(sys.stderr) + else: + print(f"Error while processing arguments: {exc}", + file=sys.stderr) raise SystemExit(errno.EINVAL) LOG.debug("General configuration: %s", general) From 8da0ab3f8c43ee5180d469c76e42d060d3bddeba Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 10:54:47 +0100 Subject: [PATCH 10/34] Code format --- can/bridge.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 8e0ee40e1..8a6b270c8 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -52,7 +52,7 @@ def get_config_list(it, separator, conf): conf.append(el) -def split_configurations(arg_list, separator='--'): +def split_configurations(arg_list, separator="--"): general = [] conf_a = [] conf_b = [] @@ -97,7 +97,7 @@ def main() -> None: _create_base_argument_parser(bus_parser) parser = argparse.ArgumentParser(description="Bridge two CAN busses.") - parser.add_argument('configs', nargs=argparse.REMAINDER) + parser.add_argument("configs", nargs=argparse.REMAINDER) # print help message when no arguments were given if len(sys.argv) < 2: @@ -108,11 +108,10 @@ def main() -> None: try: general, conf_a, conf_b = split_configurations(args) except UserError as exc: - if len(args) == 1 and args[0] == 'help_bus': + if len(args) == 1 and args[0] == "help_bus": bus_parser.print_help(sys.stderr) else: - print(f"Error while processing arguments: {exc}", - file=sys.stderr) + print(f"Error while processing arguments: {exc}", file=sys.stderr) raise SystemExit(errno.EINVAL) LOG.debug("General configuration: %s", general) @@ -122,12 +121,16 @@ def main() -> None: verbosity = g_results.verbosity a_results, a_unknown_args = bus_parser.parse_known_args(conf_a) - a_additional_config = _parse_additional_config([*a_results.extra_args, *a_unknown_args]) - a_results.__dict__['verbosity'] = verbosity + a_additional_config = _parse_additional_config( + [*a_results.extra_args, *a_unknown_args] + ) + a_results.__dict__["verbosity"] = verbosity b_results, b_unknown_args = bus_parser.parse_known_args(conf_b) - b_additional_config = _parse_additional_config([*b_results.extra_args, *b_unknown_args]) - b_results.__dict__['verbosity'] = verbosity + b_additional_config = _parse_additional_config( + [*b_results.extra_args, *b_unknown_args] + ) + b_results.__dict__["verbosity"] = verbosity LOG.debug("General configuration results: %s", g_results) LOG.debug("Bus A configuration results: %s", a_results) From 9fa9395f934a382ab932c659a6e5d5216210b082 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:03:07 +0100 Subject: [PATCH 11/34] Add exception for prints for can_bridge --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index fd4461d61..2f434cb09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,6 +167,7 @@ ignore = [ ] "can/logger.py" = ["T20"] # flake8-print "can/player.py" = ["T20"] # flake8-print +"can/bridge.py" = ["T20"] # flake8-print [tool.ruff.lint.isort] known-first-party = ["can"] From 3e3dd9ecae01abff1873a7dde14c9d867cb7ba6c Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:05:02 +0100 Subject: [PATCH 12/34] Add from to exception in exception --- can/bridge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 8a6b270c8..65bd25664 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -76,7 +76,7 @@ def split_configurations(arg_list, separator="--"): except StopIteration: LOG.debug("All configurations were split") if not found_sep: - raise UserError("Missing separator") + raise UserError("Missing separator") from None return general, conf_a, conf_b @@ -112,7 +112,7 @@ def main() -> None: bus_parser.print_help(sys.stderr) else: print(f"Error while processing arguments: {exc}", file=sys.stderr) - raise SystemExit(errno.EINVAL) + raise SystemExit(errno.EINVAL) from exc LOG.debug("General configuration: %s", general) LOG.debug("Bus A configuration: %s", conf_a) From 1f2de7d6b2cd9b53edf2c084ac0be463e09c74da Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:05:19 +0100 Subject: [PATCH 13/34] Remove assignment to unused variable --- can/bridge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 65bd25664..992c96ee5 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -141,8 +141,8 @@ def main() -> None: with _create_bus(b_results, **b_additional_config) as bus_b: reader_a = can.RedirectReader(bus_b) reader_b = can.RedirectReader(bus_a) - notifier_a = can.Notifier(bus_a, [reader_a]) - notifier_b = can.Notifier(bus_b, [reader_b]) + can.Notifier(bus_a, [reader_a]) + can.Notifier(bus_b, [reader_b]) print(f"CAN Bridge (Started on {datetime.now()})") try: while True: From ac6e4dbae83b9c13b3dc70cd7833d240db9abc09 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:06:45 +0100 Subject: [PATCH 14/34] Shorten line length --- can/bridge.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 992c96ee5..5a4a16d21 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -22,10 +22,12 @@ Bridge two CAN busses. -Both can busses will be connected so that messages from bus A will be sent on bus B and messages on bus B will be sent to bus A. The busses are separated by a `--` +Both can busses will be connected so that messages from bus A will be sent on +bus B and messages on bus B will be sent to bus A. The busses are separated by a `--` positional arguments: - {general config} The configuration for this program excluding the config for each bus. Can be omitted + {general config} The configuration for this program excluding + the config for each bus. Can be omitted {can A config} The configuration for the first bus {can B config} The configuration for the second bus From 0fcea6483c881886830990f2ad6ffcf5512d707e Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:10:33 +0100 Subject: [PATCH 15/34] Organize imports --- can/bridge.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 5a4a16d21..e9f51c1d4 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -7,15 +7,14 @@ import argparse import errno +import logging import sys import time -import logging from datetime import datetime -from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config - import can +from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config USAGE = """ usage: can_bridge [{general config} --] {can A config} -- {can B config} From d37af871c1d5e8e976aedeca67890d84025e7e7e Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:12:35 +0100 Subject: [PATCH 16/34] Remove unnecessary else --- can/bridge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index e9f51c1d4..6833af8af 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -49,8 +49,8 @@ def get_config_list(it, separator, conf): el = next(it) if el == separator: break - else: - conf.append(el) + + conf.append(el) def split_configurations(arg_list, separator="--"): From 6b0378ec4c7f71abcf9e6e0759b3e6f1feee8702 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:18:58 +0100 Subject: [PATCH 17/34] Add documentation for new script --- doc/scripts.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/scripts.rst b/doc/scripts.rst index 2d59b7528..281391162 100644 --- a/doc/scripts.rst +++ b/doc/scripts.rst @@ -57,6 +57,21 @@ The full usage page can be seen below: :shell: +can.bridge +---------- + +A small application that can be used to connect two can busses: + +.. command-output:: python -m can.bridge -h + :shell: + + +Example call: +:: + + python -m can.bridge -i socketcan -c can0 -- -i socketcan -c can1 + + can.logconvert -------------- From 28c80bdb078069b5acfa6f3a065113dbd5b6a442 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:25:08 +0100 Subject: [PATCH 18/34] Add handling for -h and help sub command Necessary for generation of documentation --- can/bridge.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 6833af8af..a2cbfd4aa 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -109,8 +109,12 @@ def main() -> None: try: general, conf_a, conf_b = split_configurations(args) except UserError as exc: - if len(args) == 1 and args[0] == "help_bus": - bus_parser.print_help(sys.stderr) + if len(args) >= 1: + if args[0] == "-h" or args[0] == "help": + print(USAGE) + raise SystemExit() + elif args[0] == "help_bus": + bus_parser.print_help(sys.stderr) else: print(f"Error while processing arguments: {exc}", file=sys.stderr) raise SystemExit(errno.EINVAL) from exc From c780e8ad5c00d2a95217e2e8da3ec15064499623 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 11:27:24 +0100 Subject: [PATCH 19/34] Add from none to exception --- can/bridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/bridge.py b/can/bridge.py index a2cbfd4aa..130ed46c6 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -112,7 +112,7 @@ def main() -> None: if len(args) >= 1: if args[0] == "-h" or args[0] == "help": print(USAGE) - raise SystemExit() + raise SystemExit() from None elif args[0] == "help_bus": bus_parser.print_help(sys.stderr) else: From de20baf367f21be972b5e7940c0adf2b4c15893e Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 18:34:02 +0100 Subject: [PATCH 20/34] Fix typo busses to bus --- can/bridge.py | 14 +++++++------- doc/scripts.rst | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 130ed46c6..0b42d525f 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -1,7 +1,7 @@ """ -Creates a bridge between two CAN busses. +Creates a bridge between two CAN buses. -This will connect to two CAN busses. Messages received on one +This will connect to two CAN buses. Messages received on one bus will be sent to the other bus and vice versa. """ @@ -19,10 +19,10 @@ USAGE = """ usage: can_bridge [{general config} --] {can A config} -- {can B config} -Bridge two CAN busses. +Bridge two CAN buses. -Both can busses will be connected so that messages from bus A will be sent on -bus B and messages on bus B will be sent to bus A. The busses are separated by a `--` +Both can buses will be connected so that messages from bus A will be sent on +bus B and messages on bus B will be sent to bus A. The buses are separated by a `--` positional arguments: {general config} The configuration for this program excluding @@ -93,11 +93,11 @@ def main() -> None: default=2, ) - bus_parser = argparse.ArgumentParser(description="Bridge two CAN busses.") + bus_parser = argparse.ArgumentParser(description="Bridge two CAN buses.") _create_base_argument_parser(bus_parser) - parser = argparse.ArgumentParser(description="Bridge two CAN busses.") + parser = argparse.ArgumentParser(description="Bridge two CAN buses.") parser.add_argument("configs", nargs=argparse.REMAINDER) # print help message when no arguments were given diff --git a/doc/scripts.rst b/doc/scripts.rst index 281391162..47555bf87 100644 --- a/doc/scripts.rst +++ b/doc/scripts.rst @@ -60,7 +60,7 @@ The full usage page can be seen below: can.bridge ---------- -A small application that can be used to connect two can busses: +A small application that can be used to connect two can buses: .. command-output:: python -m can.bridge -h :shell: From 5a17ef6d01b57abcff4d06d588788e66c0699cf0 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 18:48:55 +0100 Subject: [PATCH 21/34] Add type annotations --- can/bridge.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 0b42d525f..12d04ca9d 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -11,6 +11,9 @@ import sys import time from datetime import datetime +from typing import ( + Iterator, +) import can @@ -44,7 +47,7 @@ class UserError(Exception): pass -def get_config_list(it, separator, conf): +def get_config_list(it: Iterator[str], separator: str, conf) -> None: while True: el = next(it) if el == separator: @@ -53,7 +56,9 @@ def get_config_list(it, separator, conf): conf.append(el) -def split_configurations(arg_list, separator="--"): +def split_configurations( + arg_list: list[str], separator: str = "--" +) -> (list, list, list): general = [] conf_a = [] conf_b = [] From d81dbab363912229224dce4e00cc8bc7ea60c78e Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 18:52:36 +0100 Subject: [PATCH 22/34] Fix type annotations --- can/bridge.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 12d04ca9d..3300a50a7 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -13,6 +13,7 @@ from datetime import datetime from typing import ( Iterator, + List, ) import can @@ -47,7 +48,7 @@ class UserError(Exception): pass -def get_config_list(it: Iterator[str], separator: str, conf) -> None: +def get_config_list(it: Iterator[str], separator: str, conf: list) -> None: while True: el = next(it) if el == separator: @@ -57,7 +58,7 @@ def get_config_list(it: Iterator[str], separator: str, conf) -> None: def split_configurations( - arg_list: list[str], separator: str = "--" + arg_list: List[str], separator: str = "--" ) -> (list, list, list): general = [] conf_a = [] From 2e8652f2462e065385f07c843d34112482f6c7a2 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 18:55:41 +0100 Subject: [PATCH 23/34] Fix type annotations again --- can/bridge.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/can/bridge.py b/can/bridge.py index 3300a50a7..50da299a3 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -14,6 +14,7 @@ from typing import ( Iterator, List, + Tuple, ) import can @@ -59,10 +60,10 @@ def get_config_list(it: Iterator[str], separator: str, conf: list) -> None: def split_configurations( arg_list: List[str], separator: str = "--" -) -> (list, list, list): +) -> Tuple[list, list, list]: general = [] - conf_a = [] - conf_b = [] + conf_a: List[str] = [] + conf_b: List[str] = [] found_sep = False it = iter(arg_list) From 3d707610d959caadff299c01238c1af0cd097efa Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 19:47:03 +0100 Subject: [PATCH 24/34] Add --help to get help --- can/bridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/can/bridge.py b/can/bridge.py index 50da299a3..bbae0a3e1 100644 --- a/can/bridge.py +++ b/can/bridge.py @@ -117,7 +117,7 @@ def main() -> None: general, conf_a, conf_b = split_configurations(args) except UserError as exc: if len(args) >= 1: - if args[0] == "-h" or args[0] == "help": + if args[0] == "-h" or args[0] == "--help" or args[0] == "help": print(USAGE) raise SystemExit() from None elif args[0] == "help_bus": From e883a4e793ff57d4fa5a88790ef6bf5736117214 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 19:47:17 +0100 Subject: [PATCH 25/34] Add basic print help test --- test/test_scripts.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_scripts.py b/test/test_scripts.py index 9d8c059cf..c1a6c082d 100644 --- a/test/test_scripts.py +++ b/test/test_scripts.py @@ -98,6 +98,20 @@ def _import(self): return module +class TestBridgeScript(CanScriptTest): + def _commands(self): + commands = [ + "python -m can.bridge --help", + "can_bridge --help", + ] + return commands + + def _import(self): + import can.bridge as module + + return module + + class TestLogconvertScript(CanScriptTest): def _commands(self): commands = [ From e32b5d66ab5300f1b17cd3aaed9bb5f8415f1add Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 19:52:55 +0100 Subject: [PATCH 26/34] Add basic test file for bridge script --- test/test_bridge.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/test_bridge.py diff --git a/test/test_bridge.py b/test/test_bridge.py new file mode 100644 index 000000000..43fb96e06 --- /dev/null +++ b/test/test_bridge.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +""" +This module tests the functions inside of bridge.py +""" + +import unittest +from unittest import mock +from unittest.mock import Mock + +import can +import can.bridge + + +class TestBridgeScriptModule(unittest.TestCase): + def setUp(self) -> None: + # Patch VirtualBus object + patcher_virtual_bus = mock.patch("can.interfaces.virtual.VirtualBus", spec=True) + self.MockVirtualBus = patcher_virtual_bus.start() + self.addCleanup(patcher_virtual_bus.stop) + self.mock_virtual_bus = self.MockVirtualBus.return_value + self.mock_virtual_bus.shutdown = Mock() + + self.testmsg = can.Message( + arbitration_id=0xC0FFEE, data=[0, 25, 0, 1, 3, 1, 4, 1], is_extended_id=True + ) + + def assert_successfull_cleanup(self): + self.MockVirtualBus.assert_called_once() + self.mock_virtual_bus.shutdown.assert_called_once() + + +if __name__ == "__main__": + unittest.main() From 74556a1717d5e9042147b43039851b5804ab23e8 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 20:16:02 +0100 Subject: [PATCH 27/34] Add very basic test --- test/test_bridge.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index 43fb96e06..bd857b071 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -4,6 +4,7 @@ This module tests the functions inside of bridge.py """ +import sys import unittest from unittest import mock from unittest.mock import Mock @@ -21,13 +22,26 @@ def setUp(self) -> None: self.mock_virtual_bus = self.MockVirtualBus.return_value self.mock_virtual_bus.shutdown = Mock() + # Patch time sleep object + patcher_sleep = mock.patch("can.io.player.time.sleep", spec=True) + self.MockSleep = patcher_sleep.start() + self.addCleanup(patcher_sleep.stop) + self.testmsg = can.Message( arbitration_id=0xC0FFEE, data=[0, 25, 0, 1, 3, 1, 4, 1], is_extended_id=True ) + self.busargs = ["-i", "virtual"] + def assert_successfull_cleanup(self): - self.MockVirtualBus.assert_called_once() - self.mock_virtual_bus.shutdown.assert_called_once() + self.MockVirtualBus.assert_called() + + def test_bridge_no_config(self): + self.MockSleep.side_effect = KeyboardInterrupt + sys.argv = [sys.argv[0], *self.busargs, "--", *self.busargs] + can.bridge.main() + + self.assert_successfull_cleanup() if __name__ == "__main__": From 8a04304c901264e98af3256412d66bd4fa16058d Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 20:20:56 +0100 Subject: [PATCH 28/34] Add different channels for virtual bus --- test/test_bridge.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index bd857b071..3189d18b7 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -38,7 +38,16 @@ def assert_successfull_cleanup(self): def test_bridge_no_config(self): self.MockSleep.side_effect = KeyboardInterrupt - sys.argv = [sys.argv[0], *self.busargs, "--", *self.busargs] + sys.argv = [ + sys.argv[0], + *self.busargs, + "-c", + "can_a", + "--", + *self.busargs, + "-c", + "can_b", + ] can.bridge.main() self.assert_successfull_cleanup() From 05f3f03dfddbf8c4438fca2abf312fb99973240f Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 20:28:39 +0100 Subject: [PATCH 29/34] Add assert for call to exit --- test/test_bridge.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index 3189d18b7..b17030aff 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -20,7 +20,7 @@ def setUp(self) -> None: self.MockVirtualBus = patcher_virtual_bus.start() self.addCleanup(patcher_virtual_bus.stop) self.mock_virtual_bus = self.MockVirtualBus.return_value - self.mock_virtual_bus.shutdown = Mock() + self.mock_virtual_bus.__enter__ = Mock(return_value=self.mock_virtual_bus) # Patch time sleep object patcher_sleep = mock.patch("can.io.player.time.sleep", spec=True) @@ -35,6 +35,7 @@ def setUp(self) -> None: def assert_successfull_cleanup(self): self.MockVirtualBus.assert_called() + self.assertEqual(2, len(self.mock_virtual_bus.__exit__.mock_calls)) def test_bridge_no_config(self): self.MockSleep.side_effect = KeyboardInterrupt From 6bfcae9f8425c7c40f6de6ad5d106169aaa6371f Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Sun, 23 Feb 2025 20:33:11 +0100 Subject: [PATCH 30/34] Patch correct function --- test/test_bridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index b17030aff..c57b5768b 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -23,7 +23,7 @@ def setUp(self) -> None: self.mock_virtual_bus.__enter__ = Mock(return_value=self.mock_virtual_bus) # Patch time sleep object - patcher_sleep = mock.patch("can.io.player.time.sleep", spec=True) + patcher_sleep = mock.patch("can.bridge.time.sleep", spec=True) self.MockSleep = patcher_sleep.start() self.addCleanup(patcher_sleep.stop) From 6ffc7d418862eedcb86e4ad490bcc44892d3f408 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Mon, 24 Feb 2025 21:20:16 +0100 Subject: [PATCH 31/34] test --- test/test_bridge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index c57b5768b..973f98e93 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -49,9 +49,9 @@ def test_bridge_no_config(self): "-c", "can_b", ] - can.bridge.main() + #can.bridge.main() - self.assert_successfull_cleanup() + #self.assert_successfull_cleanup() if __name__ == "__main__": From 036e25c99802572f7424dd33d5d066a37cc82773 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Mon, 24 Feb 2025 21:23:59 +0100 Subject: [PATCH 32/34] fjkdf --- test/test_bridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index 973f98e93..df5a10a94 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -49,7 +49,7 @@ def test_bridge_no_config(self): "-c", "can_b", ] - #can.bridge.main() + can.bridge.main() #self.assert_successfull_cleanup() From e8f03ed2f191901608f3ed2d26b0def81cd53586 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Mon, 24 Feb 2025 21:27:42 +0100 Subject: [PATCH 33/34] once again -.- --- test/test_bridge.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index df5a10a94..c57b5768b 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -51,7 +51,7 @@ def test_bridge_no_config(self): ] can.bridge.main() - #self.assert_successfull_cleanup() + self.assert_successfull_cleanup() if __name__ == "__main__": From 8df35aa43e1fd5bd563fe9c6ce2b0c94cd554864 Mon Sep 17 00:00:00 2001 From: Peter Kessen Date: Mon, 24 Feb 2025 21:32:40 +0100 Subject: [PATCH 34/34] Try snakecase --- test/test_bridge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_bridge.py b/test/test_bridge.py index c57b5768b..11e645ede 100644 --- a/test/test_bridge.py +++ b/test/test_bridge.py @@ -33,7 +33,7 @@ def setUp(self) -> None: self.busargs = ["-i", "virtual"] - def assert_successfull_cleanup(self): + def assertSuccessfullCleanup(self): self.MockVirtualBus.assert_called() self.assertEqual(2, len(self.mock_virtual_bus.__exit__.mock_calls)) @@ -51,7 +51,7 @@ def test_bridge_no_config(self): ] can.bridge.main() - self.assert_successfull_cleanup() + self.assertSuccessfullCleanup() if __name__ == "__main__":