Fixed the messy auto-generated serde logic in the library
@mridang đang làm issue này rồi.
Từ ngày 7/5/2025.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
Title: Refactor Python SDK Models to Standardize Pydantic Usage via ZitadelModel Base Class
Description:
This initiative will refactor the Python SDK's model classes, which already use Pydantic, to standardize their implementation, remove boilerplate, and leverage Pydantic V2 features more directly via a common ZitadelModel base class.
Problem:
The current Python models, while using Pydantic, contain generated boilerplate code:
- Custom
to_json,from_json,to_dict,from_dictmethods that partially replicate or deviate from standard Pydantic V2 functionality. - An
additional_propertiesfield and associated logic (__properties) that may not be necessary and complicates parsing/serialization. - Lack of a common base class for shared configuration and helper methods.
This leads to unnecessary code duplication and potential inconsistencies with idiomatic Pydantic V2 usage.
Impact:
Refactoring will result in:
- Slimmer, cleaner, and more maintainable Pydantic models.
- Consistent use of Pydantic V2's efficient
model_dump,model_dump_json,model_validate, andmodel_validate_jsonmethods. - Removal of potentially confusing or unnecessary custom serialization/deserialization logic and
additional_propertieshandling. - Improved developer experience.
Solution / Tasks:
1. Implement ZitadelModel Base Class:
Create a class ZitadelModel(BaseModel) that serves as the base for all SDK models. It should define the common Pydantic configuration and provide standardized serialization/deserialization methods.
Example zitadel_model.py:
from pydantic import BaseModel, ConfigDict
from typing import Any, Dict, Optional, TypeVar, Type
# Use typing_extensions for Self if Python < 3.11
from typing_extensions import Self
# Define a TypeVar for the class type
T = TypeVar('T', bound='ZitadelModel')
class ZitadelModel(BaseModel):
model_config = ConfigDict(
populate_by_name=True, # Allow using JSON field names (aliases)
validate_assignment=True, # Validate fields on assignment
protected_namespaces=(), # Standard Pydantic setting
extra='ignore', # Ignore unexpected fields in JSON input
# Use 'forbid' to raise an error instead
)
def to_zitadel_dict(self, by_alias: bool = True, exclude_unset: bool = True, exclude_none: bool = False) -> Dict[str, Any]:
"""Standard dictionary representation using Pydantic V2."""
return self.model_dump(
mode='python',
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_none=exclude_none
)
def to_zitadel_json(self, by_alias: bool = True, exclude_unset: bool = True, exclude_none: bool = False) -> str:
"""Standard JSON representation using Pydantic V2."""
return self.model_dump_json(
by_alias=by_alias,
exclude_unset=exclude_unset,
exclude_none=exclude_none
)
@classmethod
def from_zitadel_dict(cls: Type[T], obj: Optional[Dict[str, Any]]) -> Optional[T]:
"""Create an instance from a dictionary using Pydantic V2."""
if obj is None:
return None
return cls.model_validate(obj)
@classmethod
def from_zitadel_json(cls: Type[T], json_str: str) -> Optional[T]:
"""Create an instance from a JSON string using Pydantic V2."""
return cls.model_validate_json(json_str)
# Optional: Keep a consistent debug string representation if needed
def to_str(self) -> str:
"""Returns the string representation of the model using alias for debugging."""
import pprint
return pprint.pformat(self.model_dump(by_alias=True))
2. Update OpenAPI Generator Templates for Python Models:
Modify the OpenAPI Generator templates for Python models to:
- Make generated models inherit from
ZitadelModel. - Define model fields using standard Python type hints (
Optional,List, etc.) and Pydantic'sFieldfor aliases (e.g.,user_id: Optional[str] = Field(default=None, alias="userId")). - Remove the
additional_propertiesfield and the__propertiesclass variable. - Remove the custom
to_json,from_json,to_dict,from_dictmethods from the generated models (they will be inherited). - Ensure enums are generated as standard Python
enum.Enumclasses, which Pydantic handles well.
Target structure for a generated model (e.g., user_service_user.py):
from __future__ import annotations
from typing import List, Optional
from pydantic import Field
# Assuming these imports point to other refactored ZitadelModel children or Enums
from .zitadel_model import ZitadelModel
from .user_service_details import UserServiceDetails
from .user_service_human_user import UserServiceHumanUser
from .user_service_machine_user import UserServiceMachineUser
from .user_service_user_state import UserServiceUserState # Assuming this is an Enum
class UserServiceUser(ZitadelModel):
"""
UserServiceUser (Refactored)
"""
user_id: Optional[str] = Field(default=None, alias="userId")
details: Optional[UserServiceDetails] = None
state: Optional[UserServiceUserState] = Field(default=UserServiceUserState.USER_STATE_UNSPECIFIED)
username: Optional[str] = None
login_names: Optional[List[str]] = Field(default=None, alias="loginNames")
preferred_login_name: Optional[str] = Field(default=None, alias="preferredLoginName")
human: Optional[UserServiceHumanUser] = None
machine: Optional[UserServiceMachineUser] = None
# No custom methods, no additional_properties, no __properties
3. Update SDK Code to Use New Model Methods:
- Search the SDK codebase (e.g.,
api_client.py, service files) for any remaining calls to the old customto_json,from_json,to_dict,from_dictmethods. - Replace them with calls to the standardized methods inherited from
ZitadelModel(e.g.,instance.to_zitadel_json(),ModelClass.from_zitadel_json(data)). - Ensure the API client uses these methods correctly when preparing request bodies and parsing responses.
Expected Outcomes:
- Python SDK models are significantly leaner, inheriting configuration and core ser/des methods from
ZitadelModel. - Serialization and deserialization consistently use Pydantic V2's
model_dump*andmodel_validate*methods. - Boilerplate related to custom ser/des methods and
additional_propertiesis removed from models. - The SDK aligns better with idiomatic Pydantic V2 usage.
- Functional equivalence for JSON-based API interactions is preserved.
Additional Notes:
- Dependencies: Ensure
pydantic>=2.0is specified. - Null Handling: Review the desired behavior for omitting fields vs. including explicit
null. Theexclude_unset=True(default in example) andexclude_none=False(default in example) parameters in the base class methods control this. Adjust as needed. - Testing: Thorough testing of serialization/deserialization for various model types is essential.
extra='ignore'vs'forbid': Decide if unknown fields in incoming JSON should be silently ignored or raise a validation error.
- Ngôn ngữ chính
- Python
- Star
- 16
- Fork
- 3
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của zitadel/client-python
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
zitadel/client-python#125 ·
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 72/100
zitadel/client-python#140 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 52/100
zitadel/client-python#99 ·
-
Release SDK for V5 Đang mở
zitadel/client-python#80 · 1 người được giao ·
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
zitadel/client-python#78 ·
Tất cả issue của zitadel/client-python
Issue tương tự
-
triage/confirmed
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
agentscope-ai/agentscope#2775 ·
-
comp/desktop P3 type/bug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 92/100
NousResearch/hermes-agent#118866 ·
-
bug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
apache/cloudstack#14222 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100