From da77bdf43441ae79f35cb5d7891937015958833a Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Mon, 30 Oct 2023 13:42:20 -0700 Subject: [PATCH 1/9] Small tweeks to docstrings, remove use of default mutable argument, fix minor security problem. --- eedl/core.py | 8 ++++---- eedl/helpers.py | 25 +++++++++++++++++-------- eedl/image.py | 35 +++++++++++++++++++++-------------- eedl/mosaic_rasters.py | 5 ++--- examples/basic.py | 6 ++---- 5 files changed, 46 insertions(+), 33 deletions(-) diff --git a/eedl/core.py b/eedl/core.py index 93afb5a..42a88d4 100644 --- a/eedl/core.py +++ b/eedl/core.py @@ -26,10 +26,10 @@ def _get_fiona_args(polygon_path: Union[str, Path]) -> Dict[str, Union[str, Path def safe_fiona_open(features_path: Union[str, Path], **extra_kwargs) -> fiona.Collection: """ - Handles opening things in fiona in a way that is safe, even for geodatabases where we need - to open the geodatabase itself and specify a layer. The caller is responsible for - ensuring the features are closed (e.g. a try/finally block with a call to features.close() - in the finally block should immediately follow calling this function. + Handles opening things in fiona in a way that is safe, even for geodatabases where we need + to open the geodatabase itself and specify a layer. The caller is responsible for + ensuring the features are closed (e.g. a try/finally block with a call to features.close()) + in the finally block should immediately follow calling this function. :param features_path: A Path object or string path to open with fiona :param extra_kwargs: Keyword arguments to directly pass through to fiona. Helpful when trying to filter features, etc :return: diff --git a/eedl/helpers.py b/eedl/helpers.py index eced360..67a25ce 100644 --- a/eedl/helpers.py +++ b/eedl/helpers.py @@ -56,11 +56,20 @@ def __init__(self, **kwargs): def _single_item_extract(self, image, task_registry, zonal_features, aoi_attr, ee_geom, image_date, aoi_download_folder): """ - This looks a bit silly here, but we need to construct this here so that we have access - to this method's variables since we can't pass them in and it can't be a class function. - :param image: - :param state: - :return: + This looks a bit silly here, but we need to construct this here so that we have access + to this method's variables since we can't pass them in and it can't be a class function. + + Args: + image: + task_registry: + zonal_features: + aoi_attr: + ee_geom: + image_date: + aoi_download_folder: + + Returns: + None """ export_image = EEDLImage( @@ -188,9 +197,9 @@ def _get_and_filter_collection(self): def mosaic_by_date(image_collection): """ - Adapted to Python from code found via https://gis.stackexchange.com/a/343453/1955 - :param image_collection: An image collection - :return: ee.ImageCollection + Adapted to Python from code found via https://gis.stackexchange.com/a/343453/1955 + :param image_collection: An image collection + :return: ee.ImageCollection """ image_list = image_collection.toList(image_collection.size()) diff --git a/eedl/image.py b/eedl/image.py index 86f47c6..47d70c8 100644 --- a/eedl/image.py +++ b/eedl/image.py @@ -81,7 +81,7 @@ def __init__(self) -> None: self.log_file: Optional[io.TextIOWrapper] = None # the open log file handle self.raise_errors: bool = True - def add(self, image: ee.image.Image) -> None: + def add(self, image: EEDLImage) -> None: """ Adds an Earth Engine image to the list of Earth Engine images. @@ -94,7 +94,7 @@ def add(self, image: ee.image.Image) -> None: self.images.append(image) @property - def incomplete_tasks(self) -> List[ee.image.Image]: + def incomplete_tasks(self) -> List[EEDLImage]: """ List of Earth Engine images that have not been completed yet. @@ -108,7 +108,7 @@ def incomplete_tasks(self) -> List[ee.image.Image]: return [image for image in self.images if image.last_task_status['state'] in self.INCOMPLETE_STATUSES] @property - def complete_tasks(self) -> List[ee.image.Image]: + def complete_tasks(self) -> List[EEDLImage]: """ List of Earth Engine images. @@ -118,7 +118,7 @@ def complete_tasks(self) -> List[ee.image.Image]: return [image for image in self.images if image.last_task_status['state'] in self.COMPLETE_STATUSES + self.FAILED_STATUSES] @property - def failed_tasks(self) -> List[ee.image.Image]: + def failed_tasks(self) -> List[EEDLImage]: """ List of Earth Engine images that have either been cancelled or that have failed @@ -128,7 +128,7 @@ def failed_tasks(self) -> List[ee.image.Image]: return [image for image in self.images if image.last_task_status['state'] in self.FAILED_STATUSES] @property - def downloadable_tasks(self) -> List[ee.image.Image]: + def downloadable_tasks(self) -> List[EEDLImage]: """ List of Earth Engine images that have not been cancelled or have failed. @@ -165,9 +165,12 @@ def setup_log(self, log_file_path: Union[str, Path], mode='a'): def log_error(self, error_type: str, error_message: str): """ - :param error_type: Options "ee", "local" to indicate whether it was an error on Earth Engine's side or on - the local processing side - :param error_message: The error message to print to the log file + Args: + error_type (str): Options "ee", "local" to indicate whether it was an error on Earth Engine's side or on the local processing side + error_message (str): The error message to print to the log file + + Returns: + None """ message = f"{error_type} Error: {error_message}" date_string = datetime.datetime.now().strftime("%Y-%m-%d %H:%M") @@ -387,9 +390,9 @@ def export(self, (drive_root_folder is None or not os.path.exists(drive_root_folder)): raise NotADirectoryError("The provided path for the Google Drive export folder is not a valid directory but" - " Drive export was specified. Either change the export type to use Google Cloud" - " and set that up properly (with a bucket, etc), or set the drive_root_folder" - " to a valid folder.") + "Drive export was specified. Either change the export type to use Google Cloud" + "and set that up properly (with a bucket, etc), or set the drive_root_folder" + "to a valid folder.") elif export_type.lower() == "drive": if drive_root_folder: self.drive_root_folder = drive_root_folder @@ -544,12 +547,11 @@ def zonal_stats(self, report_threshold: int = 1000, write_batch_size: int = 2000, use_points: bool = False, - inject_constants: dict = dict(), + inject_constants: Optional[dict] = None, nodata_value: int = -9999, all_touched: bool = False ) -> None: """ - Args: polygons (Union[str, Path]): keep_fields (tuple[str, ...]): @@ -558,10 +560,15 @@ def zonal_stats(self, Set to None to disable. write_batch_size (int): How many zones should we store up before writing to the disk? Defaults to 2000. use_points (bool): + inject_constants(Optional[dict]): + nodata_value (int): + all_touched (bool): Returns: None """ + if inject_constants is None: + inject_constants = dict() self.zonal_output_filepath = zonal.zonal_stats( polygons, @@ -580,7 +587,7 @@ def zonal_stats(self, def _check_task_status(self) -> Dict[str, Union[Dict[str, str], bool]]: """ - Updates the status is it needs to be changed + Updates the status if it needs to be changed Returns: Dict[str, Union[Dict[str, str], bool]]: Returns a dictionary of the most up-to-date status and whether that status was changed diff --git a/eedl/mosaic_rasters.py b/eedl/mosaic_rasters.py index ebee210..bf8fcae 100644 --- a/eedl/mosaic_rasters.py +++ b/eedl/mosaic_rasters.py @@ -3,7 +3,6 @@ import tempfile from pathlib import Path from typing import Sequence, Union - from osgeo import gdal @@ -21,7 +20,7 @@ def mosaic_folder(folder_path: Union[str, Path], output_path: Union[str, Path], """ tifs = [os.path.join(folder_path, filename) for filename in os.listdir(folder_path) if filename.endswith(".tif") and filename.startswith(prefix)] - if len(tifs) == 1: # If we only got one image back, don't both mosaicking, though this will also skip generating overviews. + if len(tifs) == 1: # If we only got one image back, don't bother mosaicking, though this will also skip generating overviews. shutil.move(tifs[0], output_path) # Just move the output image to the "mosaic" name, then return. return @@ -44,7 +43,7 @@ def mosaic_rasters(raster_paths: Sequence[Union[str, Path]], """ # gdal.SetConfigOption("GTIFF_SRC_SOURCE", "GEOKEYS") - vrt_path = tempfile.mktemp(suffix=".vrt", prefix="mosaic_rasters_") + vrt_path = tempfile.mkstemp(suffix=".vrt", prefix="mosaic_rasters_") vrt_options = gdal.BuildVRTOptions(resampleAlg='nearest', resolution="highest") my_vrt = gdal.BuildVRT(vrt_path, raster_paths, options=vrt_options) diff --git a/examples/basic.py b/examples/basic.py index ea7f5c9..1580dd3 100644 --- a/examples/basic.py +++ b/examples/basic.py @@ -1,10 +1,8 @@ import ee from ee import ImageCollection -# we should change the name of our Image class - it conflicts with the class image in the ee package, and people will -# likely be using both. Let's not cause confusion -from eedl.image import EEDLImage import eedl +from eedl.image import EEDLImage def test_simple() -> None: @@ -14,7 +12,7 @@ def test_simple() -> None: # Adam, make sure to set the drive root folder for your own testing - we'll need to fix this, and in the future, # we can use a Google Cloud bucket for most testing this is clunky - we should make the instantiation of the image be able to take a kwarg that sets the value of image, I think. image = EEDLImage() - image.export(s2_image, "valley_water_s2_test_image", export_type="Drive", drive_root_folder=r"G:\My Drive", clip=geometry) + image.export(s2_image, "valley_water_s2_test_image", export_type="Drive", clip=geometry, drive_root_folder=r"G:\My Drive") # We need to make it check and report whether the export on the EE side was successful. This test "passed" because Earth Engine failed and there wasn't anything to download (oops) # Adam, make sure to set the folder you want results to be downloaded to From 802af5d08153c38e8e6f2c37552bd1b6ff965852 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Mon, 30 Oct 2023 13:56:22 -0700 Subject: [PATCH 2/9] Forward reference EEDLImage to pass linting check. --- eedl/image.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eedl/image.py b/eedl/image.py index 47d70c8..3dd66f4 100644 --- a/eedl/image.py +++ b/eedl/image.py @@ -81,7 +81,7 @@ def __init__(self) -> None: self.log_file: Optional[io.TextIOWrapper] = None # the open log file handle self.raise_errors: bool = True - def add(self, image: EEDLImage) -> None: + def add(self, image: "EEDLImage") -> None: """ Adds an Earth Engine image to the list of Earth Engine images. @@ -94,7 +94,7 @@ def add(self, image: EEDLImage) -> None: self.images.append(image) @property - def incomplete_tasks(self) -> List[EEDLImage]: + def incomplete_tasks(self) -> List["EEDLImage"]: """ List of Earth Engine images that have not been completed yet. @@ -108,7 +108,7 @@ def incomplete_tasks(self) -> List[EEDLImage]: return [image for image in self.images if image.last_task_status['state'] in self.INCOMPLETE_STATUSES] @property - def complete_tasks(self) -> List[EEDLImage]: + def complete_tasks(self) -> List["EEDLImage"]: """ List of Earth Engine images. @@ -118,7 +118,7 @@ def complete_tasks(self) -> List[EEDLImage]: return [image for image in self.images if image.last_task_status['state'] in self.COMPLETE_STATUSES + self.FAILED_STATUSES] @property - def failed_tasks(self) -> List[EEDLImage]: + def failed_tasks(self) -> List["EEDLImage"]: """ List of Earth Engine images that have either been cancelled or that have failed @@ -128,7 +128,7 @@ def failed_tasks(self) -> List[EEDLImage]: return [image for image in self.images if image.last_task_status['state'] in self.FAILED_STATUSES] @property - def downloadable_tasks(self) -> List[EEDLImage]: + def downloadable_tasks(self) -> List["EEDLImage"]: """ List of Earth Engine images that have not been cancelled or have failed. From bb39a6847156ac8b3cfe474ce3d44698955ed6b9 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Wed, 8 Nov 2023 11:58:59 -0800 Subject: [PATCH 3/9] Fix typo in variable name, update version number, and improved error message. --- eedl/__init__.py | 2 +- eedl/helpers.py | 4 ++-- eedl/image.py | 2 +- examples/basic.py | 1 + setup.cfg | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/eedl/__init__.py b/eedl/__init__.py index 0344b79..117de8c 100644 --- a/eedl/__init__.py +++ b/eedl/__init__.py @@ -1 +1 @@ -__version__ = "0.2023.10.18" +__version__ = "0.2023.11.8" diff --git a/eedl/helpers.py b/eedl/helpers.py index 67a25ce..ece5e2b 100644 --- a/eedl/helpers.py +++ b/eedl/helpers.py @@ -156,8 +156,8 @@ def extract(self): zonal_features = zonal_features_filtered image = aoi_collection.filter(ee.Filter.eq("system:time_start", image_info[1])).first() # Get the image from the collection again based on ID. - timsetamp_in_seconds = int(str(image_info[1])[:-3]) # We could divide by 1000, but then we'd coerce back from a float. This is precise. - date_string = datetime.datetime.fromtimestamp(timsetamp_in_seconds, tz=datetime.timezone.utc).strftime("%Y-%m-%d") + timestamp_in_seconds = int(str(image_info[1])[:-3]) # We could divide by 1000, but then we'd coerce back from a float. This is precise. + date_string = datetime.datetime.fromtimestamp(timestamp_in_seconds, tz=datetime.timezone.utc).strftime("%Y-%m-%d") self._single_item_extract(image, task_registry, zonal_features, aoi_attr, ee_geom, date_string, aoi_download_folder) diff --git a/eedl/image.py b/eedl/image.py index 3dd66f4..9ce14a1 100644 --- a/eedl/image.py +++ b/eedl/image.py @@ -218,7 +218,7 @@ def wait_for_images(self, self.download_ready_images(download_location) except OSError: if try_again_disk_full: - print("OSError reported. Disk may be full - will try again - clear space") + print("OSError reported. Invalid disk or the disk may be full - will try again - clear space") pass else: raise diff --git a/examples/basic.py b/examples/basic.py index 1580dd3..ed70bb2 100644 --- a/examples/basic.py +++ b/examples/basic.py @@ -17,3 +17,4 @@ def test_simple() -> None: # We need to make it check and report whether the export on the EE side was successful. This test "passed" because Earth Engine failed and there wasn't anything to download (oops) # Adam, make sure to set the folder you want results to be downloaded to eedl.image.main_task_registry.wait_for_images(r"D:\ee_export_test", sleep_time=60, callback="mosaic") + \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 210da04..3431f06 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,7 +7,7 @@ long_description_content_type=text/markdown long_description=file: README.md platforms = unix, linux, osx, cygwin, win32 url = https://github.com/water3d/eedl -version = 0.2023.10.18 +version = 0.2023.11.8 classifiers = Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only From eab7640a770262aacd8694f4c9d8c08af6217b09 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Wed, 8 Nov 2023 12:05:19 -0800 Subject: [PATCH 4/9] Fix linting issue. --- examples/basic.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/basic.py b/examples/basic.py index ed70bb2..1580dd3 100644 --- a/examples/basic.py +++ b/examples/basic.py @@ -17,4 +17,3 @@ def test_simple() -> None: # We need to make it check and report whether the export on the EE side was successful. This test "passed" because Earth Engine failed and there wasn't anything to download (oops) # Adam, make sure to set the folder you want results to be downloaded to eedl.image.main_task_registry.wait_for_images(r"D:\ee_export_test", sleep_time=60, callback="mosaic") - \ No newline at end of file From 2d6ce0ebafbcca5404b38df493c8c2d108a563b5 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Wed, 8 Nov 2023 12:59:16 -0800 Subject: [PATCH 5/9] GitHub releases now have a whl file attached. --- .github/workflows/github-release.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 779dfd3..d12a3e9 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -24,6 +24,10 @@ jobs: version=$(python -c "from eedl import __version__; print(__version__)") echo "VERSION=$version" >> $GITHUB_ENV + - name: Build WHL file + run: | + pip install setuptools wheel + python setup.py bdist_wheel - name: Create a Release uses: elgohr/Github-Release-Action@v5 @@ -32,3 +36,9 @@ jobs: with: title: ${{ env.VERSION }} + + - name: Upload WHL file to Release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release upload $(gh release view --json tagName | jq -r .tagName) dist/*.whl From 409db67c100c943467e1d20a15c3d92243bd91b1 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Thu, 9 Nov 2023 12:18:54 -0800 Subject: [PATCH 6/9] Redo creating and attaching whl file to release. --- .github/workflows/github-release.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index d12a3e9..06aa5f4 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -29,16 +29,9 @@ jobs: pip install setuptools wheel python setup.py bdist_wheel - - name: Create a Release - uses: elgohr/Github-Release-Action@v5 + - name: Create and attach whl to Release env: GH_TOKEN: ${{ github.token }} - with: - title: ${{ env.VERSION }} - - - name: Upload WHL file to Release - env: - GH_TOKEN: ${{ github.token }} run: | - gh release upload $(gh release view --json tagName | jq -r .tagName) dist/*.whl + gh release create ${{env.VERSION}} ./dist/*.whl --generate-notes From 219b98e3a81e9220d3c252e440dd90843952bfa2 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Mon, 13 Nov 2023 10:41:09 -0800 Subject: [PATCH 7/9] More small changes. --- eedl/__init__.py | 2 +- eedl/image.py | 4 ++-- examples/get_gridmet_eto.py | 6 +++--- examples/scv_et_rework.py | 15 ++++++++------- setup.cfg | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/eedl/__init__.py b/eedl/__init__.py index 117de8c..36fcc4d 100644 --- a/eedl/__init__.py +++ b/eedl/__init__.py @@ -1 +1 @@ -__version__ = "0.2023.11.8" +__version__ = "0.2023.11.13" diff --git a/eedl/image.py b/eedl/image.py index 9ce14a1..ddc0387 100644 --- a/eedl/image.py +++ b/eedl/image.py @@ -226,7 +226,7 @@ def wait_for_images(self, time.sleep(sleep_time) if len(self.failed_tasks) > 0: - message = f"{len(self.failed_tasks)} images failed to export. Example error message from first" \ + message = f"{len(self.failed_tasks)} image(s) failed to export. Example error message from first" \ f" failed image \"{self.failed_tasks[0].last_task_status['description']}\" was" \ f" \"{self.failed_tasks[0].last_task_status['error_message']}\"." \ f" Check https://code.earthengine.google.com/tasks in your web browser to see status and" \ @@ -373,7 +373,7 @@ def export(self, clip (Optional[ee.geometry.Geometry]): Defines the region of interest for export - does not perform a strict clip, which is often slower. Instead, it uses the Earth Engine export's "region" parameter to clip the results to the bounding box of the clip geometry. To clip to the actual geometry, set strict_clip to True. - strict_clip (Optional[bool]: When set to True, performs a true clip on the result so that it's not just the bounding box but also the + strict_clip (Optional[bool]): When set to True, performs a true clip on the result so that it's not just the bounding box but also the actual clipping geometry. Defaults to False. drive_root_folder (Optional[Union[str, Path]]): The folder for exporting if "drive" is selected. diff --git a/examples/get_gridmet_eto.py b/examples/get_gridmet_eto.py index 59828ab..e8f12f0 100644 --- a/examples/get_gridmet_eto.py +++ b/examples/get_gridmet_eto.py @@ -4,10 +4,10 @@ ee.Initialize() -def get_days(month, year): +def get_days(input_month: str, input_year: int) -> int: days = { '01': 31, - '02': 28 if not year == 2020 else 29, + '02': 28 if not input_year == 2020 else 29, '03': 31, '04': 30, '05': 31, @@ -20,7 +20,7 @@ def get_days(month, year): '12': 31 } - return days[month] + return days[input_month] years = (2019, 2020, 2021) diff --git a/examples/scv_et_rework.py b/examples/scv_et_rework.py index 19c1a9d..241cc41 100644 --- a/examples/scv_et_rework.py +++ b/examples/scv_et_rework.py @@ -1,17 +1,15 @@ import os -from typing import Iterable +from typing import Iterable, Optional import ee from ee import ImageCollection -# we should change the name of our Image class - it conflicts with the class image in the ee package, and people will -# likely be using both. Let's not cause confusion from eedl.image import EEDLImage import eedl ee.Initialize() -def scv_data_download_for_year(year, openet_collection=r"OpenET/ENSEMBLE/CONUS/GRIDMET/MONTHLY/v2_0", band="et_ensemble_mad") -> Iterable: +def scv_data_download_for_year(year: str, openet_collection: str = r"OpenET/ENSEMBLE/CONUS/GRIDMET/MONTHLY/v2_0", band: str = "et_ensemble_mad") -> Iterable[EEDLImage, EEDLImage]: geometry = ee.FeatureCollection("users/nrsantos/vw_extraction_mask").geometry() # so, we need two images per year - one is for all months, the other is for just the winter months @@ -52,7 +50,7 @@ def scv_data_download_for_year(year, openet_collection=r"OpenET/ENSEMBLE/CONUS/G folder="vw_et_update_2023" ) - return (annual_export_image, winter_export_image) + return annual_export_image, winter_export_image # return (annual_export_image, ) @@ -64,8 +62,11 @@ def scv_data_download_for_year(year, openet_collection=r"OpenET/ENSEMBLE/CONUS/G } -def download_updated_vw_et_images_by_year(download_folder=r"D:\vw_et_update_2023", - field_boundaries=field_boundaries_by_year) -> None: +def download_updated_vw_et_images_by_year(download_folder: str = r"D:\vw_et_update_2023", + field_boundaries: Optional[dict[str: str]] = None) -> None: + if field_boundaries is None: + field_boundaries = field_boundaries_by_year + exports_by_year = {} print("Running exports") diff --git a/setup.cfg b/setup.cfg index 3431f06..a6d9582 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,7 +7,7 @@ long_description_content_type=text/markdown long_description=file: README.md platforms = unix, linux, osx, cygwin, win32 url = https://github.com/water3d/eedl -version = 0.2023.11.8 +version = 0.2023.11.13 classifiers = Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only From caf1783f1b49b8d239eca50027017b1b2163cf91 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Tue, 14 Nov 2023 14:06:33 -0800 Subject: [PATCH 8/9] Fix requested changes. --- eedl/image.py | 6 +++--- examples/scv_et_rework.py | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/eedl/image.py b/eedl/image.py index ddc0387..ab2d9c9 100644 --- a/eedl/image.py +++ b/eedl/image.py @@ -390,9 +390,9 @@ def export(self, (drive_root_folder is None or not os.path.exists(drive_root_folder)): raise NotADirectoryError("The provided path for the Google Drive export folder is not a valid directory but" - "Drive export was specified. Either change the export type to use Google Cloud" - "and set that up properly (with a bucket, etc), or set the drive_root_folder" - "to a valid folder.") + " Drive export was specified. Either change the export type to use Google Cloud" + " and set that up properly (with a bucket, etc), or set the drive_root_folder" + " to a valid folder.") elif export_type.lower() == "drive": if drive_root_folder: self.drive_root_folder = drive_root_folder diff --git a/examples/scv_et_rework.py b/examples/scv_et_rework.py index 241cc41..d90e835 100644 --- a/examples/scv_et_rework.py +++ b/examples/scv_et_rework.py @@ -63,9 +63,7 @@ def scv_data_download_for_year(year: str, openet_collection: str = r"OpenET/ENSE def download_updated_vw_et_images_by_year(download_folder: str = r"D:\vw_et_update_2023", - field_boundaries: Optional[dict[str: str]] = None) -> None: - if field_boundaries is None: - field_boundaries = field_boundaries_by_year + field_boundaries: dict[str: str] = field_boundaries_by_year) -> None: exports_by_year = {} From 55bf7d15bdff580c2a4cd103c5c3e50565583dc1 Mon Sep 17 00:00:00 2001 From: Adam Crawford Date: Tue, 14 Nov 2023 14:07:31 -0800 Subject: [PATCH 9/9] Fix linting issue. --- examples/scv_et_rework.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/scv_et_rework.py b/examples/scv_et_rework.py index d90e835..426c740 100644 --- a/examples/scv_et_rework.py +++ b/examples/scv_et_rework.py @@ -1,5 +1,5 @@ import os -from typing import Iterable, Optional +from typing import Iterable import ee from ee import ImageCollection