diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 12cf538..921e364 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ '3.8', '3.9', '3.10', '3.11' ] + python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] steps: - uses: actions/checkout@v3 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a300aa5..e291536 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,19 +1,21 @@ repos: -- repo: https://github.com/psf/black - rev: 23.3.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.9 hooks: - - id: black + - id: ruff + - id: ruff-format -- repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.2.0 + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.7.1 hooks: - - id: mypy - args: [--disallow-untyped-defs, --no-implicit-optional, --warn-unused-ignores, --warn-redundant-casts, --warn-unreachable] + - id: mypy + args: + [ + --disallow-untyped-defs, + --no-implicit-optional, + --warn-unused-ignores, + --warn-redundant-casts, + --warn-unreachable, + ] exclude: test additional_dependencies: [types-requests, xarray] - -- repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - args: [--profile, black] diff --git a/docs/conf.py b/docs/conf.py index ad82721..5b80cf9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,7 @@ sys.path.insert(0, os.path.abspath("..")) -from wxee import __version__ +from wxee import __version__ # noqa: E402 # -- Project information ----------------------------------------------------- diff --git a/pyproject.toml b/pyproject.toml index 3d4c6e6..ffaffe8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,9 @@ path = "wxee/__init__.py" [tool.hatch.build.targets.sdist] include = ["/wxee"] +[tool.hatch.envs.default] +dependencies = ["pre-commit"] + [tool.hatch.envs.docs] dependences = [ "nbsphinx", diff --git a/test/conftest.py b/test/conftest.py index 3368e4d..7bde248 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,5 +1,3 @@ -import ee - import wxee diff --git a/test/test_image.py b/test/test_image.py index 885e866..c33c534 100644 --- a/test/test_image.py +++ b/test/test_image.py @@ -5,7 +5,7 @@ import pytest import rasterio -import wxee +import wxee # noqa: F401 from wxee.exceptions import MissingPropertyError diff --git a/test/test_time_series.py b/test/test_time_series.py index c1697f9..9cf503a 100644 --- a/test/test_time_series.py +++ b/test/test_time_series.py @@ -451,3 +451,25 @@ def test_dataframe(): df["system:time_start"].dt.strftime("%Y-%m-%d").values.tolist() == start_dates ) assert df["system:id"].values.tolist() == ids + + +@pytest.mark.ee +def test_timeline(): + """Test that you can generate a timeline figure from a time series.""" + start_dates = ["2020-01-01", "2020-02-01", "2021-03-03"] + ids = ["id1", "id2", "id3"] + + imgs = [ + ee.Image.constant(1).set( + "system:time_start", + ee.Date(start_dates[i]).millis(), + "system:id", + ids[i], + ) + for i in range(3) + ] + ts = wxee.TimeSeries(imgs) + + timeline = ts.timeline() + + assert timeline.data diff --git a/wxee/__init__.py b/wxee/__init__.py index 3bd0868..656d59a 100644 --- a/wxee/__init__.py +++ b/wxee/__init__.py @@ -1,7 +1,9 @@ -import wxee.xarray +from wxee import xarray from wxee.collection import ImageCollection from wxee.image import Image from wxee.time_series import TimeSeries from wxee.utils import Initialize __version__ = "0.4.1" + +__all__ = ["xarray", "Image", "ImageCollection", "TimeSeries", "Initialize"] diff --git a/wxee/image.py b/wxee/image.py index 7fe391c..98cdabf 100644 --- a/wxee/image.py +++ b/wxee/image.py @@ -272,7 +272,7 @@ def _get_download_id(self) -> ee.String: except ee.EEException as e: if "Parameter 'value' is required" in str(e): raise MissingPropertyError( - f"Image is missing a `system:time_start` property which is required for " + "Image is missing a `system:time_start` property which is required for " "downloading.\n\nEarth Engine properties can be lost when modifying images, so make sure to manually " "set or copy properties using the `.set` and `.copyProperties` methods after using methods like " "`.multiply` or `.median`. If you don't need time information, you can set an arbitrary time with " diff --git a/wxee/time_series.py b/wxee/time_series.py index 11464da..c46333e 100644 --- a/wxee/time_series.py +++ b/wxee/time_series.py @@ -171,7 +171,7 @@ def dataframe(self, props: Union[None, List[str], ee.List] = None) -> pd.DataFra df.index.id = collection_id return df - def timeline(self) -> "go.Figure": # pragma: no cover + def timeline(self) -> "go.Figure": """Generate an interactive plot showing the acquisition time of each image in the time series. Returns @@ -181,6 +181,7 @@ def timeline(self) -> "go.Figure": # pragma: no cover """ try: import plotly.express as px # type: ignore + import plotly.graph_objects as go except ImportError: raise ImportError( "The `plotly` package is required for this feature. " @@ -579,7 +580,7 @@ def climatology_anomaly( ) if std.reducer != mean.reducer: # There is no way to determine the type of reducer used after the fact, or else I would list them. - raise ValueError(f"Mean reducer does not match std reducer.") + raise ValueError("Mean reducer does not match std reducer.") def image_anomaly(img: ee.Image) -> ee.Image: """Identify the climatological mean and std deviation for a given image diff --git a/wxee/xarray.py b/wxee/xarray.py index db8ee04..cdd2eea 100644 --- a/wxee/xarray.py +++ b/wxee/xarray.py @@ -67,14 +67,14 @@ def rgb( """ if bands is not None: if len(bands) != 3: - raise ValueError(f"Bands must be a list with exactly 3 names.") + raise ValueError("Bands must be a list with exactly 3 names.") else: bands = list(self._obj.var())[:3] # type: ignore # Raise a different error if the bands were identified implicitly to avoid confusion if len(bands) != 3: # type: ignore raise ValueError( - f"The Dataset must contain at least 3 data variables for RGB plotting." + "The Dataset must contain at least 3 data variables for RGB plotting." ) da = self._obj[bands].to_array(name="rgb") @@ -83,7 +83,7 @@ def rgb( if interactive: try: - import hvplot.xarray # type: ignore + import hvplot.xarray # type: ignore # noqa F401 except ImportError: raise ImportError( "The `hvplot` package is required for interactive plots. Run `pip install hvplot`."