diff --git a/HISTORY.rst b/HISTORY.rst
index 2e0e319a..1d6a6ebc 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -4,6 +4,7 @@ History
 
 0.18.x
 ------
+* `xclim.sdba.detrending` objects can now act on groups.
 * Replaced `dask[complete]` with `dask[array]` in basic installation and added `distributed` to `docs` build dependencies.
 * `xclim.core.locales` now supported in Windows build environments.
 * `ensembles.ensemble_percentiles` modified to compute along a `percentiles` dimension by default, instead of creating different variables.
diff --git a/setup.cfg b/setup.cfg
index 07c12a04..4b6bea72 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 0.17.3-beta
+current_version = 0.17.4-beta
 commit = False
 tag = False
 parse = (?P<major>\d+)\.(?P<minor>\d+).(?P<patch>\d+)(\-(?P<release>[a-z]+))?
diff --git a/setup.py b/setup.py
index 218b76cc..2222a0ea 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@ URL = "https://github.com/Ouranosinc/xclim"
 AUTHOR = "Travis Logan"
 AUTHOR_EMAIL = "logan.travis@ouranos.ca"
 REQUIRES_PYTHON = ">=3.6.0"
-VERSION = "0.17.3-beta"
+VERSION = "0.17.4-beta"
 LICENSE = "Apache Software License 2.0"
 
 with open("README.rst") as readme_file:
diff --git a/xclim/__init__.py b/xclim/__init__.py
index ae5f1b3b..4c244691 100644
--- a/xclim/__init__.py
+++ b/xclim/__init__.py
@@ -10,4 +10,4 @@ from xclim.indicators import seaIce
 
 __author__ = """Travis Logan"""
 __email__ = "logan.travis@ouranos.ca"
-__version__ = "0.17.3-beta"
+__version__ = "0.17.4-beta"
diff --git a/xclim/sdba/__init__.py b/xclim/sdba/__init__.py
index 2a197896..85d8a64c 100644
--- a/xclim/sdba/__init__.py
+++ b/xclim/sdba/__init__.py
@@ -37,10 +37,10 @@ A generic bias adjustment process is laid out as follows:
 - preprocessing on `ref`, `hist` and `sim` (using methods in `xclim.sdba.processing` or `xclim.sdba.detrending`)
 - creating the adjustment object `Adj = Adjustment(**kwargs)` (from `xclim.sdba.adjustment`)
 - training `Adj.train(obs, sim)`
-- adjustment with corresponding arguments `scen = Adj.adjust(sim, **kwargs)`
+- adjustment `scen = Adj.adjust(sim, **kwargs)`
 - post-processing on `scen` (for example: re-trending)
 
-The train-adjust approach allows to inspect the trained adjustment object. The trained information is stored in
+The train-adjust approach allows to inspect the trained adjustment object. The training information is stored in
 the underlying `Adj.ds` dataset and always has a `af` variable with the adjustment factors. Its layout and the
 other available variables vary between the different algorithm, refer to :ref:`bias-adjustment-algos`.
 
diff --git a/xclim/sdba/adjustment.py b/xclim/sdba/adjustment.py
index 6aa1ccde..c1fbccfb 100644
--- a/xclim/sdba/adjustment.py
+++ b/xclim/sdba/adjustment.py
@@ -132,7 +132,7 @@ class EmpiricalQuantileMapping(BaseAdjustment):
 
     Parameters
     ----------
-    At init:
+    At instantiation:
 
     nquantiles : int
       The number of quantiles to use. Two endpoints at 1e-6 and 1 - 1e-6 will be added.
@@ -141,7 +141,7 @@ class EmpiricalQuantileMapping(BaseAdjustment):
     group : Union[str, Grouper]
       The grouping information. See :py:class:`xclim.sdba.base.Grouper` for details.
 
-    In adjust:
+    In adjustment:
 
     interp : {'nearest', 'linear', 'cubic'}
       The interpolation method to use when interpolating the adjustment factors. Defaults to "nearset".
@@ -201,12 +201,9 @@ class DetrendedQuantileMapping(EmpiricalQuantileMapping):
     1. A scaling factor that would make the mean of `hist` match the mean of `ref` is computed.
     2. `ref` and `hist` are normalized by removing the group-wise mean.
     3. Adjustment factors are computed between the quantiles of the normalized `ref` and `hist`.
-    4. `sim` is corrected by the scaling factor, normalized by the group-wise mean and then detrended using a linear fit.*
+    4. `sim` is corrected by the scaling factor, and detrended group-wise using a linear fit.
     5. Values of detrended `sim` are matched to the corresponding quantiles of normalized `hist` and corrected accordingly.
-    6. The group-wise mean and trend are put back on the result.*
-
-    * Steps 4 and 6 include a group-wise normalization to overcome the fact that detrending is not made group-wise.
-    A future release of xclim will have grouped detrending and not require this extra step any more.
+    6. The trend is put back on the result.
 
     .. math::
 
@@ -217,7 +214,7 @@ class DetrendedQuantileMapping(EmpiricalQuantileMapping):
 
     Parameters
     ----------
-    At init:
+    At instantiation:
 
     nquantiles : int
       The number of quantiles to use. Two endpoints at 1e-6 and 1 - 1e-6 will be added.
@@ -226,7 +223,7 @@ class DetrendedQuantileMapping(EmpiricalQuantileMapping):
     group : Union[str, Grouper]
       The grouping information. See :py:class:`xclim.sdba.base.Grouper` for details.
 
-    In adjust:
+    In adjustment:
 
     interp : {'nearest', 'linear', 'cubic'}
       The interpolation method to use when interpolating the adjustment factors. Defaults to "nearest".
@@ -261,39 +258,19 @@ class DetrendedQuantileMapping(EmpiricalQuantileMapping):
             self.kind,
         )
 
-        # Normalize sim group-wise
-        # This group-wise pre normalization + reapplication further down
-        # is to circumvent #442 (detrending is not groupwise)
-        mu_sim = self.group.apply("mean", sim)
-        sim_norm = apply_correction(
-            sim,
-            broadcast(
-                invert(mu_sim, kind=self.kind), sim, group=self.group, interp=interp,
-            ),
-            kind=self.kind,
-        )
-
-        # Find trend on sim (for debugging purpose, the detrending is overridable)
+        # Find trend on sim
         if isinstance(detrend, int):
