[Git][debian-gis-team/asf-search][upstream] New upstream version 6.7.3
Antonio Valentino (@antonio.valentino)
gitlab at salsa.debian.org
Wed Jan 10 06:30:27 GMT 2024
Antonio Valentino pushed to branch upstream at Debian GIS Project / asf-search
Commits:
9bcf72e4 by Antonio Valentino at 2024-01-10T06:25:58+00:00
New upstream version 6.7.3
- - - - -
10 changed files:
- CHANGELOG.md
- asf_search/ASFSearchOptions/validators.py
- asf_search/constants/PRODUCT_TYPE.py
- asf_search/search/geo_search.py
- asf_search/search/granule_search.py
- asf_search/search/product_search.py
- asf_search/search/search.py
- asf_search/search/search_count.py
- asf_search/search/search_generator.py
- setup.py
Changes:
=====================================
CHANGELOG.md
=====================================
@@ -25,9 +25,22 @@ and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-->
+------
+## [v6.7.3](https://github.com/asfadmin/Discovery-asf_search/compare/v6.7.2...v6.7.3)
+### Added
+- Adds OPERA-S1 constants `RTC`, `RTC_STATIC` (RTC-STATIC), `CSLC`, `CSLC_STATIC` (CSLC-STATIC) to `PRODUCT_TYPE.py`
+
+### Fixed
+- Harmonizes `search()`, `geo_search()`, and `search_count()` parameters
+- Updates python version requirement in `setup.py` to 3.8+
+
+### Changed
+- search method params with `Iterable` type hinting now changed to `Sequence`
+- search method param validators updated to support `Sequence` type
+
------
## [v6.7.2](https://github.com/asfadmin/Discovery-asf_search/compare/v6.7.1...v6.7.2)
-### Adds
+### Added
- Adds constants for `dataset` keyword, under `asf_search.DATASET`
- Adds CALVAL concept-ids to 'OPERA-S1' dataset
- Adds `validityStartDate` for applicable OPERA-S1 products
=====================================
asf_search/ASFSearchOptions/validators.py
=====================================
@@ -2,7 +2,7 @@ import dateparser
import datetime
import requests
-from typing import Union, Tuple, TypeVar, Callable, List, Type
+from typing import Union, Tuple, TypeVar, Callable, List, Type, Sequence
import math
from shapely import wkt, errors
@@ -93,60 +93,64 @@ def parse_float_range(value: Tuple[float, float]) -> Tuple[float, float]:
return parse_range(value, float)
-# Parse and validate a list of values, using h() to validate each value: "a,b,c", "1,2,3", "1.1,2.3"
-def parse_list(value: list, h) -> list:
- if not isinstance(value, list):
+# Parse and validate an iterable of values, using h() to validate each value: "a,b,c", "1,2,3", "1.1,2.3"
+def parse_list(value: Sequence, h) -> List:
+ if not isinstance(value, Sequence) or isinstance(value, str):
value = [value]
try:
return [h(a) for a in value]
except ValueError as exc:
raise ValueError(f'Invalid {h.__name__} list: {exc}') from exc
-# Parse and validate a list of strings: "foo,bar,baz"
-def parse_string_list(value: List[str]) -> List[str]:
+# Parse and validate an iterable of strings: "foo,bar,baz"
+def parse_string_list(value: Sequence[str]) -> List[str]:
return parse_list(value, str)
-# Parse and validate a list of integers: "1,2,3"
-def parse_int_list(value: List[int]) -> List[int]:
+# Parse and validate an iterable of integers: "1,2,3"
+def parse_int_list(value: Sequence[int]) -> List[int]:
return parse_list(value, int)
-# Parse and validate a list of floats: "1.1,2.3,4.5"
-def parse_float_list(value: List[float]) -> List[float]:
+# Parse and validate an iterable of floats: "1.1,2.3,4.5"
+def parse_float_list(value: Sequence[float]) -> List[float]:
return parse_list(value, float)
-def parse_number_or_range(value: Union[list, Tuple[number, number]], h):
+def parse_number_or_range(value: Union[List, Tuple[number, number], range], h):
try:
if isinstance(value, tuple):
return parse_range(value, h)
+ if isinstance(value, range):
+ if value.step == 1:
+ return [value.start, value.stop]
+
return h(value)
+
except ValueError as exc:
raise ValueError(f'Invalid {h.__name__} or range: {exc}') from exc
-
-
-# Parse and validate a list of numbers or number ranges, using h() to validate each value: "1,2,3-5", "1.1,1.4,5.1-6.7"
-def parse_number_or_range_list(value: list, h) -> list:
- if not isinstance(value, list):
+
+# Parse and validate an iterable of numbers or number ranges, using h() to validate each value: "1,2,3-5", "1.1,1.4,5.1-6.7"
+def parse_number_or_range_list(value: Sequence, h) -> List:
+ if not isinstance(value, Sequence) or isinstance(value, range):
value = [value]
- return [parse_number_or_range(x, h) for x in value]
+ return [parse_number_or_range(x, h) for x in value]
-# Parse and validate a list of integers or integer ranges: "1,2,3-5"
-def parse_int_or_range_list(value: list) -> list:
+# Parse and validate an iterable of integers or integer ranges: "1,2,3-5"
+def parse_int_or_range_list(value: Sequence) -> List:
return parse_number_or_range_list(value, int)
-# Parse and validate a list of float or float ranges: "1.0,2.0,3.0-5.0"
-def parse_float_or_range_list(value: list) -> list:
+# Parse and validate an iterable of float or float ranges: "1.0,2.0,3.0-5.0"
+def parse_float_or_range_list(value: Sequence) -> List:
return parse_number_or_range_list(value, parse_float)
# Parse and validate a coordinate list
-def parse_coord_list(value: List[float]) -> List[float]:
- if not isinstance(value, list):
- raise ValueError(f'Invalid coord list list: Must pass in a list. Got {type(value)}.')
+def parse_coord_list(value: Sequence[float]) -> List[float]:
+ if not isinstance(value, Sequence):
+ raise ValueError(f'Invalid coord list list: Must pass in an iterable. Got {type(value)}.')
for coord in value:
try:
float(coord)
@@ -158,9 +162,9 @@ def parse_coord_list(value: List[float]) -> List[float]:
# Parse and validate a bbox coordinate list
-def parse_bbox_list(value: List[float]) -> List[float]:
+def parse_bbox_list(value: Sequence[float]) -> List[float]:
try:
- # This also makes sure v is a list:
+ # This also makes sure v is an iterable:
value = parse_coord_list(value)
except ValueError as exc:
raise ValueError(f'Invalid bbox: {exc}') from exc
@@ -170,9 +174,9 @@ def parse_bbox_list(value: List[float]) -> List[float]:
# Parse and validate a point coordinate list
-def parse_point_list(value: List[float]) -> List[float]:
+def parse_point_list(value: Sequence[float]) -> List[float]:
try:
- # This also makes sure v is a list:
+ # This also makes sure v is an iterable:
value = parse_coord_list(value)
except ValueError as exc:
raise ValueError(f'Invalid point: {exc}') from exc
=====================================
asf_search/constants/PRODUCT_TYPE.py
=====================================
@@ -94,3 +94,9 @@ THREEFP = '3FP'
# SEASAT
GEOTIFF = 'GEOTIFF'
# L1 provided by RADARSAT
+
+# OPERA-S1
+RTC = 'RTC'
+CSLC = 'CSLC'
+RTC_STATIC = 'RTC-STATIC'
+CSLS_STATIC = 'CSLC-STATIC'
\ No newline at end of file
=====================================
asf_search/search/geo_search.py
=====================================
@@ -1,4 +1,4 @@
-from typing import Union, Iterable
+from typing import Tuple, Union, Sequence
import datetime
from copy import copy
@@ -8,25 +8,43 @@ from asf_search.ASFSearchResults import ASFSearchResults
def geo_search(
- intersectsWith: str,
- absoluteOrbit: Iterable[Union[int, range]] = None,
- asfFrame: Iterable[Union[int, range]] = None,
- beamMode: Iterable[str] = None,
- beamSwath: Union[str, Iterable[str]] = None,
- campaign: Union[str, Iterable[str]] = None,
+ absoluteOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ asfFrame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ beamMode: Union[str, Sequence[str]] = None,
+ beamSwath: Union[str, Sequence[str]] = None,
+ campaign: Union[str, Sequence[str]] = None,
+ maxDoppler: float = None,
+ minDoppler: float = None,
end: Union[datetime.datetime, str] = None,
- flightDirection: Iterable[str] = None,
- frame: Iterable[Union[int, range]] = None,
- instrument: Iterable[str] = None,
- lookDirection: Iterable[str] = None,
- platform: Iterable[str] = None,
- polarization: Iterable[str] = None,
+ maxFaradayRotation: float = None,
+ minFaradayRotation: float = None,
+ flightDirection: str = None,
+ flightLine: str = None,
+ frame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ granule_list: Union[str, Sequence[str]] = None,
+ groupID: Union[str, Sequence[str]] = None,
+ insarStackId: str = None,
+ instrument: Union[str, Sequence[str]] = None,
+ intersectsWith: str = None,
+ lookDirection: Union[str, Sequence[str]] = None,
+ offNadirAngle: Union[float, Tuple[float, float], Sequence[Union[float, Tuple[float, float]]]] = None,
+ platform: Union[str, Sequence[str]] = None,
+ polarization: Union[str, Sequence[str]] = None,
processingDate: Union[datetime.datetime, str] = None,
- processingLevel: Iterable[str] = None,
- relativeOrbit: Iterable[Union[int, range]] = None,
+ processingLevel: Union[str, Sequence[str]] = None,
+ product_list: Union[str, Sequence[str]] = None,
+ relativeOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ season: Tuple[int, int] = None,
start: Union[datetime.datetime, str] = None,
+ absoluteBurstID: Union[int, Sequence[int]] = None,
+ relativeBurstID: Union[int, Sequence[int]] = None,
+ fullBurstID: Union[str, Sequence[str]] = None,
+ collections: Union[str, Sequence[str]] = None,
+ temporalBaselineDays: Union[str, Sequence[str]] = None,
+ operaBurstID: Union[str, Sequence[str]] = None,
+ dataset: Union[str, Sequence[str]] = None,
maxResults: int = None,
- opts: ASFSearchOptions = None
+ opts: ASFSearchOptions = None,
) -> ASFSearchResults:
"""
Performs a geographic search using the ASF SearchAPI
=====================================
asf_search/search/granule_search.py
=====================================
@@ -1,4 +1,4 @@
-from typing import Iterable
+from typing import Sequence
from copy import copy
from asf_search.search import search
@@ -7,8 +7,8 @@ from asf_search.ASFSearchResults import ASFSearchResults
def granule_search(
- granule_list: Iterable[str],
- opts: ASFSearchOptions = None,
+ granule_list: Sequence[str],
+ opts: ASFSearchOptions = None
) -> ASFSearchResults:
"""
Performs a granule name search using the ASF SearchAPI
=====================================
asf_search/search/product_search.py
=====================================
@@ -1,4 +1,4 @@
-from typing import Iterable
+from typing import Sequence
from copy import copy
from asf_search.search import search
@@ -7,7 +7,7 @@ from asf_search.ASFSearchResults import ASFSearchResults
def product_search(
- product_list: Iterable[str],
+ product_list: Sequence[str],
opts: ASFSearchOptions = None
) -> ASFSearchResults:
"""
=====================================
asf_search/search/search.py
=====================================
@@ -1,4 +1,4 @@
-from typing import Union, Iterable, Tuple
+from typing import Union, Sequence, Tuple
from copy import copy
import datetime
@@ -7,11 +7,11 @@ from asf_search.ASFSearchOptions import ASFSearchOptions
from asf_search.search.search_generator import search_generator
def search(
- absoluteOrbit: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- asfFrame: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- beamMode: Union[str, Iterable[str]] = None,
- beamSwath: Union[str, Iterable[str]] = None,
- campaign: Union[str, Iterable[str]] = None,
+ absoluteOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ asfFrame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ beamMode: Union[str, Sequence[str]] = None,
+ beamSwath: Union[str, Sequence[str]] = None,
+ campaign: Union[str, Sequence[str]] = None,
maxDoppler: float = None,
minDoppler: float = None,
end: Union[datetime.datetime, str] = None,
@@ -19,29 +19,29 @@ def search(
minFaradayRotation: float = None,
flightDirection: str = None,
flightLine: str = None,
- frame: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- granule_list: Union[str, Iterable[str]] = None,
- groupID: Union[str, Iterable[str]] = None,
+ frame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ granule_list: Union[str, Sequence[str]] = None,
+ groupID: Union[str, Sequence[str]] = None,
insarStackId: str = None,
- instrument: Union[str, Iterable[str]] = None,
+ instrument: Union[str, Sequence[str]] = None,
intersectsWith: str = None,
- lookDirection: Union[str, Iterable[str]] = None,
- offNadirAngle: Union[float, Tuple[float, float], Iterable[Union[float, Tuple[float, float]]]] = None,
- platform: Union[str, Iterable[str]] = None,
- polarization: Union[str, Iterable[str]] = None,
+ lookDirection: Union[str, Sequence[str]] = None,
+ offNadirAngle: Union[float, Tuple[float, float], Sequence[Union[float, Tuple[float, float]]]] = None,
+ platform: Union[str, Sequence[str]] = None,
+ polarization: Union[str, Sequence[str]] = None,
processingDate: Union[datetime.datetime, str] = None,
- processingLevel: Union[str, Iterable[str]] = None,
- product_list: Union[str, Iterable[str]] = None,
- relativeOrbit: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
+ processingLevel: Union[str, Sequence[str]] = None,
+ product_list: Union[str, Sequence[str]] = None,
+ relativeOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
season: Tuple[int, int] = None,
start: Union[datetime.datetime, str] = None,
- absoluteBurstID: Union[int, Iterable[int]] = None,
- relativeBurstID: Union[int, Iterable[int]] = None,
- fullBurstID: Union[str, Iterable[str]] = None,
- collections: Union[str, Iterable[str]] = None,
- temporalBaselineDays: Union[str, Iterable[str]] = None,
- operaBurstID: Union[str, Iterable[str]] = None,
- dataset: Union[str, Iterable[str]] = None,
+ absoluteBurstID: Union[int, Sequence[int]] = None,
+ relativeBurstID: Union[int, Sequence[int]] = None,
+ fullBurstID: Union[str, Sequence[str]] = None,
+ collections: Union[str, Sequence[str]] = None,
+ temporalBaselineDays: Union[str, Sequence[str]] = None,
+ operaBurstID: Union[str, Sequence[str]] = None,
+ dataset: Union[str, Sequence[str]] = None,
maxResults: int = None,
opts: ASFSearchOptions = None,
) -> ASFSearchResults:
=====================================
asf_search/search/search_count.py
=====================================
@@ -1,5 +1,5 @@
import datetime
-from typing import Iterable, Tuple, Union
+from typing import Sequence, Tuple, Union
from copy import copy
from asf_search.ASFSearchOptions import ASFSearchOptions
from asf_search.CMR.subquery import build_subqueries
@@ -9,11 +9,11 @@ from asf_search import INTERNAL
def search_count(
- absoluteOrbit: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- asfFrame: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- beamMode: Union[str, Iterable[str]] = None,
- beamSwath: Union[str, Iterable[str]] = None,
- campaign: Union[str, Iterable[str]] = None,
+ absoluteOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ asfFrame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ beamMode: Union[str, Sequence[str]] = None,
+ beamSwath: Union[str, Sequence[str]] = None,
+ campaign: Union[str, Sequence[str]] = None,
maxDoppler: float = None,
minDoppler: float = None,
end: Union[datetime.datetime, str] = None,
@@ -21,22 +21,29 @@ def search_count(
minFaradayRotation: float = None,
flightDirection: str = None,
flightLine: str = None,
- frame: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- granule_list: Union[str, Iterable[str]] = None,
- groupID: Union[str, Iterable[str]] = None,
+ frame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ granule_list: Union[str, Sequence[str]] = None,
+ groupID: Union[str, Sequence[str]] = None,
insarStackId: str = None,
- instrument: Union[str, Iterable[str]] = None,
+ instrument: Union[str, Sequence[str]] = None,
intersectsWith: str = None,
- lookDirection: Union[str, Iterable[str]] = None,
- offNadirAngle: Union[float, Tuple[float, float], Iterable[Union[float, Tuple[float, float]]]] = None,
- platform: Union[str, Iterable[str]] = None,
- polarization: Union[str, Iterable[str]] = None,
+ lookDirection: Union[str, Sequence[str]] = None,
+ offNadirAngle: Union[float, Tuple[float, float], Sequence[Union[float, Tuple[float, float]]]] = None,
+ platform: Union[str, Sequence[str]] = None,
+ polarization: Union[str, Sequence[str]] = None,
processingDate: Union[datetime.datetime, str] = None,
- processingLevel: Union[str, Iterable[str]] = None,
- product_list: Union[str, Iterable[str]] = None,
- relativeOrbit: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
+ processingLevel: Union[str, Sequence[str]] = None,
+ product_list: Union[str, Sequence[str]] = None,
+ relativeOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
season: Tuple[int, int] = None,
start: Union[datetime.datetime, str] = None,
+ absoluteBurstID: Union[int, Sequence[int]] = None,
+ relativeBurstID: Union[int, Sequence[int]] = None,
+ fullBurstID: Union[str, Sequence[str]] = None,
+ collections: Union[str, Sequence[str]] = None,
+ temporalBaselineDays: Union[str, Sequence[str]] = None,
+ operaBurstID: Union[str, Sequence[str]] = None,
+ dataset: Union[str, Sequence[str]] = None,
maxResults: int = None,
opts: ASFSearchOptions = None,
) -> int:
=====================================
asf_search/search/search_generator.py
=====================================
@@ -1,5 +1,5 @@
import logging
-from typing import Generator, Union, Iterable, Tuple, List
+from typing import Generator, Union, Sequence, Tuple, List
from copy import copy
from requests.exceptions import HTTPError
from requests import ReadTimeout, Response
@@ -21,11 +21,11 @@ from asf_search.WKT.validate_wkt import validate_wkt
from asf_search.search.error_reporting import report_search_error
def search_generator(
- absoluteOrbit: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- asfFrame: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- beamMode: Union[str, Iterable[str]] = None,
- beamSwath: Union[str, Iterable[str]] = None,
- campaign: Union[str, Iterable[str]] = None,
+ absoluteOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ asfFrame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ beamMode: Union[str, Sequence[str]] = None,
+ beamSwath: Union[str, Sequence[str]] = None,
+ campaign: Union[str, Sequence[str]] = None,
maxDoppler: float = None,
minDoppler: float = None,
end: Union[datetime.datetime, str] = None,
@@ -33,29 +33,29 @@ def search_generator(
minFaradayRotation: float = None,
flightDirection: str = None,
flightLine: str = None,
- frame: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
- granule_list: Union[str, Iterable[str]] = None,
- groupID: Union[str, Iterable[str]] = None,
+ frame: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
+ granule_list: Union[str, Sequence[str]] = None,
+ groupID: Union[str, Sequence[str]] = None,
insarStackId: str = None,
- instrument: Union[str, Iterable[str]] = None,
+ instrument: Union[str, Sequence[str]] = None,
intersectsWith: str = None,
- lookDirection: Union[str, Iterable[str]] = None,
- offNadirAngle: Union[float, Tuple[float, float], Iterable[Union[float, Tuple[float, float]]]] = None,
- platform: Union[str, Iterable[str]] = None,
- polarization: Union[str, Iterable[str]] = None,
+ lookDirection: Union[str, Sequence[str]] = None,
+ offNadirAngle: Union[float, Tuple[float, float], Sequence[Union[float, Tuple[float, float]]]] = None,
+ platform: Union[str, Sequence[str]] = None,
+ polarization: Union[str, Sequence[str]] = None,
processingDate: Union[datetime.datetime, str] = None,
- processingLevel: Union[str, Iterable[str]] = None,
- product_list: Union[str, Iterable[str]] = None,
- relativeOrbit: Union[int, Tuple[int, int], Iterable[Union[int, Tuple[int, int]]]] = None,
+ processingLevel: Union[str, Sequence[str]] = None,
+ product_list: Union[str, Sequence[str]] = None,
+ relativeOrbit: Union[int, Tuple[int, int], range, Sequence[Union[int, Tuple[int, int], range]]] = None,
season: Tuple[int, int] = None,
start: Union[datetime.datetime, str] = None,
- absoluteBurstID: Union[int, Iterable[int]] = None,
- relativeBurstID: Union[int, Iterable[int]] = None,
- fullBurstID: Union[str, Iterable[str]] = None,
- collections: Union[str, Iterable[str]] = None,
- temporalBaselineDays: Union[str, Iterable[str]] = None,
- operaBurstID: Union[str, Iterable[str]] = None,
- dataset: Union[str, Iterable[str]] = None,
+ absoluteBurstID: Union[int, Sequence[int]] = None,
+ relativeBurstID: Union[int, Sequence[int]] = None,
+ fullBurstID: Union[str, Sequence[str]] = None,
+ collections: Union[str, Sequence[str]] = None,
+ temporalBaselineDays: Union[str, Sequence[str]] = None,
+ operaBurstID: Union[str, Sequence[str]] = None,
+ dataset: Union[str, Sequence[str]] = None,
maxResults: int = None,
opts: ASFSearchOptions = None,
) -> Generator[ASFSearchResults, None, None]:
=====================================
setup.py
=====================================
@@ -43,7 +43,7 @@ setup(
packages=find_packages(exclude=["tests.*", "tests", "examples.*", "examples"]),
package_dir={'asf_search': 'asf_search'},
include_package_data=True,
- python_requires='>=3.6',
+ python_requires='>=3.8',
install_requires=requirements,
extras_require={ "test": test_requirements },
license='BSD',
@@ -56,8 +56,6 @@ setup(
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.6",
- "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Software Development",
View it on GitLab: https://salsa.debian.org/debian-gis-team/asf-search/-/commit/9bcf72e408840de97c0a2c6c7fd1f01568222899
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/asf-search/-/commit/9bcf72e408840de97c0a2c6c7fd1f01568222899
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20240110/48f64b02/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list