Пример #1
0
	def testenv_coverage(self):
		"""
		``[testenv:coverage]``.
		"""

		if self["enable_tests"]:
			self._ini["testenv:coverage"]["basepython"] = f"python{self['min_py_version']}"
			self._ini["testenv:coverage"]["skip_install"] = True
			self._ini["testenv:coverage"]["ignore_errors"] = True
			self._ini["testenv:coverage"]["whitelist_externals"] = "/bin/bash"
			self._ini["testenv:coverage"]["passenv"] = indent_join([
					"COV_PYTHON_VERSION",
					"COV_PLATFORM",
					"COV_PYTHON_IMPLEMENTATION",
					])
			self._ini["testenv:coverage"]["changedir"] = "{toxinidir}"

			coverage_deps = ["coverage>=5"]
			if self["pypi_name"] != "coverage_pyver_pragma":
				coverage_deps.append("coverage_pyver_pragma>=0.2.1")

			self._ini["testenv:coverage"]["deps"] = indent_join(coverage_deps)

			self._ini["testenv:coverage"]["commands"] = indent_join([
					'/bin/bash -c "rm -rf htmlcov"',
					"coverage html",
					"/bin/bash -c \"DISPLAY=:0 firefox 'htmlcov/index.html'\"",
					])
		else:
			self._ini.remove_section("testenv:coverage")
Пример #2
0
	def testenv_docs(self):
		"""
		``[testenv:docs]``.
		"""

		if self["enable_docs"]:
			envvars = ["SHOW_TODOS = 1"]
			self._ini["testenv:docs"]["setenv"] = indent_join(envvars)

			self._ini["testenv:docs"]["basepython"] = "python3.8"
			self._ini["testenv:docs"]["pip_version"] = "pip>=21"
			self._ini["testenv:docs"]["changedir"] = f"{{toxinidir}}/{self['docs_dir']}"

			if self["tox_testenv_extras"]:
				self._ini["testenv:docs"]["extras"] = self["tox_testenv_extras"]

			self._ini["testenv:docs"]["deps"] = f"-r{{toxinidir}}/{self['docs_dir']}/requirements.txt"

			# self._ini["testenv:docs"]["deps"] = indent_join([
			# 		"-r{toxinidir}/requirements.txt",
			# 		f"-r{{toxinidir}}/{self['docs_dir']}/requirements.txt",
			# 		], )

			self._ini["testenv:docs"]["commands"] = "sphinx-build -M {env:SPHINX_BUILDER:html} . ./build {posargs}"

		else:
			self._ini.remove_section("testenv:docs")
Пример #3
0
    def options_packages_find(self):
        """
		``[options.packages.find]``.
		"""

        excludes = [
            self["tests_dir"], f"{self['tests_dir']}.*", self["docs_dir"]
        ]
        self._ini["options.packages.find"]["exclude"] = indent_join(
            sorted(set(excludes)))
Пример #4
0
	def testenv_mypy(self):
		"""
		``[testenv:mypy]``.
		"""

		self._ini["testenv:mypy"]["basepython"] = "python{python_deploy_version}".format(**self._globals)
		self._ini["testenv:mypy"]["ignore_errors"] = True
		self._ini["testenv:mypy"]["changedir"] = "{toxinidir}"

		if self._globals["tox_testenv_extras"]:
			self._ini["testenv:mypy"]["extras"] = self._globals["tox_testenv_extras"]

		self._ini["testenv:mypy"]["deps"] = indent_join(self.get_mypy_dependencies())

		commands = self.get_mypy_commands()

		if commands:
			self._ini["testenv:mypy"]["commands"] = indent_join(commands)
		else:
			self._ini.remove_section("testenv:mypy")
Пример #5
0
	def testenv_build(self):
		"""
		``[testenv:build]``.
		"""

		self._ini["testenv:build"]["skip_install"] = True
		self._ini["testenv:build"]["changedir"] = "{toxinidir}"
		self._ini["testenv:build"]["deps"] = indent_join([
				"build[virtualenv]>=0.3.1",
				"check-wheel-contents>=0.1.0",
				"twine>=3.2.0",
				*self["tox_build_requirements"],
				])
		self._ini["testenv:build"]["commands"] = indent_join([
				'python -m build --sdist --wheel "{toxinidir}"',
				# python setup.py {posargs} sdist bdist_wheel
				# "twine check dist/*",
				"twine check dist/*.tar.gz dist/*.whl",  # source
				"check-wheel-contents dist/",
				])