-            detrend = PolyDetrend(degree=detrend, kind=self.kind)
+            detrend = PolyDetrend(degree=detrend, kind=self.kind, group=self.group)
 
-        sim_fit = detrend.fit(sim_norm)
-        sim_detrended = sim_fit.detrend(sim_norm)
+        sim_fit = detrend.fit(sim)
+        sim_detrended = sim_fit.detrend(sim)
 
         # Adjust using `EmpiricalQuantileMapping.adjust`
         scen_detrended = super()._adjust(
             sim_detrended, extrapolation=extrapolation, interp=interp
         )
         # Retrend
-        scen_norm = sim_fit.retrend(scen_detrended)
-
-        # # Reapply-mean
-        scen = apply_correction(
-            scen_norm,
-            broadcast(mu_sim, sim, group=self.group, interp=interp),
-            kind=self.kind,
-        )
-        return scen
+        return sim_fit.retrend(scen_detrended)
 
 
 class QuantileDeltaMapping(EmpiricalQuantileMapping):
@@ -311,7 +288,7 @@ class QuantileDeltaMapping(EmpiricalQuantileMapping):
 
     Parameters
     ----------
-    At init:
+    At instantiation:
 
     nquantiles : int
       The number of quantiles to use. Two endpoints at 1e-6 and 1 - 1e-6 will be added.
@@ -320,7 +297,7 @@ class QuantileDeltaMapping(EmpiricalQuantileMapping):
     group : Union[str, Grouper]
       The grouping information. See :py:class:`xclim.sdba.base.Grouper` for details.
 
-    In adjust:
+    In adjustment:
 
     interp : {'nearest', 'linear', 'cubic'}
       The interpolation method to use when interpolating the adjustment factors. Defaults to "nearest".
@@ -368,14 +345,14 @@ class LOCI(BaseAdjustment):
 
     Parameters
     ----------
-    At init:
+    At instantiation:
 
     group : Union[str, Grouper]
       The grouping information. See :py:class:`xclim.sdba.base.Grouper` for details.
     thresh : float
       The threshold in `ref` above which the values are scaled.
 
-    In adjust:
+    In adjustment:
 
     interp : {'nearest', 'linear', 'cubic'}
       The interpolation method to use then interpolating the adjustment factors. Defaults to "linear".
@@ -423,14 +400,14 @@ class Scaling(BaseAdjustment):
 
     Parameters
     ----------
-    At init:
+    At instantiation:
 
     group : Union[str, Grouper]
       The grouping information. See :py:class:`xclim.sdba.base.Grouper` for details.
     kind : {'+', '*'}
       The adjustment kind, either additive or multiplicative.
 
-    In adjust:
+    In adjustment:
 
     interp : {'nearest', 'linear', 'cubic'}
       The interpolation method to use then interpolating the adjustment factors. Defaults to "nearest".
diff --git a/xclim/sdba/base.py b/xclim/sdba/base.py
index b161820c..e875c7e0 100644
--- a/xclim/sdba/base.py
+++ b/xclim/sdba/base.py
@@ -6,6 +6,7 @@ from typing import Optional
 from typing import Sequence
 from typing import Union
 
+import numpy as np
 import xarray as xr
 from boltons.funcutils import wraps
 
@@ -91,11 +92,31 @@ class Grouper(Parametrizable):
         More than one array can be combined to a dataset before grouping using the `das`  kwargs.
         A new `window` dimension is added if `self.window` is larger than 1.
         If `Grouper.dim` is 'time', but 'prop' is None, the whole array is grouped together.
+
+        When multiple arrays are passed, some of them can be grouped along the same group as self.
+        They are boadcasted, merged to the grouping dataset and regrouped in the output.
         """
         if das:
+            from .utils import broadcast  # pylint: disable=cyclic-import
+
             if da is not None:
                 das[da.name] = da
-            da = xr.Dataset(data_vars=das)
+
+            da = xr.Dataset(
+                data_vars={
+                    name: das.pop(name)
+                    for name in list(das.keys())
+                    if self.dim in das[name].dims
+                }
+            )
+
+            # "Ungroup" the grouped arrays
+            da = da.assign(
+                {
+                    name: broadcast(var, da[self.dim], group=self, interp="nearest")
+                    for name, var in das.items()
+                }
+            )
 
         if self.window > 1:
             da = da.rolling(center=True, **{self.dim: self.window}).construct(
@@ -143,6 +164,12 @@ class Grouper(Parametrizable):
 
         ind = da.indexes[self.dim]
         i = getattr(ind, self.prop)
+
+        if i.dtype != np.int:
+            raise ValueError(
+                f"Index {self.name} is not of type int (rather {ind.dtype}), but {self.__class__.__name__} requires integer indexes."
+            )
+
         interp = (
             (interp or self.interp)
             if not isinstance(interp, str)
@@ -215,6 +242,7 @@ class Grouper(Parametrizable):
                 map(
                     lambda d: (
                         d.chunks is not None
+                        and self.dim in d.dims
                         and len(d.chunks[d.get_axis_num(self.dim)]) > 1
                     ),
                     da.values(),
@@ -241,10 +269,12 @@ class Grouper(Parametrizable):
         if isinstance(out, xr.Dataset):
             for name, outvar in out.data_vars.items():
                 if "_group_apply_reshape" in outvar.attrs:
-                    if outvar.attrs["_group_apply_reshape"] and self.prop is not None:
+                    if self.prop is not None:
                         out[name] = outvar.groupby(self.name).first(
                             skipna=False, keep_attrs=True
                         )
+                    else:
+                        out[name] = out[name].isel({self.dim: 0})
                     del out[name].attrs["_group_apply_reshape"]
 
         # Save input parameters as attributes of output DataArray.
@@ -266,7 +296,7 @@ class Grouper(Parametrizable):
             self.window > 1 and "window" in out.dims
         ):  # On non reducing ops, drop the constructed window
             out = out.isel(window=self.window // 2, drop=True)
-        if self.prop in out.dims and out.chunks is not None:
+        if self.prop in out.dims and bool(out.chunks):
             # Same as above : downstream methods expect only one chunk along the group
             out = out.chunk({self.prop: -1})
 
@@ -282,7 +312,7 @@ def parse_group(func):
 
     @wraps(func)
     def _parse_group(*args, **kwargs):
-        group = kwargs.get("group", default_group)
+        group = kwargs.setdefault("group", default_group)
         if not isinstance(group, Grouper):
             if not isinstance(group, str):
                 dim, *add_dims = group
diff --git a/xclim/sdba/detrending.py b/xclim/sdba/detrending.py
index aa82e7ec..cce24308 100644
--- a/xclim/sdba/detrending.py
+++ b/xclim/sdba/detrending.py
@@ -1,11 +1,16 @@
 """Detrending objects"""
+from typing import Union
+
 import xarray as xr
 
+from .base import Grouper
 from .base import Parametrizable
+from .base import parse_group
 from .utils import ADDITIVE
 from .utils import apply_correction
 from .utils import invert
-from .utils import loffsets
+
+# from .utils import loffsets
 
 
 class BaseDetrend(Parametrizable):
@@ -13,48 +18,80 @@ class BaseDetrend(Parametrizable):
 
     Defines three methods:
 
-    fit(da)     : Compute trend from da and return a new _fitted_ Detrend object.
-    detrend(da) : Return detrended array.
-    retrend(da) : Puts trend back on da.
+    fit(da)      : Compute trend from da and return a new _fitted_ Detrend object.
+    get_trend(da): Return the fitted trend along da's coordinate.
+    detrend(da)  : Return detrended array.
+    retrend(da)  : Puts trend back on da.
 
-    * Subclasses should implement _fit(), _detrend() and _retrend(), not the methods themselves.
-    Only _fit() should store data. _detrend() and _retrend() are meant to be used on any dataarray with the trend computed in fit.
+    * Subclasses should implement _fit() and _get_trend(). Both will be called in a `group.apply()`.
+    `_fit()` is called with the dataarray and str `dim` that indicates the fitting dimension,
+        it should return a dataset that will be set as `.fitds`.
+    `_get_trend()` is called with .fitds broadcasted on the main dim of the input DataArray.
     """
 
