Fixes: 1) Addressed missing or incorrect imports and type hints with `# ty:ignore` markers; 2) Fixed search queryset error handling in filters module; 3) Resolved issues in viewsets with updated `@action` method usage. Extra: Removed unused classes and dependencies (e.g., `BaseMutation`, `basedpyright`, and related packages); streamlined GraphQL mutation implementations; cleaned up unused arguments in model `save` methods.
118 lines
3.8 KiB
Python
118 lines
3.8 KiB
Python
import re
|
|
from typing import Any, Collection, MutableMapping
|
|
|
|
from django.utils.module_loading import import_string
|
|
from drf_orjson_renderer.renderers import ORJSONRenderer
|
|
|
|
from evibes.settings.base import MIDDLEWARE
|
|
from evibes.settings.drf import JSON_UNDERSCOREIZE
|
|
|
|
camelize_re = re.compile(r"[a-z0-9]?_[a-z0-9]")
|
|
|
|
|
|
def underscore_to_camel(match):
|
|
group = match.group()
|
|
if len(group) == 3:
|
|
return group[0] + group[2].upper()
|
|
else:
|
|
return group[1].upper()
|
|
|
|
|
|
def _camelize_key(key: str) -> str:
|
|
if not isinstance(key, str) or not key:
|
|
return key
|
|
if "_" not in key:
|
|
return key
|
|
parts = key.split("_")
|
|
first = parts[0]
|
|
rest = [p.capitalize() if p else "" for p in parts[1:]]
|
|
return first + "".join(rest)
|
|
|
|
|
|
def camelize(obj: Any) -> Any:
|
|
if isinstance(obj, dict):
|
|
return {
|
|
(_camelize_key(k) if isinstance(k, str) else k): camelize(v)
|
|
for k, v in obj.items()
|
|
}
|
|
if isinstance(obj, list):
|
|
return [camelize(v) for v in obj]
|
|
if isinstance(obj, tuple):
|
|
return tuple(camelize(v) for v in obj)
|
|
return obj
|
|
|
|
|
|
def camelize_serializer_fields(result, generator, request, public):
|
|
ignore_fields: Collection[Any] = JSON_UNDERSCOREIZE.get("ignore_fields", ())
|
|
ignore_keys: Collection[Any] = JSON_UNDERSCOREIZE.get("ignore_keys", ())
|
|
|
|
def has_middleware_installed():
|
|
try:
|
|
from evibes.middleware import CamelCaseMiddleWare
|
|
except ImportError:
|
|
return False
|
|
|
|
return any(
|
|
isinstance(m, type) and issubclass(m, CamelCaseMiddleWare)
|
|
for m in map(import_string, MIDDLEWARE)
|
|
)
|
|
|
|
def camelize_str(key: str) -> str:
|
|
new_key = re.sub(camelize_re, underscore_to_camel, key) if "_" in key else key
|
|
if key in ignore_keys or new_key in ignore_keys:
|
|
return key
|
|
return new_key
|
|
|
|
def camelize_component(
|
|
schema: MutableMapping, name: str | None = None
|
|
) -> MutableMapping:
|
|
if name is not None and (
|
|
name in ignore_fields or camelize_str(name) in ignore_fields
|
|
):
|
|
return schema
|
|
elif schema.get("type") == "object":
|
|
if "properties" in schema:
|
|
schema["properties"] = {
|
|
camelize_str(field_name): camelize_component(
|
|
field_schema, field_name
|
|
)
|
|
for field_name, field_schema in schema["properties"].items()
|
|
}
|
|
if "required" in schema:
|
|
schema["required"] = [
|
|
camelize_str(field) for field in schema["required"]
|
|
]
|
|
elif schema.get("type") == "array" and isinstance(
|
|
schema["items"], MutableMapping
|
|
):
|
|
camelize_component(schema["items"])
|
|
return schema
|
|
|
|
for (_, component_type), component in generator.registry._components.items():
|
|
if component_type == "schemas":
|
|
camelize_component(component.schema)
|
|
|
|
if has_middleware_installed():
|
|
for url_schema in result["paths"].values():
|
|
for method_schema in url_schema.values():
|
|
for parameter in method_schema.get("parameters", []):
|
|
parameter["name"] = camelize_str(parameter["name"])
|
|
|
|
return result
|
|
|
|
|
|
class CamelCaseRenderer(ORJSONRenderer):
|
|
def render(
|
|
self, data: Any, media_type: str | None = None, renderer_context: Any = None
|
|
) -> bytes: # ty:ignore[invalid-method-override]
|
|
if data is None:
|
|
return b""
|
|
|
|
ctx = renderer_context or {}
|
|
camelize_disabled = ctx.get("camelize", True) is False
|
|
payload = data if camelize_disabled else camelize(data)
|
|
|
|
return super().render(payload, media_type=media_type, renderer_context=ctx)
|
|
|
|
|
|
__all__ = ["CamelCaseRenderer", "camelize"]
|