From 50b1855cbc2dbf1fbbfb2e4709a5643622b268fc Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 12:58:11 -0700 Subject: [PATCH 01/10] initial cut at modernizing lsst-rsp --- .DS_Store | Bin 0 -> 6148 bytes .github/CODE_OF_CONDUCT | 1 + .github/CONTRIBUTING.md | 16 ++ .github/dependabot.yml | 2 +- .github/workflows/ci.yaml | 132 ++++++++++----- .github/workflows/dependencies.yaml | 33 ++++ .github/workflows/periodic-ci.yaml | 58 +++++++ .gitignore | 11 +- .pre-commit-config.yaml | 23 ++- CHANGELOG.md | 7 + LICENSE | 2 +- Makefile | 30 +++- README.md | 40 +++++ README.rst | 5 - changelog.d/_template.md.jinja | 7 + docs/.gitignore | 2 + docs/_rst_epilog.rst | 7 + docs/api.rst | 8 + docs/changelog.md | 7 + docs/conf.py | 1 + docs/dev/development.rst | 157 ++++++++++++++++++ docs/dev/index.rst | 13 ++ docs/dev/release.rst | 103 ++++++++++++ docs/documenteer.toml | 16 ++ docs/index.rst | 24 +++ docs/user-guide/index.rst | 9 + pyproject.toml | 247 ++++++++++++++++++++++++---- setup.cfg | 68 -------- setup.py | 3 - tests/__init__.py | 4 + tests/conftest.py | 1 + tests/version_test.py | 12 ++ tox.ini | 25 ++- 33 files changed, 902 insertions(+), 172 deletions(-) create mode 100644 .DS_Store create mode 100644 .github/CODE_OF_CONDUCT create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/workflows/dependencies.yaml create mode 100644 .github/workflows/periodic-ci.yaml create mode 100644 CHANGELOG.md create mode 100644 README.md delete mode 100644 README.rst create mode 100644 changelog.d/_template.md.jinja create mode 100644 docs/.gitignore create mode 100644 docs/_rst_epilog.rst create mode 100644 docs/api.rst create mode 100644 docs/changelog.md create mode 100644 docs/conf.py create mode 100644 docs/dev/development.rst create mode 100644 docs/dev/index.rst create mode 100644 docs/dev/release.rst create mode 100644 docs/documenteer.toml create mode 100644 docs/index.rst create mode 100644 docs/user-guide/index.rst delete mode 100644 setup.cfg delete mode 100644 setup.py create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/version_test.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..dbe171e5e2faf85c0cbf4336c40fe4b89c018e03 GIT binary patch literal 6148 zcmeHKyGjE=6g`uyxEh2MDJ&NxU?l|X-Gmji&IhP@kO&D0CMoQ;3>dKRI}{sh8^zKz zwl@BRMGEho8O@BFXcI)jT)1;)=RWs@oyh}^J=GVM>Zf*2fwC%MY z?cJuaH*Ab46swXV>&6w$-frmftJfC?1S>^WA5ASoPKK!#y}z z90Nk7@-vG|=`uM690Nw=imSB zAot`La11OJ1Hy~SQHfqjpRI|P7UPCaDy%1w0`PHO2~Q Rg~a_4kTkf#G4Q7hd;spBs>=WX literal 0 HcmV?d00001 diff --git a/.github/CODE_OF_CONDUCT b/.github/CODE_OF_CONDUCT new file mode 100644 index 0000000..bdc7248 --- /dev/null +++ b/.github/CODE_OF_CONDUCT @@ -0,0 +1 @@ +Please see the [Team Culture and Conduct Standards](https://developer.lsst.io/team/code-of-conduct.html) for LSST Data Management. diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..3677193 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,16 @@ +Thanks for contributing to lsst-rsp. + +## Support + +If you are a Rubin Observatory staff member, please reach out of us on Slack in the #dm-square channel or create a Jira ticket. + +If you are a community member, feel free to create a GitHub issue and we'll do our best to help you. + +## Pull requests + +Since lsst-rsp is built for the Vera C. Rubin Observatory and Legacy Survey of Space and Time, community contributions can only be accepted if they align with the Rubin Observatory's mission. +For that reason, it's a good idea to propose changes with a new GitHub issue before investing time in making a pull request. + +* * * + +See also our [Code of Conduct](./CODE_OF_CONDUCT). diff --git a/.github/dependabot.yml b/.github/dependabot.yml index dfb90b7..696b5d7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ updates: schedule: interval: "weekly" - - package-ecosystem: "docker" + - package-ecosystem: "pip" directory: "/" schedule: interval: "weekly" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 60297da..cbd4837 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,6 +1,8 @@ -name: CI +name: Python CI "on": + merge_group: {} + pull_request: {} push: branches-ignore: # These should always correspond to pull requests, so ignore them for @@ -8,70 +10,124 @@ name: CI # trigger, avoiding running the workflow twice. This is a minor # optimization so there's no need to ensure this is comprehensive. - "dependabot/**" + - "gh-readonly-queue/**" - "renovate/**" - "tickets/**" - "u/**" - tags: - - "*" - pull_request: {} + release: + types: [published] jobs: + lint: + + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Run pre-commit + uses: pre-commit/action@v3.0.0 + test: + runs-on: ubuntu-latest + timeout-minutes: 10 strategy: matrix: python: - - "3.10" + - "3.11" steps: - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 + - name: Run tox + uses: lsst-sqre/run-tox@v1 with: python-version: ${{ matrix.python }} + tox-envs: "py,typing" - - name: Run pre-commit - uses: pre-commit/action@v3.0.0 + docs: - - name: Install tox - run: pip install tox + runs-on: ubuntu-latest + timeout-minutes: 10 - - name: Cache tox environments - id: cache-tox - uses: actions/cache@v3 + steps: + - uses: actions/checkout@v3 with: - path: .tox - key: tox-${{ matrix.python }}-${{ hashFiles('setup.cfg') }}-${{ hashFiles('pyproject.toml') }} - restore-keys: | - tox-${{ matrix.python }}-${{ hashFiles('setup.cfg') }}- + fetch-depth: 0 # full history for setuptools_scm + + - name: Install Graphviz + run: sudo apt-get install graphviz - name: Run tox - run: tox -e py,coverage-report,typing - pypi: + uses: lsst-sqre/run-tox@v1 + with: + python-version: "3.11" + tox-envs: "docs" + # Add docs-linkcheck when the docs and PyPI package are published + # tox-envs: "docs,docs-linkcheck" + + # Only attempt documentation uploads for tagged releases and pull + # requests from ticket branches in the same repository. This avoids + # version clutter in the docs and failures when a PR doesn't have access + # to secrets. + - name: Upload to LSST the Docs + uses: lsst-sqre/ltd-upload@v1 + with: + project: "lsst-rsp" + dir: "docs/_build/html" + username: ${{ secrets.LTD_USERNAME }} + password: ${{ secrets.LTD_PASSWORD }} + if: > + github.event_name != 'merge_group' + && (github.event_name != 'pull_request' + || startsWith(github.head_ref, 'tickets/')) + + test-packaging: + + name: Test packaging runs-on: ubuntu-latest - needs: [test] - if: startsWith(github.ref, 'refs/tags/') steps: - uses: actions/checkout@v3 + with: + fetch-depth: 0 # full history for setuptools_scm - - name: Set up Python - uses: actions/setup-python@v4 + - name: Build and publish + uses: lsst-sqre/build-and-publish-to-pypi@v2 with: - python-version: "3.10" - cache: "pip" - cache-dependency-path: "setup.cfg" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install --upgrade setuptools wheel twine + python-version: "3.11" + upload: false + + pypi: + + # This job requires set up: + # 1. Set up a trusted publisher for PyPI + # 2. Set up a "pypi" environment in the repository + # See https://github.com/lsst-sqre/build-and-publish-to-pypi + name: Upload release to PyPI + runs-on: ubuntu-latest + needs: [lint, test, docs, test-packaging] + environment: + name: pypi + url: https://pypi.org/p/lsst-rsp + permissions: + id-token: write + if: github.event_name == 'release' && github.event.action == 'published' + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # full history for setuptools_scm + - name: Build and publish - env: - TWINE_USERNAME: "__token__" - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - python setup.py sdist bdist_wheel --universal - twine upload dist/* + uses: lsst-sqre/build-and-publish-to-pypi@v2 + with: + python-version: "3.11" diff --git a/.github/workflows/dependencies.yaml b/.github/workflows/dependencies.yaml new file mode 100644 index 0000000..96075c9 --- /dev/null +++ b/.github/workflows/dependencies.yaml @@ -0,0 +1,33 @@ +name: Dependency Update + +"on": + schedule: + - cron: "0 12 * * 1" + workflow_dispatch: {} + +jobs: + update: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v3 + + - name: Run neophile + uses: lsst-sqre/run-neophile@v1 + with: + python-version: "3.11" + mode: pr + types: pre-commit + app-id: ${{ secrets.NEOPHILE_APP_ID }} + app-secret: ${{ secrets.NEOPHILE_PRIVATE_KEY }} + + - name: Report status + if: always() + uses: ravsamhq/notify-slack-action@v2 + with: + status: ${{ job.status }} + notify_when: "failure" + notification_title: "Periodic dependency update for {repo} failed" + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ALERT_WEBHOOK }} diff --git a/.github/workflows/periodic-ci.yaml b/.github/workflows/periodic-ci.yaml new file mode 100644 index 0000000..40014be --- /dev/null +++ b/.github/workflows/periodic-ci.yaml @@ -0,0 +1,58 @@ +# This is a separate run of the Python test suite that doesn't cache the tox +# environment and runs from a schedule. The purpose is to test compatibility +# with the latest versions of dependencies. + +name: Periodic CI + +"on": + schedule: + - cron: "0 12 * * 1" + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 10 + + strategy: + matrix: + python: + - "3.11" + + steps: + - uses: actions/checkout@v3 + + - name: Run tests in tox + uses: lsst-sqre/run-tox@v1 + with: + python-version: ${{ matrix.python }} + tox-envs: "lint,typing,py" + use-cache: false + + docs: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v3 + + - name: Build docs in tox + uses: lsst-sqre/run-tox@v1 + with: + python-version: "3.11" + tox-envs: "docs,docs-linkcheck" + use-cache: false + + test-packaging: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # full history for setuptools_scm + + - name: Build and publish + uses: lsst-sqre/build-and-publish-to-pypi@v2 + with: + python-version: "3.11" + upload: false diff --git a/.gitignore b/.gitignore index f1289eb..2afcff0 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ instance/ # Sphinx documentation docs/_build/ +docs/api/ # PyBuilder target/ @@ -82,9 +83,7 @@ profile_default/ ipython_config.py # pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version +.python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. @@ -129,9 +128,3 @@ dmypy.json # Pyre type checker .pyre/ - -# pytype static type analyzer -.pytype/ - -# Mac metadata -.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1c3735a..fc80b94 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,22 +2,35 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: + - id: trailing-whitespace - id: check-yaml - id: check-toml - - repo: https://github.com/pycqa/isort + - repo: https://github.com/PyCQA/isort rev: 5.12.0 hooks: - id: isort - additional_dependencies: - - toml + additional_dependencies: [toml] - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.3.0 hooks: - id: black - - repo: https://github.com/pycqa/flake8 + - repo: https://github.com/asottile/blacken-docs + rev: v1.12.1 + hooks: + - id: blacken-docs + additional_dependencies: [black==23.3.0] + args: [-l, "79", -t, py38] + + - repo: https://github.com/PyCQA/flake8 rev: 6.0.0 hooks: - id: flake8 + + - repo: https://github.com/PyCQA/pydocstyle + rev: 6.3.0 + hooks: + - id: pydocstyle + additional_dependencies: [toml] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fad52c1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Change log + +lsst-rsp is versioned with [semver](https://semver.org/). + +Find changes for the upcoming release in the project's [changelog.d directory](https://github.com/lsst-sqre/lsst-rsp/tree/main/changelog.d/). + + diff --git a/LICENSE b/LICENSE index 59c49ff..fdfe095 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 LSST SQuaRE +Copyright (c) 2021-2023 Association of Universities for Research in Astronomy, Inc. (AURA) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index d5ee361..60b82ea 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,29 @@ +.PHONY: help +help: + @echo "Make targets for lsst-rsp:" + @echo "make clean - Remove generated files" + @echo "make init - Set up dev environment (install pre-commit hooks)" + @echo "make linkcheck - Check for broken links in documentation" + +.PHONY: clean +clean: + rm -rf .tox + rm -rf docs/_build + rm -rf docs/api + .PHONY: init init: - pip install --upgrade pip pre-commit setuptools wheel - pip install --upgrade --editable . - rm -rf .tox - pip install --upgrade tox + pip install --upgrade pip tox pre-commit + pip install --upgrade -e ".[dev]" pre-commit install + rm -rf .tox + +# This is defined as a Makefile target instead of only a tox command because +# if the command fails we want to cat output.txt, which contains the +# actually useful linkcheck output. tox unfortunately doesn't support this +# level of shell trickery after failed commands. +.PHONY: linkcheck +linkcheck: + sphinx-build --keep-going -n -W -T -b linkcheck docs \ + docs/_build/linkcheck \ + || (cat docs/_build/linkcheck/output.txt; exit 1) diff --git a/README.md b/README.md new file mode 100644 index 0000000..02415b0 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# lsst-rsp + +User-facing Python classes and functions for use in the RSP environment. +Learn more at https://lsst-rsp.lsst.io + +Install from PyPI: + +```sh +pip install lsst-rsp +``` + +lsst-rsp is developed by Rubin Observatory at https://github.com/lsst-sqre/lsst-rsp. + +## Features + + + +## Developing lsst-rsp + +The best way to start contributing to lsst-rsp is by cloning this repository, creating a virtual environment, and running the `make init` command: + +```sh +git clone https://github.com/lsst-sqre/lsst-rsp.git +cd lsst-rsp +make init +``` + +You can run tests and build documentation with [tox](https://tox.wiki/en/latest/): + +```sh +tox +``` + +To learn more about the individual environments: + +```sh +tox -av +``` + +[See the docs for more information.](https://lsst-rsp.lsst.io/dev/development.html) diff --git a/README.rst b/README.rst deleted file mode 100644 index ee6049a..0000000 --- a/README.rst +++ /dev/null @@ -1,5 +0,0 @@ -######## -lsst.rsp -######## - -User-facing Python classes and functions for use in the RSP environment. diff --git a/changelog.d/_template.md.jinja b/changelog.d/_template.md.jinja new file mode 100644 index 0000000..6e644b8 --- /dev/null +++ b/changelog.d/_template.md.jinja @@ -0,0 +1,7 @@ + +{%- for cat in config.categories %} + +### {{ cat }} + +- +{%- endfor %} diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..3c1f3b5 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +_build +api diff --git a/docs/_rst_epilog.rst b/docs/_rst_epilog.rst new file mode 100644 index 0000000..afd04ce --- /dev/null +++ b/docs/_rst_epilog.rst @@ -0,0 +1,7 @@ +.. _Click: https://click.palletsprojects.com/ +.. _mypy: http://www.mypy-lang.org +.. _pre-commit: https://pre-commit.com +.. _pytest: https://docs.pytest.org/en/latest/ +.. _scriv: https://scriv.readthedocs.io/en/stable/ +.. _semver: https://semver.org/ +.. _tox: https://tox.wiki/en/latest/ diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..b47bd9b --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,8 @@ +:og:description: Comprehensive API documentation for lsst-rsp. + +#################### +Python API reference +#################### + +.. automodapi:: lsst-rsp + :include-all-objects: diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..fad52c1 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,7 @@ +# Change log + +lsst-rsp is versioned with [semver](https://semver.org/). + +Find changes for the upcoming release in the project's [changelog.d directory](https://github.com/lsst-sqre/lsst-rsp/tree/main/changelog.d/). + + diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..3fd6377 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1 @@ +from documenteer.conf.guide import * diff --git a/docs/dev/development.rst b/docs/dev/development.rst new file mode 100644 index 0000000..480766f --- /dev/null +++ b/docs/dev/development.rst @@ -0,0 +1,157 @@ +################# +Development guide +################# + +This page provides procedures and guidelines for developing and contributing to lsst-rsp. + +Scope of contributions +====================== + +lsst-rsp is an open source package, meaning that you can contribute to lsst-rsp itself, or fork lsst-rsp for your own purposes. + +Since lsst-rsp is intended for internal use by Rubin Observatory, community contributions can only be accepted if they align with Rubin Observatory's aims. +For that reason, it's a good idea to propose changes with a new `GitHub issue`_ before investing time in making a pull request. + +lsst-rsp is developed by the Rubin Observatory SQuaRE team. + +.. _GitHub issue: https://github.com/lsst-sqre/lsst-rsp/issues/new + +.. _dev-environment: + +Setting up a local development environment +========================================== + +To develop lsst-rsp, create a virtual environment with your method of choice (like virtualenvwrapper) and then clone or fork, and install: + +.. code-block:: sh + + git clone https://github.com/lsst-sqre/lsst-rsp.git + cd lsst-rsp + make init + +This init step does three things: + +1. Installs lsst-rsp in an editable mode with its "dev" extra that includes test and documentation dependencies. +2. Installs pre-commit and tox. +3. Installs the pre-commit hooks. + +You must have Docker installed and configured so that your user can start Docker containers in order to run the test suite. + +.. _pre-commit-hooks: + +Pre-commit hooks +================ + +The pre-commit hooks, which are automatically installed by running the :command:`make init` command on :ref:`set up `, ensure that files are valid and properly formatted. +Some pre-commit hooks automatically reformat code: + +``isort`` + Automatically sorts imports in Python modules. + +``black`` + Automatically formats Python code. + +``blacken-docs`` + Automatically formats Python code in reStructuredText documentation and docstrings. + +When these hooks fail, your Git commit will be aborted. +To proceed, stage the new modifications and proceed with your Git commit. + +.. _dev-run-tests: + +Running tests +============= + +To test the library, run tox_, which tests the library the same way that the CI workflow does: + +.. code-block:: sh + + tox run + +To see a listing of test environments, run: + +.. code-block:: sh + + tox list + +To run a specific test or list of tests, you can add test file names (and any other pytest_ options) after ``--`` when executing the ``py`` tox environment. +For lsst-rsp: + +.. code-block:: sh + + tox run -e py -- tests/database_test.py + +.. _dev-build-docs: + +Building documentation +====================== + +Documentation is built with Sphinx_: + +.. _Sphinx: https://www.sphinx-doc.org/en/master/ + +.. code-block:: sh + + tox run -e docs + +The built documentation is located in the :file:`docs/_build/html` directory. + +.. _dev-change-log: + +Updating the change log +======================= + +lsst-rsp uses scriv_ to maintain its change log. + +When preparing a pull request, run :command:`scriv create`. +This will create a change log fragment in :file:`changelog.d`. +Edit that fragment, removing the sections that do not apply and adding entries fo this pull request. +You can pass the ``--edit`` flag to :command:`scriv create` to open the created fragment automatically in an editor. + +Change log entries use the following sections: + +.. rst-class:: compact + +- **Backward-incompatible changes** +- **New features** +- **Bug fixes** +- **Other changes** (for minor, patch-level changes that are not bug fixes, such as logging formatting changes or updates to the documentation) + +These entries will eventually be cut and pasted into the release description for the next release, so the Markdown for the change descriptions should be compatible with GitHub's Markdown conventions for the release description. +Specifically: + +- Each bullet point should be entirely on one line, even if it contains multiple sentences. + This is an exception to the normal documentation convention of a newline after each sentence. + Unfortunately, GitHub interprets those newlines as hard line breaks, so they would result in an ugly release description. +- Avoid using too much complex markup, such as nested bullet lists, since the formatting in the GitHub release description may not be what you expect and manually editing it is tedious. + +.. _style-guide: + +Style guide +=========== + +Code +---- + +- The code style follows :pep:`8`, though in practice lean on Black and isort to format the code for you. + +- Use :pep:`484` type annotations. + The ``tox run -e typing`` test environment, which runs mypy_, ensures that the project's types are consistent. + +- Write tests for Pytest_. + +Documentation +------------- + +- Follow the `LSST DM User Documentation Style Guide`_, which is primarily based on the `Google Developer Style Guide`_. + +- Document the Python API with numpydoc-formatted docstrings. + See the `LSST DM Docstring Style Guide`_. + +- Follow the `LSST DM ReStructuredTextStyle Guide`_. + In particular, ensure that prose is written **one-sentence-per-line** for better Git diffs. + +.. _`LSST DM User Documentation Style Guide`: https://developer.lsst.io/user-docs/index.html +.. _`Google Developer Style Guide`: https://developers.google.com/style/ +.. _`LSST DM Docstring Style Guide`: https://developer.lsst.io/python/style.html +.. _`LSST DM ReStructuredTextStyle Guide`: https://developer.lsst.io/restructuredtext/style.html diff --git a/docs/dev/index.rst b/docs/dev/index.rst new file mode 100644 index 0000000..00921a5 --- /dev/null +++ b/docs/dev/index.rst @@ -0,0 +1,13 @@ +:og:description: Learn how to contribute to the lsst-rsp open source project. + +############ +Contributing +############ + +Learn how to contribute to the lsst-rsp open source project. + +.. toctree:: + :caption: Guides + + development + release diff --git a/docs/dev/release.rst b/docs/dev/release.rst new file mode 100644 index 0000000..a7ae89b --- /dev/null +++ b/docs/dev/release.rst @@ -0,0 +1,103 @@ +################# +Release procedure +################# + +This page gives an overview of how lsst-rsp releases are made. +This information is only useful for maintainers. + +lsst-rsp's releases are largely automated through GitHub Actions (see the `ci.yaml`_ workflow file for details). +When a semantic version tag is pushed to GitHub, `lsst-rsp is released to PyPI`_ with that version. +Similarly, documentation is built and pushed for each version (see https://lsst-rsp.lsst.io/v). + +.. _`lsst-rsp is released to PyPI`: https://pypi.org/project/lsst-rsp/ +.. _`ci.yaml`: https://github.com/lsst-sqre/lsst-rsp/blob/main/.github/workflows/ci.yaml + +.. _regular-release: + +Regular releases +================ + +Regular releases happen from the ``main`` branch after changes have been merged. +From the ``main`` branch you can release a new major version (``X.0.0``), a new minor version of the current major version (``X.Y.0``), or a new patch of the current major-minor version (``X.Y.Z``). +See :ref:`backport-release` to patch an earlier major-minor version. + +Release tags are semantic version identifiers following the :pep:`440` specification. + +1. Change log and documentation +------------------------------- + +Change log messages for each release are accumulated using scriv_. +See :ref:`dev-change-log` in the *Developer guide* for more details. + +When it comes time to make the release, there should be a collection of change log fragments in :file:`changelog.d`. +Those fragments will make up the change log for the new release. + +Review those fragments to determine the version number of the next release. +Safir follows semver_, so follow its rules to pick the next version: + +.. rst-class:: compact + +- If there are any backward-incompatible changes, incremeent the major version number and set the other numbers to 0. +- If there are any new features, increment the minor version number and set the patch version to 0. +- Otherwise, increment the patch version number. + +Then, run ``scriv collect --version `` specifying the version number you decided on. +This will delete the fragment files and collect them into :file:`CHANGELOG.md` under an entry for the new release. +Review that entry and edit it as needed (proofread, change the order to put more important things first, etc.). +scriv will put blank lines between entries from different files. +You may wish to remove those blank lines to ensure consistent formatting by various Markdown parsers. + +Finally, create a PR from those changes and merge it before continuing with the release process. + +2. GitHub release and tag +------------------------- + +Use `GitHub's Release feature `__ to create releases and their corresponding Git tags. + +1. Specify a tag from the appropriate branch (typically ``main``). + This tag's name is :pep:`440` and is usually formatted at ``X.Y.Z`` (without a ``v`` prefix). + +2. For the release name, repeat the version string. + +3. Fill in the release notes, copied from the release notes. + You can use GitHub's change log feature to additionally generate a list of PRs included in the release. + +The tag **must** follow the :pep:`440` specification since lsst-rsp uses setuptools_scm_ to set version metadata based on Git tags. +In particular, **don't** prefix the tag with ``v``. + +.. _setuptools_scm: https://github.com/pypa/setuptools_scm + +The `ci.yaml`_ GitHub Actions workflow uploads the new release to PyPI and documentation to https://lsst-rsp.lsst.io. + +.. _backport-release: + +Backport releases +================= + +The regular release procedure works from the main line of development on the ``master`` Git branch. +To create a release that patches an earlier major or minor version, you need to release from a **release branch.** + +Creating a release branch +------------------------- + +Release branches are named after the major and minor components of the version string: ``X.Y``. +If the release branch doesn't already exist, check out the latest patch for that major-minor version: + +.. code-block:: sh + + git checkout X.Y.Z + git checkout -b X.Y + git push -u + +Developing on a release branch +------------------------------ + +Once a release branch exists, it becomes the "main" branch for patches of that major-minor version. +Pull requests should be based on, and merged into, the release branch. + +If the development on the release branch is a backport of commits on the ``main`` branch, use ``git cherry-pick`` to copy those commits into a new pull request against the release branch. + +Releasing from a release branch +------------------------------- + +Releases from a release branch are equivalent to :ref:`regular releases `, except that the release branch takes the role of the ``main`` branch. diff --git a/docs/documenteer.toml b/docs/documenteer.toml new file mode 100644 index 0000000..6840da6 --- /dev/null +++ b/docs/documenteer.toml @@ -0,0 +1,16 @@ +[project] +title = "lsst-rsp" +copyright = "2021-2023 Association of Universities for Research in Astronomy, Inc. (AURA)" + +[project.python] +package = "lsst-rsp" + +[sphinx] +rst_epilog_file = "_rst_epilog.rst" +disable_primary_sidebars = [ + "index", + "changelog", +] + +[sphinx.intersphinx.projects] +python = "https://docs.python.org/3/" diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..f08f91a --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,24 @@ +:og:description: Short one-sentence description of the package +:html_theme.sidebar_secondary.remove: + +####### +lsst-rsp +####### + +Short one-sentence description of the package + +Install lsst-rsp from PyPI: + +.. code-block:: bash + + pip install lsst-rsp + +lsst-rsp is developed on GitHub at https://github.com/lsst-sqre/lsst-rsp. + +.. toctree:: + :hidden: + + User guide + API + Change log + Contributing diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst new file mode 100644 index 0000000..6adec7d --- /dev/null +++ b/docs/user-guide/index.rst @@ -0,0 +1,9 @@ +:og:description: Learn how to use lsst-rsp. + +########## +User guide +########## + +.. .. toctree:: +.. :maxdepth: 2 +.. .. :titlesonly: diff --git a/pyproject.toml b/pyproject.toml index 090da21..8e0146c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,20 +1,83 @@ +[project] +# https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ +name = "lsst-rsp" +description = "Short one-sentence description of the package" +license = {file = "LICENSE"} +readme= "README.md" +keywords = [ + "rubin", + "lsst", +] +# https://pypi.org/classifiers/ +classifiers = [ + "Development Status :: 4 - Beta", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Intended Audience :: Developers", + "Natural Language :: English", + "Operating System :: POSIX", + "Typing :: Typed", +] +requires-python = ">=3.11" +dependencies = [] +dynamic = ["version"] + +[project.optional-dependencies] +dev = [ + # Testing + "coverage[toml]", + "pytest", + "pytest-asyncio", + "pre-commit", + "mypy", + # Documentation + "documenteer[guide]<1", + "scriv", +] + +[project.urls] +Homepage = "https://lsst-rsp.lsst.io" +Source = "https://github.com/lsst-sqre/lsst-rsp" + [build-system] requires = [ - "setuptools>=42", + "setuptools>=61", "wheel", - "setuptools_scm[toml]>=3.4", - "isort", - "black", - "pre-commit" + "setuptools_scm[toml]>=6.2" ] -build-backend = 'setuptools.build_meta' +build-backend = "setuptools.build_meta" [tool.setuptools_scm] +[tool.setuptools.packages.find] +# https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html +where = ["src"] +include = ["lsst-rsp*"] + +[tool.black] +line-length = 79 +target-version = ["py38"] +exclude = ''' +/( + \.eggs + | \.git + | \.mypy_cache + | \.tox + | \.venv + | _build + | build + | dist +)/ +''' +# Use single-quoted strings so TOML treats the string like a Python r-string +# Multi-line strings are implicitly treated by black as regular expressions + [tool.coverage.run] parallel = true branch = true -source = ["src"] +source = ["lsst-rsp"] [tool.coverage.paths] source = ["src", ".tox/*/site-packages"] @@ -33,39 +96,155 @@ exclude_lines = [ "if TYPE_CHECKING:" ] -[tool.black] -line-length = 79 -target-version = ['py310'] -exclude = ''' -/( - \.eggs - | \.git - | \.mypy_cache - | \.tox - | \.venv - | _build - | build - | dist -)/ -''' -# Use single-quoted strings so TOML treats the string like a Python r-string -# Multi-line strings are implicitly treated by black as regular expressions - [tool.isort] -include_trailing_comma = true -multi_line_output = 3 -known_first_party = ["rsp", "tests"] +profile = "black" +line_length = 79 +known_first_party = ["lsst-rsp", "tests"] skip = ["docs/conf.py"] -[tool.pytest.ini_options] -filterwarnings = [ - # Bug in pyvo - "ignore:Using or importing the ABCs:DeprecationWarning", - # Bugs in aiojobs - "ignore:The loop argument is deprecated:DeprecationWarning" +[tool.mypy] +disallow_untyped_defs = true +disallow_incomplete_defs = true +ignore_missing_imports = true +local_partial_types = true +no_implicit_reexport = true +strict_equality = true +warn_redundant_casts = true +warn_unreachable = true +warn_unused_ignores = true +# plugins = + +[tool.pydocstyle] +# Reference: http://www.pydocstyle.org/en/stable/error_codes.html +convention = "numpy" +add_select = [ + "D212" # Multi-line docstring summary should start at the first line ] +add-ignore = [ + "D105", # Missing docstring in magic method + "D102", # Missing docstring in public method (needed for docstring inheritance) + "D100", # Missing docstring in public module + # Below are required to allow multi-line summaries. + "D200", # One-line docstring should fit on one line with quotes + "D205", # 1 blank line required between summary line and description + "D400", # First line should end with a period + # Properties shouldn't be written in imperative mode. This will be fixed + # post 6.1.1, see https://github.com/PyCQA/pydocstyle/pull/546 + "D401", +] + +[tool.pytest.ini_options] +asyncio_mode = "strict" python_files = [ "tests/*.py", "tests/*/*.py" ] +# The rule used with Ruff configuration is to disable every lint that has +# legitimate exceptions that are not dodgy code, rather than cluttering code +# with noqa markers. This is therefore a reiatively relaxed configuration that +# errs on the side of disabling legitimate lints. +# +# Reference for settings: https://beta.ruff.rs/docs/settings/ +# Reference for rules: https://beta.ruff.rs/docs/rules/ +[tool.ruff] +exclude = [ + "docs/**", +] +line-length = 79 +ignore = [ + "ANN101", # self should not have a type annotation + "ANN102", # cls should not have a type annotation + "ANN401", # sometimes Any is the right type + "ARG001", # unused function arguments are often legitimate + "ARG002", # unused method arguments are often legitimate + "ARG005", # unused lambda arguments are often legitimate + "BLE001", # we want to catch and report Exception in background tasks + "C414", # nested sorted is how you sort by multiple keys with reverse + "COM812", # omitting trailing commas allows black autoreformatting + "D102", # sometimes we use docstring inheritence + "D104", # don't see the point of documenting every package + "D105", # our style doesn't require docstrings for magic methods + "D106", # Pydantic uses a nested Config class that doesn't warrant docs + "EM101", # justification (duplicate string in traceback) is silly + "EM102", # justification (duplicate string in traceback) is silly + "FBT003", # positional booleans are normal for Pydantic field defaults + "G004", # forbidding logging f-strings is appealing, but not our style + "RET505", # disagree that omitting else always makes code more readable + "PLR0913", # factory pattern uses constructors with many arguments + "PLR2004", # too aggressive about magic values + "S105", # good idea but too many false positives on non-passwords + "S106", # good idea but too many false positives on non-passwords + "SIM102", # sometimes the formatting of nested if statements is clearer + "SIM117", # sometimes nested with contexts are clearer + "TCH001", # we decided to not maintain separate TYPE_CHECKING blocks + "TCH002", # we decided to not maintain separate TYPE_CHECKING blocks + "TCH003", # we decided to not maintain separate TYPE_CHECKING blocks + "TID252", # if we're going to use relative imports, use them always + "TRY003", # good general advice but lint is way too aggressive +] +select = ["ALL"] +target-version = "py311" + +[tool.ruff.per-file-ignores] +"src/lsst-rsp/handlers/**" = [ + "D103", # FastAPI handlers should not have docstrings +] +"tests/**" = [ + "D103", # tests don't need docstrings + "PLR0915", # tests are allowed to be long, sometimes that's convenient + "PT012", # way too aggressive about limiting pytest.raises blocks + "S101", # tests should use assert + "SLF001", # tests are allowed to access private members +] + +[tool.ruff.isort] +known-first-party = ["lsst-rsp", "tests"] +split-on-trailing-comma = false + +[tool.ruff.flake8-bugbear] +extend-immutable-calls = [ + "fastapi.Form", + "fastapi.Header", + "fastapi.Depends", + "fastapi.Path", + "fastapi.Query", +] + +# These are too useful as attributes or methods to allow the conflict with the +# built-in to rule out their use. +[tool.ruff.flake8-builtins] +builtins-ignorelist = [ + "all", + "any", + "help", + "id", + "list", + "type", +] + +[tool.ruff.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.pep8-naming] +classmethod-decorators = [ + "pydantic.root_validator", + "pydantic.validator", +] + +[tool.ruff.pydocstyle] +convention = "numpy" + +[tool.scriv] +categories = [ + "Backwards-incompatible changes", + "New features", + "Bug fixes", + "Other changes", +] +entry_title_template = "{{ version }} ({{ date.strftime('%Y-%m-%d') }})" +format = "md" +md_header_level = "2" +new_fragment_template = "file:changelog.d/_template.md.jinja" +skip_fragments = "_template.md.jinja" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index e002362..0000000 --- a/setup.cfg +++ /dev/null @@ -1,68 +0,0 @@ -[metadata] -name = lsst-rsp -description = User-facing classes and functions for RSP notebooks -author = Association of Universities for Research in Astronomy, Inc. (AURA) -author_email = sqre-admin@lists.lsst.org -long_description = file: README.rst, LICENSE -long_description_content_type = text/x-rst -url = https://github.com/lsst-sqre/lsst-rsp -project_urls = - Source code = https://github.com/lsst-sqre/lsst-rsp - Issue tracker = https://github.com/lsst-sqre/lsst-rsp/issues -classifiers = - Development Status :: 4 - Beta - License :: OSI Approved :: MIT License - Programming Language :: Python - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.10 - Natural Language :: English - Operating System :: POSIX -keywords = - lsst - -[options] -zip_safe = False -include_package_data = True -package_dir = - = src -packages=find: -python_requires = >=3.10 -setup_requires = - setuptools_scm -install_requires = - bokeh - deprecated - kubernetes - maproxy - notebook - pyvo @ git+https://github.com/astropy/pyvo.git@7682a1809cb2169cc2ffd9313feb6a4abd7f7e37 - requests - tornado - -[options.extras_require] -dev = - coverage[toml] - mypy - pytest - pytest-cov - types-requests - types-Deprecated - -[options.packages.find] -where = src - -[flake8] -max-line-length = 79 -# E203: whitespace before :, flake8 disagrees with PEP-8 -# W503: line break after binary operator, flake8 disagrees with PEP-8 -ignore = E203, W503 - -[mypy] -disallow_untyped_defs = True -disallow_incomplete_defs = True -ignore_missing_imports = True -show_error_codes = True -strict_equality = True -warn_redundant_casts = True -warn_unreachable = True -warn_unused_ignores = True diff --git a/setup.py b/setup.py deleted file mode 100644 index d5d43d7..0000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup(use_scm_version=True) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..d8c4dfb --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +"""Tests and test support modules.""" + +# This __init__.py file enables test modules to import support code +# inside tests/ diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..898ca87 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1 @@ +"""Pytest configuration and fixtures.""" diff --git a/tests/version_test.py b/tests/version_test.py new file mode 100644 index 0000000..3da5ccd --- /dev/null +++ b/tests/version_test.py @@ -0,0 +1,12 @@ +"""Test the packaging.""" + +from __future__ import annotations + +from example import __version__ + + +def test_version() -> None: + """Ensure that the version is set.""" + assert isinstance(__version__, str) + # Indicates the package is not installed otherwise + assert __version__ != "0.0.0" diff --git a/tox.ini b/tox.ini index d10fe15..b401f35 100644 --- a/tox.ini +++ b/tox.ini @@ -1,13 +1,16 @@ [tox] -envlist = py,coverage-report,typing,lint +envlist = py,coverage-report,typing,lint,docs,docs-linkcheck isolated_build = True [testenv] description = Run pytest against {envname}. extras = dev + +[testenv:py] +description = Run pytest commands = - pytest --cov=lsst.rsp --cov-branch --cov-report= {posargs} + coverage run -m pytest {posargs} [testenv:coverage-report] description = Compile coverage from each test run. @@ -15,12 +18,14 @@ skip_install = true deps = coverage[toml]>=5.0.2 depends = py -commands = coverage report +commands = + coverage combine + coverage report [testenv:typing] description = Run mypy. commands = - mypy src/lsst/rsp tests setup.py + mypy src/lsst-rsp tests [testenv:lint] description = Lint codebase by running pre-commit (Black, isort, Flake8). @@ -28,3 +33,15 @@ skip_install = true deps = pre-commit commands = pre-commit run --all-files + +[testenv:docs] +description = Build documentation (HTML) with Sphinx. +commands = + sphinx-build --keep-going -n -W -T -b html -d {envtmpdir}/doctrees docs docs/_build/html + +[testenv:docs-linkcheck] +description = Check links in the documentation. +allowlist_externals = + make +commands = + make linkcheck From 2ab3705c51901119d2d8e105615d827bc60c9947 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 14:51:18 -0700 Subject: [PATCH 02/10] Move to modern python machinery framework; remove deprecated/broken functions --- .flake8 | 7 ++ docs/index.rst | 4 +- pyproject.toml | 12 ++- src/jupyterlabutils/__init__.py | 8 -- src/jupyterlabutils/notebook/__init__.py | 13 --- src/lsst/rsp/__init__.py | 5 +- src/lsst/rsp/forwarder.py | 51 ------------ src/lsst/rsp/log.py | 6 +- src/lsst/rsp/utils.py | 83 +++---------------- src/rubin_jupyter_utils/__init__.py | 0 src/rubin_jupyter_utils/lab/__init__.py | 3 - .../lab/notebook/__init__.py | 57 ------------- .../lab/notebook/utils/__init__.py | 8 -- tests/version_test.py | 2 +- tox.ini | 2 +- 15 files changed, 37 insertions(+), 224 deletions(-) create mode 100644 .flake8 delete mode 100644 src/jupyterlabutils/__init__.py delete mode 100644 src/jupyterlabutils/notebook/__init__.py delete mode 100644 src/lsst/rsp/forwarder.py delete mode 100644 src/rubin_jupyter_utils/__init__.py delete mode 100644 src/rubin_jupyter_utils/lab/__init__.py delete mode 100644 src/rubin_jupyter_utils/lab/notebook/__init__.py delete mode 100644 src/rubin_jupyter_utils/lab/notebook/utils/__init__.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..01ee522 --- /dev/null +++ b/.flake8 @@ -0,0 +1,7 @@ +[flake8] +max-line-length = 79 +# E203: whitespace before :, flake8 disagrees with PEP-8 +# W503: line break after binary operator, flake8 disagrees with PEP-8 +ignore = E203, W503 +exclude = + docs/conf.py diff --git a/docs/index.rst b/docs/index.rst index f08f91a..e3890ae 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,9 +1,9 @@ :og:description: Short one-sentence description of the package :html_theme.sidebar_secondary.remove: -####### +######## lsst-rsp -####### +######## Short one-sentence description of the package diff --git a/pyproject.toml b/pyproject.toml index 8e0146c..4c8f521 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,11 +21,19 @@ classifiers = [ "Typing :: Typed", ] requires-python = ">=3.11" -dependencies = [] +dependencies = [ + "bokeh", + "Deprecated", + "IPython", + "pyvo" +] dynamic = ["version"] [project.optional-dependencies] dev = [ + # Typing + "types-deprecated", + "types-requests", # Testing "coverage[toml]", "pytest", @@ -77,7 +85,7 @@ exclude = ''' [tool.coverage.run] parallel = true branch = true -source = ["lsst-rsp"] +source = ["lsst"] [tool.coverage.paths] source = ["src", ".tox/*/site-packages"] diff --git a/src/jupyterlabutils/__init__.py b/src/jupyterlabutils/__init__.py deleted file mode 100644 index 7ee132d..0000000 --- a/src/jupyterlabutils/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from deprecated import deprecated - -import lsst.rsp - - -@deprecated(reason="Please use lsst.rsp.show_with_bokeh_server()") -def show_with_bokeh_server(obj): - return lsst.rsp.show_with_bokeh_server(obj) diff --git a/src/jupyterlabutils/notebook/__init__.py b/src/jupyterlabutils/notebook/__init__.py deleted file mode 100644 index 3faaf6e..0000000 --- a/src/jupyterlabutils/notebook/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from deprecated import deprecated - -import lsst.rsp - - -@deprecated(reason="Please use lsst.rsp.get_tap_service()") -def get_catalog(): - return lsst.rsp.get_tap_service() - - -@deprecated(reason="Please use lsst.rsp.retrieve_query()") -def retrieve_query(query_url): - return lsst.rsp.retrieve_query(query_url) diff --git a/src/lsst/rsp/__init__.py b/src/lsst/rsp/__init__.py index b263515..f5bccbc 100644 --- a/src/lsst/rsp/__init__.py +++ b/src/lsst/rsp/__init__.py @@ -1,5 +1,4 @@ -""" -Collection of utilities, formerly in rsp_jupyter_utils.lab and +"""Collection of utilities, formerly in rsp_jupyter_utils.lab and rsp_jupyter_utils.helper """ from importlib.metadata import PackageNotFoundError, version @@ -10,7 +9,6 @@ get_tap_service, retrieve_query, ) -from .forwarder import Forwarder from .log import IPythonHandler, forward_lsst_log from .service import get_datalink_result, get_siav2_service from .utils import ( @@ -35,7 +33,6 @@ __all__ = [ "__version__", - "Forwarder", "IPythonHandler", "format_bytes", "forward_lsst_log", diff --git a/src/lsst/rsp/forwarder.py b/src/lsst/rsp/forwarder.py deleted file mode 100644 index e0978ea..0000000 --- a/src/lsst/rsp/forwarder.py +++ /dev/null @@ -1,51 +0,0 @@ -import logging -from typing import Any, List, Optional - -import maproxy.iomanager -import maproxy.proxyserver -import tornado.netutil - - -class Forwarder(maproxy.proxyserver.ProxyServer): - """This creates a TCP proxy server running on a randomly-assigned - dynamic local port. Pass it the target host and port to construct it. - """ - - _ioloop = None - _thread = None - _logger = None - _bind_addresses: List[Any] = [] # Fix this when we correct typing. - - def __init__(self, *args: Any, **kwargs: Any) -> None: - self._logger = logging.getLogger(__name__) - self._logger.debug("Creating TCP Forwarder") - sockets = tornado.netutil.bind_sockets(0, "") - ioloop = None - save_ioloop = None - if "ioloop" in kwargs: - self._logger.debug("IOLoop specified; saving current") - ioloop = kwargs["ioloop"] - save_ioloop = tornado.ioloop.IOLoop.current() - if ioloop != save_ioloop: - self._logger.debug("Switching IOLoop") - ioloop.make_current() - del kwargs["ioloop"] - super().__init__(*args, **kwargs) - self.add_sockets(sockets) - self.bind_addresses = [x.getsockname()[:2] for x in sockets] - self._ioloop = tornado.ioloop.IOLoop.current() - if save_ioloop and save_ioloop != self._ioloop: - self._logger.debug("Restoring IOLoop") - save_ioloop.make_current() - self._logger.debug("TCP Forwarder created") - - def get_ports(self) -> List[Any]: - """Returns a list of the ports the Forwarder is listening to.""" - return list(set(x[1] for x in self.bind_addresses)) - - def get_port(self) -> Optional[int]: - """Returns the first port the Forwarder is listening to, or None.""" - rval = self.get_ports() - if rval and len(rval) > 0: - return rval[0] - return None diff --git a/src/lsst/rsp/log.py b/src/lsst/rsp/log.py index 5d53f99..3bf0304 100644 --- a/src/lsst/rsp/log.py +++ b/src/lsst/rsp/log.py @@ -50,8 +50,9 @@ class IPythonHandler(logging.Handler): * The message itself. It can be enabled (forcing other log handlers to be removed) with: .. code-block:: python - logging.basicConfig(level=logging.INFO, force=True, - handlers=[IPythonHandler()]) + logging.basicConfig( + level=logging.INFO, force=True, handlers=[IPythonHandler()] + ) """ def emit(self, record: logging.LogRecord) -> None: @@ -88,6 +89,7 @@ def emit(self, record: logging.LogRecord) -> None: def forward_lsst_log(level: str) -> None: """Forward ``lsst.log`` level messages to Python logging. + Parameters ---------- level : `str` diff --git a/src/lsst/rsp/utils.py b/src/lsst/rsp/utils.py index b6cf32d..20949c4 100644 --- a/src/lsst/rsp/utils.py +++ b/src/lsst/rsp/utils.py @@ -6,17 +6,7 @@ from typing import Any, Optional, Union import bokeh.io -import pyvo.auth.authsession -import requests - -_NO_K8S = False - -try: - from kubernetes import client, config - from kubernetes.client.rest import ApiException - from kubernetes.config.config_exception import ConfigException -except ImportError: - _NO_K8S = True +from deprecated import deprecated def format_bytes(n: int) -> str: @@ -104,8 +94,7 @@ def show_with_bokeh_server(obj: Any) -> None: """Method to wrap bokeh with proxy URL""" def jupyter_proxy_url(port: Optional[int] = None) -> str: - """ - Callable to configure Bokeh's show method when a proxy must be + """Callable to configure Bokeh's show method when a proxy must be configured. If port is None we're asking about the URL @@ -131,38 +120,14 @@ def jupyter_proxy_url(port: Optional[int] = None) -> str: bokeh.io.show(obj=obj, notebook_url=jupyter_proxy_url) -def get_pod() -> Optional[client.V1Pod]: - """Get the Kubernetes object for the pod in which this is running. - - Returns - ------- - kubernetes.client.V1Pod or None - Kubernetes object for the pod in which this code is running, or `None` - if not running inside Kubernetes or running without access to the - Kubernetes API (the normal case for Nublado v3 and later). +@deprecated( + reason="get_pod() always returns None in RSPs running Nubladov3 or later" +) +def get_pod() -> None: + """No longer useful. Formerly used to return the Kubernetes object for + the pod in which this code was running. """ - if _NO_K8S: - return None - try: - config.load_incluster_config() - except ConfigException: - # We have the K8S libraries, but we don't have in-cluster config. - return None - api = client.CoreV1Api() - namespace = "default" - try: - with open( - "/var/run/secrets/kubernetes.io/serviceaccount/namespace", "r" - ) as f: - namespace = f.readlines()[0] - except FileNotFoundError: - pass # use 'default' as namespace - try: - pod = api.read_namespaced_pod(get_hostname(), namespace) - except ApiException: - # Well, that didn't work. - return None - return pod + return None def get_node() -> str: @@ -174,17 +139,7 @@ def get_node() -> str: Name of the Kubernetes node on which this code is running, or the empty string if the node could not be determined. """ - node = os.environ.get("KUBERNETES_NODE_NAME") - if node: - return node - - # Fallback for Nublado v2, which got this information from the Kubernetes - # API (and therefore had to have access to the Kubernetes API). - pod = get_pod() - if pod is not None: - return pod.spec.node_name - else: - return "" + return os.environ.get("KUBERNETES_NODE_NAME", "") def get_digest() -> str: @@ -196,23 +151,7 @@ def get_digest() -> str: Digest of the Docker image this code is running inside, or the empty string if the digest could not be determined. """ - reference = os.environ.get("JUPYTER_IMAGE_SPEC", "") - - # Fallback for Nublado v2, which got this information from the Kubernetes - # API (and therefore had to have access to the Kubernetes API). - if not reference: - pod = get_pod() - if pod: - try: - reference = pod.status.container_statuses[0].image_id - except Exception: - pass - - try: - # Reference looks like host/[project/]owner/repo@sha256:hash - return (reference.split("@")[-1]).split(":")[-1] - except Exception: - return "" + return os.environ.get("JUPYTER_IMAGE_SPEC", "") def get_access_token( diff --git a/src/rubin_jupyter_utils/__init__.py b/src/rubin_jupyter_utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/rubin_jupyter_utils/lab/__init__.py b/src/rubin_jupyter_utils/lab/__init__.py deleted file mode 100644 index 4fc1ad1..0000000 --- a/src/rubin_jupyter_utils/lab/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .notebook import show_with_bokeh_server - -all = [show_with_bokeh_server] diff --git a/src/rubin_jupyter_utils/lab/notebook/__init__.py b/src/rubin_jupyter_utils/lab/notebook/__init__.py deleted file mode 100644 index 2d12322..0000000 --- a/src/rubin_jupyter_utils/lab/notebook/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -"""All of this stuff moved between JL2 and JL3. Export these functions and -methods again, but with deprecated warnings so people know how to use them -correctly. -""" -from deprecated import deprecated - -import lsst.rsp - -from .utils import get_node - - -@deprecated(reason="Please use lsst.rsp.format_bytes()") -def format_bytes(n): - return lsst.rsp.format_bytes(n) - - -@deprecated(reason="Please use lsst.rsp.get_tap_service()") -def get_catalog(): - return lsst.rsp.get_tap_service() - - -@deprecated(reason="Please use lsst.rsp.get_tap_service()") -def get_tap_service(): - return lsst.rsp.get_tap_service() - - -@deprecated(reason="Please use lsst.rsp.retrieve_query()") -def retrieve_query(query_url): - return lsst.rsp.retrieve_query(query_url) - - -@deprecated(reason="Please use lsst.rsp.get_hostname()") -def get_hostname(): - return lsst.rsp.get_hostname() - - -@deprecated(reason="Please use lsst.rsp.show_with_bokeh_server()") -def show_with_bokeh_server(obj): - return lsst.rsp.show_with_bokeh_server(obj) - - -@deprecated(reason="Please use lsst.rsp.Forwarder") -class Forwarder(lsst.rsp.Forwarder): - def __init__(self, args, **kwargs): - return super().__init__() - - -__all__ = [ - Forwarder, - format_bytes, - get_catalog, - get_node, - get_tap_service, - retrieve_query, - get_hostname, - show_with_bokeh_server, -] diff --git a/src/rubin_jupyter_utils/lab/notebook/utils/__init__.py b/src/rubin_jupyter_utils/lab/notebook/utils/__init__.py deleted file mode 100644 index 14a5b48..0000000 --- a/src/rubin_jupyter_utils/lab/notebook/utils/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from deprecated import deprecated - -import lsst.rsp - - -@deprecated(reason="Please use lsst.rsp.get_node()") -def get_node(): - return lsst.rsp.get_node() diff --git a/tests/version_test.py b/tests/version_test.py index 3da5ccd..cc2d32b 100644 --- a/tests/version_test.py +++ b/tests/version_test.py @@ -2,7 +2,7 @@ from __future__ import annotations -from example import __version__ +from lsst.rsp import __version__ def test_version() -> None: diff --git a/tox.ini b/tox.ini index b401f35..e1a091d 100644 --- a/tox.ini +++ b/tox.ini @@ -25,7 +25,7 @@ commands = [testenv:typing] description = Run mypy. commands = - mypy src/lsst-rsp tests + mypy src/lsst tests [testenv:lint] description = Lint codebase by running pre-commit (Black, isort, Flake8). From 0d45ab41b31abf6af525bf55c18f4880f3d896bb Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 15:11:32 -0700 Subject: [PATCH 03/10] Add some docstrings to make the linter happy. --- src/lsst/__init__.py | 1 + src/lsst/rsp/catalog.py | 3 +++ tests/utils_test.py | 1 + 3 files changed, 5 insertions(+) diff --git a/src/lsst/__init__.py b/src/lsst/__init__.py index f77af49..15b3e36 100644 --- a/src/lsst/__init__.py +++ b/src/lsst/__init__.py @@ -1,3 +1,4 @@ +"""pkgutil-style namespace package""" import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) diff --git a/src/lsst/rsp/catalog.py b/src/lsst/rsp/catalog.py index 6e11b8c..ff07c33 100644 --- a/src/lsst/rsp/catalog.py +++ b/src/lsst/rsp/catalog.py @@ -8,11 +8,13 @@ @deprecated(reason='Please use get_tap_service("tap")') def get_catalog() -> pyvo.dal.TAPService: + """Deprecated alias for get_tap_service("tap")""" return get_tap_service("tap") @deprecated(reason='Please use get_tap_service("live")') def get_obstap_service() -> pyvo.dal.TAPService: + """Deprecated alias for get_tap_service("tap")""" return get_tap_service("live") @@ -54,6 +56,7 @@ def get_tap_service(*args: str) -> pyvo.dal.TAPService: def retrieve_query(query_url: str) -> pyvo.dal.AsyncTAPJob: + """Retrieve job corresponding to a particular query URL.""" # # This is not ideal, but warning appears because require pyvo does # not register uws:Sync and uws:Async. It's harmless. The broadness diff --git a/tests/utils_test.py b/tests/utils_test.py index 3aa3ceb..2b9102f 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -6,6 +6,7 @@ def test_format_bytes() -> None: + """Test human-readable names for numeric byte inputs.""" assert format_bytes(1) == "1 B" assert format_bytes(1234) == "1.23 kB" assert format_bytes(12345678) == "12.35 MB" From cfe6ba71349a14b24de6f15cdc2106c6e1358465 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 15:17:29 -0700 Subject: [PATCH 04/10] Add .DS_Store to .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2afcff0..ba527ab 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,6 @@ dmypy.json # Pyre type checker .pyre/ + +# MacOS desktop +.DS_Store From 099048d42f92d070d5d746082de4b7d3b8cec170 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 15:17:49 -0700 Subject: [PATCH 05/10] Remove incorrectly-added .DS_Store file --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index dbe171e5e2faf85c0cbf4336c40fe4b89c018e03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKyGjE=6g`uyxEh2MDJ&NxU?l|X-Gmji&IhP@kO&D0CMoQ;3>dKRI}{sh8^zKz zwl@BRMGEho8O@BFXcI)jT)1;)=RWs@oyh}^J=GVM>Zf*2fwC%MY z?cJuaH*Ab46swXV>&6w$-frmftJfC?1S>^WA5ASoPKK!#y}z z90Nk7@-vG|=`uM690Nw=imSB zAot`La11OJ1Hy~SQHfqjpRI|P7UPCaDy%1w0`PHO2~Q Rg~a_4kTkf#G4Q7hd;spBs>=WX From 0b9e9adef926783a2633108edf5622037c7d78ea Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 15:46:12 -0700 Subject: [PATCH 06/10] Remove docs for now --- docs/.gitignore | 2 - docs/_rst_epilog.rst | 7 -- docs/api.rst | 8 -- docs/changelog.md | 7 -- docs/conf.py | 1 - docs/dev/development.rst | 157 -------------------------------------- docs/dev/index.rst | 13 ---- docs/dev/release.rst | 103 ------------------------- docs/documenteer.toml | 16 ---- docs/index.rst | 24 ------ docs/user-guide/index.rst | 9 --- pyproject.toml | 5 -- tox.ini | 13 +--- 13 files changed, 1 insertion(+), 364 deletions(-) delete mode 100644 docs/.gitignore delete mode 100644 docs/_rst_epilog.rst delete mode 100644 docs/api.rst delete mode 100644 docs/changelog.md delete mode 100644 docs/conf.py delete mode 100644 docs/dev/development.rst delete mode 100644 docs/dev/index.rst delete mode 100644 docs/dev/release.rst delete mode 100644 docs/documenteer.toml delete mode 100644 docs/index.rst delete mode 100644 docs/user-guide/index.rst diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index 3c1f3b5..0000000 --- a/docs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -_build -api diff --git a/docs/_rst_epilog.rst b/docs/_rst_epilog.rst deleted file mode 100644 index afd04ce..0000000 --- a/docs/_rst_epilog.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _Click: https://click.palletsprojects.com/ -.. _mypy: http://www.mypy-lang.org -.. _pre-commit: https://pre-commit.com -.. _pytest: https://docs.pytest.org/en/latest/ -.. _scriv: https://scriv.readthedocs.io/en/stable/ -.. _semver: https://semver.org/ -.. _tox: https://tox.wiki/en/latest/ diff --git a/docs/api.rst b/docs/api.rst deleted file mode 100644 index b47bd9b..0000000 --- a/docs/api.rst +++ /dev/null @@ -1,8 +0,0 @@ -:og:description: Comprehensive API documentation for lsst-rsp. - -#################### -Python API reference -#################### - -.. automodapi:: lsst-rsp - :include-all-objects: diff --git a/docs/changelog.md b/docs/changelog.md deleted file mode 100644 index fad52c1..0000000 --- a/docs/changelog.md +++ /dev/null @@ -1,7 +0,0 @@ -# Change log - -lsst-rsp is versioned with [semver](https://semver.org/). - -Find changes for the upcoming release in the project's [changelog.d directory](https://github.com/lsst-sqre/lsst-rsp/tree/main/changelog.d/). - - diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 3fd6377..0000000 --- a/docs/conf.py +++ /dev/null @@ -1 +0,0 @@ -from documenteer.conf.guide import * diff --git a/docs/dev/development.rst b/docs/dev/development.rst deleted file mode 100644 index 480766f..0000000 --- a/docs/dev/development.rst +++ /dev/null @@ -1,157 +0,0 @@ -################# -Development guide -################# - -This page provides procedures and guidelines for developing and contributing to lsst-rsp. - -Scope of contributions -====================== - -lsst-rsp is an open source package, meaning that you can contribute to lsst-rsp itself, or fork lsst-rsp for your own purposes. - -Since lsst-rsp is intended for internal use by Rubin Observatory, community contributions can only be accepted if they align with Rubin Observatory's aims. -For that reason, it's a good idea to propose changes with a new `GitHub issue`_ before investing time in making a pull request. - -lsst-rsp is developed by the Rubin Observatory SQuaRE team. - -.. _GitHub issue: https://github.com/lsst-sqre/lsst-rsp/issues/new - -.. _dev-environment: - -Setting up a local development environment -========================================== - -To develop lsst-rsp, create a virtual environment with your method of choice (like virtualenvwrapper) and then clone or fork, and install: - -.. code-block:: sh - - git clone https://github.com/lsst-sqre/lsst-rsp.git - cd lsst-rsp - make init - -This init step does three things: - -1. Installs lsst-rsp in an editable mode with its "dev" extra that includes test and documentation dependencies. -2. Installs pre-commit and tox. -3. Installs the pre-commit hooks. - -You must have Docker installed and configured so that your user can start Docker containers in order to run the test suite. - -.. _pre-commit-hooks: - -Pre-commit hooks -================ - -The pre-commit hooks, which are automatically installed by running the :command:`make init` command on :ref:`set up `, ensure that files are valid and properly formatted. -Some pre-commit hooks automatically reformat code: - -``isort`` - Automatically sorts imports in Python modules. - -``black`` - Automatically formats Python code. - -``blacken-docs`` - Automatically formats Python code in reStructuredText documentation and docstrings. - -When these hooks fail, your Git commit will be aborted. -To proceed, stage the new modifications and proceed with your Git commit. - -.. _dev-run-tests: - -Running tests -============= - -To test the library, run tox_, which tests the library the same way that the CI workflow does: - -.. code-block:: sh - - tox run - -To see a listing of test environments, run: - -.. code-block:: sh - - tox list - -To run a specific test or list of tests, you can add test file names (and any other pytest_ options) after ``--`` when executing the ``py`` tox environment. -For lsst-rsp: - -.. code-block:: sh - - tox run -e py -- tests/database_test.py - -.. _dev-build-docs: - -Building documentation -====================== - -Documentation is built with Sphinx_: - -.. _Sphinx: https://www.sphinx-doc.org/en/master/ - -.. code-block:: sh - - tox run -e docs - -The built documentation is located in the :file:`docs/_build/html` directory. - -.. _dev-change-log: - -Updating the change log -======================= - -lsst-rsp uses scriv_ to maintain its change log. - -When preparing a pull request, run :command:`scriv create`. -This will create a change log fragment in :file:`changelog.d`. -Edit that fragment, removing the sections that do not apply and adding entries fo this pull request. -You can pass the ``--edit`` flag to :command:`scriv create` to open the created fragment automatically in an editor. - -Change log entries use the following sections: - -.. rst-class:: compact - -- **Backward-incompatible changes** -- **New features** -- **Bug fixes** -- **Other changes** (for minor, patch-level changes that are not bug fixes, such as logging formatting changes or updates to the documentation) - -These entries will eventually be cut and pasted into the release description for the next release, so the Markdown for the change descriptions should be compatible with GitHub's Markdown conventions for the release description. -Specifically: - -- Each bullet point should be entirely on one line, even if it contains multiple sentences. - This is an exception to the normal documentation convention of a newline after each sentence. - Unfortunately, GitHub interprets those newlines as hard line breaks, so they would result in an ugly release description. -- Avoid using too much complex markup, such as nested bullet lists, since the formatting in the GitHub release description may not be what you expect and manually editing it is tedious. - -.. _style-guide: - -Style guide -=========== - -Code ----- - -- The code style follows :pep:`8`, though in practice lean on Black and isort to format the code for you. - -- Use :pep:`484` type annotations. - The ``tox run -e typing`` test environment, which runs mypy_, ensures that the project's types are consistent. - -- Write tests for Pytest_. - -Documentation -------------- - -- Follow the `LSST DM User Documentation Style Guide`_, which is primarily based on the `Google Developer Style Guide`_. - -- Document the Python API with numpydoc-formatted docstrings. - See the `LSST DM Docstring Style Guide`_. - -- Follow the `LSST DM ReStructuredTextStyle Guide`_. - In particular, ensure that prose is written **one-sentence-per-line** for better Git diffs. - -.. _`LSST DM User Documentation Style Guide`: https://developer.lsst.io/user-docs/index.html -.. _`Google Developer Style Guide`: https://developers.google.com/style/ -.. _`LSST DM Docstring Style Guide`: https://developer.lsst.io/python/style.html -.. _`LSST DM ReStructuredTextStyle Guide`: https://developer.lsst.io/restructuredtext/style.html diff --git a/docs/dev/index.rst b/docs/dev/index.rst deleted file mode 100644 index 00921a5..0000000 --- a/docs/dev/index.rst +++ /dev/null @@ -1,13 +0,0 @@ -:og:description: Learn how to contribute to the lsst-rsp open source project. - -############ -Contributing -############ - -Learn how to contribute to the lsst-rsp open source project. - -.. toctree:: - :caption: Guides - - development - release diff --git a/docs/dev/release.rst b/docs/dev/release.rst deleted file mode 100644 index a7ae89b..0000000 --- a/docs/dev/release.rst +++ /dev/null @@ -1,103 +0,0 @@ -################# -Release procedure -################# - -This page gives an overview of how lsst-rsp releases are made. -This information is only useful for maintainers. - -lsst-rsp's releases are largely automated through GitHub Actions (see the `ci.yaml`_ workflow file for details). -When a semantic version tag is pushed to GitHub, `lsst-rsp is released to PyPI`_ with that version. -Similarly, documentation is built and pushed for each version (see https://lsst-rsp.lsst.io/v). - -.. _`lsst-rsp is released to PyPI`: https://pypi.org/project/lsst-rsp/ -.. _`ci.yaml`: https://github.com/lsst-sqre/lsst-rsp/blob/main/.github/workflows/ci.yaml - -.. _regular-release: - -Regular releases -================ - -Regular releases happen from the ``main`` branch after changes have been merged. -From the ``main`` branch you can release a new major version (``X.0.0``), a new minor version of the current major version (``X.Y.0``), or a new patch of the current major-minor version (``X.Y.Z``). -See :ref:`backport-release` to patch an earlier major-minor version. - -Release tags are semantic version identifiers following the :pep:`440` specification. - -1. Change log and documentation -------------------------------- - -Change log messages for each release are accumulated using scriv_. -See :ref:`dev-change-log` in the *Developer guide* for more details. - -When it comes time to make the release, there should be a collection of change log fragments in :file:`changelog.d`. -Those fragments will make up the change log for the new release. - -Review those fragments to determine the version number of the next release. -Safir follows semver_, so follow its rules to pick the next version: - -.. rst-class:: compact - -- If there are any backward-incompatible changes, incremeent the major version number and set the other numbers to 0. -- If there are any new features, increment the minor version number and set the patch version to 0. -- Otherwise, increment the patch version number. - -Then, run ``scriv collect --version `` specifying the version number you decided on. -This will delete the fragment files and collect them into :file:`CHANGELOG.md` under an entry for the new release. -Review that entry and edit it as needed (proofread, change the order to put more important things first, etc.). -scriv will put blank lines between entries from different files. -You may wish to remove those blank lines to ensure consistent formatting by various Markdown parsers. - -Finally, create a PR from those changes and merge it before continuing with the release process. - -2. GitHub release and tag -------------------------- - -Use `GitHub's Release feature `__ to create releases and their corresponding Git tags. - -1. Specify a tag from the appropriate branch (typically ``main``). - This tag's name is :pep:`440` and is usually formatted at ``X.Y.Z`` (without a ``v`` prefix). - -2. For the release name, repeat the version string. - -3. Fill in the release notes, copied from the release notes. - You can use GitHub's change log feature to additionally generate a list of PRs included in the release. - -The tag **must** follow the :pep:`440` specification since lsst-rsp uses setuptools_scm_ to set version metadata based on Git tags. -In particular, **don't** prefix the tag with ``v``. - -.. _setuptools_scm: https://github.com/pypa/setuptools_scm - -The `ci.yaml`_ GitHub Actions workflow uploads the new release to PyPI and documentation to https://lsst-rsp.lsst.io. - -.. _backport-release: - -Backport releases -================= - -The regular release procedure works from the main line of development on the ``master`` Git branch. -To create a release that patches an earlier major or minor version, you need to release from a **release branch.** - -Creating a release branch -------------------------- - -Release branches are named after the major and minor components of the version string: ``X.Y``. -If the release branch doesn't already exist, check out the latest patch for that major-minor version: - -.. code-block:: sh - - git checkout X.Y.Z - git checkout -b X.Y - git push -u - -Developing on a release branch ------------------------------- - -Once a release branch exists, it becomes the "main" branch for patches of that major-minor version. -Pull requests should be based on, and merged into, the release branch. - -If the development on the release branch is a backport of commits on the ``main`` branch, use ``git cherry-pick`` to copy those commits into a new pull request against the release branch. - -Releasing from a release branch -------------------------------- - -Releases from a release branch are equivalent to :ref:`regular releases `, except that the release branch takes the role of the ``main`` branch. diff --git a/docs/documenteer.toml b/docs/documenteer.toml deleted file mode 100644 index 6840da6..0000000 --- a/docs/documenteer.toml +++ /dev/null @@ -1,16 +0,0 @@ -[project] -title = "lsst-rsp" -copyright = "2021-2023 Association of Universities for Research in Astronomy, Inc. (AURA)" - -[project.python] -package = "lsst-rsp" - -[sphinx] -rst_epilog_file = "_rst_epilog.rst" -disable_primary_sidebars = [ - "index", - "changelog", -] - -[sphinx.intersphinx.projects] -python = "https://docs.python.org/3/" diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index e3890ae..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -:og:description: Short one-sentence description of the package -:html_theme.sidebar_secondary.remove: - -######## -lsst-rsp -######## - -Short one-sentence description of the package - -Install lsst-rsp from PyPI: - -.. code-block:: bash - - pip install lsst-rsp - -lsst-rsp is developed on GitHub at https://github.com/lsst-sqre/lsst-rsp. - -.. toctree:: - :hidden: - - User guide - API - Change log - Contributing diff --git a/docs/user-guide/index.rst b/docs/user-guide/index.rst deleted file mode 100644 index 6adec7d..0000000 --- a/docs/user-guide/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -:og:description: Learn how to use lsst-rsp. - -########## -User guide -########## - -.. .. toctree:: -.. :maxdepth: 2 -.. .. :titlesonly: diff --git a/pyproject.toml b/pyproject.toml index 4c8f521..8f2cefb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,6 @@ dev = [ "pre-commit", "mypy", # Documentation - "documenteer[guide]<1", "scriv", ] @@ -108,7 +107,6 @@ exclude_lines = [ profile = "black" line_length = 79 known_first_party = ["lsst-rsp", "tests"] -skip = ["docs/conf.py"] [tool.mypy] disallow_untyped_defs = true @@ -156,9 +154,6 @@ python_files = [ # Reference for settings: https://beta.ruff.rs/docs/settings/ # Reference for rules: https://beta.ruff.rs/docs/rules/ [tool.ruff] -exclude = [ - "docs/**", -] line-length = 79 ignore = [ "ANN101", # self should not have a type annotation diff --git a/tox.ini b/tox.ini index e1a091d..3be1626 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py,coverage-report,typing,lint,docs,docs-linkcheck +envlist = py,coverage-report,typing,lint isolated_build = True [testenv] @@ -34,14 +34,3 @@ deps = pre-commit commands = pre-commit run --all-files -[testenv:docs] -description = Build documentation (HTML) with Sphinx. -commands = - sphinx-build --keep-going -n -W -T -b html -d {envtmpdir}/doctrees docs docs/_build/html - -[testenv:docs-linkcheck] -description = Check links in the documentation. -allowlist_externals = - make -commands = - make linkcheck From a93432dccae2d64706d9ca4cd64a0df80f859ea4 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 15:48:20 -0700 Subject: [PATCH 07/10] Remove docs from Github Actions too --- .github/workflows/ci.yaml | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cbd4837..3c4f767 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -53,42 +53,6 @@ jobs: python-version: ${{ matrix.python }} tox-envs: "py,typing" - docs: - - runs-on: ubuntu-latest - timeout-minutes: 10 - - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # full history for setuptools_scm - - - name: Install Graphviz - run: sudo apt-get install graphviz - - - name: Run tox - uses: lsst-sqre/run-tox@v1 - with: - python-version: "3.11" - tox-envs: "docs" - # Add docs-linkcheck when the docs and PyPI package are published - # tox-envs: "docs,docs-linkcheck" - - # Only attempt documentation uploads for tagged releases and pull - # requests from ticket branches in the same repository. This avoids - # version clutter in the docs and failures when a PR doesn't have access - # to secrets. - - name: Upload to LSST the Docs - uses: lsst-sqre/ltd-upload@v1 - with: - project: "lsst-rsp" - dir: "docs/_build/html" - username: ${{ secrets.LTD_USERNAME }} - password: ${{ secrets.LTD_PASSWORD }} - if: > - github.event_name != 'merge_group' - && (github.event_name != 'pull_request' - || startsWith(github.head_ref, 'tickets/')) test-packaging: @@ -114,7 +78,7 @@ jobs: # See https://github.com/lsst-sqre/build-and-publish-to-pypi name: Upload release to PyPI runs-on: ubuntu-latest - needs: [lint, test, docs, test-packaging] + needs: [lint, test, test-packaging] environment: name: pypi url: https://pypi.org/p/lsst-rsp From 39e5fdce08149303260fce6aa54dee82dea6a42a Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 18:03:19 -0700 Subject: [PATCH 08/10] Pin pyvo --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8f2cefb..4a2763d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,11 +21,12 @@ classifiers = [ "Typing :: Typed", ] requires-python = ">=3.11" +# FIXME When pyvo 1.5.0 is released, remove pin. dependencies = [ "bokeh", "Deprecated", "IPython", - "pyvo" + "pyvo@git+https://github.com/astropy/pyvo.git@7682a1809cb2169cc2ffd9313feb6a4abd7f7e37" ] dynamic = ["version"] From b3af5da717d002b8becbad89b4b57a42e2896b69 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 11 Dec 2023 18:09:46 -0700 Subject: [PATCH 09/10] Make linter happy again --- src/lsst/rsp/catalog.py | 3 ++- src/lsst/rsp/utils.py | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lsst/rsp/catalog.py b/src/lsst/rsp/catalog.py index ff07c33..958aab2 100644 --- a/src/lsst/rsp/catalog.py +++ b/src/lsst/rsp/catalog.py @@ -20,7 +20,8 @@ def get_obstap_service() -> pyvo.dal.TAPService: def get_tap_service(*args: str) -> pyvo.dal.TAPService: """Returns a TAP service instance to interact with the - requested TAP service.""" + requested TAP service. + """ if len(args) == 0: warnings.warn( 'get_tap_service() is deprecated, use get_tap_service("tap")', diff --git a/src/lsst/rsp/utils.py b/src/lsst/rsp/utils.py index 20949c4..2c4de7c 100644 --- a/src/lsst/rsp/utils.py +++ b/src/lsst/rsp/utils.py @@ -6,6 +6,8 @@ from typing import Any, Optional, Union import bokeh.io +import pyvo +import requests from deprecated import deprecated @@ -46,6 +48,7 @@ def get_hostname() -> str: def get_service_url(name: str, env_name: Optional[str] = None) -> str: + """Get our best guess at the URL for the requested service.""" if not env_name: env_name = name.upper() From d98af6b3d39d1814204d9ff611160b452f083244 Mon Sep 17 00:00:00 2001 From: adam Date: Tue, 12 Dec 2023 10:25:58 -0700 Subject: [PATCH 10/10] remove show_with_bokeh_server(); update README.md --- README.md | 77 +++++++++++++++++++++++++++++++++++++--- pyproject.toml | 1 - src/lsst/rsp/__init__.py | 2 -- src/lsst/rsp/utils.py | 32 ----------------- 4 files changed, 73 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 02415b0..a037591 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,11 @@ Install from PyPI: pip install lsst-rsp ``` -lsst-rsp is developed by Rubin Observatory at https://github.com/lsst-sqre/lsst-rsp. +but, really, lsst-rsp is only useful inside an RSP JupyterLab container. -## Features +See below for how to test new versions within such a container. - +lsst-rsp is developed by Rubin Observatory at https://github.com/lsst-sqre/lsst-rsp. ## Developing lsst-rsp @@ -37,4 +37,73 @@ To learn more about the individual environments: tox -av ``` -[See the docs for more information.](https://lsst-rsp.lsst.io/dev/development.html) +## Developing lsst-rsp on the RSP + +The `LSST` kernel in the RSP `sciplat-lab` image already has a release +version of `lsst-rsp` in it. Therefore, there is some setup you need to +do in order to create a development environment you can use. +Specifically, you need to create a virtualenv for the editable +`lsst-rsp`, install `tox` and `pre-commit` for its test machinery, and +then create a JupyterLab kernel pointing to it. + +Open a terminal session: + +```bash +VENV="lsst_rsp" +mkdir -p ${HOME}/venvs +python -m venv ${HOME}/venvs/${VENV} +. ${HOME}/venvs/${VENV}/bin/activate +mkdir -p ${HOME}/src +cd ${HOME}/src +git clone https://github.com/lsst-sqre/lsst-rsp # or git@github.com:lsst-sqre/lsst-rsp.git if you prefer +cd lsst-rsp +make init +pip install ipykernel +python -m ipykernel install --user --name=${VENV} +``` + +Now you will need to shut down your lab and get a new container image. +That's because the process your Lab interface is running inside doesn't +know about the new kernel--but once you restart the Lab container, it +will. + +Once you're in your new container, you will notice that you have a new +kernel named `lsst_rsp`. + +Now you've got an editable version installed in your custom kernel, and +you can still run all the usual tox environments too. + +If you start a notebook with your custom kernel, + +```python +import lsst.rsp + +lsst.rsp.__version__ +``` + +will show you your development version. Note that you will still need +to restart the kernel to pick up changes you make to your copy of +`lsst_rsp`. + +Uninstalling a development version from the RSP +=============================================== + +Open a terminal window. + +```bash +. $HOME/venvs/lsst_rsp/bin/activate +jupyter kernelspec uninstall lsst_rsp +y +deactivate +``` + +Shut down and restart your notebook as before. When you come back in, +in a terminal window: + +```bash +rm -rf $HOME/venvs/lsst_rsp +``` + +You will need to remove the virtualenv directory after restarting the +Lab container, because otherwise JupyterLab will be holding some files +open because it still believes it has a kernel there. diff --git a/pyproject.toml b/pyproject.toml index 4a2763d..916ef01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ classifiers = [ requires-python = ">=3.11" # FIXME When pyvo 1.5.0 is released, remove pin. dependencies = [ - "bokeh", "Deprecated", "IPython", "pyvo@git+https://github.com/astropy/pyvo.git@7682a1809cb2169cc2ffd9313feb6a4abd7f7e37" diff --git a/src/lsst/rsp/__init__.py b/src/lsst/rsp/__init__.py index f5bccbc..966790a 100644 --- a/src/lsst/rsp/__init__.py +++ b/src/lsst/rsp/__init__.py @@ -18,7 +18,6 @@ get_hostname, get_node, get_pod, - show_with_bokeh_server, ) __version__: str @@ -47,5 +46,4 @@ "get_obstap_service", "retrieve_query", "get_hostname", - "show_with_bokeh_server", ] diff --git a/src/lsst/rsp/utils.py b/src/lsst/rsp/utils.py index 2c4de7c..60a3b2f 100644 --- a/src/lsst/rsp/utils.py +++ b/src/lsst/rsp/utils.py @@ -1,11 +1,9 @@ """Utility functions for LSST JupyterLab notebook environment.""" import os -import urllib from pathlib import Path from typing import Any, Optional, Union -import bokeh.io import pyvo import requests from deprecated import deprecated @@ -93,36 +91,6 @@ def get_pyvo_auth() -> Optional[pyvo.auth.authsession.AuthSession]: return auth -def show_with_bokeh_server(obj: Any) -> None: - """Method to wrap bokeh with proxy URL""" - - def jupyter_proxy_url(port: Optional[int] = None) -> str: - """Callable to configure Bokeh's show method when a proxy must be - configured. - - If port is None we're asking about the URL - for the origin header. - - https://docs.bokeh.org/en/latest/docs/user_guide/jupyter.html - """ - base_url = os.environ["EXTERNAL_INSTANCE_URL"] - host = urllib.parse.urlparse(base_url).netloc - - # If port is None we're asking for the URL origin - # so return the public hostname. - if port is None: - return host - - service_url_path = os.environ["JUPYTERHUB_SERVICE_PREFIX"] - proxy_url_path = "proxy/%d" % port - - user_url = urllib.parse.urljoin(base_url, service_url_path) - full_url = urllib.parse.urljoin(user_url, proxy_url_path) - return full_url - - bokeh.io.show(obj=obj, notebook_url=jupyter_proxy_url) - - @deprecated( reason="get_pod() always returns None in RSPs running Nubladov3 or later" )