From 092a781360a9284d19d9d4f78351b9e27da0ed06 Mon Sep 17 00:00:00 2001 From: Basile Dura Date: Fri, 31 Mar 2023 14:04:47 +0200 Subject: [PATCH] feat: add ruff for code linting (#12) * feat: add ruff requirement and configuration * style: apply ruff * style: remove now unnecessary # noqa comments * feat: remove dead code? * build: add python version constraint on ruff * style: add isort to avoid multi-line imports * build: fix requirements * fix: use more general exception --- pyproject.toml | 20 ++++++++++++++++++++ requirements.txt | 2 ++ setup.py | 2 +- weasel/__init__.py | 16 ++++++++-------- weasel/_util.py | 29 +++++++++++++---------------- weasel/cli/assets.py | 17 +++++++++-------- weasel/cli/clone.py | 13 +++++++------ weasel/cli/document.py | 6 +++--- weasel/cli/dvc.py | 11 +++++------ weasel/cli/pull.py | 8 ++++---- weasel/cli/push.py | 8 ++++---- weasel/cli/remote_storage.py | 17 +++++++++-------- weasel/cli/run.py | 18 +++++++++--------- weasel/compat.py | 6 ------ weasel/schemas.py | 6 +++--- weasel/tests/test_cli.py | 12 +++++------- weasel/util.py | 30 +++++++++++++++--------------- 17 files changed, 117 insertions(+), 104 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fed528d..11cf8d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,23 @@ [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" + +[tool.ruff] +ignore = [ + "E501", +] +select = [ + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # Pyflakes + "Q", # flake8-quotes +] + +[tool.ruff.per-file-ignores] +# Ignore unused imports in __init__ files +"__init__.py" = ["F401"] + + +[tool.isort] +multi_line_output = 9 +profile = "black" diff --git a/requirements.txt b/requirements.txt index 57591cf..4d86f4b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,5 @@ typing_extensions>=3.7.4.1,<4.5.0; python_version < "3.8" # Development dependencies black==22.3.0 pytest>=5.2.0,!=7.1.0 +ruff>=0.0.259; python_version > "3.6" +isort>=5.12.0,<6.0; python_version > "3.7" \ No newline at end of file diff --git a/setup.py b/setup.py index 8f25fdb..80081a7 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python if __name__ == "__main__": - from setuptools import setup, find_packages + from setuptools import find_packages, setup setup(name="weasel", packages=find_packages()) diff --git a/weasel/__init__.py b/weasel/__init__.py index f3172d6..1be162f 100644 --- a/weasel/__init__.py +++ b/weasel/__init__.py @@ -1,11 +1,11 @@ -from ._util import app # noqa: F401 +from ._util import app # These are the actual functions, NOT the wrapped CLI commands. The CLI commands # are registered automatically and won't have to be imported here. -from .cli.assets import project_assets # noqa: F401 -from .cli.clone import project_clone # noqa: F401 -from .cli.document import project_document # noqa: F401 -from .cli.dvc import project_update_dvc # noqa: F401 -from .cli.pull import project_pull # noqa: F401 -from .cli.push import project_push # noqa: F401 -from .cli.run import project_run # noqa: F401 +from .cli.assets import project_assets +from .cli.clone import project_clone +from .cli.document import project_document +from .cli.dvc import project_update_dvc +from .cli.pull import project_pull +from .cli.push import project_push +from .cli.run import project_run diff --git a/weasel/_util.py b/weasel/_util.py index c28ec58..4c662e8 100644 --- a/weasel/_util.py +++ b/weasel/_util.py @@ -1,30 +1,28 @@ # code initially copied from spacy/cli/_util.py -from typing import Dict, Any, Union, List, Optional, Tuple, Iterable -from typing import TYPE_CHECKING -import sys +import hashlib +import os import shutil +import sys +from configparser import InterpolationError +from contextlib import contextmanager from pathlib import Path -from wasabi import msg +from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Tuple, Union + import srsly -import hashlib import typer from click import NoSuchOption from click.parser import split_arg_string -from contextlib import contextmanager from thinc.api import Config, ConfigValidationError -from configparser import InterpolationError -import os - -from .util import run_command, make_tempdir, logger -from .util import is_compatible_version, SimpleFrozenDict, ENV_VARS - -from .schemas import ProjectConfigSchema, validate +from wasabi import msg from . import about +from .schemas import ProjectConfigSchema, validate +from .util import ENV_VARS, SimpleFrozenDict, is_compatible_version, logger +from .util import make_tempdir, run_command if TYPE_CHECKING: - from pathy import FluidPath # noqa: F401 + from pathy import FluidPath COMMAND = "python -m weasel" @@ -459,7 +457,7 @@ def get_git_version( """ try: ret = run_command("git --version", capture=True) - except: + except Exception: raise RuntimeError(error) stdout = ret.stdout.strip() if not stdout or not stdout.startswith("git version"): @@ -490,4 +488,3 @@ def is_subpath_of(parent, child): parent_realpath = os.path.realpath(parent) child_realpath = os.path.realpath(child) return os.path.commonpath([parent_realpath, child_realpath]) == parent_realpath - diff --git a/weasel/cli/assets.py b/weasel/cli/assets.py index 1ed7955..6da9bde 100644 --- a/weasel/cli/assets.py +++ b/weasel/cli/assets.py @@ -1,16 +1,17 @@ -from typing import Any, Dict, Optional -from pathlib import Path -from wasabi import msg import os import re import shutil +from pathlib import Path +from typing import Any, Dict, Optional + import requests import typer +from wasabi import msg +from .._util import PROJECT_FILE, Arg, Opt, SimpleFrozenDict, app, download_file +from .._util import get_checksum, get_git_version, git_checkout, load_project_config +from .._util import parse_config_overrides from ..util import ensure_path, working_dir -from .._util import app, Arg, Opt, PROJECT_FILE, load_project_config -from .._util import get_checksum, download_file, git_checkout, get_git_version -from .._util import SimpleFrozenDict, parse_config_overrides # Whether assets are extra if `extra` is not set. EXTRA_DEFAULT = False @@ -77,8 +78,8 @@ def project_assets( checksum = asset.get("checksum") if "git" in asset: git_err = ( - f"Cloning spaCy project templates requires Git and the 'git' command. " - f"Make sure it's installed and that the executable is available." + "Cloning spaCy project templates requires Git and the 'git' command. " + "Make sure it's installed and that the executable is available." ) get_git_version(error=git_err) if dest.exists(): diff --git a/weasel/cli/clone.py b/weasel/cli/clone.py index 7c6ca1f..a39e6cf 100644 --- a/weasel/cli/clone.py +++ b/weasel/cli/clone.py @@ -1,13 +1,14 @@ -from typing import Optional +import re +import subprocess from pathlib import Path +from typing import Optional + from wasabi import msg -import subprocess -import re from .. import about +from .._util import COMMAND, PROJECT_FILE, Arg, Opt, app, get_git_version, git_checkout +from .._util import git_repo_branch_exists from ..util import ensure_path -from .._util import app, Arg, Opt, COMMAND, PROJECT_FILE -from .._util import git_checkout, get_git_version, git_repo_branch_exists DEFAULT_REPO = about.__projects__ DEFAULT_PROJECTS_BRANCH = about.__projects_branch__ @@ -83,7 +84,7 @@ def project_clone( if not (project_dir / PROJECT_FILE).exists(): msg.warn(f"No {PROJECT_FILE} found in directory") else: - msg.good(f"Your project is now ready!") + msg.good("Your project is now ready!") print(f"To fetch the assets, run:\n{COMMAND} project assets {dest}") diff --git a/weasel/cli/document.py b/weasel/cli/document.py index 1f80a85..ee4a600 100644 --- a/weasel/cli/document.py +++ b/weasel/cli/document.py @@ -1,9 +1,9 @@ from pathlib import Path -from wasabi import msg, MarkdownRenderer -from ..util import working_dir -from .._util import app, Arg, Opt, PROJECT_FILE, load_project_config +from wasabi import MarkdownRenderer, msg +from .._util import PROJECT_FILE, Arg, Opt, app, load_project_config +from ..util import working_dir DOCS_URL = "https://spacy.io" INTRO_PROJECT = f"""The [`{PROJECT_FILE}`]({PROJECT_FILE}) defines the data assets required by the diff --git a/weasel/cli/dvc.py b/weasel/cli/dvc.py index 36bbb7d..99e9b7b 100644 --- a/weasel/cli/dvc.py +++ b/weasel/cli/dvc.py @@ -1,15 +1,14 @@ """This module contains helpers and subcommands for integrating spaCy projects with Data Version Controk (DVC). https://dvc.org""" -from typing import Dict, Any, List, Optional, Iterable import subprocess from pathlib import Path -from wasabi import msg +from typing import Any, Dict, List, Optional -from .._util import PROJECT_FILE, load_project_config, get_hash, app -from .._util import Arg, Opt, NAME, COMMAND -from ..util import working_dir, split_command, join_command, run_command -from ..util import SimpleFrozenList +from wasabi import msg +from .._util import COMMAND, NAME, PROJECT_FILE, Arg, Opt, app, get_hash +from .._util import load_project_config +from ..util import join_command, run_command, working_dir DVC_CONFIG = "dvc.yaml" DVC_DIR = ".dvc" diff --git a/weasel/cli/pull.py b/weasel/cli/pull.py index c58084b..b4fb641 100644 --- a/weasel/cli/pull.py +++ b/weasel/cli/pull.py @@ -1,9 +1,9 @@ from pathlib import Path + from wasabi import msg -from .remote_storage import RemoteStorage -from .remote_storage import get_command_hash -from .._util import app, Arg, logger -from .._util import load_project_config + +from .._util import Arg, app, load_project_config, logger +from .remote_storage import RemoteStorage, get_command_hash from .run import update_lockfile diff --git a/weasel/cli/push.py b/weasel/cli/push.py index 7e1bb31..e6349b9 100644 --- a/weasel/cli/push.py +++ b/weasel/cli/push.py @@ -1,9 +1,9 @@ from pathlib import Path + from wasabi import msg -from .remote_storage import RemoteStorage -from .remote_storage import get_content_hash, get_command_hash -from .._util import load_project_config -from .._util import app, Arg, logger + +from .._util import Arg, app, load_project_config, logger +from .remote_storage import RemoteStorage, get_command_hash, get_content_hash @app.command("push") diff --git a/weasel/cli/remote_storage.py b/weasel/cli/remote_storage.py index 2619759..0d35f85 100644 --- a/weasel/cli/remote_storage.py +++ b/weasel/cli/remote_storage.py @@ -1,21 +1,22 @@ -from typing import Optional, List, Dict, TYPE_CHECKING +import hashlib import os import site -import hashlib -import urllib.parse import tarfile +import urllib.parse from pathlib import Path +from typing import TYPE_CHECKING, Dict, List, Optional + from wasabi import msg -from .._util import get_hash, get_checksum, upload_file, download_file -from .._util import ensure_pathy, make_tempdir -from ..util import get_minor_version, ENV_VARS, check_bool_env_var -from ..git_info import GIT_VERSION from .. import about +from .._util import download_file, ensure_pathy, get_checksum, get_hash, make_tempdir +from .._util import upload_file from ..errors import Errors +from ..git_info import GIT_VERSION +from ..util import ENV_VARS, check_bool_env_var, get_minor_version if TYPE_CHECKING: - from pathy import FluidPath # noqa: F401 + from pathy import FluidPath class RemoteStorage: diff --git a/weasel/cli/run.py b/weasel/cli/run.py index 1d65220..1fa5d0c 100644 --- a/weasel/cli/run.py +++ b/weasel/cli/run.py @@ -1,20 +1,20 @@ -from typing import Optional, List, Dict, Sequence, Any, Iterable, Tuple import os.path +import sys from pathlib import Path +from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple -from wasabi import msg -from wasabi.util import locale_escape -import sys import srsly import typer +from wasabi import msg +from wasabi.util import locale_escape from .. import about +from .._util import COMMAND, PROJECT_FILE, PROJECT_LOCK, Arg, Opt, app, get_checksum +from .._util import get_hash, load_project_config, parse_config_overrides from ..git_info import GIT_VERSION -from ..util import working_dir, run_command, split_command, is_cwd, join_command -from ..util import SimpleFrozenList, is_minor_version_match, ENV_VARS -from ..util import check_bool_env_var, SimpleFrozenDict -from .._util import PROJECT_FILE, PROJECT_LOCK, load_project_config, get_hash -from .._util import get_checksum, app, Arg, Opt, COMMAND, parse_config_overrides +from ..util import ENV_VARS, SimpleFrozenDict, SimpleFrozenList, check_bool_env_var +from ..util import is_cwd, is_minor_version_match, join_command, run_command +from ..util import split_command, working_dir @app.command( diff --git a/weasel/compat.py b/weasel/compat.py index 1545c57..515171a 100644 --- a/weasel/compat.py +++ b/weasel/compat.py @@ -1,11 +1,5 @@ import sys -if sys.version_info[:2] >= (3, 8): # Python 3.8+ - from typing import Literal -else: - from typing_extensions import Literal # noqa: F401 - - is_windows = sys.platform.startswith("win") is_linux = sys.platform.startswith("linux") is_osx = sys.platform == "darwin" diff --git a/weasel/schemas.py b/weasel/schemas.py index 543ce6c..568f810 100644 --- a/weasel/schemas.py +++ b/weasel/schemas.py @@ -1,9 +1,9 @@ # code copied from spacy/schemas.py -from typing import Dict, List, Union, Optional, Any, Type -from pydantic import BaseModel, ValidationError -from pydantic import StrictStr, Field from collections import defaultdict +from typing import Any, Dict, List, Optional, Type, Union + +from pydantic import BaseModel, Field, StrictStr, ValidationError def validate(schema: Type[BaseModel], obj: Dict[str, Any]) -> List[str]: diff --git a/weasel/tests/test_cli.py b/weasel/tests/test_cli.py index 64c086e..35ce652 100644 --- a/weasel/tests/test_cli.py +++ b/weasel/tests/test_cli.py @@ -1,18 +1,16 @@ # code copied from spacy/tests/test_cli.py import os -import pytest -import srsly import time -from weasel._util import is_subpath_of, load_project_config -from weasel._util import substitute_project_variables -from weasel._util import validate_project_commands, ConfigValidationError -from weasel.schemas import ProjectConfigSchema, validate +import pytest +import srsly +from weasel._util import ConfigValidationError, is_subpath_of, load_project_config +from weasel._util import substitute_project_variables, validate_project_commands from weasel.cli.remote_storage import RemoteStorage from weasel.cli.run import _check_requirements - +from weasel.schemas import ProjectConfigSchema, validate from weasel.util import make_tempdir diff --git a/weasel/util.py b/weasel/util.py index b60df65..2b3e2b8 100644 --- a/weasel/util.py +++ b/weasel/util.py @@ -1,25 +1,25 @@ # code copied from spacy/util.py -from typing import List, Union, Any -from typing import Optional, Iterator, Generator -from types import ModuleType -import os import importlib -from pathlib import Path +import logging +import os +import shlex +import shutil +import stat +import subprocess import sys +import tempfile import warnings -from packaging.specifiers import SpecifierSet, InvalidSpecifier -from packaging.version import Version, InvalidVersion -import subprocess from contextlib import contextmanager -import tempfile -import shutil -import shlex -import logging -import stat +from pathlib import Path +from types import ModuleType +from typing import Any, Generator, Iterator, List, Optional, Union + +from packaging.specifiers import InvalidSpecifier, SpecifierSet +from packaging.version import InvalidVersion, Version -from .errors import Errors, Warnings from .compat import is_windows +from .errors import Errors, Warnings logger = logging.getLogger("spacy") logger_stream_handler = logging.StreamHandler() @@ -229,7 +229,7 @@ def run_command( message = f"Error running command:\n\n{cmd_str}\n\n" message += f"Subprocess exited with status {ret.returncode}" if ret.stdout is not None: - message += f"\n\nProcess log (stdout and stderr):\n\n" + message += "\n\nProcess log (stdout and stderr):\n\n" message += ret.stdout error = subprocess.SubprocessError(message) error.ret = ret # type: ignore[attr-defined]