Skip to content

Commit

Permalink
GitHub Action to lint Python code with codespell and ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
cclauss committed Jul 9, 2023
1 parent d3fad57 commit 4ab4a83
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 60 deletions.
16 changes: 16 additions & 0 deletions .github/workflows/codespell_and_ruff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# https://github.com/codespell-project/codespell#readme
# https://beta.ruff.rs
name: codespell_and_ruff
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
codespell_and_ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: pip install --user codespell[toml] ruff
- run: codespell --quiet-level 1
- run: ruff --format=github .
75 changes: 75 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,78 @@ yaml2json = 'remarshal:main'
yaml2msgpack = 'remarshal:main'
yaml2toml = 'remarshal:main'
yaml2yaml = 'remarshal:main'

[tool.ruff]
select = [
"A", # flake8-builtins
"AIR", # Airflow
"ARG", # flake8-unused-arguments
"ASYNC", # flake8-async
"B", # flake8-bugbear
"BLE", # flake8-blind-except
"C4", # flake8-comprehensions
"C90", # McCabe cyclomatic complexity
"CPY", # Copyright-related rules
"DTZ", # flake8-datetimez
"E", # pycodestyle
"EM", # flake8-errmsg
"EXE", # flake8-executable
"F", # Pyflakes
"FA", # flake8-future-annotations
"FBT", # flake8-boolean-trap
"FIX", # flake8-fixme
"FLY", # flynt
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"INP", # flake8-no-pep420
"INT", # flake8-gettext
"ISC", # flake8-implicit-str-concat
"N", # pep8-naming
"PERF", # Perflint
"PGH", # pygrep-hooks
"PIE", # flake8-pie
"PL", # Pylint
"PT", # flake8-pytest-style
"PYI", # flake8-pyi
"RET", # flake8-return
"RSE", # flake8-raise
"RUF", # Ruff-specific rules
"S", # flake8-bandit
"SIM", # flake8-simplify
"SLF", # flake8-self
"SLOT", # flake8-slots
"T10", # flake8-debugger
"T20", # flake8-print
"TCH", # flake8-type-checking
"TD", # flake8-todos
"TID", # flake8-tidy-imports
"W", # pycodestyle
"YTT", # flake8-2020
# "ANN", # flake8-annotations
# "COM", # flake8-commas
# "D", # pydocstyle
# "DJ", # flake8-django
# "ERA", # eradicate
# "NPY", # NumPy-specific rules
# "PD", # pandas-vet
# "PTH", # flake8-use-pathlib
# "Q", # flake8-quotes
# "TRY", # tryceratops
# "UP", # pyupgrade
]
ignore = ["A002", "B006", "FBT002", "PGH003"]
target-version = "py37"

[tool.ruff.mccabe]
max-complexity = 14

[tool.ruff.pylint]
allow-magic-value-types = ["int", "str"]
max-args = 11
max-branches = 19

[tool.ruff.per-file-ignores]
"remarshal.py" = ["ARG001", "B904", "EM103", "RET506", "S506", "SIM115"]
"tests/test_remarshal.py" = ["F841", "PT011"]
"tests/*" = ["S101"]
74 changes: 39 additions & 35 deletions remarshal.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@


import argparse
import cbor2 # type: ignore
import datetime
import dateutil.parser
import json
import os.path
import re
import sys

import cbor2
import dateutil.parser
import tomlkit
import umsgpack # type: ignore
import yaml


__version__ = "0.15.0"

FORMATS = ["cbor", "json", "msgpack", "toml", "yaml"]
Expand Down Expand Up @@ -60,7 +60,8 @@ def timestamp_constructor(loader, node):
def json_default(obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
raise TypeError(f"{repr(obj)} is not JSON-serializable")
msg = f"{obj!r} is not JSON serializable"
raise TypeError(msg)


# === CLI ===
Expand All @@ -69,11 +70,8 @@ def json_default(obj):
def argv0_to_format(argv0):
possible_format = "(" + "|".join(FORMATS) + ")"
match = re.search("^" + possible_format + "2" + possible_format, argv0)
if match:
from_, to = match.groups()
return True, from_, to
else:
return False, None, None
from_, to = match.groups() if match else (None, None)
return bool(match), from_, to


def extension_to_format(path):
Expand Down Expand Up @@ -275,21 +273,24 @@ def decode_json(input_data):
input_data.decode("utf-8"),
)
except json.JSONDecodeError as e:
raise ValueError(f"Cannot parse as JSON ({e})")
msg = f"Cannot parse as JSON ({e})"
raise ValueError(msg)


