From fcf1fddb7396caee891c4dade0bf9092b4ffc48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Mon, 22 Mar 2021 18:32:30 +0100 Subject: [PATCH 01/16] CI: drop py35 build; use new cibuildwheel Github action workflow with cibw 1.10 --- .github/workflows/main.yml | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4320196c1..d9a71309b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,14 +13,6 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -env: - # needed by coveralls - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CIBW_BUILD: "cp35-* cp36-* cp37-* cp38-* cp39-*" - CIBW_BEFORE_BUILD: "pip install numpy==1.17.3 cython>=0.29.14 setuptools" - CIBW_TEST_REQUIRES: "pytest" - CIBW_TEST_COMMAND: "pytest -v {project}/tests" - jobs: build_wheels: name: wheels on ${{ matrix.os }} @@ -35,18 +27,15 @@ jobs: with: fetch-depth: '0' - - name: Set up Python - uses: actions\setup-python@v2 - with: - python-version: "3.8" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install cibuildwheel==1.7.0 - name: Build wheels - run: | - python -m cibuildwheel --output-dir dist + uses: joerick/cibuildwheel@v1.10.0 + env: + CIBW_BUILD: cp36-* cp37-* cp38-* cp39-* + CIBW_BEFORE_BUILD: pip install numpy==1.17.3 cython>=0.29.14 setuptools + CIBW_TEST_REQUIRES: pytest + CIBW_TEST_COMMAND: pytest -v {project}/tests + with: + output-dir: dist - uses: actions/upload-artifact@v2 with: @@ -59,7 +48,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: [3.5, 3.6, 3.7, 3.8, 3.9] + python-version: [3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 @@ -85,6 +74,8 @@ jobs: python setup.py --openmp build_ext --inplace - name: Run tests + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python -m pytest --cov gstools --cov-report term-missing -v tests/ python -m coveralls --service=github @@ -105,7 +96,7 @@ jobs: path: dist - name: Publish to Test PyPI - # only if working on develop + # only if working on master or develop if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' uses: pypa/gh-action-pypi-publish@master with: From f78c1792a555dc39532aa1067bbf0aaba32cf75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Mon, 22 Mar 2021 18:54:21 +0100 Subject: [PATCH 02/16] Init: use ModuleNotFoundError to be more precise (not available in py35) --- gstools/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gstools/__init__.py b/gstools/__init__.py index ba6ef832a..e18b5001e 100644 --- a/gstools/__init__.py +++ b/gstools/__init__.py @@ -165,7 +165,7 @@ try: from gstools._version import __version__ -except ImportError: # pragma: nocover +except ModuleNotFoundError: # pragma: nocover # package is not installed __version__ = "0.0.0.dev0" From d2bbee2f698e565ee697d1229a184382f31ca01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Mon, 22 Mar 2021 19:00:53 +0100 Subject: [PATCH 03/16] CovModel: remove py35 hack for metaclass --- gstools/covmodel/base.py | 3 +-- gstools/covmodel/tools.py | 35 ----------------------------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/gstools/covmodel/base.py b/gstools/covmodel/base.py index e121acb2c..851a75222 100644 --- a/gstools/covmodel/base.py +++ b/gstools/covmodel/base.py @@ -24,7 +24,6 @@ pos2latlon, ) from gstools.covmodel.tools import ( - InitSubclassMeta, _init_subclass, set_opt_args, set_len_anis, @@ -47,7 +46,7 @@ HANKEL_DEFAULT = {"a": -1, "b": 1, "N": 200, "h": 0.001, "alt": True} -class CovModel(metaclass=InitSubclassMeta): +class CovModel(metaclass=type): r"""Base class for the GSTools covariance models. Parameters diff --git a/gstools/covmodel/tools.py b/gstools/covmodel/tools.py index 6ad2212c6..700993e01 100644 --- a/gstools/covmodel/tools.py +++ b/gstools/covmodel/tools.py @@ -56,41 +56,6 @@ class AttributeWarning(UserWarning): """Attribute warning for CovModel class.""" -# __init_subclass__ hack for Python 3.5 - -if hasattr(object, "__init_subclass__"): - InitSubclassMeta = type -else: - - class InitSubclassMeta(type): # pragma: no cover - """Metaclass that implements PEP 487 protocol. - - Notes - ----- - See : - https://www.python.org/dev/peps/pep-0487 - - taken from : - https://github.com/graphql-python/graphene/blob/master/graphene/pyutils/init_subclass.py - """ - - def __new__(cls, name, bases, ns, **kwargs): - """Create a new subclass.""" - __init_subclass__ = ns.pop("__init_subclass__", None) - if __init_subclass__: - __init_subclass__ = classmethod(__init_subclass__) - ns["__init_subclass__"] = __init_subclass__ - return super(InitSubclassMeta, cls).__new__( - cls, name, bases, ns, **kwargs - ) - - def __init__(cls, name, bases, ns, **kwargs): - super(InitSubclassMeta, cls).__init__(name, bases, ns) - super_class = super(cls, cls) - if hasattr(super_class, "__init_subclass__"): - super_class.__init_subclass__.__func__(cls, **kwargs) - - def _init_subclass(cls): """Initialize gstools covariance model.""" From 9eb36265209a4f9271b5a64b6447f4c21d27dd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Mon, 22 Mar 2021 19:20:02 +0100 Subject: [PATCH 04/16] Setup: remove py35 classifier --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 4213ddc53..c7060d99f 100644 --- a/setup.py +++ b/setup.py @@ -216,7 +216,6 @@ class MPDistribution(Distribution): "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", From 16ff76f5cf46681c6181322c669c7264a85ebe6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Mon, 22 Mar 2021 19:24:52 +0100 Subject: [PATCH 05/16] covmodel.tools: remove InitSubclassMeta from docstring and __all__ --- gstools/covmodel/tools.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gstools/covmodel/tools.py b/gstools/covmodel/tools.py index 700993e01..6ce40265d 100644 --- a/gstools/covmodel/tools.py +++ b/gstools/covmodel/tools.py @@ -7,7 +7,6 @@ The following classes and functions are provided .. autosummary:: - InitSubclassMeta AttributeWarning rad_fac set_opt_args @@ -34,7 +33,6 @@ from gstools.tools.geometric import set_anis, set_angles __all__ = [ - "InitSubclassMeta", "AttributeWarning", "rad_fac", "set_opt_args", From b7c8d9c63f099af02a1bb7bfd59004f2b3eb916b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 11:00:26 +0100 Subject: [PATCH 06/16] CI: build wheels with updated versions of numpy and cython --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d9a71309b..972cc9f94 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,7 +31,7 @@ jobs: uses: joerick/cibuildwheel@v1.10.0 env: CIBW_BUILD: cp36-* cp37-* cp38-* cp39-* - CIBW_BEFORE_BUILD: pip install numpy==1.17.3 cython>=0.29.14 setuptools + CIBW_BEFORE_BUILD: pip install numpy==1.19.* cython==0.29.* setuptools CIBW_TEST_REQUIRES: pytest CIBW_TEST_COMMAND: pytest -v {project}/tests with: From 45f47ebc294b06853a6cfd6a5dfc7ecd0bbfbb3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 11:06:22 +0100 Subject: [PATCH 07/16] CI: pin version for pypi gh-action --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 972cc9f94..65b8ab6f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -98,7 +98,7 @@ jobs: - name: Publish to Test PyPI # only if working on master or develop if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.test_pypi_password }} @@ -108,7 +108,7 @@ jobs: - name: Publish to PyPI # only if tagged if: startsWith(github.ref, 'refs/tags') - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.pypi_password }} From cf70af841964aa79a8d4f5130fc8a23aeb067026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 13:30:11 +0100 Subject: [PATCH 08/16] CovModel: remove redundant metaclass; __init_subclass__ was added in py36 --- gstools/covmodel/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gstools/covmodel/base.py b/gstools/covmodel/base.py index 851a75222..2001be8ef 100644 --- a/gstools/covmodel/base.py +++ b/gstools/covmodel/base.py @@ -46,7 +46,7 @@ HANKEL_DEFAULT = {"a": -1, "b": 1, "N": 200, "h": 0.001, "alt": True} -class CovModel(metaclass=type): +class CovModel: r"""Base class for the GSTools covariance models. Parameters From 7fac5885d41c7318e25787c21a90d2706f19832e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 14:53:37 +0100 Subject: [PATCH 09/16] covmodel.tools: use f-strings --- gstools/covmodel/tools.py | 41 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/gstools/covmodel/tools.py b/gstools/covmodel/tools.py index 6ce40265d..42efdbe6d 100644 --- a/gstools/covmodel/tools.py +++ b/gstools/covmodel/tools.py @@ -100,11 +100,9 @@ def cor_from_correlation(self, h): abstract = False if abstract: raise TypeError( - "Can't instantiate class '" - + cls.__name__ - + "', " - + "without providing at least one of the methods " - + "'cor', 'variogram', 'covariance' or 'correlation'." + f"Can't instantiate class '{cls.__name__}', " + "without providing at least one of the methods " + "'cor', 'variogram', 'covariance' or 'correlation'." ) @@ -134,7 +132,7 @@ def rad_fac(dim, r): dim * r ** (dim - 1) * np.sqrt(np.pi) ** dim - / sps.gamma(dim / 2.0 + 1.0) + / sps.gamma(dim / 2 + 1) ) return fac @@ -161,9 +159,9 @@ def set_opt_args(model, opt_arg): for opt_name in opt_arg: if opt_name not in default: warnings.warn( - "The given optional argument '{}' ".format(opt_name) - + "is unknown or has at least no defined standard value. " - + "Or you made a Typo... hehe.", + f"The given optional argument '{opt_name}' " + "is unknown or has at least no defined standard value. " + "Or you made a Typo... hehe.", AttributeWarning, ) # add the default vaules if not specified @@ -176,10 +174,9 @@ def set_opt_args(model, opt_arg): for opt_name in opt_arg: if opt_name in dir(model): # "dir" also respects properties raise ValueError( - "parameter '" - + opt_name - + "' has a 'bad' name, since it is already present in " - + "the class. It could not be added to the model" + f"parameter '{opt_name}' has a 'bad' name, " + "since it is already present in " + "the class. It could not be added to the model." ) # Magic happens here setattr(model, opt_name, float(opt_arg[opt_name])) @@ -514,10 +511,8 @@ def set_dim(model, dim): dim = model.fix_dim() if model.latlon and dim != 3: raise ValueError( - model.name - + ": using fixed dimension " - + str(model.fix_dim()) - + ", which is not compatible with a latlon model." + f"{model.name}: using fixed dimension {model.fix_dim()}, " + "which is not compatible with a latlon model." ) # force dim=3 for latlon models dim = 3 if model.latlon else dim @@ -526,7 +521,7 @@ def set_dim(model, dim): raise ValueError("Only dimensions of d >= 1 are supported.") if not model.check_dim(dim): warnings.warn( - "Dimension {} is not appropriate for this model.".format(dim), + f"Dimension {dim} is not appropriate for this model.", AttributeWarning, ) model._dim = int(dim) @@ -589,21 +584,20 @@ def model_repr(model): # pragma: no cover if model.latlon: std_str = ( "{0}(latlon={1}, var={2:.{p}}, len_scale={3:.{p}}, " - "nugget={4:.{p}}".format( + "nugget={4:.{p}}{5})".format( model.name, model.latlon, model.var, model.len_scale, model.nugget, + opt_str, p=model._prec, ) - + opt_str - + ")" ) else: std_str = ( "{0}(dim={1}, var={2:.{p}}, len_scale={3:.{p}}, " - "nugget={4:.{p}}, anis={5}, angles={6}".format( + "nugget={4:.{p}}, anis={5}, angles={6}{7})".format( model.name, model.dim, model.var, @@ -611,9 +605,8 @@ def model_repr(model): # pragma: no cover model.nugget, list_format(model.anis, 3), list_format(model.angles, 3), + opt_str, p=model._prec, ) - + opt_str - + ")" ) return std_str From e619ca1f428aa9d982b0b0c8e69d3049490a4959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 15:00:55 +0100 Subject: [PATCH 10/16] covmodel: use f-strings; add trailing commas for **kwargs --- gstools/covmodel/base.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/gstools/covmodel/base.py b/gstools/covmodel/base.py index 2001be8ef..d65d62d57 100644 --- a/gstools/covmodel/base.py +++ b/gstools/covmodel/base.py @@ -133,7 +133,7 @@ def __init__( latlon=False, var_raw=None, hankel_kw=None, - **opt_arg + **opt_arg, ): # assert, that we use a subclass # this is the case, if __init_subclass__ is called, which creates @@ -210,12 +210,8 @@ def __init_subclass__(cls): # modify the docstrings: class docstring gets attributes added if cls.__doc__ is None: - cls.__doc__ = ( - "User defined GSTools Covariance-Model." - + CovModel.__doc__[45:] - ) - else: - cls.__doc__ += CovModel.__doc__[45:] + cls.__doc__ = "User defined GSTools Covariance-Model." + cls.__doc__ += CovModel.__doc__[45:] # overridden functions get standard doc if no new doc was created ignore = ["__", "variogram", "covariance", "cor"] for attr in cls.__dict__: @@ -571,7 +567,7 @@ def fit_variogram( max_eval=None, return_r2=False, curve_fit_kwargs=None, - **para_select + **para_select, ): """ Fiting the variogram-model to an empirical variogram. @@ -714,7 +710,7 @@ def fit_variogram( max_eval=max_eval, return_r2=return_r2, curve_fit_kwargs=curve_fit_kwargs, - **para_select + **para_select, ) # bounds setting and checks @@ -771,7 +767,7 @@ def var_bounds(self): def var_bounds(self, bounds): if not check_bounds(bounds): raise ValueError( - "Given bounds for 'var' are not valid, got: " + str(bounds) + f"Given bounds for 'var' are not valid, got: {bounds}" ) self._var_bounds = bounds @@ -791,8 +787,7 @@ def len_scale_bounds(self): def len_scale_bounds(self, bounds): if not check_bounds(bounds): raise ValueError( - "Given bounds for 'len_scale' are not valid, got: " - + str(bounds) + f"Given bounds for 'len_scale' are not valid, got: {bounds}" ) self._len_scale_bounds = bounds @@ -812,7 +807,7 @@ def nugget_bounds(self): def nugget_bounds(self, bounds): if not check_bounds(bounds): raise ValueError( - "Given bounds for 'nugget' are not valid, got: " + str(bounds) + f"Given bounds for 'nugget' are not valid, got: {bounds}" ) self._nugget_bounds = bounds @@ -832,7 +827,7 @@ def anis_bounds(self): def anis_bounds(self, bounds): if not check_bounds(bounds): raise ValueError( - "Given bounds for 'anis' are not valid, got: " + str(bounds) + f"Given bounds for 'anis' are not valid, got: {bounds}" ) self._anis_bounds = bounds @@ -1001,9 +996,8 @@ def integral_scale(self, integral_scale): self.len_scale = integral_scale / int_tmp if not np.isclose(self.integral_scale, integral_scale, rtol=1e-3): raise ValueError( - self.name - + ": Integral scale could not be set correctly!" - + " Please just give a len_scale!" + f"{self.name}: Integral scale could not be set correctly! " + "Please just provide a 'len_scale'!" ) @property From 22fe2e611ea7764dfdb2e05a45d9f21d88f1d52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 15:08:13 +0100 Subject: [PATCH 11/16] covmodel: f-strings everywhere --- gstools/covmodel/fit.py | 14 ++++---------- gstools/covmodel/plot.py | 36 ++++++++++++------------------------ 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/gstools/covmodel/fit.py b/gstools/covmodel/fit.py index 96462d9ef..397f0ba7c 100755 --- a/gstools/covmodel/fit.py +++ b/gstools/covmodel/fit.py @@ -36,7 +36,7 @@ def fit_variogram( max_eval=None, return_r2=False, curve_fit_kwargs=None, - **para_select + **para_select, ): """ Fitting a variogram-model to an empirical variogram. @@ -217,9 +217,7 @@ def _pre_para(model, para_select, sill, anis): var_last = False for par in para_select: if par not in model.arg_bounds: - raise ValueError( - "fit: unknow parameter in selection: {}".format(par) - ) + raise ValueError(f"fit: unknown parameter in selection: {par}") if not isinstance(para_select[par], bool): if par == "var": var_last = True @@ -288,16 +286,12 @@ def _pre_init_guess(model, init_guess, mean_x=1.0, mean_y=1.0): # "default" init guess is the respective default value default_guess = init_guess.pop("default", "default") if default_guess not in ["default", "current"]: - raise ValueError( - "fit_variogram: unknown def. guess: {}".format(default_guess) - ) + raise ValueError(f"fit_variogram: unknown def. guess: {default_guess}") default = default_guess == "default" # check invalid names for given init guesses invalid_para = set(init_guess) - set(model.iso_arg + ["anis"]) if invalid_para: - raise ValueError( - "fit_variogram: unknown init guess: {}".format(invalid_para) - ) + raise ValueError(f"fit_variogram: unknown init guess: {invalid_para}") bnd = model.arg_bounds # default length scale is mean of given bin centers (respecting "rescale") init_guess.setdefault( diff --git a/gstools/covmodel/plot.py b/gstools/covmodel/plot.py index 818f457a6..6489c1fee 100644 --- a/gstools/covmodel/plot.py +++ b/gstools/covmodel/plot.py @@ -117,7 +117,7 @@ def plot_variogram( if x_max is None: x_max = 3 * model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault("label", model.name + " variogram") + kwargs.setdefault("label", f"{model.name} variogram") ax.plot(x_s, model.variogram(x_s), **kwargs) ax.legend() fig.show() @@ -132,7 +132,7 @@ def plot_covariance( if x_max is None: x_max = 3 * model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault("label", model.name + " covariance") + kwargs.setdefault("label", f"{model.name} covariance") ax.plot(x_s, model.covariance(x_s), **kwargs) ax.legend() fig.show() @@ -147,7 +147,7 @@ def plot_correlation( if x_max is None: x_max = 3 * model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault("label", model.name + " correlation") + kwargs.setdefault("label", f"{model.name} correlation") ax.plot(x_s, model.correlation(x_s), **kwargs) ax.legend() fig.show() @@ -162,7 +162,7 @@ def plot_vario_yadrenko( if x_max is None: x_max = min(3 * model.len_rescaled, np.pi) x_s = np.linspace(x_min, x_max) - kwargs.setdefault("label", model.name + " Yadrenko variogram") + kwargs.setdefault("label", f"{model.name} Yadrenko variogram") ax.plot(x_s, model.vario_yadrenko(x_s), **kwargs) ax.legend() fig.show() @@ -177,7 +177,7 @@ def plot_cov_yadrenko( if x_max is None: x_max = min(3 * model.len_rescaled, np.pi) x_s = np.linspace(x_min, x_max) - kwargs.setdefault("label", model.name + " Yadrenko covariance") + kwargs.setdefault("label", f"{model.name} Yadrenko covariance") ax.plot(x_s, model.cov_yadrenko(x_s), **kwargs) ax.legend() fig.show() @@ -192,7 +192,7 @@ def plot_cor_yadrenko( if x_max is None: x_max = min(3 * model.len_rescaled, np.pi) x_s = np.linspace(x_min, x_max) - kwargs.setdefault("label", model.name + " Yadrenko correlation") + kwargs.setdefault("label", f"{model.name} Yadrenko correlation") ax.plot(x_s, model.cor_yadrenko(x_s), **kwargs) ax.legend() fig.show() @@ -207,9 +207,7 @@ def plot_vario_axis( if x_max is None: x_max = 3 * model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault( - "label", model.name + " variogram on axis {}".format(axis) - ) + kwargs.setdefault("label", f"{model.name} variogram on axis {axis}") ax.plot(x_s, model.vario_axis(x_s, axis), **kwargs) ax.legend() fig.show() @@ -224,9 +222,7 @@ def plot_cov_axis( if x_max is None: x_max = 3 * model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault( - "label", model.name + " covariance on axis {}".format(axis) - ) + kwargs.setdefault("label", f"{model.name} covariance on axis {axis}") ax.plot(x_s, model.cov_axis(x_s, axis), **kwargs) ax.legend() fig.show() @@ -241,9 +237,7 @@ def plot_cor_axis( if x_max is None: x_max = 3 * model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault( - "label", model.name + " correlation on axis {}".format(axis) - ) + kwargs.setdefault("label", f"{model.name} correlation on axis {axis}") ax.plot(x_s, model.cor_axis(x_s, axis), **kwargs) ax.legend() fig.show() @@ -258,9 +252,7 @@ def plot_spectrum( if x_max is None: x_max = 3 / model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault( - "label", model.name + " " + str(model.dim) + "D spectrum" - ) + kwargs.setdefault("label", f"{model.name} {model.dim}D spectrum") ax.plot(x_s, model.spectrum(x_s), **kwargs) ax.legend() fig.show() @@ -275,9 +267,7 @@ def plot_spectral_density( if x_max is None: x_max = 3 / model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault( - "label", model.name + " " + str(model.dim) + "D spectral-density" - ) + kwargs.setdefault("label", f"{model.name} {model.dim}D spectral-density") ax.plot(x_s, model.spectral_density(x_s), **kwargs) ax.legend() fig.show() @@ -292,9 +282,7 @@ def plot_spectral_rad_pdf( if x_max is None: x_max = 3 / model.len_scale x_s = np.linspace(x_min, x_max) - kwargs.setdefault( - "label", model.name + " " + str(model.dim) + "D spectral-rad-pdf" - ) + kwargs.setdefault("label", f"{model.name} {model.dim}D spectral-rad-pdf") ax.plot(x_s, model.spectral_rad_pdf(x_s), **kwargs) ax.legend() fig.show() From efab281af5c5f180d23082176451fb8e097cf126 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 15:28:37 +0100 Subject: [PATCH 12/16] field: use f-strings; minor fixes --- gstools/field/base.py | 8 +++----- gstools/field/cond_srf.py | 2 +- gstools/field/generator.py | 12 ++++++------ gstools/field/plot.py | 16 +++++++--------- gstools/field/srf.py | 10 ++++------ gstools/field/tools.py | 30 +++++++++++++----------------- 6 files changed, 34 insertions(+), 44 deletions(-) diff --git a/gstools/field/base.py b/gstools/field/base.py index 5e6519ae8..7bc836357 100755 --- a/gstools/field/base.py +++ b/gstools/field/base.py @@ -32,7 +32,7 @@ def _set_mean_trend(value, dim): return value value = np.array(value, dtype=np.double).ravel() if value.size > 1 and value.size != dim: # vector mean - raise ValueError("Mean/Trend: Wrong size ({})".format(value)) + raise ValueError(f"Mean/Trend: Wrong size ({value})") return value if value.size > 1 else value.item() @@ -308,9 +308,7 @@ def plot( "Streamflow plotting only supported for 2d case." ) else: - raise ValueError( - "Unknown field value type: {}".format(self.value_type) - ) + raise ValueError(f"Unknown field value type: {self.value_type}") return r @@ -363,7 +361,7 @@ def value_type(self): @value_type.setter def value_type(self, value_type): if value_type not in VALUE_TYPES: - raise ValueError("Field: value type not in {}".format(VALUE_TYPES)) + raise ValueError(f"Field: value type not in {VALUE_TYPES}") self._value_type = value_type @property diff --git a/gstools/field/cond_srf.py b/gstools/field/cond_srf.py index 0514c23e1..6a31e99f5 100644 --- a/gstools/field/cond_srf.py +++ b/gstools/field/cond_srf.py @@ -142,7 +142,7 @@ def set_generator(self, generator, **generator_kwargs): self._generator = gen(self.model, **generator_kwargs) self.value_type = self.generator.value_type else: - raise ValueError("gstools.CondSRF: Unknown generator " + generator) + raise ValueError(f"gstools.CondSRF: Unknown generator {generator}") @property def krige(self): diff --git a/gstools/field/generator.py b/gstools/field/generator.py index 5bcdd8d36..e87122faa 100644 --- a/gstools/field/generator.py +++ b/gstools/field/generator.py @@ -80,7 +80,7 @@ def __init__( seed=None, verbose=False, sampling="auto", - **kwargs + **kwargs, ): if kwargs: warnings.warn("gstools.RandMeth: **kwargs are ignored") @@ -192,13 +192,13 @@ def update(self, model=None, seed=np.nan): else: raise ValueError( "gstools.field.generator.RandMeth: " - + "neither 'model' nor 'seed' given!" + "neither 'model' nor 'seed' given!" ) # wrong model type else: raise ValueError( "gstools.field.generator.RandMeth: 'model' is not an " - + "instance of 'gstools.CovModel'" + "instance of 'gstools.CovModel'" ) def reset_seed(self, seed=np.nan): @@ -249,7 +249,7 @@ def sampling(self): @sampling.setter def sampling(self, sampling): if sampling not in ["auto", "inversion", "mcmc"]: - raise ValueError("RandMeth: sampling not in {}.".format(SAMPLING)) + raise ValueError(f"RandMeth: sampling not in {SAMPLING}.") self._sampling = sampling @property @@ -310,7 +310,7 @@ def value_type(self): def __repr__(self): """Return String representation.""" return "RandMeth(model={0}, mode_no={1}, seed={2})".format( - repr(self.model), self._mode_no, self.seed + self.model, self._mode_no, self.seed ) @@ -374,7 +374,7 @@ def __init__( seed=None, verbose=False, sampling="auto", - **kwargs + **kwargs, ): if model.dim < 2 or model.dim > 3: raise ValueError( diff --git a/gstools/field/plot.py b/gstools/field/plot.py index b0474f6de..559894067 100644 --- a/gstools/field/plot.py +++ b/gstools/field/plot.py @@ -82,7 +82,7 @@ def plot_1d(pos, field, fig=None, ax=None, ax_names=None): # pragma: no cover Axis containing the plot. """ fig, ax = _get_fig_ax(fig, ax) - title = "Field 1D: " + str(field.shape) + title = f"Field 1D: {field.shape}" x = pos[0] x = x.flatten() arg = np.argsort(x) @@ -108,7 +108,7 @@ def plot_nd( show_colorbar=True, convex_hull=False, contour_plot=True, - **kwargs + **kwargs, ): # pragma: no cover """ Plot field in arbitrary dimensions. @@ -167,9 +167,7 @@ def plot_nd( ax_names = _ax_names(dim, latlon, ax_names) # init planes planes = rotation_planes(dim) - plane_names = [ - " {} - {}".format(ax_names[p[0]], ax_names[p[1]]) for p in planes - ] + plane_names = [f" {ax_names[p[0]]} - {ax_names[p[1]]}" for p in planes] ax_ends = [[p.min(), p.max()] for p in pos] ax_rngs = [end[1] - end[0] for end in ax_ends] ax_steps = [rng / resolution for rng in ax_rngs] @@ -177,7 +175,7 @@ def plot_nd( # create figure reformat = fig is None and ax is None fig, ax = _get_fig_ax(fig, ax) - ax.set_title("Field {}D {} {}".format(dim, mesh_type, field.shape)) + ax.set_title(f"Field {dim}D {mesh_type} {field.shape}") if reformat: # only format fig if it was created here fig.set_size_inches(8, 5.5 + 0.5 * (dim - 2)) # init additional axis, radio-buttons and sliders @@ -306,7 +304,7 @@ def plot_vec_field(fld, field="field", fig=None, ax=None): # pragma: no cover norm = np.sqrt(plot_field[0, :].T ** 2 + plot_field[1, :].T ** 2) fig, ax = _get_fig_ax(fig, ax) - title = "Field 2D " + fld.mesh_type + ": " + str(plot_field.shape) + title = f"Field 2D {fld.mesh_type}: {plot_field.shape}" x = fld.pos[0] y = fld.pos[1] @@ -334,7 +332,7 @@ def _ax_names(dim, latlon=False, ax_names=None): return ["lon", "lat"] if dim <= 3: return ["$x$", "$y$", "$z$"][:dim] + (dim == 1) * ["field"] - return ["$x_{" + str(i) + "}$" for i in range(dim)] + return [f"$x_{{{i}}}$" for i in range(dim)] def _plot_2d( @@ -350,7 +348,7 @@ def _plot_2d( ): # pragma: no cover """Plot a 2d field with a contour plot.""" fig, ax = _get_fig_ax(fig, ax) - title = "Field 2D " + mesh_type + ": " + str(field.shape) + title = f"Field 2D {mesh_type}: {field.shape}" ax_names = _ax_names(2, latlon, ax_names=ax_names) x, y = pos[::-1] if latlon else pos if mesh_type == "unstructured": diff --git a/gstools/field/srf.py b/gstools/field/srf.py index 50ceed654..6de904df2 100644 --- a/gstools/field/srf.py +++ b/gstools/field/srf.py @@ -89,7 +89,7 @@ def __init__( trend=None, upscaling="no_scaling", generator="RandMeth", - **generator_kwargs + **generator_kwargs, ): super().__init__(model, mean=mean, normalizer=normalizer, trend=trend) # initialize private attributes @@ -162,11 +162,11 @@ def set_generator(self, generator, **generator_kwargs): self._generator = gen(self.model, **generator_kwargs) self.value_type = self._generator.value_type else: - raise ValueError("gstools.SRF: Unknown generator: " + generator) + raise ValueError(f"gstools.SRF: Unknown generator: {generator}") for val in [self.mean, self.trend]: if not callable(val) and val is not None: if np.size(val) > 1 and self.value_type == "scalar": - raise ValueError("Mean/Trend: Wrong size ({})".format(val)) + raise ValueError(f"Mean/Trend: Wrong size ({val})") @property def generator(self): @@ -191,9 +191,7 @@ def upscaling(self, upscaling): self._upscaling = upscaling self._upscaling_func = UPSCALING[upscaling] else: - raise ValueError( - "gstools.SRF: Unknown upscaling method: " + upscaling - ) + raise ValueError(f"SRF: Unknown upscaling method: {upscaling}") def __repr__(self): """Return String representation.""" diff --git a/gstools/field/tools.py b/gstools/field/tools.py index 0e2f5424e..867d3d378 100644 --- a/gstools/field/tools.py +++ b/gstools/field/tools.py @@ -7,8 +7,9 @@ The following classes and functions are provided .. autosummary:: + fmt_mean_norm_trend to_vtk_helper - mesh_call + generate_on_mesh """ import numpy as np import meshio @@ -18,7 +19,7 @@ from gstools.tools.misc import list_format -__all__ = ["fmt_mean_norm_trend", "to_vtk_helper", "mesh_call"] +__all__ = ["fmt_mean_norm_trend", "to_vtk_helper", "generate_on_mesh"] def _fmt_func_val(f_cls, func_val): # pragma: no cover @@ -95,11 +96,9 @@ def to_vtk_helper( filename, f_cls.pos, {fieldname: field}, f_cls.mesh_type ) else: - print("Field.to_vtk: '{}' not available.".format(field_select)) + raise ValueError(f"Field.to_vtk: '{field_select}' not available.") else: - raise ValueError( - "Unknown field value type: {}".format(f_cls.value_type) - ) + raise ValueError(f"Unknown field value type: {f_cls.value_type}") def generate_on_mesh( @@ -167,9 +166,8 @@ def generate_on_mesh( select = direction[: f_cls.dim] if len(select) < f_cls.dim: raise ValueError( - "Field.mesh: need at least {} direction(s), got '{}'".format( - f_cls.dim, direction - ) + f"Field.mesh: need at least {f_cls.dim} direction(s), " + f"got '{direction}'" ) # convert pyvista mesh if has_pyvista and pv.is_pyvista_dataset(mesh): @@ -235,7 +233,7 @@ def generate_on_mesh( def _names(name, cnt): name = [name] if isinstance(name, str) else list(name)[:cnt] if len(name) < cnt: - name += [name[-1] + str(i + 1) for i in range(cnt - len(name))] + name += [f"{name[-1]}{i + 1}" for i in range(cnt - len(name))] return name @@ -243,29 +241,27 @@ def _get_select(direction): select = [] if not (0 < len(direction) < 4): raise ValueError( - "Field.mesh: need 1 to 3 direction(s), got '{}'".format(direction) + f"Field.mesh: need 1 to 3 direction(s), got '{direction}'" ) for axis in direction: if axis == "x": if 0 in select: raise ValueError( - "Field.mesh: got duplicate directions {}".format(direction) + f"Field.mesh: got duplicate directions {direction}" ) select.append(0) elif axis == "y": if 1 in select: raise ValueError( - "Field.mesh: got duplicate directions {}".format(direction) + f"Field.mesh: got duplicate directions {direction}" ) select.append(1) elif axis == "z": if 2 in select: raise ValueError( - "Field.mesh: got duplicate directions {}".format(direction) + f"Field.mesh: got duplicate directions {direction}" ) select.append(2) else: - raise ValueError( - "Field.mesh: got unknown direction {}".format(axis) - ) + raise ValueError(f"Field.mesh: got unknown direction {axis}") return select From 51a4be09bd3c56405ec5f7c7ac1086c084cc483f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 15:35:47 +0100 Subject: [PATCH 13/16] normalizer: use f-strings --- gstools/normalizer/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gstools/normalizer/base.py b/gstools/normalizer/base.py index 40e2006f2..6993851ca 100644 --- a/gstools/normalizer/base.py +++ b/gstools/normalizer/base.py @@ -217,7 +217,7 @@ def _neg_kllf(par, dat): return -self.kernel_loglikelihood(dat) if len(para_names) == 0: # transformations without para. (no opti.) - warnings.warn(self.name + ".fit: no parameters!") + warnings.warn(f"{self.name}.fit: no parameters!") return {} if len(para_names) == 1: # one-para. transformations (simple opti.) # default bracket like in scipy's boxcox (if not given) @@ -255,4 +255,4 @@ def __repr__(self): "{0}={1:.{2}}".format(p, float(getattr(self, p)), self._prec) for p in sorted(self.default_parameter) ] - return self.name + "(" + ", ".join(para_strs) + ")" + return f"{self.name}({', '.join(para_strs)})" From 9f2cb278a47ca678430dab2fa363717e7259c1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 15:37:22 +0100 Subject: [PATCH 14/16] random: use f-strings --- gstools/random/rng.py | 2 +- gstools/random/tools.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gstools/random/rng.py b/gstools/random/rng.py index d9205cbcf..6df5e12f0 100644 --- a/gstools/random/rng.py +++ b/gstools/random/rng.py @@ -216,4 +216,4 @@ def seed(self, new_seed=None): def __repr__(self): """Return String representation.""" - return "RNG(seed={})".format(self.seed) + return f"RNG(seed={self.seed})" diff --git a/gstools/random/tools.py b/gstools/random/tools.py index 67a248963..5498a81b0 100644 --- a/gstools/random/tools.py +++ b/gstools/random/tools.py @@ -48,7 +48,7 @@ def seed(self): def __repr__(self): """Return String representation.""" - return "MasterRNG(seed={})".format(self.seed) + return f"MasterRNG(seed={self.seed})" def dist_gen(pdf_in=None, cdf_in=None, ppf_in=None, **kwargs): From 4d60c75aa454c614ee50abd57c42126e80c94e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 15:43:30 +0100 Subject: [PATCH 15/16] tools: use f-strings --- gstools/tools/geometric.py | 4 ++-- gstools/tools/misc.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/gstools/tools/geometric.py b/gstools/tools/geometric.py index 555fea46c..ef245851b 100644 --- a/gstools/tools/geometric.py +++ b/gstools/tools/geometric.py @@ -571,13 +571,13 @@ def ang2dir(angles, dtype=np.double, dim=None): pre_dim = np.asanyarray(angles).ndim angles = np.array(angles, ndmin=2, dtype=dtype) if len(angles.shape) > 2: - raise ValueError("Can't interpret angles array {}".format(angles)) + raise ValueError(f"Can't interpret angles array {angles}") dim = angles.shape[1] + 1 if dim is None else dim if dim == 2 and angles.shape[0] == 1 and pre_dim < 2: # fix for 2D where only one angle per direction is given angles = angles.T # can't be interpreted if dim=None is given if dim != angles.shape[1] + 1 or dim == 1: - raise ValueError("Wrong dim. ({}) for angles {}".format(dim, angles)) + raise ValueError(f"Wrong dim. ({dim}) for angles {angles}") vec = np.empty((angles.shape[0], dim), dtype=dtype) vec[:, 0] = np.prod(np.sin(angles), axis=1) for i in range(1, dim): diff --git a/gstools/tools/misc.py b/gstools/tools/misc.py index aca1d276c..a80084b68 100755 --- a/gstools/tools/misc.py +++ b/gstools/tools/misc.py @@ -19,9 +19,7 @@ def list_format(lst, prec): # pragma: no cover """Format a list of floats.""" - return "[{}]".format( - ", ".join("{x:.{p}}".format(x=float(x), p=prec) for x in lst) - ) + return f"[{', '.join(f'{float(x):.{prec}}' for x in lst)}]" def eval_func( From 5b86634caabd4dbb973299beaaebe13028eef0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20M=C3=BCller?= Date: Tue, 23 Mar 2021 15:47:03 +0100 Subject: [PATCH 16/16] variogram: use f-strings --- gstools/variogram/variogram.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gstools/variogram/variogram.py b/gstools/variogram/variogram.py index 417d590a5..7f7d8d3ea 100644 --- a/gstools/variogram/variogram.py +++ b/gstools/variogram/variogram.py @@ -48,9 +48,7 @@ def _set_estimator(estimator): elif estimator.lower() == "cressie": cython_estimator = "c" else: - raise ValueError( - "Unknown variogram estimator function " + str(estimator) - ) + raise ValueError(f"Unknown variogram estimator function: {estimator}") return cython_estimator @@ -285,9 +283,9 @@ def vario_estimate( if direction is not None and dim > 1: direction = np.array(direction, ndmin=2, dtype=np.double) if len(direction.shape) > 2: - raise ValueError("Can't interpret directions {}".format(direction)) + raise ValueError(f"Can't interpret directions: {direction}") if direction.shape[1] != dim: - raise ValueError("Can't interpret directions {}".format(direction)) + raise ValueError(f"Can't interpret directions: {direction}") dir_no = direction.shape[0] # convert given angles to direction vector if angles is not None and direction is None and dim > 1: @@ -299,7 +297,7 @@ def vario_estimate( raise ValueError("Directional variogram not allowed for lat-lon.") norms = np.linalg.norm(direction, axis=1) if np.any(np.isclose(norms, 0)): - raise ValueError("Zero length direction {}".format(direction)) + raise ValueError(f"Zero length directions: {direction}") # only unit-vectors for directions direction = np.divide(direction, norms[:, np.newaxis]) # negative bandwidth to turn it off