Skip to content

Commit caee375

Browse files
committed
[python] Review fixes
* Fixup property type definitions * Fixup property descriptions * Descriptions inlined where possible * Property descriptions are placed after properties per se * Remove redundant double-quotes at type definitions * Split enums and model templates * Simplify gh-action test matrix * Fixup empty project.toml settings
1 parent 9b8bffc commit caee375

File tree

8 files changed

+272
-446
lines changed

8 files changed

+272
-446
lines changed

.github/workflows/test-python.yml

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,18 @@ jobs:
1818
strategy:
1919
matrix:
2020
include:
21-
- os: ubuntu-latest
22-
python-version: "3.9"
23-
- os: ubuntu-latest
24-
python-version: "3.10"
25-
- os: ubuntu-latest
26-
python-version: "3.11"
27-
- os: ubuntu-latest
28-
python-version: "3.12"
29-
- os: ubuntu-latest
30-
python-version: "3.13"
31-
- os: ubuntu-latest
32-
python-version: "pypy3.9"
33-
- os: ubuntu-latest
34-
python-version: "pypy3.10"
35-
- os: windows-latest
36-
python-version: "3.13"
37-
- os: macos-latest
38-
python-version: "3.13"
21+
# Test latest python on Windows / macOS
22+
- { os: 'windows-latest', python-version: '3.13' }
23+
- { os: 'macos-latest', python-version: '3.13' }
24+
os: ['ubuntu-latest']
25+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', 'pypy3.9', 'pypy3.10']
3926

4027
steps:
4128
- uses: actions/checkout@v4
4229
- name: Set up Python ${{ matrix.python-version }}
4330
uses: actions/setup-python@v5
4431
with:
4532
python-version: ${{ matrix.python-version }}
46-
- name: Generate code
47-
working-directory: ./python
48-
run: |
49-
make clean
50-
make generate
5133
- name: Install dependencies
5234
run: |
5335
python -m pip install --upgrade pip

codegen/generators/python.rb

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,21 @@ def format_property(parent_type_name, property_name, property, required_fields)
2121
property_type = get_property_type(parent_type_name, property_name, property)
2222
is_required = required_fields.include?(property_name)
2323

24+
property_description = if property['description'] && !property['description'].include?("\n")
25+
" # #{property['description']}"
26+
else
27+
''
28+
end
2429
if is_required
25-
"#{snake_name}: #{property_type}"
30+
"#{snake_name}: #{property_type}#{property_description}"
2631
else
27-
"#{snake_name}: Optional[#{property_type}] = None"
32+
"#{snake_name}: Optional[#{property_type}] = None#{property_description}"
2833
end
2934
end
3035

3136
def get_property_type(parent_type_name, property_name, property)
3237
type = type_for(parent_type_name, property_name, property)
33-
34-
if type.start_with?('list[')
35-
list_type = type.match(/list\[(.*?)\]/)
36-
inner_type = list_type[1]
37-
if inner_type =~ /^[A-Z]/
38-
"list[\"#{class_name(inner_type)}\"]"
39-
else
40-
"list[#{inner_type}]"
41-
end
42-
elsif type =~ /^[A-Z]/
43-
"\"#{class_name(type)}\""
44-
else
45-
type
46-
end
38+
type.match?(/\A[A-Z]/) ? class_name(type) : type
4739
end
4840

4941
def array_type_for(type_name)
@@ -52,7 +44,7 @@ def array_type_for(type_name)
5244
else
5345
class_name(type_name) # CamelCase for complex types
5446
end
55-
"list[#{inner_type}]"
47+
inner_type
5648
end
5749

5850
def format_description(raw_description, indent_string: ' ')
@@ -117,7 +109,9 @@ def type_for(parent_type_name, property_name, property)
117109

118110
def property_type_from_type(parent_type_name, property_name, property, type:)
119111
if type == 'array'
120-
array_type_for(type_for(parent_type_name, nil, property['items']))
112+
type = type_for(parent_type_name, nil, property['items'])
113+
inner_type = array_type_for(type)
114+
"list[#{inner_type}]"
121115
elsif property['enum']
122116
enum_name(parent_type_name, property_name, property['enum'])
123117
else
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This code was generated using the code generator from cucumber-messages.
2+
# Manual changes will be lost if the code is regenerated.
3+
# Generator: cucumber-messages-python
4+
5+
from enum import Enum
6+
7+
8+
<%- @enums.each_with_index do |enum, index| -%>
9+
class <%= enum[:name] %>(Enum):
10+
<%- enum[:values].each do |value| -%>
11+
<%= format_enum_value(value) %> = "<%= value %>"
12+
<%- end -%>
13+
<%- if index < @enums.length - 1 -%>
14+
15+
16+
<%- end -%>
17+
<%- end -%>

codegen/templates/python.py.erb

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,10 @@
44

55
from __future__ import annotations
66
from dataclasses import dataclass
7-
from enum import Enum
87
from typing import Optional
98

