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
2 changes: 1 addition & 1 deletion .github/workflows/codegen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
- ".github/workflows/codegen.yaml"

env:
GOLANGCI_LINT_VERSION: v2.6.2
GOLANGCI_LINT_VERSION: v2.9.0

permissions:
contents: read
Expand Down
2 changes: 2 additions & 0 deletions codegen/pkg/builder/intermediate_representation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type ClassDeclaration struct {
Fields []Property
// Description holds the description of the type
Description string
// AdditionalPropertiesType holds the value type for additional properties if enabled.
AdditionalPropertiesType string
}

type OneOfDeclaration struct {
Expand Down
39 changes: 28 additions & 11 deletions codegen/pkg/builder/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,31 +321,48 @@ func (b *Builder) genSchema(sp *base.SchemaProxy, name string) (string, []Writab

// createObject converts openapi schema into golang object.
func (b *Builder) createObject(schema *base.Schema, name string) (Writable, []Writable) {
if (schema.Properties == nil || schema.Properties.Len() == 0) &&
schema.AdditionalProperties != nil &&
((schema.AdditionalProperties.IsB() && schema.AdditionalProperties.B) ||
(schema.AdditionalProperties.IsA())) {
hasProperties := schema.Properties != nil && schema.Properties.Len() > 0
hasAdditionalProperties := schema.AdditionalProperties != nil &&
((schema.AdditionalProperties.IsB() && schema.AdditionalProperties.B) || schema.AdditionalProperties.IsA())

additionalPropertyType := ""
additionalTypes := []Writable{}
if hasAdditionalProperties {
additionalPropertyType = "typing.Any"
if schema.AdditionalProperties.IsA() {
var generatedType string
generatedType, additionalTypes = b.genSchema(schema.AdditionalProperties.A, name+"AdditionalProperty")
additionalPropertyType = generatedType
}
}

if !hasProperties && hasAdditionalProperties {
return &TypeAlias{
Comment: schemaDoc(name, schema),
Name: name,
Type: "dict[typing.Any, typing.Any]",
}, nil
Type: "dict[str, " + additionalPropertyType + "]",
}, additionalTypes
}

fields, additionalTypes := b.createFields(schema.Properties, name, schema.Required)
fields, fieldTypes := b.createFields(schema.Properties, name, schema.Required)
additionalTypes = append(additionalTypes, fieldTypes...)

return &ClassDeclaration{
Description: schemaDoc(name, schema),
Name: name,
Type: "class",
Fields: fields,
Description: schemaDoc(name, schema),
Name: name,
Type: "class",
Fields: fields,
AdditionalPropertiesType: additionalPropertyType,
}, additionalTypes
}

// createFields returns list of fields for openapi schema properties.
func (b *Builder) createFields(properties *orderedmap.Map[string, *base.SchemaProxy], name string, required []string) ([]Property, []Writable) {
fields := []Property{}
types := []Writable{}
if properties == nil {
return fields, types
}

for property, schema := range properties.FromOldest() {
typeName, moreTypes := b.genSchema(schema, name+strcase.ToCamel(property))
Expand Down
64 changes: 49 additions & 15 deletions codegen/pkg/builder/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,37 @@ func (c *ClassDeclaration) String() string {
fmt.Fprint(buf, indent(1, ft.String()))
}
}
if c.AdditionalPropertiesType != "" {
fmt.Fprint(buf, "\n")
fmt.Fprint(buf, "\tmodel_config = pydantic.ConfigDict(extra=\"allow\")\n")
fmt.Fprint(buf, "\n")
fmt.Fprint(buf, "\t@pydantic.model_validator(mode=\"before\")\n")
fmt.Fprint(buf, "\t@classmethod\n")
fmt.Fprint(buf, "\tdef _merge_additional_properties(cls, values: typing.Any) -> typing.Any:\n")
fmt.Fprint(buf, "\t\tif not isinstance(values, dict):\n")
fmt.Fprint(buf, "\t\t\treturn values\n")
fmt.Fprint(buf, "\n")
fmt.Fprint(buf, "\t\tadditional = values.get(\"additional_properties\")\n")
fmt.Fprint(buf, "\t\tif not isinstance(additional, dict):\n")
fmt.Fprint(buf, "\t\t\treturn values\n")
fmt.Fprint(buf, "\n")
fmt.Fprint(buf, "\t\tmerged = dict(additional)\n")
fmt.Fprint(buf, "\t\tfor key, value in values.items():\n")
fmt.Fprint(buf, "\t\t\tif key != \"additional_properties\":\n")
fmt.Fprint(buf, "\t\t\t\tmerged[key] = value\n")
fmt.Fprint(buf, "\n")
fmt.Fprint(buf, "\t\treturn merged\n")
fmt.Fprint(buf, "\n")
fmt.Fprint(buf, "\t@property\n")
fmt.Fprintf(buf, "\tdef additional_properties(self) -> dict[str, %s]:\n", c.AdditionalPropertiesType)
fmt.Fprint(buf, "\t\tif self.model_extra is None:\n")
fmt.Fprint(buf, "\t\t\tobject.__setattr__(self, \"__pydantic_extra__\", {})\n")
fmt.Fprintf(buf, "\t\treturn typing.cast(dict[str, %s], self.model_extra)\n", c.AdditionalPropertiesType)
fmt.Fprint(buf, "\n")
fmt.Fprint(buf, "\t@additional_properties.setter\n")
fmt.Fprintf(buf, "\tdef additional_properties(self, value: dict[str, %s]) -> None:\n", c.AdditionalPropertiesType)
fmt.Fprint(buf, "\t\tobject.__setattr__(self, \"__pydantic_extra__\", dict(value))\n")
}
fmt.Fprint(buf, "\n")
return buf.String()
}
Expand All @@ -68,21 +99,7 @@ func (p *Property) String() string {
name := p.Name
alias := p.SerializedName

// TODO: extract into helper
if strings.HasPrefix(name, "+") {
name = strings.Replace(name, "+", "Plus", 1)
}
if strings.HasPrefix(name, "-") {
name = strings.Replace(name, "-", "Minus", 1)
}
if strings.HasPrefix(name, "@") {
name = strings.Replace(name, "@", "At", 1)
}
if strings.HasPrefix(name, "$") {
name = strings.Replace(name, "$", "", 1)
}

fieldName := name
fieldName := pythonFieldName(name)

useAlias := alias != "" && alias != fieldName

Expand Down Expand Up @@ -122,3 +139,20 @@ func (e *EnumDeclaration[E]) String() string {
func (e *EnumDeclaration[E]) TypeName() string {
return e.Name
}

func pythonFieldName(name string) string {
if strings.HasPrefix(name, "+") {
name = strings.Replace(name, "+", "Plus", 1)
}
if strings.HasPrefix(name, "-") {
name = strings.Replace(name, "-", "Minus", 1)
}
if strings.HasPrefix(name, "@") {
name = strings.Replace(name, "@", "At", 1)
}
if strings.HasPrefix(name, "$") {
name = strings.Replace(name, "$", "", 1)
}

return name
}
1 change: 0 additions & 1 deletion codegen/templates/types.py.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Code generated by `py-sdk-gen`. DO NOT EDIT.
from ._service import Service
import datetime
import typing
import pydantic
Expand Down
33 changes: 31 additions & 2 deletions sumup/members/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ class Invite(pydantic.BaseModel):

MembershipStatus = typing.Literal["accepted", "disabled", "expired", "pending", "unknown"]

Metadata = dict[typing.Any, typing.Any]
Metadata = dict[str, typing.Any]
"""
Set of user-defined key-value pairs attached to the object. Partial updates are not supported. When updating, alwayssubmit whole metadata. Maximum of 64 parameters are allowed in the object.
Max properties: 64
"""

Attributes = dict[typing.Any, typing.Any]
Attributes = dict[str, typing.Any]
"""
Object attributes that are modifiable only by SumUp applications.
"""
Expand Down Expand Up @@ -188,3 +188,32 @@ class Problem(pydantic.BaseModel):
"""
A short, human-readable summary of the problem type.
"""

model_config = pydantic.ConfigDict(extra="allow")

@pydantic.model_validator(mode="before")
@classmethod
def _merge_additional_properties(cls, values: typing.Any) -> typing.Any:
if not isinstance(values, dict):
return values

additional = values.get("additional_properties")
if not isinstance(additional, dict):
return values

merged = dict(additional)
for key, value in values.items():
if key != "additional_properties":
merged[key] = value

return merged

@property
def additional_properties(self) -> dict[str, typing.Any]:
if self.model_extra is None:
object.__setattr__(self, "__pydantic_extra__", {})
return typing.cast(dict[str, typing.Any], self.model_extra)

@additional_properties.setter
def additional_properties(self, value: dict[str, typing.Any]) -> None:
object.__setattr__(self, "__pydantic_extra__", dict(value))
4 changes: 2 additions & 2 deletions sumup/memberships/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ class Invite(pydantic.BaseModel):

MembershipStatus = typing.Literal["accepted", "disabled", "expired", "pending", "unknown"]

Metadata = dict[typing.Any, typing.Any]
Metadata = dict[str, typing.Any]
"""
Set of user-defined key-value pairs attached to the object. Partial updates are not supported. When updating, alwayssubmit whole metadata. Maximum of 64 parameters are allowed in the object.
Max properties: 64
"""

Attributes = dict[typing.Any, typing.Any]
Attributes = dict[str, typing.Any]
"""
Object attributes that are modifiable only by SumUp applications.
"""
Expand Down
33 changes: 31 additions & 2 deletions sumup/merchants/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class CompanyIdentifier(pydantic.BaseModel):
Max length: 64
"""

Attributes = dict[typing.Any, typing.Any]
Attributes = dict[str, typing.Any]
"""
Object attributes that are modifiable only by SumUp applications.
"""
Expand Down Expand Up @@ -335,7 +335,7 @@ class BusinessProfile(pydantic.BaseModel):
"""


Meta = dict[typing.Any, typing.Any]
Meta = dict[str, str]
"""
A set of key-value pairs that you can attach to an object. This can be useful for storing additional informationabout the object in a structured format.

Expand Down Expand Up @@ -536,6 +536,35 @@ class Problem(pydantic.BaseModel):
A short, human-readable summary of the problem type.
"""

model_config = pydantic.ConfigDict(extra="allow")

@pydantic.model_validator(mode="before")
@classmethod
def _merge_additional_properties(cls, values: typing.Any) -> typing.Any:
if not isinstance(values, dict):
return values

additional = values.get("additional_properties")
if not isinstance(additional, dict):
return values

merged = dict(additional)
for key, value in values.items():
if key != "additional_properties":
merged[key] = value

return merged

@property
def additional_properties(self) -> dict[str, typing.Any]:
if self.model_extra is None:
object.__setattr__(self, "__pydantic_extra__", {})
return typing.cast(dict[str, typing.Any], self.model_extra)

@additional_properties.setter
def additional_properties(self, value: dict[str, typing.Any]) -> None:
object.__setattr__(self, "__pydantic_extra__", dict(value))


class Ownership(pydantic.BaseModel):
"""
Expand Down
2 changes: 1 addition & 1 deletion sumup/readers/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class UpdateReaderBody(pydantic.BaseModel):
"""


CreateReaderCheckoutBodyAffiliateTags = dict[typing.Any, typing.Any]
CreateReaderCheckoutBodyAffiliateTags = dict[str, typing.Any]
"""
Additional metadata for the transaction.
It is key-value object that can be associated with the transaction.
Expand Down
37 changes: 33 additions & 4 deletions sumup/readers/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class ReaderDevice(pydantic.BaseModel):
"""


Metadata = dict[typing.Any, typing.Any]
Metadata = dict[str, typing.Any]
"""
Set of user-defined key-value pairs attached to the object. Partial updates are not supported. When updating, alwayssubmit whole metadata. Maximum of 64 parameters are allowed in the object.
Max properties: 64
Expand Down Expand Up @@ -142,6 +142,35 @@ class Problem(pydantic.BaseModel):
A short, human-readable summary of the problem type.
"""

model_config = pydantic.ConfigDict(extra="allow")

@pydantic.model_validator(mode="before")
@classmethod
def _merge_additional_properties(cls, values: typing.Any) -> typing.Any:
if not isinstance(values, dict):
return values

additional = values.get("additional_properties")
if not isinstance(additional, dict):
return values

merged = dict(additional)
for key, value in values.items():
if key != "additional_properties":
merged[key] = value

return merged

@property
def additional_properties(self) -> dict[str, typing.Any]:
if self.model_extra is None:
object.__setattr__(self, "__pydantic_extra__", {})
return typing.cast(dict[str, typing.Any], self.model_extra)

@additional_properties.setter
def additional_properties(self, value: dict[str, typing.Any]) -> None:
object.__setattr__(self, "__pydantic_extra__", dict(value))


ReaderPairingCode = str
"""
Expand Down Expand Up @@ -191,7 +220,7 @@ class CreateReaderCheckoutError(pydantic.BaseModel):
errors: CreateReaderCheckoutErrorErrors


CreateReaderCheckoutUnprocessableEntityErrors = dict[typing.Any, typing.Any]
CreateReaderCheckoutUnprocessableEntityErrors = dict[str, typing.Any]
"""
CreateReaderCheckoutUnprocessableEntityErrors is a schema definition.
"""
Expand All @@ -205,7 +234,7 @@ class CreateReaderCheckoutUnprocessableEntity(pydantic.BaseModel):
errors: CreateReaderCheckoutUnprocessableEntityErrors


CreateReaderCheckoutRequestAffiliateTags = dict[typing.Any, typing.Any]
CreateReaderCheckoutRequestAffiliateTags = dict[str, typing.Any]
"""
Additional metadata for the transaction.
It is key-value object that can be associated with the transaction.
Expand Down Expand Up @@ -564,7 +593,7 @@ class CreateReaderTerminateError(pydantic.BaseModel):
errors: CreateReaderTerminateErrorErrors


CreateReaderTerminateUnprocessableEntityErrors = dict[typing.Any, typing.Any]
CreateReaderTerminateUnprocessableEntityErrors = dict[str, typing.Any]
"""
CreateReaderTerminateUnprocessableEntityErrors is a schema definition.
"""
Expand Down
Loading
Loading