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 functionality for introspection #73

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
42 changes: 34 additions & 8 deletions turms/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
scan_folder_for_single_config,
load_projects_from_configpath,
build_schema_from_schema_type,
build_introspection_from_schema_type
)
from .watch import stream_changes
from graphql import print_schema
from functools import wraps

import json
click.rich_click.USE_RICH_MARKUP = True

directory = os.getcwd()
Expand Down Expand Up @@ -259,32 +260,57 @@
@with_projects
@click.option(
"--out",
default=".schema.graphql",
default=None,
help="The output file extension (will be appended to the project name)",
)
@click.option(
"--dir",
default=None,
help="The output directory for the schema files (will default to the current working directory)",
)
def download(projects, out, dir):
@click.option(
"--format",
default="sdl",
help="The output format for the schema files (sdl or json)",
type=click.Choice(["sdl", "introspection"]),
)
def download(projects, out, dir, format):
"""Download the graphql projects schema as a sdl file"""



default_extensions = {
"sdl": ".schema.graphql",
"introspection": ".introspection.json",
}

out = out or default_extensions.get(format, ".schema.graphql")

try:
app_directory = dir or os.getcwd()
for key, project in projects.items():
filename = f"{key}{out}"
get_console().print(
f"Downloading schema for project {key} to {app_directory}/{filename}"
)
schema = build_schema_from_schema_type(
project.schema_url, allow_introspection=True
)
if format == "sdl":
schema = build_schema_from_schema_type(
project.schema_url, allow_introspection=True
)
output = print_schema(schema)

Check warning on line 301 in turms/cli/main.py

View check run for this annotation

Codecov / codecov/patch

turms/cli/main.py#L301

Added line #L301 was not covered by tests
else:
introspection = build_introspection_from_schema_type(
project.schema_url

Check warning on line 304 in turms/cli/main.py

View check run for this annotation

Codecov / codecov/patch

turms/cli/main.py#L304

Added line #L304 was not covered by tests
)
output = json.dumps(introspection, indent=2)


with open(os.path.join(app_directory, filename), "w") as f:
f.write(print_schema(schema))
f.write(output)

Check warning on line 311 in turms/cli/main.py

View check run for this annotation

Codecov / codecov/patch

turms/cli/main.py#L310-L311

Added lines #L310 - L311 were not covered by tests
except Exception as e:
raise click.ClickException(str(e)) from e


if __name__ == "__main__":
cli()
138 changes: 137 additions & 1 deletion turms/plugins/inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,145 @@
inputtype_bases: List[str] = ["pydantic.BaseModel"]
skip_underscore: bool = True
skip_unreferenced: bool = True
arguments_allow_population_by_field_name: bool = True

class Config:
env_prefix = "TURMS_PLUGINS_INPUTS_"


def generate_input_config_class(
graphQLType: GraphQLTypes,
config: GeneratorConfig,
plugin_config: InputsPluginConfig,
typename: str = None,
):
"""Generates the config class for a specific type

It will append the config class to the registry, and set the frozen
attribute for the class to True, if the freeze config is enabled and
the type appears in the freeze list.

It will also add config attributes to the class, if the type appears in
'additional_config' in the config file.

"""

config_fields = []

if config.freeze.enabled:
if graphQLType in config.freeze.types:
if config.freeze.exclude and typename in config.freeze.exclude:
pass
elif config.freeze.include and typename not in config.freeze.include:
pass

Check warning on line 63 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L59-L63

Added lines #L59 - L63 were not covered by tests
else:
config_fields.append(

Check warning on line 65 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L65

Added line #L65 was not covered by tests
ast.Assign(
targets=[ast.Name(id="frozen", ctx=ast.Store())],
value=ast.Constant(value=True),
)
)

if config.options.enabled:
if graphQLType in config.options.types:
if config.options.exclude and typename in config.options.exclude:
pass
elif config.options.include and typename not in config.options.include:
pass

Check warning on line 77 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L73-L77

Added lines #L73 - L77 were not covered by tests
else:
if config.options.allow_mutation is not None:
config_fields.append(

Check warning on line 80 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L79-L80

Added lines #L79 - L80 were not covered by tests
ast.Assign(
targets=[ast.Name(id="allow_mutation", ctx=ast.Store())],
value=ast.Constant(value=config.options.allow_mutation),
)
)

if config.options.extra is not None:
config_fields.append(

Check warning on line 88 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L87-L88

Added lines #L87 - L88 were not covered by tests
ast.Assign(
targets=[ast.Name(id="extra", ctx=ast.Store())],
value=ast.Constant(value=config.options.extra),
)
)

if config.options.validate_assignment is not None:
config_fields.append(

Check warning on line 96 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L95-L96

Added lines #L95 - L96 were not covered by tests
ast.Assign(
targets=[
ast.Name(id="validate_assignment", ctx=ast.Store())
],
value=ast.Constant(
value=config.options.validate_assignment
),
)
)

