• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

abravalheri / validate-pyproject / 5226968556240896

pending completion
5226968556240896

push

cirrus-ci

GitHub
Typo: validate-project => validate-pyproject (#78)

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.55
/src/validate_pyproject/pre_compile/__init__.py
1
import logging
8✔
2
import os
8✔
3
import sys
8✔
4
from pathlib import Path
8✔
5
from types import MappingProxyType
8✔
6
from typing import TYPE_CHECKING, Dict, Mapping, Optional, Sequence, Union
8✔
7

8
from .. import api, dist_name, types
8✔
9
from .._vendor import fastjsonschema as FJS
8✔
10

11
if sys.version_info[:2] >= (3, 8):  # pragma: no cover
12
    from importlib import metadata as _M
13
else:  # pragma: no cover
14
    import importlib_metadata as _M
15

16
if TYPE_CHECKING:  # pragma: no cover
17
    from ..plugins import PluginWrapper  # noqa
18

19

20
_logger = logging.getLogger(__name__)
8✔
21

22

23
TEXT_REPLACEMENTS = MappingProxyType(
8✔
24
    {
25
        "from fastjsonschema import": "from .fastjsonschema_exceptions import",
26
        "from ._vendor.fastjsonschema import": "from .fastjsonschema_exceptions import",
27
    }
28
)
29

30

31
def pre_compile(
8✔
32
    output_dir: Union[str, os.PathLike] = ".",
33
    main_file: str = "__init__.py",
34
    original_cmd: str = "",
35
    plugins: Union[api.AllPlugins, Sequence["PluginWrapper"]] = api.ALL_PLUGINS,
36
    text_replacements: Mapping[str, str] = TEXT_REPLACEMENTS,
37
) -> Path:
38
    """Populate the given ``output_dir`` with all files necessary to perform
39
    the validation.
40
    The validation can be performed by calling the ``validate`` function inside the
41
    the file named with the ``main_file`` value.
42
    ``text_replacements`` can be used to
43
    """
44
    out = Path(output_dir)
8✔
45
    out.mkdir(parents=True, exist_ok=True)
8✔
46
    replacements = {**TEXT_REPLACEMENTS, **text_replacements}
8✔
47

48
    validator = api.Validator(plugins)
8✔
49
    header = "\n".join(NOCHECK_HEADERS)
8✔
50
    code = replace_text(validator.generated_code, replacements)
8✔
51
    (out / "fastjsonschema_validations.py").write_text(header + code, "UTF-8")
8✔
52

53
    copy_fastjsonschema_exceptions(out, replacements)
8✔
54
    copy_module("extra_validations", out, replacements)
8✔
55
    copy_module("formats", out, replacements)
8✔
56
    copy_module("error_reporting", out, replacements)
8✔
57
    write_main(out / main_file, validator.schema, replacements)
8✔
58
    write_notice(out, main_file, original_cmd, replacements)
8✔
59
    (out / "__init__.py").touch()
8✔
60

61
    return out
8✔
62

63

64
def replace_text(text: str, replacements: Dict[str, str]) -> str:
8✔
65
    for orig, subst in replacements.items():
8✔
66
        text = text.replace(orig, subst)
8✔
67
    return text
8✔
68

69

70
def copy_fastjsonschema_exceptions(
8✔
71
    output_dir: Path, replacements: Dict[str, str]
72
) -> Path:
73
    file = output_dir / "fastjsonschema_exceptions.py"
8✔
74
    code = replace_text(api.read_text(FJS.__name__, "exceptions.py"), replacements)
8✔
75
    file.write_text(code, "UTF-8")
8✔
76
    return file
8✔
77

78

79
def copy_module(name: str, output_dir: Path, replacements: Dict[str, str]) -> Path:
8✔
80
    file = output_dir / f"{name}.py"
8✔
81
    code = api.read_text(api.__package__, f"{name}.py")
8✔
82
    code = replace_text(code, replacements)
8✔
83
    file.write_text(code, "UTF-8")
8✔
84
    return file
8✔
85

86

87
def write_main(
8✔
88
    file_path: Path, schema: types.Schema, replacements: Dict[str, str]
89
) -> Path:
90
    code = api.read_text(__name__, "main_file.template")
8✔
91
    code = replace_text(code, replacements)
8✔
92
    file_path.write_text(code, "UTF-8")
8✔
93
    return file_path
8✔
94

95

96
def write_notice(
8✔
97
    out: Path, main_file: str, cmd: str, replacements: Dict[str, str]
98
) -> Path:
99
    if cmd:
8✔
100
        opening = api.read_text(__name__, "cli-notice.template")
8✔
101
        opening = opening.format(command=cmd)
8✔
102
    else:
103
        opening = api.read_text(__name__, "api-notice.template")
8✔
104
    notice = api.read_text(__name__, "NOTICE.template")
8✔
105
    notice = notice.format(notice=opening, main_file=main_file, **load_licenses())
8✔
106
    notice = replace_text(notice, replacements)
8✔
107

108
    file = out / "NOTICE"
8✔
109
    file.write_text(notice, "UTF-8")
8✔
110
    return file
8✔
111

112

113
def load_licenses() -> Dict[str, str]:
8✔
114
    return {
8✔
115
        "fastjsonschema_license": api.read_text(FJS, "LICENSE"),
116
        "validate_pyproject_license": _find_and_load_licence(_M.files(dist_name)),
117
    }
118

119

120
NOCHECK_HEADERS = (
8✔
121
    "# noqa",
122
    "# type: ignore",
123
    "# flake8: noqa",
124
    "# pylint: skip-file",
125
    "# mypy: ignore-errors",
126
    "# yapf: disable",
127
    "# pylama:skip=1",
128
    "\n\n# *** PLEASE DO NOT MODIFY DIRECTLY: Automatically generated code *** \n\n\n",
129
)
130

131

132
def _find_and_load_licence(files: Optional[Sequence[_M.PackagePath]]) -> str:
8✔
133
    if files is None:  # pragma: no cover
134
        raise ImportError("Could not find LICENSE for package")
135
    try:
8✔
136
        return next(f for f in files if f.stem.upper() == "LICENSE").read_text("UTF-8")
8!
137
    except FileNotFoundError:  # pragma: no cover
138
        msg = (
139
            "Please make sure to install `validate-pyproject` and `fastjsonschema` "
140
            "in a NON-EDITABLE way. This is necessary due to the issue #112 in "
141
            "python/importlib_metadata."
142
        )
143
        _logger.warning(msg)
144
        raise
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc