Skip to content

Refactored code structure in next-api #45

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

Merged
merged 8 commits into from
Aug 19, 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
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Set up Python 3.11
- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.12"
- name: Install pypa/build
run: >-
python -m
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v2
Expand Down
14 changes: 7 additions & 7 deletions ariadne_graphql_modules/next/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@
)
from .deferredtype import deferred
from .description import get_description_node
from .enumtype import (
from .graphql_enum_type import (
GraphQLEnum,
GraphQLEnumModel,
create_graphql_enum_model,
graphql_enum,
)
from .executable_schema import make_executable_schema
from .idtype import GraphQLID
from .inputtype import GraphQLInput, GraphQLInputModel
from .objecttype import GraphQLObject, GraphQLObjectModel, object_field
from .graphql_input import GraphQLInput, GraphQLInputModel
from .graphql_object import GraphQLObject, GraphQLObjectModel, object_field
from .roots import ROOTS_NAMES, merge_root_nodes
from .scalartype import GraphQLScalar, GraphQLScalarModel
from .graphql_scalar import GraphQLScalar, GraphQLScalarModel
from .sort import sort_schema_document
from .uniontype import GraphQLUnion, GraphQLUnionModel
from .graphql_union import GraphQLUnion, GraphQLUnionModel
from .value import get_value_from_node, get_value_node
from .interfacetype import GraphQLInterface, GraphQLInterfaceModel
from .subscriptiontype import GraphQLSubscription, GraphQLSubscriptionModel
from .graphql_interface import GraphQLInterface, GraphQLInterfaceModel
from .graphql_subscription import GraphQLSubscription, GraphQLSubscriptionModel

__all__ = [
"GraphQLEnum",
Expand Down
101 changes: 49 additions & 52 deletions ariadne_graphql_modules/next/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,25 @@ class GraphQLType:
__abstract__: bool = True

@classmethod
def __get_graphql_name__(cls) -> "str":
if getattr(cls, "__graphql_name__", None):
return cls.__graphql_name__
def __get_graphql_name__(cls) -> str:
name = getattr(cls, "__graphql_name__", None)
if name:
return name

name_mappings = [
("GraphQLEnum", "Enum"),
("GraphQLInput", "Input"),
("GraphQLScalar", ""),
("Scalar", ""),
("GraphQL", ""),
("Type", ""),
("GraphQLType", ""),
]

name = cls.__name__
if name.endswith("GraphQLEnum"):
# 'UserLevelGraphQLEnum' will produce the 'UserLevelEnum' name
return f"{name[:-11]}Enum" or name
if name.endswith("GraphQLInput"):
# 'UserGraphQLInput' will produce the 'UserInput' name
return f"{name[:-11]}Input" or name
if name.endswith("GraphQLScalar"):
# 'DateTimeGraphQLScalar' will produce the 'DateTime' name
return name[:-13] or name
if name.endswith("Scalar"):
# 'DateTimeLScalar' will produce the 'DateTime' name
return name[:-6] or name
if name.endswith("GraphQL"):
# 'UserGraphQL' will produce the 'User' name
return name[:-7] or name
if name.endswith("Type"):
# 'UserType' will produce the 'User' name
return name[:-4] or name
if name.endswith("GraphQLType"):
# 'UserGraphQLType' will produce the 'User' name
return name[:-11] or name
for suffix, replacement in name_mappings:
if name.endswith(suffix):
return name[: -len(suffix)] + replacement

return name

Expand All @@ -48,8 +41,8 @@ def __get_graphql_model__(cls, metadata: "GraphQLMetadata") -> "GraphQLModel":

@classmethod
def __get_graphql_types__(
cls, metadata: "GraphQLMetadata"
) -> Iterable["GraphQLType"]:
cls, _: "GraphQLMetadata"
) -> Iterable[Union[Type["GraphQLType"], Type[Enum]]]:
"""Returns iterable with GraphQL types associated with this type"""
return [cls]

Expand All @@ -60,10 +53,6 @@ class GraphQLModel:
ast: TypeDefinitionNode
ast_type: Type[TypeDefinitionNode]

def __init__(self, name: str, ast: TypeDefinitionNode):
self.name = name
self.ast = ast

def bind_to_schema(self, schema: GraphQLSchema):
pass

Expand All @@ -76,37 +65,45 @@ class GraphQLMetadata:
default_factory=dict
)

def get_data(self, type: Union[Type[GraphQLType], Type[Enum]]) -> Any:
def get_data(self, graphql_type: Union[Type[GraphQLType], Type[Enum]]) -> Any:
try:
return self.data[type]
return self.data[graphql_type]
except KeyError as e:
raise KeyError(f"No data is set for '{type}'.") from e
raise KeyError(f"No data is set for '{graphql_type}'.") from e