if (

Check warning on line 107 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L107

Added line #L107 was not covered by tests
config.options.allow_population_by_field_name is not None
or plugin_config.arguments_allow_population_by_field_name
):
config_fields.append(

Check warning on line 111 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L111

Added line #L111 was not covered by tests
ast.Assign(
targets=[
ast.Name(
id="allow_population_by_field_name", ctx=ast.Store()
)
],
value=ast.Constant(
value=config.options.allow_population_by_field_name
or plugin_config.arguments_allow_population_by_field_name
),
)
)

if config.options.orm_mode is not None:
config_fields.append(

Check warning on line 126 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L125-L126

Added lines #L125 - L126 were not covered by tests
ast.Assign(
targets=[ast.Name(id="orm_mode", ctx=ast.Store())],
value=ast.Constant(value=config.options.orm_mode),
)
)

if config.options.use_enum_values is not None:
config_fields.append(

Check warning on line 134 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L133-L134

Added lines #L133 - L134 were not covered by tests
ast.Assign(
targets=[ast.Name(id="use_enum_values", ctx=ast.Store())],
value=ast.Constant(value=config.options.use_enum_values),
)
)

if typename:
if typename in config.additional_config:
for key, value in config.additional_config[typename].items():
config_fields.append(

Check warning on line 144 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L143-L144

Added lines #L143 - L144 were not covered by tests
ast.Assign(
targets=[ast.Name(id=key, ctx=ast.Store())],
value=ast.Constant(value=value),
)
)

if len(config_fields) > 0:
config_fields.insert(

Check warning on line 152 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L152

Added line #L152 was not covered by tests
0,
ast.Expr(
value=ast.Str(s="A config class"),
),
)
if len(config_fields) > 0:
return [

Check warning on line 159 in turms/plugins/inputs.py

View check run for this annotation

Codecov / codecov/patch

turms/plugins/inputs.py#L159

Added line #L159 was not covered by tests
ast.ClassDef(
name="Config",
bases=[],
keywords=[],
body=config_fields,
decorator_list=[],
)
]
else:
return []


def generate_input_annotation(
type: GraphQLInputType,
parent: str,
Expand Down Expand Up @@ -236,7 +370,9 @@
decorator_list=[],
keywords=[],
body=fields
+ generate_config_class(GraphQLTypes.INPUT, config, typename=key),
+ generate_input_config_class(
GraphQLTypes.INPUT, config, plugin_config, typename=key
),
)
)

Expand Down
2 changes: 1 addition & 1 deletion turms/plugins/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class OperationsPluginConfig(PluginConfig):
operations_glob: Optional[str]
create_arguments: bool = True
extract_documentation: bool = True
arguments_allow_population_by_field_name: bool = False
arguments_allow_population_by_field_name: bool = True

class Config:
env_prefix = "TURMS_PLUGINS_OPERATIONS_"
Expand Down
39 changes: 39 additions & 0 deletions turms/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,45 @@
"""
return import_string(module_path)(**kwargs)

def build_introspection_from_schema_type(
schema: SchemaType
) -> GraphQLSchema:
"""Builds a schema from a project

Args:
project (GraphQLProject): The project

Returns:
GraphQLSchema: The schema
"""
if isinstance(schema, dict):
if len(schema.values()) == 1:
key, value = list(schema.items())[0]
return load_introspection_from_url(key, value.headers)

Check warning on line 247 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L244-L247

Added lines #L244 - L247 were not covered by tests

else:
# Multiple schemas, now we only support dsl
raise GenerationError("Multiple schemas not supported for introspection")

Check warning on line 251 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L251

Added line #L251 was not covered by tests

if isinstance(schema, list):
if len(schema) == 1:

Check warning on line 254 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L253-L254

Added lines #L253 - L254 were not covered by tests
# Only one schema, probably because of aesthetic reasons
return build_introspection_from_schema_type(

Check warning on line 256 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L256

Added line #L256 was not covered by tests
schema[0]
)

else:
raise GenerationError("Multiple schemas not supported for introspection")

Check warning on line 261 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L261

Added line #L261 was not covered by tests

if isinstance(schema, AnyHttpUrl):
return load_introspection_from_url(schema)

Check warning on line 264 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L263-L264

Added lines #L263 - L264 were not covered by tests

if isinstance(schema, str):
return load_introspection_from_url(schema)

Check warning on line 267 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L266-L267

Added lines #L266 - L267 were not covered by tests


raise GenerationError("Could not build introspection with type " + str(type(schema)))

Check warning on line 270 in turms/run.py

View check run for this annotation

Codecov / codecov/patch

turms/run.py#L270

Added line #L270 was not covered by tests


def build_schema_from_schema_type(
schema: SchemaType, allow_introspection: bool = False
Expand Down
4 changes: 3 additions & 1 deletion turms/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ def generate_typename_field(


def generate_config_class(
graphQLType: GraphQLTypes, config: GeneratorConfig, typename: str = None
graphQLType: GraphQLTypes,
config: GeneratorConfig,
typename: str = None,
):
"""Generates the config class for a specific type

Expand Down
Loading