def test_add_requirement( tmp_pathplus: PathPlus, requirement: str, cassette, advanced_file_regression: AdvancedFileRegressionFixture): (tmp_pathplus / "repo_helper.yml").touch() (tmp_pathplus / "requirements.txt").touch() (tmp_pathplus / "tests").mkdir() (tmp_pathplus / "tests" / "requirements.txt").touch() result: Result with in_directory(tmp_pathplus): runner = CliRunner() result = runner.invoke(add.requirement, args=requirement) assert result.exit_code == 0 advanced_file_regression.check_file(tmp_pathplus / "requirements.txt") with in_directory(tmp_pathplus): runner = CliRunner() result = runner.invoke( add.requirement, args=[requirement, "--file", "tests/requirements.txt"]) assert result.exit_code == 0 advanced_file_regression.check_file(tmp_pathplus / "tests" / "requirements.txt")
def test_cli_verbose_verbose( tmp_pathplus: PathPlus, advanced_file_regression: AdvancedFileRegressionFixture, advanced_data_regression: AdvancedDataRegressionFixture, demo_environment, ): result: Result with in_directory(tmp_pathplus): runner = CliRunner(mix_stderr=False) result = runner.invoke( main, args=["code.py", "--no-colour", "--diff", "--verbose", "-v"], ) assert result.exit_code == 1 advanced_file_regression.check_file(tmp_pathplus / "code.py") # Calling a second time shouldn't change anything with in_directory(tmp_pathplus): runner = CliRunner(mix_stderr=False) result = runner.invoke( main, args=[ "code.py", "code.c", "--no-colour", "--diff", "--verbose", "-v" ], ) assert result.exit_code == 0 check_out(result, advanced_data_regression)
def test_reformat( tmp_pathplus: PathPlus, toml_string: str, cli_runner: CliRunner, advanced_file_regression: AdvancedFileRegressionFixture, show_diff: bool, ): (tmp_pathplus / "pyproject.toml").write_clean(toml_string) (tmp_pathplus / "README.rst").write_clean("This is the README") (tmp_pathplus / "LICENSE").write_clean("This is the LICENSE") if show_diff: args = ["--no-colour", "--show-diff"] else: args = [] with in_directory(tmp_pathplus): result: Result = cli_runner.invoke(reformat, args=args, catch_exceptions=False) assert result.exit_code == 1 advanced_file_regression.check_file(tmp_pathplus / "pyproject.toml") result.check_stdout(advanced_file_regression, extension=".diff") # Should be no changes with in_directory(tmp_pathplus): result = cli_runner.invoke(reformat, args=args, catch_exceptions=False) assert result.exit_code == 0 advanced_file_regression.check_file(tmp_pathplus / "pyproject.toml") assert result.stdout == "Reformatting 'pyproject.toml'\n"
def test_requirements_concise( self, tmp_repo, advanced_file_regression: AdvancedFileRegressionFixture, py_version, fixed_version_number, ): for directory in show_directories: with in_directory(directory): runner = CliRunner() result: Result = runner.invoke(show.requirements, catch_exceptions=False, args=["--concise", "--no-venv"]) assert result.exit_code == 0 result.check_stdout(advanced_file_regression, extension=".tree") with in_directory(directory): runner = CliRunner() result = runner.invoke(show.requirements, catch_exceptions=False, args=["-c", "--no-venv"]) assert result.exit_code == 0 result.check_stdout(advanced_file_regression, extension=".tree")
def test_release_unclean( temp_repo, advanced_file_regression: AdvancedFileRegressionFixture): (temp_repo.path / "file.txt").write_clean("Hello World") temp_repo.stage("file.txt") result: Result for command in (major, minor, patch): with in_directory(temp_repo.path): runner = CliRunner(mix_stderr=False) result = runner.invoke(command, catch_exceptions=False) assert result.exit_code == 1 assert result.stderr.splitlines() == [ "Git working directory is not clean:", " A file.txt", "Aborted!", ] assert not result.stdout with in_directory(temp_repo.path): runner = CliRunner(mix_stderr=False) result = runner.invoke(release, catch_exceptions=False, args=["1.2.3"]) assert result.exit_code == 1 assert result.stderr.splitlines() == [ "Git working directory is not clean:", " A file.txt", "Aborted!", ] assert not result.stdout
def test_get_repo_or_raise(temp_repo): with tempfile.TemporaryDirectory() as tmpdir: with in_directory(tmpdir): with pytest.raises( click.UsageError, match=r"The current directory is not a git repository\."): get_repo_or_raise() with in_directory(temp_repo): assert isinstance(get_repo_or_raise(), Repo)
def test_in_directory(tmp_pathplus: PathPlus): cwd = os.getcwd() with in_directory(tmp_pathplus): assert str(os.getcwd()) == str(tmp_pathplus) assert os.getcwd() == cwd tmpdir = tmp_pathplus / "tmp" tmpdir.maybe_make() with in_directory(tmpdir): assert str(os.getcwd()) == str(tmpdir) assert os.getcwd() == cwd
def test_list_remotes(temp_repo, file_regression: FileRegressionFixture): with in_directory(temp_repo): runner = CliRunner() result: Result = runner.invoke(main, args="--list") assert result.exit_code == 0 check_file_regression(result.stdout, file_regression)
def test_cli_syntax_error_py310( tmp_pathplus: PathPlus, advanced_file_regression: AdvancedFileRegressionFixture, advanced_data_regression: AdvancedDataRegressionFixture, demo_environment, ): code = [ "class F:", "\tfrom collections import (", "Iterable,", "\tCounter,", "\t\t)", '', "\tdef foo(self):", "\t\tpass", '', "print('hello world'", ] (tmp_pathplus / "code.py").write_lines(code, trailing_whitespace=True) with in_directory(tmp_pathplus): runner = CliRunner(mix_stderr=False) result: Result = runner.invoke( main, args=["code.py", "--no-colour", "--verbose"]) assert result.exit_code == 126 check_out(result, advanced_data_regression)
def test_via_Repo_class( temp_repo, capsys, file_regression: FileRegressionFixture, data_regression: DataRegressionFixture, monkeypatch, example_config, ): with in_directory(temp_repo.path): (temp_repo.path / "repo_helper.yml").write_text(example_config) (temp_repo.path / "requirements.txt").touch() (temp_repo.path / "tests").maybe_make() (temp_repo.path / "tests" / "requirements.txt").touch() (temp_repo.path / "README.rst").touch() (temp_repo.path / "doc-source").mkdir() (temp_repo.path / "doc-source" / "index.rst").touch() (temp_repo.path / ".pre-commit-config.yaml").touch() rh = RepoHelper(temp_repo.path) rh.load_settings() managed_files = rh.run() data_regression.check(sorted(managed_files)) assert capsys.readouterr().out == '' assert capsys.readouterr().err == ''
def cloned_repos(): with TemporaryPathPlus() as tmp_pathplus: repo = Repo.clone_from( "https://github.com/domdfcoding/domdf_python_tools", tmp_pathplus / "domdf_python_tools", ) repo.git.checkout("63648712285eeaac6c26708e817c8c02595e165e") with in_directory(tmp_pathplus / "domdf_python_tools"): process = Popen(["tox", "-e", "build"], stdout=PIPE, stderr=PIPE) (output_, err) = process.communicate() exit_code = process.wait() repo = Repo.clone_from( "https://github.com/sphinx-toolbox/sphinx-toolbox", tmp_pathplus / "sphinx-toolbox") repo.git.checkout("fb7841d1d53e6bc9fe5be3ef92391ec78ff77365") repo = Repo.clone_from( "https://github.com/repo-helper/repo_helper_github", tmp_pathplus / "repo_helper_github", ) repo.git.checkout("db0e713882b7d8191e00ce6ed4eeaec47de2773f") yield tmp_pathplus
def test_mkrecipe_bad_type( tmp_pathplus, pyproject_file, advanced_file_regression: AdvancedFileRegressionFixture, click_ver, ): (tmp_pathplus / "pyproject.toml").write_text( (configs_dir / pyproject_file).read_text()) (tmp_pathplus / "requirements.txt").write_lines([ "click>=7.1.2", 'colorama>=0.4.3; python_version < "3.10"', "deprecation-alias>=0.1.1", "domdf-python-tools>=2.5.1", "mistletoe>=0.7.2", "typing-extensions>=3.7.4.3", ]) with in_directory(tmp_pathplus): runner = CliRunner() result: Result = runner.invoke(main, args=["--type", "egg"], catch_exceptions=False) assert result.exit_code == 2 result.check_stdout(advanced_file_regression)
def test_suggest_classifiers_add_existing(tmp_pathplus, advanced_file_regression: AdvancedFileRegressionFixture): (tmp_pathplus / "repo_helper.yml").write_lines([ "modname: repo_helper", 'copyright_years: "2020"', 'author: "Dominic Davis-Foster"', 'email: "*****@*****.**"', 'version: "0.0.1"', 'username: "******"', "license: 'LGPLv3+'", "short_desc: 'Update multiple configuration files, build scripts etc. from a single location.'", '', "classifiers:", " - 'Framework :: Flake8'", " - 'Intended Audience :: Developers'", ]) (tmp_pathplus / "requirements.txt").touch() (tmp_pathplus / "repo_helper").mkdir() with in_directory(tmp_pathplus): runner = CliRunner() result: Result = runner.invoke( suggest.classifiers, catch_exceptions=False, args=["-s", '4', "-l", "--add"] ) assert result.exit_code == 0 advanced_file_regression.check_file(tmp_pathplus / "repo_helper.yml")
def test_toggle(temp_repo): toggler = Toggler(temp_repo) with in_directory(temp_repo): runner = CliRunner() result: Result = runner.invoke(main) assert result.exit_code == 0 assert toggler.get_current_remote( ) == "https://github.com/domdfcoding/git-toggle.git" assert toggler.get_current_remote( "upstream") == "[email protected]:repo-helper/git-toggler.git" result = runner.invoke(main, args="ssh") assert result.exit_code == 0 assert toggler.get_current_remote( ) == "[email protected]:domdfcoding/git-toggle.git" assert toggler.get_current_remote( "upstream") == "[email protected]:repo-helper/git-toggler.git" result = runner.invoke(main, args="http") assert result.exit_code == 0 assert toggler.get_current_remote( ) == "https://github.com/domdfcoding/git-toggle.git" assert toggler.get_current_remote( "upstream") == "[email protected]:repo-helper/git-toggler.git" result = runner.invoke(main, args=["https", "--name", "upstream"]) assert result.exit_code == 0 assert toggler.get_current_remote( ) == "https://github.com/domdfcoding/git-toggle.git" assert toggler.get_current_remote( "upstream") == "https://github.com/repo-helper/git-toggler.git"
def test_iterchildren_match( advanced_data_regression: AdvancedDataRegressionFixture, absolute: bool): repo_path = PathPlus(__file__).parent.parent with in_directory(repo_path.parent): assert repo_path.is_dir() if not absolute: repo_path = repo_path.relative_to(repo_path.parent) if (repo_path / "build").is_dir(): shutil.rmtree(repo_path / "build") children = list(repo_path.iterchildren(match="**/*.py")) assert children child_paths = sorted( p.relative_to(repo_path).as_posix() for p in children) for exclude_filename in { ".coverage", "pathtype_demo.py", "dist", "htmlcov", "conda", ".idea", "mutdef.py" }: if exclude_filename in child_paths: child_paths.remove(exclude_filename) advanced_data_regression.check(child_paths, basename="test_iterchildren_match")
def test_conda_recipe_specifiers( tmp_pathplus, file_regression: FileRegressionFixture, example_config, ): config = example_config.replace("repo_helper_demo", "repo_helper").replace("0.0.1", "2021.3.8") (tmp_pathplus / "repo_helper.yml").write_text(config) (tmp_pathplus / "requirements.txt").write_lines([ 'apeye>=0.3.0; python_version < "3.10"', "attrs[extra]>=20.2.0", ]) with in_directory(tmp_pathplus): runner = CliRunner() result: Result = runner.invoke(make_recipe, catch_exceptions=False) assert result.exit_code == 0 if os.sep == '/': assert re.match(r"Wrote recipe to .*/conda/meta\.yaml", result.stdout) elif os.sep == '\\': assert re.match(r"Wrote recipe to .*(\\)?conda\\meta\.yaml", result.stdout.splitlines()[0]) else: raise NotImplementedError(os.sep) check_file_output(tmp_pathplus / "conda/meta.yaml", file_regression)
def test_buildsystem_parser_errors(config: str, expects: Type[Exception], match: str, tmp_pathplus: PathPlus): (tmp_pathplus / "pyproject.toml").write_clean(config) with in_directory(tmp_pathplus), pytest.raises(expects, match=match): BuildSystemParser().parse( dom_toml.load(tmp_pathplus / "pyproject.toml")["build-system"])
def check_file(self, filename: str, mode: black.Mode, kwargs: dict, *, data: bool = True) -> None: source, expected = read_data(filename, data=data) result: Result with TemporaryPathPlus() as tmp_pathplus: (tmp_pathplus / filename).write_text(source) toml_data = dom_toml.load( PathPlus(__file__).parent / "example_formate.toml") toml_data["hooks"]["black"]["kwargs"] = kwargs dom_toml.dump(toml_data, tmp_pathplus / "formate.toml") with in_directory(tmp_pathplus): runner = CliRunner(mix_stderr=False) result = runner.invoke( main, args=[ filename, "--no-colour", "--diff", "--verbose", "-v" ], ) # TODO: check stdout actual = (tmp_pathplus / filename).read_text() self.assertFormatEqual(expected, actual) if source != actual: black.assert_equivalent(source, actual) black.assert_stable(source, actual, mode)
def test_devenv_verbose(temp_repo: Repo, extra_args, tests): lib_requirements = [ "click", "flask", "werkzeug", "consolekit", "requests", "apeye", ] test_requirements = [ "pytest", "hypothesis", ] repo_path = PathPlus(temp_repo.path) (repo_path / "requirements.txt").write_lines(lib_requirements) if tests: (repo_path / "tests").mkdir() (repo_path / "tests/requirements.txt").write_lines(test_requirements) else: with (repo_path / "repo_helper.yml").open('a') as fp: fp.write("enable_tests: false") with in_directory(temp_repo.path): runner = CliRunner() result: Result = runner.invoke(devenv, args=extra_args) assert result.exit_code == 0 assert "Installing project requirements" in result.stdout assert "Successfully created development virtualenv." in result.stdout if tests: assert "Installing test requirements" in result.stdout
def test_devenv(temp_repo: Repo): lib_requirements = [ "click", "flask", "werkzeug", "consolekit", "requests", "apeye", ] test_requirements = [ "pytest", "hypothesis", ] repo_path = PathPlus(temp_repo.path) (repo_path / "requirements.txt").write_lines(lib_requirements) (repo_path / "tests").mkdir() (repo_path / "tests/requirements.txt").write_lines(test_requirements) with in_directory(temp_repo.path): runner = CliRunner() result: Result = runner.invoke(devenv) assert result.exit_code == 0 assert result.stdout == 'Successfully created development virtualenv.\n' # Check list of packages in virtualenv venv_dir = repo_path / "venv" if sys.platform == "win32": version_dirs = [(venv_dir / "Lib")] elif PYPY: version_dirs = [venv_dir] else: version_dirs = list((venv_dir / "lib").glob("py*")) for version_dir in version_dirs: for package in lib_requirements: assert (version_dir / "site-packages" / package).is_dir() for package in test_requirements: assert (version_dir / "site-packages" / package).is_dir() assert len(version_dirs) == 1 pyvenv_config: Dict[str, str] = read_pyvenv(venv_dir) assert "prompt" in pyvenv_config assert pyvenv_config["prompt"] == "(repo_helper_demo) " assert "repo_helper_devenv" in pyvenv_config assert pyvenv_config["repo_helper_devenv"] == __version__ assert "virtualenv" in pyvenv_config assert "include-system-site-packages" in pyvenv_config assert not strtobool(pyvenv_config["include-system-site-packages"])
def test_bad_config_cli(tmp_pathplus: PathPlus, config: Dict, match: str): dom_toml.dump({"project": config}, tmp_pathplus / "pyproject.toml") with in_directory(tmp_pathplus): runner = CliRunner() result: Result = runner.invoke(main) assert result.exit_code == 1 assert match in result.stdout
def test_version(tmp_pathplus): with in_directory(tmp_pathplus): runner = CliRunner() result: Result = runner.invoke(devenv, args=["--version"]) assert result.exit_code == 0 assert result.stdout == f"repo_helper_devenv version {__version__}\n"
def test_toggle_errors(temp_repo): with in_directory(temp_repo): runner = CliRunner() result: Result = runner.invoke(main, args="ftp") assert result.exit_code == 2 error = "Error: Invalid value for '[[http|https|ssh]]': invalid choice: ftp. (choose from http, https, ssh, )" assert result.stdout.splitlines()[-1] == error
def load_toml(filename: PathLike) -> Dict[str, Any]: # TODO: TypedDict """ Load the ``mkrecipe`` configuration mapping from the given TOML file. :param filename: """ filename = PathPlus(filename) project_dir = filename.parent config = dom_toml.load(filename) parsed_config: Dict[str, Any] = {} tool_table = config.get("tool", {}) with in_directory(filename.parent): parsed_config.update(BuildSystemParser().parse(config.get( "build-system", {}), set_defaults=True)) parsed_config.update(whey.config.WheyParser().parse( tool_table.get("whey", {}))) parsed_config.update(MkrecipeParser().parse(tool_table.get( "mkrecipe", {}), set_defaults=True)) if "project" in config: parsed_config.update(PEP621Parser().parse(config["project"], set_defaults=True)) else: raise KeyError(f"'project' table not found in '{filename!s}'") # set defaults parsed_config.setdefault("package", config["project"]["name"].split('.', 1)[0]) parsed_config.setdefault("license-key", None) if "dependencies" in parsed_config.get("dynamic", []): if (project_dir / "requirements.txt").is_file(): dependencies = read_requirements(project_dir / "requirements.txt", include_invalid=True)[0] parsed_config["dependencies"] = sorted( combine_requirements(dependencies)) else: raise BadConfigError( "'project.dependencies' was listed as a dynamic field " "but no 'requirements.txt' file was found.") parsed_config["version"] = str(parsed_config["version"]) parsed_config["requires"] = sorted( set( combine_requirements( parsed_config["requires"], ComparableRequirement("setuptools"), ComparableRequirement("wheel"), ))) return parsed_config
def test_create_repo(github_manager, temp_github_repo): with in_directory(temp_github_repo): github_manager.new() github_manager.github.repository("domdfcoding", "repo_helper_demo") with pytest.raises(UnprocessableEntity, match="422 Repository creation failed."): github_manager.new()
def test_cli_version(tmp_pathplus: PathPlus) -> None: with in_directory(tmp_pathplus): runner = CliRunner(mix_stderr=False) result: Result = runner.invoke(main, args=["--version"]) assert not result.stderr assert fix_stdout(result.stdout) == "importcheck version 0.0.0" assert result.exit_code == 0
def test_bad_config_cli_traceback(tmp_pathplus: PathPlus, config: Dict, match: str): dom_toml.dump({"project": config}, tmp_pathplus / "pyproject.toml") with in_directory(tmp_pathplus): runner = CliRunner() with pytest.raises(BadConfigError, match=match): runner.invoke(main, args=["-T"])
def test_version(tmp_pathplus, advanced_file_regression: AdvancedFileRegressionFixture): with in_directory(tmp_pathplus): runner = CliRunner() result: Result = runner.invoke(main, args=["--version"]) assert result.exit_code == 0 assert result.stdout == f"pyproject-devenv version {__version__}\n"
def test_list_remotes_no_remotes(tmp_pathplus): Repo.init(tmp_pathplus) with in_directory(tmp_pathplus): runner = CliRunner() result: Result = runner.invoke(main, args="--list") assert result.exit_code == 1 assert result.stdout == "No remotes set!\nAborted!\n"
def test_update(github_manager, temp_github_repo): with in_directory(temp_github_repo): github_manager.update() repo = github_manager.github.repository("domdfcoding", "repo_helper_demo") assert set(repo.topics().names) == { "python", "repo-helper", "github", "configuration" } assert repo.description == "Update multiple configuration files, build scripts etc. from a single location."