def set_data(self, type: Union[Type[GraphQLType], Type[Enum]], data: Any) -> Any:
self.data[type] = data
def set_data(
self, graphql_type: Union[Type[GraphQLType], Type[Enum]], data: Any
) -> Any:
self.data[graphql_type] = data
return data

def get_graphql_model(
self, type: Union[Type[GraphQLType], Type[Enum]]
self, graphql_type: Union[Type[GraphQLType], Type[Enum]]
) -> GraphQLModel:
if type not in self.models:
if hasattr(type, "__get_graphql_model__"):
self.models[type] = type.__get_graphql_model__(self)
elif issubclass(type, Enum):
from .enumtype import create_graphql_enum_model

self.models[type] = create_graphql_enum_model(type)
if graphql_type not in self.models:
if hasattr(graphql_type, "__get_graphql_model__"):
self.models[graphql_type] = graphql_type.__get_graphql_model__(self)
elif issubclass(graphql_type, Enum):
from .graphql_enum_type import ( # pylint: disable=R0401,C0415
create_graphql_enum_model,
)

self.models[graphql_type] = create_graphql_enum_model(graphql_type)
else:
raise ValueError(f"Can't retrieve GraphQL model for '{type}'.")
raise ValueError(f"Can't retrieve GraphQL model for '{graphql_type}'.")

return self.models[type]
return self.models[graphql_type]

def set_graphql_name(self, type: Union[Type[GraphQLType], Type[Enum]], name: str):
self.names[type] = name
def set_graphql_name(
self, graphql_type: Union[Type[GraphQLType], Type[Enum]], name: str
):
self.names[graphql_type] = name

def get_graphql_name(self, type: Union[Type[GraphQLType], Type[Enum]]) -> str:
if type not in self.names:
model = self.get_graphql_model(type)
self.set_graphql_name(type, model.name)
def get_graphql_name(
self, graphql_type: Union[Type[GraphQLType], Type[Enum]]
) -> str:
if graphql_type not in self.names:
model = self.get_graphql_model(graphql_type)
self.set_graphql_name(graphql_type, model.name)

return self.names[type]
return self.names[graphql_type]
30 changes: 8 additions & 22 deletions ariadne_graphql_modules/next/convert_name.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
def convert_python_name_to_graphql(python_name: str) -> str:
final_name = ""
for i, c in enumerate(python_name):
if not i:
final_name += c.lower()
else:
if c == "_":
continue
if python_name[i - 1] == "_":
final_name += c.upper()
else:
final_name += c.lower()

return final_name
components = python_name.split("_")
return components[0].lower() + "".join(x.capitalize() for x in components[1:])


def convert_graphql_name_to_python(graphql_name: str) -> str:
final_name = ""
for i, c in enumerate(graphql_name.lower()):
if not i:
final_name += c
python_name = ""
for c in graphql_name:
if c.isupper() or c.isdigit():
python_name += "_" + c.lower()
else:
if final_name[-1] != "_" and (c != graphql_name[i] or c.isdigit()):
final_name += "_"
final_name += c

return final_name
python_name += c
return python_name.lstrip("_")
28 changes: 21 additions & 7 deletions ariadne_graphql_modules/next/deferredtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,38 @@ def deferred(module_path: str) -> DeferredTypeData:
if not module_path.startswith("."):
return DeferredTypeData(module_path)

frame = sys._getframe(2)
frame = _get_caller_frame()
current_package = cast(str, frame.f_globals["__package__"])

module_path_suffix = _resolve_module_path_suffix(module_path, current_package)

return DeferredTypeData(module_path_suffix)


def _get_caller_frame():
"""Retrieve the caller's frame and ensure it's within a valid context."""
frame = sys._getframe(2) # pylint: disable=protected-access
if not frame:
raise RuntimeError(
"'deferred' can't be called outside of class's attribute's "
"definition context."
"'deferred' must be called within a class attribute definition context."
)
return frame


def _resolve_module_path_suffix(module_path: str, current_package: str) -> str:
"""Resolve the full module path by handling relative imports."""
module_path_suffix = module_path[1:] # Remove initial dot
current_package = cast(str, frame.f_globals["__package__"])
packages = current_package.split(".")

while module_path_suffix.startswith(".") and packages:
module_path_suffix = module_path_suffix[1:] # Remove dot
packages = packages[:-1]
packages.pop()

if not packages:
raise ValueError(
f"'{module_path}' points outside of the '{current_package}' package."
)

package = ".".join(packages)
return DeferredTypeData(f"{package}.{module_path_suffix}")
return (
f"{'.'.join(packages)}.{module_path_suffix}" if packages else module_path_suffix
)
Loading
Loading