Skip to content
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
19 changes: 19 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## 2025-05-08 "Metadata Field API Improvements & Bugfixes" - version 1.12.0

### Fixed
- Fixed validation errors in field creation and updating by changing the return type from `Field` to `FieldResponse` model

### Changed
- **Improved Metadata Field API (in `pythonik.specs.metadata.MetadataSpec`):**
- Renamed `create_metadata_field()` to `create_field()` for more consistent naming
- Renamed `update_metadata_field()` to `update_field()` for more consistent naming
- Renamed `delete_metadata_field()` to `delete_field()` for more consistent naming
- Return type now uses `FieldResponse` model instead of `Field` for more comprehensive metadata field information
- Added backward compatibility aliases for the old method names (will be removed in a future version)
- **Testing:**
- Updated all tests to use the new method names and return types
- Added tests to verify backward compatibility aliases work correctly

### Technical Details
This update fixes validation errors that occurred when creating and updating metadata fields by correctly using the `FieldResponse` model instead of `Field`, making the API work as expected. It also improves the metadata field management API with more consistent method naming while maintaining backward compatibility through aliases. The `FieldResponse` model provides the proper structure for the API responses, and the backward compatibility aliases ensure existing code continues to work correctly.

## 2025-05-08 "Metadata Field Management & Type Safety" - version 1.11.0

### Added
Expand Down
27 changes: 27 additions & 0 deletions pythonik/models/metadata/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,30 @@ class Field(_FieldConfigurable):
date_created: Optional[datetime] = None
date_modified: Optional[datetime] = None
mapped_field_name: Optional[str] = None

class FieldResponse(BaseModel):
auto_set: bool
date_created: datetime
date_modified: datetime
description: Optional[str] = None
external_id: Optional[str] = None
field_type: IconikFieldType
hide_if_not_set: bool
is_block_field: bool
is_warning_field: bool
label: str
mapped_field_name: Optional[str] = None
max_value: Optional[float] = None
min_value: Optional[float] = None
multi: bool
name: str
options: Optional[List[FieldOption]] = None
read_only: bool
representative: bool
required: bool
sortable: bool
source_url: Optional[HttpUrl] = None
use_as_facet: bool

class Config:
use_enum_values = True
88 changes: 79 additions & 9 deletions pythonik/specs/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
CreateViewRequest,
UpdateViewRequest,
)
from pythonik.models.metadata.view_responses import ViewResponse, ViewListResponse
from pythonik.models.metadata.view_responses import (
ViewResponse,
ViewListResponse,
)
from pythonik.models.mutation.metadata.mutate import (
UpdateMetadata,
UpdateMetadataResponse,
)
from pythonik.models.metadata.fields import Field, FieldCreate, FieldUpdate
from pythonik.models.metadata.fields import FieldCreate, FieldUpdate, FieldResponse
from pythonik.specs.base import Spec
from typing import Literal, Union, Dict, Any, List

Expand Down Expand Up @@ -401,7 +404,7 @@ def delete_view(self, view_id: str, **kwargs) -> Response:
# Metadata Field Management
# -------------------------

def create_metadata_field(
def create_field(
self,
field_data: FieldCreate,
exclude_defaults: bool = True,
Expand All @@ -415,15 +418,16 @@ def create_metadata_field(
**kwargs: Additional kwargs to pass to the request.

Returns:
Response: The created metadata field.
Response: An object containing the HTTP response and a `data` attribute
with a `FieldResponse` model instance on success, or `None` on error.
"""
json_data = self._prepare_model_data(
field_data, exclude_defaults=exclude_defaults
)
resp = self._post(FIELDS_BASE_PATH, json=json_data, **kwargs)
return self.parse_response(resp, Field)
return self.parse_response(resp, FieldResponse)

def update_metadata_field(
def update_field(
self,
field_name: str,
field_data: FieldUpdate,
Expand All @@ -439,16 +443,17 @@ def update_metadata_field(
**kwargs: Additional kwargs to pass to the request.

Returns:
Response: The updated metadata field.
Response: An object containing the HTTP response and a `data` attribute
with a `FieldResponse` model instance on success, or `None` on error.
"""
json_data = self._prepare_model_data(
field_data, exclude_defaults=exclude_defaults
)
endpoint = FIELD_BY_NAME_PATH.format(field_name=field_name)
resp = self._put(endpoint, json=json_data, **kwargs)
return self.parse_response(resp, Field)
return self.parse_response(resp, FieldResponse)

def delete_metadata_field(
def delete_field(
self,
field_name: str,
**kwargs,
Expand All @@ -465,3 +470,68 @@ def delete_metadata_field(
endpoint = FIELD_BY_NAME_PATH.format(field_name=field_name)
resp = self._delete(endpoint, **kwargs)
return self.parse_response(resp)

# Backward compatibility aliases
# ------------------------------

def create_metadata_field(
self,
field_data: FieldCreate,
exclude_defaults: bool = True,
**kwargs,
) -> Response:
"""Create a new metadata field (deprecated, use create_field instead).

This method is kept for backward compatibility and will be removed in a future version.

Args:
field_data: The data for the new field.
exclude_defaults: Whether to exclude default values when dumping Pydantic models.
**kwargs: Additional kwargs to pass to the request.

Returns:
Response: An object containing the HTTP response and a `data` attribute
with a `FieldResponse` model instance on success, or `None` on error.
"""
return self.create_field(field_data, exclude_defaults, **kwargs)

def update_metadata_field(
self,
field_name: str,
field_data: FieldUpdate,
exclude_defaults: bool = True,
**kwargs,
) -> Response:
"""Update an existing metadata field by its name (deprecated, use update_field instead).

This method is kept for backward compatibility and will be removed in a future version.

Args:
field_name: The name of the field to update.
field_data: The data to update the field with.
exclude_defaults: Whether to exclude default values when dumping Pydantic models.
**kwargs: Additional kwargs to pass to the request.

Returns:
Response: An object containing the HTTP response and a `data` attribute
with a `FieldResponse` model instance on success, or `None` on error.
"""
return self.update_field(field_name, field_data, exclude_defaults, **kwargs)

def delete_metadata_field(
self,
field_name: str,
**kwargs,
) -> Response:
"""Delete a metadata field by its name (deprecated, use delete_field instead).

This method is kept for backward compatibility and will be removed in a future version.

Args:
field_name: The name of the field to delete.
**kwargs: Additional kwargs to pass to the request.

Returns:
Response: An empty response, expecting HTTP 204 No Content on success.
"""
return self.delete_field(field_name, **kwargs)
Loading