From 3d86357d570385c3c570908fd40cda1d9ff9822c Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 12 Jul 2020 18:51:58 -0400 Subject: [PATCH 1/2] Add blackdoc to format Python codes in docstrings --- .github/workflows/ci_tests.yaml | 2 +- CONTRIBUTING.md | 6 +++--- Makefile | 7 +++++-- environment.yml | 1 + requirements-dev.txt | 1 + 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index b4818fd89a1..6be5427ebb0 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -28,7 +28,7 @@ jobs: python-version: 3.7 - name: Install packages - run: pip install black flake8 pylint + run: pip install black blackdoc flake8 pylint - name: Formatting check (black and flake8) run: make check diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 919b381dc26..19dd0d6f6d8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -245,8 +245,8 @@ directory). ### Code style -We use [Black](https://github.com/ambv/black) to format the code so we don't have to -think about it. +We use [Black](https://github.com/ambv/black) and [blackdoc](https://github.com/keewis/blackdoc) +to format the code so we don't have to think about it. Black loosely follows the [PEP8](http://pep8.org) guide but with a few differences. Regardless, you won't have to worry about formatting the code yourself. Before committing, run it to automatically format your code: @@ -265,7 +265,7 @@ common errors. The [`Makefile`](Makefile) contains rules for running both checks: ```bash -make check # Runs flake8 and black (in check mode) +make check # Runs flake8, black and blackdoc (in check mode) make lint # Runs pylint, which is a bit slower ``` diff --git a/Makefile b/Makefile index d6672c19f5e..9f5fdd40e6b 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ PYTEST_ARGS=--cov=$(PROJECT) --cov-config=../.coveragerc \ --doctest-modules -v --mpl --mpl-results-path=results \ --pyargs ${PYTEST_EXTRA} BLACK_FILES=$(PROJECT) setup.py doc/conf.py examples +BLACKDOC_OPTIONS=--line-length 79 FLAKE8_FILES=$(PROJECT) setup.py doc/conf.py LINT_FILES=$(PROJECT) setup.py doc/conf.py @@ -14,8 +15,8 @@ help: @echo "" @echo " install install in editable mode" @echo " test run the test suite (including doctests) and report coverage" - @echo " format run black to automatically format the code" - @echo " check run code style and quality checks (black and flake8)" + @echo " format run black and blackdoc to automatically format the code" + @echo " check run code style and quality checks (black, blackdoc and flake8)" @echo " lint run pylint for a deeper (and slower) quality check" @echo " clean clean up build and generated files" @echo "" @@ -36,9 +37,11 @@ test: format: black $(BLACK_FILES) + blackdoc $(BLACKDOC_OPTIONS) $(BLACK_FILES) check: black --check $(BLACK_FILES) + blackdoc --check $(BLACKDOC_OPTIONS) $(BLACK_FILES) flake8 $(FLAKE8_FILES) lint: diff --git a/environment.yml b/environment.yml index 0590f52b8ca..39de11039a6 100644 --- a/environment.yml +++ b/environment.yml @@ -19,6 +19,7 @@ dependencies: - pytest-mpl - coverage - black + - blackdoc - pylint - flake8 - sphinx=2.2.1 diff --git a/requirements-dev.txt b/requirements-dev.txt index 76352e17224..f6a53ef0310 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,6 +7,7 @@ pytest-cov pytest-mpl coverage black +blackdoc pylint flake8 sphinx=2.2.1 From a92fa5b73e4f9f3fa05dced3394664760dccf275 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 4 Oct 2020 03:21:37 -0400 Subject: [PATCH 2/2] Run "makeformat" to format codes in docstrings --- pygmt/base_plotting.py | 2 +- pygmt/clib/conversion.py | 17 +++++------ pygmt/clib/session.py | 57 +++++++++++++++++++++---------------- pygmt/figure.py | 10 +++---- pygmt/helpers/decorators.py | 36 ++++++++++++----------- pygmt/helpers/tempfile.py | 2 +- pygmt/helpers/utils.py | 21 +++++++++----- 7 files changed, 82 insertions(+), 63 deletions(-) diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py index e02eb03d310..0f7a20ad7f3 100644 --- a/pygmt/base_plotting.py +++ b/pygmt/base_plotting.py @@ -48,7 +48,7 @@ def _preprocess(self, **kwargs): # pylint: disable=no-self-use -------- >>> base = BasePlotting() - >>> base._preprocess(resolution='low') + >>> base._preprocess(resolution="low") {'resolution': 'low'} """ diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py index 8dd8adbeb93..e851211050d 100644 --- a/pygmt/clib/conversion.py +++ b/pygmt/clib/conversion.py @@ -47,7 +47,7 @@ def dataarray_to_matrix(grid): >>> from pygmt.datasets import load_earth_relief >>> # Use the global Earth relief grid with 1 degree spacing - >>> grid = load_earth_relief(resolution='01d') + >>> grid = load_earth_relief(resolution="01d") >>> matrix, region, inc = dataarray_to_matrix(grid) >>> print(region) [-180.0, 180.0, -90.0, 90.0] @@ -61,7 +61,7 @@ def dataarray_to_matrix(grid): True >>> # Using a slice of the grid, the matrix will be copied to guarantee >>> # that it's C-contiguous in memory. The increment should be unchanged. - >>> matrix, region, inc = dataarray_to_matrix(grid[10:41,30:101]) + >>> matrix, region, inc = dataarray_to_matrix(grid[10:41, 30:101]) >>> matrix.flags.c_contiguous True >>> print(matrix.shape) @@ -71,7 +71,7 @@ def dataarray_to_matrix(grid): >>> print(inc) [1.0, 1.0] >>> # but not if only taking every other grid point. - >>> matrix, region, inc = dataarray_to_matrix(grid[10:41:2,30:101:2]) + >>> matrix, region, inc = dataarray_to_matrix(grid[10:41:2, 30:101:2]) >>> matrix.flags.c_contiguous True >>> print(matrix.shape) @@ -231,11 +231,12 @@ def kwargs_to_ctypes_array(argument, kwargs, dtype): -------- >>> import ctypes as ct - >>> value = kwargs_to_ctypes_array('bla', {'bla': [10, 10]}, ct.c_long*2) + >>> value = kwargs_to_ctypes_array("bla", {"bla": [10, 10]}, ct.c_long * 2) >>> type(value) >>> should_be_none = kwargs_to_ctypes_array( - ... 'swallow', {'bla': 1, 'foo': [20, 30]}, ct.c_int*2) + ... "swallow", {"bla": 1, "foo": [20, 30]}, ct.c_int * 2 + ... ) >>> print(should_be_none) None @@ -313,9 +314,9 @@ def array_to_datetime(array): >>> # Mixed datetime types >>> x = [ - ... "2018-01-01", - ... np.datetime64("2018-01-01"), - ... datetime.datetime(2018, 1, 1), + ... "2018-01-01", + ... np.datetime64("2018-01-01"), + ... datetime.datetime(2018, 1, 1), ... ] >>> array_to_datetime(x) # doctest: +NORMALIZE_WHITESPACE DatetimeIndex(['2018-01-01', '2018-01-01', '2018-01-01'], diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index d5ce3a8a4cb..73cead5b47d 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -270,8 +270,9 @@ def get_libgmt_func(self, name, argtypes=None, restype=None): >>> from ctypes import c_void_p, c_int >>> with Session() as lib: - ... func = lib.get_libgmt_func('GMT_Destroy_Session', - ... argtypes=[c_void_p], restype=c_int) + ... func = lib.get_libgmt_func( + ... "GMT_Destroy_Session", argtypes=[c_void_p], restype=c_int + ... ) >>> type(func) ._FuncPtr'> @@ -702,15 +703,15 @@ def _check_dtype_and_dim(self, array, ndim): -------- >>> import numpy as np - >>> data = np.array([1, 2, 3], dtype='float64') + >>> data = np.array([1, 2, 3], dtype="float64") >>> with Session() as ses: ... gmttype = ses._check_dtype_and_dim(data, ndim=1) ... gmttype == ses["GMT_DOUBLE"] True - >>> data = np.ones((5, 2), dtype='float32') + >>> data = np.ones((5, 2), dtype="float32") >>> with Session() as ses: ... gmttype = ses._check_dtype_and_dim(data, ndim=2) - ... gmttype == ses['GMT_FLOAT'] + ... gmttype == ses["GMT_FLOAT"] True """ @@ -1022,23 +1023,23 @@ def open_virtual_file(self, family, geometry, direction, data): >>> x = np.array([0, 1, 2, 3, 4]) >>> y = np.array([5, 6, 7, 8, 9]) >>> with Session() as lib: - ... family = 'GMT_IS_DATASET|GMT_VIA_VECTOR' - ... geometry = 'GMT_IS_POINT' + ... family = "GMT_IS_DATASET|GMT_VIA_VECTOR" + ... geometry = "GMT_IS_POINT" ... dataset = lib.create_data( ... family=family, ... geometry=geometry, - ... mode='GMT_CONTAINER_ONLY', + ... mode="GMT_CONTAINER_ONLY", ... dim=[2, 5, 1, 0], # columns, lines, segments, type ... ) ... lib.put_vector(dataset, column=0, vector=x) ... lib.put_vector(dataset, column=1, vector=y) ... # Add the dataset to a virtual file - ... vfargs = (family, geometry, 'GMT_IN|GMT_IS_REFERENCE', dataset) + ... vfargs = (family, geometry, "GMT_IN|GMT_IS_REFERENCE", dataset) ... with lib.open_virtual_file(*vfargs) as vfile: ... # Send the output to a temp file so that we can read it ... with GMTTempFile() as ofile: - ... args = '{} ->{}'.format(vfile, ofile.name) - ... lib.call_module('info', args) + ... args = "{} ->{}".format(vfile, ofile.name) + ... lib.call_module("info", args) ... print(ofile.read().strip()) : N = 5 <0/4> <5/9> @@ -1133,7 +1134,7 @@ def virtualfile_from_vectors(self, *vectors): ... # Send the output to a file so that we can read it ... with GMTTempFile() as fout: ... ses.call_module( - ... 'info', '{} ->{}'.format(fin, fout.name) + ... "info", "{} ->{}".format(fin, fout.name) ... ) ... print(fout.read().strip()) : N = 3 <1/3> <4/6> <7/9> @@ -1245,7 +1246,7 @@ def virtualfile_from_matrix(self, matrix): ... # Send the output to a file so that we can read it ... with GMTTempFile() as fout: ... ses.call_module( - ... 'info', '{} ->{}'.format(fin, fout.name) + ... "info", "{} ->{}".format(fin, fout.name) ... ) ... print(fout.read().strip()) : N = 4 <0/9> <1/10> <2/11> @@ -1314,7 +1315,7 @@ def virtualfile_from_grid(self, grid): >>> from pygmt.datasets import load_earth_relief >>> from pygmt.helpers import GMTTempFile - >>> data = load_earth_relief(resolution='01d') + >>> data = load_earth_relief(resolution="01d") >>> print(data.shape) (180, 360) >>> print(data.lon.values.min(), data.lon.values.max()) @@ -1327,8 +1328,8 @@ def virtualfile_from_grid(self, grid): ... with ses.virtualfile_from_grid(data) as fin: ... # Send the output to a file so that we can read it ... with GMTTempFile() as fout: - ... args = '{} -L0 -Cn ->{}'.format(fin, fout.name) - ... ses.call_module('grdinfo', args) + ... args = "{} -L0 -Cn ->{}".format(fin, fout.name) + ... ses.call_module("grdinfo", args) ... print(fout.read().strip()) -180 180 -90 90 -8182 5651.5 1 1 360 180 1 1 >>> # The output is: w e s n z0 z1 dx dy n_columns n_rows reg gtype @@ -1378,22 +1379,27 @@ def extract_region(self): >>> import pygmt >>> fig = pygmt.Figure() - >>> fig.coast(region=[0, 10, -20, -10], projection="M6i", frame=True, - ... land='black') + >>> fig.coast( + ... region=[0, 10, -20, -10], + ... projection="M6i", + ... frame=True, + ... land="black", + ... ) >>> with Session() as lib: ... wesn = lib.extract_region() - >>> print(', '.join(['{:.2f}'.format(x) for x in wesn])) + >>> print(", ".join(["{:.2f}".format(x) for x in wesn])) 0.00, 10.00, -20.00, -10.00 Using ISO country codes for the regions (for example ``'US.HI'`` for Hawaii): >>> fig = pygmt.Figure() - >>> fig.coast(region='US.HI', projection="M6i", frame=True, - ... land='black') + >>> fig.coast( + ... region="US.HI", projection="M6i", frame=True, land="black" + ... ) >>> with Session() as lib: ... wesn = lib.extract_region() - >>> print(', '.join(['{:.2f}'.format(x) for x in wesn])) + >>> print(", ".join(["{:.2f}".format(x) for x in wesn])) -164.71, -154.81, 18.91, 23.58 The country codes can have an extra argument that rounds the region a @@ -1401,11 +1407,12 @@ def extract_region(self): region to multiples of 5): >>> fig = pygmt.Figure() - >>> fig.coast(region='US.HI+r5', projection="M6i", frame=True, - ... land='black') + >>> fig.coast( + ... region="US.HI+r5", projection="M6i", frame=True, land="black" + ... ) >>> with Session() as lib: ... wesn = lib.extract_region() - >>> print(', '.join(['{:.2f}'.format(x) for x in wesn])) + >>> print(", ".join(["{:.2f}".format(x) for x in wesn])) -165.00, -150.00, 15.00, 25.00 """ diff --git a/pygmt/figure.py b/pygmt/figure.py index d32588ae85d..7f91492aad3 100644 --- a/pygmt/figure.py +++ b/pygmt/figure.py @@ -43,21 +43,21 @@ class Figure(BasePlotting): -------- >>> fig = Figure() - >>> fig.basemap(region=[0, 360, -90, 90], projection='W7i', frame=True) + >>> fig.basemap(region=[0, 360, -90, 90], projection="W7i", frame=True) >>> fig.savefig("my-figure.png") >>> # Make sure the figure file is generated and clean it up >>> import os - >>> os.path.exists('my-figure.png') + >>> os.path.exists("my-figure.png") True - >>> os.remove('my-figure.png') + >>> os.remove("my-figure.png") The plot region can be specified through ISO country codes (for example, ``'JP'`` for Japan): >>> fig = Figure() - >>> fig.basemap(region='JP', projection="M3i", frame=True) + >>> fig.basemap(region="JP", projection="M3i", frame=True) >>> # The fig.region attribute shows the WESN bounding box for the figure - >>> print(', '.join('{:.2f}'.format(i) for i in fig.region)) + >>> print(", ".join("{:.2f}".format(i) for i in fig.region)) 122.94, 145.82, 20.53, 45.52 """ diff --git a/pygmt/helpers/decorators.py b/pygmt/helpers/decorators.py index 376952891b4..28e8fafd896 100644 --- a/pygmt/helpers/decorators.py +++ b/pygmt/helpers/decorators.py @@ -154,7 +154,7 @@ def fmt_docstring(module_func): -------- >>> @fmt_docstring - ... @use_alias(R='region', J='projection') + ... @use_alias(R="region", J="projection") ... def gmtinfo(**kwargs): ... ''' ... My nice module. @@ -230,19 +230,19 @@ def use_alias(**aliases): Examples -------- - >>> @use_alias(R='region', J='projection') + >>> @use_alias(R="region", J="projection") ... def my_module(**kwargs): - ... print('R =', kwargs['R'], 'J =', kwargs['J']) - >>> my_module(R='bla', J='meh') + ... print("R =", kwargs["R"], "J =", kwargs["J"]) + >>> my_module(R="bla", J="meh") R = bla J = meh - >>> my_module(region='bla', J='meh') + >>> my_module(region="bla", J="meh") R = bla J = meh - >>> my_module(R='bla', projection='meh') + >>> my_module(R="bla", projection="meh") R = bla J = meh - >>> my_module(region='bla', projection='meh') + >>> my_module(region="bla", projection="meh") R = bla J = meh >>> my_module( - ... region='bla', projection='meh', J="bla" + ... region="bla", projection="meh", J="bla" ... ) # doctest: +NORMALIZE_WHITESPACE Traceback (most recent call last): ... @@ -309,21 +309,25 @@ def kwargs_to_strings(convert_bools=True, **conversions): -------- >>> @kwargs_to_strings( - ... R='sequence', i='sequence_comma', files='sequence_space' + ... R="sequence", i="sequence_comma", files="sequence_space" ... ) ... def module(*args, **kwargs): ... "A module that prints the arguments it received" - ... print('{', end='') - ... print(', '.join( - ... "'{}': {}".format(k, repr(kwargs[k])) for k in sorted(kwargs)), - ... end='') - ... print('}') + ... print("{", end="") + ... print( + ... ", ".join( + ... "'{}': {}".format(k, repr(kwargs[k])) + ... for k in sorted(kwargs) + ... ), + ... end="", + ... ) + ... print("}") ... if args: - ... print("args:", ' '.join('{}'.format(x) for x in args)) + ... print("args:", " ".join("{}".format(x) for x in args)) >>> module(R=[1, 2, 3, 4]) {'R': '1/2/3/4'} >>> # It's already a string, do nothing - >>> module(R='5/6/7/8') + >>> module(R="5/6/7/8") {'R': '5/6/7/8'} >>> module(P=True) {'P': ''} diff --git a/pygmt/helpers/tempfile.py b/pygmt/helpers/tempfile.py index a17293eb460..7dd1b7c3710 100644 --- a/pygmt/helpers/tempfile.py +++ b/pygmt/helpers/tempfile.py @@ -45,7 +45,7 @@ class GMTTempFile: >>> with GMTTempFile() as tmpfile: ... # write data to temporary file ... x = y = z = np.arange(0, 3, 1) - ... np.savetxt(tmpfile.name, (x, y, z), fmt='%.1f') + ... np.savetxt(tmpfile.name, (x, y, z), fmt="%.1f") ... lines = tmpfile.read() ... print(lines) ... nx, ny, nz = tmpfile.loadtxt(unpack=True, dtype=float) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 5004e1b24cf..79b65fc0048 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -51,7 +51,7 @@ def data_kind(data, x=None, y=None, z=None): 'vectors' >>> data_kind(data=np.arange(10).reshape((5, 2)), x=None, y=None) 'matrix' - >>> data_kind(data='my-data-file.txt', x=None, y=None) + >>> data_kind(data="my-data-file.txt", x=None, y=None) 'file' >>> data_kind(data=xr.DataArray(np.random.rand(4, 3))) 'grid' @@ -94,7 +94,7 @@ def dummy_context(arg): Examples -------- - >>> with dummy_context('some argument') as temp: + >>> with dummy_context("some argument") as temp: ... print(temp) some argument @@ -127,11 +127,18 @@ def build_arg_string(kwargs): Examples -------- - >>> print(build_arg_string(dict(R='1/2/3/4', J="X4i", P='', E=200))) + >>> print(build_arg_string(dict(R="1/2/3/4", J="X4i", P="", E=200))) -E200 -JX4i -P -R1/2/3/4 - >>> print(build_arg_string(dict(R='1/2/3/4', J="X4i", - ... B=['xaf', 'yaf', 'WSen'], - ... I=('1/1p,blue', '2/0.25p,blue')))) + >>> print( + ... build_arg_string( + ... dict( + ... R="1/2/3/4", + ... J="X4i", + ... B=["xaf", "yaf", "WSen"], + ... I=("1/1p,blue", "2/0.25p,blue"), + ... ) + ... ) + ... ) -Bxaf -Byaf -BWSen -I1/1p,blue -I2/0.25p,blue -JX4i -R1/2/3/4 """ @@ -164,7 +171,7 @@ def is_nonstr_iter(value): Examples -------- - >>> is_nonstr_iter('abc') + >>> is_nonstr_iter("abc") False >>> is_nonstr_iter(10) False