From 7ecc43272fe50af18fdef48f621e7e404cff9e0d Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:38:49 -0600 Subject: [PATCH 1/8] ruff . --select COM --fix --- conftest.py | 4 ++-- docs/conf.py | 2 +- scripts/generate_gitlab.py | 8 ++++---- src/vcspull/cli/__init__.py | 2 +- src/vcspull/config.py | 14 +++++++------- src/vcspull/log.py | 4 ++-- tests/fixtures/example.py | 8 ++++---- tests/test_cli.py | 6 +++--- tests/test_config.py | 6 +++--- tests/test_config_file.py | 32 ++++++++++++++++---------------- tests/test_sync.py | 14 +++++++------- tests/test_utils.py | 4 ++-- 12 files changed, 52 insertions(+), 52 deletions(-) diff --git a/conftest.py b/conftest.py index e3fbd5d5..972c38a4 100644 --- a/conftest.py +++ b/conftest.py @@ -58,7 +58,7 @@ def xdg_config_path( @pytest.fixture(scope="function") def config_path( - xdg_config_path: pathlib.Path, request: pytest.FixtureRequest + xdg_config_path: pathlib.Path, request: pytest.FixtureRequest, ) -> pathlib.Path: """Ensure and return vcspull configuration path.""" conf_path = xdg_config_path / "vcspull" @@ -73,7 +73,7 @@ def clean() -> None: @pytest.fixture(autouse=True) def set_xdg_config_path( - monkeypatch: pytest.MonkeyPatch, xdg_config_path: pathlib.Path + monkeypatch: pytest.MonkeyPatch, xdg_config_path: pathlib.Path, ) -> None: """Set XDG_CONFIG_HOME environment variable.""" monkeypatch.setenv("XDG_CONFIG_HOME", str(xdg_config_path)) diff --git a/docs/conf.py b/docs/conf.py index d6e56dd1..6402a3e4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -96,7 +96,7 @@ "sidebar/navigation.html", "sidebar/projects.html", "sidebar/scroll-end.html", - ] + ], } # linkify_issues diff --git a/scripts/generate_gitlab.py b/scripts/generate_gitlab.py index 7afe4664..d0c2e3f7 100755 --- a/scripts/generate_gitlab.py +++ b/scripts/generate_gitlab.py @@ -20,7 +20,7 @@ parser = argparse.ArgumentParser( description="Script to generate vcsconfig for all repositories \ - under the given namespace (needs Gitlab >= 10.3)" + under the given namespace (needs Gitlab >= 10.3)", ) parser.add_argument("gitlab_host", type=str, help="url to the gitlab instance") parser.add_argument( @@ -47,14 +47,14 @@ result = input( "The target config file (%s) already exists, \ do you want to overwrite it? [y/N] " - % (config_filename) + % (config_filename), ) if result != "y": print( "Aborting per user request as existing config file (%s) \ should not be overwritten!" - % (config_filename) + % (config_filename), ) sys.exit(0) @@ -103,7 +103,7 @@ name="origin", fetch_url=f"ssh://{url_to_repo}", push_url=f"ssh://{url_to_repo}", - ) + ), }, "vcs": vcs, } diff --git a/src/vcspull/cli/__init__.py b/src/vcspull/cli/__init__.py index ff8446c0..af99f568 100644 --- a/src/vcspull/cli/__init__.py +++ b/src/vcspull/cli/__init__.py @@ -23,7 +23,7 @@ vcspull sync "django-*" flask vcspull sync -c ./myrepos.yaml "*" vcspull sync -c ./myrepos.yaml myproject -""" +""", ).strip() diff --git a/src/vcspull/config.py b/src/vcspull/config.py index 928b1bdf..ac69463b 100644 --- a/src/vcspull/config.py +++ b/src/vcspull/config.py @@ -116,13 +116,13 @@ def extract_repos( continue if isinstance(url, str): conf["remotes"][remote_name] = GitRemote( - name=remote_name, fetch_url=url, push_url=url + name=remote_name, fetch_url=url, push_url=url, ) elif isinstance(url, dict): assert "push_url" in url assert "fetch_url" in url conf["remotes"][remote_name] = GitRemote( - name=remote_name, **url + name=remote_name, **url, ) def is_valid_config_dict(val: t.Any) -> "TypeGuard[ConfigDict]": @@ -153,7 +153,7 @@ def find_home_config_files( log.debug( "No config file found. Create a .vcspull.yaml or .vcspull.json" " in your $HOME directory. http://vcspull.git-pull.com for a" - " quickstart." + " quickstart.", ) else: if sum(filter(None, [has_json_config, has_yaml_config])) > 1: @@ -280,7 +280,7 @@ def load_configs( def detect_duplicate_repos( - config1: list["ConfigDict"], config2: list["ConfigDict"] + config1: list["ConfigDict"], config2: list["ConfigDict"], ) -> list[ConfigDictTuple]: """Return duplicate repos dict if repo_dir same and vcs different. @@ -379,7 +379,7 @@ def filter_repos( r for r in config if fnmatch.fnmatch(str(pathlib.Path(r["path"]).parent), str(path)) - ] + ], ) if vcs_url: @@ -391,14 +391,14 @@ def filter_repos( if name: repo_list.extend( - [r for r in config if fnmatch.fnmatch(str(r.get("name")), name)] + [r for r in config if fnmatch.fnmatch(str(r.get("name")), name)], ) return repo_list def is_config_file( - filename: str, extensions: t.Optional[t.Union[list[str], str]] = None + filename: str, extensions: t.Optional[t.Union[list[str], str]] = None, ) -> bool: """Return True if file has a valid config file type. diff --git a/src/vcspull/log.py b/src/vcspull/log.py index 7dac8cad..5ae4f2c2 100644 --- a/src/vcspull/log.py +++ b/src/vcspull/log.py @@ -164,7 +164,7 @@ def template(self, record: logging.LogRecord) -> str: ] tpl = "".join( - reset + levelname + asctime + name + module_funcName + lineno + reset + reset + levelname + asctime + name + module_funcName + lineno + reset, ) return tpl @@ -176,7 +176,7 @@ class RepoLogFormatter(LogFormatter): def template(self, record: logging.LogRecord) -> str: """Template for logging vcs bin name, along with a contextual hint.""" record.message = "".join( - [Fore.MAGENTA, Style.BRIGHT, record.message, Fore.RESET, Style.RESET_ALL] + [Fore.MAGENTA, Style.BRIGHT, record.message, Fore.RESET, Style.RESET_ALL], ) return "{}|{}| {}({}) {}".format( Fore.GREEN + Style.DIM, diff --git a/tests/fixtures/example.py b/tests/fixtures/example.py index 0066e1b7..c92b1ae4 100644 --- a/tests/fixtures/example.py +++ b/tests/fixtures/example.py @@ -21,7 +21,7 @@ "upstream": "git+https://github.com/emre/kaptan", "ms": "git+https://github.com/ms/kaptan.git", }, - } + }, }, "/home/me/myproject": { ".vim": { @@ -31,7 +31,7 @@ ".tmux": { "url": "git+git@github.com:tony/tmux-config.git", "shell_command_after": [ - "ln -sf /home/me/.tmux/.tmux.conf /home/me/.tmux.conf" + "ln -sf /home/me/.tmux/.tmux.conf /home/me/.tmux.conf", ], }, }, @@ -73,14 +73,14 @@ "name": "upstream", "fetch_url": "git+https://github.com/emre/kaptan", "push_url": "git+https://github.com/emre/kaptan", - } + }, ), "ms": GitRemote( **{ "name": "ms", "fetch_url": "git+https://github.com/ms/kaptan.git", "push_url": "git+https://github.com/ms/kaptan.git", - } + }, ), }, }, diff --git a/tests/test_cli.py b/tests/test_cli.py index a6991a4c..20629a3c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -87,7 +87,7 @@ def test_sync_cli_filter_non_existent( "url": f"git+file://{git_repo.path}", "remotes": {"test_remote": f"git+file://{git_repo.path}"}, }, - } + }, } yaml_config = config_path / ".vcspull.yaml" yaml_config_data = yaml.dump(config, default_flow_style=False) @@ -226,7 +226,7 @@ def test_sync( "url": f"git+file://{git_repo.path}", "remotes": {"test_remote": "git+file://non-existent-remote"}, }, - } + }, } yaml_config = config_path / ".vcspull.yaml" yaml_config_data = yaml.dump(config, default_flow_style=False) @@ -366,7 +366,7 @@ def test_sync_broken( "my_git_repo_not_found": { "url": "git+file:///dev/null", }, - } + }, } yaml_config = config_path / ".vcspull.yaml" yaml_config_data = yaml.dump(config, default_flow_style=False) diff --git a/tests/test_config.py b/tests/test_config.py index d3daa6d0..12b70258 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -28,7 +28,7 @@ def load_yaml(tmp_path: pathlib.Path) -> LoadYAMLFn: """Return a yaml loading function that uses temporary directory path.""" def fn( - content: str, path: str = "randomdir", filename: str = "randomfilename.yaml" + content: str, path: str = "randomdir", filename: str = "randomfilename.yaml", ) -> tuple[pathlib.Path, list[pathlib.Path], list["ConfigDict"]]: """Return vcspull configurations and write out config to temp directory.""" _dir = tmp_path / path @@ -49,7 +49,7 @@ def test_simple_format(load_yaml: LoadYAMLFn) -> None: """ vcspull: libvcs: git+https://github.com/vcs-python/libvcs - """ + """, ) assert len(repos) == 1 @@ -65,7 +65,7 @@ def test_relative_dir(load_yaml: LoadYAMLFn) -> None: """ ./relativedir: docutils: svn+http://svn.code.sf.net/p/docutils/code/trunk - """ + """, ) config_files = config.find_config_files(path=path) diff --git a/tests/test_config_file.py b/tests/test_config_file.py index 84ba3507..1106701a 100644 --- a/tests/test_config_file.py +++ b/tests/test_config_file.py @@ -220,7 +220,7 @@ def test_in_dir( def test_find_config_path_string( - config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path + config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path, ) -> None: """Tests find_config_files() returns configuration files found in directory.""" config_files = config.find_config_files(path=config_path) @@ -288,7 +288,7 @@ def test_find_config_match_list( assert json_config in config_files config_files = config.find_config_files( - path=[config_path], match=[yaml_config.stem] + path=[config_path], match=[yaml_config.stem], ) assert yaml_config in config_files assert len([c for c in config_files if str(yaml_config) in str(c)]) == 1 @@ -297,52 +297,52 @@ def test_find_config_match_list( def test_find_config_filetype_string( - config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path + config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path, ) -> None: """Tests find_config_files() filters files by filetype when param passed.""" config_files = config.find_config_files( - path=[config_path], match=yaml_config.stem, filetype="yaml" + path=[config_path], match=yaml_config.stem, filetype="yaml", ) assert yaml_config in config_files assert json_config not in config_files config_files = config.find_config_files( - path=[config_path], match=yaml_config.stem, filetype="json" + path=[config_path], match=yaml_config.stem, filetype="json", ) assert yaml_config not in config_files assert json_config not in config_files config_files = config.find_config_files( - path=[config_path], match="repos*", filetype="json" + path=[config_path], match="repos*", filetype="json", ) assert yaml_config not in config_files assert json_config in config_files config_files = config.find_config_files( - path=[config_path], match="repos*", filetype="*" + path=[config_path], match="repos*", filetype="*", ) assert yaml_config in config_files assert json_config in config_files def test_find_config_filetype_list( - config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path + config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path, ) -> None: """Test find_config_files() accepts a list of file types, including wildcards.""" config_files = config.find_config_files( - path=[config_path], match=["repos*"], filetype=["*"] + path=[config_path], match=["repos*"], filetype=["*"], ) assert yaml_config in config_files assert json_config in config_files config_files = config.find_config_files( - path=[config_path], match=["repos*"], filetype=["json", "yaml"] + path=[config_path], match=["repos*"], filetype=["json", "yaml"], ) assert yaml_config in config_files assert json_config in config_files config_files = config.find_config_files( - path=[config_path], filetype=["json", "yaml"] + path=[config_path], filetype=["json", "yaml"], ) assert yaml_config in config_files assert json_config in config_files @@ -358,7 +358,7 @@ def test_find_config_include_home_config_files( with EnvironmentVarGuard() as env: env.set("HOME", str(tmp_path)) config_files = config.find_config_files( - path=[config_path], match="*", include_home=True + path=[config_path], match="*", include_home=True, ) assert yaml_config in config_files assert json_config in config_files @@ -366,7 +366,7 @@ def test_find_config_include_home_config_files( config_file3 = tmp_path / ".vcspull.json" config_file3.touch() results = config.find_config_files( - path=[config_path], match="*", include_home=True + path=[config_path], match="*", include_home=True, ) expected_in = config_file3 assert expected_in in results @@ -385,7 +385,7 @@ def test_merge_nested_dict(tmp_path: pathlib.Path, config_path: pathlib.Path) -> url: svn+file:///path/to/svnrepo subRepoSameVCS: git+file://path/to/gitrepo vcsOn1: svn+file:///path/to/another/svn - """ + """, ), ) config2 = write_config( @@ -397,13 +397,13 @@ def test_merge_nested_dict(tmp_path: pathlib.Path, config_path: pathlib.Path) -> url: git+file:///path/to/diffrepo subRepoSameVCS: git+file:///path/to/gitrepo vcsOn2: svn+file:///path/to/another/svn - """ + """, ), ) # Duplicate path + name with different repo URL / remotes raises. config_files = config.find_config_files( - path=config_path, match="repoduplicate[1-2]" + path=config_path, match="repoduplicate[1-2]", ) assert config1 in config_files assert config2 in config_files diff --git a/tests/test_sync.py b/tests/test_sync.py index bfb50725..bb0b0926 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -30,7 +30,7 @@ def test_makes_recursive( f""" {tmp_path}/study/myrepo: my_url: git+file://{git_remote_repo} - """ + """, ), ) if is_valid_config(conf): @@ -59,7 +59,7 @@ def write_config_remote( return write_config( config_path=config_path, content=config_tpl.format( - tmp_path=str(tmp_path.parent), path=path, CLONE_NAME=clone_name + tmp_path=str(tmp_path.parent), path=path, CLONE_NAME=clone_name, ), ) @@ -164,7 +164,7 @@ def test_config_variations( remotes = repo.remotes() or {} remote_names = set(remotes.keys()) assert set(remote_list).issubset(remote_names) or {"origin"}.issubset( - remote_names + remote_names, ) for remote_name in remotes: @@ -178,12 +178,12 @@ def test_config_variations( and remote_name in repo_dict["remotes"] ): if repo_dict["remotes"][remote_name].fetch_url.startswith( - "git+file://" + "git+file://", ): assert current_remote.fetch_url == repo_dict["remotes"][ remote_name ].fetch_url.replace( - "git+", "" + "git+", "", ), "Final git remote should chop git+ prefix" else: assert ( @@ -267,7 +267,7 @@ def test_updating_remote( name=mirror_name, fetch_url=f"git+file://{dummy_repo}", push_url=f"git+file://{dummy_repo}", - ) + ), }, } @@ -297,7 +297,7 @@ def test_updating_remote( if remote_name in expected_config["remotes"]: assert ( expected_config["remotes"][remote_name].fetch_url.replace( - "git+", "" + "git+", "", ) == current_remote_url ) diff --git a/tests/test_utils.py b/tests/test_utils.py index db308f66..9fd3f134 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -7,7 +7,7 @@ def test_vcspull_configdir_env_var( - tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch + tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, ) -> None: """Test retrieving config directory with VCSPULL_CONFIGDIR set.""" monkeypatch.setenv("VCSPULL_CONFIGDIR", str(tmp_path)) @@ -16,7 +16,7 @@ def test_vcspull_configdir_env_var( def test_vcspull_configdir_xdg_config_dir( - tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch + tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, ) -> None: """Test retrieving config directory with XDG_CONFIG_HOME set.""" monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path)) From 19c1fca0c4f6becae6ddee382f358eddf1746fb5 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:39:07 -0600 Subject: [PATCH 2/8] ruff format (after adding flake8-commas) --- conftest.py | 6 +++-- src/vcspull/config.py | 13 +++++++--- tests/test_config.py | 4 ++- tests/test_config_file.py | 53 ++++++++++++++++++++++++++++----------- tests/test_sync.py | 10 +++++--- tests/test_utils.py | 6 +++-- 6 files changed, 66 insertions(+), 26 deletions(-) diff --git a/conftest.py b/conftest.py index 972c38a4..b1d3939d 100644 --- a/conftest.py +++ b/conftest.py @@ -58,7 +58,8 @@ def xdg_config_path( @pytest.fixture(scope="function") def config_path( - xdg_config_path: pathlib.Path, request: pytest.FixtureRequest, + xdg_config_path: pathlib.Path, + request: pytest.FixtureRequest, ) -> pathlib.Path: """Ensure and return vcspull configuration path.""" conf_path = xdg_config_path / "vcspull" @@ -73,7 +74,8 @@ def clean() -> None: @pytest.fixture(autouse=True) def set_xdg_config_path( - monkeypatch: pytest.MonkeyPatch, xdg_config_path: pathlib.Path, + monkeypatch: pytest.MonkeyPatch, + xdg_config_path: pathlib.Path, ) -> None: """Set XDG_CONFIG_HOME environment variable.""" monkeypatch.setenv("XDG_CONFIG_HOME", str(xdg_config_path)) diff --git a/src/vcspull/config.py b/src/vcspull/config.py index ac69463b..34cd62a0 100644 --- a/src/vcspull/config.py +++ b/src/vcspull/config.py @@ -116,13 +116,16 @@ def extract_repos( continue if isinstance(url, str): conf["remotes"][remote_name] = GitRemote( - name=remote_name, fetch_url=url, push_url=url, + name=remote_name, + fetch_url=url, + push_url=url, ) elif isinstance(url, dict): assert "push_url" in url assert "fetch_url" in url conf["remotes"][remote_name] = GitRemote( - name=remote_name, **url, + name=remote_name, + **url, ) def is_valid_config_dict(val: t.Any) -> "TypeGuard[ConfigDict]": @@ -280,7 +283,8 @@ def load_configs( def detect_duplicate_repos( - config1: list["ConfigDict"], config2: list["ConfigDict"], + config1: list["ConfigDict"], + config2: list["ConfigDict"], ) -> list[ConfigDictTuple]: """Return duplicate repos dict if repo_dir same and vcs different. @@ -398,7 +402,8 @@ def filter_repos( def is_config_file( - filename: str, extensions: t.Optional[t.Union[list[str], str]] = None, + filename: str, + extensions: t.Optional[t.Union[list[str], str]] = None, ) -> bool: """Return True if file has a valid config file type. diff --git a/tests/test_config.py b/tests/test_config.py index 12b70258..537151b0 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -28,7 +28,9 @@ def load_yaml(tmp_path: pathlib.Path) -> LoadYAMLFn: """Return a yaml loading function that uses temporary directory path.""" def fn( - content: str, path: str = "randomdir", filename: str = "randomfilename.yaml", + content: str, + path: str = "randomdir", + filename: str = "randomfilename.yaml", ) -> tuple[pathlib.Path, list[pathlib.Path], list["ConfigDict"]]: """Return vcspull configurations and write out config to temp directory.""" _dir = tmp_path / path diff --git a/tests/test_config_file.py b/tests/test_config_file.py index 1106701a..7d5fed81 100644 --- a/tests/test_config_file.py +++ b/tests/test_config_file.py @@ -220,7 +220,9 @@ def test_in_dir( def test_find_config_path_string( - config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path, + config_path: pathlib.Path, + yaml_config: pathlib.Path, + json_config: pathlib.Path, ) -> None: """Tests find_config_files() returns configuration files found in directory.""" config_files = config.find_config_files(path=config_path) @@ -288,7 +290,8 @@ def test_find_config_match_list( assert json_config in config_files config_files = config.find_config_files( - path=[config_path], match=[yaml_config.stem], + path=[config_path], + match=[yaml_config.stem], ) assert yaml_config in config_files assert len([c for c in config_files if str(yaml_config) in str(c)]) == 1 @@ -297,52 +300,69 @@ def test_find_config_match_list( def test_find_config_filetype_string( - config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path, + config_path: pathlib.Path, + yaml_config: pathlib.Path, + json_config: pathlib.Path, ) -> None: """Tests find_config_files() filters files by filetype when param passed.""" config_files = config.find_config_files( - path=[config_path], match=yaml_config.stem, filetype="yaml", + path=[config_path], + match=yaml_config.stem, + filetype="yaml", ) assert yaml_config in config_files assert json_config not in config_files config_files = config.find_config_files( - path=[config_path], match=yaml_config.stem, filetype="json", + path=[config_path], + match=yaml_config.stem, + filetype="json", ) assert yaml_config not in config_files assert json_config not in config_files config_files = config.find_config_files( - path=[config_path], match="repos*", filetype="json", + path=[config_path], + match="repos*", + filetype="json", ) assert yaml_config not in config_files assert json_config in config_files config_files = config.find_config_files( - path=[config_path], match="repos*", filetype="*", + path=[config_path], + match="repos*", + filetype="*", ) assert yaml_config in config_files assert json_config in config_files def test_find_config_filetype_list( - config_path: pathlib.Path, yaml_config: pathlib.Path, json_config: pathlib.Path, + config_path: pathlib.Path, + yaml_config: pathlib.Path, + json_config: pathlib.Path, ) -> None: """Test find_config_files() accepts a list of file types, including wildcards.""" config_files = config.find_config_files( - path=[config_path], match=["repos*"], filetype=["*"], + path=[config_path], + match=["repos*"], + filetype=["*"], ) assert yaml_config in config_files assert json_config in config_files config_files = config.find_config_files( - path=[config_path], match=["repos*"], filetype=["json", "yaml"], + path=[config_path], + match=["repos*"], + filetype=["json", "yaml"], ) assert yaml_config in config_files assert json_config in config_files config_files = config.find_config_files( - path=[config_path], filetype=["json", "yaml"], + path=[config_path], + filetype=["json", "yaml"], ) assert yaml_config in config_files assert json_config in config_files @@ -358,7 +378,9 @@ def test_find_config_include_home_config_files( with EnvironmentVarGuard() as env: env.set("HOME", str(tmp_path)) config_files = config.find_config_files( - path=[config_path], match="*", include_home=True, + path=[config_path], + match="*", + include_home=True, ) assert yaml_config in config_files assert json_config in config_files @@ -366,7 +388,9 @@ def test_find_config_include_home_config_files( config_file3 = tmp_path / ".vcspull.json" config_file3.touch() results = config.find_config_files( - path=[config_path], match="*", include_home=True, + path=[config_path], + match="*", + include_home=True, ) expected_in = config_file3 assert expected_in in results @@ -403,7 +427,8 @@ def test_merge_nested_dict(tmp_path: pathlib.Path, config_path: pathlib.Path) -> # Duplicate path + name with different repo URL / remotes raises. config_files = config.find_config_files( - path=config_path, match="repoduplicate[1-2]", + path=config_path, + match="repoduplicate[1-2]", ) assert config1 in config_files assert config2 in config_files diff --git a/tests/test_sync.py b/tests/test_sync.py index bb0b0926..1016342d 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -59,7 +59,9 @@ def write_config_remote( return write_config( config_path=config_path, content=config_tpl.format( - tmp_path=str(tmp_path.parent), path=path, CLONE_NAME=clone_name, + tmp_path=str(tmp_path.parent), + path=path, + CLONE_NAME=clone_name, ), ) @@ -183,7 +185,8 @@ def test_config_variations( assert current_remote.fetch_url == repo_dict["remotes"][ remote_name ].fetch_url.replace( - "git+", "", + "git+", + "", ), "Final git remote should chop git+ prefix" else: assert ( @@ -297,7 +300,8 @@ def test_updating_remote( if remote_name in expected_config["remotes"]: assert ( expected_config["remotes"][remote_name].fetch_url.replace( - "git+", "", + "git+", + "", ) == current_remote_url ) diff --git a/tests/test_utils.py b/tests/test_utils.py index 9fd3f134..b3aeb92c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -7,7 +7,8 @@ def test_vcspull_configdir_env_var( - tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, + monkeypatch: pytest.MonkeyPatch, ) -> None: """Test retrieving config directory with VCSPULL_CONFIGDIR set.""" monkeypatch.setenv("VCSPULL_CONFIGDIR", str(tmp_path)) @@ -16,7 +17,8 @@ def test_vcspull_configdir_env_var( def test_vcspull_configdir_xdg_config_dir( - tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch, + tmp_path: pathlib.Path, + monkeypatch: pytest.MonkeyPatch, ) -> None: """Test retrieving config directory with XDG_CONFIG_HOME set.""" monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path)) From 7677b2f219059b21e40d027f9b87af182ca333c8 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:40:11 -0600 Subject: [PATCH 3/8] pyproject(ruff): Add flake8-commas, ignore COM812 for `ruff format` See also: - https://docs.astral.sh/ruff/rules/#flake8-commas-com - https://pypi.org/project/flake8-commas/ Ignoring COM812: - https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules - https://docs.astral.sh/ruff/rules/missing-trailing-comma/ --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 4b217e02..fdceac3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -152,6 +152,7 @@ select = [ "UP", # pyupgrade "B", # flake8-bugbear "C4", # flake8-comprehensions + "COM", # flake8-commas "Q", # flake8-quotes "PTH", # flake8-use-pathlib "SIM", # flake8-simplify @@ -160,6 +161,9 @@ select = [ "RUF", # Ruff-specific rules "D", # pydocstyle ] +ignore = [ + "COM812", # missing trailing comma, ruff format conflict +] [tool.ruff.lint.pydocstyle] convention = "numpy" From 28ca345137bdf20495cf129143b531a08b082dbb Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:40:31 -0600 Subject: [PATCH 4/8] pyproject(ruff): Add flake8-errmsg See also: - https://docs.astral.sh/ruff/rules/#flake8-errmsg-em - https://pypi.org/project/flake8-errmsg/ --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index fdceac3f..6b0285d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -153,6 +153,7 @@ select = [ "B", # flake8-bugbear "C4", # flake8-comprehensions "COM", # flake8-commas + "EM", # flake8-errmsg "Q", # flake8-quotes "PTH", # flake8-use-pathlib "SIM", # flake8-simplify From fe5c241d527af7a38cb35a97cc9f70655b56fd41 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:41:06 -0600 Subject: [PATCH 5/8] fix: direct `.format()` usage in exception messages src/vcspull/_internal/config_reader.py:49:39: EM102 [*] Exception must not use an f-string literal, assign to variable first src/vcspull/_internal/config_reader.py:112:39: EM102 [*] Exception must not use an f-string literal, assign to variable first src/vcspull/_internal/config_reader.py:187:39: EM102 [*] Exception must not use an f-string literal, assign to variable first Found 3 errors. --- src/vcspull/_internal/config_reader.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vcspull/_internal/config_reader.py b/src/vcspull/_internal/config_reader.py index 793ca436..06683339 100644 --- a/src/vcspull/_internal/config_reader.py +++ b/src/vcspull/_internal/config_reader.py @@ -46,7 +46,8 @@ def _load(format: "FormatLiteral", content: str) -> dict[str, t.Any]: elif format == "json": return t.cast(dict[str, t.Any], json.loads(content)) else: - raise NotImplementedError(f"{format} not supported in configuration") + msg = f"{format} not supported in configuration" + raise NotImplementedError(msg) @classmethod def load(cls, format: "FormatLiteral", content: str) -> "ConfigReader": @@ -109,7 +110,8 @@ def _from_file(cls, path: pathlib.Path) -> dict[str, t.Any]: elif path.suffix == ".json": format = "json" else: - raise NotImplementedError(f"{path.suffix} not supported in {path}") + msg = f"{path.suffix} not supported in {path}" + raise NotImplementedError(msg) return cls._load( format=format, @@ -184,7 +186,8 @@ def _dump( indent=2, ) else: - raise NotImplementedError(f"{format} not supported in config") + msg = f"{format} not supported in config" + raise NotImplementedError(msg) def dump(self, format: "FormatLiteral", indent: int = 2, **kwargs: t.Any) -> str: r"""Dump via ConfigReader instance. From f0f3f616201130486056503685b685c010270945 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:41:58 -0600 Subject: [PATCH 6/8] pyproject(ruff): flake8-builtins See also: - https://docs.astral.sh/ruff/rules/#flake8-builtins-a - https://pypi.org/project/flake8-builtins/ --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 6b0285d0..1c5ed71e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -150,6 +150,7 @@ select = [ "F", # pyflakes "I", # isort "UP", # pyupgrade + "A", # flake8-builtins "B", # flake8-bugbear "C4", # flake8-comprehensions "COM", # flake8-commas From 7b5c2bfc730b6dc6ee2444852c540fc9f52cec54 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:45:59 -0600 Subject: [PATCH 7/8] fix!: Fix shadowing of python builtins conftest.py:87:5: A001 Variable `dir` is shadowing a Python builtin docs/conf.py:56:1: A001 Variable `copyright` is shadowing a Python builtin src/vcspull/_internal/config_reader.py:29:15: A002 Argument `format` is shadowing a Python builtin src/vcspull/_internal/config_reader.py:53:19: A002 Argument `format` is shadowing a Python builtin src/vcspull/_internal/config_reader.py:109:13: A001 Variable `format` is shadowing a Python builtin src/vcspull/_internal/config_reader.py:111:13: A001 Variable `format` is shadowing a Python builtin src/vcspull/_internal/config_reader.py:163:9: A002 Argument `format` is shadowing a Python builtin src/vcspull/_internal/config_reader.py:192:20: A002 Argument `format` is shadowing a Python builtin tests/helpers.py:54:25: A002 Argument `format` is shadowing a Python builtin Found 9 errors. --- conftest.py | 8 +++---- docs/conf.py | 2 +- src/vcspull/_internal/config_reader.py | 30 +++++++++++++------------- tests/helpers.py | 4 ++-- tests/test_config_file.py | 8 +++---- tests/test_sync.py | 2 +- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/conftest.py b/conftest.py index b1d3939d..6378eceb 100644 --- a/conftest.py +++ b/conftest.py @@ -84,11 +84,11 @@ def set_xdg_config_path( @pytest.fixture(scope="function") def repos_path(user_path: pathlib.Path, request: pytest.FixtureRequest) -> pathlib.Path: """Return temporary directory for repository checkout guaranteed unique.""" - dir = user_path / "repos" - dir.mkdir(exist_ok=True) + path = user_path / "repos" + path.mkdir(exist_ok=True) def clean() -> None: - shutil.rmtree(dir) + shutil.rmtree(path) request.addfinalizer(clean) - return dir + return path diff --git a/docs/conf.py b/docs/conf.py index 6402a3e4..7f02236d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -53,7 +53,7 @@ master_doc = "index" project = about["__title__"] -copyright = about["__copyright__"] +project_copyright = about["__copyright__"] version = "%s" % (".".join(about["__version__"].split("."))[:2]) release = "%s" % (about["__version__"]) diff --git a/src/vcspull/_internal/config_reader.py b/src/vcspull/_internal/config_reader.py index 06683339..a203453d 100644 --- a/src/vcspull/_internal/config_reader.py +++ b/src/vcspull/_internal/config_reader.py @@ -26,7 +26,7 @@ def __init__(self, content: "RawConfigData") -> None: self.content = content @staticmethod - def _load(format: "FormatLiteral", content: str) -> dict[str, t.Any]: + def _load(fmt: "FormatLiteral", content: str) -> dict[str, t.Any]: """Load raw config data and directly return it. >>> ConfigReader._load("json", '{ "session_name": "my session" }') @@ -35,7 +35,7 @@ def _load(format: "FormatLiteral", content: str) -> dict[str, t.Any]: >>> ConfigReader._load("yaml", 'session_name: my session') {'session_name': 'my session'} """ - if format == "yaml": + if fmt == "yaml": return t.cast( dict[str, t.Any], yaml.load( @@ -43,14 +43,14 @@ def _load(format: "FormatLiteral", content: str) -> dict[str, t.Any]: Loader=yaml.SafeLoader, ), ) - elif format == "json": + elif fmt == "json": return t.cast(dict[str, t.Any], json.loads(content)) else: - msg = f"{format} not supported in configuration" + msg = f"{fmt} not supported in configuration" raise NotImplementedError(msg) @classmethod - def load(cls, format: "FormatLiteral", content: str) -> "ConfigReader": + def load(cls, fmt: "FormatLiteral", content: str) -> "ConfigReader": """Load raw config data into a ConfigReader instance (to dump later). >>> cfg = ConfigReader.load("json", '{ "session_name": "my session" }') @@ -67,7 +67,7 @@ def load(cls, format: "FormatLiteral", content: str) -> "ConfigReader": """ return cls( content=cls._load( - format=format, + fmt=fmt, content=content, ), ) @@ -106,15 +106,15 @@ def _from_file(cls, path: pathlib.Path) -> dict[str, t.Any]: content = path.open().read() if path.suffix in [".yaml", ".yml"]: - format: "FormatLiteral" = "yaml" + fmt: "FormatLiteral" = "yaml" elif path.suffix == ".json": - format = "json" + fmt = "json" else: msg = f"{path.suffix} not supported in {path}" raise NotImplementedError(msg) return cls._load( - format=format, + fmt=fmt, content=content, ) @@ -160,7 +160,7 @@ def from_file(cls, path: pathlib.Path) -> "ConfigReader": @staticmethod def _dump( - format: "FormatLiteral", + fmt: "FormatLiteral", content: "RawConfigData", indent: int = 2, **kwargs: t.Any, @@ -173,23 +173,23 @@ def _dump( >>> ConfigReader._dump("json", { "session_name": "my session" }) '{\n "session_name": "my session"\n}' """ - if format == "yaml": + if fmt == "yaml": return yaml.dump( content, indent=2, default_flow_style=False, Dumper=yaml.SafeDumper, ) - elif format == "json": + elif fmt == "json": return json.dumps( content, indent=2, ) else: - msg = f"{format} not supported in config" + msg = f"{fmt} not supported in config" raise NotImplementedError(msg) - def dump(self, format: "FormatLiteral", indent: int = 2, **kwargs: t.Any) -> str: + def dump(self, fmt: "FormatLiteral", indent: int = 2, **kwargs: t.Any) -> str: r"""Dump via ConfigReader instance. >>> cfg = ConfigReader({ "session_name": "my session" }) @@ -199,7 +199,7 @@ def dump(self, format: "FormatLiteral", indent: int = 2, **kwargs: t.Any) -> str '{\n "session_name": "my session"\n}' """ return self._dump( - format=format, + fmt=fmt, content=self.content, indent=indent, **kwargs, diff --git a/tests/helpers.py b/tests/helpers.py index e900dcc9..424fa15f 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -51,6 +51,6 @@ def write_config(config_path: pathlib.Path, content: str) -> pathlib.Path: return config_path -def load_raw(data: str, format: t.Literal["yaml", "json"]) -> dict[str, t.Any]: +def load_raw(data: str, fmt: t.Literal["yaml", "json"]) -> dict[str, t.Any]: """Load configuration data via string value. Accepts yaml or json.""" - return ConfigReader._load(format=format, content=data) + return ConfigReader._load(fmt=fmt, content=data) diff --git a/tests/test_config_file.py b/tests/test_config_file.py index 7d5fed81..0ba9571d 100644 --- a/tests/test_config_file.py +++ b/tests/test_config_file.py @@ -31,9 +31,9 @@ def json_config(config_path: pathlib.Path) -> pathlib.Path: def test_dict_equals_yaml() -> None: - """Verify that example YAML is returning expected dict format.""" + """Verify that example YAML is returning expected dict fmt.""" config = ConfigReader._load( - format="yaml", + fmt="yaml", content="""\ /home/me/myproject/study/: linux: git+git://git.kernel.org/linux/torvalds/linux.git @@ -142,7 +142,7 @@ def test_expandenv_and_homevars() -> None: .tmux: url: git+file://{git_repo_path} """, - format="yaml", + fmt="yaml", ) config2 = load_raw( """\ @@ -162,7 +162,7 @@ def test_expandenv_and_homevars() -> None: } } """, - format="json", + fmt="json", ) assert is_valid_config(config1) diff --git a/tests/test_sync.py b/tests/test_sync.py index 1016342d..1d2e2061 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -25,7 +25,7 @@ def test_makes_recursive( ) -> None: """Ensure that syncing creates directories recursively.""" conf = ConfigReader._load( - format="yaml", + fmt="yaml", content=textwrap.dedent( f""" {tmp_path}/study/myrepo: From 6f328a7d349f1972b009a9f3d2d8a3311d65fb6f Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Wed, 7 Feb 2024 05:47:39 -0600 Subject: [PATCH 8/8] docs(CHANGES): Note linting improvements --- CHANGES | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGES b/CHANGES index c1612f41..be09e7a5 100644 --- a/CHANGES +++ b/CHANGES @@ -31,6 +31,25 @@ $ pipx install --suffix=@next 'vcspull' --pip-args '\--pre' --force - `dir` -> `path` (#435) +### Development + +- Strengthen linting (#436) + + - Add flake8-commas (COM) + + - https://docs.astral.sh/ruff/rules/#flake8-commas-com + - https://pypi.org/project/flake8-commas/ + + - Add flake8-builtins (A) + + - https://docs.astral.sh/ruff/rules/#flake8-builtins-a + - https://pypi.org/project/flake8-builtins/ + + - Add flake8-errmsg (EM) + + - https://docs.astral.sh/ruff/rules/#flake8-errmsg-em + - https://pypi.org/project/flake8-errmsg/ + ### Documentation - Refactor API docs to split across multiple pages (#431)