Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Pydantic v2 support #77

Merged
merged 7 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,900 changes: 1,047 additions & 853 deletions poetry.lock

Large diffs are not rendered by default.

16 changes: 6 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ classifiers = [
python = "^3.9"
rich = "^11.0.0"
graphql-core = "^3.2.0"
pydantic = "^1.9.0"
pydantic = ">2"
PyYAML = ">=5.3.0"
black = { version = "^22.1.0", optional = true }
isort = { version = "^5.10.1", optional = true }
libcst = { version = "^0.4.9", optional = true }
libcst = { version = "^1.4.0", optional = true }
rich-click = ">=1.6"
watchfiles = "^0.18.1"
pydantic-settings = "^2.5.2"

[tool.poetry.dev-dependencies]
[tool.poetry.group.dev.dependencies]
pytest = "^6.2.5"
pytest-aiohttp = "^0.3.0"
pytest-cov = "^3.0.0"
Expand All @@ -39,8 +40,9 @@ black = "^22.1.0"
pylint = "^2.12.2"
autoflake = "^1.4"
strawberry-graphql = "^0.151.0"
libcst = "^0.4.9"
libcst = "^1.4.0"
requests = "^2.28.1"
pytest-snapshot = "^0.9.0"

[tool.poetry.extras]
watch = ["watchdog"]
Expand All @@ -51,12 +53,6 @@ merge = ["libcst"]
[tool.poetry.scripts]
turms = "turms.cli.main:cli"


[tool.poetry.group.dev.dependencies]
libcst = "^0.4.9"
ruff = "^0.0.257"
pytest-snapshot = "^0.9.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Expand Down
16 changes: 8 additions & 8 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def test_run_gen_multiple(tmp_path):
)

result = runner.invoke(cli, ["gen"])
assert result.exit_code == 0
assert result.exit_code == 0, result.output


def test_run_gen_display_errors(tmp_path):
Expand All @@ -75,7 +75,7 @@ def test_run_gen_display_errors(tmp_path):
shutil.copytree(country_documents, os.path.join(graphql_dir, "countries"))

result = runner.invoke(cli, ["gen"])
assert result.exit_code == 1
assert result.exit_code == 1, result.output
assert "*.graphql" in result.output


Expand All @@ -97,7 +97,7 @@ def test_run_gen_multiple_but_one(tmp_path):
shutil.copytree(country_documents, os.path.join(graphql_dir, "countries"))

result = runner.invoke(cli, ["gen", "countries"])
assert result.exit_code == 0
assert result.exit_code == 0, result.output


def test_run_download(tmp_path):
Expand All @@ -112,7 +112,7 @@ def test_run_download(tmp_path):
result = runner.invoke(cli, ["download"])

assert os.path.exists(os.path.join(td, "default.schema.graphql"))
assert result.exit_code == 0
assert result.exit_code == 0, result.output


def test_run_download_multiple(tmp_path):
Expand All @@ -133,7 +133,7 @@ def test_run_download_multiple(tmp_path):
)

result = runner.invoke(cli, ["download"])
assert result.exit_code == 0
assert result.exit_code == 0, result.output
assert os.path.exists(
os.path.join(td, "countries.schema.graphql")
), "countries schema not found"
Expand All @@ -151,7 +151,7 @@ def test_run_init(tmp_path):
result = runner.invoke(cli, ["init"])

assert os.path.exists(os.path.join(td, "graphql.config.yaml"))
assert result.exit_code == 0
assert result.exit_code == 0, result.output


def test_run_error_code(tmp_path):
Expand All @@ -167,7 +167,7 @@ def test_run_error_code(tmp_path):
shutil.copytree(d, os.path.join(td, "graphql"))

result = runner.invoke(cli, ["gen"])
assert result.exit_code == 1
assert result.exit_code == 1, result.output


def test_run_no_error_code(tmp_path):
Expand All @@ -183,4 +183,4 @@ def test_run_no_error_code(tmp_path):
shutil.copytree(d, os.path.join(td, "graphql"))

result = runner.invoke(cli, ["gen"])
assert result.exit_code == 0
assert result.exit_code == 0, result.output
35 changes: 35 additions & 0 deletions tests/test_countries_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import ast

from .utils import build_relative_glob, unit_test_with
from turms.config import GeneratorConfig
from turms.run import generate_ast
from turms.plugins.enums import EnumsPlugin
from turms.plugins.inputs import InputsPlugin
from turms.plugins.fragments import FragmentsPlugin
from turms.plugins.operations import OperationsPlugin
from turms.stylers.default import DefaultStyler
from turms.run import generate_ast


def test_complex_operations(countries_schema):
config = GeneratorConfig(
pydantic_version="v1",
documents=build_relative_glob("/documents/countries/**.graphql"),
)

generated_ast = generate_ast(
config,
countries_schema,
stylers=[DefaultStyler()],
plugins=[
EnumsPlugin(),
InputsPlugin(),
FragmentsPlugin(),
OperationsPlugin(),
],
)

md = ast.Module(body=generated_ast, type_ignores=[])
generated = ast.unparse(ast.fix_missing_locations(md))
unit_test_with(generated_ast, "Countries(countries=[])")
assert "from enum import Enum" in generated, "EnumPlugin not working"
87 changes: 87 additions & 0 deletions tests/test_documentation_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

