|
| 1 | +# --------------------------------------------------------------------------------- |
| 2 | +# Copyright (c) Tim Littlefair. All rights reserved. |
| 3 | +# Licensed under the MIT License. See LICENSE in project root for information. |
| 4 | +# --------------------------------------------------------------------------------- |
| 5 | + |
| 6 | +""" |
| 7 | +This script is part of the tl-python-package-template project. |
| 8 | +The project is, as the name suggests, a template from which other |
| 9 | +projects can be cloned. |
| 10 | +
|
| 11 | +The purpose of this test script is to encourage users who clone |
| 12 | +the template as a basis for their own projects, to update the |
| 13 | +pyproject.toml file in the base directory and the directory |
| 14 | +structure of the project to reflect the name of the project |
| 15 | +they are instantiating rather than leaving the placeholder names |
| 16 | +in the template. |
| 17 | +
|
| 18 | +The tests below make the following assertions: |
| 19 | ++ that the basename of the git remote URL matches the name attribute |
| 20 | + in pyproject.toml section [project]; |
| 21 | ++ that there is a subdirectory under src with a name which matches |
| 22 | + the name attribute in pyproject.toml section [tool.flit.module] |
| 23 | ++ that the name attributes in pyproject.toml [project]; and |
| 24 | + [tool.flit.module] agree apart from the conversion of any |
| 25 | + '-' (dash) characters in the [project] name into '_' (underscore) |
| 26 | + characters in the [tool.flit.module] name. |
| 27 | +
|
| 28 | +The names in the base versions of files in the template satisfy |
| 29 | +these assertions provided the 'origin' git remote still refers |
| 30 | +to https://github.com/tim-littlefair/tl-python-package-template.git, |
| 31 | +but when an end-user uses the template as the basis for a repository |
| 32 | +with a different basename and clones a sandbox from their new repo, |
| 33 | +at least one of the assertions above will fail and will force the |
| 34 | +user (preferably) to update pyproject.toml to define their own, |
| 35 | +PyPi package name and Python module name where these appear in the |
| 36 | +pyproject.toml files and under the src, docs and tests subdirectories |
| 37 | +in order to achieve clean-running tests. |
| 38 | +Alternatively the end user can delete or modify the source of this |
| 39 | +test. |
| 40 | +""" |
| 41 | + |
| 42 | +import os |
| 43 | +import subprocess |
| 44 | +import sys |
| 45 | + |
| 46 | + |
| 47 | +def _get_name_from_toml_section(toml_section_name): |
| 48 | + assert os.path.exists("./pyproject.toml") is True |
| 49 | + grep_toml_command = "|".join([ |
| 50 | + # filter out all lines until we see the section heading |
| 51 | + # retain all lines after that point |
| 52 | + f"grep -A1 -F '[{toml_section_name}]' pyproject.toml", |
| 53 | + # scan for lines after the heading which start with 'name' |
| 54 | + "grep -E '^name'", |
| 55 | + # accept only the very first line still accepted at this point |
| 56 | + "head -1", |
| 57 | + # isolate the value, enclosed in double quotes |
| 58 | + """grep -E '"[^"]+"' --only-matching""", |
| 59 | + # discard the double quotes |
| 60 | + """sed -e 's/"//g' -""" |
| 61 | + ]) |
| 62 | + print(grep_toml_command,file=sys.stderr) |
| 63 | + grep_toml_result = subprocess.run( |
| 64 | + grep_toml_command, |
| 65 | + shell=True, capture_output=True, text=True |
| 66 | + ) |
| 67 | + name_attribute_from_section = grep_toml_result.stdout.strip() |
| 68 | + # Uncomment the next two lines to debug the command chain |
| 69 | + # assert False, \ |
| 70 | + # f"Command '{grep_toml_command}' found '{name_attribute_from_sectionUnable to find 'name' attribute section {toml_section_name} in pyproject.toml" |
| 71 | + assert len(name_attribute_from_section)>0, \ |
| 72 | + f"Command '{grep_toml_command}' found '{name_attribute_from_section}' in .toml section '{toml_section_name}'" |
| 73 | + print(name_attribute_from_section) |
| 74 | + return name_attribute_from_section |
| 75 | + |
| 76 | +_TOML_PROJECT_NAME = _get_name_from_toml_section("project") |
| 77 | +_TOML_MODULE_NAME = _get_name_from_toml_section("tool.flit.module") |
| 78 | + |
| 79 | + |
| 80 | +def test_check_project_name_against_git_remote_origin(): |
| 81 | + """ |
| 82 | + This test requires that the project name in ./pyproject.toml's |
| 83 | + [project] section matches the basename of the URL of the default |
| 84 | + git remote 'origin', providing that a git remote with that name |
| 85 | + exists. |
| 86 | + """ |
| 87 | + git_remote_result = subprocess.run( |
| 88 | + "git remote get-url origin", |
| 89 | + shell=True, capture_output=True, text=True |
| 90 | + ) |
| 91 | + origin_repo_basename = os.path.basename(git_remote_result.stdout).strip() |
| 92 | + |
| 93 | + if len(origin_repo_basename)>0: |
| 94 | + assert origin_repo_basename.startswith(_TOML_PROJECT_NAME), \ |
| 95 | + f"Project name in toml file ({_TOML_PROJECT_NAME})" + \ |
| 96 | + f" does not match prefix of git origin repo URL ({origin_repo_basename})" |
| 97 | + print( |
| 98 | + f"Project name ({_TOML_PROJECT_NAME})" + \ |
| 99 | + f" matches URL basename for git remote 'origin' ({origin_repo_basename})" |
| 100 | + ) |
| 101 | + else: |
| 102 | + print( |
| 103 | + "Project name check skipped because 'git remote get-url origin' returned an empty string" |
| 104 | + ) |
| 105 | + |
| 106 | + |
| 107 | +def test_check_module_name_against_src_directory(): |
| 108 | + """ |
| 109 | + This test requires that there is a subdirectory under src which matches |
| 110 | + the Python module name in ./pyproject.toml's [tool.flit.module] section. |
| 111 | + """ |
| 112 | + src_subdirs = os.listdir("./src") |
| 113 | + assert _TOML_MODULE_NAME in src_subdirs, f"No subdirectory {_TOML_MODULE_NAME} found under ./src" |
| 114 | + |
| 115 | + |
| 116 | +def test_check_module_name_against_project_name(): |
| 117 | + """ |
| 118 | + This test requires that the project name in ./pyproject.toml |
| 119 | + (which will also be the package name if and when the project is |
| 120 | + uploaded to PyPi) matches the name of the Python module it |
| 121 | + contains. |
| 122 | + If the project name contains '-' (dash) characters, these |
| 123 | + are expected to be converted to '_' underscore characters |
| 124 | + to generate the Python module name. Other than this t |
| 125 | + transliteration, no difference between the names is expected. |
| 126 | + """ |
| 127 | + assert _TOML_MODULE_NAME == _TOML_PROJECT_NAME.replace("-","_"), \ |
| 128 | + f"Module name '{_TOML_MODULE_NAME}' does not match project name '{_TOML_PROJECT_NAME}'" |
| 129 | + |
| 130 | + |
0 commit comments