Пример #6
0
	def flake8(self):
		"""
		``[flake8]``.
		"""

		test_ignores = list(code_only_warning)
		test_ignores.remove("E301")
		test_ignores.remove("E302")
		test_ignores.remove("E305")

		self._ini["flake8"]["max-line-length"] = "120"
		self._ini["flake8"]["select"] = f"{DelimitedList(lint_warn_list + code_only_warning): }"
		self._ini["flake8"]["extend-exclude"] = ','.join([self["docs_dir"], *standard_flake8_excludes])
		self._ini["flake8"]["rst-directives"] = indent_join(sorted(allowed_rst_directives))
		self._ini["flake8"]["rst-roles"] = indent_join(sorted(allowed_rst_roles))
		self._ini["flake8"]["per-file-ignores"] = indent_join([
				'',
				f"{self['tests_dir']}/*: {' '.join(str(e) for e in test_ignores)}",
				f"*/*.pyi: {' '.join(str(e) for e in code_only_warning)}",
				])
		self._ini["flake8"]["pytest-parametrize-names-type"] = "csv"
		self._ini["flake8"]["inline-quotes"] = '"'
		self._ini["flake8"]["multiline-quotes"] = '"""'
		self._ini["flake8"]["docstring-quotes"] = '"""'
		self._ini["flake8"]["count"] = True

		if self["requires_python"] is None:
			if self["min_py_version"] in {"3.6", 3.6}:
				requires_python = "3.6.1"
			else:
				requires_python = self["min_py_version"]
		else:
			requires_python = self["requires_python"]

		self._ini["flake8"]["min_python_version"] = requires_python
		self._ini["flake8"]["unused-arguments-ignore-abstract-functions"] = True
		self._ini["flake8"]["unused-arguments-ignore-overload-functions"] = True
		self._ini["flake8"]["unused-arguments-ignore-magic-methods"] = True
		self._ini["flake8"]["unused-arguments-ignore-variadic-names"] = True
Пример #7
0
	def coverage_report(self):
		"""
		``[coverage:report]``.
		"""

		self._ini["coverage:report"]["fail_under"] = self["min_coverage"]
		self._ini["coverage:report"]["exclude_lines"] = indent_join([
				"raise AssertionError",
				"raise NotImplementedError",
				"if 0:",
				"if False:",
				"if TYPE_CHECKING:",
				"if typing.TYPE_CHECKING:",
				"if __name__ == .__main__.:",
				])
Пример #8
0
    def merge_existing(self, ini_file):

        if ini_file.is_file():
            existing_config = ConfigUpdater()
            existing_config.read(str(ini_file))

            for section in existing_config.sections_blocks():
                if section.name == "options.packages.find" and "exclude" in section:

                    all_excludes = (
                        *section["exclude"].value.splitlines(),
                        *self._ini["options.packages.find"]
                        ["exclude"].value.splitlines(),
                    )

                    exclude_packages = sorted(
                        filter(bool, set(map(str.strip, all_excludes))))
                    self._ini["options.packages.find"][
                        "exclude"] = indent_join(exclude_packages)

                if section.name not in self.managed_sections:
                    self._ini.add_section(section)
                elif section.name == "mypy":
                    self.copy_existing_value(section, "incremental")

        if "options.entry_points" not in self._ini.sections():
            self._ini.add_section("options.entry_points")

        # if self["console_scripts"]:
        # 	self._ini["options.entry_points"]["console_scripts"] = self["console_scripts"]
        # else:
        if not self._ini["options.entry_points"].options():
            self._ini.remove_section("options.entry_points")

        if self["use_whey"]:
            self._ini.remove_section("metadata")
            self._ini.remove_section("options")
            self._ini.remove_section("options.packages.find")

        if float(self["mypy_version"]) >= 0.901:
            self._ini.remove_section("mypy")
Пример #9
0
	def testenv_lint(self):
		"""
		``[testenv:lint]``.
		"""

		self._ini["testenv:lint"]["basepython"] = "python{python_deploy_version}".format(**self._globals)
		self._ini["testenv:lint"]["changedir"] = "{toxinidir}"
		self._ini["testenv:lint"]["ignore_errors"] = True

		if self["pypi_name"] in {"domdf_python_tools", "consolekit"}:
			self._ini["testenv:lint"]["skip_install"] = False
		elif self["pypi_name"].startswith("flake8"):
			self._ini["testenv:lint"]["skip_install"] = False
		else:
			self._ini["testenv:lint"]["skip_install"] = True

		self._ini["testenv:lint"]["deps"] = indent_join([
				"flake8>=3.8.2",
				"flake8-2020>=1.6.0",
				"flake8-builtins>=1.5.3",
				"flake8-docstrings>=1.5.0",
				"flake8-dunder-all>=0.1.1",
				"flake8-encodings>=0.1.0",
				"flake8-github-actions>=0.1.0",
				"flake8-noqa>=1.1.0",
				"flake8-pyi>=20.10.0",
				"flake8-pytest-style>=1.3.0",
				"flake8-quotes>=3.3.0",
				"flake8-slots>=0.1.0",
				"flake8-sphinx-links>=0.0.4",
				"flake8-strftime>=0.1.1",
				"flake8-typing-imports>=1.10.0",
				"git+https://github.com/domdfcoding/flake8-rst-docstrings-sphinx.git",
				"git+https://github.com/domdfcoding/flake8-rst-docstrings.git",
				"git+https://github.com/python-formate/flake8-unused-arguments.git@magic-methods",
				"pydocstyle>=6.0.0",
				"pygments>=2.7.1",
				"importlib_metadata<4.5.0; python_version<'3.8'"
				])
		cmd = f"python3 -m flake8_rst_docstrings_sphinx {' '.join(self.get_source_files())} --allow-toolbox {{posargs}}"
		self._ini["testenv:lint"]["commands"] = cmd