from .utils import build_relative_glob, unit_test_with
from turms.config import GeneratorConfig
from turms.run import generate_ast
from turms.plugins.enums import EnumsPlugin
from turms.plugins.inputs import InputsPlugin
from turms.plugins.fragments import FragmentsPlugin
from turms.plugins.operations import OperationsPlugin
from turms.plugins.funcs import (
FunctionDefinition,
FuncsPlugin,
FuncsPluginConfig,
)
from turms.stylers.snake_case import SnakeCaseStyler
from turms.stylers.capitalize import CapitalizeStyler
from turms.run import generate_ast


def test_documentatoin(nested_input_schema):
config = GeneratorConfig(
pydantic_version="v1",
documents=build_relative_glob("/documents/documentation/*.graphql"),
)
generated_ast = generate_ast(
config,
nested_input_schema,
stylers=[CapitalizeStyler(), SnakeCaseStyler()],
plugins=[
EnumsPlugin(),
InputsPlugin(),
FragmentsPlugin(),
OperationsPlugin(),
FuncsPlugin(
config=FuncsPluginConfig(
definitions=[
FunctionDefinition(
type="mutation",
use="mocks.aquery",
is_async=False,
),
FunctionDefinition(
type="mutation",
use="mocks.aquery",
is_async=True,
),
]
),
),
],
)

unit_test_with(generated_ast, "")


def test_default_input_funcs(nested_input_schema):
config = GeneratorConfig(
documents=build_relative_glob("/documents/inputs_default/*.graphql"),
)
generated_ast = generate_ast(
config,
nested_input_schema,
stylers=[CapitalizeStyler(), SnakeCaseStyler()],
plugins=[
EnumsPlugin(),
InputsPlugin(),
FragmentsPlugin(),
OperationsPlugin(),
FuncsPlugin(
config=FuncsPluginConfig(
definitions=[
FunctionDefinition(
type="mutation",
use="mocks.aquery",
is_async=False,
),
FunctionDefinition(
type="mutation",
use="mocks.aquery",
is_async=True,
),
]
),
),
],
)

unit_test_with(generated_ast, "")
29 changes: 29 additions & 0 deletions tests/test_forward_reference_to_interface_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@


from .utils import (
unit_test_with,
)
from turms.config import GeneratorConfig
from turms.run import generate_ast
from turms.plugins.objects import ObjectsPlugin
from turms.run import generate_ast
from turms.stylers.default import DefaultStyler


def test_generation(forward_reference_to_interface_schema):
config = GeneratorConfig(
pydantic_version="v1",

)

generated_ast = generate_ast(

config,
forward_reference_to_interface_schema,
stylers=[DefaultStyler()],
plugins=[
ObjectsPlugin(),
],
)

unit_test_with(generated_ast, "")
2 changes: 1 addition & 1 deletion tests/test_introspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Schema(BaseModel):


def test_introspect():
return build_client_schema(
build_client_schema(
load_introspection_from_url("https://countries.trevorblades.com/")
)

Expand Down
4 changes: 2 additions & 2 deletions tests/test_load_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def test_load_single_config():


def test_failure_on_wrong_scalars():
with pytest.raises(pydantic.error_wrappers.ValidationError):
with pytest.raises(pydantic.ValidationError):
GeneratorConfig(scalar_definitions={"X": "zzzzz"})
with pytest.raises(pydantic.error_wrappers.ValidationError):
with pytest.raises(pydantic.ValidationError):
GeneratorConfig(scalar_definitions={"X": 15})


Expand Down
2 changes: 1 addition & 1 deletion tests/test_non_implemented_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_generation_ok(unimplemented_interface_schema):
],
)

unit_test_with(generated_ast, "Foo(forward=Ref(id=3))")
unit_test_with(generated_ast, "Foo(forward=Ref(id='3'))")


def test_generation_raises(unimplemented_interface_schema):
Expand Down
48 changes: 48 additions & 0 deletions tests/test_operations_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

from .utils import build_relative_glob, unit_test_with
from turms.config import GeneratorConfig
from turms.run import generate_ast
from turms.plugins.enums import EnumsPlugin
from turms.plugins.inputs import InputsPlugin
from turms.plugins.operations import OperationsPlugin, OperationsPluginConfig
from turms.plugins.fragments import FragmentsPlugin
from turms.stylers.default import DefaultStyler
from turms.run import generate_ast


def test_extra_arguments(arkitekt_schema):
config = GeneratorConfig(
pydantic_version="v1",
documents=build_relative_glob("/documents/arkitekt/**/*.graphql"),
scalar_definitions={
"uuid": "str",
"Callback": "str",
"Any": "typing.Any",
"QString": "str",
"UUID": "pydantic.UUID4",
},
)

generated_ast = generate_ast(
config,
arkitekt_schema,
stylers=[DefaultStyler()],
plugins=[
EnumsPlugin(),
InputsPlugin(),
FragmentsPlugin(),
OperationsPlugin(
config=OperationsPluginConfig(
subscription_bases=["mocks.ExtraOnOperations"],
mutation_bases=["mocks.ExtraOnOperations"],
query_bases=["mocks.ExtraOnOperations"],
arguments_bases=["mocks.ExtraArguments"],
)
),
],
)

unit_test_with(
generated_ast,
"ReturnPortInput(child=ReturnPortInput(bound=BoundTypeInput.AGENT))",
)
7 changes: 7 additions & 0 deletions turms/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ def log(message, level):
live.update(panel)

if raised_exceptions:
# print traceback of first exception
for e in raised_exceptions:
try:
raise e
except Exception:
get_console().print_exception()

raise click.ClickException(
"One or more projects failed to generate. First error"
) from raised_exceptions[0]
Expand Down
Loading
Loading