Skip to content

Commit

Permalink
Apply Black to grass package, use Python 3 style everywhere (OSGeo#1382)
Browse files Browse the repository at this point in the history
This applies Black 20.8b1 formatting to grass Python package and all related tests.
ctypes is not formatted by Black and two additional files are ignored because
of bug in Black which breaks strings with escape sequence for tab.

This adds pyproject.toml file with Black configuration for the project.
In the CI, instead of mutliple Black runs, just run once for the whole tree and ignore directories which are not formatted yet.
Black is very fast (so no need for multiple job) and only one configuration is needed (unlike Flake8)

Newly, only Python 3 versions are specified as targets for Black,
so also string literals starting with u (Python 2) are replaced by
simple strings.

This also applies Python 3 targeted Black to already formatted code.
This replaces unicode literals (Python 2) by plain Python 3 strings and adds commas to kwargs in function calls.

Update Flake8 config for use with Black. Enable Flake8 whitespace checks and fix remaining issues not
touched by Black. Ignore many E226 in images2gif.py which is now ignored by Black.
Enable long line warning in Flake8. Fix or ignore lines not fixed by Black.
  • Loading branch information
wenzeslaus authored Feb 21, 2021
1 parent 981a6db commit 1aab3bb
Show file tree
Hide file tree
Showing 191 changed files with 23,287 additions and 17,267 deletions.
11 changes: 1 addition & 10 deletions .github/workflows/black.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,8 @@ on:

jobs:
run-black:
name: ${{ matrix.directory }}
name: Check
runs-on: ubuntu-20.04
strategy:
matrix:
directory:
- lib/init
- man
- scripts
- utils
fail-fast: false

steps:
- uses: actions/checkout@v2
Expand All @@ -32,5 +24,4 @@ jobs:
- name: Run Black
run: |
cd ${{ matrix.directory }}
black --check --diff .
24 changes: 12 additions & 12 deletions man/sphinx/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
master_doc = "index"

# General information about the project.
project = u"GRASS 7.9 Documentation"
copyright = u"2019, GRASS Development Team"
project = "GRASS 7.9 Documentation"
copyright = "2019, GRASS Development Team"

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
Expand Down Expand Up @@ -182,8 +182,8 @@
(
"content",
"grass79Documentation.tex",
u"GRASS 7.9 Documentation",
u"GRASS Development Team",
"GRASS 7.9 Documentation",
"GRASS Development Team",
"manual",
),
]
Expand Down Expand Up @@ -217,8 +217,8 @@
(
"content",
"grass79documentation",
u"GRASS 7.9 Documentation",
[u"GRASS Development Team"],
"GRASS 7.9 Documentation",
["GRASS Development Team"],
1,
)
]
Expand All @@ -236,8 +236,8 @@
(
"content",
"grass79Documentation",
u"GRASS 7.9 Documentation",
u"GRASS Development Team",
"GRASS 7.9 Documentation",
"GRASS Development Team",
"grass79Documentation",
"One line description of project.",
"Miscellaneous",
Expand All @@ -257,10 +257,10 @@
# -- Options for Epub output ---------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = u"GRASS 7.9 Documentation"
epub_author = u"GRASS Development Team"
epub_publisher = u"GRASS Development Team"
epub_copyright = u"2017, GRASS Development Team"
epub_title = "GRASS 7.9 Documentation"
epub_author = "GRASS Development Team"
epub_publisher = "GRASS Development Team"
epub_copyright = "2017, GRASS Development Team"

# The language of the text. It defaults to the language option
# or en if the language is not set.
Expand Down
39 changes: 39 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[tool.black]
line-length = 88
target-version = ['py36', 'py37', 'py38']
include = '\.pyi?$'
exclude = '''
(
# exclude directories in the root of the project
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| bin\.
| dist\.
)/
| python/grass/ctypes
# Bug in Black related to tab escape prevents these from being formatted correctly.
# https://github.com/psf/black/issues/1970
| python/grass/imaging/images2gif.py
| python/grass/pygrass/raster/category.py
# Directories and files not yet under Black
| db
| doc
| general
| gui
| imagery
| lib/gis
| temporal
| raster
| vector
| docker/testdata/test_grass_session.py
| display/d.mon/render_cmd.py
)
'''
37 changes: 17 additions & 20 deletions python/grass/.flake8
Original file line number Diff line number Diff line change
@@ -1,24 +1,8 @@
[flake8]
ignore =
E121, # continuation line under-indented for hanging indent
E125, # continuation line with same indent as next logical line
E127, # continuation line over-indented for visual indent
E128, # continuation line under-indented for visual indent
E202, # whitespace before ')'
E211, # whitespace before '('
E221, # multiple spaces before operator
E226, # missing whitespace around arithmetic operator
E231, # missing whitespace after ':'
E251, # unexpected spaces around keyword / parameter equals
E261, # at least two spaces before inline comment
E265, # block comment should start with '# '
E203, # whitespace before ':' (Black)
W503, # line break before binary operator (Black)
E266, # too many leading '#' for block comment
E271, # multiple spaces after keyword
E272, # multiple spaces before keyword
E302, # expected 2 blank lines, found 1
E303, # too many blank lines (3)
E305, # expected 2 blank lines after class or function definition, found 1
E501, # line too long (183 > 150 characters)
E722, # do not use bare 'except'
E741, # ambiguous variable name 'l'
F403, # 'from ctypes import *' used; unable to detect undefined names
Expand All @@ -34,13 +18,26 @@ per-file-ignores =
# TODO: Is this really needed?
pygrass/vector/__init__.py: E402,
pygrass/raster/__init__.py: E402,
pygrass/utils.py: E402,
# Files and directories which need fixes or specific exceptions
gunittest/*.py: E501 # These are mainly just todo comments
pygrass/vector/table.py: E501
pygrass/vector/__init__.py: E501, E402
pygrass/modules/interface/*.py: E501, F401
pygrass/modules/grid/*.py: E501, F401
pygrass/raster/*.py: E501
pygrass/rpc/__init__.py: E501, F401
pygrass/utils.py: E402, E501
script/db.py: E501
script/vector.py: E501 # Long doctest lines which need review anyway
temporal/*.py: E501
# Current benchmarks/tests are changing sys.path before import.
# Possibly, a different approach should be taken there anyway.
pygrass/tests/benchmark.py: E402, F401, F821
pygrass/tests/benchmark.py: E501, E402, F401, F821
# Configuration file for Sphinx:
# Ignoring import/code mix and line length.
docs/conf.py: E402, E501,
# Files not managed by Black
imaging/images2gif.py: E226, E501
# Unused imports
*/__init__.py: F401,
*/*/__init__.py: F401,
Expand Down
14 changes: 7 additions & 7 deletions python/grass/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
# - https://pymotw.com/2//gettext/index.html#application-vs-module-localization
# - https://www.wefearchange.org/2012/06/the-right-way-to-internationalize-your.html
#
_LOCALE_DIR = os.path.join(os.getenv("GISBASE"), 'locale')
_LOCALE_DIR = os.path.join(os.getenv("GISBASE"), "locale")
if six.PY2:
gettext.install('grasslibs', _LOCALE_DIR, unicode=True)
gettext.install('grassmods', _LOCALE_DIR, unicode=True)
gettext.install('grasswxpy', _LOCALE_DIR, unicode=True)
gettext.install("grasslibs", _LOCALE_DIR, unicode=True)
gettext.install("grassmods", _LOCALE_DIR, unicode=True)
gettext.install("grasswxpy", _LOCALE_DIR, unicode=True)
else:
gettext.install('grasslibs', _LOCALE_DIR)
gettext.install('grassmods', _LOCALE_DIR)
gettext.install('grasswxpy', _LOCALE_DIR)
gettext.install("grasslibs", _LOCALE_DIR)
gettext.install("grassmods", _LOCALE_DIR)
gettext.install("grasswxpy", _LOCALE_DIR)


__all__ = ["script", "temporal"]
Expand Down
83 changes: 37 additions & 46 deletions python/grass/bandref/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@
# https://github.com/radiantearth/stac-spec/blob/master/extensions/eo/README.md#band-object
# custom names must be possible


class BandReferenceReaderError(Exception):
pass


class BandReferenceReader:
"""Band references reader"""

def __init__(self):
self._json_files = glob.glob(
os.path.join(os.environ['GISBASE'], 'etc', 'g.bands', '*.json')
os.path.join(os.environ["GISBASE"], "etc", "g.bands", "*.json")
)
if not self._json_files:
raise BandReferenceReaderError("No band definitions found")
Expand All @@ -35,15 +37,11 @@ def _read_config(self):
for json_file in self._json_files:
try:
with open(json_file) as fd:
config = json.load(
fd,
object_pairs_hook=OrderedDict
)
config = json.load(fd, object_pairs_hook=OrderedDict)
except json.decoder.JSONDecodeError as e:
raise BandReferenceReaderError(
"Unable to parse '{}': {}".format(
json_file, e
))
"Unable to parse '{}': {}".format(json_file, e)
)

# check if configuration is valid
self._check_config(config)
Expand All @@ -59,12 +57,12 @@ def _check_config(config):
:param dict config: configuration to be validated
"""
for items in config.values():
for item in ('shortcut', 'bands'):
for item in ("shortcut", "bands"):
if item not in items.keys():
raise BandReferenceReaderError(
"Invalid band definition: <{}> is missing".format(item
))
if len(items['bands']) < 1:
"Invalid band definition: <{}> is missing".format(item)
)
if len(items["bands"]) < 1:
raise BandReferenceReaderError(
"Invalid band definition: no bands defined"
)
Expand All @@ -76,25 +74,24 @@ def _print_band_extended(band, item):
:param str band: band identifier
:param str item: items to be printed out
"""

def print_kv(k, v, indent):
if isinstance(v, OrderedDict):
print ('{}{}:'.format(' ' * indent * 2, k))
print("{}{}:".format(" " * indent * 2, k))
for ki, vi in v.items():
print_kv(ki, vi, indent * 2)
else:
print ('{}{}: {}'.format(' ' * indent * 2, k, v))
print("{}{}: {}".format(" " * indent * 2, k, v))

indent = 4
print ('{}band: {}'.format(
' ' * indent, band
))
print("{}band: {}".format(" " * indent, band))
for k, v in item[band].items():
print_kv(k, v, indent)

def _print_band(self, shortcut, band, tag=None):
sys.stdout.write(self._band_identifier(shortcut, band))
if tag:
sys.stdout.write(' {}'.format(tag))
sys.stdout.write(" {}".format(tag))
sys.stdout.write(os.linesep)

def print_info(self, shortcut=None, band=None, extended=False):
Expand All @@ -110,48 +107,41 @@ def print_info(self, shortcut=None, band=None, extended=False):
for root in self.config.values():
for item in root.values():
try:
if shortcut and re.match(shortcut, item['shortcut']) is None:
if shortcut and re.match(shortcut, item["shortcut"]) is None:
continue
except re.error as e:
raise BandReferenceReaderError(
"Invalid pattern: {}".format(e)
)
raise BandReferenceReaderError("Invalid pattern: {}".format(e))

found = True
if band and band not in item['bands']:
if band and band not in item["bands"]:
raise BandReferenceReaderError(
"Band <{}> not found in <{}>".format(
band, shortcut
))
"Band <{}> not found in <{}>".format(band, shortcut)
)

# print generic information
if extended:
for subitem in item.keys():
if subitem == 'bands':
if subitem == "bands":
# bands item is processed bellow
continue
print ('{}: {}'.format(
subitem, item[subitem]
))
print("{}: {}".format(subitem, item[subitem]))

# print detailed band information
if band:
self._print_band_extended(band, item['bands'])
self._print_band_extended(band, item["bands"])
else:
for iband in item['bands']:
self._print_band_extended(iband, item['bands'])
for iband in item["bands"]:
self._print_band_extended(iband, item["bands"])
else:
# basic information only
if band:
self._print_band(
item['shortcut'], band,
item['bands'][band].get('tag')
item["shortcut"], band, item["bands"][band].get("tag")
)
else:
for iband in item['bands']:
for iband in item["bands"]:
self._print_band(
item['shortcut'], iband,
item['bands'][iband].get('tag')
item["shortcut"], iband, item["bands"][iband].get("tag")
)

# raise error when defined shortcut not found
Expand All @@ -170,7 +160,7 @@ def find_file(self, band_reference):
:return str: file basename if found or None
"""
try:
shortcut, band = band_reference.split('_')
shortcut, band = band_reference.split("_")
except ValueError:
# raise BandReferenceReaderError("Invalid band identifier <{}>".format(
# band_reference
Expand All @@ -180,8 +170,11 @@ def find_file(self, band_reference):

for filename, config in self.config.items():
for root in config.keys():
if config[root]['shortcut'].upper() == shortcut.upper() and \
band.upper() in map(lambda x: x.upper(), config[root]['bands'].keys()):
if config[root][
"shortcut"
].upper() == shortcut.upper() and band.upper() in map(
lambda x: x.upper(), config[root]["bands"].keys()
):
return filename

return None
Expand All @@ -194,12 +187,10 @@ def get_bands(self):
bands = []
for root in self.config.values():
for item in root.values():
for band in item['bands']:
bands.append(
self._band_identifier(item['shortcut'], band)
)
for band in item["bands"]:
bands.append(self._band_identifier(item["shortcut"], band))
return bands

@staticmethod
def _band_identifier(shortcut, band):
return '{}_{}'.format(shortcut, band)
return "{}_{}".format(shortcut, band)
Loading

0 comments on commit 1aab3bb

Please sign in to comment.