9+
from ._message_enums import *
1010

11-
<%- @enums.each do |enum| -%>
12-
class <%= enum[:name] %>(Enum):
13-
<%- enum[:values].each do |value| -%>
14-
<%= format_enum_value(value) %> = "<%= value %>"
15-
<%- end -%>
16-
17-
18-
<%- end -%>
1911
<%- @schemas.each_with_index do |schema_pair, index| -%>
2012
<%- key, definition = schema_pair -%>
2113
@dataclass
@@ -26,10 +18,11 @@ class <%= class_name(key) %>:
2618
<%- if definition['properties'].any? -%>
2719
<%- required_fields = definition['required'] || [] -%>
2820
<%- get_sorted_properties(definition).each do |property_name, property| -%>
29-
<%- if property['description'] -%>
21+
<%= format_property(key, property_name, property, required_fields) %>
22+
<%- if property['description'] && property['description'].include?("\n") -%>
3023
<%= format_description(property['description']) %>
24+
3125
<%- end -%>
32-
<%= format_property(key, property_name, property, required_fields) %>
3326
<%- end -%>
3427
<%- else -%>
3528
pass

python/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ schemas = $(shell find ../jsonschema -name "*.json")
55
help: ## Show this help
66
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make <target>\n\nWhere <target> is one of:\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
77

8-
generate: require src/cucumber_messages/_messages.py
8+
generate: require src/cucumber_messages/_messages.py src/cucumber_messages/_message_enums.py
99

1010
require: ## Check requirements for the code generation (ruby is required)
1111
@ruby --version >/dev/null 2>&1 || (echo "ERROR: ruby is required."; exit 1)
1212

1313
clean: ## Remove automatically generated files and related artifacts
1414
rm -f src/cucumber_messages/_messages.py
15+
rm -f src/cucumber_messages/_message_enums.py
1516

1617
src/cucumber_messages/_messages.py: $(schemas) ../codegen/codegen.rb ../codegen/templates/python.py.erb
1718
ruby ../codegen/codegen.rb Generator::Python python.py.erb > $@
19+
20+
src/cucumber_messages/_message_enums.py: $(schemas) ../codegen/codegen.rb ../codegen/templates/python.enum.py.erb
21+
ruby ../codegen/codegen.rb Generator::Python python.enum.py.erb > $@

python/pyproject.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ requires-python = ">=3.9"
3434
urls = {Repository = "https://github.com/cucumber/messages"}
3535
version = "0.1.0"
3636

37-
[project.entry-points]
38-
3937
[project.optional-dependencies]
4038
test = [
4139
# local
@@ -52,8 +50,6 @@ test-coverage = [
5250
"pytest"
5351
]
5452

55-
[project.scripts]
56-
5753
[tool.black]
5854
# Don't include autogenerated file
5955
force-exclude = ".*\\/src\\/cucumber_messages\\/_messages\\.py"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# This code was generated using the code generator from cucumber-messages.
2+
# Manual changes will be lost if the code is regenerated.
3+
# Generator: cucumber-messages-python
4+
5+
from enum import Enum
6+
7+
8+
class AttachmentContentEncoding(Enum):
9+
identity = "IDENTITY"
10+
base64 = "BASE64"
11+
12+
13+
class HookType(Enum):
14+
before_test_run = "BEFORE_TEST_RUN"
15+
after_test_run = "AFTER_TEST_RUN"
16+
before_test_case = "BEFORE_TEST_CASE"
17+
after_test_case = "AFTER_TEST_CASE"
18+
before_test_step = "BEFORE_TEST_STEP"
19+
after_test_step = "AFTER_TEST_STEP"
20+
21+
22+
class PickleStepType(Enum):
23+
unknown = "Unknown"
24+
context = "Context"
25+
action = "Action"
26+
outcome = "Outcome"
27+
28+
29+
class SourceMediaType(Enum):
30+
text_x_cucumber_gherkin_plain = "text/x.cucumber.gherkin+plain"
31+
text_x_cucumber_gherkin_markdown = "text/x.cucumber.gherkin+markdown"
32+
33+
34+
class StepDefinitionPatternType(Enum):
35+
cucumber_expression = "CUCUMBER_EXPRESSION"
36+
regular_expression = "REGULAR_EXPRESSION"
37+
38+
39+
class StepKeywordType(Enum):
40+
unknown = "Unknown"
41+
context = "Context"
42+
action = "Action"
43+
outcome = "Outcome"
44+
conjunction = "Conjunction"
45+
46+
47+
class TestStepResultStatus(Enum):
48+
unknown = "UNKNOWN"
49+
passed = "PASSED"
50+
skipped = "SKIPPED"
51+
pending = "PENDING"
52+
undefined = "UNDEFINED"
53+
ambiguous = "AMBIGUOUS"
54+
failed = "FAILED"

0 commit comments

Comments
 (0)