improved entry-point main for calling matrix-commander from Python

- created error class MatrixCommanderError
- instead of sys.exit() exceptions are created and they bubble up till the very top
  so that main() never calles sys.exit()
- improvements in documentation
- minor touch-ups
pull/74/head
8go 2 months ago
parent 4061c63282
commit 0e8c2c4085
  1. 2
      .gitignore
  2. 1
      MANIFEST.in
  3. 17
      PyPi-Instructions.md
  4. 11
      README.md
  5. 318
      matrix_commander/matrix_commander.py
  6. 6
      scripts/create-pypi-package.sh
  7. 8
      setup.cfg
  8. 2
      tests/test-event.sh
  9. 31
      tests/test-send.py

2
.gitignore vendored

@ -21,6 +21,8 @@ help.txt.*
# ignore soft link
mc
m-c
m_c
# ignore certain scripts
/scripts/prepare-commit.sh

@ -0,0 +1 @@
include PyPi-Instructions.md

@ -1,12 +1,13 @@
# PRE-INSTALLATION
Before you install `matrix-commander` with `pip3 --install matrix-commander`
you *must* have `libolm` installed. `pip3` installation will fail otherwise!
Before you install `matrix-commander` with `pip install matrix-commander`
you *must* have `libolm` installed. `pip` installation will fail otherwise!
For e2ee
support, python-olm is needed which requires the
For e2ee support, python-olm is needed which requires the
[libolm](https://gitlab.matrix.org/matrix-org/olm) C library (version 3.x).
On Debian and Ubuntu one can use `apt-get` to install package `libolm-dev`.
On Fedora one can use `dnf` to install package `libolm-devel`.
On MacOS one can use [brew](https://brew.sh/) to install package `libolm`.
Make sure version 3 is installed.
- On Debian, Ubuntu and Debian or Ubuntu derivate distributions do `sudo apt install libolm-dev` to install the `libolm` package.
- On Fedora or Fedora derivate distributions do `sudo dnf install libolm-devel` to install the `libolm` package.
- On MacOS one can use [brew](https://brew.sh/) to install package `libolm`.
Make sure that version 3 is installed. Version 2 will not work.

@ -2,7 +2,7 @@
https://img.shields.io/badge/built%20with-matrix--nio-brightgreen)](
https://github.com/poljar/matrix-nio)
![logo](https://github.com/8go/matrix-commander/logos/matrix-commander-logo.svg)
![logo](https://github.com/8go/matrix-commander/blob/master/logos/matrix-commander-logo.svg)
# :loudspeaker: :new: :boom: Latest News! :fire: :mega: :tada:
@ -14,7 +14,7 @@ https://github.com/poljar/matrix-nio)
preferred way to execute the program.
- `matrix-commander` is now callable from a Python program as well.
See [tests/test-send.py](
https://github.com/8go/matrix-commander/tests/test-send.py)
https://github.com/8go/matrix-commander/blob/master/tests/test-send.py)
for an example on how to do that.
# matrix-commander
@ -221,7 +221,7 @@ dependencies that you must take care of:
Import the Python module `matrix_commander` and use the provided
entry point `main`. An example of how this can be done can be found
in [tests/test-send.py](
https://github.com/8go/matrix-commander/tests/test-send.py).
https://github.com/8go/matrix-commander/blob/master/tests/test-send.py).
```
$ matrix-commander # first run; this will configure everything
@ -751,7 +751,7 @@ options:
information program will continue to run. This is
useful for having version number in the log files.
You are running version 2.16.0 2022-05-29. Enjoy, star on Github and
You are running version 2.17.0 2022-05-30. Enjoy, star on Github and
contribute by submitting a Pull Request.
```
@ -815,7 +815,8 @@ Tab completion is provided for shells (e.g. bash), courtesy of @mizlan).
Here is a sample snapshot of tab completion in action:
![tab completion](./screenshots/tab_complete.png)
![tab completion](
https://github.com/8go/matrix-commander/blob/master/screenshots/tab_complete.png)
# Performance and Speed

@ -9,7 +9,7 @@ r"""matrix_commander.py.
https://img.shields.io/badge/built%20with-matrix--nio-brightgreen)](
https://github.com/poljar/matrix-nio)
![logo](https://github.com/8go/matrix-commander/logos/matrix-commander-logo.svg)
![logo](https://github.com/8go/matrix-commander/blob/master/logos/matrix-commander-logo.svg)
# :loudspeaker: :new: :boom: Latest News! :fire: :mega: :tada:
@ -21,7 +21,7 @@ https://github.com/poljar/matrix-nio)
preferred way to execute the program.
- `matrix-commander` is now callable from a Python program as well.
See [tests/test-send.py](
https://github.com/8go/matrix-commander/tests/test-send.py)
https://github.com/8go/matrix-commander/blob/master/tests/test-send.py)
for an example on how to do that.
# matrix-commander
@ -228,7 +228,7 @@ dependencies that you must take care of:
Import the Python module `matrix_commander` and use the provided
entry point `main`. An example of how this can be done can be found
in [tests/test-send.py](
https://github.com/8go/matrix-commander/tests/test-send.py).
https://github.com/8go/matrix-commander/blob/master/tests/test-send.py).
```
$ matrix-commander # first run; this will configure everything
@ -758,7 +758,7 @@ options:
information program will continue to run. This is
useful for having version number in the log files.
You are running version 2.16.0 2022-05-29. Enjoy, star on Github and
You are running version 2.17.0 2022-05-30. Enjoy, star on Github and
contribute by submitting a Pull Request.
```
@ -822,7 +822,8 @@ Tab completion is provided for shells (e.g. bash), courtesy of @mizlan).
Here is a sample snapshot of tab completion in action:
![tab completion](./screenshots/tab_complete.png)
![tab completion](
https://github.com/8go/matrix-commander/blob/master/screenshots/tab_complete.png)
# Performance and Speed
@ -888,6 +889,7 @@ See [GPL3 at FSF](https://www.fsf.org/licensing/).
import argparse
import asyncio
import datetime
import errno
import getpass
import json
import logging
@ -980,8 +982,8 @@ except ImportError:
HAVE_NOTIFY = False
# version number
VERSION = "2022-05-29"
VERSIONNR = "2.16.0"
VERSION = "2022-05-30"
VERSIONNR = "2.17.0"
# matrix-commander; for backwards compitability replace _ with -
PROG_WITHOUT_EXT = os.path.splitext(os.path.basename(__file__))[0].replace(
"_", "-"
@ -1039,6 +1041,21 @@ SSL_CERTIFICATE_DEFAULT = None # use None if --ssl-certificate is not given
NO_SSO_UNUSED_DEFAULT = None # use None if --no-sso is not given
class MatrixCommanderError(RuntimeError):
def __init__(
self,
errmsg: str,
traceback: bool = False, # is traceback printing desired?
level: str = "error",
):
self.errmsg = errmsg
self.traceback = traceback
self.level = level # debug, info, warning, error
def __str__(self):
return self.errmsg
class GlobalState:
"""Keep global variables.
@ -2883,9 +2900,11 @@ async def create_credentials_file( # noqa: C901
)
if confirm.lower() != "yes" and confirm.lower() != "y":
print("") # add newline to stdout to separate any log info
gs.log.info("Aborting.")
cleanup()
sys.exit(1)
raise MatrixCommanderError(
"Aborting due to user request.",
traceback=False,
level="info",
)
homeserver = "https://matrix.example.org"
homeserver = input(f"Enter URL of your homeserver: [{homeserver}] ")
if not homeserver:
@ -2985,38 +3004,41 @@ async def create_credentials_file( # noqa: C901
try:
subprocess.check_output(cmd)
except Exception:
gs.log.info(
raise MatrixCommanderError(
"Browser could not be launched. "
"Hence SSO (Single Sign-On) login could not be "
"completed. Sorry. If you think the browser and "
"SSO should work then try again. If you do not have "
"a browser or don't want SSO or want to login with a "
"password instead, then use the '--no-sso' option in "
"the command line."
"the command line.",
traceback=False,
level="error",
)
sys.exit(1)
# wait and shutdown server
try:
await asyncio.wait_for(stop_server_evt.wait(), 5 * 60)
except asyncio.TimeoutError:
gs.log.info(
raise MatrixCommanderError(
f"The program {PROG_WITH_EXT} failed. "
"No response was received from SSO provider. "
"Sorry."
"Sorry.",
traceback=False,
level="error",
)
sys.exit(1)
finally:
await runner.cleanup()
elif not password:
gs.log.info(
raise MatrixCommanderError(
"No supported login method found for homeserver. "
"Neither SSO nor password are accepted login "
"methods of the server."
"methods of the server.",
traceback=False,
level="error",
)
sys.exit(1)
# Configuration options for the AsyncClient
client_config = AsyncClientConfig(
@ -3044,6 +3066,8 @@ async def create_credentials_file( # noqa: C901
)
try:
txt = ""
level = ""
if sso:
resp = await client.login(
token=login_token, device_name=device_name
@ -3066,29 +3090,29 @@ async def create_credentials_file( # noqa: C901
room_id,
gs.pa.credentials,
)
text = f"""
txt = f"""
Log in using {method} was successful.
Credentials were stored in file \"{gs.pa.credentials}\".
Run program \"{PROG_WITH_EXT}\" again to
login with credentials and to send a message.
If you plan on having many credential files, consider
moving them to directory \"{CREDENTIALS_DIR_LASTRESORT}\"."""
print(textwrap.fill(textwrap.dedent(text).strip(), width=79))
txt = textwrap.fill(textwrap.dedent(txt).strip(), width=79)
level = "info"
else:
gs.log.info(
f"The program {PROG_WITH_EXT} failed. "
"Most likely wrong credentials were entered. "
"Sorry."
)
gs.log.info(
f'homeserver="{homeserver}"; user="{user_id}"; '
f'room_id="{room_id}"; '
f"failed to log in: {resp}"
)
txt = f"The program {PROG_WITH_EXT} failed. "
"Most likely wrong credentials were entered. "
"Sorry. \n"
f'homeserver="{homeserver}"; user="{user_id}"; '
f'room_id="{room_id}"; '
f"failed to log in: {resp}"
level = "error"
finally:
await client.close()
cleanup()
sys.exit(1)
if level == "error":
raise MatrixCommanderError(txt, traceback=True, level=level)
elif level == "info":
raise MatrixCommanderError(txt, traceback=False, level=level)
def login_using_credentials_file(
@ -3541,16 +3565,15 @@ async def main_listen() -> None:
credentials_file = determine_credentials_file()
store_dir = determine_store_dir()
if not os.path.isfile(credentials_file):
gs.log.info(
raise MatrixCommanderError(
f"""Credentials file was not found.
Did you start {PROG_WITHOUT_EXT} in the wrong directory?
Did you specify the credentials options incorrectly?
Credentials file must be created first before one can
listen.
Aborting due to missing or not-found credentials file."""
Credentials file must be created first before one can listen.
Aborting due to missing or not-found credentials file.""",
traceback=False,
level="error",
)
cleanup()
sys.exit(1)
gs.log.debug("Credentials file does exist.")
try:
client, credentials = login_using_credentials_file(
@ -3586,16 +3609,16 @@ async def main_rename_device() -> None:
credentials_file = determine_credentials_file()
store_dir = determine_store_dir()
if not os.path.isfile(credentials_file):
gs.log.info(
raise MatrixCommanderError(
f"""Credentials file was not found.
Did you start {PROG_WITHOUT_EXT} in the wrong directory?
Did you specify the credentials options incorrectly?
Credentials file must be created first before one can
rename device.
Aborting due to missing or not-found credentials file."""
Aborting due to missing or not-found credentials file.""",
traceback=False,
level="error",
)
cleanup()
sys.exit(1)
gs.log.debug("Credentials file does exist.")
try:
client, credentials = login_using_credentials_file(
@ -3617,16 +3640,16 @@ async def main_rename_user() -> None:
credentials_file = determine_credentials_file()
store_dir = determine_store_dir()
if not os.path.isfile(credentials_file):
gs.log.info(
raise MatrixCommanderError(
f"""Credentials file was not found.
Did you start {PROG_WITHOUT_EXT} in the wrong directory?
Did you specify the credentials options incorrectly?
Credentials file must be created first before one can
rename user.
Aborting due to missing or not-found credentials file."""
Aborting due to missing or not-found credentials file.""",
traceback=False,
level="error",
)
cleanup()
sys.exit(1)
gs.log.debug("Credentials file does exist.")
try:
client, credentials = login_using_credentials_file(
@ -3648,16 +3671,16 @@ async def main_room_actions() -> None: # noqa: C901
credentials_file = determine_credentials_file()
store_dir = determine_store_dir()
if not os.path.isfile(credentials_file):
gs.log.info(
raise MatrixCommanderError(
f"""Credentials file was not found.
Did you start {PROG_WITHOUT_EXT} in the wrong directory?
Did you specify the credentials options incorrectly?
Credentials file must be created first before one can
perform room actions.
Aborting due to missing or not-found credentials file."""
Aborting due to missing or not-found credentials file.""",
traceback=False,
level="error",
)
cleanup()
sys.exit(1)
gs.log.debug("Credentials file does exist.")
try:
client, credentials = login_using_credentials_file(
@ -3705,16 +3728,15 @@ async def main_verify() -> None:
credentials_file = determine_credentials_file()
store_dir = determine_store_dir()
if not os.path.isfile(credentials_file):
gs.log.info(
raise MatrixCommanderError(
f"""Credentials file was not found.
Did you start {PROG_WITHOUT_EXT} in the wrong directory?
Did you specify the credentials options incorrectly?
Credentials file must be created first before one can
verify.
Aborting due to missing or not-found credentials file."""
Credentials file must be created first before one can verify.
Aborting due to missing or not-found credentials file.""",
traceback=False,
level="error",
)
cleanup()
sys.exit(1)
gs.log.debug("Credentials file does exist.")
try:
client, credentials = login_using_credentials_file(
@ -3773,60 +3795,67 @@ async def main_send() -> None:
await client.close()
def are_arg_files_readable() -> bool:
def check_arg_files_readable() -> None:
"""Check if files from command line are readable."""
arg_files = gs.pa.image if gs.pa.image else []
arg_files += gs.pa.audio if gs.pa.audio else []
arg_files += gs.pa.file if gs.pa.file else []
arg_files += gs.pa.event if gs.pa.event else []
r = True
errtxt = (
"These file specified in the command line were not found "
"or are not readable: "
)
for fn in arg_files:
if (fn != "-") and not (isfile(fn) and access(fn, R_OK)):
gs.log.error(
f'File "{fn}" specified in the command line was not found '
"or is not readable."
)
if not r:
errtxt += ", "
errtxt += f'"{fn}"'
r = False
return r
errfile = fn
if not r:
raise FileNotFoundError(errno.ENOENT, errtxt, errfile)
def is_download_media_dir_valid() -> bool:
def check_download_media_dir() -> None:
"""Check if media download directory is correct."""
if not gs.pa.download_media:
return True # "": that means no download of media, valid value
return # "": that means no download of media, valid value
# normailzed for humans
dl = os.path.normpath(gs.pa.download_media)
gs.pa.download_media = dl
if os.path.isfile(dl):
gs.log.error(
raise NotADirectoryError(
errno.ENOTDIR,
f'"{dl}" cannot be used as media directory, because '
f'"{dl}" is a file. Specify a different directory for downloading '
"media."
"media.",
dl,
)
return False
if os.path.isdir(dl):
if os.access(dl, os.W_OK): # Check for write access
return True
return # all OK
else:
gs.log.error(
raise PermissionError(
errno.EPERM,
"Found an existing media download directory "
f'"{dl}". But this directory is lacking write '
"permissions. Add write permissions to it."
"permissions. Add write permissions to it.",
dl,
)
return False
else:
# not a file, not a directory, create directory
mode = 0o777
try:
os.mkdir(dl, mode)
except OSError as exc:
gs.log.error(
except OSError as e:
raise OSError(
e.errno,
"Could not create media download directory "
f"{dl} for you. ({exc})"
f"{dl} for you. ({e})",
dl,
)
return False
gs.log.debug(f'Created media download directory "{dl}" for you.')
return True
def version() -> None:
@ -3844,10 +3873,19 @@ def version() -> None:
gs.log.debug(version_info)
def initial_check_of_log_args() -> str:
"""Check logging related arguments."""
def initial_check_of_log_args() -> None:
"""Check logging related arguments.
Arguments:
---------
None
Returns: None
Raises exception on error.
"""
if not gs.pa.log_level:
return
return # all OK
t = ""
for i in range(len(gs.pa.log_level)):
up = gs.pa.log_level[i].upper()
@ -3859,10 +3897,9 @@ def initial_check_of_log_args() -> str:
f"({up})"
)
if t == "":
return
return # all OK
else:
gs.log.error(t)
sys.exit(1)
raise MatrixCommanderError(t)
# according to pylama: function too complex: C901 # noqa: C901
@ -3990,7 +4027,7 @@ def initial_check_of_args() -> None: # noqa: C901
):
t = (
"If --rename_device is specified, only rename can be done. "
"No messages, images, files or events can be sent."
"No messages, images, files or events can be sent. "
"No listening or tailing allowed. No verification. "
"No actions on rooms."
)
@ -4004,7 +4041,7 @@ def initial_check_of_args() -> None: # noqa: C901
):
t = (
"If --listen is specified, only listening can be done. "
"No messages, images, files or events can be sent."
"No messages, images, files or events can be sent. "
"No room actions allowed."
)
elif (
@ -4081,18 +4118,44 @@ def initial_check_of_args() -> None: # noqa: C901
)
else:
gs.log.debug("All arguments are valid. All checks passed.")
return
gs.log.error(t)
sys.exit(1)
return # all OK
raise MatrixCommanderError(t, traceback=False)
# according to linter: function is too complex, C901
def main(): # noqa: C901 # ignore mccabe if-too-complex
def main(
argv: Union[None, list] = None
) -> None: # noqa: C901 # ignore mccabe if-too-complex
"""Run the program.
main() is an entry point so that other Python programs can
main() is an entry point allowing other Python programs to
easily call matrix-commander.
Arguments:
---------
argv : list of arguments as in sys.argv; first element is the
program name, further elements are the arguments; every
element must be of type "str".
argv is optional and can be None.
If argv is set then these arguments will be used as arguments for
matrix-commander. If argv is not set (None or empty list), then
sys.argv will be used as arguments for matrix-commander.
Example input argv: ["matrix-commander"]
["matrix-commander" "--version"]
["matrix-commander" "--message" "Hello" --image "pic.jpg"]
Returns nothing.
Raises exception if an error is detected. Many exceptions are
possible. One of them is: MatrixCommanderError.
"""
if argv:
sys.argv = argv
# prepare the global state
global gs
gs = GlobalState()
# Construct the argument parser
ap = argparse.ArgumentParser(
description=(
@ -4768,8 +4831,6 @@ def main(): # noqa: C901 # ignore mccabe if-too-complex
"program will continue to run. This is useful for having version "
"number in the log files.",
)
global gs
gs = GlobalState()
gs.pa = ap.parse_args()
logging.basicConfig( # initialize root logger, a must
@ -4812,16 +4873,17 @@ def main(): # noqa: C901 # ignore mccabe if-too-complex
gs.log.warning("Debug option -d overwrote option --log-level.")
initial_check_of_args()
if not is_download_media_dir_valid():
sys.exit(1)
if not are_arg_files_readable():
gs.log.debug(
check_download_media_dir()
try:
check_arg_files_readable()
except Exception as e:
gs.log.error(e)
raise MatrixCommanderError(
f"{PROG_WITHOUT_EXT} forces an early abort. "
"To avoid partial execution, no action has been performed at all. "
"Nothing has been sent. Fix your arguments and run the command "
"again."
)
sys.exit(1)
create_pid_file()
if gs.pa.version:
@ -4838,23 +4900,23 @@ def main(): # noqa: C901 # ignore mccabe if-too-complex
# type SSLContext
gs.ssl = ssl.create_default_context(cafile=gs.pa.ssl_certificate)
except FileNotFoundError:
gs.log.error(
raise MatrixCommanderError(
f'SSL certificate file "{gs.pa.ssl_certificate}" was '
"not found."
"not found.",
traceback=False,
)
sys.exit(1)
except PermissionError:
gs.log.error(
raise MatrixCommanderError(
f'SSL certificate file "{gs.pa.ssl_certificate}" does '
"not have read permissions."
"not have read permissions.",
traceback=False,
)
sys.exit(1)
except ssl.SSLError:
gs.log.error(
raise MatrixCommanderError(
f'SSL certificate file "{gs.pa.ssl_certificate}" has '
"invalid content. Does not seem to be a certificate."
"invalid content. Does not seem to be a certificate.",
traceback=False,
)
sys.exit(1)
elif gs.pa.no_ssl:
gs.log.debug(
"SSL will be not be used. The SSL certificate validation "
@ -4898,27 +4960,47 @@ def main(): # noqa: C901 # ignore mccabe if-too-complex
# the next can be reached on success or failure
gs.log.debug(f"The program {PROG_WITH_EXT} left the event loop.")
except TimeoutError:
gs.log.info(
cleanup()
raise MatrixCommanderError(
f"The program {PROG_WITH_EXT} ran into a timeout. "
"Most likely connectivity to internet was lost. "
"If this happens frequently consider running this "
"program as a service so it will restart automatically. "
"Sorry. Here is the traceback."
"program as a service so it will restart automatically. Sorry.",
True,
)
gs.log.info(traceback.format_exc())
except Exception:
gs.log.error(
f"The program {PROG_WITH_EXT} failed. "
"Sorry. Here is the traceback."
except MatrixCommanderError as e:
cleanup()
raise MatrixCommanderError(
f"{e}", traceback=e.traceback, level=e.level
)
except Exception as e:
cleanup()
raise MatrixCommanderError(
f"The program {PROG_WITH_EXT} failed. Sorry.\n{e}",
traceback=True,
)
gs.log.error(traceback.format_exc())
# traceback.print_exc(file=sys.stdout)
except KeyboardInterrupt:
gs.log.debug("Keyboard interrupt received.")
cleanup()
sys.exit(0)
if __name__ == "__main__":
main()
try:
main()
except MatrixCommanderError as e:
tb = ""
if e.traceback:
tb = f"\nHere is the traceback.\n{traceback.format_exc()}"
if e.level == "info":
gs.log.info(f"{e}{tb}")
else:
gs.log.error(f"{e}{tb}")
sys.exit(1)
except Exception as e:
tb = ""
if gs.pa.debug > 0:
tb = f"\nHere is the traceback.\n{traceback.format_exc()}"
gs.log.error(f"{e}{tb}")
sys.exit(1)
sys.exit(0)
# EOF

@ -3,6 +3,7 @@
#
# # on PC where PyPi package is to be created
# python3 -m pip install --upgrade build # install necessary build packages
# python3 -m pip install --upgrade twine # install necessary build packages
# rm dist/* # cleanup
# nano setup.cfg # increment version number
# python3 -m build # build PyPi package
@ -17,4 +18,7 @@
# prepare-commit, including version increase in setup.cfg
rm dist/* # cleanup
python3 -m build && python3 -m twine upload dist/*
python3 -m build &&
ls -l dist/* &&
echo "Use __token__ as user." &&
python3 -m twine upload dist/*

@ -2,7 +2,7 @@
# https://packaging.python.org/en/latest/tutorials/packaging-projects/
# https://setuptools.pypa.io/en/latest/userguide/
name = matrix-commander
version = 2.16.0
version = 2.17.0
author = 8go
description = A simple command-line Matrix client
long_description = file: PyPi-Instructions.md, README.md
@ -26,6 +26,7 @@ classifiers =
# use root, i.e. leave empty
package_dir =
packages = find:
include_package_data = True
python_requires = >=3.8
install_requires =
aiohttp
@ -42,6 +43,11 @@ install_requires =
uuid
[options.package_data]
# add docu if there is any inside the module(s)
* = *.md, *.rst
[options.entry_points]
console_scripts =
# desired-command-name = module:function

@ -38,7 +38,7 @@ matrix-commander --event event1.json event2.json -m "" $MC_OPTIONS
# also test the stdin pipe logic
cat event3.json | matrix-commander --event - $MC_OPTIONS
echo -e "\n\n\nThe next 4 test cases should ***FAIL*** due to " \
echo -e "\n\n\nThe next 4 test cases should ***FAIL*** due to" \
"***INCORRECT*** JSON objects.\n\n\n"
# This is how NOT to do events and event templates.
BAD_MSC2676_EDIT='{ "type": "m.room.message", "fail-content": { "body": "%s", "msgtype": "m.text", "m.new_content": { "body": "%s", "msgtype": "m.text" }, "m.relates_to": { "rel_type": "m.replace", "event_id": "%s" } } }'

@ -10,30 +10,41 @@ can be called from a Python program.
# isort: skip_file
# isort: off
from os.path import isfile
from os import R_OK, access
from datetime import datetime
import subprocess
import shutil
import re
import sys
# importing matrix_commander module
try:
# if installed via pip
import matrix_commander # nopep8 # isort: skip
from matrix_commander import main # nopep8 # isort: skip
from matrix_commander import (
main,
MatrixCommanderError,
) # nopep8 # isort: skip
except:
# not installed via pip. installed via 'git clone' or file download
# if not installed via pip. if installed via 'git clone' or file download
# appending a local path to sys.path
sys.path.append("matrix_commander")
sys.path.append("../matrix_commander")
import matrix_commander # nopep8 # isort: skip
from matrix_commander import main # nopep8 # isort: skip
from matrix_commander import (
main,
MatrixCommanderError,
) # nopep8 # isort: skip
now = datetime.now().strftime("%Y%m%d-%H%M%S")
# set up some test arguments
print(f"Running test program: {sys.argv[0]}")
print(f"Arguments that are passed on to matrix-commander are: {sys.argv[1:]}")
sys.argv[0] = "matrix-commander"
sys.argv.extend(["--version"])
sys.argv.extend(["--message", "Hello World!"])
sys.argv.extend(["--message", f"Hello World @ {now}!"])
sys.argv.extend(["--image", "tests/test.s.png"])
print(f"Testing with these arguments: {sys.argv}")
matrix_commander.main()
try:
matrix_commander.main()
except MatrixCommanderError as e:
print(e)
except Exception as e:
print(e)

Loading…
Cancel
Save