diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7370ca0..6af36fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: - name: Install dependencies run: | - uv sync --no-dev --frozen --extra ephemeris --extra slack + uv sync --no-dev --frozen --extra all - name: Test with pytest run: | diff --git a/pyproject.toml b/pyproject.toml index 6da76c4..c0de5c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lvmopstools" -version = "0.5.2a0" +version = "0.5.2" description = "LVM tools and utilities for operations" authors = [ { name = "José Sánchez-Gallego", email = "gallegoj@uw.edu" } @@ -11,7 +11,7 @@ requires-python = ">=3.10,<4" dependencies = [ "sdsstools>=1.8.2", - "sdss-clu>=2.2.7", + "sdss-clu>=2.4.0", "sdss-drift>=1.2.0", "asyncudp>=0.11.0", "httpx>=0.27.2", @@ -22,6 +22,8 @@ dependencies = [ "strenum>=0.4.15", "aiohttp>=3.11.11", "jinja2>=3.1.5", + "cachetools>=5.5.0", + "aiocache>=0.12.3" ] [project.optional-dependencies] @@ -32,11 +34,17 @@ ephemeris = [ "astropy>=6.0.0; python_version<'3.11'", "astropy>=7.0.0; python_version>='3.11'", "astroplan>=0.10.1", - "cachetools>=5.5.0" ] slack = [ "slack-sdk>=3.34.0", - "aiocache>=0.12.3" +] +all = [ + "kubernetes>=31.0.0", + "influxdb-client>=1.47.0", + "astropy>=6.0.0; python_version<'3.11'", + "astropy>=7.0.0; python_version>='3.11'", + "astroplan>=0.10.1", + "slack-sdk>=3.34.0", ] [project.urls] diff --git a/readthedocs.yml b/readthedocs.yml index 3766e08..bc8cfff 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -12,4 +12,6 @@ python: install: - method: pip path: . + extra_requirements: + - all - requirements: docs/sphinx/requirements.txt diff --git a/src/lvmopstools/ephemeris.py b/src/lvmopstools/ephemeris.py index 08bc2c0..4916d15 100644 --- a/src/lvmopstools/ephemeris.py +++ b/src/lvmopstools/ephemeris.py @@ -12,16 +12,22 @@ from typing import TypedDict -import astroplan import numpy import polars -from astropy import units as uu -from astropy.time import Time from cachetools import TTLCache, cached from sdsstools import get_sjd +try: + import astroplan + from astropy import units as uu + from astropy.time import Time +except ImportError: + uu = None + Time = None + astroplan = None + EPHEMERIS_FILE = pathlib.Path(__file__).parent / "data/ephemeris_59945_62866.parquet" @@ -35,6 +41,11 @@ def get_ephemeris_data(filename: pathlib.Path | str) -> polars.DataFrame: def sjd_ephemeris(sjd: int, twilight_horizon: float = -15) -> polars.DataFrame: """Returns the ephemeris for a given SJD.""" + if not astroplan or not uu or not Time: + raise ImportError( + "astropy and astroplan are required. Install the ephemeris extra." + ) + observer = astroplan.Observer.at_site("Las Campanas Observatory") observer.pressure = 0.76 * uu.bar @@ -151,6 +162,11 @@ class EphemerisDict(TypedDict): def get_ephemeris_summary(sjd: int | None = None) -> EphemerisDict: """Returns a summary of the ephemeris for a given SJD.""" + if not uu or not Time: + raise ImportError( + "astropy and astroplan are required. Install the ephemeris or all extras." + ) + sjd = sjd or get_sjd("LCO") from_file = True diff --git a/src/lvmopstools/influxdb.py b/src/lvmopstools/influxdb.py index f50e5d3..270c20b 100644 --- a/src/lvmopstools/influxdb.py +++ b/src/lvmopstools/influxdb.py @@ -37,7 +37,9 @@ async def query_influxdb( """Runs a query in InfluxDB and returns a Polars dataframe.""" if not InfluxDBClientAsync or not MissingPivotFunction: - raise ImportError("influxdb-client is not installed. Use the influxdb extra.") + raise ImportError( + "influxdb-client is not installed. Install the influxdb or all extras." + ) warnings.simplefilter("ignore", MissingPivotFunction) # noqa: F821 diff --git a/src/lvmopstools/kubernetes.py b/src/lvmopstools/kubernetes.py index 01e29aa..55cd6f2 100644 --- a/src/lvmopstools/kubernetes.py +++ b/src/lvmopstools/kubernetes.py @@ -30,7 +30,9 @@ class Kubernetes: def __init__(self, deployments_path: str | Path | None = None): if kubernetes is None: - raise ImportError("kubernetes is not installed. Use the kubernetes extra.") + raise ImportError( + "kubernetes is not installed. Install the kubernetes or all extras." + ) self.is_notebook = is_notebook() diff --git a/src/lvmopstools/slack.py b/src/lvmopstools/slack.py index 162b6b8..c9bf10b 100644 --- a/src/lvmopstools/slack.py +++ b/src/lvmopstools/slack.py @@ -14,8 +14,6 @@ from typing import Sequence from aiocache import cached -from slack_sdk.errors import SlackApiError -from slack_sdk.web.async_client import AsyncWebClient from lvmopstools import config @@ -31,6 +29,13 @@ def get_api_client(token: str | None = None): """Gets a Slack API client.""" + try: + from slack_sdk.web.async_client import AsyncWebClient + except ImportError: + raise ImportError( + "slack-sdk is not installed. Install the slack or all extras." + ) + token = token or config["slack.token"] or os.environ["SLACK_API_TOKEN"] return AsyncWebClient(token=token) @@ -91,6 +96,11 @@ async def post_message( """ + try: + from slack_sdk.errors import SlackApiError + except ImportError: + SlackApiError = None + if text is None and blocks is None: raise ValueError("Must specify either text or blocks.") @@ -104,6 +114,7 @@ async def post_message( icon_url = ICONS[username.lower()] client = get_api_client() + assert SlackApiError is not None try: text = await format_mentions(text, mentions) @@ -127,7 +138,13 @@ async def get_user_list(): """ + try: + from slack_sdk.errors import SlackApiError + except ImportError: + SlackApiError = None + client = get_api_client() + assert SlackApiError is not None try: users_list = await client.users_list() diff --git a/uv.lock b/uv.lock index 1d65a0a..9f4d56c 100644 --- a/uv.lock +++ b/uv.lock @@ -950,12 +950,14 @@ wheels = [ [[package]] name = "lvmopstools" -version = "0.5.2a0" +version = "0.5.2" source = { editable = "." } dependencies = [ { name = "aio-pika" }, + { name = "aiocache" }, { name = "aiohttp" }, { name = "asyncudp" }, + { name = "cachetools" }, { name = "httpx" }, { name = "jinja2" }, { name = "polars" }, @@ -968,6 +970,14 @@ dependencies = [ ] [package.optional-dependencies] +all = [ + { name = "astroplan" }, + { name = "astropy", version = "6.1.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "astropy", version = "7.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "influxdb-client" }, + { name = "kubernetes" }, + { name = "slack-sdk" }, +] ds9 = [ { name = "pyds9" }, ] @@ -975,7 +985,6 @@ ephemeris = [ { name = "astroplan" }, { name = "astropy", version = "6.1.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "astropy", version = "7.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "cachetools" }, ] influxdb = [ { name = "influxdb-client" }, @@ -984,7 +993,6 @@ kubernetes = [ { name = "kubernetes" }, ] slack = [ - { name = "aiocache" }, { name = "slack-sdk" }, ] @@ -1017,23 +1025,29 @@ dev = [ [package.metadata] requires-dist = [ { name = "aio-pika", specifier = ">=9.5.3" }, - { name = "aiocache", marker = "extra == 'slack'", specifier = ">=0.12.3" }, + { name = "aiocache", specifier = ">=0.12.3" }, { name = "aiohttp", specifier = ">=3.11.11" }, + { name = "astroplan", marker = "extra == 'all'", specifier = ">=0.10.1" }, { name = "astroplan", marker = "extra == 'ephemeris'", specifier = ">=0.10.1" }, + { name = "astropy", marker = "python_full_version >= '3.11' and extra == 'all'", specifier = ">=7.0.0" }, { name = "astropy", marker = "python_full_version >= '3.11' and extra == 'ephemeris'", specifier = ">=7.0.0" }, + { name = "astropy", marker = "python_full_version < '3.11' and extra == 'all'", specifier = ">=6.0.0" }, { name = "astropy", marker = "python_full_version < '3.11' and extra == 'ephemeris'", specifier = ">=6.0.0" }, { name = "asyncudp", specifier = ">=0.11.0" }, - { name = "cachetools", marker = "extra == 'ephemeris'", specifier = ">=5.5.0" }, + { name = "cachetools", specifier = ">=5.5.0" }, { name = "httpx", specifier = ">=0.27.2" }, + { name = "influxdb-client", marker = "extra == 'all'", specifier = ">=1.47.0" }, { name = "influxdb-client", marker = "extra == 'influxdb'", specifier = ">=1.47.0" }, { name = "jinja2", specifier = ">=3.1.5" }, + { name = "kubernetes", marker = "extra == 'all'", specifier = ">=31.0.0" }, { name = "kubernetes", marker = "extra == 'kubernetes'", specifier = ">=31.0.0" }, { name = "polars", specifier = ">=1.13.0" }, { name = "pydantic", specifier = ">=2.10.3" }, { name = "pyds9", marker = "extra == 'ds9'", specifier = ">=1.8.1" }, - { name = "sdss-clu", specifier = ">=2.2.7" }, + { name = "sdss-clu", specifier = ">=2.4.0" }, { name = "sdss-drift", specifier = ">=1.2.0" }, { name = "sdsstools", specifier = ">=1.8.2" }, + { name = "slack-sdk", marker = "extra == 'all'", specifier = ">=3.34.0" }, { name = "slack-sdk", marker = "extra == 'slack'", specifier = ">=3.34.0" }, { name = "strenum", specifier = ">=0.4.15" }, { name = "typing-extensions", specifier = ">=4.12.2" }, @@ -2131,7 +2145,7 @@ wheels = [ [[package]] name = "sdss-clu" -version = "2.3.1" +version = "2.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aio-pika" }, @@ -2141,12 +2155,13 @@ dependencies = [ { name = "click-default-group" }, { name = "jsonschema" }, { name = "prompt-toolkit" }, + { name = "pydantic" }, { name = "sdsstools" }, { name = "unclick" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/ed/69a64f393e8a123946aaa03c80deb69f3640a727a0beccee6bf2fde320e3/sdss_clu-2.3.1.tar.gz", hash = "sha256:157b5e0ec6a0d456603d59b0c718008e46bb109b455593725a7da7888f8bc984", size = 122771 } +sdist = { url = "https://files.pythonhosted.org/packages/a7/ff/ee9b933617b4660111cb178fae1c7f87ae6d1da28971ab307d2bec84015b/sdss_clu-2.4.0.tar.gz", hash = "sha256:3895c1606b28eee5a830bda30f1abcae4bca83a36af4b82bd43cde6a26d3f777", size = 122983 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/8a/f65351c9f037e3f7441bd8e8dd7169bb2ebe5b3dbd7c3279d32b9bc62686/sdss_clu-2.3.1-py3-none-any.whl", hash = "sha256:c5125fcce0a09b97e661e68a836a61056908834eeb0beb2b919ae0745848f555", size = 142249 }, + { url = "https://files.pythonhosted.org/packages/7e/0a/df9de24104ec253e75f2a5e3e46f8932a55b7b615444fbd17a509434e361/sdss_clu-2.4.0-py3-none-any.whl", hash = "sha256:9abbeb922a1f3a15e4f81fc229db3a44497b0d492782ee5547d714014ce41595", size = 142434 }, ] [[package]]