-    def __init__(self, **kwargs):
+    @parse_group
+    def __init__(
+        self, *, group: Union[Grouper, str] = "time", kind: str = "+", **kwargs
+    ):
+        """Initialize Detrending object.
+
+        Parameters
+        ----------
+        group : Union[str, Grouper]
+            The grouping information. See :py:class:`xclim.sdba.base.Grouper` for details.
+            The fit is performed along the group's main dim.
+        kind : {'*', '+'}
+            The way the trend is removed or added, either additive or multiplicative.
+        """
         self.__fitted = False
-        super().__init__(**kwargs)
+        super().__init__(group=group, kind=kind, **kwargs)
 
-    def fit(self, da: xr.DataArray, dim="time"):
+    def fit(self, da: xr.DataArray):
         """Extract the trend of a DataArray along a specific dimension.
 
         Returns a new object storing the fit data that can be used for detrending and retrending.
         """
         new = self.copy()
-        new._fit(da, dim=dim)
-        new._fitted_dim = dim
+        new._set_fitds(new.group.apply(new._fit, da, main_only=True))
         new.__fitted = True
         return new
 
+    def get_trend(self, da: xr.DataArray):
+        return self.group.apply(
+            self._get_trend,
+            {self.group.dim: da[self.group.dim], **self.fit_ds.data_vars},
+            main_only=True,
+        )
+
     def detrend(self, da: xr.DataArray):
         """Removes the previously fitted trend from a DataArray."""
         if not self.__fitted:
             raise ValueError("You must call fit() before detrending.")
-        return self._detrend(da)
+        trend = self.get_trend(da)
+        return self._detrend(da, trend)
 
     def retrend(self, da: xr.DataArray):
         """Puts back the previsouly fitted trend on a DataArray."""
         if not self.__fitted:
             raise ValueError("You must call fit() before retrending")
-        return self._retrend(da)
+        trend = self.get_trend(da)
+        return self._retrend(da, trend)
 
-    def _fit(self, da):
-        raise NotImplementedError
+    def _set_fitds(self, ds):
+        self.fit_ds = ds
+
+    def _detrend(self, da, trend):
+        # Remove trend from series
+        return apply_correction(da, invert(trend, self.kind), self.kind)
 
-    def _detrend(self, da):
+    def _retrend(self, da, trend):
+        # Add trend to series
+        return apply_correction(da, trend, self.kind)
+
+    def _get_trend(self, grpd, dim="time"):
         raise NotImplementedError
 
-    def _retrend(self, da):
+    def _fit(self, da):
         raise NotImplementedError
 
 
@@ -62,26 +99,25 @@ class NoDetrend(BaseDetrend):
     """Convenience class for polymorphism. Does nothing."""
 
     def _fit(self, da, dim=None):
-        pass
+        return da.isel({dim: 0})
 
-    def _detrend(self, da):
+    def _detrend(self, da, trend):
         return da
 
-    def _retrend(self, da):
+    def _retrend(self, da, trend):
         return da
 
 
 class MeanDetrend(BaseDetrend):
-    """Simple detrending removing only the mean from the data, quite similar to normalizing in additive mode."""
+    """Simple detrending removing only the mean from the data, quite similar to normalizing."""
 
     def _fit(self, da, dim="time"):
-        self._mean = da.mean(dim=dim)
+        mean = da.mean(dim=dim)
+        mean.name = "mean"
+        return mean
 
-    def _detrend(self, da):
-        return da - self._mean
-
-    def _retrend(self, da):
-        return da + self._mean
+    def _get_trend(self, grpd, dim="time"):
+        return grpd.mean
 
 
 class PolyDetrend(BaseDetrend):
@@ -90,47 +126,33 @@ class PolyDetrend(BaseDetrend):
 
     Parameters
     ----------
+    group : Union[str, Grouper]
+        The grouping information. See :py:class:`xclim.sdba.base.Grouper` for details.
+        The fit is performed along the group's main dim.
+    kind : {'*', '+'}
+        The way the trend is removed or added, either additive or multiplicative.
     degree : int
