commit python-fritzconnection for openSUSE:Factory
Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-fritzconnection for openSUSE:Factory checked in at 2024-10-30 17:36:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-fritzconnection (Old) and /work/SRC/openSUSE:Factory/.python-fritzconnection.new.2020 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "python-fritzconnection" Wed Oct 30 17:36:28 2024 rev:10 rq:1219189 version:1.14.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-fritzconnection/python-fritzconnection.changes 2024-01-15 22:19:10.382720603 +0100 +++ /work/SRC/openSUSE:Factory/.python-fritzconnection.new.2020/python-fritzconnection.changes 2024-10-30 17:37:21.279591961 +0100 @@ -1,0 +2,7 @@ +Tue Oct 29 21:19:51 UTC 2024 - Dirk Müller <dmueller@suse.com> + +- update to 1.14.0: + * support added for Python 3.13 + * New FritzTopology module: represents the mesh-topology graph. + +------------------------------------------------------------------- Old: ---- fritzconnection-1.13.2.tar.gz New: ---- fritzconnection-1.14.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-fritzconnection.spec ++++++ --- /var/tmp/diff_new_pack.SyxZjU/_old 2024-10-30 17:37:22.823656642 +0100 +++ /var/tmp/diff_new_pack.SyxZjU/_new 2024-10-30 17:37:22.823656642 +0100 @@ -18,7 +18,7 @@ %global pythons python3 Name: python-fritzconnection -Version: 1.13.2 +Version: 1.14.0 Release: 0 Summary: A Python module to talk to a AVM fritzbox License: MIT ++++++ fritzconnection-1.13.2.tar.gz -> fritzconnection-1.14.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/.gitignore new/fritzconnection-1.14.0/.gitignore --- old/fritzconnection-1.13.2/.gitignore 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/.gitignore 2024-08-12 17:58:36.000000000 +0200 @@ -16,6 +16,7 @@ bin build/* dist/* +docs/requirements.txt fritzconnection.egg-info/* include lib_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/CONTRIBUTING.md new/fritzconnection-1.14.0/CONTRIBUTING.md --- old/fritzconnection-1.13.2/CONTRIBUTING.md 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/CONTRIBUTING.md 2024-08-12 17:58:36.000000000 +0200 @@ -1,21 +1,21 @@ # Contributing -Thank you for taking your time to contribute to this project. +Thank you for taking time to contribute to this project. The project is not large enough to need a lot of rules, but here are some guidelines: ## Issues -In case you think that something is not working as expected or you have a new idea, feel free to create an issue. Especially if you want to provide a pull-request, it is a good idea to create an issue first. Please also keep in mind that issues are not for support. For support try 'discussions' (but please keep in mind that this is not a commercial product, so you may get support or not). +In case you think that something is not working as expected or you have a new idea, feel free to create an issue. Especially if you want to provide a pull-request, it is a good idea to create an issue first. Please also keep in mind that issues are not for support. For support try 'discussions' (please keep in mind that this is not a commercial product, so you may get support or not). ## Pull requests -In general pull requests are welcome. But please create an issue first before putting too much work into a pull request that may not get merged at the end, for whatever reason. An issue can help to clarify points of view and motivation. +In general pull requests are welcome. Please create an issue first before putting too much work into a pull request that may not get merged at the end, for whatever reason. An issue can help to clarify points of view and motivation. For pull requests there is a golden rule: **keep them small**. Smaller pull requests are easier to review and easier to merge – especially in cases when not every part of a larger changeset should get merged and has to get modifications. -Please avoid to just change the formatting. The result is most often nothing else than git-diff pollution. This is especially true for `black` – this project startet before `black` (or `blue`). It is ok to use `black` for modified code snippets, but not for a module. +Please avoid to just change the formatting. The result is most often nothing else than git-diff pollution. This is especially true for `black` (or `blue` or the corresponding modes in `ruff`) – this project startet before `black`. It is ok to use these tools for modified code snippets, but not for a module. ## Status of core and lib @@ -32,7 +32,7 @@ - In general the style guide is PEP 8. - Recommended maximum line length is 80 something. - Use proper names: i.e. an atrribute for `attributes` or `properties`, a verb for `callables`. -- Try to avoid `black` (see "Pull requests"). +- Avoid `black` (see "Pull requests"). ## Comments @@ -44,11 +44,23 @@ This project started long ago without type hints. Keep it that way. The project is small enough, so there is no real benefit. Also some parts of the code are really dynamic (one strength of Python), where type-hints can lead to a nightmare. The place for types in this project are in the comments. Readability counts! -Update: since version 1.13.0 type hints are introduced for the public API (and only there). Type-hints must be backward compatible for the oldest supported python-version. For type-checking `mypy` is used. +Update: since version `1.13.0` type hints are introduced for the public API (and only there). Type-hints must be backward compatible for the oldest supported python-version. For type-checking `mypy` is used. ## Tests -This project comes with tests. The test framework is tox/pytest. For development run `pip install -r requirements_test.txt` to install both libraries. As far as possible, the code should get tests. Before committing run the tests with tox. +This project comes with tests. Since version `1.13.0` `nox` is used for testautomation (`https://nox.thea.codes/en/stable/index.html`). `nox` should get installed separately. In the same environment where `nox` has been installed also `ruff` must be installed because the `noxfile` makes use of `ruff` as external module for linting. -Update: since version 1.13.0 `nox` has been introduced for testing. For `nox` there is no need for the `requirements_test.txt` file. +After installation the sessions from the `noxfile.py` can be used like: + +- `nox -s test`: run the tests with all supported python versions. The supported versions must be installed on the local development system and must be callable like `python3.11` or `python3.12`. Currently python `3.7` and newer are supported (no new language features are used, so backward compatibility is cheap). You can run `nox -s test-3.11` to run the tests with a single python version. This can be handy for development running the test for all versions later on. + +- `nox -s test_router`: run all tests making a connection to the router. These tests are taking much more time and can fail because of connection errors. In case of a connection error run the tests again - chances are good the error was temporarly and gone and there are no real bugs. In all other cases: fix it. A test run with a defined python version (here `3.11`) can get started with `nox -s test_router-3.11`. + +- `nox -s test_all`: run all tests including the time consuming router-tests. + +- `nox -s check`: run `ruff` to `lint` the code. + +- `nox -s mypy`: apply a mypy check. + +- `nox -s sphinx`: make a local build of the documentation. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/README.md new/fritzconnection-1.14.0/README.md --- old/fritzconnection-1.13.2/README.md 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/README.md 2024-08-12 17:58:36.000000000 +0200 @@ -53,7 +53,7 @@ ### Caching -On instanciation FritzConnection has to inspect the model-specific router-API. This causes a lot of network requests and can take some seconds. To avoid this FritzConnection provides a cache that can get activated by the `use_cache` parameter: +On instantiation FritzConnection has to inspect the model-specific router-API. This causes a lot of network requests and can take some seconds. To avoid this FritzConnection provides a cache that can get activated by the `use_cache` parameter: ``` fc = FritzConnection(..., use_cache=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/docs/requirements.local.in new/fritzconnection-1.14.0/docs/requirements.local.in --- old/fritzconnection-1.13.2/docs/requirements.local.in 1970-01-01 01:00:00.000000000 +0100 +++ new/fritzconnection-1.14.0/docs/requirements.local.in 2024-08-12 17:58:36.000000000 +0200 @@ -0,0 +1,3 @@ +Sphinx==5.1.1 +sphinx-rtd-theme==1.2.2 +furo==2023.3.27 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/docs/requirements.txt new/fritzconnection-1.14.0/docs/requirements.txt --- old/fritzconnection-1.13.2/docs/requirements.txt 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/docs/requirements.txt 2024-08-12 17:58:36.000000000 +0200 @@ -1,78 +1,69 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.12 # by the following command: # -# pip-compile --strip-extras docs/requirements.in +# pip-compile --output-file=docs/requirements.txt --strip-extras docs/requirements.local.in # -alabaster==0.7.13 +alabaster==0.7.16 # via sphinx -babel==2.12.1 +babel==2.16.0 # via sphinx -beautifulsoup4==4.12.2 +beautifulsoup4==4.12.3 # via furo -certifi==2023.7.22 +certifi==2024.7.4 # via requests -charset-normalizer==3.2.0 +charset-normalizer==3.3.2 # via requests docutils==0.18.1 # via # sphinx # sphinx-rtd-theme -fritzconnection==1.13.1 - # via -r docs/requirements.in furo==2023.3.27 - # via -r docs/requirements.in -idna==3.4 + # via -r docs/requirements.local.in +idna==3.7 # via requests imagesize==1.4.1 # via sphinx -jinja2==3.1.2 +jinja2==3.1.4 # via sphinx -markupsafe==2.1.3 +markupsafe==2.1.5 # via jinja2 -packaging==23.1 +packaging==24.1 # via sphinx -pygments==2.16.1 +pygments==2.18.0 # via # furo # sphinx -requests==2.31.0 - # via - # fritzconnection - # sphinx +requests==2.32.3 + # via sphinx snowballstemmer==2.2.0 # via sphinx -soupsieve==2.4.1 +soupsieve==2.5 # via beautifulsoup4 sphinx==5.1.1 # via - # -r docs/requirements.in + # -r docs/requirements.local.in # furo # sphinx-basic-ng # sphinx-rtd-theme - # sphinxcontrib-applehelp - # sphinxcontrib-devhelp - # sphinxcontrib-htmlhelp # sphinxcontrib-jquery - # sphinxcontrib-qthelp - # sphinxcontrib-serializinghtml sphinx-basic-ng==1.0.0b2 # via furo sphinx-rtd-theme==1.2.2 - # via -r docs/requirements.in -sphinxcontrib-applehelp==1.0.7 + # via -r docs/requirements.local.in +sphinxcontrib-applehelp==2.0.0 # via sphinx -sphinxcontrib-devhelp==1.0.5 +sphinxcontrib-devhelp==2.0.0 # via sphinx -sphinxcontrib-htmlhelp==2.0.4 +sphinxcontrib-htmlhelp==2.1.0 # via sphinx sphinxcontrib-jquery==4.1 # via sphinx-rtd-theme sphinxcontrib-jsmath==1.0.1 # via sphinx -sphinxcontrib-qthelp==1.0.6 +sphinxcontrib-qthelp==2.0.0 # via sphinx -sphinxcontrib-serializinghtml==1.1.8 +sphinxcontrib-serializinghtml==2.0.0 # via sphinx -urllib3==2.0.4 +urllib3==2.2.2 # via requests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/docs/sources/getting_started.rst new/fritzconnection-1.14.0/docs/sources/getting_started.rst --- old/fritzconnection-1.13.2/docs/sources/getting_started.rst 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/docs/sources/getting_started.rst 2024-08-12 17:58:36.000000000 +0200 @@ -60,7 +60,7 @@ -e [ENCRYPT], --encrypt [ENCRYPT] Flag: use secure connection (TLS) -x, --use-cache Flag: use api cache - (speed-up subsequent instanciations) + (speed-up subsequent instantiations) -y, --suppress-cache-verification Flag: suppress cache verification, implies -x --cache-format [CACHE_FORMAT] @@ -215,9 +215,9 @@ At first an instance of `FritzConnection` must be created. There can be a short delay doing this, because fritzconnection has to do a lot of communication with the router to get the router-specific API. .. note :: - A FritzConnection instance can be **reused** for all further `call_action()` calls (and also `call_http()` calls) **without side-effects**. For a single device (i.e. the router) an application needs just one instance. Because instanciation can be expensive (time consuming), having a single instance can save memory and speed up things. + A FritzConnection instance can be **reused** for all further `call_action()` calls (and also `call_http()` calls) **without side-effects**. For a single device (i.e. the router) an application needs just one instance. Because instantiation can be expensive (time consuming), having a single instance can save memory and speed up things. - Update: with the introduction of the `api-cache` in version `1.10` instanciation is much more faster than before. However, reusing an instance is still a good idea. + Update: with the introduction of the `api-cache` in version `1.10` instantiation is much more faster than before. However, reusing an instance is still a good idea. The method `call_action` takes two required arguments: the service- and the action-name as strings. In case that a service is unknown (because of a typo or incompatible router model) fritzconnection will raise a `FritzServiceError`. If the service is known, but not the action, then a `FritzActionError` gets raised. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/docs/sources/library_modules.rst new/fritzconnection-1.14.0/docs/sources/library_modules.rst --- old/fritzconnection-1.13.2/docs/sources/library_modules.rst 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/docs/sources/library_modules.rst 2024-08-12 17:58:36.000000000 +0200 @@ -287,6 +287,36 @@ :members: +FritzTopology +------------- + +Module to access the current Network-Topology information. This can be a cyclic graph with the devices as nodes. The devices do have interfaces and the interfaces provide links to other the interfaces of other devices. Links do have attributes like the current throughput. + +The following example prints an overview of a topology: :: + + from fritzconnection import FritzConnection + from fritzconnection.lib.fritztopology import FritzMeshTopology + + # assume user and password are read from the environment: + fc = FritzConnection(address="192.168.178.1") + + # create a topology-instance + fm = FritzMeshTopology(fc=fc) + + # read the topology data (can take some time) + fm.load_topology() + + # print the instance: + print(fm) + + +FritzTopology API +................. + +.. automodule:: fritzconnection.lib.fritztopology + :members: + + FritzWLAN --------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/docs/sources/version_history.rst new/fritzconnection-1.14.0/docs/sources/version_history.rst --- old/fritzconnection-1.13.2/docs/sources/version_history.rst 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/docs/sources/version_history.rst 2024-08-12 17:58:36.000000000 +0200 @@ -4,6 +4,28 @@ =============== +1.14.0 - 2024-08-12 +------------------- + +- support added for Python 3.13 +- New FritzTopology module: represents the mesh-topology graph. +- FritzWLAN: + + - internal function `_get_beacon_security()` removed and substituted with a mapping. (#224) + - added ability to output QR code as string stream with ANSI or unicode. (#223) + - new property `is_hidden` for wlan ssid. Internal use of this property to handle hidden SSID in QR codes. Parameter `hidden` removed from `FritzWLAN.get_wifi_qr_code()`. (#221) + - bugfix: fixed potential password leak in QR code for an unencrypted connection. (#225, #226) + +- FritzHomeAutomation: + + - bugfix: converting data from actors which are reporting missing data as non integer values. Missing data are now represented by `None`. (#215) + +- bugfix: some devices may not return system-information the propper way, causing errors on the cli output. In these cases the system-information will get ignored. (#214) +- documentation: some typos corrected. (#202, #204) +- testing: `tox.ini` removed because of change to `nox`. Change from `pylint` to `ruff` for linting. +- deprecation: use of the `json` cache-format is discouraged. Use the default pickle-format instead. The highly dynamic TR-064 parser may get an ouverhaul in the future and to reduce the complexity of the parser the support of `json` for caching will be removed. + + 1.13.2 - 2023-09-17 ------------------- @@ -117,7 +139,7 @@ - FritzConnection: - - API cache integration added: for faster start up times the router API can optional get saved in a cache-file. This can save up to several seconds run-time on instanciation. + - API cache integration added: for faster start up times the router API can optional get saved in a cache-file. This can save up to several seconds run-time on instantiation. - FritzHosts: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/__init__.py new/fritzconnection-1.14.0/fritzconnection/__init__.py --- old/fritzconnection-1.13.2/fritzconnection/__init__.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/__init__.py 2024-08-12 17:58:36.000000000 +0200 @@ -10,7 +10,10 @@ https://fritzconnection.readthedocs.io/ """ -__version__ = "1.13.2" +# unused shortcut import are intended: +# ruff: noqa: F401 + +__version__ = "1.14.0" # import shortcuts from .core.fritzconnection import FritzConnection diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/cli/fritzinspection.py new/fritzconnection-1.14.0/fritzconnection/cli/fritzinspection.py --- old/fritzconnection-1.13.2/fritzconnection/cli/fritzinspection.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/cli/fritzinspection.py 2024-08-12 17:58:36.000000000 +0200 @@ -87,11 +87,13 @@ """ print() system_info = self.fc.device_manager.system_info - print( - f"system : {system_info[-1]}\n" - f"build : {system_info[-2]}\n" - f"hw-code: {system_info[0]}" - ) + # some devices may return None as system_info + if system_info: + print( + f"system : {system_info[-1]}\n" + f"build : {system_info[-2]}\n" + f"hw-code: {system_info[0]}" + ) now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") print(f"Report date: {now}") for service_name, service in self.fc.services.items(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/cli/utils.py new/fritzconnection-1.14.0/fritzconnection/cli/utils.py --- old/fritzconnection-1.13.2/fritzconnection/cli/utils.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/cli/utils.py 2024-08-12 17:58:36.000000000 +0200 @@ -35,13 +35,13 @@ def print_common_exception_message(error_object): - print(error_object) - print( - "\nSeems you forgot to provide the user and/or the password." - "\nYou can provide these with the flag -u and -p or store them" - "\nin the environment as FRITZ_USERNAME and FRITZ_PASSWORD." - "\n(Environment changes will get recognized by new processes.)\n" - ) + print(error_object) + print( + "\nSeems you forgot to provide the user and/or the password." + "\nYou can provide these with the flag -u and -p or store them" + "\nin the environment as FRITZ_USERNAME and FRITZ_PASSWORD." + "\n(Environment changes will get recognized by new processes.)\n" + ) def get_instance(cls, args): @@ -86,7 +86,7 @@ action="store_true", dest='use_cache', help='Flag: use api cache (e[x]cellerate: speed-up subsequent ' - 'instanciations)' + 'instantiations)' ) parser.add_argument('-y', '--suppress-cache-verification', action='store_false', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/core/fritzconnection.py new/fritzconnection-1.14.0/fritzconnection/core/fritzconnection.py --- old/fritzconnection-1.13.2/fritzconnection/core/fritzconnection.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/core/fritzconnection.py 2024-08-12 17:58:36.000000000 +0200 @@ -152,7 +152,7 @@ .. versionadded:: 1.6 The flag `use_cache` activates caching (default `False`). Caching - can speed up instanciation significantly. The cached data are + can speed up instantiation significantly. The cached data are specific for the router ip, the router model and the installed FritzOS version. Multiple devices in the network can have separate cache-fies and can get used in parallel. By default the cache files @@ -219,7 +219,7 @@ `use_cache` is a boolean whether a cache should get used for the router api data. By default the api data are loaded from the - router at instanciation time what can take several seconds to + router at instantiation time what can take several seconds to complete. `cache_directory` is the path to the directory storing the cached data. By default this is a folder named '.fritzconnection' in the users home-directory. `cache_format` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/core/fritzhttp.py new/fritzconnection-1.14.0/fritzconnection/core/fritzhttp.py --- old/fritzconnection-1.13.2/fritzconnection/core/fritzhttp.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/core/fritzhttp.py 2024-08-12 17:58:36.000000000 +0200 @@ -1,7 +1,7 @@ """ fritzhttp.py -Access the AVM Fritz!Box AHA-HTTP-Inferface +Access the AVM Fritz!Box AHA-HTTP-Interface """ # This module is part of the FritzConnection package. # https://github.com/kbr/fritzconnection diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/lib/fritzhomeauto.py new/fritzconnection-1.14.0/fritzconnection/lib/fritzhomeauto.py --- old/fritzconnection-1.13.2/fritzconnection/lib/fritzhomeauto.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/lib/fritzhomeauto.py 2024-08-12 17:58:36.000000000 +0200 @@ -395,7 +395,16 @@ if key == "datatime": value = datetime.datetime.fromtimestamp(value) # type: ignore content[key] = value - content["data"] = list(map(int, stats.text.split(","))) # type: ignore + # convert the csv-list of returned values from text to int. + # on missing data dashes (-) may get returned. + # this get catched and missing data are represented as `None`. + content["data"] = [] + for item in stats.text.split(","): # type: ignore + try: + value = int(item) # type: ignore + except ValueError: + value = None # type: ignore + content["data"].append(value) elements[element.tag] = content return elements diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/lib/fritzhosts.py new/fritzconnection-1.14.0/fritzconnection/lib/fritzhosts.py --- old/fritzconnection-1.13.2/fritzconnection/lib/fritzhosts.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/lib/fritzhosts.py 2024-08-12 17:58:36.000000000 +0200 @@ -130,7 +130,7 @@ ) return result - def get_mesh_topology(self, raw=False) -> dict: + def get_mesh_topology(self, raw=False) -> dict | str: """ Returns information about the mesh network topology. If `raw` is `False` the topology gets returned as a dictionary with a list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/lib/fritztopology.py new/fritzconnection-1.14.0/fritzconnection/lib/fritztopology.py --- old/fritzconnection-1.13.2/fritzconnection/lib/fritztopology.py 1970-01-01 01:00:00.000000000 +0100 +++ new/fritzconnection-1.14.0/fritzconnection/lib/fritztopology.py 2024-08-12 17:58:36.000000000 +0200 @@ -0,0 +1,299 @@ +""" +Module to access to the Mesh Topology +See https://avm.de/service/schnittstellen/ "Mesh-Topologie" +""" +# This module is part of the FritzConnection package. +# https://github.com/kbr/fritzconnection +# License: MIT (https://opensource.org/licenses/MIT) +# Authors: Klaus Bremer + +# code partly to dynamic for a useful mypy run: +# mypy: disable-error-code="attr-defined" + +from __future__ import annotations + +from .fritzhosts import FritzHosts +from .fritzbase import AbstractLibraryBase + + +class Connection: + """ + Represents a connection from one device to another device. + This is basically a convenience wrapper for InterfaceLink + exposing the devices and some instance attributes in a more + comfortable way. + + self.source is the origin device + self.target is the connected device + self.type is the connection type (like "WLAN") + self.state is the connection state (like "DISCONNECTED", "CONNECTED") + + self.max_rx, max_tx, cur_rx and cur_tx are the maximum and + current throughput data rates in kbit/sec. + + tx is the upload-throughput from source to target, even if the + source is represented by the interface-link node 2. + """ + + def __init__(self, source, target, interface_link): + self.source = source + self.target = target + self.interface_link = interface_link + + @property + def type(self) -> str | None: + return self._get_interface_attribute("type") + + @property + def state(self) -> str | None: + return self._get_interface_attribute("state") + + @property + def max_rx(self) -> int | None: + return self._get_transfer_rate("max_data_rate_rx") + + @property + def max_tx(self) -> int | None: + return self._get_transfer_rate("max_data_rate_tx") + + @property + def cur_rx(self) -> int | None: + return self._get_transfer_rate("cur_data_rate_rx") + + @property + def cur_tx(self) -> int | None: + return self._get_transfer_rate("cur_data_rate_tx") + + def _get_transfer_rate(self, name): + """ + Adapt the rate to the link direction: 'tx' is the transfer rate + from node 1 to node 2 which is ok, if node 1 represents the + 'source' node. In case it is the other way around the commands + 'tx' and 'rx' must get exchanged. + """ + if self.interface_link.source_index == 2: + name, direction = name.rsplit("_", 1) + direction = "rx" if direction == "tx" else "tx" + name = f"{name}_{direction}" + return self._get_interface_attribute(name) + + def _get_interface_attribute(self, name, default=None): + return getattr(self.interface_link, name, default) + + +class InterfaceLink: + """ + Represents a node-link from an Interface of a device + to another Interface of another device. + (These are the vertexes of the mesh.) + + Instance attributes are all elements described as "node_links.properties" + in the AVM documentation and accessible by their names, i.e. like + 'self.last_connected' in case the UNIX timestamp is requested. + """ + + def __init__(self, data: dict, interface: Interface): + self.__dict__.update(data) + self.interface = interface + # The starting point is assumed to be the device, which is + # the owner of self.interface. + if self.node_interface_1_uid == self.interface.uid: + self.source_index = 1 + self.target_index = 2 + else: + self.source_index = 2 + self.target_index = 1 + + def __repr__(self) -> str: + return f"InterfaceLink: {self.uid:<8}target-interface: {self.node_interface_2_uid}" + + def __str__(self) -> str: + connection = Connection(self.source, self.target, self) + if connection.cur_tx is not None: + throughput = connection.cur_tx // 1000 # from kB/s to MB/s + else: + throughput = None # not known + return f"from {self.source.name} to {self.target.name} (-> {throughput} MBit/s)" + + @property + def source(self) -> Device: + return self._get_connected_device(target=False) + + @property + def target(self) -> Device: + return self._get_connected_device(target=True) + + def get_connection(self) -> Connection: + """ + Returns a connection instance describing a connection + from one device to another device. + """ + return Connection(self.source, self.target, self) + + def _get_connected_device(self, target=True): + """ + Returns the device connected by this link, + either the target or source device. + """ + index = self.target_index if target else self.source_index + device_id = getattr(self, f"node_{index}_uid") + return self.interface.device.mesh.get_device_by_id(device_id) + + +class Interface: + """ + An interface represents a physical infrastructure of a device + to connect with other devices. + An interface is part of a device and able to connect to another + interface of another device. + A connection is represented by the InterfaceLink class. + """ + + def __init__(self, data: dict, device: Device): + self.__dict__.update(data) + self.interface_links = [ + InterfaceLink(link, self) for link in self.node_links + ] + self.device = device + + def __repr__(self) -> str: + representation = ( + f"Interface: mac={self.mac:<20}" + f"uid={self.uid:<8}" + f"type={self.type:<8}" + ) + if self.name: + representation = f"{representation}name={self.name}" + return representation + + def __str__(self) -> str: + interface = repr(self) + if self.interface_links: + space = " " * 8 + links = f"\n{space}".join(str(link) for link in self.interface_links) + interface = f"{interface}\n{space}{links}" + return interface + + @property + def mac(self) -> str: + """mac address of the interface""" + return self.mac_address + + def get_connections(self): + """ + Returns a list of Connection objects describing all devices + connected by this interface. + """ + return [link.get_connection() for link in self.interface_links] + + +class Device: + """ + A Device represents a physical item in the mesh, like a router, + repeater, a laptop, a cell phone and other devices. + (This is a node of the mesh.) + + Instance attributes created dynamical according to the + AVM mesh topology schema: https://avm.de/service/schnittstellen/ + + For convenience there are some properties and methods to access + the data in a more mnemonic way. + """ + + def __init__(self, data: dict, mesh: FritzMeshTopology): + self.__dict__.update(data) + self.interfaces = [ + Interface(interface_data, self) + for interface_data in self.node_interfaces + ] + self.mesh = mesh + + def __repr__(self) -> str: + return f"Device: mac={self.mac:<20}uid={self.uid:<8}{self.name}" + + def __str__(self) -> str: + representation = repr(self) + space = " " * 4 + interfaces = f"\n{space}".join(str(interface) for interface in self.interfaces) + return f"{representation}\n{space}{interfaces}" + + @property + def name(self) -> str: + return self.device_name + + @property + def model(self) -> str: + return self.device_model + + @property + def vendor(self) -> str: + return self.device_manufacturer + + @property + def mac(self) -> str: + return self.device_mac_address + + def get_connections(self): + """ + Returns a list of Connection objects describing all + devices connected to this device. + """ + connections = [] + for interface in self.interfaces: + connections.extend(interface.get_connections()) + return connections + + +class FritzMeshTopology(AbstractLibraryBase): + """ + Represents the mesh topology with nodes representing the devices. + + """ + + def __init__(self, fc=None, *args, **kwargs): + super().__init__(fc, *args, **kwargs) + self._fritzhosts = FritzHosts(self.fc) + self.topology = {} + self.nodes = {} + + def __repr__(self) -> str: + return ( + f"{self.__class__.__name__}: " + f"schema_version={self.schema_version}, " + f"registered Devices: {self.number_of_devices}" + ) + + def __str__(self) -> str: + nodes = "\n\n".join(str(device) for device in self.devices) + return f"{repr(self)}\n{nodes}" + + @property + def schema_version(self) -> str: + return self.topology.get("schema_version", "unknown") + + @property + def number_of_devices(self) -> int: + return len(self.nodes) + + @property + def devices(self) -> list[Device]: + return list(self.nodes.values()) + + def get_device_by_id(self, uid: str) -> Device: + """ + Returns a device by id. The id is the node-uid like "n-1". + The node-uids are fixed to devices after calling + `load_topology()` but may change if `load_topology()` gets + called again. + """ + return self.nodes[uid] + + def load_topology(self): + """ + Load the topology from the router. + """ + self.topology = self._fritzhosts.get_mesh_topology(raw=False) + self.nodes = { + node["uid"]: Device(node, self) + for node in self.topology.get("nodes", ()) + } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/lib/fritzwlan.py new/fritzconnection-1.14.0/fritzconnection/lib/fritzwlan.py --- old/fritzconnection-1.13.2/fritzconnection/lib/fritzwlan.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/lib/fritzwlan.py 2024-08-12 17:58:36.000000000 +0200 @@ -28,52 +28,28 @@ # important: don't set an extension number here: SERVICE = 'WLANConfiguration' DEFAULT_PASSWORD_LENGTH = 12 -WPA_SECURITY = 'WPA' -NO_PASS = 'nopass' +_QR_SECURITY_WPA = 'WPA' +_QR_SECURITY_WEP = 'WEP' +_QR_SECURITY_NO_PASS = 'nopass' +_BEACONTYPE_TO_QR_SECURITY = { + 'WPA': _QR_SECURITY_WPA, + '11i': _QR_SECURITY_WPA, + 'WPAand11i': _QR_SECURITY_WPA, + 'WPA3': _QR_SECURITY_WPA, + '11iandWPA3': _QR_SECURITY_WPA, + 'Basic': _QR_SECURITY_WEP, + 'OWE': _QR_SECURITY_NO_PASS, + 'OWETrans': _QR_SECURITY_NO_PASS, + 'None': _QR_SECURITY_NO_PASS, +} -POSSIBLE_BEACON_TYPES_KEY = "NewX_AVM-DE_PossibleBeaconTypes" - -def _get_beacon_security(instance, security): - """ - Returns the beacon-security as a string based on the security - argument. Possible return values are 'nopass' and 'WPA'. If the - security is None or an empty string, the function tries to find the - proper security setting ('nopass'|'WPA'). If security is neither - None nor an empty string, the value is returned as is. - - This function is not intended to get called directly. - - .. versionadded:: 1.10 - """ - if not security: - security = NO_PASS - info = instance.get_info() - beacontype = info["NewBeaconType"] - # check for the POSSIBLE_BEACON_TYPES_KEY argument - # as older models may not provide it: - if POSSIBLE_BEACON_TYPES_KEY in info: - beacontypes = set(info[POSSIBLE_BEACON_TYPES_KEY].split(",")) - beacontypes -= set(('None', 'OWETrans')) - if beacontype in beacontypes: - security = WPA_SECURITY - else: - # dealing with an older model - # assuming at least providing WPA security - # (unable to test for WEP because of missing hardware) - if beacontype != "None": - security = WPA_SECURITY - return security - - -def _get_wifi_qr_code(instance, kind='svg', - security=None, hidden=False, - scale=4): +def _get_wifi_qr_code(instance, kind='svg', security=None, scale=4, border=0): """ Returns a file-like object providing a bytestring representing a qr-code for wlan access. `instance` is a FritzWLAN or FritzGuestWLAN instance. `kind` describes the type of the qr-code. Supported types - are: 'svg', 'png' and 'pdf'. Default is 'svg'. + are: 'svg', 'png', 'pdf', 'text' and 'text-compact'. Default is 'svg'. This function is not intended to get called directly. Instead it is available as a method on FritzWLAN instances (as well as on @@ -93,6 +69,11 @@ with open('qr_code.png', 'wb') as fobj: fobj.write(stream.read()) + The stream can be printed out if qr-code is represented as text: :: + + stream = guest_wlan.get_wifi_qr_code(kind='text') + print(stream.getvalue()) + If `segno` is not installed the call will trigger an AttributeError when called on an instance and a NameError when called directly. @@ -115,15 +96,24 @@ .. versionadded:: 1.10 """ - stream = io.BytesIO() - security = _get_beacon_security(instance, security) + if not security: + # if beacon type is something unknown, assume a "no pass" connection: + security = _BEACONTYPE_TO_QR_SECURITY.get(instance.beacontype, + _QR_SECURITY_NO_PASS) + password = instance.get_password() if security != _QR_SECURITY_NO_PASS else None qr_code = segno.helpers.make_wifi( ssid=instance.ssid, - password=instance.get_password(), + password=password, security=security, - hidden=hidden + hidden=instance.is_hidden ) - qr_code.save(out=stream, kind=kind, scale=scale) + if kind in ['text', 'text-compact']: + stream = io.StringIO() + compact = kind != 'text' + qr_code.terminal(out=stream, border=border, compact=compact) + else: + stream = io.BytesIO() + qr_code.save(out=stream, kind=kind, scale=scale, border=border) stream.seek(0) return stream @@ -204,6 +194,11 @@ return self.get_info()['NewBeaconType'] @property + def is_hidden(self) -> bool: + """Returns True if the SSID hidden (not advertised through beacons).""" + return not self._action('GetBeaconAdvertisement')['NewBeaconAdvertisementEnabled'] + + @property def channel(self) -> int: """The WLAN channel in use""" return self.channel_info()['NewChannel'] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_devices.py new/fritzconnection-1.14.0/fritzconnection/tests/test_devices.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_devices.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_devices.py 2024-08-12 17:58:36.000000000 +0200 @@ -1,10 +1,7 @@ import json import os -from io import StringIO -from pathlib import Path import pytest -from xml.etree import ElementTree as etree from ..core.devices import DeviceManager diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzconnection.py new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzconnection.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzconnection.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzconnection.py 2024-08-12 17:58:36.000000000 +0200 @@ -76,7 +76,7 @@ def test_invalide_cache_format(): mock = SimpleNamespace(address='192.168.178.1', port=49000) with pytest.raises(FritzConnectionException): - result = FritzConnection._get_cache_path(mock, None, 'weird') + _ = FritzConnection._get_cache_path(mock, None, 'weird') @pytest.mark.parametrize( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzhomeauto.py new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzhomeauto.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzhomeauto.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzhomeauto.py 2024-08-12 17:58:36.000000000 +0200 @@ -1,8 +1,4 @@ -import json -import pathlib -import pytest - from ..lib.fritzhomeauto import HomeAutomationDevice diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzmonitor.py new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzmonitor.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzmonitor.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzmonitor.py 2024-08-12 17:58:36.000000000 +0200 @@ -307,7 +307,7 @@ mock_socket = MockReconnectFailSocket(timeouts=timeouts) fm = FritzMonitor() fm.mock_socket = mock_socket - socket = fm._get_connected_socket() # make initional connection + _ = fm._get_connected_socket() # make initional connection result = fm._reconnect_socket( max_reconnect_delay=0.001, reconnect_tries=tries ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzwlan.py new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzwlan.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_fritzwlan.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_fritzwlan.py 2024-08-12 17:58:36.000000000 +0200 @@ -16,7 +16,6 @@ else: OPENCV_NOT_AVAILABLE = False -from fritzconnection.lib.fritzwlan import _get_beacon_security as get_beacon_security from fritzconnection.lib.fritzwlan import _get_wifi_qr_code as get_wifi_qr_code @@ -121,31 +120,6 @@ return self.mock_data["NewSSID"] -@pytest.mark.parametrize( - "current_beacontype, security, expected_result", [ - ('11i', None, 'WPA'), - ('11i', '', 'WPA'), - ('11i', 'WPA3', 'WPA3'), - ('WPAand11i', None, 'WPA'), - ('11iandWPA3', None, 'WPA'), - ('None', None, 'nopass'), - ('OWETrans', None, 'nopass'), - ] -) -def test_get_beacon_security(current_beacontype, security, expected_result): - """ - Test for correct selection of "WPA" or "nopass" depending on the - WLAN-settings. - """ - mock_data = { - 'NewBeaconType': current_beacontype, - 'NewX_AVM-DE_PossibleBeaconTypes': 'None,11i,WPAand11i,11iandWPA3' - } - instance = WLANConfigMock(mock_data) - result = get_beacon_security(instance, security) - assert result == expected_result - - @pytest.mark.skipif(OPENCV_NOT_AVAILABLE, reason="requires opencv") @pytest.mark.parametrize( "current_beacontype, security, expected_security", [ @@ -154,6 +128,7 @@ ('11i', 'WPA3', 'WPA3'), ('WPAand11i', None, 'WPA'), ('11iandWPA3', None, 'WPA'), + ('Basic', None, 'WEP'), ('None', None, 'nopass'), ('OWETrans', None, 'nopass'), ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_functional.py new/fritzconnection-1.14.0/fritzconnection/tests/test_functional.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_functional.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_functional.py 2024-08-12 17:58:36.000000000 +0200 @@ -3,7 +3,6 @@ """ import pytest -import requests from ..core.exceptions import ( FritzConnectionException, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_processor.py new/fritzconnection-1.14.0/fritzconnection/tests/test_processor.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_processor.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_processor.py 2024-08-12 17:58:36.000000000 +0200 @@ -151,7 +151,7 @@ def test_system_version_igd(igddesc_source): d = Description(igddesc_source) - assert d.system_version == None + assert d.system_version is None def test_system_version_tr64(tr64desc_source): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/fritzconnection/tests/test_serialize.py new/fritzconnection-1.14.0/fritzconnection/tests/test_serialize.py --- old/fritzconnection-1.13.2/fritzconnection/tests/test_serialize.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/fritzconnection/tests/test_serialize.py 2024-08-12 17:58:36.000000000 +0200 @@ -4,8 +4,6 @@ import json -import pytest - from fritzconnection.core.processor import ( Action, Argument, @@ -71,12 +69,12 @@ JSON_RESULT_TEST_SERIALIZE_ACTION = f"""{{"name": "{DATA_ACTION_NAME}", "arguments": [{JSON_RESULT_TEST_SERIALIZE_ARGUMENT}, {JSON_RESULT_TEST_SERIALIZE_ARGUMENT}]}}""" # weird but f-strings substitute lists of strings different than json.dumps: -JSON_RESULT_TEST_SERIALIZE_STATEVARIABLE = f"""{{"attributes": {{"allowed_values": """ + json.dumps(DATA_STATEVARIABLE_ALLOWED_VALUES) + f""", "dataType": "{DATA_STATEVARIABLE_DATATYPE}", "defaultValue": "{DATA_STATEVARIABLE_DEFAULTVALUE}", "name": "{DATA_STATEVARIABLE_NAME}"}}, "allowedValueRange": {JSON_RESULT_TEST_SERIALIZE_VALUERANGE}}}""" +JSON_RESULT_TEST_SERIALIZE_STATEVARIABLE = f"""{{"attributes": {{"allowed_values": """ + json.dumps(DATA_STATEVARIABLE_ALLOWED_VALUES) + f""", "dataType": "{DATA_STATEVARIABLE_DATATYPE}", "defaultValue": "{DATA_STATEVARIABLE_DEFAULTVALUE}", "name": "{DATA_STATEVARIABLE_NAME}"}}, "allowedValueRange": {JSON_RESULT_TEST_SERIALIZE_VALUERANGE}}}""" # noqa: F541 JSON_RESULT_TEST_SERIALIZE_SCPD = f"""{{"actions": [{JSON_RESULT_TEST_SERIALIZE_ACTION}, {JSON_RESULT_TEST_SERIALIZE_ACTION}], "specVersion": {JSON_RESULT_TEST_SERIALIZE_SPECVERSION}, "state_variables": [{JSON_RESULT_TEST_SERIALIZE_STATEVARIABLE}, {JSON_RESULT_TEST_SERIALIZE_STATEVARIABLE}]}}""" JSON_RESULT_TEST_SERIALIZE_SERVICE = f"""{{"attributes": {{"SCPDURL": "{DATA_SERVICE_SCPDURL}", "controlURL": "{DATA_SERVICE_CONTROLURL}", "eventSubURL": "{DATA_SERVICE_EVENTSUBURL}", "serviceId": "{DATA_SERVICE_SERVICEID}", "serviceType": "{DATA_SERVICE_SERVICETYPE}"}}, "scpd": {JSON_RESULT_TEST_SERIALIZE_SCPD}}}""" JSON_RESULT_TEST_SERIALIZE_DEVICE_BASIC = f"""{{"attributes": {{"UDN": "{DATA_DEVICE_UDN}", "UPC": null, "deviceType": "{DATA_DEVICE_DEVICETYPE}", "friendlyName": "{DATA_DEVICE_FRIENDLYNAME}", "manufacturer": "{DATA_DEVICE_MANUFACTURER}", "manufacturerURL": "{DATA_DEVICE_MANUFACTURERURL}", "modelDescription": "{DATA_DEVICE_MODELDESCRIPTION}", "modelName": "{DATA_DEVICE_MODELNAME}", "modelNumber": "{DATA_DEVICE_MODELNUMBER}", "modelURL": "{DATA_DEVICE_MODELURL}", "presentationURL": "{DATA_DEVICE_PRESENTATIONURL}"}}""" JSON_RESULT_TEST_SERIALIZE_DEVICE_BASIC_SERVICE = f""", "services": [{JSON_RESULT_TEST_SERIALIZE_SERVICE}, {JSON_RESULT_TEST_SERIALIZE_SERVICE}]}}""" -JSON_RESULT_TEST_SERIALIZE_DEVICE = JSON_RESULT_TEST_SERIALIZE_DEVICE_BASIC + f""", "devices": [], "services": []}}""" +JSON_RESULT_TEST_SERIALIZE_DEVICE = JSON_RESULT_TEST_SERIALIZE_DEVICE_BASIC + f""", "devices": [], "services": []}}""" # noqa: F541 JSON_RESULT_TEST_SERIALIZE_DEVICE_WITH_SERVICES = JSON_RESULT_TEST_SERIALIZE_DEVICE_BASIC + ', "devices": []' + JSON_RESULT_TEST_SERIALIZE_DEVICE_BASIC_SERVICE # subdevices don't provide services and further devices diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/noxfile.py new/fritzconnection-1.14.0/noxfile.py --- old/fritzconnection-1.13.2/noxfile.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/noxfile.py 2024-08-12 17:58:36.000000000 +0200 @@ -1,7 +1,7 @@ import nox -PYTHON_TEST_VERSIONS = ("3.7", "3.8", "3.9", "3.10", "3.11", "3.12") +PYTHON_TEST_VERSIONS = ("3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13") PYTHON_DEVELOPMENT_VERSION = "3.11" @@ -26,17 +26,15 @@ session.run("pytest") -@nox.session -def lint(session): - session.install("-e", ".") - session.install("pylint") - session.run("pylint", "fritzconnection") +@nox.session(name="check") +def ruff_check(session): + session.run("ruff", "check", "fritzconnection", external=True) @nox.session def mypy(session): session.install("-e", ".") - session.install("mypy==1.4.1", "types-requests", "segno") + session.install("mypy==1.11.1", "types-requests", "segno") session.run("mypy", "fritzconnection/core/fritzconnection.py") session.run("mypy", "fritzconnection/core/fritzmonitor.py") session.run("mypy", "fritzconnection/lib") @@ -46,7 +44,13 @@ def sphinx(session): session.install("-e", ".") session.install("pip-tools==7.3.0") - session.run("pip-compile", "--strip-extras", "-q", "docs/requirements.in") + session.run( + "pip-compile", + "--strip-extras", + "-q", + "--output-file=docs/requirements.txt", + "docs/requirements.local.in" + ) session.install("-r", "docs/requirements.txt") session.run("sphinx-build", "docs", "docs_out") @@ -57,8 +61,15 @@ session.run("python", "setup.py", "sdist", "bdist_wheel") +@nox.session(name="check-twine", python=PYTHON_DEVELOPMENT_VERSION) +def check_twine(session): + session.install("-e", ".") + session.install("twine") + session.run("twine", "check", "dist/*") + + @nox.session(name="upload-to-pypi", python=PYTHON_DEVELOPMENT_VERSION) -def uppload_to_pypi(session): +def upload_to_pypi(session): session.install("-e", ".") session.install("twine") session.run("twine", "upload", "dist/*") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/requirements_test.txt new/fritzconnection-1.14.0/requirements_test.txt --- old/fritzconnection-1.13.2/requirements_test.txt 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/requirements_test.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,4 +0,0 @@ -pytest -tox -segno -opencv-python-headless diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/setup.py new/fritzconnection-1.14.0/setup.py --- old/fritzconnection-1.13.2/setup.py 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/setup.py 2024-08-12 17:58:36.000000000 +0200 @@ -43,9 +43,10 @@ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries :: Python Modules", ], - keywords="AVM FRITZ!Box fritzbox fritz", + keywords="AVM FRITZ!Box fritzbox fritz TR-064 AHA-HTTP homeautomation", python_requires=">= 3.7", install_requires=["requests>=2.22.0",], extras_require={ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fritzconnection-1.13.2/tox.ini new/fritzconnection-1.14.0/tox.ini --- old/fritzconnection-1.13.2/tox.ini 2023-09-17 14:58:30.000000000 +0200 +++ new/fritzconnection-1.14.0/tox.ini 1970-01-01 01:00:00.000000000 +0100 @@ -1,75 +0,0 @@ -[tox] -skip_missing_interpreters = True -envlist = - py37 - py38 - py39 - py310 - py311 - py312 - doc - - -[testenv] -passenv = LANG -deps = - pytest -; segno -; opencv-python-headless - -commands = {envbindir}/pytest {posargs} - - -[testenv:py38] -deps = - pytest - segno - opencv-python-headless - -[testenv:py39] -deps = - pytest - segno - opencv-python-headless - -[testenv:py310] -deps = - pytest - segno - opencv-python-headless - -[testenv:py311] -deps = - pytest - segno - opencv-python-headless - -[testenv:py312] -deps = - pytest - segno -; opencv-python-headless ; needs distutils removed from Python 3.12 - - - -[testenv:doc] -changedir = docs -setenv = APIDOC=True - -deps = - sphinx - sphinx_rtd_theme - -commands = - sphinx-build -qb html -d {envtmpdir}/doctrees . {envtmpdir}/html - - -[testenv:cov] -passenv = COVERALLS_REPO_TOKEN GIT_* -deps = - {[testenv]deps} - pytest-cov - coveralls -commands = - pytest -qq --cov=fritzconnection --cov-report=term-missing -# coveralls
participants (1)
-
Source-Sync