Пример #10
0
	def tox(self):
		"""
		``[tox]``.
		"""

		tox_envs: List[str] = []
		if self["third_party_version_matrix"]:
			for third_party_library in self["third_party_version_matrix"]:
				third_party_versions = DelimitedList(self["third_party_version_matrix"][third_party_library])
				matrix_testenv_string = f"-{third_party_library}{{{third_party_versions:,}}}"
				tox_envs.extend(v + matrix_testenv_string for v in self["tox_py_versions"])
		else:
			tox_envs = self["tox_py_versions"]

		self._ini["tox"]["envlist"] = [*tox_envs, "mypy", "build"]
		self._ini["tox"]["skip_missing_interpreters"] = True
		self._ini["tox"]["isolated_build"] = True

		tox_requires = {"pip>=20.3.3", "tox-pip-version>=0.0.7", *self["tox_requirements"]}

		if self["pypi_name"] != "tox-envlist":
			tox_requires.add("tox-envlist>=0.2.1")

		self._ini["tox"]["requires"] = indent_join(sorted(tox_requires))
Пример #11
0
	def merge_existing(self, ini_file):
		"""
		Merge existing sections in the configuration file into the new configuration.

		:param ini_file: The existing ``.ini`` file.
		"""

		if ini_file.is_file():
			existing_config = ConfigUpdater()
			existing_config.read(str(ini_file))

			for section in existing_config.sections_blocks():
				if section.name not in self.managed_sections:
					self._ini.add_section(section)
				elif section.name == "coverage:report" and "omit" in section:
					self._ini["coverage:report"]["omit"] = section["omit"].value
				elif section.name == "flake8":
					if "rst-directives" in section:
						existing_directives = section["rst-directives"].value.splitlines()
						new_directives = self._ini["flake8"]["rst-directives"].value.splitlines()
						combined_directives = set(map(str.strip, (*new_directives, *existing_directives)))
						self._ini["flake8"]["rst-directives"] = indent_join(
								sorted(filter(bool, combined_directives))
								)

					if "rst-roles" in section:
						existing_roles = section["rst-roles"].value.splitlines()
						new_roles = self._ini["flake8"]["rst-roles"].value.splitlines()
						combined_roles = set(map(str.strip, (*new_roles, *existing_roles)))
						self._ini["flake8"]["rst-roles"] = indent_join(sorted(filter(bool, combined_roles)))

					if "per-file-ignores" in section:
						combined_ignores = {}

						# Existing first, so they're always overridden by our new ones
						for line in section["per-file-ignores"].value.splitlines():
							if not line.strip():
								continue
							glob, ignores = line.split(':', 1)
							combined_ignores[glob.strip()] = ignores.strip()

						for line in self._ini["flake8"]["per-file-ignores"].value.splitlines():
							if not line.strip():
								continue
							glob, ignores = line.split(':', 1)
							combined_ignores[glob.strip()] = ignores.strip()

						# Always put tests/* and */*.pyi first
						combined_ignores_strings = [
								f"tests/*: {combined_ignores.pop('tests/*')}",
								f"*/*.pyi: {combined_ignores.pop('*/*.pyi')}",
								]

						combined_ignores_strings.extend(
								sorted(filter(bool, (map(": ".join, combined_ignores.items()))))
								)
						self._ini["flake8"]["per-file-ignores"] = indent_join(combined_ignores_strings)
				elif section.name == "pytest":
					if "filterwarnings" in section:
						existing_value = set(map(str.strip, section["filterwarnings"].value.splitlines()))
						self._ini["pytest"]["filterwarnings"] = indent_join(sorted(filter(bool, existing_value)))
					if "markers" in section:
						existing_value = set(map(str.strip, section["markers"].value.splitlines()))
						self._ini["pytest"]["markers"] = indent_join(sorted(filter(bool, existing_value)))
Пример #12
0
	def testenv(self):
		"""
		``[testenv]``.
		"""

		if self["enable_devmode"]:
			self._ini["testenv"]["setenv"] = indent_join(("PYTHONDEVMODE=1", "PIP_DISABLE_PIP_VERSION_CHECK=1"))

		if self["enable_tests"]:

			deps = [f"-r{{toxinidir}}/{self['tests_dir']}/requirements.txt"]

			if self["third_party_version_matrix"]:
				for third_party_library in self["third_party_version_matrix"].keys():

					for version in self["third_party_version_matrix"][third_party_library]:
						if version == "latest":
							deps.append(f"{third_party_library}latest: {third_party_library}")
						else:
							v = Version(version)

							if v.is_prerelease:
								deps.append(f"{third_party_library}{version}: {third_party_library}=={version}")
							else:
								deps.append(f"{third_party_library}{version}: {third_party_library}~={version}.0")

			self._ini["testenv"]["deps"] = indent_join(deps)

		elif not self["stubs_package"]:
			deps = ["importcheck>=0.1.0"]

			if self["third_party_version_matrix"]:
				third_party_library = list(self["third_party_version_matrix"].keys())[0]

				for version in self["third_party_version_matrix"][third_party_library]:
					if version == "latest":
						deps.append(f"{third_party_library}latest: {third_party_library}")
					else:
						v = Version(version)
						if v.is_prerelease:
							deps.append(f"{third_party_library}{version}: {third_party_library}=={version}")
						else:
							deps.append(f"{third_party_library}{version}: {third_party_library}~={version}.0")

			self._ini["testenv"]["deps"] = indent_join(deps)

		if self["tox_testenv_extras"]:
			self._ini["testenv"]["extras"] = self["tox_testenv_extras"]

		testenv_commands = ["python --version"]

		if self["enable_tests"]:
			testenv_commands.append(
					f"python -m pytest --cov={self['import_name']} -r aR {self['tests_dir']}/ {{posargs}}"
					)
			# TODO: for tox-isolation
			# testenv_commands.append(
			# 		f"python -m pytest --cov={{envsitepackagesdir}}/{self['import_name']} -r aR {self['tests_dir']}/ {{posargs}}"
			# 		)

		elif not self["stubs_package"]:
			testenv_commands.append("python -m importcheck {posargs}")

		self._ini["testenv"]["commands"] = indent_join(testenv_commands)
Пример #13
0
def typed():
    """
	Add a 'py.typed' file and the associated trove classifier.
	"""

    # 3rd party
    from domdf_python_tools.paths import PathPlus
    from domdf_python_tools.stringlist import StringList
    from natsort import natsorted

    # this package
    from repo_helper.configupdater2 import ConfigUpdater
    from repo_helper.core import RepoHelper
    from repo_helper.utils import indent_join, stage_changes

    rh = RepoHelper(PathPlus.cwd())
    rh.load_settings()

    py_typed = rh.target_repo / rh.templates.globals["import_name"] / "py.typed"
    if not py_typed.is_file():
        py_typed.touch()

    stage_changes(rh.target_repo, [py_typed])

    setup_cfg = rh.target_repo / "setup.cfg"
    pyproject_file = rh.target_repo / "pyproject.toml"

    if setup_cfg.is_file() and not rh.templates.globals["use_whey"]:
        content = setup_cfg.read_text()

        config = ConfigUpdater()
        config.read_string(content)

        existing_classifiers = config["metadata"]["classifiers"]
        existing_classifiers_string = str(existing_classifiers)

        classifiers = set(
            map(str.strip, existing_classifiers.value.split('\n')))
        classifiers.add("Typing :: Typed")

        new_classifiers_lines = StringList(
            indent_join(natsorted(classifiers)).expandtabs(4))
        new_classifiers_lines[0] = "classifiers ="
        new_classifiers_lines.blankline(ensure_single=True)

        setup_cfg.write_clean(
            content.replace(existing_classifiers_string,
                            str(new_classifiers_lines)))

    if pyproject_file.is_file() and rh.templates.globals["use_whey"]:
        pyproject_config = dom_toml.load(pyproject_file)
        if "whey" in pyproject_config.get("tool", {}):
            classifiers = set(
                pyproject_config["tool"]["whey"]["base-classifiers"])
            classifiers.add("Typing :: Typed")
            pyproject_config["tool"]["whey"]["base-classifiers"] = natsorted(
                classifiers)

        dom_toml.dump(pyproject_config,
                      pyproject_file,
                      encoder=dom_toml.TomlEncoder)