def decode_msgpack(input_data):
try:
return umsgpack.unpackb(input_data)
except umsgpack.UnpackException as e:
raise ValueError(f"Cannot parse as MessagePack ({e})")
msg = f"Cannot parse as MessagePack ({e})"
raise ValueError(msg)


def decode_cbor(input_data):
try:
return cbor2.loads(input_data)
except cbor2.CBORDecodeError as e:
raise ValueError(f"Cannot parse as CBOR ({e})")
msg = f"Cannot parse as CBOR ({e})"
raise ValueError(msg)


def decode_toml(input_data):
Expand Down Expand Up @@ -337,15 +338,17 @@ def decode_toml(input_data):
},
)
except tomlkit.exceptions.ParseError as e:
raise ValueError(f"Cannot parse as TOML ({e})")
msg = f"Cannot parse as TOML ({e})"
raise ValueError(msg)


def decode_yaml(input_data):
try:
loader = TimezoneLoader
return yaml.load(input_data, loader)
except (yaml.scanner.ScannerError, yaml.parser.ParserError) as e:
raise ValueError(f"Cannot parse as YAML ({e})")
msg = f"Cannot parse as YAML ({e})"
raise ValueError(msg)


def decode(input_format, input_data):
Expand All @@ -358,7 +361,8 @@ def decode(input_format, input_data):
}

if input_format not in decoder:
raise ValueError(f"Unknown input format: {input_format}")
msg = f"Unknown input format: {input_format}"
raise ValueError(msg)

return decoder[input_format](input_data)

Expand All @@ -367,18 +371,12 @@ def encode_json(data, ordered, indent):
if indent is True:
indent = 2

if indent:
separators = (",", ": ")
else:
separators = (",", ":")
separators = (",", ": ") if indent else (",", ":")

def stringify_key(key):
if isinstance(key, bool):
return "true" if key else "false"
elif key is None:
return "null"
else:
return key
return "null" if key is None else key

try:
return (
Expand All @@ -396,37 +394,41 @@ def stringify_key(key):
+ "\n"
)
except TypeError as e:
raise ValueError(f"Cannot convert data to JSON ({e})")
msg = f"Cannot convert data to JSON ({e})"
raise ValueError(msg)


def encode_msgpack(data):
try:
return umsgpack.packb(data)
except umsgpack.UnsupportedTypeException as e:
raise ValueError(f"Cannot convert data to MessagePack ({e})")
msg = f"Cannot convert data to MessagePack ({e})"
raise ValueError(msg)


def encode_cbor(data):
try:
return cbor2.dumps(data)
except cbor2.CBOREncodeError as e:
raise ValueError(f"Cannot convert data to CBOR ({e})")
msg = f"Cannot convert data to CBOR ({e})"
raise ValueError(msg)


def encode_toml(data, ordered):
try:
return tomlkit.dumps(data, sort_keys=not ordered)
except AttributeError as e:
if str(e) == "'list' object has no attribute 'as_string'":
raise ValueError(
"Cannot convert non-dictionary data to "
'TOML; use "wrap" to wrap it in a '
"dictionary"
msg = (
"Cannot convert non-dictionary data to TOML; "
'use "wrap" to wrap it in a dictionary'
)
raise ValueError(msg)
else:
raise e
except (TypeError, ValueError) as e:
raise ValueError(f"Cannot convert data to TOML ({e})")
msg = f"Cannot convert data to TOML ({e})"
raise ValueError(msg)


def encode_yaml(data, ordered, yaml_options):
Expand All @@ -439,10 +441,11 @@ def encode_yaml(data, ordered, yaml_options):
allow_unicode=True,
default_flow_style=False,
encoding=None,
**yaml_options
**yaml_options,
)
except yaml.representer.RepresenterError as e:
raise ValueError(f"Cannot convert data to YAML ({e})")
msg = f"Cannot convert data to YAML ({e})"
raise ValueError(msg)


# === Main ===
Expand Down Expand Up @@ -511,7 +514,8 @@ def remarshal(
elif output_format == "cbor":
output_data = encode_cbor(parsed)
else:
raise ValueError(f"Unknown output format: {output_format}")
msg = f"Unknown output format: {output_format}"
raise ValueError(msg)

if output_format == "msgpack" or output_format == "cbor":
encoded = output_data
Expand All @@ -533,7 +537,7 @@ def main():
except KeyboardInterrupt:
pass
except (OSError, ValueError) as e:
print(f"Error: {e}", file=sys.stderr)
print(f"Error: {e}", file=sys.stderr) # noqa: T201
sys.exit(1)


Expand Down
Loading

0 comments on commit 4ab4a83

Please sign in to comment.