-      The order of the polynomial to fit.
-    freq : Optional[str]
-      If given, resamples the data to this frequency before computing the trend.
-    kind : {'+', '*'}
-      The way the trend is removed and put back, either additively or multiplicatively.
-
-    Notes
-    -----
-    If freq is used to resample at a lower frequency, make sure the series includes full periods.
+        The order of the polynomial to fit.
+    preserve_mean : bool
+        Whether to preserve the mean when de/re-trending. If True, the trend has its mean
+        removed before it is used.
     """
 
-    def __init__(self, degree=4, freq=None, kind=ADDITIVE, preserve_mean=False):
+    def __init__(self, group="time", kind=ADDITIVE, degree=4, preserve_mean=False):
         super().__init__(
-            degree=degree, freq=freq, kind=kind, preserve_mean=preserve_mean
+            group=group, kind=kind, degree=degree, preserve_mean=preserve_mean
         )
 
     def _fit(self, da, dim="time"):
-        if self.freq is not None:
-            da = da.resample(
-                time=self.freq, label="left", loffset=loffsets[self.freq]
-            ).mean()
-        self._fitds = da.polyfit(dim=dim, deg=self.degree, full=True)
+        return da.polyfit(dim=dim, deg=self.degree)
 
-    def _get_trend(self, da):
+    def _get_trend(self, grpd, dim="time"):
         # Estimate trend over da
-        trend = xr.polyval(
-            coord=da[self._fitted_dim], coeffs=self._fitds.polyfit_coefficients
-        )
+        trend = xr.polyval(coord=grpd[dim], coeffs=grpd.polyfit_coefficients)
 
         if self.preserve_mean:
             trend = apply_correction(
-                trend, invert(trend.mean(dim=self._fitted_dim), self.kind), self.kind
+                trend, invert(trend.mean(dim=dim), self.kind), self.kind
             )
 
         return trend
-
-    def _detrend(self, da):
-        # Remove trend from series
-        return apply_correction(da, invert(self._get_trend(da), self.kind), self.kind)
-
-    def _retrend(self, da):
-        # Add trend to series
-        return apply_correction(da, self._get_trend(da), self.kind)

sdba - Grouped Detrending
We need to implement grouped detrending into sdba.
diff --git a/tests/test_sdba/test_adjustment.py b/tests/test_sdba/test_adjustment.py
index ac54ae4e..4047e5f5 100644
--- a/tests/test_sdba/test_adjustment.py
+++ b/tests/test_sdba/test_adjustment.py
@@ -209,7 +209,7 @@ class TestDQM:
         DQM = DetrendedQuantileMapping(group="time.month")
         DQM.train(ref, hist)
         scen = DQM.adjust(sim, interp="linear")
-        xr.testing.assert_allclose(ref, scen, rtol=1.5e-4)
+        xr.testing.assert_allclose(ref, scen, rtol=1e-3)
 
 
 class TestQDM:
diff --git a/tests/test_sdba/test_base.py b/tests/test_sdba/test_base.py
index ee14b65e..a09206f6 100644
--- a/tests/test_sdba/test_base.py
+++ b/tests/test_sdba/test_base.py
@@ -6,7 +6,6 @@ sdba = pytest.importorskip("xclim.sdba")  # noqa
 
 from xclim.sdba.base import Grouper
 from xclim.sdba.base import Parametrizable
-from xclim.sdba.processing import normalize
 
 
 def test_param_class():
@@ -52,45 +51,94 @@ def test_grouper_get_index(tas_series, group, interp, val90):
     assert indx[90] == val90
 
 
-def test_grouper_apply(tas_series):
+@pytest.mark.parametrize(
+    "group,n",
+    [("time", 1), ("time.month", 12), ("time.week", 52), ("mytime.dayofyear", 366)],
+)
+@pytest.mark.parametrize("use_dask", [True, False])
+def test_grouper_apply(tas_series, use_dask, group, n):
     tas1 = tas_series(np.arange(366), start="2000-01-01")
     tas0 = tas_series(np.zeros(366), start="2000-01-01")
     tas = xr.concat((tas1, tas0), dim="lat")
 
-    grouper = Grouper("time.month")
-    out = grouper.apply("mean", tas)
-    assert out.isel(month=0, lat=0) == 15.0
-    out = normalize(tas, group=grouper)
-
-    grouper = Grouper("time.month", add_dims=["lat"])
+    grouper = Grouper(group)
+    if not group.startswith("time"):
+        tas = tas.rename(time=grouper.dim)
+        tas1 = tas1.rename(time=grouper.dim)
+        tas0 = tas0.rename(time=grouper.dim)
+
+    if use_dask:
+        tas = tas.chunk({"lat": 1, grouper.dim: -1})
+        tas0 = tas1.chunk({grouper.dim: -1})
+        tas1 = tas0.chunk({grouper.dim: -1})
+
+    # Normal monthly mean
+    out_mean = grouper.apply("mean", tas)
+    if grouper.prop:
+        exp = tas.groupby(group).mean()
+    else:
+        exp = tas.mean(dim=grouper.dim)
+    np.testing.assert_array_equal(out_mean, exp)
+
+    # With additionnal dimension included
+    grouper = Grouper(group, add_dims=["lat"])
     out = grouper.apply("mean", tas)
-    assert out.ndim == 1
-    assert out.isel(month=0,) == 7.5
-    assert out.attrs["group"] == "time.month"
-    assert out.attrs["group_compute_dims"] == ["time", "lat"]
+    assert out.ndim == int(grouper.prop is not None)
+    np.testing.assert_array_equal(out, exp.mean("lat"))
+    assert out.attrs["group"] == group
+    assert out.attrs["group_compute_dims"] == [grouper.dim, "lat"]
     assert out.attrs["group_window"] == 1
 
-    grouper = Grouper("time.month", window=5)
-    out = grouper.apply("mean", tas)
-    np.testing.assert_almost_equal(out.isel(month=0, lat=0), 15.32236842)
+    # Additionnal but main_only
+    out = grouper.apply("mean", tas, main_only=True)
+    np.testing.assert_array_equal(out, out_mean)
 
-    tas = tas.chunk({"lat": 1})
+    # With window
+    grouper = Grouper(group, window=5)
     out = grouper.apply("mean", tas)
-    assert out.chunks == ((1, 1), (12,))
+    rolld = tas.rolling({grouper.dim: 5}, center=True).construct(window_dim="window")
+    if grouper.prop:
+        exp = rolld.groupby(group).mean(dim=[grouper.dim, "window"])
+    else:
+        exp = rolld.mean(dim=[grouper.dim, "window"])
+    np.testing.assert_array_equal(out, exp)
+
+    # With function + nongrouping-grouped
+    grouper = Grouper(group)
 
-    out = normalize(tas, group=grouper)
-    assert out.chunks == ((1, 1), (366,))
+    def normalize(grp, dim):
+        return grp / grp.mean(dim=dim)
 
+    normed = grouper.apply(normalize, tas)
+    assert normed.shape == tas.shape
+    if use_dask:
+        assert normed.chunks == ((1, 1), (366,))
+
+    # Mixed output
     def mixed_reduce(grdds, dim=None):
         tas1 = grdds.tas1.mean(dim=dim)
         tas0 = grdds.tas0 / grdds.tas0.mean(dim=dim)
         tas1.attrs["_group_apply_reshape"] = True
         return xr.Dataset(data_vars={"tas1_mean": tas1, "norm_tas0": tas0})
 
-    tas1 = tas1.chunk({"time": -1})
     out = grouper.apply(mixed_reduce, {"tas1": tas1, "tas0": tas0})
-    assert "month" not in out.norm_tas0.dims
-    assert "month" in out.tas1_mean.dims
-
-    assert out.tas1_mean.chunks == ((12,),)
-    assert out.norm_tas0.chunks == ((366,),)
+    if grouper.prop:
+        assert grouper.prop not in out.norm_tas0.dims
+        assert grouper.prop in out.tas1_mean.dims
+
+    if use_dask:
+        assert out.tas1_mean.chunks == (((n,),) if grouper.prop else tuple())
+        assert out.norm_tas0.chunks == ((366,),)
+
+    # Mixed input
+    if grouper.prop:
+
+        def normalize_from_precomputed(grpds, dim=None):
+            return (grpds.tas / grpds.tas1_mean).mean(dim=dim)
+
+        out = grouper.apply(
+            normalize_from_precomputed, {"tas": tas, "tas1_mean": out.tas1_mean}
+        ).isel(lat=0)
+        exp = normed.groupby(group).mean().isel(lat=0)
+        assert grouper.prop in out.dims
+        np.testing.assert_array_equal(out, exp)

environment.yml
pip install -e .[dev]
parse_log_pytest
environment.yml
pytest pytest-cov pytest
apt-get update apt-get install -y libspatialindex-dev
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///home/conda/feedstock_root/build_artifacts/attrs_1722977137225/work
bleach==6.0.0
bokeh @ file:///home/conda/feedstock_root/build_artifacts/bokeh_1660586590972/work
boltons @ file:///home/conda/feedstock_root/build_artifacts/boltons_1711936407380/work
Bottleneck @ file:///home/conda/feedstock_root/build_artifacts/bottleneck_1649629660965/work
branca @ file:///home/conda/feedstock_root/build_artifacts/branca_1714071803448/work
Brotli @ file:///home/conda/feedstock_root/build_artifacts/brotli-split_1648883617327/work
bump2version==1.0.1
certifi @ file:///home/conda/feedstock_root/build_artifacts/certifi_1725278078093/work/certifi
cffi==1.15.1
cfgv==3.3.1
cftime @ file:///home/conda/feedstock_root/build_artifacts/cftime_1649636858592/work
charset-normalizer @ file:///home/conda/feedstock_root/build_artifacts/charset-normalizer_1728479282467/work
click @ file:///home/conda/feedstock_root/build_artifacts/click_1651215140632/work
click-plugins==1.1.1
cligj @ file:///home/conda/feedstock_root/build_artifacts/cligj_1633637764473/work
cloudpickle @ file:///home/conda/feedstock_root/build_artifacts/cloudpickle_1674202310934/work
coverage==7.2.7
cryptography==44.0.2
cycler @ file:///home/conda/feedstock_root/build_artifacts/cycler_1635519461629/work
cytoolz==0.11.2
dask==2021.10.0
distlib==0.3.9
distributed @ file:///tmp/build/80754af9/distributed_1635968201545/work
docutils==0.20.1
exceptiongroup==1.2.2
filelock==3.12.2
Fiona==1.8.20
flake8==5.0.4
folium @ file:///home/conda/feedstock_root/build_artifacts/folium_1709209270269/work
fonttools @ file:///home/conda/feedstock_root/build_artifacts/fonttools_1651017735934/work
fsspec @ file:///home/conda/feedstock_root/build_artifacts/fsspec_1674184942191/work
GDAL==3.3.2
geojson @ file:///home/conda/feedstock_root/build_artifacts/geojson_1699269511365/work
geopandas @ file:///home/conda/feedstock_root/build_artifacts/geopandas_1638382567988/work
HeapDict @ file:///home/conda/feedstock_root/build_artifacts/heapdict_1722613793866/work
identify==2.5.24
idna @ file:///home/conda/feedstock_root/build_artifacts/idna_1726459485162/work
importlib-metadata==4.2.0
iniconfig==2.0.0
jaraco.classes==3.2.3
jeepney==0.9.0
Jinja2 @ file:///home/conda/feedstock_root/build_artifacts/jinja2_1715127149914/work
joblib @ file:///home/conda/feedstock_root/build_artifacts/joblib_1691577114857/work
keyring==23.9.3
kiwisolver @ file:///home/conda/feedstock_root/build_artifacts/kiwisolver_1648854392523/work
llvmlite==0.38.0
locket @ file:///home/conda/feedstock_root/build_artifacts/locket_1650660393415/work
mapclassify @ file:///home/conda/feedstock_root/build_artifacts/mapclassify_1673861555770/work
markdown-it-py==2.2.0
MarkupSafe @ file:///home/conda/feedstock_root/build_artifacts/markupsafe_1648737551960/work
matplotlib @ file:///home/conda/feedstock_root/build_artifacts/matplotlib-suite_1651609498426/work
mccabe==0.7.0
mdurl==0.1.2
more-itertools==9.1.0
msgpack @ file:///home/conda/feedstock_root/build_artifacts/msgpack-python_1648745991116/work
munch==2.5.0
munkres==1.1.4
netCDF4 @ file:///home/conda/feedstock_root/build_artifacts/netcdf4_1636302995763/work
networkx @ file:///home/conda/feedstock_root/build_artifacts/networkx_1646092782768/work
nodeenv==1.9.1
numba @ file:///home/conda/feedstock_root/build_artifacts/numba_1652226558760/work
numexpr @ file:///home/conda/feedstock_root/build_artifacts/numexpr_1649636747170/work
numpy @ file:///home/conda/feedstock_root/build_artifacts/numpy_1649806299270/work
olefile @ file:///home/conda/feedstock_root/build_artifacts/olefile_1701735466804/work
packaging @ file:///home/conda/feedstock_root/build_artifacts/packaging_1696202382185/work
pandas==1.3.5
partd @ file:///home/conda/feedstock_root/build_artifacts/partd_1695667515973/work
Pillow @ file:///home/conda/feedstock_root/build_artifacts/pillow_1630696604087/work
Pint @ file:///home/conda/feedstock_root/build_artifacts/pint_1635280347517/work
pkginfo==1.10.0
platformdirs==2.6.2
pluggy==1.2.0
pre-commit==2.21.0
psutil @ file:///home/conda/feedstock_root/build_artifacts/psutil_1653089169272/work
py==1.11.0
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
Pygments==2.17.2
pyparsing @ file:///home/conda/feedstock_root/build_artifacts/pyparsing_1724616129934/work
pyproj @ file:///home/conda/feedstock_root/build_artifacts/pyproj_1650061576675/work
PySocks @ file:///home/conda/feedstock_root/build_artifacts/pysocks_1648857264451/work
pytest==7.4.4
pytest-cov==4.1.0
pytest-runner==6.0.1
python-dateutil @ file:///home/conda/feedstock_root/build_artifacts/python-dateutil_1709299778482/work
pytz @ file:///home/conda/feedstock_root/build_artifacts/pytz_1726055524169/work
PyYAML @ file:///home/conda/feedstock_root/build_artifacts/pyyaml_1648757092905/work
readme-renderer==37.3
requests @ file:///home/conda/feedstock_root/build_artifacts/requests_1716354486713/work
requests-toolbelt==1.0.0
rfc3986==2.0.0
rich==13.8.1
Rtree @ file:///home/conda/feedstock_root/build_artifacts/rtree_1665582585745/work
scikit-learn @ file:///home/conda/feedstock_root/build_artifacts/scikit-learn_1640464152916/work
scipy @ file:///home/conda/feedstock_root/build_artifacts/scipy_1637806658031/work
SecretStorage==3.3.3
Shapely @ file:///home/conda/feedstock_root/build_artifacts/shapely_1635194349843/work
six @ file:///home/conda/feedstock_root/build_artifacts/six_1620240208055/work
sortedcontainers @ file:///home/conda/feedstock_root/build_artifacts/sortedcontainers_1621217038088/work
tblib @ file:///home/conda/feedstock_root/build_artifacts/tblib_1702066284995/work
threadpoolctl @ file:///home/conda/feedstock_root/build_artifacts/threadpoolctl_1643647933166/work
tomli==2.0.1
toolz @ file:///home/conda/feedstock_root/build_artifacts/toolz_1706112571092/work
tornado @ file:///home/conda/feedstock_root/build_artifacts/tornado_1648827244717/work
tox==3.28.0
twine==4.0.2
typing_extensions @ file:///home/conda/feedstock_root/build_artifacts/typing_extensions_1688315532570/work
unicodedata2 @ file:///home/conda/feedstock_root/build_artifacts/unicodedata2_1649111917568/work
urllib3 @ file:///home/conda/feedstock_root/build_artifacts/urllib3_1708239446578/work
virtualenv==20.16.2
watchdog==3.0.0
webencodings==0.5.1
xarray @ file:///home/conda/feedstock_root/build_artifacts/xarray_1639125986756/work
-e git+https://github.com/Ouranosinc/xclim.git@17bc5e9afdc76d7f802b5193ed4209b0e7d5a67c#egg=xclim
xyzservices @ file:///home/conda/feedstock_root/build_artifacts/xyzservices_1684539629266/work
zict @ file:///home/conda/feedstock_root/build_artifacts/zict_1651156074437/work
zipp @ file:///home/conda/feedstock_root/build_artifacts/zipp_1677313463193/work

name: xclim
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=24.2.0=pyh71513ae_0
  - bokeh=2.4.3=pyhd8ed1ab_3
  - boltons=24.0.0=pyhd8ed1ab_0
  - boost-cpp=1.74.0=h312852a_4
  - bottleneck=1.3.4=py37hda87dfa_1
  - branca=0.7.2=pyhd8ed1ab_0
  - brotli=1.0.9=h166bdaf_7
  - brotli-bin=1.0.9=h166bdaf_7
  - brotli-python=1.0.9=py37hd23a5d3_7
  - bzip2=1.0.8=h7f98852_4
  - c-ares=1.18.1=h7f98852_0
  - ca-certificates=2025.2.25=h06a4308_0
  - cairo=1.16.0=h6cf1ce9_1008
  - certifi=2024.8.30=pyhd8ed1ab_0
  - cfitsio=3.470=hb418390_7
  - cftime=1.6.0=py37hda87dfa_1
  - charset-normalizer=3.4.0=pyhd8ed1ab_0
  - click=8.1.3=py37h89c1867_0
  - click-plugins=1.1.1=py_0
  - cligj=0.7.2=pyhd8ed1ab_1
  - cloudpickle=2.2.1=pyhd8ed1ab_0
  - curl=7.79.1=h2574ce0_1
  - cycler=0.11.0=pyhd8ed1ab_0
  - cytoolz=0.11.2=py37h540881e_2
  - dask=2021.10.0=pyhd8ed1ab_0
  - dask-core=2021.10.0=pyhd3eb1b0_0
  - distributed=2021.10.0=py37h06a4308_0
  - expat=2.4.8=h27087fc_0
  - fiona=1.8.20=py37hb7e2723_2
  - folium=0.16.0=pyhd8ed1ab_0
  - font-ttf-dejavu-sans-mono=2.37=hab24e00_0
  - font-ttf-inconsolata=3.000=h77eed37_0
  - font-ttf-source-code-pro=2.038=h77eed37_0
  - font-ttf-ubuntu=0.83=h77eed37_3
  - fontconfig=2.14.0=h8e229c2_0
  - fonts-conda-ecosystem=1=0
  - fonts-conda-forge=1=0
  - fonttools=4.33.3=py37h540881e_0
  - freetype=2.10.4=h0708190_1
  - freexl=1.0.6=h7f98852_0
  - fsspec=2023.1.0=pyhd8ed1ab_0
  - gdal=3.3.2=py37hd5a0ba4_2
  - geojson=3.1.0=pyhd8ed1ab_0
  - geopandas=0.10.2=pyhd8ed1ab_1
  - geopandas-base=0.10.2=pyha770c72_1
  - geos=3.9.1=h9c3ff4c_2
  - geotiff=1.7.0=h4f31c25_0
  - gettext=0.19.8.1=h73d1719_1008
  - giflib=5.2.1=h36c2ea0_2
  - hdf4=4.2.15=h10796ff_3
  - hdf5=1.12.1=nompi_h2750804_100
  - heapdict=1.0.1=pyhd8ed1ab_1
  - icu=68.2=h9c3ff4c_0
  - idna=3.10=pyhd8ed1ab_0
  - importlib_metadata=4.11.4=hd8ed1ab_0
  - jbig=2.1=h7f98852_2003
  - jinja2=3.1.4=pyhd8ed1ab_0
  - joblib=1.3.2=pyhd8ed1ab_0
  - jpeg=9e=h166bdaf_1
  - json-c=0.15=h98cffda_0
  - kealib=1.4.14=h87e4c3c_3
  - keyutils=1.6.1=h166bdaf_0
  - kiwisolver=1.4.2=py37h7cecad7_1
  - krb5=1.19.3=h3790be6_0
  - lcms2=2.12=hddcbb42_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - lerc=2.2.1=h9c3ff4c_0
  - libblas=3.9.0=16_linux64_openblas
  - libbrotlicommon=1.0.9=h166bdaf_7
  - libbrotlidec=1.0.9=h166bdaf_7
  - libbrotlienc=1.0.9=h166bdaf_7
  - libcblas=3.9.0=16_linux64_openblas
  - libcurl=7.79.1=h2574ce0_1
  - libdap4=3.20.6=hd7c4107_2
  - libdeflate=1.7=h7f98852_5
  - libedit=3.1.20191231=he28a2e2_2
  - libev=4.33=h516909a_1
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgdal=3.3.2=hd2dd7ad_2
  - libgfortran-ng=13.2.0=h69a702a_0
  - libgfortran5=13.2.0=ha4646dd_0
  - libglib=2.68.4=h174f98d_1
  - libgomp=11.2.0=h1234567_1
  - libiconv=1.17=h166bdaf_0
  - libkml=1.3.0=h238a007_1014
  - liblapack=3.9.0=16_linux64_openblas
  - libllvm11=11.1.0=hf817b99_2
  - libnetcdf=4.8.1=nompi_hb3fd0d9_101
  - libnghttp2=1.43.0=h812cca2_1
  - libnsl=2.0.0=h7f98852_0
  - libopenblas=0.3.21=h043d6bf_0
  - libpng=1.6.37=h21135ba_2
  - libpq=13.3=hd57d9b9_0
  - librttopo=1.1.0=h1185371_6
  - libspatialindex=1.9.3=h9c3ff4c_4
  - libspatialite=5.0.1=h8694cbe_6
  - libssh2=1.10.0=ha56f1ee_2
  - libstdcxx-ng=11.2.0=h1234567_1
  - libtiff=4.3.0=hf544144_1
  - libuuid=2.32.1=h7f98852_1000
  - libwebp-base=1.2.2=h7f98852_1
  - libxcb=1.13=h7f98852_1004
  - libxml2=2.9.12=h72842e0_0
  - libzip=1.8.0=h4de3113_1
  - llvmlite=0.38.0=py37h4ff587b_0
  - locket=1.0.0=pyhd8ed1ab_0
  - lz4-c=1.9.3=h9c3ff4c_1
  - mapclassify=2.5.0=pyhd8ed1ab_1
  - markupsafe=2.1.1=py37h540881e_1
  - matplotlib-base=3.5.2=py37hc347a89_0
  - msgpack-python=1.0.3=py37h7cecad7_1
  - munch=2.5.0=py_0
  - munkres=1.1.4=pyh9f0ad1d_0
  - ncurses=6.4=h6a678d5_0
  - netcdf4=1.5.8=nompi_py37hf784469_101
  - networkx=2.7=pyhd8ed1ab_0
  - nomkl=1.0=h5ca1d4c_0
  - nspr=4.32=h9c3ff4c_1
  - nss=3.69=hb5efdd6_1
  - numba=0.55.1=py37h43839f2_1
  - numexpr=2.8.0=py37h85a3170_102
  - numpy=1.21.6=py37h976b520_0
  - olefile=0.47=pyhd8ed1ab_0
  - openjpeg=2.4.0=hb52868f_1
  - openssl=1.1.1w=h7f8727e_0
  - packaging=23.2=pyhd8ed1ab_0
  - pandas=1.3.5=py37h8c16a72_0
  - partd=1.4.1=pyhd8ed1ab_0
  - pcre=8.45=h9c3ff4c_0
  - pillow=8.3.2=py37h0f21c89_0
  - pint=0.18=pyhd8ed1ab_0
  - pip=22.3.1=py37h06a4308_0
  - pixman=0.40.0=h36c2ea0_0
  - poppler=21.09.0=ha39eefc_3
  - poppler-data=0.4.12=hd8ed1ab_0
  - postgresql=13.3=h2510834_0
  - proj=8.0.1=h277dcde_0
  - psutil=5.9.1=py37h540881e_0
  - pthread-stubs=0.4=h36c2ea0_1001
  - pyparsing=3.1.4=pyhd8ed1ab_0
  - pyproj=3.2.1=py37hcc46e62_6
  - pysocks=1.7.1=py37h89c1867_5
  - python=3.7.16=h7a1cb2a_0
  - python-dateutil=2.9.0=pyhd8ed1ab_0
  - python_abi=3.7=2_cp37m
  - pytz=2024.2=pyhd8ed1ab_0
  - pyyaml=6.0=py37h540881e_4
  - readline=8.2=h5eee18b_0
  - requests=2.32.2=pyhd8ed1ab_0
  - rtree=1.0.1=py37h0b55af0_0
  - scikit-learn=1.0.2=py37hf9e9bfc_0
  - scipy=1.7.3=py37hf2a6cf1_0
  - setuptools=65.6.3=py37h06a4308_0
  - shapely=1.8.0=py37h48c49eb_0
  - six=1.16.0=pyh6c4a22f_0
  - sortedcontainers=2.4.0=pyhd8ed1ab_0
  - sqlite=3.45.3=h5eee18b_0
  - tblib=3.0.0=pyhd8ed1ab_0
  - threadpoolctl=3.1.0=pyh8a188c0_0
  - tiledb=2.3.4=he87e0bf_0
  - tk=8.6.14=h39e8969_0
  - toolz=0.12.1=pyhd8ed1ab_0
  - tornado=6.1=py37h540881e_3
  - typing-extensions=4.7.1=hd8ed1ab_0
  - typing_extensions=4.7.1=pyha770c72_0
  - tzcode=2022a=h166bdaf_0
  - tzdata=2025b=h78e105d_0
  - unicodedata2=14.0.0=py37h540881e_1
  - urllib3=2.2.1=pyhd8ed1ab_0
  - wheel=0.38.4=py37h06a4308_0
  - xarray=0.20.2=pyhd8ed1ab_0
  - xerces-c=3.2.3=h9d8b166_3
  - xorg-kbproto=1.0.7=h7f98852_1002
  - xorg-libice=1.0.10=h7f98852_0
  - xorg-libsm=1.2.3=hd9c2040_1000
  - xorg-libx11=1.7.2=h7f98852_0
  - xorg-libxau=1.0.9=h7f98852_0
  - xorg-libxdmcp=1.1.3=h7f98852_0
  - xorg-libxext=1.3.4=h7f98852_1
  - xorg-libxrender=0.9.10=h7f98852_1003
  - xorg-renderproto=0.11.1=h7f98852_1002
  - xorg-xextproto=7.3.0=h7f98852_1002
  - xorg-xproto=7.0.31=h7f98852_1007
  - xyzservices=2023.5.0=pyhd8ed1ab_0
  - xz=5.6.4=h5eee18b_1
  - yaml=0.2.5=h7f98852_2
  - zict=2.2.0=pyhd8ed1ab_0
  - zipp=3.15.0=pyhd8ed1ab_0
  - zlib=1.2.13=h5eee18b_1
  - zstd=1.5.0=ha95c52a_0
  - pip:
      - bleach==6.0.0
      - bump2version==1.0.1
      - cffi==1.15.1
      - cfgv==3.3.1
      - coverage==7.2.7
      - cryptography==44.0.2
      - distlib==0.3.9
      - docutils==0.20.1
      - exceptiongroup==1.2.2
      - filelock==3.12.2
      - flake8==5.0.4
      - identify==2.5.24
      - importlib-metadata==4.2.0
      - iniconfig==2.0.0
      - jaraco-classes==3.2.3
      - jeepney==0.9.0
      - keyring==23.9.3
      - markdown-it-py==2.2.0
      - mccabe==0.7.0
      - mdurl==0.1.2
      - more-itertools==9.1.0
      - nodeenv==1.9.1
      - pkginfo==1.10.0
      - platformdirs==2.6.2
      - pluggy==1.2.0
      - pre-commit==2.21.0
      - py==1.11.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pytest-runner==6.0.1
      - readme-renderer==37.3
      - requests-toolbelt==1.0.0
      - rfc3986==2.0.0
      - rich==13.8.1
      - secretstorage==3.3.3
      - tomli==2.0.1
      - tox==3.28.0
      - twine==4.0.2
      - virtualenv==20.16.2
      - watchdog==3.0.0
      - webencodings==0.5.1
prefix: /opt/conda/envs/xclim

tests/test_sdba/test_base.py::test_grouper_apply[True-time-1] tests/test_sdba/test_base.py::test_grouper_apply[True-time.month-12] tests/test_sdba/test_base.py::test_grouper_apply[True-time.week-52] tests/test_sdba/test_base.py::test_grouper_apply[True-mytime.dayofyear-366] tests/test_sdba/test_base.py::test_grouper_apply[False-time.month-12] tests/test_sdba/test_base.py::test_grouper_apply[False-time.week-52] tests/test_sdba/test_base.py::test_grouper_apply[False-mytime.dayofyear-366]
tests/test_sdba/test_adjustment.py::TestLoci::test_time[time-2] tests/test_sdba/test_adjustment.py::TestLoci::test_time[time.month-1] tests/test_sdba/test_adjustment.py::TestScaling::test_time[+-tas] tests/test_sdba/test_adjustment.py::TestScaling::test_time[*-pr] tests/test_sdba/test_adjustment.py::TestScaling::test_mon_U[+-tas] tests/test_sdba/test_adjustment.py::TestScaling::test_mon_U[*-pr] tests/test_sdba/test_adjustment.py::TestDQM::test_quantiles[+-tas] tests/test_sdba/test_adjustment.py::TestDQM::test_quantiles[*-pr] tests/test_sdba/test_adjustment.py::TestDQM::test_mon_U[None-+-tas] tests/test_sdba/test_adjustment.py::TestDQM::test_mon_U[None-*-pr] tests/test_sdba/test_adjustment.py::TestDQM::test_mon_U[spatial_dims1-+-tas] tests/test_sdba/test_adjustment.py::TestDQM::test_mon_U[spatial_dims1-*-pr] tests/test_sdba/test_adjustment.py::TestDQM::test_cannon tests/test_sdba/test_adjustment.py::TestDQM::test_group_norm tests/test_sdba/test_adjustment.py::TestQDM::test_quantiles[+-tas] tests/test_sdba/test_adjustment.py::TestQDM::test_quantiles[*-pr] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[True-+-tas-True] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[True-+-tas-False] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[True-*-pr-True] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[True-*-pr-False] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[False-+-tas-True] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[False-+-tas-False] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[False-*-pr-True] tests/test_sdba/test_adjustment.py::TestQDM::test_mon_U[False-*-pr-False] tests/test_sdba/test_adjustment.py::TestQDM::test_cannon tests/test_sdba/test_adjustment.py::TestQM::test_quantiles[+-tas] tests/test_sdba/test_adjustment.py::TestQM::test_quantiles[*-pr] tests/test_sdba/test_adjustment.py::TestQM::test_mon_U[+-tas] tests/test_sdba/test_adjustment.py::TestQM::test_mon_U[*-pr] tests/test_sdba/test_base.py::test_param_class tests/test_sdba/test_base.py::test_grouper_group[time-1-366] tests/test_sdba/test_base.py::test_grouper_group[time.month-1-31] tests/test_sdba/test_base.py::test_grouper_group[time.dayofyear-5-1] tests/test_sdba/test_base.py::test_grouper_get_index[time-False-True] tests/test_sdba/test_base.py::test_grouper_get_index[time.month-False-3] tests/test_sdba/test_base.py::test_grouper_get_index[time.month-True-3.5] tests/test_sdba/test_base.py::test_grouper_apply[False-time-1]
xclim/__init__.py HISTORY.rst xclim/sdba/__init__.py setup.py xclim/sdba/base.py xclim/sdba/detrending.py setup.cfg xclim/sdba/adjustment.py
xclim/__init__.py HISTORY.rst xclim/sdba/__init__.py setup.py xclim/sdba/base.py xclim/sdba/detrending.py setup.cfg xclim/sdba/adjustment.py