772. Chaining methods on :class:`WCPSExpr` objects, e.g. `Datacube("cube").sum()`
88
99Each subclass defines the ``__str__`` method, so that executing
10- ``str(Sum(Datacube("cube"))`` returns a valid WCPS query string
10+ ``str(Sum(Datacube("cube"))) `` returns a valid WCPS query string
1111that can be sent to a WCPS server.
1212"""
1313
@@ -32,7 +32,7 @@ class WCPSExpr:
3232 an expression by chaining them, e.g
3333 ``Sum(Datacube("cube1") + Datacube("cube2"))``
3434 is the same as
35- ``Datacube("cube1").add(Datacube("cube2").sum()``. Notable exceptions are :class:`Switch` and
35+ ``Datacube("cube1").add(Datacube("cube2").sum()) ``. Notable exceptions are :class:`Switch` and
3636 :class:`Coverage`.
3737
3838 Various builtin operators are overloaded to allow writing expressions more naturally,
@@ -49,7 +49,7 @@ class WCPSExpr:
4949 """
5050
5151 def __init__ (self , operands : Optional [OperandType | list [OperandType ]] = None ):
52- self .parent : WCPSExpr = None
52+ self .parent : Optional [ WCPSExpr ] = None
5353 """
5454 A :class:`WCPSExpr` of which this expression is an operand; ``None`` if this is the root expression.
5555 E.g. in if this expression is the :class:`Datacube` object in ``Datacube("test") * 5``,
@@ -960,11 +960,11 @@ def subset(self, axes) -> Subset:
960960 :param axes: specifies a spatio-temporal subset as:
961961
962962 1. a single :class:`Axis` object: ``Axis(axis_name, low, high?, crs?)``
963- 2. a tuple of multiple :class:`Axis` objects: ``(Axis(..), Axis(..))``
963+ 2. a tuple of multiple :class:`Axis` objects: ``(Axis(... ), Axis(. ..))``
964964 3. a tuple specifying the axis subset in place: ``(axis_name, low, high?, crs?)``
965- 4. a tuple of axis subset tuples (see 3.): ``((axis_name, low, high?, crs?), (...), ..)``
966- 5. a list of :class:`Axis` objects: `[Axis(..), Axis(..), ..]`
967- 6. a list of axis subset tuples (see 3.): ``[(axis_name, low, high?, crs?), (...), ..]``
965+ 4. a tuple of axis subset tuples (see 3.): ``((axis_name, low, high?, crs?), (...), ... )``
966+ 5. a list of :class:`Axis` objects: `[Axis(... ), Axis(... ), . ..]`
967+ 6. a list of axis subset tuples (see 3.): ``[(axis_name, low, high?, crs?), (...), ... ]``
968968
969969 :return: An instance of the :class:`Subset` class
970970
@@ -982,16 +982,16 @@ def subset(self, axes) -> Subset:
982982 def __getitem__ (self , axes ) -> Subset :
983983 """
984984 Extract a spatio-temporal subset from this object as specified by the list of ``axes``
985- with an index operator ``[..]``.
985+ with an index operator ``[... ]``.
986986
987987 :param axes: specifies a spatio-temporal subset as:
988988
989989 1. a single :class:`Axis` object: ``Axis(axis_name, low, high?, crs?)``
990- 2. a tuple of multiple :class:`Axis` objects: ``(Axis(..), Axis(..))``
990+ 2. a tuple of multiple :class:`Axis` objects: ``(Axis(... ), Axis(. ..))``
991991 3. a tuple specifying the axis subset in place: ``(axis_name, low, high?, crs?)``
992- 4. a tuple of axis subset tuples (see 3.): ``((axis_name, low, high?, crs?), (...), ..)``
993- 5. a list of :class:`Axis` objects: `[Axis(..), Axis(..), ..]`
994- 6. a list of axis subset tuples (see 3.): ``[(axis_name, low, high?, crs?), (...), ..]``
992+ 4. a tuple of axis subset tuples (see 3.): ``((axis_name, low, high?, crs?), (...), ... )``
993+ 5. a list of :class:`Axis` objects: `[Axis(... ), Axis(... ), . ..]`
994+ 6. a list of axis subset tuples (see 3.): ``[(axis_name, low, high?, crs?), (...), ... ]``
995995
996996 :return: An instance of the :class:`Subset` class
997997
@@ -1014,11 +1014,11 @@ def extend(self, axes) -> Extend:
10141014 :param axes: specifies a spatio-temporal subset as:
10151015
10161016 1. a single :class:`Axis` object: ``Axis(axis_name, low, high?, crs?)``
1017- 2. a tuple of multiple :class:`Axis` objects: ``(Axis(..), Axis(..))``
1017+ 2. a tuple of multiple :class:`Axis` objects: ``(Axis(... ), Axis(. ..))``
10181018 3. a tuple specifying the axis subset in place: ``(axis_name, low, high?, crs?)``
1019- 4. a tuple of axis subset tuples (see 3.): ``((axis_name, low, high?, crs?), (...), ..)``
1020- 5. a list of :class:`Axis` objects: `[Axis(..), Axis(..), ..]`
1021- 6. a list of axis subset tuples (see 3.): ``[(axis_name, low, high?, crs?), (...), ..]``
1019+ 4. a tuple of axis subset tuples (see 3.): ``((axis_name, low, high?, crs?), (...), ... )``
1020+ 5. a list of :class:`Axis` objects: `[Axis(... ), Axis(... ), . ..]`
1021+ 6. a list of axis subset tuples (see 3.): ``[(axis_name, low, high?, crs?), (...), ... ]``
10221022
10231023 :return: An instance of the :class:`Subset` class
10241024
@@ -1081,6 +1081,8 @@ def reproject(self, target_crs: str, interpolation_method: str = None,
10811081 :param target_crs: the new CRS, e.g. "EPSG:4326"
10821082 :param interpolation_method: an optional interpolation method, one of the constants
10831083 defined by :class:`ResampleAlg`, e.g. :const:`ResampleAlg.BILINEAR`
1084+ :param axis_resolutions: optional list of target axis resolutions to
1085+ maintain in the reprojected result
10841086 :param axis_subsets: crop the result by the specified axis subsets (same syntax as for ``subset(axes)``)
10851087 :param domain_of_coverage: crop the result to the geo domain of another coverage object
10861088
@@ -1202,28 +1204,6 @@ def some(self) -> Some:
12021204 """
12031205 return Some (self )
12041206
1205- def condense (self , condense_op : CondenseOp ) -> Condense :
1206- """
1207- Condense the cell values of the current operand with the ``condense_op``.
1208- Iterator variables can be specified with the ``over()`` method, filtering of values
1209- with ``where()``, and the aggregation expression with ``using()``.
1210-
1211- :param condense_op: a condense operator, one of the constants defined in
1212- :class:`CondenseOp`, e.g. :const:`CondenseOp.PLUS`.
1213- :return: An instance of the :class:`Condense` class; at least ``over()`` and the
1214- ``using()`` methods must be called subsequently on the returned value.
1215-
1216- Examples:
1217-
1218- ```
1219- cov = Datacube("testcube")
1220- pt_var = AxisIter('$pt', 'time').of_grid_axis(cov)
1221- pt_ref = pt_var.ref()
1222- cov.condense(CondenseOp.PLUS).over(pt_var).where().where(cov["time", pt_ref] > 100).using(cov["time", pt_ref])
1223- ```
1224- """
1225- return Condense (self , condense_op )
1226-
12271207 def encode (self , data_format : str = None , format_params : str = None ) -> Encode :
12281208 """
12291209 Encode a coverage to some ``data_format``. The data format must be specified
@@ -1884,7 +1864,7 @@ def __init__(self, bands: dict):
18841864
18851865 def __str__ (self ):
18861866 bands = [f'{ k } : { v } ' for k , v in self .bands .items ()]
1887- return f'{ super ().__str__ ()} {{{ '; ' .join (bands )} }}'
1867+ return f'{ super ().__str__ ()} {{{ "; " .join (bands )} }}'
18881868
18891869
18901870# ---------------------------------------------------------------------------------
@@ -1911,7 +1891,7 @@ def __str__(self):
19111891 ret += f':"{ self .crs } "'
19121892 operands = [str (op ) for op in self .operands ]
19131893 operands = [op if op != '"*"' else '*' for op in operands ]
1914- ret += f'({ ':' .join (operands )} )'
1894+ ret += f'({ ":" .join (operands )} )'
19151895 return ret
19161896
19171897 @staticmethod
@@ -1923,12 +1903,12 @@ def get_axis_list(axes: Union[Axis, slice, tuple[Axis], AxisTuple, tuple[AxisTup
19231903
19241904 - a single Axis, e.g. ``Axis("X", 0, 100.5, "EPSG:4326")``
19251905 - a single slice, e.g. ``"X":1``, or ``"X":1:15.3``
1926- - a tuple of Axis objects, e.g. ``(Axis(..), Axis(..), ..)``
1906+ - a tuple of Axis objects, e.g. ``(Axis(... ), Axis(... ), . ..)``
19271907 - a single in-place axis tuple, e.g. ``("X", 0, 100.5, "EPSG:4326")``
1928- - a tuple of axis tuples, e.g. ``(("X", 0, 100.5), (..), ..)``
1908+ - a tuple of axis tuples, e.g. ``(("X", 0, 100.5), (... ), . ..)``
19291909 - a tuple of slices, e.g. ``("X":1, "Y":0:100.5)``
1930- - a list of Axis objects, e.g. ``[Axis(..), Axis(..), ..]``
1931- - a list of axis tuples, e.g. ``[("X", 0, 100.5), (..), ..]``
1910+ - a list of Axis objects, e.g. ``[Axis(... ), Axis(... ), . ..]``
1911+ - a list of axis tuples, e.g. ``[("X", 0, 100.5), (... ), . ..]``
19321912
19331913 :raise: a :class:`WCPSClientException` in case ``axes`` is in invalid shape.
19341914 """
@@ -1971,8 +1951,7 @@ def __init__(self, op: WCPSExpr, axes):
19711951 super ().__init__ (operands = [op ] + Axis .get_axis_list (axes ))
19721952
19731953 def __str__ (self ):
1974- axis_subsets = [str (op ) for op in self .operands [1 :]]
1975- axis_subsets_str = ', ' .join (axis_subsets )
1954+ axis_subsets_str = _list_to_str (self .operands [1 :], ', ' )
19761955 return f'{ super ().__str__ ()} { self .operands [0 ]} [{ axis_subsets_str } ]'
19771956
19781957
@@ -1985,8 +1964,7 @@ def __init__(self, op: WCPSExpr, axes):
19851964 super ().__init__ (operands = [op ] + Axis .get_axis_list (axes ))
19861965
19871966 def __str__ (self ):
1988- axis_subsets = [str (op ) for op in self .operands [1 :]]
1989- axis_subsets_str = ', ' .join (axis_subsets )
1967+ axis_subsets_str = _list_to_str (self .operands [1 :], ', ' )
19901968 return f'{ super ().__str__ ()} extend({ self .operands [0 ]} , {{ { axis_subsets_str } }})'
19911969
19921970
@@ -2023,15 +2001,13 @@ def __str__(self):
20232001 ret = f'{ super ().__str__ ()} scale({ self .operands [0 ]} , {{ '
20242002
20252003 if self .axis_subsets is not None :
2026- axis_subsets = [str (op ) for op in self .operands [1 :]]
2027- ret += ', ' .join (axis_subsets )
2004+ ret += _list_to_str (self .operands [1 :], ', ' )
20282005 elif self .another_coverage is not None :
20292006 ret += f'imageCrsDomain({ self .another_coverage } )'
20302007 elif self .scale_factor is not None :
20312008 return f'{ super ().__str__ ()} scale({ self .operands [0 ]} , { self .scale_factor } )'
20322009 elif self .scale_factors is not None :
2033- axis_subsets = [str (op ) for op in self .operands [1 :]]
2034- ret += ', ' .join (axis_subsets )
2010+ ret += _list_to_str (self .operands [1 :], ', ' )
20352011
20362012 ret += ' })'
20372013 return ret
@@ -2135,8 +2111,7 @@ def __str__(self):
21352111 axis_subsets_str = ', ' .join (axis_subsets )
21362112 ret += f', {{ { axis_subsets_str } }}'
21372113 if self .axis_subsets is not None :
2138- axis_subsets = [str (axis ) for axis in self .axis_subsets ]
2139- axis_subsets_str = ', ' .join (axis_subsets )
2114+ axis_subsets_str = _list_to_str (self .axis_subsets , ', ' )
21402115 ret += f', {{ { axis_subsets_str } }}'
21412116 elif self .subset_domain is not None :
21422117 ret += f', {{ domain({ self .subset_domain } ) }}'
@@ -2526,7 +2501,7 @@ def __str__(self):
25262501 :raise: :class:`WCPSClientException` if no iterator variables or a using expression have been set.
25272502 """
25282503 self ._validate ()
2529- over = ', ' . join ( str ( axis_iter ) for axis_iter in self .iter_vars )
2504+ over = _list_to_str ( self .iter_vars , ', ' )
25302505 ret = f'{ super ().__str__ ()} (condense { self .condense_op } over { over } '
25312506 if self .where_where is not None :
25322507 ret += f' where { self .where_where } '
@@ -2640,7 +2615,7 @@ def __str__(self):
26402615 """
26412616 self ._validate ()
26422617 ret = super ().__str__ ()
2643- over = ', ' . join ( str ( axis_iter ) for axis_iter in self .iter_vars )
2618+ over = _list_to_str ( self .iter_vars , ', ' )
26442619 ret += f'(coverage { self .name } over { over } values { self .values_clause } )'
26452620 return ret
26462621
@@ -2775,6 +2750,34 @@ def default(self, default_expr: WCPSExpr) -> Switch:
27752750 return self
27762751
27772752
2753+ # ---------------------------------------------------------------------------------
2754+ # user-defined functions
2755+
2756+ class Udf (WCPSExpr ):
2757+ """
2758+ Execute a user-defined function (UDF), or any other WCPS function for which
2759+ no concrete class exists yet.
2760+
2761+ :param function_name: the UDF name, e.g. image.stretch
2762+ :param operands: a list of operands that the UDF expects
2763+
2764+ Examples: ::
2765+
2766+ stretch = Udf('stretch', Datacube('cov1'))
2767+ """
2768+
2769+ def __init__ (self , function_name : str , operands : list [OperandType ]):
2770+ super ().__init__ (operands = operands )
2771+ self .function_name = function_name
2772+
2773+ def __str__ (self ):
2774+ ret = super ().__str__ ()
2775+ ret += f'{ self .function_name } ('
2776+ ret += _list_to_str (self .operands , ', ' )
2777+ ret += ')'
2778+ return ret
2779+
2780+
27782781# ---------------------------------------------------------------------------------
27792782# data encode/decode
27802783
@@ -2784,6 +2787,10 @@ class Encode(WCPSExpr):
27842787 with the :meth:`to` method if it isn't provided here. Format parameters can
27852788 be specified with the :meth:`params` method.
27862789
2790+ :param op: the coverage expression to encode.
2791+ :param data_format: the data format, e.g. "GTiff"
2792+ :param format_params: additional format parameters the influence the encoding
2793+
27872794 Examples:
27882795
27892796 - ``Encode(Datacube("test")).to("GTiff")``
@@ -2792,11 +2799,6 @@ class Encode(WCPSExpr):
27922799 """
27932800
27942801 def __init__ (self , op : WCPSExpr , data_format : str = None , format_params : str = None ):
2795- """
2796- :param op: the coverage expression to encode.
2797- :param data_format: the data format, e.g. "GTiff"
2798- :param format_params: additional format parameters the influence the encoding
2799- """
28002802 super ().__init__ (operands = [op ])
28012803 self .data_format = data_format
28022804 self .format_params = format_params
@@ -2833,3 +2835,18 @@ class WCPSClientException(Exception):
28332835 """
28342836 An exception thrown by this library.
28352837 """
2838+
2839+
2840+ def _list_to_str (lst : list , sep : str ) -> str :
2841+ """
2842+ Convert a list of items into a single string. Each item is converted to a string
2843+ and separated by a specified separator in the result.
2844+
2845+ :param lst: The list of items to be joined into a string. Each item in the list
2846+ will be converted to a string before joining.
2847+ :param sep: The separator to use between each item in the resulting string.
2848+
2849+ :return: A single string containing all items from the list, separated by the
2850+ specified separator.
2851+ """
2852+ return sep .join ([str (item ) for item in lst ])
0 commit comments