summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoris Roovers <joris.roovers@gmail.com>2023-01-09 12:07:50 +0100
committerGitHub <noreply@github.com>2023-01-09 12:07:50 +0100
commit56ea2963b3135a811f9869effdc7009ea43998ed (patch)
tree2edec807eb5d1c416e7e1716b60a8da285a78a7d
parent5dc7a586a9dcb1700ad9bc056737c04a15b7716b (diff)
Ruff: additional style enforcement (#407)
Enable additional styling rules for ruff and fix related violations.
-rw-r--r--docs/index.md3
-rw-r--r--gitlint-core/gitlint/cli.py36
-rw-r--r--gitlint-core/gitlint/config.py4
-rw-r--r--gitlint-core/gitlint/exception.py2
-rw-r--r--gitlint-core/gitlint/git.py2
-rw-r--r--gitlint-core/gitlint/options.py1
-rw-r--r--gitlint-core/gitlint/rule_finder.py6
-rw-r--r--gitlint-core/gitlint/rules.py16
-rw-r--r--gitlint-core/gitlint/shell.py4
-rw-r--r--gitlint-core/gitlint/tests/base.py4
-rw-r--r--gitlint-core/gitlint/tests/cli/test_cli.py3
-rw-r--r--gitlint-core/gitlint/tests/cli/test_cli_hooks.py114
-rw-r--r--gitlint-core/gitlint/tests/config/test_config.py2
-rw-r--r--gitlint-core/gitlint/tests/config/test_config_builder.py3
-rw-r--r--gitlint-core/gitlint/tests/git/test_git_commit.py8
-rw-r--r--gitlint-core/gitlint/utils.py5
-rw-r--r--pyproject.toml30
-rw-r--r--qa/base.py6
-rw-r--r--qa/shell.py11
-rw-r--r--qa/test_stdin.py2
20 files changed, 118 insertions, 144 deletions
diff --git a/docs/index.md b/docs/index.md
index 91daea5..521242f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -30,7 +30,8 @@ useful throughout the years.
- **User-defined rules:** Want to do more then what gitlint offers out of the box? Write your own [user defined rules](user_defined_rules.md).
- **Full unicode support:** Lint your Russian, Chinese or Emoji commit messages with ease!
- **Production-ready:** Gitlint checks a lot of the boxes you're looking for: actively maintained, high unit test coverage, integration tests,
- python code standards (pep8, pylint), good documentation, widely used, proven track record.
+ python code standards ([black](https://github.com/psf/black), [ruff](https://github.com/charliermarsh/ruff)),
+ good documentation, widely used, proven track record.
## Getting Started
### Installation
diff --git a/gitlint-core/gitlint/cli.py b/gitlint-core/gitlint/cli.py
index d10512a..4433ec3 100644
--- a/gitlint-core/gitlint/cli.py
+++ b/gitlint-core/gitlint/cli.py
@@ -42,8 +42,6 @@ LOG = logging.getLogger("gitlint.cli")
class GitLintUsageError(GitlintError):
"""Exception indicating there is an issue with how gitlint is used."""
- pass
-
def setup_logging():
"""Setup gitlint logging"""
@@ -247,40 +245,40 @@ class ContextObj:
# fmt: off
-@click.group(invoke_without_command=True, context_settings={'max_content_width': 120},
+@click.group(invoke_without_command=True, context_settings={"max_content_width": 120},
epilog="When no COMMAND is specified, gitlint defaults to 'gitlint lint'.")
-@click.option('--target', envvar='GITLINT_TARGET',
+@click.option("--target", envvar="GITLINT_TARGET",
type=click.Path(exists=True, resolve_path=True, file_okay=False, readable=True),
help="Path of the target git repository. [default: current working directory]")
-@click.option('-C', '--config', envvar='GITLINT_CONFIG',
+@click.option("-C", "--config", envvar="GITLINT_CONFIG",
type=click.Path(exists=True, dir_okay=False, readable=True, resolve_path=True),
help=f"Config file location [default: {DEFAULT_CONFIG_FILE}]")
-@click.option('-c', multiple=True,
+@click.option("-c", multiple=True,
help="Config flags in format <rule>.<option>=<value> (e.g.: -c T1.line-length=80). " +
"Flag can be used multiple times to set multiple config values.") # pylint: disable=bad-continuation
-@click.option('--commit', envvar='GITLINT_COMMIT', default=None, help="Hash (SHA) of specific commit to lint.")
-@click.option('--commits', envvar='GITLINT_COMMITS', default=None,
+@click.option("--commit", envvar="GITLINT_COMMIT", default=None, help="Hash (SHA) of specific commit to lint.")
+@click.option("--commits", envvar="GITLINT_COMMITS", default=None,
help="The range of commits (refspec or comma-separated hashes) to lint. [default: HEAD]")
-@click.option('-e', '--extra-path', envvar='GITLINT_EXTRA_PATH',
+@click.option("-e", "--extra-path", envvar="GITLINT_EXTRA_PATH",
help="Path to a directory or python module with extra user-defined rules",
type=click.Path(exists=True, resolve_path=True, readable=True))
-@click.option('--ignore', envvar='GITLINT_IGNORE', default="", help="Ignore rules (comma-separated by id or name).")
-@click.option('--contrib', envvar='GITLINT_CONTRIB', default="",
+@click.option("--ignore", envvar="GITLINT_IGNORE", default="", help="Ignore rules (comma-separated by id or name).")
+@click.option("--contrib", envvar="GITLINT_CONTRIB", default="",
help="Contrib rules to enable (comma-separated by id or name).")
-@click.option('--msg-filename', type=click.File(encoding=gitlint.utils.DEFAULT_ENCODING),
+@click.option("--msg-filename", type=click.File(encoding=gitlint.utils.DEFAULT_ENCODING),
help="Path to a file containing a commit-msg.")
-@click.option('--ignore-stdin', envvar='GITLINT_IGNORE_STDIN', is_flag=True,
+@click.option("--ignore-stdin", envvar="GITLINT_IGNORE_STDIN", is_flag=True,
help="Ignore any stdin data. Useful for running in CI server.")
-@click.option('--staged', envvar='GITLINT_STAGED', is_flag=True,
+@click.option("--staged", envvar="GITLINT_STAGED", is_flag=True,
help="Attempt smart guesses about meta info (like author name, email, branch, changed files, etc) " +
"for staged commits.")
-@click.option('--fail-without-commits', envvar='GITLINT_FAIL_WITHOUT_COMMITS', is_flag=True,
+@click.option("--fail-without-commits", envvar="GITLINT_FAIL_WITHOUT_COMMITS", is_flag=True,
help="Hard fail when the target commit range is empty.")
-@click.option('-v', '--verbose', envvar='GITLINT_VERBOSITY', count=True, default=0,
- help="Verbosity, more v's for more verbose output (e.g.: -v, -vv, -vvv). [default: -vvv]", )
-@click.option('-s', '--silent', envvar='GITLINT_SILENT', is_flag=True,
+@click.option("-v", "--verbose", envvar="GITLINT_VERBOSITY", count=True, default=0,
+ help="Verbosity, use multiple times for more verbose output (e.g.: -v, -vv, -vvv). [default: -vvv]", )
+@click.option("-s", "--silent", envvar="GITLINT_SILENT", is_flag=True,
help="Silent mode (no output). Takes precedence over -v, -vv, -vvv.")
-@click.option('-d', '--debug', envvar='GITLINT_DEBUG', help="Enable debugging output.", is_flag=True)
+@click.option("-d", "--debug", envvar="GITLINT_DEBUG", help="Enable debugging output.", is_flag=True)
@click.version_option(version=gitlint.__version__)
@click.pass_context
def cli( # pylint: disable=too-many-arguments
diff --git a/gitlint-core/gitlint/config.py b/gitlint-core/gitlint/config.py
index 600cbba..f06192e 100644
--- a/gitlint-core/gitlint/config.py
+++ b/gitlint-core/gitlint/config.py
@@ -296,7 +296,7 @@ class LintConfig: # pylint: disable=too-many-instance-attributes
if not hasattr(self, attr_name) or attr_name[0] == "_":
raise LintConfigError(f"'{option_name}' is not a valid gitlint option")
- # else:
+ # else
setattr(self, attr_name, option_value)
def __eq__(self, other):
@@ -386,7 +386,7 @@ class RuleCollection:
"""Deletes all rules from the collection that match a given attribute name and value"""
# Create a new list based on _rules.values() because in python 3, values() is a ValuesView as opposed to a list
# This means you can't modify the ValueView while iterating over it.
- for rule in [r for r in self._rules.values()]: # pylint: disable=unnecessary-comprehension
+ for rule in list(self._rules.values()):
if hasattr(rule, attr_name) and (getattr(rule, attr_name) == attr_val):
del self._rules[rule.id]
diff --git a/gitlint-core/gitlint/exception.py b/gitlint-core/gitlint/exception.py
index bcba54e..d1e8c9c 100644
--- a/gitlint-core/gitlint/exception.py
+++ b/gitlint-core/gitlint/exception.py
@@ -1,4 +1,2 @@
class GitlintError(Exception):
"""Based Exception class for all gitlint exceptions"""
-
- pass
diff --git a/gitlint-core/gitlint/git.py b/gitlint-core/gitlint/git.py
index b6c3b21..4750171 100644
--- a/gitlint-core/gitlint/git.py
+++ b/gitlint-core/gitlint/git.py
@@ -21,8 +21,6 @@ LOG = logging.getLogger(__name__)
class GitContextError(GitlintError):
"""Exception indicating there is an issue with the git context"""
- pass
-
class GitNotInstalledError(GitContextError):
def __init__(self):
diff --git a/gitlint-core/gitlint/options.py b/gitlint-core/gitlint/options.py
index c634ad9..ff7d9f1 100644
--- a/gitlint-core/gitlint/options.py
+++ b/gitlint-core/gitlint/options.py
@@ -37,7 +37,6 @@ class RuleOption:
@abstractmethod
def set(self, value):
"""Validates and sets the option's value"""
- pass # pragma: no cover
def __str__(self):
return f"({self.name}: {self.value} ({self.description}))"
diff --git a/gitlint-core/gitlint/rule_finder.py b/gitlint-core/gitlint/rule_finder.py
index a3a6d17..fdc9f22 100644
--- a/gitlint-core/gitlint/rule_finder.py
+++ b/gitlint-core/gitlint/rule_finder.py
@@ -55,7 +55,7 @@ def find_rule_classes(extra_path):
importlib.import_module(module)
except Exception as e:
- raise rules.UserRuleError(f"Error while importing extra-path module '{module}': {e}")
+ raise rules.UserRuleError(f"Error while importing extra-path module '{module}': {e}") from e
# Find all rule classes in the module. We do this my inspecting all members of the module and checking
# 1) is it a class, if not, skip
@@ -138,13 +138,13 @@ def assert_valid_rule_class(clazz, rule_type="User-defined"): # pylint: disable
if not hasattr(clazz, "validate") or not inspect.isroutine(clazz.validate):
raise rules.UserRuleError(f"{rule_type} rule class '{clazz.__name__}' must have a 'validate' method")
# Configuration rules must have an `apply` method
- elif issubclass(clazz, rules.ConfigurationRule):
+ elif issubclass(clazz, rules.ConfigurationRule): # noqa: SIM102
if not hasattr(clazz, "apply") or not inspect.isroutine(clazz.apply):
msg = f"{rule_type} Configuration rule class '{clazz.__name__}' must have an 'apply' method"
raise rules.UserRuleError(msg)
# LineRules must have a valid target: rules.CommitMessageTitle or rules.CommitMessageBody
- if issubclass(clazz, rules.LineRule):
+ if issubclass(clazz, rules.LineRule): # noqa: SIM102
if clazz.target not in [rules.CommitMessageTitle, rules.CommitMessageBody]:
msg = (
f"The target attribute of the {rule_type.lower()} LineRule class '{clazz.__name__}' "
diff --git a/gitlint-core/gitlint/rules.py b/gitlint-core/gitlint/rules.py
index 9cf8166..cea4645 100644
--- a/gitlint-core/gitlint/rules.py
+++ b/gitlint-core/gitlint/rules.py
@@ -50,40 +50,28 @@ class Rule:
class ConfigurationRule(Rule):
"""Class representing rules that can dynamically change the configuration of gitlint during runtime."""
- pass
-
class CommitRule(Rule):
"""Class representing rules that act on an entire commit at once"""
- pass
-
class LineRule(Rule):
"""Class representing rules that act on a line by line basis"""
- pass
-
class LineRuleTarget:
"""Base class for LineRule targets. A LineRuleTarget specifies where a given rule will be applied
(e.g. commit message title, commit message body).
Each LineRule MUST have a target specified."""
- pass
-
class CommitMessageTitle(LineRuleTarget):
"""Target class used for rules that apply to a commit message title"""
- pass
-
class CommitMessageBody(LineRuleTarget):
"""Target class used for rules that apply to a commit message body"""
- pass
-
class RuleViolation:
"""Class representing a violation of a rule. I.e.: When a rule is broken, the rule will instantiate this class
@@ -107,8 +95,6 @@ class RuleViolation:
class UserRuleError(GitlintError):
"""Error used to indicate that an error occurred while trying to load a user rule"""
- pass
-
class MaxLineLength(LineRule):
name = "max-line-length"
@@ -319,7 +305,7 @@ class BodyChangedFileMention(CommitRule):
for needs_mentioned_file in self.options["files"].value:
# if a file that we need to look out for is actually changed, then check whether it occurs
# in the commit msg body
- if needs_mentioned_file in commit.changed_files:
+ if needs_mentioned_file in commit.changed_files: # noqa: SIM102
if needs_mentioned_file not in " ".join(commit.message.body):
violation_message = f"Body does not mention changed file '{needs_mentioned_file}'"
violations.append(RuleViolation(self.id, violation_message, None, len(commit.message.body) + 1))
diff --git a/gitlint-core/gitlint/shell.py b/gitlint-core/gitlint/shell.py
index 2f66f30..21dfaba 100644
--- a/gitlint-core/gitlint/shell.py
+++ b/gitlint-core/gitlint/shell.py
@@ -27,8 +27,6 @@ else:
class CommandNotFound(Exception):
"""Exception indicating a command was not found during execution"""
- pass
-
class ShResult:
"""Result wrapper class. We use this to more easily migrate from using https://amoffat.github.io/sh/ to using
the builtin subprocess module"""
@@ -45,8 +43,6 @@ else:
class ErrorReturnCode(ShResult, Exception):
"""ShResult subclass for unexpected results (acts as an exception)."""
- pass
-
def git(*command_parts, **kwargs):
"""Git shell wrapper.
Implemented as separate function here, so we can do a 'sh' style imports:
diff --git a/gitlint-core/gitlint/tests/base.py b/gitlint-core/gitlint/tests/base.py
index 0ac51e7..7c91963 100644
--- a/gitlint-core/gitlint/tests/base.py
+++ b/gitlint-core/gitlint/tests/base.py
@@ -173,11 +173,11 @@ class BaseTestCase(unittest.TestCase):
exception_msg = str(exc)
if exception_msg != expected_msg:
error = f"Right exception, wrong message:\n got: {exception_msg}\n expected: {expected_msg}"
- raise self.fail(error)
+ raise self.fail(error) from exc
# else: everything is fine, just return
return
except Exception as exc:
- raise self.fail(f"Expected '{expected_exception.__name__}' got '{exc.__class__.__name__}'")
+ raise self.fail(f"Expected '{expected_exception.__name__}' got '{exc.__class__.__name__}'") from exc
# No exception raised while we expected one
raise self.fail(f"Expected to raise {expected_exception.__name__}, didn't get an exception at all")
diff --git a/gitlint-core/gitlint/tests/cli/test_cli.py b/gitlint-core/gitlint/tests/cli/test_cli.py
index 7bf3b4f..b4577c8 100644
--- a/gitlint-core/gitlint/tests/cli/test_cli.py
+++ b/gitlint-core/gitlint/tests/cli/test_cli.py
@@ -218,8 +218,7 @@ class CLITests(BaseTestCase):
self.assertEqual(result.exit_code, 2)
@patch("gitlint.cli.get_stdin_data", return_value=False)
- @patch("gitlint.git.sh")
- def test_lint_commit_negative(self, sh, _):
+ def test_lint_commit_negative(self, _):
"""Negative test for --commit option"""
# Try using --commit and --commits at the same time (not allowed)
diff --git a/gitlint-core/gitlint/tests/cli/test_cli_hooks.py b/gitlint-core/gitlint/tests/cli/test_cli_hooks.py
index 641961d..cf8298a 100644
--- a/gitlint-core/gitlint/tests/cli/test_cli_hooks.py
+++ b/gitlint-core/gitlint/tests/cli/test_cli_hooks.py
@@ -128,68 +128,65 @@ class CLIHookTests(BaseTestCase):
# When set_editors[i] == None, ensure we don't fallback to EDITOR set in shell invocating the tests
os.environ.pop("EDITOR", None)
- with self.patch_input(["e", "e", "n"]):
- with self.tempdir() as tmpdir:
- msg_filename = os.path.realpath(os.path.join(tmpdir, "hür"))
- with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
- f.write(commit_messages[i] + "\n")
-
- with patch("gitlint.display.stderr", new=StringIO()) as stderr:
- result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
- self.assertEqual(
- result.output,
- self.get_expected(
- "cli/test_cli_hooks/test_hook_edit_1_stdout", {"commit_msg": commit_messages[i]}
- ),
- )
- expected = self.get_expected(
- "cli/test_cli_hooks/test_hook_edit_1_stderr", {"commit_msg": commit_messages[i]}
- )
- self.assertEqual(stderr.getvalue(), expected)
-
- # exit code = number of violations
- self.assertEqual(result.exit_code, 2)
-
- shell.assert_called_with(expected_editors[i] + " " + msg_filename)
- self.assert_log_contains("DEBUG: gitlint.cli run-hook: editing commit message")
- self.assert_log_contains(f"DEBUG: gitlint.cli run-hook: {expected_editors[i]} {msg_filename}")
+ with self.patch_input(["e", "e", "n"]), self.tempdir() as tmpdir:
+ msg_filename = os.path.realpath(os.path.join(tmpdir, "hür"))
+ with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
+ f.write(commit_messages[i] + "\n")
+
+ with patch("gitlint.display.stderr", new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
+ self.assertEqual(
+ result.output,
+ self.get_expected(
+ "cli/test_cli_hooks/test_hook_edit_1_stdout", {"commit_msg": commit_messages[i]}
+ ),
+ )
+ expected = self.get_expected(
+ "cli/test_cli_hooks/test_hook_edit_1_stderr", {"commit_msg": commit_messages[i]}
+ )
+ self.assertEqual(stderr.getvalue(), expected)
+
+ # exit code = number of violations
+ self.assertEqual(result.exit_code, 2)
+
+ shell.assert_called_with(expected_editors[i] + " " + msg_filename)
+ self.assert_log_contains("DEBUG: gitlint.cli run-hook: editing commit message")
+ self.assert_log_contains(f"DEBUG: gitlint.cli run-hook: {expected_editors[i]} {msg_filename}")
def test_run_hook_no(self):
"""Test for run-hook subcommand, answering 'n(o)' after commit-hook"""
- with self.patch_input(["n"]):
- with self.tempdir() as tmpdir:
- msg_filename = os.path.join(tmpdir, "hür")
- with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
- f.write("WIP: höok no\n")
+ with self.patch_input(["n"]), self.tempdir() as tmpdir:
+ msg_filename = os.path.join(tmpdir, "hür")
+ with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
+ f.write("WIP: höok no\n")
- with patch("gitlint.display.stderr", new=StringIO()) as stderr:
- result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
- self.assertEqual(result.output, self.get_expected("cli/test_cli_hooks/test_hook_no_1_stdout"))
- self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli_hooks/test_hook_no_1_stderr"))
+ with patch("gitlint.display.stderr", new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
+ self.assertEqual(result.output, self.get_expected("cli/test_cli_hooks/test_hook_no_1_stdout"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli_hooks/test_hook_no_1_stderr"))
- # We decided not to keep the commit message: hook returns number of violations (>0)
- # This will cause git to abort the commit
- self.assertEqual(result.exit_code, 2)
- self.assert_log_contains("DEBUG: gitlint.cli run-hook: commit message declined")
+ # We decided not to keep the commit message: hook returns number of violations (>0)
+ # This will cause git to abort the commit
+ self.assertEqual(result.exit_code, 2)
+ self.assert_log_contains("DEBUG: gitlint.cli run-hook: commit message declined")
def test_run_hook_yes(self):
"""Test for run-hook subcommand, answering 'y(es)' after commit-hook"""
- with self.patch_input(["y"]):
- with self.tempdir() as tmpdir:
- msg_filename = os.path.join(tmpdir, "hür")
- with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
- f.write("WIP: höok yes\n")
+ with self.patch_input(["y"]), self.tempdir() as tmpdir:
+ msg_filename = os.path.join(tmpdir, "hür")
+ with open(msg_filename, "w", encoding=DEFAULT_ENCODING) as f:
+ f.write("WIP: höok yes\n")
- with patch("gitlint.display.stderr", new=StringIO()) as stderr:
- result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
- self.assertEqual(result.output, self.get_expected("cli/test_cli_hooks/test_hook_yes_1_stdout"))
- self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli_hooks/test_hook_yes_1_stderr"))
+ with patch("gitlint.display.stderr", new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["--msg-filename", msg_filename, "run-hook"])
+ self.assertEqual(result.output, self.get_expected("cli/test_cli_hooks/test_hook_yes_1_stdout"))
+ self.assertEqual(stderr.getvalue(), self.get_expected("cli/test_cli_hooks/test_hook_yes_1_stderr"))
- # Exit code is 0 because we decide to keep the commit message
- # This will cause git to keep the commit
- self.assertEqual(result.exit_code, 0)
- self.assert_log_contains("DEBUG: gitlint.cli run-hook: commit message accepted")
+ # Exit code is 0 because we decide to keep the commit message
+ # This will cause git to keep the commit
+ self.assertEqual(result.exit_code, 0)
+ self.assert_log_contains("DEBUG: gitlint.cli run-hook: commit message accepted")
@patch("gitlint.cli.get_stdin_data", return_value=False)
@patch("gitlint.git.sh")
@@ -271,11 +268,10 @@ class CLIHookTests(BaseTestCase):
"commit-1-branch-1\ncommit-1-branch-2\n",
]
- with self.patch_input(["e"]):
- with patch("gitlint.display.stderr", new=StringIO()) as stderr:
- result = self.cli.invoke(cli.cli, ["run-hook"])
- expected = self.get_expected("cli/test_cli_hooks/test_hook_local_commit_1_stderr")
- self.assertEqual(stderr.getvalue(), expected)
- self.assertEqual(result.output, self.get_expected("cli/test_cli_hooks/test_hook_local_commit_1_stdout"))
- # If we can't edit the message, run-hook follows regular gitlint behavior and exit code = # violations
- self.assertEqual(result.exit_code, 2)
+ with self.patch_input(["e"]), patch("gitlint.display.stderr", new=StringIO()) as stderr:
+ result = self.cli.invoke(cli.cli, ["run-hook"])
+ expected = self.get_expected("cli/test_cli_hooks/test_hook_local_commit_1_stderr")
+ self.assertEqual(stderr.getvalue(), expected)
+ self.assertEqual(result.output, self.get_expected("cli/test_cli_hooks/test_hook_local_commit_1_stdout"))
+ # If we can't edit the message, run-hook follows regular gitlint behavior and exit code = # violations
+ self.assertEqual(result.exit_code, 2)
diff --git a/gitlint-core/gitlint/tests/config/test_config.py b/gitlint-core/gitlint/tests/config/test_config.py
index e70bebe..439fd93 100644
--- a/gitlint-core/gitlint/tests/config/test_config.py
+++ b/gitlint-core/gitlint/tests/config/test_config.py
@@ -170,7 +170,7 @@ class LintConfigTests(BaseTestCase):
# UserRuleError, RuleOptionError should be re-raised as LintConfigErrors
side_effects = [rules.UserRuleError("üser-rule"), options.RuleOptionError("rüle-option")]
for side_effect in side_effects:
- with patch("gitlint.config.rule_finder.find_rule_classes", side_effect=side_effect):
+ with patch("gitlint.config.rule_finder.find_rule_classes", side_effect=side_effect): # noqa: SIM117
with self.assertRaisesMessage(LintConfigError, str(side_effect)):
config.contrib = "contrib-title-conventional-commits"
diff --git a/gitlint-core/gitlint/tests/config/test_config_builder.py b/gitlint-core/gitlint/tests/config/test_config_builder.py
index eee4afa..ac2a896 100644
--- a/gitlint-core/gitlint/tests/config/test_config_builder.py
+++ b/gitlint-core/gitlint/tests/config/test_config_builder.py
@@ -254,8 +254,7 @@ class LintConfigBuilderTests(BaseTestCase):
my_rule.options["regex"].set("wrong")
def test_named_rules_negative(self):
- # T7 = title-match-regex
- # Invalid rule name
+ # Invalid rule name (T7 = title-match-regex)
for invalid_name in ["", " ", " ", "\t", "\n", "å b", "å:b", "åb:", ":åb"]:
config_builder = LintConfigBuilder()
config_builder.set_option(f"T7:{invalid_name}", "regex", "tëst")
diff --git a/gitlint-core/gitlint/tests/git/test_git_commit.py b/gitlint-core/gitlint/tests/git/test_git_commit.py
index 4e2439c..e6b0b2c 100644
--- a/gitlint-core/gitlint/tests/git/test_git_commit.py
+++ b/gitlint-core/gitlint/tests/git/test_git_commit.py
@@ -379,7 +379,7 @@ class GitCommitTests(BaseTestCase):
@patch("gitlint.git.sh")
def test_get_latest_commit_fixup_squash_commit(self, sh):
commit_prefixes = {"fixup": "is_fixup_commit", "squash": "is_squash_commit", "amend": "is_fixup_amend_commit"}
- for commit_type in commit_prefixes.keys():
+ for commit_type in commit_prefixes:
sample_sha = "d8ac47e9f2923c7f22d8668e3a1ed04eb4cdbca9"
sh.git.side_effect = [
@@ -612,7 +612,7 @@ class GitCommitTests(BaseTestCase):
# mapping between cleanup commit prefixes and the commit object attribute
commit_prefixes = {"fixup": "is_fixup_commit", "squash": "is_squash_commit", "amend": "is_fixup_amend_commit"}
- for commit_type in commit_prefixes.keys():
+ for commit_type in commit_prefixes:
commit_msg = f"{commit_type}! Test message"
gitcontext = GitContext.from_commit_msg(commit_msg)
commit = gitcontext.commits[-1]
@@ -638,7 +638,7 @@ class GitCommitTests(BaseTestCase):
@patch("gitlint.git.sh")
@patch("arrow.now")
def test_staged_commit(self, now, sh):
- # StagedLocalGitCommit()
+ """Test for StagedLocalGitCommit()"""
sh.git.side_effect = [
"#", # git config --get core.commentchar
@@ -740,7 +740,7 @@ class GitCommitTests(BaseTestCase):
git.return_value = "foöbar"
# Test simple equality case
- now = datetime.datetime.utcnow()
+ now = datetime.datetime.now(datetime.timezone.utc)
context1 = GitContext()
commit_message1 = GitCommitMessage(context1, "tëst\n\nfoo", "tëst\n\nfoo", "tēst", ["", "föo"])
commit1 = GitCommit(
diff --git a/gitlint-core/gitlint/utils.py b/gitlint-core/gitlint/utils.py
index e94b2f7..20368b7 100644
--- a/gitlint-core/gitlint/utils.py
+++ b/gitlint-core/gitlint/utils.py
@@ -59,10 +59,7 @@ def getpreferredencoding():
# Support dotted (C.UTF-8) and non-dotted (C or UTF-8) charsets:
# If encoding contains a dot: split and use second part, otherwise use everything
dot_index = encoding.find(".")
- if dot_index != -1:
- default_encoding = encoding[dot_index + 1 :]
- else:
- default_encoding = encoding
+ default_encoding = encoding[dot_index + 1 :] if dot_index != -1 else encoding
break
# We've determined what encoding the user *wants*, let's now check if it's actually a valid encoding on the
diff --git a/pyproject.toml b/pyproject.toml
index a219f4a..3633c53 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -88,7 +88,7 @@ dependencies = [
"pytest-cov==4.0.0",
"python-coveralls==2.9.3",
"pylint==2.15.3",
- "ruff==0.0.211",
+ "ruff==0.0.215",
"radon==5.1.0",
"pdbr==0.7.5; sys_platform != \"win32\""
]
@@ -101,10 +101,11 @@ u = "unit-tests"
unit-tests-no-cov = "pytest -rw -s {args:gitlint-core}"
format = "black --check --diff ."
plint = "pylint gitlint-core/gitlint qa"
-lint = "ruff gitlint-core/gitlint qa"
+lint = "ruff {args:gitlint-core/gitlint qa}"
+autoformat = "black ."
autofix = [
"ruff --fix gitlint-core/gitlint qa",
- "black .",
+ "autoformat",
]
all = [
@@ -165,20 +166,33 @@ target-version = "py37"
extend-exclude = ["gitlint-core/gitlint/tests/samples/user_rules/import_exception/invalid_python.py"]
ignore = [
- "E501", # Never enforce `E501` (line length violations) - taken care of by black
+ "E501", # Never enforce `E501` (line length violations) - taken care of by black
+ "SIM108" # Use ternary operator instead of if-else-block
]
select = [
- "E", # Pycodestyle
"F", # PyFlakes
- "T20", # no print statements
- "UP", # pyupgrade
+ "E", # Pycodestyle
+ "W", # Pycodestyle
+ "I", # isort (import order)
+ "YTT", # flake8-2020 (misuse of sys.version)
+ "S", # flake8-bandit (security)
+ "B", # flake8-bugbear
+ "C4", # flake8-comprehensions (correct use of comprehensions)
+ "T10", # flake8-debugger (no debug statements)
+ "T20", # flake8-print (no print statements)
+ "SIM", # flake8-simplify (use simple code)
+ "TID", # flake8-tidy-imports (correct import syntax)
+ "ARG", # flake8-unused-arguments (no unused function arguments)
+ "DTZ", # flake8-datetimez (correct datetime usage)
+ "ERA", # eradicate (no commented out code)
+ "UP", # pyupgrade (modern python syntax)
"PLC", # pylint
"PLE", # pylint
"PLR", # pylint
"PLW", # pylint
+ "PIE", # flake8-pie
"RUF", # ruff specific
- "I", # isort
]
[tool.coverage.run]
diff --git a/qa/base.py b/qa/base.py
index 5e11972..713e3f9 100644
--- a/qa/base.py
+++ b/qa/base.py
@@ -6,7 +6,7 @@ import platform
import shutil
import sys
import tempfile
-from datetime import datetime
+from datetime import datetime, timezone
from unittest import TestCase
from uuid import uuid4
@@ -50,8 +50,8 @@ class BaseTestCase(TestCase):
@staticmethod
def generate_temp_path():
- timestamp = datetime.now().strftime("%Y%m%d-%H%M%S-%f")
- return os.path.realpath(f"/tmp/gitlint-test-{timestamp}")
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S-%f")
+ return os.path.realpath(f"/tmp/gitlint-test-{timestamp}") # noqa
def create_tmp_git_repo(self):
"""Creates a temporary git repository and returns its directory path"""
diff --git a/qa/shell.py b/qa/shell.py
index cd9447c..ac3d57d 100644
--- a/qa/shell.py
+++ b/qa/shell.py
@@ -25,10 +25,8 @@ else:
class CommandNotFound(Exception):
"""Exception indicating a command was not found during execution"""
- pass
-
class RunningCommand:
- pass
+ ...
class ShResult(RunningCommand):
"""Result wrapper class. We use this to more easily migrate from using https://amoffat.github.io/sh/ to using
@@ -67,8 +65,6 @@ else:
class ErrorReturnCode(ShResult, Exception):
"""ShResult subclass for unexpected results (acts as an exception)."""
- pass
-
def git(*command_parts, **kwargs):
return run_command("git", *command_parts, **kwargs)
@@ -102,10 +98,7 @@ else:
try:
with subprocess.Popen(args, **popen_kwargs) as p:
- if stdin_input:
- result = p.communicate(stdin_input)
- else:
- result = p.communicate()
+ result = p.communicate(stdin_input)
except FileNotFoundEr