Skip to content

Commit d8c8ffd

Browse files
committed
Adopt smithy-python sync renames and regenerate clients
1 parent 91a08e4 commit d8c8ffd

215 files changed

Lines changed: 317878 additions & 719755 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,6 @@ dist/
2323

2424
# scratch workspace
2525
/workspace
26+
27+
# IDE
28+
.idea

‎Makefile‎

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ PYTHON_VERSION := 3.12
44
# Colocated smithy-python checkout that provides the codegen jars.
55
SMITHY_PYTHON ?= ../smithy-python
66

7-
.PHONY: docs docs-serve docs-clean docs-install docs-lock venv gen publish-codegen
7+
.PHONY: docs docs-serve docs-clean docs-install docs-lock venv gen publish-codegen dev-install test test-integration typecheck ruff
8+
9+
# Each client and hand-written package is its own project with its own pytest
10+
# and pyright config, so the check targets run them one at a time.
11+
PROJECTS := $(patsubst %/pyproject.toml,%,$(wildcard clients/*/pyproject.toml packages/*/pyproject.toml))
12+
SMITHY_PACKAGES := aws-sdk-signers smithy-core smithy-json smithy-cbor smithy-xml smithy-aws-core smithy-aws-event-stream smithy-test
13+
VENV_BIN := $(CURDIR)/.venv/bin
814

915
# Publishes the smithy-python codegen jars to the local Maven cache so `gen`
1016
# can resolve them. Run once, and again whenever the generator changes.
@@ -25,6 +31,40 @@ endif
2531
venv:
2632
uv venv --python $(PYTHON_VERSION)
2733

