From 17275876dc524e99f4c4124275a03c4023771f09 Mon Sep 17 00:00:00 2001 From: Jerry Johns Date: Mon, 15 Nov 2021 13:54:24 -0800 Subject: [PATCH] Updated Matter Python REPL (#11563) * Updated CHIP REPL! This resurrects the chip-repl to be more usable and user-friendly, especially around how pretty printing, help text/documentation are generated. Notably, it leverages the 'rich' module to: - Provide capabilities to inspect the methods/values in any given class/module. - Pretty printing of cluster objects. * Missed a file * Restyled --- scripts/build_python.sh | 4 +- src/controller/python/BUILD.gn | 1 + src/controller/python/ChipReplStartup.py | 51 ++++++++++ src/controller/python/build-chip-wheel.py | 2 + src/controller/python/chip-repl.py | 110 +++++++++------------- 5 files changed, 98 insertions(+), 70 deletions(-) create mode 100644 src/controller/python/ChipReplStartup.py mode change 100644 => 100755 src/controller/python/chip-repl.py diff --git a/scripts/build_python.sh b/scripts/build_python.sh index 7d26083947657e..61b1e331fbd3cf 100755 --- a/scripts/build_python.sh +++ b/scripts/build_python.sh @@ -109,9 +109,9 @@ gn --root="$CHIP_ROOT" gen "$OUTPUT_ROOT" --args="chip_detail_logging=$chip_deta # Compiles python files # Check pybindings was requested if [ "$enable_pybindings" == true ]; then - ninja -v -C "$OUTPUT_ROOT" pycontroller + ninja -C "$OUTPUT_ROOT" pycontroller else - ninja -v -C "$OUTPUT_ROOT" python + ninja -C "$OUTPUT_ROOT" python fi # Create a virtual environment that has access to the built python tools diff --git a/src/controller/python/BUILD.gn b/src/controller/python/BUILD.gn index c670a48b7544bd..bfc6ba5041c96c 100644 --- a/src/controller/python/BUILD.gn +++ b/src/controller/python/BUILD.gn @@ -95,6 +95,7 @@ pw_python_action("python") { { src_dir = "." sources = [ + "ChipReplStartup.py", "chip-device-ctrl.py", "chip-repl.py", "chip/ChipBleBase.py", diff --git a/src/controller/python/ChipReplStartup.py b/src/controller/python/ChipReplStartup.py new file mode 100644 index 00000000000000..865042e34315be --- /dev/null +++ b/src/controller/python/ChipReplStartup.py @@ -0,0 +1,51 @@ +from rich import print +from rich.pretty import pprint +from rich import pretty +from rich import inspect +from rich.console import Console +import logging +from chip import ChipDeviceCtrl +import chip.clusters as Clusters +import coloredlogs +import chip.logging +import argparse +import builtins + + +def ReplInit(): + # + # Install the pretty printer that rich provides to replace the existing + # printer. + # + pretty.install(indent_guides=True, expand_all=True) + + console = Console() + + console.rule('Matter REPL') + console.print(''' + [bold blue] + + Welcome to the Matter Python REPL! + + For help, please type [/][bold green]matterhelp()[/][bold blue] + + To get more information on a particular object/class, you can pass + that into [bold green]matterhelp()[/][bold blue] as well. + + ''') + console.rule() + + coloredlogs.install(level='DEBUG') + chip.logging.RedirectToPythonLogging() + logging.getLogger().setLevel(logging.ERROR) + + +def matterhelp(classOrObj=None): + if (classOrObj == None): + inspect(builtins.devCtrl, methods=True, help=True, private=False) + else: + inspect(classOrObj, methods=True, help=True, private=False) + + +def mattersetlog(level): + logging.getLogger().setLevel(level) diff --git a/src/controller/python/build-chip-wheel.py b/src/controller/python/build-chip-wheel.py index 984da8158f0f38..f9b141ca5897be 100644 --- a/src/controller/python/build-chip-wheel.py +++ b/src/controller/python/build-chip-wheel.py @@ -119,6 +119,8 @@ def finalize_options(self): 'ipython', 'dacite', 'rich', + 'stringcase', + 'pyyaml', ] if platform.system() == 'Darwin': diff --git a/src/controller/python/chip-repl.py b/src/controller/python/chip-repl.py old mode 100644 new mode 100755 index 99ad8714a119e7..0f6798137e4d06 --- a/src/controller/python/chip-repl.py +++ b/src/controller/python/chip-repl.py @@ -17,81 +17,55 @@ # limitations under the License. # -from IPython import embed +import IPython import chip import chip.logging import coloredlogs import logging +from traitlets.config import Config +from rich import print +from rich import pretty +from rich import inspect +import builtins +import argparse +import sys def main(): - # The chip imports at the top level will be visible in the ipython REPL. - - coloredlogs.install(level='DEBUG') - chip.logging.RedirectToPythonLogging() - - # trace/debug logging is not friendly to an interactive console. Only keep errors. - logging.getLogger().setLevel(logging.ERROR) - - embed(header=''' -Welcome to the CHIP python REPL utilty. - -Usage examples: - -######## Enable detailed logging if needed ######### - -import logging -logging.getLogger().setLevel(logging.DEBUG) - -######## List available BLE adapters ######### -import chip.ble -print(chip.ble.GetAdapters()) - -######## Discover chip devices ######### -import chip.ble - -chip.ble.DiscoverAsync(2000, lambda *x: print('Discovered: %r' % (x,)), lambda: print('Done')) - -for device in chip.ble.DiscoverSync(2000): - print(device) - -####### Commision a BLE device ######### - -import chip.ble.commissioning - -device = chip.ble.commissioning.Connect(discriminator=3840, pin=20202021) -if device.needsNetworkCredentials: - device.ConnectToWifi("ssid", "password") - -######## Thread provisioning ######## - -import chip.ble.commissioning -device = chip.ble.commissioning.Connect(discriminator=3840, pin=20202021) - -# Thread data is an opaque blob, but it can be build with internal constructs -# starting from a memset(0) equivalent -from chip.internal.thread import ThreadNetworkInfo - -data = ThreadNetworkInfo.parse(b'\\x00'*ThreadNetworkInfo.sizeof()) -data.NetworkName = "OpenThread" -data.ExtendedPANId = b"\\xde\\xad\\x00\\xbe\\xef\\x00\\xca\\xfe" -data.MasterKey = b"\\x00\\x11\\x22\\x33\\x44\\x55\\x66\\x77\\x88\\x99\\xAA\\xBB\\xCC\\xDD\\xEE\\xFF" -data.PANId = 0xabcd -data.Channel = 15 - - -if device.needsNetworkCredentials: - device.ConnectToThread(ThreadNetworkInfo.build(data)) - -######## Node discovery ######## - -import chip.discovery - -chip.discovery.FindAddressAsync(123, 456, lambda x: print("%r", x)) - -print(chip.discovery.FindAddress(123, 456) - - '''.strip()) + parser = argparse.ArgumentParser() + parser.add_argument( + "-n", "--noautoinit", help="Disable the default auto-initialization of the controller", action="store_true") + args = parser.parse_args() + + c = Config() + c.InteractiveShellApp.exec_lines = [ + "from rich import print", + "from rich.pretty import pprint", + "from rich import pretty", + "from rich import inspect", + "from rich.console import Console", + "import logging", + "from chip import ChipDeviceCtrl", + "import chip.clusters as Clusters", + "import coloredlogs", + "import chip.logging", + "import argparse", + "from chip.ChipReplStartup import *", + "ReplInit()", + ] + + if (not(args.noautoinit)): + c.InteractiveShellApp.exec_lines.extend([ + "import builtins", + "devCtrl = ChipDeviceCtrl.ChipDeviceController(controllerNodeId=12344321)", + "builtins.devCtrl = devCtrl", + "console = Console()", + "console.print('\\n\\n[blue]CHIP Device Controller has been initialized, and is available as [bold red]devCtrl')" + ]) + + sys.argv = [sys.argv[0]] + + IPython.start_ipython(config=c) if __name__ == "__main__":