8000 Core: Add type hints to aws/core.py (#12617) · localstack/localstack@70b8643 · GitHub
[go: up one dir, main page]

Skip to content

Commit 70b8643

Browse files
authored
Core: Add type hints to aws/core.py (#12617)
1 parent 73789e1 commit 70b8643

File tree

19 files changed

+109
-95
lines changed

19 files changed

+109
-95
lines changed

.circleci/config.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,16 @@ jobs:
164164
steps:
165165
- checkout
166166
- restore_cache:
167-
key: python-requirements-{{ checksum "requirements-dev.txt" }}
167+
key: python-requirements-{{ checksum "requirements-typehint.txt" }}
168168
- run:
169169
name: Setup environment
170170
command: |
171+
make install-dev-types
171172
make install
172173
mkdir -p target/reports
173174
mkdir -p target/coverage
174175
- save_cache:
175-
key: python-requirements-{{ checksum "requirements-dev.txt" }}
176+
key: python-requirements-{{ checksum "requirements-typehint.txt" }}
176177
paths:
177178
- "~/.cache/pip"
178179
- persist_to_workspace:

.github/actions/load-localstack-docker-from-artifacts/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ runs:
1818
with:
1919
python-version-file: '.python-version'
2020
cache: 'pip'
21-
cache-dependency-path: 'requirements-dev.txt'
21+
cache-dependency-path: 'requirements-typehint.txt'
2222

2323
- name: Install docker helper dependencies
2424
shell: bash

.github/actions/setup-tests-env/action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ runs:
88
with:
99
python-version-file: '.python-version'
1010
cache: 'pip'
11-
cache-dependency-path: 'requirements-dev.txt'
11+
cache-dependency-path: 'requirements-typehint.txt'
1212

1313
- name: Install Community Dependencies
1414
shell: bash
15-
run: make install-dev
15+
run: make install-dev-types
1616

1717
- name: Setup environment
1818
shell: bash

.github/workflows/aws-main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ jobs:
184184
fetch-depth: 0
185185

186186
- name: Load Localstack ${{ env.PLATFORM_NAME_AMD64 }} Docker Image
187-
uses: localstack/localstack/.github/actions/load-localstack-docker-from-artifacts@master
187+
uses: ./.github/actions/load-localstack-docker-from-artifacts
188188
with:
189189
platform: ${{ env.PLATFORM_NAME_AMD64 }}
190190

@@ -213,7 +213,7 @@ jobs:
213213
TARGET_IMAGE_NAME="public.ecr.aws/localstack/localstack" ./bin/docker-helper.sh push
214214
215215
- name: Load Localstack ${{ env.PLATFORM_NAME_ARM64 }} Docker Image
216 10000 -
uses: localstack/localstack/.github/actions/load-localstack-docker-from-artifacts@master
216+
uses: ./.github/actions/load-localstack-docker-from-artifacts
217217
with:
218218
platform: ${{ env.PLATFORM_NAME_ARM64 }}
219219

.github/workflows/aws-tests.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ jobs:
198198
fetch-depth: 0
199199

200200
- name: Prepare Local Test Environment
201-
uses: localstack/localstack/.github/actions/setup-tests-env@master
201+
uses: ./.github/actions/setup-tests-env
202202

203203
- name: Linting
204204
run: make lint
@@ -310,7 +310,7 @@ jobs:
310310
tests/aws/services/lambda_/functions/common
311311
312312
- name: Load Localstack Docker Image
313-
uses: localstack/localstack/.github/actions/load-localstack-docker-from-artifacts@master
313+
uses: ./.github/actions/load-localstack-docker-from-artifacts
314314
with:
315315
platform: "${{ env.PLATFORM }}"
316316

@@ -376,10 +376,10 @@ jobs:
376376
fetch-depth: 0
377377

378378
- name: Prepare Local Test Environment
379-
uses: localstack/localstack/.github/actions/setup-tests-env@master
379+
uses: ./.github/actions/setup-tests-env
380380

381381
- name: Load Localstack Docker Image
382-
uses: localstack/localstack/.github/actions/load-localstack-docker-from-artifacts@master
382+
uses: ./.github/actions/load-localstack-docker-from-artifacts
383383
with:
384384
platform: "${{ env.PLATFORM }}"
385385

@@ -451,7 +451,7 @@ jobs:
451451
fetch-depth: 0
452452

453453
- name: Load Localstack Docker Image
454-
uses: localstack/localstack/.github/actions/load-localstack-docker-from-artifacts@master
454+
uses: ./.github/actions/load-localstack-docker-from-artifacts
455455
with:
456456
platform: "${{ env.PLATFORM }}"
457457

@@ -498,7 +498,7 @@ jobs:
498498
uses: actions/checkout@v4
499499

500500
- name: Prepare Local Test Environment
501-
uses: localstack/localstack/.github/actions/setup-tests-env@master
501+
uses: ./.github/actions/setup-tests-env
502502

503503
- name: Run Cloudwatch v1 Provider Tests
504504
timeout-minutes: 30
@@ -541,7 +541,7 @@ jobs:
541541
uses: actions/checkout@v4
542542

543543
- name: Prepare Local Test Environment
544-
uses: localstack/localstack/.github/actions/setup-tests-env@master
544+
uses: ./.github/actions/setup-tests-env
545545

546546
- name: Download Test Selection
547547
if: ${{ env.TESTSELECTION_PYTEST_ARGS }}
@@ -590,7 +590,7 @@ jobs:
590590
uses: actions/checkout@v4
591591

592592
- name: Prepare Local Test Environment
593-
uses: localstack/localstack/.github/actions/setup-tests-env@master
593+
uses: ./.github/actions/setup-tests-env
594594

595595
- name: Download Test Selection
596596
if: ${{ env.TESTSELECTION_PYTEST_ARGS }}
@@ -641,7 +641,7 @@ jobs:
641641
uses: actions/checkout@v4
642642

643643
- name: Prepare Local Test Environment
644-
uses: localstack/localstack/.github/actions/setup-tests-env@master
644+
uses: ./.github/actions/setup-tests-env
645645

646646
- name: Download Test Selection
647647
if: ${{ env.TESTSELECTION_PYTEST_ARGS }}
@@ -694,7 +694,7 @@ jobs:
694694
fetch-depth: 0
695695

696696
- name: Load Localstack Docker Image
697-
uses: localstack/localstack/.github/actions/load-localstack-docker-from-artifacts@master
697+
uses: ./.github/actions/load-localstack-docker-from-artifacts
698698
with:
699699
platform: "${{ env.PLATFORM }}"
700700

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ repos:
1515
hooks:
1616
- id: mypy
1717
entry: bash -c 'cd localstack-core && mypy --install-types --non-interactive'
18+
additional_dependencies: ['botocore-stubs', 'rolo']
1819

1920
- repo: https://github.com/pre-commit/pre-commit-hooks
2021
rev: v5.0.0

localstack-core/localstack/aws/api/core.py

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import functools
2-
from typing import Any, NamedTuple, Optional, Protocol, Type, TypedDict, Union
2+
from typing import (
3+
Any,
4+
Callable,
5+
NamedTuple,
6+
ParamSpec,
7+
Protocol,
8+
Type,
9+
TypedDict,
10+
TypeVar,
11+
)
312

413
from botocore.model import OperationModel, ServiceModel
514
from rolo.gateway import RequestContext as RoloRequestContext
@@ -13,6 +22,10 @@ class ServiceRequest(TypedDict):
1322
pass
1423

1524

25+
P = ParamSpec("P")
26+
T = TypeVar("T")
27+
28+
1629
ServiceResponse = Any
1730

1831

@@ -28,7 +41,7 @@ class ServiceException(Exception):
2841
sender_fault: bool
2942
message: str
3043

31-
def __init__(self, *args, **kwargs):
44+
def __init__(self, *args: Any, **kwargs: Any):
3245
super(ServiceException, self).__init__(*args)
3346

3447
if len(args) >= 1:
@@ -72,38 +85,38 @@ class RequestContext(RoloRequestContext):
7285
context, so it can be used for logging or modification before going to the serializer.
7386
"""
7487

75-
request: Optional[Request]
88+
request: Request
7689
"""The underlying incoming HTTP request."""
77-
service: Optional[ServiceModel]
90+
service: ServiceModel | None
7891
"""The botocore ServiceModel of the service the request is made to."""
79-
operation: Optional[OperationModel]
92+
operation: OperationModel | None
8093
"""The botocore OperationModel of the AWS operation being invoked."""
81-
region: Optional[str]
94+
region: str
8295
"""The region the request is made to."""
8396
partition: str
8497
"""The partition the request is made to."""
85-
account_id: Optional[str]
98+
account_id: str
8699
"""The account the request is made from."""
87-
request_id: Optional[str]
100+
request_id: str | None
88101
"""The autogenerated AWS request ID identifying the original request"""
89-
service_request: Optional[ServiceRequest]
102+
service_request: ServiceRequest | None
90103
"""The AWS operation parameters."""
91-
service_response: Optional[ServiceResponse]
104+
service_response: ServiceResponse | None
92105
"""The response from the AWS emulator backend."""
93< 10000 /td>-
service_exception: Optional[ServiceException]
106+
service_exception: ServiceException | None
94107
"""The exception the AWS emulator backend may have raised."""
95-
internal_request_params: Optional[InternalRequestParameters]
108+
internal_request_params: InternalRequestParameters | None
96109
"""Data sent by client-side LocalStack during internal calls."""
97-
trace_context: dict
110+
trace_context: dict[str, Any]
98111
"""Tracing metadata such as X-Ray trace headers"""
99112

100-
def __init__(self, request=None) -> None:
113+
def __init__(self, request: Request):
101114
super().__init__(request)
102115
self.service = None
103116
self.operation = None
104-
self.region = None
117+
self.region = None # type: ignore[assignment] # type=str, because we know it will always be set downstream
105118
self.partition = "aws" # Sensible default - will be overwritten by region-handler
106-
self.account_id = None
119+
self.account_id = None # type: ignore[assignment] # type=str, because we know it will always be set downstream
107120
self.request_id = long_uid()
108121
self.service_request = None
109122
self.service_response = None
@@ -119,7 +132,7 @@ def is_internal_call(self) -> bool:
119132
return self.internal_request_params is not None
120133

121134
@property
122-
def service_operation(self) -> Optional[ServiceOperation]:
135+
def service_operation(self) -> ServiceOperation | None:
123136
"""
124137
If both the service model and the operation model are set, this returns a tuple of the service name and
125138
operation name.
@@ -130,7 +143,7 @@ def service_operation(self) -> Optional[ServiceOperation]:
130143
return None
131144
return ServiceOperation(self.service.service_name, self.operation.name)
132145

133-
def __repr__(self):
146+
def __repr__(self) -> str:
134147
return f"<RequestContext {self.service=}, {self.operation=}, {self.region=}, {self.account_id=}, {self.request=}>"
135148

136149

@@ -141,7 +154,7 @@ class ServiceRequestHandler(Protocol):
141154

142155
def __call__(
143156
self, cont 10000 ext: RequestContext, request: ServiceRequest
144-
) -> Optional[Union[ServiceResponse, Response]]:
157+
) -> ServiceResponse | Response | None:
145158
"""
146159
Handle the given request.
147160
@@ -152,19 +165,21 @@ def __call__(
152165
raise NotImplementedError
153166

154167

155-
def handler(operation: str = None, context: bool = True, expand: bool = True):
168+
def handler(
169+
operation: str | None = None, context: bool = True, expand: bool = True
170+
) -> Callable[[Callable[P, T]], Callable[P, T]]:
156171
"""
157172
Decorator that indicates that the given function is a handler
158173
"""
159174

160-
def wrapper(fn):
175+
def wrapper(fn: Callable[P, T]) -> Callable[P, T]:
161176
@functools.wraps(fn)
162-
def operation_marker(*args, **kwargs):
177+
def operation_marker(*args: P.args, **kwargs: P.kwargs) -> T:
163178
return fn(*args, **kwargs)
164179

165-
operation_marker.operation = operation
166-
operation_marker.expand_parameters = expand
167-
operation_marker.pass_context = context
180+
operation_marker.operation = operation # type: ignore[attr-defined]
181+
operation_marker.expand_parameters = expand # type: ignore[attr-defined]
182+
operation_marker.pass_context = context # type: ignore[attr-defined]
168183

169184
return operation_marker
170185

localstack-core/localstack/aws/client.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,7 @@ def __call__(
395395
operation: OperationModel = request.operation_model
396396

397397
# create request
398-
context = RequestContext()
399-
context.request = create_http_request(request)
398 10000 +
context = RequestContext(request=create_http_request(request))
400399

401400
# TODO: just a hacky thing to unblock the service model being set to `sqs-query` blocking for now
402401
# this is using the same services as `localstack.aws.protocol.service_router.resolve_conflicts`, maybe

localstack-core/localstack/aws/forwarder.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,10 @@ def create_aws_request_context(
262262
)
263263

264264
aws_request: AWSPreparedRequest = client._endpoint.create_request(request_dict, operation)
265-
context = RequestContext()
265+
context = RequestContext(request=create_http_request(aws_request))
266266
context.service = service
267267
context.operation = operation
268268
context.region = region
269-
context.request = create_http_request(aws_request)
270269
context.service_request = parameters
271270

272271
return context

localstack-core/localstack/testing/aws/util.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,14 @@ def create_client_with_keys(
108108
def create_request_context(
109109
service_name: str, operation_name: str, region: str, aws_request: AWSPreparedRequest
110110
) -> RequestContext:
111-
context = RequestContext()
111+
if hasattr(aws_request.body, "read"):
112+
aws_request.body = aws_request.body.read()
113+
request = create_http_request(aws_request)
114+
115+
context = RequestContext(request=request)
112116
context.service = load_service(service_name)
113117
context.operation = context.service.operation_model(operation_name=operation_name)
114118
context.region = region
115-
if hasattr(aws_request.body, "read"):
116-
aws_request.body = aws_request.body.read()
117-
context.request = create_http_request(aws_request)
118119
parser = create_parser(context.service)
119120
_, instance = parser.parse(context.request)
120121
context.service_request = instance

0 commit comments

Comments
 (0)
0