Coverage for tests/test_generation/test_generator.py: 100%
84 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2024-08-27 18:25 +0000
1import sys
2import subprocess
3from typing import cast
4from pathlib import Path
5from typing_extensions import override
7import pytest
8from jinja2 import Environment, FileSystemLoader
10from prisma import __version__
11from prisma._compat import PYDANTIC_V2
12from prisma.generator import (
13 BASE_PACKAGE_DIR,
14 Manifest,
15 Generator,
16 GenericGenerator,
17 render_template,
18 cleanup_templates,
19)
20from prisma.generator.utils import Faker, copy_tree
22from .utils import assert_module_is_clean, assert_module_not_clean
23from ..utils import Testdir
26def test_repeated_rstrip_bug(tmp_path: Path) -> None:
27 """Previously, rendering schema.prisma.jinja would have rendered the file
28 to schema.prism instead of schema.prisma
29 """
30 env = Environment(loader=FileSystemLoader(str(tmp_path)))
32 template = 'schema.prisma.jinja'
33 tmp_path.joinpath(template).write_text('foo')
34 render_template(tmp_path, template, dict(), env=env)
36 assert tmp_path.joinpath('schema.prisma').read_text() == 'foo'
39def test_template_cleanup(testdir: Testdir) -> None:
40 """Cleaning up templates removes all rendered files"""
41 path = testdir.path / 'prisma'
42 assert not path.exists()
43 copy_tree(BASE_PACKAGE_DIR, path)
45 assert_module_not_clean(path)
46 cleanup_templates(path)
47 assert_module_is_clean(path)
49 # ensure cleaning an already clean module doesn't change anything
50 cleanup_templates(path)
51 assert_module_is_clean(path)
54def test_erroneous_template_cleanup(testdir: Testdir) -> None:
55 """Template runtime errors do not result in a partially generated module"""
56 path = testdir.path / 'prisma'
57 copy_tree(BASE_PACKAGE_DIR, path)
59 assert_module_not_clean(path)
61 template = '{{ undefined.foo }}'
62 template_path = testdir.path / 'prisma' / 'generator' / 'templates' / 'template.py.jinja'
63 template_path.write_text(template)
65 with pytest.raises(subprocess.CalledProcessError) as exc:
66 testdir.generate()
68 output = str(exc.value.output, sys.getdefaultencoding())
69 assert template in output
71 assert_module_is_clean(path)
74def test_generation_version_number(testdir: Testdir) -> None:
75 """Ensure the version number is shown when the client is generated"""
76 stdout = testdir.generate().stdout.decode('utf-8')
77 assert f'Generated Prisma Client Python (v{__version__})' in stdout
80def test_faker() -> None:
81 """Ensure Faker is re-playable"""
82 iter1 = iter(Faker())
83 iter2 = iter(Faker())
84 first = [next(iter1) for _ in range(10)]
85 second = [next(iter2) for _ in range(10)]
86 assert first == second
89def test_invoke_outside_generation() -> None:
90 """Attempting to invoke a generator outside of Prisma generation errors"""
91 with pytest.raises(RuntimeError) as exc:
92 Generator.invoke()
94 assert exc.value.args[0] == 'Attempted to invoke a generator outside of Prisma generation'
97def test_invalid_type_argument() -> None:
98 """Non-BaseModel argument to GenericGenerator raises an error"""
100 class MyGenerator(GenericGenerator[Path]): # type: ignore
101 @override
102 def get_manifest(self) -> Manifest: # pragma: no cover
103 return super().get_manifest() # type: ignore
105 @override
106 def generate(self, data: Path) -> None: # pragma: no cover
107 raise NotImplementedError()
109 with pytest.raises(TypeError) as exc:
110 MyGenerator().data_class # noqa: B018
112 assert 'pathlib.Path' in exc.value.args[0]
113 assert 'pydantic.main.BaseModel' in exc.value.args[0]
115 class MyGenerator2(GenericGenerator[Manifest]):
116 @override
117 def get_manifest(self) -> Manifest: # pragma: no cover
118 return super().get_manifest() # type: ignore
120 @override
121 def generate(self, data: Manifest) -> None: # pragma: no cover
122 raise NotImplementedError()
124 data_class = MyGenerator2().data_class
125 assert data_class == Manifest
128def test_generator_subclass_mismatch() -> None:
129 """Attempting to subclass Generator instead of BaseGenerator raises an error"""
130 with pytest.raises(TypeError) as exc:
132 class MyGenerator(Generator): # pyright: ignore[reportUnusedClass]
133 ...
135 message = exc.value.args[0]
136 assert 'cannot be subclassed, maybe you meant' in message
137 assert 'BaseGenerator' in message
140def test_error_handling(testdir: Testdir) -> None:
141 """Config validation errors are returned through JSONRPC without a stack trace"""
142 with pytest.raises(subprocess.CalledProcessError) as exc:
143 testdir.generate(options='partial_type_generator = "foo"')
145 output = cast(bytes, exc.value.output).decode('utf-8').strip()
146 if PYDANTIC_V2:
147 line = output.splitlines()[-2]
148 assert (
149 line
150 == " Value error, Could not find a python file or module at foo [type=value_error, input_value='foo', input_type=str]"
151 )
152 else:
153 assert output.endswith(
154 '\nError: \n'
155 '1 validation error for PythonData\n'
156 'generator -> config -> partial_type_generator -> spec\n'
157 ' Could not find a python file or module at foo (type=value_error)'
158 )
161def test_schema_path_same_path(testdir: Testdir) -> None:
162 """Generating to the same directory does not cause any errors due to schema copying
164 https://github.com/RobertCraigie/prisma-client-py/issues/513
165 """
166 proc = testdir.generate(output='.')
167 assert proc.returncode == 0
168 assert 'Generated Prisma Client Python' in proc.stdout.decode('utf-8')