diff --git a/data/templates/check_dependencies-with_url.py b/data/templates/check_dependencies-with_url.py index e3664595..ee263a93 100755 --- a/data/templates/check_dependencies-with_url.py +++ b/data/templates/check_dependencies-with_url.py @@ -4,19 +4,18 @@ import sys # Change PYTHONPATH to include dependencies. -sys.path.insert(0, '.') +sys.path.insert(0, ".") import utils.dependencies # pylint: disable=wrong-import-position +if __name__ == "__main__": + dependency_helper = utils.dependencies.DependencyHelper() -if __name__ == '__main__': - dependency_helper = utils.dependencies.DependencyHelper() + if not dependency_helper.CheckDependencies(): + build_instructions_url = ( + "https://${project_name}.readthedocs.io/en/latest/sources/user/Users-Guide.html" + ) + print(f"See: {build_instructions_url:s} on how to set up ${project_name}.") + print("") - if not dependency_helper.CheckDependencies(): - build_instructions_url = ( - 'https://${project_name}.readthedocs.io/en/latest/sources/user/Users-Guide.html') - - print(f'See: {build_instructions_url:s} on how to set up ${project_name}.') - print('') - - sys.exit(1) + sys.exit(1) diff --git a/data/templates/dependencies.py b/data/templates/dependencies.py index 1480ac6b..4a5dab0f 100644 --- a/data/templates/dependencies.py +++ b/data/templates/dependencies.py @@ -1,12 +1,11 @@ """Functionality to check for the availability and version of dependencies. -This file is generated by l2tdevtools update-dependencies.py, any dependency -related changes should be made in dependencies.ini. +This file is generated by l2tdevtools update-dependencies.py, any dependency related +changes should be made in dependencies.ini. """ import re - # Dictionary that contains version tuples per module name. # # A version tuple consists of: @@ -15,158 +14,174 @@ # Where version_attribute_name is either a name of an attribute, # property or method. PYTHON_DEPENDENCIES = { -${python_dependencies}} +${python_dependencies} +} -_VERSION_SPLIT_REGEX = re.compile(r'\.|\-') +_VERSION_SPLIT_REGEX = re.compile(r"\.|\-") def _CheckPythonModule( - module_name, version_attribute_name, minimum_version, - is_required=True, maximum_version=None, verbose_output=True): - """Checks the availability of a Python module. - - Args: - module_name (str): name of the module. - version_attribute_name (str): name of the attribute that contains - the module version or method to retrieve the module version. - minimum_version (str): minimum required version. - is_required (Optional[bool]): True if the Python module is a required - dependency. - maximum_version (Optional[str]): maximum required version. Should only be - used if there is a later version that is not supported. - verbose_output (Optional[bool]): True if output should be verbose. - - Returns: - bool: True if the Python module is available and conforms to - the minimum required version, False otherwise. - """ - module_object = _ImportPythonModule(module_name) - if not module_object: - if not is_required: - print(f'[OPTIONAL]\tmissing: {module_name:s}.') - return True - - print(f'[FAILURE]\tmissing: {module_name:s}.') - return False - - if not version_attribute_name or not minimum_version: - if verbose_output: - print(f'[OK]\t\t{module_name:s}') - return True - - module_version = None - if not version_attribute_name.endswith('()'): - module_version = getattr(module_object, version_attribute_name, None) - else: - version_method = getattr(module_object, version_attribute_name[:-2], None) - if version_method: - module_version = version_method() - - if not module_version: - if not is_required: - print(( - f'[OPTIONAL]\tunable to determine version information ' - f'for: {module_name:s}')) - return True - - print(( - f'[FAILURE]\tunable to determine version information ' - f'for: {module_name:s}')) - return False - - # Make sure the module version is a string. - module_version = f'{module_version!s}' - - # Remove a version suffix, such as: 0.7.0~rc1 - module_version_list = _VERSION_SPLIT_REGEX.split(module_version) - - try: - int(module_version_list[-1], 10) - except (TypeError, ValueError): - module_version_list.pop() - - # Split the version string and convert every digit into an integer. - # A string compare of both version strings will yield an incorrect result. - module_version_map = list(map(int, module_version_list)) - minimum_version_map = list( - map(int, _VERSION_SPLIT_REGEX.split(minimum_version))) - - if module_version_map < minimum_version_map: - if not is_required: - print(( - f'[OPTIONAL]\t{module_name:s} version: {module_version!s} is too ' - f'old, {minimum_version!s} or later required.')) - return True - - print(( - f'[FAILURE]\t{module_name:s} version: {module_version!s} is too old, ' - f'{minimum_version!s} or later required.')) - return False - - if maximum_version: - maximum_version_map = list( - map(int, _VERSION_SPLIT_REGEX.split(maximum_version))) - if module_version_map > maximum_version_map: - if not is_required: - print(( - f'[OPTIONAL]\t{module_name:s} version: {module_version!s} is too ' - f'recent, {minimum_version!s} or earlier required.')) + module_name, + version_attribute_name, + minimum_version, + is_required=True, + maximum_version=None, + verbose_output=True, +): + """Checks the availability of a Python module. + + Args: + module_name (str): name of the module. + version_attribute_name (str): name of the attribute that contains + the module version or method to retrieve the module version. + minimum_version (str): minimum required version. + is_required (Optional[bool]): True if the Python module is a required + dependency. + maximum_version (Optional[str]): maximum required version. Should only be + used if there is a later version that is not supported. + verbose_output (Optional[bool]): True if output should be verbose. + + Returns: + bool: True if the Python module is available and conforms to + the minimum required version, False otherwise. + """ + module_object = _ImportPythonModule(module_name) + if not module_object: + if not is_required: + print(f"[OPTIONAL]\tmissing: {module_name:s}.") + return True + + print(f"[FAILURE]\tmissing: {module_name:s}.") + return False + + if not version_attribute_name or not minimum_version: + if verbose_output: + print(f"[OK]\t\t{module_name:s}") return True - print(( - f'[FAILURE]\t{module_name:s} version: {module_version!s} is too ' - f'recent, {maximum_version!s} or earlier required.')) - return False + module_version = None + if not version_attribute_name.endswith("()"): + module_version = getattr(module_object, version_attribute_name, None) + else: + version_method = getattr(module_object, version_attribute_name[:-2], None) + if version_method: + module_version = version_method() + + if not module_version: + if not is_required: + print( + f"[OPTIONAL]\tunable to determine version information " + f"for: {module_name:s}" + ) + return True + + print( + f"[FAILURE]\tunable to determine version information " + f"for: {module_name:s}" + ) + return False + + # Make sure the module version is a string. + module_version = f"{module_version!s}" + + # Remove a version suffix, such as: 0.7.0~rc1 + module_version_list = _VERSION_SPLIT_REGEX.split(module_version) + + try: + int(module_version_list[-1], 10) + except (TypeError, ValueError): + module_version_list.pop() + + # Split the version string and convert every digit into an integer. + # A string compare of both version strings will yield an incorrect result. + module_version_map = list(map(int, module_version_list)) + minimum_version_map = list(map(int, _VERSION_SPLIT_REGEX.split(minimum_version))) + + if module_version_map < minimum_version_map: + if not is_required: + print( + f"[OPTIONAL]\t{module_name:s} version: {module_version!s} is too " + f"old, {minimum_version!s} or later required." + ) + return True + + print( + f"[FAILURE]\t{module_name:s} version: {module_version!s} is too old, " + f"{minimum_version!s} or later required." + ) + return False + + if maximum_version: + maximum_version_map = list( + map(int, _VERSION_SPLIT_REGEX.split(maximum_version)) + ) + if module_version_map > maximum_version_map: + if not is_required: + print( + f"[OPTIONAL]\t{module_name:s} version: {module_version!s} is too " + f"recent, {minimum_version!s} or earlier required." + ) + return True + + print( + f"[FAILURE]\t{module_name:s} version: {module_version!s} is too " + f"recent, {maximum_version!s} or earlier required." + ) + return False - if verbose_output: - print(f'[OK]\t\t{module_name:s} version: {module_version!s}') + if verbose_output: + print(f"[OK]\t\t{module_name:s} version: {module_version!s}") - return True + return True def _ImportPythonModule(module_name): - """Imports a Python module. + """Imports a Python module. - Args: - module_name (str): name of the module. + Args: + module_name (str): name of the module. - Returns: - module: Python module or None if the module cannot be imported. - """ - try: - module_object = list(map(__import__, [module_name]))[0] - except ImportError: - return None + Returns: + module: Python module or None if the module cannot be imported. + """ + try: + module_object = list(map(__import__, [module_name]))[0] + except ImportError: + return None - # If the module name contains dots get the upper most module object. - if '.' in module_name: - for submodule_name in module_name.split('.')[1:]: - module_object = getattr(module_object, submodule_name, None) + # If the module name contains dots get the upper most module object. + if "." in module_name: + for submodule_name in module_name.split(".")[1:]: + module_object = getattr(module_object, submodule_name, None) - return module_object + return module_object def CheckDependencies(verbose_output=True): - """Checks the availability of the dependencies. - - Args: - verbose_output (Optional[bool]): True if output should be verbose. - - Returns: - bool: True if the dependencies are available, False otherwise. - """ - print('Checking availability and versions of dependencies.') - check_result = True - - for module_name, version_tuple in sorted(PYTHON_DEPENDENCIES.items()): - if not _CheckPythonModule( - module_name, version_tuple[0], version_tuple[1], - is_required=version_tuple[3], maximum_version=version_tuple[2], - verbose_output=verbose_output): - check_result = False - - if check_result and not verbose_output: - print('[OK]') - - print('') - return check_result + """Checks the availability of the dependencies. + + Args: + verbose_output (Optional[bool]): True if output should be verbose. + + Returns: + bool: True if the dependencies are available, False otherwise. + """ + print("Checking availability and versions of dependencies.") + check_result = True + + for module_name, version_tuple in sorted(PYTHON_DEPENDENCIES.items()): + if not _CheckPythonModule( + module_name, + version_tuple[0], + version_tuple[1], + is_required=version_tuple[3], + maximum_version=version_tuple[2], + verbose_output=verbose_output, + ): + check_result = False + + if check_result and not verbose_output: + print("[OK]") + + print("") + return check_result diff --git a/data/templates/pyproject.toml/docformatter.toml b/data/templates/pyproject.toml/docformatter.toml new file mode 100644 index 00000000..0f72585d --- /dev/null +++ b/data/templates/pyproject.toml/docformatter.toml @@ -0,0 +1,5 @@ + +[tool.docformatter] +black = true +non-cap = ${docformatter_non_cap} +non-strict = true diff --git a/data/templates/pyproject.toml/setuptools.packages.toml b/data/templates/pyproject.toml/setuptools.toml similarity index 100% rename from data/templates/pyproject.toml/setuptools.packages.toml rename to data/templates/pyproject.toml/setuptools.toml diff --git a/data/templates/tox.ini/testenv_black b/data/templates/tox.ini/testenv_black index 7792ffa7..df5352fb 100644 --- a/data/templates/tox.ini/testenv_black +++ b/data/templates/tox.ini/testenv_black @@ -13,4 +13,4 @@ deps = setuptools >= 65 commands = black --version - black --check . + black . diff --git a/data/templates/tox.ini/testenv_docformatter b/data/templates/tox.ini/testenv_docformatter new file mode 100644 index 00000000..c7edc11a --- /dev/null +++ b/data/templates/tox.ini/testenv_docformatter @@ -0,0 +1,16 @@ + +[testenv:docformatter] +skipsdist = True +pip_pre = True +passenv = + CFLAGS + CPPFLAGS + LDFLAGS +setenv = + PYTHONPATH = {toxinidir} +deps = + docformatter + setuptools >= 65 +commands = + docformatter --version + docformatter --in-place --recursive ${paths_to_lint_python} diff --git a/l2tdevtools/dependencies.py b/l2tdevtools/dependencies.py index 6c9732a7..4fe664c1 100644 --- a/l2tdevtools/dependencies.py +++ b/l2tdevtools/dependencies.py @@ -137,12 +137,12 @@ def __init__( dependency_reader = DependencyDefinitionReader() - with open(dependencies_file, "r", encoding="utf-8") as file_object: + with open(dependencies_file, encoding="utf-8") as file_object: for dependency in dependency_reader.Read(file_object): self.dependencies[dependency.name] = dependency if os.path.exists(test_dependencies_file): - with open(test_dependencies_file, "r", encoding="utf-8") as file_object: + with open(test_dependencies_file, encoding="utf-8") as file_object: for dependency in dependency_reader.Read(file_object): self._test_dependencies[dependency.name] = dependency @@ -624,7 +624,6 @@ def GetPylintRcExtensionPkgs(self): "yara", "zstd", ) - extension_packages = [] for dependency in sorted( self.dependencies.values(), key=lambda dependency: dependency.name diff --git a/l2tdevtools/dependency_writers/dependencies_py.py b/l2tdevtools/dependency_writers/dependencies_py.py index 00429e7a..b7355874 100644 --- a/l2tdevtools/dependency_writers/dependencies_py.py +++ b/l2tdevtools/dependency_writers/dependencies_py.py @@ -34,13 +34,14 @@ def Write(self): not_optional = not dependency.is_optional python_dependency = ( - f" '{dependency.name:s}': ('{version_property:s}', " - f"'{minimum_version:s}', {maximum_version:s}, {not_optional!s})" + f' "{dependency.name:s}": ("{version_property:s}", ' + f'"{minimum_version:s}", {maximum_version:s}, {not_optional!s})' ) - python_dependencies.append(python_dependency) python_dependencies = ",\n".join(python_dependencies) + if python_dependencies: + python_dependencies = f"{python_dependencies:s}," template_mappings = {"python_dependencies": python_dependencies} diff --git a/l2tdevtools/dependency_writers/setup.py b/l2tdevtools/dependency_writers/pyproject.py similarity index 89% rename from l2tdevtools/dependency_writers/setup.py rename to l2tdevtools/dependency_writers/pyproject.py index c099da6a..965966fa 100644 --- a/l2tdevtools/dependency_writers/setup.py +++ b/l2tdevtools/dependency_writers/pyproject.py @@ -1,4 +1,4 @@ -"""Writer for setup configuration and script files.""" +"""Writer for pyproject configuration files.""" import datetime import glob @@ -78,7 +78,6 @@ def Write(self): data_file_directory = os.path.dirname( data_file[len(f"{python_module_name:s}/") :] ) - data_file = "*.yaml" if data_file_directory: data_file = "/".join([data_file_directory, data_file]) @@ -97,12 +96,11 @@ def Write(self): scripts_directory = None if scripts_directory: - if glob.glob(f"{scripts_directory:s}/[a-z]*.py"): + scripts_glob = os.path.join(scripts_directory, "[a-z]*.py") + if glob.glob(scripts_glob): logging.warning( - ( - "Scripts are not supported by pyproject.toml, change them to " - "console_scripts entry points." - ) + "Scripts are not supported by pyproject.toml, change them to " + "console_scripts entry points." ) console_scripts_directory = os.path.join(python_module_name, "scripts") @@ -111,23 +109,27 @@ def Write(self): console_scripts = [] if console_scripts_directory: - console_scripts = glob.glob(f"{console_scripts_directory:s}/[a-z]*.py") + console_scripts_glob = os.path.join(console_scripts_directory, "[a-z]*.py") + console_scripts = glob.glob(console_scripts_glob) date_time = datetime.datetime.now() version = date_time.strftime("%Y%m%d") + # TODO: configure in project.ini file + docformatter_non_cap = "[]" + template_mappings = { "description_short": ( self._project_definition.description_short.rstrip(".") ), "development_status": development_status, + "docformatter_non_cap": docformatter_non_cap, "maintainer_email": maintainer_email, "maintainer_name": maintainer_name, "python_module_name": python_module_name, "readme_file": readme_file, "version": version, } - file_content = [] template_data = self._GenerateFromTemplate("header.toml", template_mappings) @@ -171,10 +173,13 @@ def Write(self): file_content.append(template_data) template_data = self._GenerateFromTemplate( - "setuptools.packages.toml", template_mappings + "docformatter.toml", template_mappings ) file_content.append(template_data) + template_data = self._GenerateFromTemplate("setuptools.toml", template_mappings) + file_content.append(template_data) + if package_data: file_content.append("\n") file_content.append("[tool.setuptools.package-data]\n") diff --git a/l2tdevtools/dependency_writers/tox_ini.py b/l2tdevtools/dependency_writers/tox_ini.py index e1c60c3f..31797d37 100644 --- a/l2tdevtools/dependency_writers/tox_ini.py +++ b/l2tdevtools/dependency_writers/tox_ini.py @@ -49,32 +49,34 @@ def Write(self): if os.path.isdir(python_module_name): paths_to_lint_python.append(python_module_name) - if glob.glob( - os.path.join(python_module_name, "**", "*.yaml"), recursive=True - ): + yaml_glob = os.path.join(python_module_name, "**", "*.yaml") + if glob.glob(yaml_glob, recursive=True): paths_to_lint_yaml.append(python_module_name) if os.path.isdir("data"): - if glob.glob(os.path.join("data", "**", "*.yaml"), recursive=True): + yaml_glob = os.path.join("data", "**", "*.yaml") + if glob.glob(yaml_glob, recursive=True): paths_to_lint_yaml.append("data") if os.path.isdir("scripts"): paths_to_lint_python.append("scripts") if os.path.isdir("test_data"): - if glob.glob(os.path.join("test_data", "**", "*.yaml"), recursive=True): + yaml_glob = os.path.join("test_data", "**", "*.yaml") + if glob.glob(yaml_glob, recursive=True): paths_to_lint_yaml.append("test_data") if os.path.isdir("tests"): paths_to_lint_python.append("tests") - if glob.glob(os.path.join("tests", "**", "*.yaml"), recursive=True): + yaml_glob = os.path.join("tests", "**", "*.yaml") + if glob.glob(yaml_glob, recursive=True): paths_to_lint_yaml.append("tests") if os.path.isdir("tools"): paths_to_lint_python.append("tools") - envlist = ["py3{10,11,12,13,14}", "black", "coverage"] + envlist = ["py3{10,11,12,13,14}", "black", "coverage", "docformatter"] if os.path.isdir("docs"): envlist.append("docs") @@ -90,7 +92,6 @@ def Write(self): "project_name": self._project_definition.name, "python_module_name": python_module_name, } - file_content = [] template_data = self._GenerateFromTemplate("header", template_mappings) @@ -99,6 +100,11 @@ def Write(self): template_data = self._GenerateFromTemplate("testenv_black", template_mappings) file_content.append(template_data) + template_data = self._GenerateFromTemplate( + "testenv_docformatter", template_mappings + ) + file_content.append(template_data) + if os.path.isdir("docs"): template_data = self._GenerateFromTemplate( "testenv_docs", template_mappings diff --git a/tests/dependency_writers/setup.py b/tests/dependency_writers/pyproject.py similarity index 91% rename from tests/dependency_writers/setup.py rename to tests/dependency_writers/pyproject.py index 498d9473..95c1ecbd 100644 --- a/tests/dependency_writers/setup.py +++ b/tests/dependency_writers/pyproject.py @@ -4,7 +4,7 @@ import unittest from l2tdevtools import dependencies -from l2tdevtools.dependency_writers import setup +from l2tdevtools.dependency_writers import pyproject from l2tdevtools.helpers import project from tests import test_lib @@ -23,7 +23,7 @@ def testInitialize(self): test_dependencies_file=test_dependencies_file, ) - writer = setup.PyprojectTomlWriter( + writer = pyproject.PyprojectTomlWriter( l2tdevtools_path, project_definition, dependency_helper ) self.assertIsNotNone(writer) diff --git a/tools/update-dependencies.py b/tools/update-dependencies.py index bbddb682..70c9521a 100755 --- a/tools/update-dependencies.py +++ b/tools/update-dependencies.py @@ -21,7 +21,7 @@ from l2tdevtools.dependency_writers import jenkins_scripts from l2tdevtools.dependency_writers import linux_scripts from l2tdevtools.dependency_writers import pylint_rc -from l2tdevtools.dependency_writers import setup +from l2tdevtools.dependency_writers import pyproject from l2tdevtools.dependency_writers import sphinx_docs from l2tdevtools.dependency_writers import tox_ini @@ -42,7 +42,7 @@ def Main(): dependencies_helper = dependencies.DependencyHelper() - for writer_class in (pylint_rc.PylintRcWriter, setup.PyprojectTomlWriter): + for writer_class in (pylint_rc.PylintRcWriter, pyproject.PyprojectTomlWriter): writer = writer_class(l2tdevtools_path, project_definition, dependencies_helper) writer.Write()