diff --git a/docs/sphinx/actor-schema.rst b/docs/sphinx/actor-schema.rst deleted file mode 100644 index 7aa5caf..0000000 --- a/docs/sphinx/actor-schema.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _actor-schema: - -Actor schema -============ - -In additional to these keywords, the actor also supports the default keywords automatically added by `CLU `__. Actors that subclass from `.lvmnps` may implement additional keywords. - -.. jsonschema:: ../../python/lvmnps/etc/schema.json \ No newline at end of file diff --git a/docs/sphinx/actor.rst b/docs/sphinx/actor.rst deleted file mode 100644 index be656a0..0000000 --- a/docs/sphinx/actor.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _lvmnps: - -Actor ------ - -.. automodule:: lvmnps.actor.actor - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/sphinx/api.rst b/docs/sphinx/api.rst new file mode 100644 index 0000000..03e4218 --- /dev/null +++ b/docs/sphinx/api.rst @@ -0,0 +1,25 @@ +.. _lvmnps-api: + +API +=== + +Base client +----------- + +.. autoclass:: lvmnps.nps.core.NPSClient + :members: + :show-inheritance: + +.. autopydantic_model:: lvmnps.nps.core.OutletModel + :model-show-json: false + :exclude-members: model_post_init + + +Implementations +--------------- + +.. autoclass:: lvmnps.nps.implementations.dli.DLIClient + +.. autopydantic_model:: lvmnps.nps.implementations.dli.DLIOutletModel + :model-show-json: false + :exclude-members: model_post_init diff --git a/docs/sphinx/commands.rst b/docs/sphinx/commands.rst index bc8475e..64f6bd0 100644 --- a/docs/sphinx/commands.rst +++ b/docs/sphinx/commands.rst @@ -5,6 +5,6 @@ Commands The ``lvmnps`` actor replies to the follwing commands. -.. click:: lvmnps.actor.commands:parser +.. click:: lvmnps.actor.commands:lvmnps_command_parser :prog: lvmnps :show-nested: diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py index f85ee60..157bfbb 100644 --- a/docs/sphinx/conf.py +++ b/docs/sphinx/conf.py @@ -13,13 +13,7 @@ from pkg_resources import parse_version - -try: - from lvmnps import __version__ -except ModuleNotFoundError: - from sdsstools import get_package_version - - __version__ = get_package_version(__file__, "sdss-lvmnps") or "dev" +from lvmnps import __version__ # Are we building in RTD? @@ -51,6 +45,7 @@ "sphinx.ext.autodoc", "sphinx.ext.napoleon", "sphinx.ext.autosummary", + "sphinx_autodoc_typehints", "sphinx.ext.todo", "sphinx.ext.viewcode", "sphinx.ext.mathjax", @@ -58,13 +53,17 @@ "sphinx.ext.inheritance_diagram", "myst_parser", "sphinx_copybutton", - "sphinx_click", + "sphinx_click.ext", "sphinx-jsonschema", + "sphinxcontrib.autodoc_pydantic", ] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] +pygments_style = "lovelace" +pygments_dark_style = "one-dark" + # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # @@ -80,8 +79,8 @@ # General information about the project. project = "lvmnps" -copyright = "{0}, {1}".format("2021", "SDSS LVMI softwareteam in Kyung Hee university") -author = "Mingyeong Yang" +copyright = "{0}, {1}".format("2021-", "Sloan Digital Sky Survey") +author = "Mingyeong Yang and others" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -97,7 +96,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -133,27 +132,24 @@ # Intersphinx mappings intersphinx_mapping = { - "python": ("https://docs.python.org/3.6", None), - "astropy": ("http://docs.astropy.org/en/latest", None), - "numpy": ("http://docs.scipy.org/doc/numpy/", None), - "click": ("https://click.palletsprojects.com/en/7.x/", None), - "aio_pika": ("https://aio-pika.readthedocs.io/en/latest/", None), + "python": ("https://docs.python.org/3.12", None), } autodoc_mock_imports = ["_tkinter", "asynctest", "numpy", "pymodbus"] autodoc_member_order = "groupwise" autodoc_default_options = {"members": None, "show-inheritance": None} -autodoc_typehints = "description" +# autodoc_typehints = "description" -napoleon_use_rtype = False -napoleon_use_ivar = True +# napoleon_use_rtype = False +# napoleon_use_ivar = True + +simplify_optional_unions = True +typehints_use_signature_return = True copybutton_prompt_text = r">>> |\$ " copybutton_prompt_is_regexp = True rst_epilog = f""" -.. |numpy_array| replace:: Numpy array -.. |HDUList| replace:: :class:`~astropy.io.fits.HDUList` .. |npsactor_version| replace:: {__version__} """ @@ -166,8 +162,13 @@ html_theme = "furo" html_logo = "_static/sdssv_logo.png" -html_title = "lvmnps" +html_title = "lvmnps documentation" html_favicon = "./_static/favicon.ico" +html_theme_options = { + "source_repository": "https://github.com/sdss/lvmnps/", + "source_branch": "main", + "source_directory": "docs/sphinx", +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, diff --git a/docs/sphinx/developer-env.rst b/docs/sphinx/developer-env.rst deleted file mode 100644 index 3beda39..0000000 --- a/docs/sphinx/developer-env.rst +++ /dev/null @@ -1,103 +0,0 @@ -Developer environment -===================== - -LVM Network Power Switch - -Features --------- - -- CLU Actor based interface -- Supports a Dummy PDU -- Supports `iBOOT g2 `__ with python - code from `here `__ -- Supports `Digital Loggers Web - Power `__ with python code - from `here `__ - -Installation ------------- - -Clone this repository. - -:: - - $ git clone https://github.com/sdss/lvmnps - $ cd lvmnps - -Quick Start ------------ - -Prerequisite -~~~~~~~~~~~~ - -If your system already have rabbitmq, and already running with the actors, you don't have to install these below. - -Install `RabbitMQ `__ by using apt-get. - -RabbitMQ is not the dependency of the 'lvmnps' but it is the system-wide configuration for running the software under CLU CLI(command line interface). - -:: - - $ sudo apt-get install -y erlang - $ sudo apt-get install -y rabbitmq-server - $ sudo systemctl enable rabbitmq-server - $ sudo systemctl start rabbitmq-server - - -If your system already have pyenv, you don't have to install these below. -Install `pyenv `__ by using `pyenv -installer `__. -Also, pyenv is the virtual environment for running the python package under your specific python environment. -This is very useful when you want to isolate your python package with others. - -:: - - $ curl https://pyenv.run | bash - -You should add the code below to ``~/.bashrc`` by using your preferred -editor. - -:: - - # pyenv - export PYENV_ROOT="$HOME/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init -)" - eval "$(pyenv init --path)" - eval "$(pyenv virtualenv-init -)" - -``pyenv`` builds Python from source. So you should install build -dependencies. For more information, check `Common build -problems `__. - -:: - - $ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev \ - libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev \ - libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl - -Set the python 3.9.1 virtual environment. - -:: - - $ pyenv install 3.9.1 - $ pyenv virtualenv 3.9.1 lvmnps-with-3.9.1 - $ pyenv local lvmnps-with-3.9.1 - -Install `poetry `__ and dependencies. For -more information, check -`sdss/archon `__. - -:: - - $ pip install poetry - $ python create_setup.py - $ pip install -e . - -Test ----- - -:: - - poetry run pytest - poetry run pytest -p no:logging -s -vv diff --git a/docs/sphinx/examples.rst b/docs/sphinx/examples.rst deleted file mode 100644 index 05474e3..0000000 --- a/docs/sphinx/examples.rst +++ /dev/null @@ -1,209 +0,0 @@ -.. _examples: - -Examples -======== - -Starting the Actor ------------------- - -lvmnps actor provides the control system to manage the NPS. -First you have to start the actor by the terminal command line in the python virtual environment that you installed the lvmnps package. :: - - $ lvmnps start - - -If you want to start with debugging mode, you can start like this. -In this case, you can finish the software by ctrl + c on the terminal :: - - $ lvmnps start --debug - - -Also you can check the status of the actor is running by this command :: - - $ lvmnps status - - -After your work is done, you can finish the actor by this command :: - - $ lvmnps stop - - -Finally, you can restart(stop -> start) the actor when the actor is running by this command :: - - $ lvmnps restart - - -Interface with the actor ------------------------- - -If you started the actor by the *lvmnps start* command, you can interface with the actor by the clu CLI(Command Line Interface) :: - - $ clu - - -If you want to ignore the status message from other actors, you can use this command :: - - $ clu -b - - -Then you will enter to the clu CLI. -You can check if the actor is running by the ping-pong commands. :: - - lvmnps ping - 04:57:53.183 lvmnps > - 04:57:53.198 lvmnps : { - "text": "Pong." - } - - - -``help`` command ----------------- - -First you can confirm the existing commands of *lvmnps* by the *help* command :: - - lvmnps help - 09:26:59.497 lvmnps > - 09:26:59.512 lvmnps : { - "help": [ - "Usage: lvmnps [OPTIONS] COMMAND [ARGS]...", - "", - "Options:", - " --help Show this message and exit.", - "", - "Commands:", - " cycle cycle power to an Outlet", - " device return the list of devices connected with switch", - " help Shows the help.", - " off Turn off the Outlet", - " on Turn on the Outlet", - " ping Pings the actor.", - " status print the status of the NPS.", - " switches return the list of switches", - " version Reports the version." - ] - } - - -``reachable`` command ---------------------- - -If you run the switches command via lvmnps, you can get the list of switches :: - - lvmnps reachable switches - -will return this kind of reply.:: - - lvmnps reachable switches - 09:27:25.948 lvmnps > - 09:27:25.960 lvmnps i { - "text": "the list of switches" - } - 09:27:25.973 lvmnps i { - "list": [ - "DLI-NPS-01", - "DLI-NPS-02", - "DLI-NPS-03" - ] - } - 09:27:25.985 lvmnps : { - "text": "done" - } - - -If you run the outlet command via lvmnps reachable command, you can get the list of devices connected with the switch.:: - - lvmnps reachable outlets DLI-NPS-01 - -will return this kind of reply.:: - - lvmnps reachable outlets DLI-NPS-01 - 08:19:36.478 lvmnps > - 08:19:36.491 lvmnps i { - "text": "Individual Control of DLI-NPS-01..." - } - 08:19:37.191 lvmnps i { - "IndividualControl": [ - "DLI-NPS-01.port1", - "-", - "DLI-NPS-01.port3", - "DLI-NPS-01.port4", - "DLI-NPS-01.port5", - "DLI-NPS-01.port6", - "DLI-NPS-01.port7", - "625 nm LED (M625L4)" - ] - } - 08:19:37.204 lvmnps : { - "text": "done" - } - - -``on`` command --------------- - -If you run the on command via lvmnps, you can turn on the power of the device which you want to control.:: - - lvmnps on eight - -will return this kind of reply.:: - - lvmnps on eight - 05:38:07.617 lvmnps > - 05:38:07.633 lvmnps i { - "text": "Turning on port eight..." - } - 05:38:08.706 lvmnps i { - "STATUS": { - "DLI Controller": { - "eight": { - "STATE": 1, - "DESCR": "DLI Controller Port 8", - "SWITCH": "DLI Controller", - "PORT": 8 - } - } - } - } - 05:38:08.719 lvmnps : { - "text": "done" - } - - -``off`` command ---------------- - -If you run the off command via lvmnps, you can turn off the power of the device which you want to control.:: - - lvmnps off eight - -will return this kind of reply.:: - - lvmnps off eight - 05:42:01.403 lvmnps > - 05:42:01.423 lvmnps i { - "text": "Turning off port eight..." - } - 05:42:02.418 lvmnps i { - "STATUS": { - "DLI Controller": { - "eight": { - "STATE": 0, - "DESCR": "DLI Controller Port 8", - "SWITCH": "DLI Controller", - "PORT": 8 - } - } - } - } - 05:42:02.426 lvmnps : { - "text": "done" - } - - -``status`` command ------------------- - -If you run the status command via lvmnps, you can receive the telemetry data of power status of devices :: - - lvmnps status *command* diff --git a/docs/sphinx/exceptions.rst b/docs/sphinx/exceptions.rst deleted file mode 100644 index 3669b83..0000000 --- a/docs/sphinx/exceptions.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _exceptions: - -Exceptions -========== - -Exceptions ----------- - -.. automodule:: lvmnps.exceptions - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index b5cbf9d..9361674 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -7,29 +7,25 @@ Contents .. toctree:: :caption: Contents + :maxdepth: 1 introduction - examples + commands .. toctree:: - :caption: API :maxdepth: 3 - actor - switch - commands - actor-schema - exceptions + api .. toctree:: :caption: Development - :maxdepth: 3 + :maxdepth: 1 - developer-env Changelog GitHub Repository Issues + Indices and tables ------------------ diff --git a/docs/sphinx/introduction.rst b/docs/sphinx/introduction.rst index b682044..f7ae24b 100644 --- a/docs/sphinx/introduction.rst +++ b/docs/sphinx/introduction.rst @@ -2,210 +2,3 @@ Introduction ============ - -An NPS (Network Power Switch) is a device that can control multiple power switches through a network. By connecting the power of the LVM-I Spectroograph Box and subsystem through this device, the power of each device can be controlled through the network. - -LVM-I selected two models for NPS. -In the LVM-I SCP, we decide to use “web power switch pro” by digital loggers(dli) for NPS. More details can be found through `dli `_ -In the LVM-I TCP, we're using iboot web power switch in dataprobe Co.(iboot). More details can be found through `iboot `_ -We updated *switch* moduel for the nps control library applicable to both models. The powerswitch class is created for the basic modules of dli and iboot and used in the actor command. - -DLI ---- - -The Digital Loggers provides a library made to control the power switch for the above models. Based on this module, the KHU team redefines and asynchronously changes the functions required for the command in SCP. This module plays a role in web crawling from the index web page that provides information about the power switch and controlling the power. For asynchronous web crawling, the asynchronous class provided by httpx was used instead of the default requests library. We also overridden the rest of the functions asynchronously. A new module for controlling power switch is defined as *lvmpower.py*. - -.. image:: _static/dlinps.png - :align: center - -iboot ------ - -.. image:: _static/ibootnps.png - :align: center - - -Start the actor ---------------- - -Start ``lvmnps`` actor. - -:: - - $ lvmnps start - -In another terminal, type ``clu`` and ``lvmnps ping`` for test. - -:: - - $ clu - lvmnps ping - 07:41:22.636 lvmnps > - 07:41:22.645 lvmnps : { - "text": "Pong." - } - -Stop ``lvmnps`` actor. - -:: - - $ lvmnps stop - -Config file structure ---------------------- - -:: - - switches: - name_your_switch_here: # should be a unique name - type: dummy # currently dummy, iboot, dli - num: 8 # number of ports - ports: - 1: - name: "skyw.pwi" # should also be a unique name - desc: "Something that make sense" - should_be_a_unique_name: - type: dummy - ports: - 1: - name: "skye.pwi" - desc: "PlaneWavemount Skye" - -Status return for all commands ------------------------------- - -- if 'name' is not defined then the port name will be 'switch - name'.'port number' eg nps\_dummy\_1.port1 otherwise 'name' from the - config file will be used. -- STATE: 1: ON, 0: OFF, -1: UNKNOWN - - :: - - "STATUS": { - "nps_dummy_1.port1": { - "STATE": -1, - "DESCR": "was 1", - "SWITCH": "nps_dummy_1", - "PORT": 1 - }, - -Run the example lvmnps\_dummy ------------------------------ - -:: - - #> cd lvmnps - #> poetry run lvmnps -vvv -c $(pwd)/python/lvmnps/etc/lvmnps_dummy.yml start - - #> poetry run clu - -- status command without parameter returns all ports of all switches. -- the default is to return only configured ports, otherwise define - 'ouo' false in the config file, see - `lvmnps\_dummy.yml `__ - - :: - - lvmnps statu - - 12:02:08.649 lvmnps > - 12:02:08.660 lvmnps i { - "STATUS": { - "nps\_dummy\_1.port1": { - "STATE": -1, - "DESCR": "was 1", - "SWITCH": "nps\_dummy\_1", - "PORT": 1 - }, - "skye.what.ever": { - "STATE": -1, - "DESCR": "whatever is connected to skye", - "SWITCH": "nps\_dummy\_1", - "PORT": 2 - }, - "skyw.what.ever": { - "STATE": -1, - "DESCR": "Something @ skyw", - "SWITCH": "nps\_dummy\_1", - "PORT": 4 - }, - "skye.pwi": { - "STATE":-1, - "DESCR": "PlaneWavemount Skye", - "SWITCH": "skye.nps", - "PORT": 1 - }, - "skyw.pwi": { - "STATE": -1, - "DESCR": "PlaneWavemount Skyw", - "SWITCH": "nps\_dummy\_3", - "PORT": 1 - } - } - } - -- status command with port name skyw.what.ever - - :: - - lvmnps status what skyw.what.ever - - 12:07:12.349 lvmnps > - 12:07:12.377 lvmnps i { - "STATUS": { - "skyw.what.ever": { - "STATE": -1, - "DESCR": "Something @ skyw", - "SWITCH": "nps\_dummy\_1", - "PORT": 4 - } - -- status command with switch name nps\_dummy\_1 - - :: - - lvmnps status what nps\_dummy\_1 - - 12:07:12.349 lvmnps > - 12:12:21.349 lvmnps i { - "STATUS": { - "nps\_dummy\_1.port1": { - "STATE": -1, - "DESCR": "was 1", - "SWITCH": "nps\_dummy\_1", - "PORT": 1 - }, - "skye.what.ever": { - "STATE": -1, - "DESCR": "whatever is connected to skye", - "SWITCH": "nps\_dummy\_1", - "PORT": 2 - }, - "skyw.what.ever": { - "STATE": -1, - "DESCR": "Something @ skyw", - "SWITCH": "nps\_dummy\_1", - "PORT": 4 - } - } - } - -- status command with switch name nps\_dummy\_1 and port 4 returns - - :: - - lvmnps status what nps\_dummy\_1 4 - - 12:07:12.349 lvmnps > - 12:12:21.349 lvmnps i { - "STATUS": { - "skyw.what.ever": { - "STATE": -1, - "DESCR": "Something @ skyw", - "SWITCH": "nps\_dummy\_1", - "PORT": 4 - } - } - } - -- the commands on and off use the same addressing scheme as status diff --git a/docs/sphinx/make.bat b/docs/sphinx/make.bat deleted file mode 100644 index 2c0764f..0000000 --- a/docs/sphinx/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/sphinx/requirements.txt b/docs/sphinx/requirements.txt index 7919f0f..b0812c2 100644 --- a/docs/sphinx/requirements.txt +++ b/docs/sphinx/requirements.txt @@ -1,8 +1,7 @@ -sphinx>=4.5.0 +sphinx>=7.0 sphinx-click>=2.6.0 sphinx-jsonschema>=1.16.7 -myst-parser>=0.14.0 +myst-parser>=0.15.0 furo>=2021.6.18-beta.36 -sphinx-autobuild>=2021.3.14 sphinx-copybutton>=0.3.3 -jinja2==3.0.0 +sphinx-autodoc-typehints>=1.23.2 diff --git a/docs/sphinx/switch.rst b/docs/sphinx/switch.rst deleted file mode 100644 index 24fa7e0..0000000 --- a/docs/sphinx/switch.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. _switch: - -Switch -====== - -.. automodule:: lvmnps.switch.powerswitchbase - :members: - :undoc-members: - :show-inheritance: - - -.. automodule:: lvmnps.switch.outlet - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: lvmnps.switch.dli.dli - :members: - :undoc-members: - :show-inheritance: - -.. automodule:: lvmnps.switch.dli.powerswitch - :members: - :undoc-members: - :show-inheritance: diff --git a/noxfile.py b/noxfile.py deleted file mode 100644 index a135495..0000000 --- a/noxfile.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# @Author: José Sánchez-Gallego (gallegoj@uw.edu) -# @Date: 2021-06-20 -# @Filename: noxfile.py -# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) - -import contextlib -import os -import tempfile - -import nox - - -@contextlib.contextmanager -def cd(path): - CWD = os.getcwd() - - os.chdir(path) - - try: - yield - finally: - os.chdir(CWD) - - -@nox.session(name="docs-live", reuse_venv=True) -def docs_live(session): - if session.posargs: - docs_dir = session.posargs[0] - else: - docs_dir = "." - - with cd(os.path.join(os.path.dirname(__file__), "docs/sphinx")): - with tempfile.TemporaryDirectory() as destination: - session.run( - "sphinx-autobuild", - # for sphinx-autobuild - "--port=0", - "--open-browser", - # for sphinx - "-b=dirhtml", - "-a", - docs_dir, - destination, - external=True, - ) diff --git a/poetry.lock b/poetry.lock index 65ea4ba..3594172 100644 --- a/poetry.lock +++ b/poetry.lock @@ -137,6 +137,29 @@ docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib- tests = ["attrs[tests-no-zope]", "zope-interface"] tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +[[package]] +name = "autodoc-pydantic" +version = "2.0.1" +description = "Seamlessly integrate pydantic models in your Sphinx documentation." +optional = false +python-versions = ">=3.7.1,<4.0.0" +files = [ + {file = "autodoc_pydantic-2.0.1-py3-none-any.whl", hash = "sha256:d3c302fdb6d37edb5b721f0f540252fa79cea7018bc1a9a85bf70f33a68b0ce4"}, + {file = "autodoc_pydantic-2.0.1.tar.gz", hash = "sha256:7a125a4ff18e4903e27be71e4ddb3269380860eacab4a584d6cc2e212fa96991"}, +] + +[package.dependencies] +importlib-metadata = {version = ">1", markers = "python_version <= \"3.8\""} +pydantic = ">=2.0,<3.0.0" +pydantic-settings = ">=2.0,<3.0.0" +Sphinx = ">=4.0" + +[package.extras] +dev = ["coverage (>=7,<8)", "flake8 (>=3,<4)", "pytest (>=7,<8)", "sphinx-copybutton (>=0.4,<0.5)", "sphinx-rtd-theme (>=1.0,<2.0)", "sphinx-tabs (>=3,<4)", "sphinxcontrib-mermaid (>=0.7,<0.8)", "tox (>=3,<4)"] +docs = ["sphinx-copybutton (>=0.4,<0.5)", "sphinx-rtd-theme (>=1.0,<2.0)", "sphinx-tabs (>=3,<4)", "sphinxcontrib-mermaid (>=0.7,<0.8)"] +erdantic = ["erdantic (>=0.6,<0.7)"] +test = ["coverage (>=7,<8)", "pytest (>=7,<8)"] + [[package]] name = "babel" version = "2.13.1" @@ -501,24 +524,6 @@ files = [ {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, ] -[[package]] -name = "doc8" -version = "1.1.1" -description = "Style checker for Sphinx (or other) RST documentation" -optional = false -python-versions = ">=3.8" -files = [ - {file = "doc8-1.1.1-py3-none-any.whl", hash = "sha256:e493aa3f36820197c49f407583521bb76a0fde4fffbcd0e092be946ff95931ac"}, - {file = "doc8-1.1.1.tar.gz", hash = "sha256:d97a93e8f5a2efc4713a0804657dedad83745cca4cd1d88de9186f77f9776004"}, -] - -[package.dependencies] -docutils = ">=0.19,<0.21" -Pygments = "*" -restructuredtext-lint = ">=0.7" -stevedore = "*" -tomli = {version = "*", markers = "python_version < \"3.11\""} - [[package]] name = "docutils" version = "0.20.1" @@ -574,22 +579,6 @@ docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1 testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] -[[package]] -name = "flake8" -version = "5.0.4" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, - {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.9.0,<2.10.0" -pyflakes = ">=2.5.0,<2.6.0" - [[package]] name = "furo" version = "2023.9.10" @@ -799,23 +788,6 @@ qtconsole = ["qtconsole"] test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] -[[package]] -name = "isort" -version = "5.12.0" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, -] - -[package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] - [[package]] name = "jedi" version = "0.19.1" @@ -1023,17 +995,6 @@ files = [ [package.dependencies] traitlets = "*" -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - [[package]] name = "mdit-py-plugins" version = "0.4.0" @@ -1256,17 +1217,6 @@ files = [ {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] -[[package]] -name = "pbr" -version = "6.0.0" -description = "Python Build Reasonableness" -optional = false -python-versions = ">=2.6" -files = [ - {file = "pbr-6.0.0-py2.py3-none-any.whl", hash = "sha256:4a7317d5e3b17a3dccb6a8cfe67dab65b20551404c52c8ed41279fa4f0cb4cda"}, - {file = "pbr-6.0.0.tar.gz", hash = "sha256:d1377122a5a00e2f940ee482999518efe16d745d423a670c27773dfbc3c9a7d9"}, -] - [[package]] name = "pexpect" version = "4.8.0" @@ -1400,17 +1350,6 @@ files = [ [package.extras] tests = ["pytest"] -[[package]] -name = "pycodestyle" -version = "2.9.1" -description = "Python style guide checker" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, - {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, -] - [[package]] name = "pydantic" version = "2.5.2" @@ -1548,16 +1487,20 @@ files = [ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] -name = "pyflakes" -version = "2.5.0" -description = "passive checker of Python programs" +name = "pydantic-settings" +version = "2.1.0" +description = "Settings management using Pydantic" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, - {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, + {file = "pydantic_settings-2.1.0-py3-none-any.whl", hash = "sha256:7621c0cb5d90d1140d2f0ef557bdf03573aac7035948109adf2574770b77605a"}, + {file = "pydantic_settings-2.1.0.tar.gz", hash = "sha256:26b1492e0a24755626ac5e6d715e9077ab7ad4fb5f19a8b7ed7011d52f36141c"}, ] +[package.dependencies] +pydantic = ">=2.3.0" +python-dotenv = ">=0.21.0" + [[package]] name = "pygments" version = "2.17.2" @@ -1667,6 +1610,20 @@ termcolor = ">=2.1.0" [package.extras] dev = ["black", "flake8", "pre-commit"] +[[package]] +name = "python-dotenv" +version = "1.0.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, + {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + [[package]] name = "python-json-logger" version = "2.0.7" @@ -1774,19 +1731,6 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] -[[package]] -name = "restructuredtext-lint" -version = "1.4.0" -description = "reStructuredText linter" -optional = false -python-versions = "*" -files = [ - {file = "restructuredtext_lint-1.4.0.tar.gz", hash = "sha256:1b235c0c922341ab6c530390892eb9e92f90b9b75046063e047cacfb0f050c45"}, -] - -[package.dependencies] -docutils = ">=0.11,<1.0" - [[package]] name = "rich" version = "13.7.0" @@ -1914,57 +1858,6 @@ files = [ {file = "rpds_py-0.13.1.tar.gz", hash = "sha256:264f3a5906c62b9df3a00ad35f6da1987d321a053895bd85f9d5c708de5c0fbf"}, ] -[[package]] -name = "rstcheck" -version = "6.2.0" -description = "Checks syntax of reStructuredText and code blocks nested within it" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rstcheck-6.2.0-py3-none-any.whl", hash = "sha256:63262c8453489a6e3873113e16c1d234c86ca90a829e685263fd6c7aec0073fa"}, - {file = "rstcheck-6.2.0.tar.gz", hash = "sha256:4f47d1e136e8dc7e6fd54d9679dbc1ed7c4d87b12e17d00003fccf4734e9ffdf"}, -] - -[package.dependencies] -importlib-metadata = {version = ">=1.6", markers = "python_version <= \"3.8\""} -rstcheck-core = ">=1.1" -typer = {version = ">=0.4.1", extras = ["all"]} -typing-extensions = {version = ">=3.7.4", markers = "python_version <= \"3.8\""} - -[package.extras] -dev = ["rstcheck[docs,sphinx,testing,toml,type-check]", "tox (>=3.15)"] -docs = ["m2r2 (>=0.3.2)", "sphinx (>=4.0)", "sphinx-autobuild (>=2021.3.14)", "sphinx-click (>=4.0.3)", "sphinx-rtd-theme (>=1.2)", "sphinxcontrib-spelling (>=7.3)"] -sphinx = ["sphinx (>=4.0)"] -testing = ["coverage-conditional-plugin (>=0.5)", "coverage[toml] (>=6.0)", "pytest (>=7.2)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.0)", "pytest-sugar (>=0.9.5)"] -toml = ["tomli (>=2.0)"] -type-check = ["mypy (>=1.0)"] - -[[package]] -name = "rstcheck-core" -version = "1.2.0" -description = "Checks syntax of reStructuredText and code blocks nested within it" -optional = false -python-versions = ">=3.8" -files = [ - {file = "rstcheck-core-1.2.0.tar.gz", hash = "sha256:991678a86b604636d2461a97fb9339366d143eb799d22d51f49f84ed272121a9"}, - {file = "rstcheck_core-1.2.0-py3-none-any.whl", hash = "sha256:53478e4f9b1aca98dd9e892eff9f90fc8741b2be0e3213497585227c369db510"}, -] - -[package.dependencies] -docutils = ">=0.7" -importlib-metadata = {version = ">=1.6", markers = "python_version <= \"3.8\""} -pydantic = ">=2" -typing-extensions = {version = ">=3.7.4", markers = "python_version <= \"3.8\""} - -[package.extras] -dev = ["rstcheck-core[docs,sphinx,testing,toml,type-check,yaml]", "tox (>=3.15)"] -docs = ["m2r2 (>=0.3.2)", "sphinx (>=4.0,!=7.2.5)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.15)", "sphinx-rtd-theme (>=1.2)", "sphinxcontrib-apidoc (>=0.3)", "sphinxcontrib-spelling (>=7.3)"] -sphinx = ["sphinx (>=4.0)"] -testing = ["coverage-conditional-plugin (>=0.5)", "coverage[toml] (>=6.0)", "pytest (>=7.2)", "pytest-cov (>=3.0)", "pytest-mock (>=3.7)", "pytest-randomly (>=3.0)", "pytest-sugar (>=0.9.5)"] -toml = ["tomli (>=2.0)"] -type-check = ["mypy (>=1.0)", "types-PyYAML (>=6.0.0)", "types-docutils (>=0.18)"] -yaml = ["pyyaml (>=6.0.0)"] - [[package]] name = "ruff" version = "0.1.6" @@ -2052,17 +1945,6 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "shellingham" -version = "1.5.4" -description = "Tool to Detect Surrounding Shell" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, -] - [[package]] name = "six" version = "1.16.0" @@ -2161,6 +2043,25 @@ sphinx = "*" [package.extras] test = ["pytest", "pytest-cov"] +[[package]] +name = "sphinx-autodoc-typehints" +version = "1.25.2" +description = "Type hints (PEP 484) support for the Sphinx autodoc extension" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sphinx_autodoc_typehints-1.25.2-py3-none-any.whl", hash = "sha256:5ed05017d23ad4b937eab3bee9fae9ab0dd63f0b42aa360031f1fad47e47f673"}, + {file = "sphinx_autodoc_typehints-1.25.2.tar.gz", hash = "sha256:3cabc2537e17989b2f92e64a399425c4c8bf561ed73f087bc7414a5003616a50"}, +] + +[package.dependencies] +sphinx = ">=7.1.2" + +[package.extras] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)"] +numpy = ["nptyping (>=2.5)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "sphobjinv (>=2.3.1)", "typing-extensions (>=4.7.1)"] + [[package]] name = "sphinx-basic-ng" version = "1.0.0b2" @@ -2336,20 +2237,6 @@ pure-eval = "*" [package.extras] tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] -[[package]] -name = "stevedore" -version = "5.1.0" -description = "Manage dynamic plugins for Python applications" -optional = false -python-versions = ">=3.8" -files = [ - {file = "stevedore-5.1.0-py3-none-any.whl", hash = "sha256:8cc040628f3cea5d7128f2e76cf486b2251a4e543c7b938f58d9a377f6694a2d"}, - {file = "stevedore-5.1.0.tar.gz", hash = "sha256:a54534acf9b89bc7ed264807013b505bf07f74dbe4bcfa37d32bd063870b087c"}, -] - -[package.dependencies] -pbr = ">=2.0.0,<2.1.0 || >2.1.0" - [[package]] name = "termcolor" version = "2.3.0" @@ -2410,30 +2297,6 @@ files = [ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] -[[package]] -name = "typer" -version = "0.9.0" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -optional = false -python-versions = ">=3.6" -files = [ - {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, - {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, -] - -[package.dependencies] -click = ">=7.1.1,<9.0.0" -colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} -rich = {version = ">=10.11.0,<14.0.0", optional = true, markers = "extra == \"all\""} -shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} -typing-extensions = ">=3.7.4.3" - -[package.extras] -all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] -dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] -doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] -test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] - [[package]] name = "typing-extensions" version = "4.8.0" @@ -2628,4 +2491,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8,<4.0" -content-hash = "85b973a9cc59be1335b33c5793e697d9312db6fa78970fe74ff6f53666489e79" +content-hash = "26bc0758c295738225f265e753fff80d0400fe66db775bbcad4c0abe996ec6f3" diff --git a/pyproject.toml b/pyproject.toml index b52efba..f9e45cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,14 +35,11 @@ sdsstools = "^1.0.0" click-default-group = "^1.2.2" sdss-clu = "^2.0.0" httpx = ">=0.18.1" +pydantic = "^2.5.2" [tool.poetry.group.dev.dependencies] ipython = ">=7.11.0" -flake8 = ">=3.7.9" -doc8 = ">=0.8.0" -isort = ">=4.3.21" ipdb = ">=0.12.3" -rstcheck = ">=3.3.1" black = ">=21.7b0" pytest = ">=5.2.2" pytest-asyncio = ">=0.10.0" @@ -50,7 +47,7 @@ pytest-cov = ">=2.8.1" pytest-mock = ">=1.13.0" pytest-sugar = ">=0.9.2" coverage = {version = ">=5.0", extras = ["toml"]} -Sphinx = ">=4.1.2" +Sphinx = ">=7.0.0" sphinx-jsonschema = ">=1.16.7" myst-parser = ">=0.14.0" furo = ">=2021.6.18" @@ -59,6 +56,9 @@ sphinx-autobuild = ">=2021.3.14" sphinx-copybutton = ">=0.3.3" sphinx-click = ">=3.0.1" ruff = ">=0.1.0" +sphinx-autodoc-typehints = ">=1.25.2" +invoke = ">=2.2.0" +autodoc-pydantic = "^2.0.1" [tool.black] line-length = 88 diff --git a/src/lvmnps/nps/implementations/dli.py b/src/lvmnps/nps/implementations/dli.py index e7cbd08..02bd325 100644 --- a/src/lvmnps/nps/implementations/dli.py +++ b/src/lvmnps/nps/implementations/dli.py @@ -15,14 +15,14 @@ from pydantic.dataclasses import dataclass from lvmnps.exceptions import VerificationError -from src.lvmnps.nps.core import NPSClient, OutletModel +from lvmnps.nps.core import NPSClient, OutletModel -__all__ = ["DLIClient"] +__all__ = ["DLIClient", "DLIOutletModel"] class DLIOutletModel(OutletModel): - """A model for an outlet status.""" + """A model for a DLI outlet status.""" index: int = 0 physical_state: bool = False diff --git a/tasks.py b/tasks.py new file mode 100644 index 0000000..bec4fe7 --- /dev/null +++ b/tasks.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# @Author: José Sánchez-Gallego (gallegoj@uw.edu) +# @Date: 2023-11-22 +# @Filename: tasks.py +# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause) + +from __future__ import annotations + +import pathlib +import tempfile + +from invoke.context import Context +from invoke.tasks import task + + +@task() +def docs_live(context: Context): + """Uses sphinx-autobuild to build a temporary copy of the docs.""" + + docs_dir = pathlib.Path(__file__).parent / "docs/sphinx" + + with context.cd(docs_dir): + with tempfile.TemporaryDirectory() as destination: + context.run( + "sphinx-autobuild --port=0 --open-browser -b=dirhtml " + f"-a {docs_dir} {destination} --watch ../../src/lvmnps", + pty=True, + )