-
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Python: move model generation to Ruby templates
- Loading branch information
1 parent
5077ac3
commit b818731
Showing
16 changed files
with
1,381 additions
and
1,222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
# frozen_string_literal: true | ||
|
||
module Generator | ||
class Python < Base | ||
def array_type_for(type_name) | ||
inner_type = if language_translations_for_data_types.values.include?(type_name) | ||
type_name # Keep primitive types as is | ||
else | ||
class_name(type_name) # CamelCase for complex types | ||
end | ||
"list[#{inner_type}]" | ||
end | ||
|
||
def format_description(raw_description, indent_string: ' ') | ||
return '""" """' if raw_description.nil? | ||
|
||
formatted = raw_description | ||
.split("\n") | ||
.map { |line| "#{line}" } | ||
.join("\n#{indent_string}") | ||
%("""\n#{indent_string}#{formatted}\n#{indent_string}""") | ||
end | ||
|
||
def language_translations_for_data_types | ||
{ | ||
'integer' => 'int', | ||
'string' => 'str', | ||
'boolean' => 'bool', | ||
'array' => 'list' | ||
} | ||
end | ||
|
||
private | ||
|
||
def default_value(parent_type_name, property_name, property) | ||
if property['type'] == 'string' | ||
default_value_for_string(parent_type_name, property_name, property) | ||
elsif property['type'] == 'integer' | ||
'0' | ||
elsif property['type'] == 'boolean' | ||
'False' | ||
elsif property['type'] == 'array' | ||
'[]' | ||
elsif property['$ref'] | ||
"#{class_name(type_for(parent_type_name, nil, property))}()" | ||
else | ||
'None' | ||
end | ||
end | ||
|
||
def default_value_for_string(parent_type_name, property_name, property) | ||
if property['enum'] | ||
enum_type_name = type_for(parent_type_name, property_name, property) | ||
"#{class_name(enum_type_name)}.#{enum_constant(property['enum'][0])}" | ||
else | ||
'""' | ||
end | ||
end | ||
|
||
def type_for(parent_type_name, property_name, property) | ||
if property['$ref'] | ||
property_type_from_ref(property['$ref']) | ||
elsif property['type'] | ||
property_type_from_type(parent_type_name, property_name, property, type: property['type']) | ||
else | ||
raise "Property #{property_name} did not define 'type' or '$ref'" | ||
end | ||
end | ||
|
||
def property_type_from_type(parent_type_name, property_name, property, type:) | ||
if type == 'array' | ||
array_type_for(type_for(parent_type_name, nil, property['items'])) | ||
elsif property['enum'] | ||
enum_name(parent_type_name, property_name, property['enum']) | ||
else | ||
language_translations_for_data_types.fetch(type) | ||
end | ||
end | ||
|
||
def enum_constant(value) | ||
value.gsub(/[.\/+]/, '_').downcase | ||
end | ||
|
||
def enum_name(parent_type_name, property_name, enum) | ||
"#{class_name(parent_type_name)}#{capitalize(property_name)}".tap do |name| | ||
@enum_set.add({ name: name, values: enum }) | ||
end | ||
end | ||
|
||
def property_type_from_ref(ref) | ||
class_name(ref) | ||
end | ||
|
||
def class_name(ref) | ||
return ref if language_translations_for_data_types.values.include?(ref) | ||
|
||
# Remove .json extension if present | ||
name = ref.sub(/\.json$/, '') | ||
# Get the basename without path | ||
name = File.basename(name) | ||
# Convert each word to proper case, handling camelCase and snake_case | ||
parts = name.gsub(/[._-]/, '_').split('_').map do |part| | ||
# Split by any existing camelCase | ||
subparts = part.scan(/[A-Z][a-z]*|[a-z]+/) | ||
subparts.map(&:capitalize).join | ||
end | ||
# Join all parts to create final CamelCase name | ||
parts.join | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# This code was generated using the code generator from cucumber-messages. | ||
# Manual changes will be lost if the code is regenerated. | ||
# Generator: cucumber-messages-python | ||
|
||
from __future__ import annotations | ||
from dataclasses import dataclass | ||
from enum import Enum | ||
from typing import Optional | ||
|
||
<%- @enums.each do |enum| -%> | ||
class <%= enum[:name] %>(Enum): | ||
<%- enum[:values].each do |value| -%> | ||
<%= value.downcase.gsub(/[.\/+\s-]/, '_') %> = "<%= value %>" | ||
<%- end -%> | ||
|
||
<%- end -%> | ||
<%- @schemas.each do |key, definition| -%> | ||
@dataclass | ||
class <%= class_name(key) %>: | ||
<%- if definition['description'] -%> | ||
<%= format_description(definition['description']) %> | ||
<%- end -%> | ||
<%- if definition['properties'].any? -%> | ||
<%- | ||
required_fields = definition['required'] || [] | ||
properties = definition['properties'].sort_by do |name, *| | ||
[required_fields.include?(name) ? 0 : 1, name] | ||
end | ||
-%> | ||
<%- properties.each do |property_name, property| -%> | ||
<%- | ||
snake_name = property_name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') | ||
.gsub(/([a-z\d])([A-Z])/, '\1_\2') | ||
.downcase | ||
|
||
property_type = type_for(key, property_name, property) | ||
is_required = required_fields.include?(property_name) | ||
is_list = property_type.start_with?('list[') | ||
|
||
if is_list | ||
list_type = property_type.match(/list\[(.*?)\]/) | ||
inner_type = list_type[1] | ||
if inner_type =~ /^[A-Z]/ | ||
property_type = "list['#{class_name(inner_type)}']" | ||
else | ||
property_type = "list[#{inner_type}]" | ||
end | ||
elsif property_type =~ /^[A-Z]/ | ||
property_type = "'#{class_name(property_type)}'" | ||
end | ||
-%> | ||
<%- if property['description'] -%> | ||
<%= format_description(property['description']) %> | ||
<%- end -%> | ||
<%- if is_required -%> | ||
<%= snake_name %>: <%= property_type %> | ||
<%- else -%> | ||
<%= snake_name %>: Optional[<%= property_type %>] = None | ||
<%- end -%> | ||
<%- end -%> | ||
<%- else -%> | ||
pass | ||
<%- end -%> | ||
|
||
<%- end -%> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,8 @@ test = [ | |
] | ||
test-coverage = [ | ||
"coverage", | ||
"GitPython", | ||
"packaging", | ||
"pytest" | ||
] | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,4 @@ | ||
from . import _messages | ||
from . import json_converter | ||
from . import _messages, json_converter | ||
from ._messages import * | ||
|
||
# Renaming types because of confusing collision naming | ||
HookType = Type | ||
PickleStepType = Type1 | ||
ExpressionType = Type2 | ||
|
||
serializer: json_converter.DataclassSerializer = json_converter.DataclassSerializer(module_scope=_messages) | ||
|
||
del Type | ||
del Type1 | ||
del Type2 | ||
message_converter: json_converter.JsonDataclassConverter = json_converter.JsonDataclassConverter(module_scope=_messages) |
Oops, something went wrong.