34+
# Installs every client and package against the colocated smithy-python
35+
# checkout, so checks run against unreleased runtime changes.
36+
dev-install:
37+
@[ -d .venv ] || uv venv --python $(PYTHON_VERSION)
38+
uv pip install --python $(VENV_BIN)/python \
39+
$(foreach p,$(SMITHY_PACKAGES),-e $(SMITHY_PYTHON)/packages/$(p)) \
40+
-e "$(SMITHY_PYTHON)/packages/smithy-http[aiohttp,awscrt]" \
41+
$(foreach p,$(PROJECTS),-e ./$(p)) \
42+
"pytest>=9.0.1,<10.0.0" "pytest-asyncio>=1.3.0,<1.4.0" \
43+
"boto3==1.43.120" "boto3-stubs[iam,lexv2-models,s3,sts]==1.43.120" \
44+
"pyright==1.1.406" "ruff==0.15.22"
45+
46+
test: dev-install
47+
@failed=; for t in $(wildcard packages/*/tests/unit); do \
48+
$(VENV_BIN)/python -m pytest -q $$t || failed="$$failed $$t"; \
49+
done; [ -z "$$failed" ] || { echo "unit tests failed in:$$failed"; exit 1; }
50+
51+
# Requires AWS credentials for the accounts and regions the suites target.
52+
test-integration: dev-install
53+
@failed=; for p in $(PROJECTS); do \
54+
[ -d $$p/tests/integration ] || continue; \
55+
$(VENV_BIN)/python -m pytest -q $$p/tests/integration || failed="$$failed $$p"; \
56+
done; [ -z "$$failed" ] || { echo "integration tests failed in:$$failed"; exit 1; }
57+
58+
typecheck: dev-install
59+
@failed=; for p in $(PROJECTS); do \
60+
dirs=$$(cd $$p && ls -d src tests 2>/dev/null); [ -n "$$dirs" ] || continue; \
61+
(cd $$p && $(VENV_BIN)/pyright --pythonpath $(VENV_BIN)/python $$dirs) || failed="$$failed $$p"; \
62+
done; [ -z "$$failed" ] || { echo "typecheck failed in:$$failed"; exit 1; }
63+
64+
ruff: dev-install
65+
$(VENV_BIN)/ruff check clients packages
66+
$(VENV_BIN)/ruff format --check clients packages
67+
2868
docs-lock: venv
2969
uv pip compile requirements-docs.in -o requirements-docs.txt
3070

‎clients/aws-sdk-api-gateway/scripts/docs/generate_doc_stubs.py‎

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,9 @@ class ClientInfo:
126126
class DocStubGenerator:
127127
"""Generate markdown API Reference stubs for AWS SDK for Python v4 clients."""
128128

129-
def __init__(self, client_dir: Path, output_dir: Path, service_name: str | None = None) -> None:
129+
def __init__(
130+
self, client_dir: Path, output_dir: Path, service_name: str | None = None
131+
) -> None:
130132
"""
131133
Initialize the documentation generator.
132134
@@ -190,7 +192,9 @@ def _analyze_client_package(self, package_name: str) -> ClientInfo:
190192
required = ("client", "config", "models")
191193
missing = [name for name in required if not package.modules.get(name)]
192194
if missing:
193-
raise ValueError(f"Missing required modules in {package_name}: {', '.join(missing)}")
195+
raise ValueError(
196+
f"Missing required modules in {package_name}: {', '.join(missing)}"
197+
)
194198

195199
# Parse submodules
196200
client_module = package.modules["client"]
@@ -199,11 +203,15 @@ def _analyze_client_package(self, package_name: str) -> ClientInfo:
199203

200204
client_class = self._find_class_with_suffix(client_module, "Client")
201205
if not client_class:
202-
raise ValueError(f"No class ending with 'Client' found in {package_name}.client")
206+
raise ValueError(
207+
f"No class ending with 'Client' found in {package_name}.client"
208+
)
203209

204210
config_class = self._find_class_with_suffix(config_module, "Config")
205211
if not config_class:
206-
raise ValueError(f"No class ending with 'Config' found in {package_name}.config")
212+
raise ValueError(
213+
f"No class ending with 'Config' found in {package_name}.config"
214+
)
207215

208216
plugin_alias = config_module.members.get("Plugin")
209217
if not plugin_alias:
@@ -288,7 +296,9 @@ def _analyze_operation(self, operation: Function) -> OperationInfo:
288296

289297
if output_type in stream_type_map:
290298
stream_type = stream_type_map[output_type]
291-
stream_args = self._get_subscript_elements(returns, f"'{operation.name}' stream type")
299+
stream_args = self._get_subscript_elements(
300+
returns, f"'{operation.name}' stream type"
301+
)
292302

293303
if stream_type in (StreamType.INPUT, StreamType.DUPLEX):
294304
event_input_type = stream_args[0].canonical_name
@@ -316,7 +326,9 @@ def _analyze_operation(self, operation: Function) -> OperationInfo:
316326
def _get_expr(self, annotation: str | Expr | None, context: str) -> Expr:
317327
"""Extract and validate an Expr from an annotation."""
318328
if not isinstance(annotation, Expr):
319-
raise TypeError(f"{context}: expected Expr, got {type(annotation).__name__}")
329+
raise TypeError(
330+
f"{context}: expected Expr, got {type(annotation).__name__}"
331+
)
320332
return annotation
321333

322334
def _get_subscript_elements(self, expr: Expr, context: str) -> list[Expr]:
@@ -330,7 +342,9 @@ def _get_subscript_elements(self, expr: Expr, context: str) -> list[Expr]:
330342
return [el for el in slice_expr.elements if isinstance(el, Expr)]
331343
return [slice_expr]
332344

333-
def _extract_models(self, models_module: Module, operations: list[OperationInfo]) -> ModelsInfo:
345+
def _extract_models(
346+
self, models_module: Module, operations: list[OperationInfo]
347+
) -> ModelsInfo:
334348
"""Extract structures, unions, enums, and errors from models module."""
335349
structures, unions, enums, errors = [], [], [], []
336350

@@ -356,14 +370,16 @@ def _extract_models(self, models_module: Module, operations: list[OperationInfo]
356370

357371
duplicates = []
358372
for structure in structures:
359-
if self._is_operation_io_type(structure.name, operations) or self._is_union_member(
360-
structure.name, unions
361-
):
373+
if self._is_operation_io_type(
374+
structure.name, operations
375+
) or self._is_union_member(structure.name, unions):
362376
duplicates.append(structure)
363377

364378
structures = [struct for struct in structures if struct not in duplicates]
365379

366-
return ModelsInfo(structures=structures, unions=unions, enums=enums, errors=errors)
380+
return ModelsInfo(
381+
structures=structures, unions=unions, enums=enums, errors=errors
382+
)
367383

368384
def _is_union(self, member: Object | Alias) -> TypeGuard[Attribute]:
369385
"""Check if a module member is a union type."""
@@ -399,7 +415,9 @@ def _extract_union_members(
399415
for name in member_names:
400416
if not (member_object := models_module.members.get(name)):
401417
raise ValueError(f"Union member '{name}' not found in models module")
402-
members.append(TypeInfo(name=member_object.name, module_path=member_object.path))
418+
members.append(
419+
TypeInfo(name=member_object.name, module_path=member_object.path)
420+
)
403421

404422
return members
405423

@@ -408,18 +426,22 @@ def _is_enum(self, member: Object | Alias) -> TypeGuard[Class]:
408426
if not isinstance(member, Class):
409427
return False
410428
return any(
411-
isinstance(base, ExprName) and base.name in ENUM_BASE_CLASSES for base in member.bases
429+
isinstance(base, ExprName) and base.name in ENUM_BASE_CLASSES
430+
for base in member.bases
412431
)
413432

414433
def _is_error(self, member: Object | Alias) -> TypeGuard[Class]:
415434
"""Check if a module member is an error."""
416435
if not isinstance(member, Class):
417436
return False
418437
return any(
419-
isinstance(base, ExprName) and base.name in ERROR_BASE_CLASSES for base in member.bases
438+
isinstance(base, ExprName) and base.name in ERROR_BASE_CLASSES
439+
for base in member.bases
420440
)
421441

422-
def _is_operation_io_type(self, type_name: str, operations: list[OperationInfo]) -> bool:
442+
def _is_operation_io_type(
443+
self, type_name: str, operations: list[OperationInfo]
444+
) -> bool:
423445
"""Check if a type is used as operation input/output."""
424446
return any(type_name in (op.input.name, op.output.name) for op in operations)
425447

@@ -437,8 +459,12 @@ def _generate_client_docs(self, client_info: ClientInfo) -> bool:
437459
self._generate_type_stubs(
438460
client_info.models.structures, "structures", "Structure Class"
439461
)
440-
self._generate_type_stubs(client_info.models.errors, "errors", "Error Class")
441-
self._generate_type_stubs(client_info.models.enums, "enums", "Enum Class", members=True)
462+
self._generate_type_stubs(
463+
client_info.models.errors, "errors", "Error Class"
464+
)
465+
self._generate_type_stubs(
466+
client_info.models.enums, "enums", "Enum Class", members=True
467+
)
442468
self._generate_union_stubs(client_info.models.unions)
443469
except OSError as e:
444470
logger.error(f"Failed to write documentation files: {e}")
@@ -470,7 +496,9 @@ def _generate_index(self, client_info: ClientInfo) -> None:
470496
]
471497

472498
for method in sorted(client_info.client_methods, key=lambda x: x.name):
473-
lines.extend([*self._mkdocs_directive(method.module_path, heading_level=4), ""])
499+
lines.extend(
500+
[*self._mkdocs_directive(method.module_path, heading_level=4), ""]
501+
)
474502

475503
# Operations section
476504
if client_info.operations:
@@ -578,7 +606,9 @@ def _generate_operation_stubs(self, operations: list[OperationInfo]) -> None:
578606

579607
output_path = self.output_dir / "operations" / f"{op.name}.md"
580608
output_path.parent.mkdir(parents=True, exist_ok=True)
581-
output_path.write_text(self._breadcrumb("Operations", op.name) + "\n".join(lines))
609+
output_path.write_text(
610+
self._breadcrumb("Operations", op.name) + "\n".join(lines)
611+
)
582612

583613
logger.info(f"Wrote {len(operations)} operation file(s)")
584614

@@ -600,7 +630,9 @@ def _generate_type_stubs(
600630

601631
output_path = self.output_dir / category / f"{item.name}.md"
602632
output_path.parent.mkdir(parents=True, exist_ok=True)
603-
output_path.write_text(self._breadcrumb(category.title(), item.name) + "\n".join(lines))
633+
output_path.write_text(
634+
self._breadcrumb(category.title(), item.name) + "\n".join(lines)
635+
)
604636

605637
logger.info(f"Wrote {len(items)} {category} file(s)")
606638

@@ -624,7 +656,9 @@ def _generate_union_stubs(self, unions: list[UnionInfo]) -> None:
624656

625657
output_path = self.output_dir / "unions" / f"{union.name}.md"
626658
output_path.parent.mkdir(parents=True, exist_ok=True)
627-
output_path.write_text(self._breadcrumb("Unions", union.name) + "\n".join(lines))
659+
output_path.write_text(
660+
self._breadcrumb("Unions", union.name) + "\n".join(lines)
661+
)
628662

629663
logger.info(f"Wrote {len(unions)} union file(s)")
630664

0 commit comments

Comments
 (0)