crossplane-function-sdk-python 0.13.0__tar.gz → 0.15.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/.github/workflows/ci.yml +9 -9
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/PKG-INFO +5 -4
- crossplane_function_sdk_python-0.15.0/crossplane/function/__init__.py +65 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/__version__.py +1 -1
- crossplane_function_sdk_python-0.15.0/crossplane/function/cli.py +127 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/response.py +6 -3
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/runtime.py +9 -6
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/pyproject.toml +3 -2
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/test_response.py +15 -11
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/.gitignore +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/CODEOWNERS +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/LICENSE +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/OWNERS.md +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/README.md +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/logging.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1/run_function.proto +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1/run_function_pb2.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1/run_function_pb2.pyi +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1/run_function_pb2_grpc.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1beta1/run_function.proto +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1beta1/run_function_pb2.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1beta1/run_function_pb2.pyi +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/proto/v1beta1/run_function_pb2_grpc.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/py.typed +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/request.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/crossplane/function/resource.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/renovate.json +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/test_request.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/test_resource.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/test_runtime.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/k8s/api/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/k8s/api/resource/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/k8s/api/resource/v1.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/k8s/apimachinery/pkg/apis/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/k8s/apimachinery/pkg/apis/meta/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/k8s/apimachinery/pkg/apis/meta/v1.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/upbound/aws/s3/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/upbound/aws/s3/v1beta2.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/upbound/m/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/upbound/m/aws/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/upbound/m/aws/iam/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/upbound/m/aws/iam/accountalias/__init__.py +0 -0
- {crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/tests/testdata/models/io/upbound/m/aws/iam/accountalias/v1beta1.py +0 -0
|
@@ -38,10 +38,10 @@ jobs:
|
|
|
38
38
|
runs-on: ubuntu-24.04
|
|
39
39
|
steps:
|
|
40
40
|
- name: Checkout
|
|
41
|
-
uses: actions/checkout@
|
|
41
|
+
uses: actions/checkout@v7
|
|
42
42
|
|
|
43
43
|
- name: Setup Python
|
|
44
|
-
uses: actions/setup-python@
|
|
44
|
+
uses: actions/setup-python@v7
|
|
45
45
|
with:
|
|
46
46
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
47
47
|
|
|
@@ -55,10 +55,10 @@ jobs:
|
|
|
55
55
|
runs-on: ubuntu-24.04
|
|
56
56
|
steps:
|
|
57
57
|
- name: Checkout
|
|
58
|
-
uses: actions/checkout@
|
|
58
|
+
uses: actions/checkout@v7
|
|
59
59
|
|
|
60
60
|
- name: Setup Python
|
|
61
|
-
uses: actions/setup-python@
|
|
61
|
+
uses: actions/setup-python@v7
|
|
62
62
|
with:
|
|
63
63
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
64
64
|
|
|
@@ -73,10 +73,10 @@ jobs:
|
|
|
73
73
|
runs-on: ubuntu-24.04
|
|
74
74
|
steps:
|
|
75
75
|
- name: Checkout
|
|
76
|
-
uses: actions/checkout@
|
|
76
|
+
uses: actions/checkout@v7
|
|
77
77
|
|
|
78
78
|
- name: Setup Python
|
|
79
|
-
uses: actions/setup-python@
|
|
79
|
+
uses: actions/setup-python@v7
|
|
80
80
|
with:
|
|
81
81
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
82
82
|
|
|
@@ -120,7 +120,7 @@ jobs:
|
|
|
120
120
|
path: "dist"
|
|
121
121
|
|
|
122
122
|
- name: Publish to PyPI
|
|
123
|
-
uses: pypa/gh-action-pypi-publish@v1.14.
|
|
123
|
+
uses: pypa/gh-action-pypi-publish@v1.14.2
|
|
124
124
|
with:
|
|
125
125
|
# Note that this is currently being pushed to the 'crossplane' PyPI
|
|
126
126
|
# user (not org). See @negz if you need access - PyPI requires 2FA to
|
|
@@ -136,10 +136,10 @@ jobs:
|
|
|
136
136
|
runs-on: ubuntu-24.04
|
|
137
137
|
steps:
|
|
138
138
|
- name: Checkout
|
|
139
|
-
uses: actions/checkout@
|
|
139
|
+
uses: actions/checkout@v7
|
|
140
140
|
|
|
141
141
|
- name: Setup Python
|
|
142
|
-
uses: actions/setup-python@
|
|
142
|
+
uses: actions/setup-python@v7
|
|
143
143
|
with:
|
|
144
144
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
145
145
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: crossplane-function-sdk-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: The Python SDK for Crossplane composition functions
|
|
5
5
|
Project-URL: Documentation, https://github.com/crossplane/function-sdk-python#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/crossplane/function-sdk-python/issues
|
|
@@ -13,9 +13,10 @@ Classifier: Programming Language :: Python
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Classifier: Typing :: Typed
|
|
15
15
|
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: click==8.*
|
|
16
17
|
Requires-Dist: grpcio-reflection==1.*
|
|
17
|
-
Requires-Dist: grpcio==1.
|
|
18
|
-
Requires-Dist: protobuf==7.
|
|
18
|
+
Requires-Dist: grpcio==1.84.0
|
|
19
|
+
Requires-Dist: protobuf==7.36.1
|
|
19
20
|
Requires-Dist: pydantic==2.*
|
|
20
21
|
Requires-Dist: structlog==26.*
|
|
21
22
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Copyright 2025 The Crossplane Authors.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Python SDK for writing Crossplane composition functions.
|
|
16
|
+
|
|
17
|
+
This SDK provides the building blocks for implementing [Crossplane composition
|
|
18
|
+
functions](https://docs.crossplane.io/latest/concepts/composition-functions) in
|
|
19
|
+
Python. Composition functions are serverless components that extend Crossplane's
|
|
20
|
+
composition capability, allowing you to programmatically control how infrastructure
|
|
21
|
+
is composed and managed.
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
Install the SDK:
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
pip install crossplane-function-sdk-python
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Create a composition function by subclassing `Runtime`:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from crossplane.function.runtime import Runtime
|
|
35
|
+
from crossplane.function.request import RunFunctionRequest
|
|
36
|
+
from crossplane.function.response import RunFunctionResponse
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class MyFunction(Runtime):
|
|
40
|
+
def Run(self, request: RunFunctionRequest) -> RunFunctionResponse:
|
|
41
|
+
# Your composition logic here
|
|
42
|
+
return response.to(request)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Modules
|
|
46
|
+
|
|
47
|
+
- **runtime** — Base class for implementing the function runtime and gRPC server.
|
|
48
|
+
- **request** — Types and utilities for parsing `RunFunctionRequest` messages.
|
|
49
|
+
- **response** — Types and utilities for building `RunFunctionResponse` messages.
|
|
50
|
+
- **resource** — Kubernetes resource types used in function pipelines.
|
|
51
|
+
- **logging** — Structured logging utilities for function output.
|
|
52
|
+
|
|
53
|
+
## Protobuf Types
|
|
54
|
+
|
|
55
|
+
The `RunFunctionRequest` and `RunFunctionResponse` types are generated from
|
|
56
|
+
proto3 schema definitions. See the proto modules for API reference:
|
|
57
|
+
|
|
58
|
+
- [`proto.v1.run_function_pb2`][crossplane.function.proto.v1.run_function_pb2]
|
|
59
|
+
— Current API
|
|
60
|
+
- [`proto.v1beta1.run_function_pb2`][crossplane.function.proto.v1beta1.run_function_pb2]
|
|
61
|
+
— Legacy API
|
|
62
|
+
|
|
63
|
+
Proto-generated fields behave like standard Python types but follow
|
|
64
|
+
[protobuf Python conventions](https://protobuf.dev/reference/python/python-generated/).
|
|
65
|
+
"""
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Copyright 2026 The Crossplane Authors.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Standard CLI options for Python composition functions.
|
|
16
|
+
|
|
17
|
+
Provides reusable options and a run helper so that every composition
|
|
18
|
+
function shares a standard set of flags, environment variables, and defaults.
|
|
19
|
+
|
|
20
|
+
Usage in a function's main.py::
|
|
21
|
+
|
|
22
|
+
import click
|
|
23
|
+
from crossplane.function import cli as sdkcli
|
|
24
|
+
from function import fn
|
|
25
|
+
|
|
26
|
+
@click.command()
|
|
27
|
+
@sdkcli.standard_options
|
|
28
|
+
def cli(**kwargs):
|
|
29
|
+
sdkcli.run(fn.FunctionRunner(), **kwargs)
|
|
30
|
+
|
|
31
|
+
To add custom options, stack them with the decorator::
|
|
32
|
+
|
|
33
|
+
@click.command()
|
|
34
|
+
@sdkcli.standard_options
|
|
35
|
+
@click.option("--cache-size", default=100, envvar="CACHE_SIZE")
|
|
36
|
+
def cli(cache_size, **kwargs):
|
|
37
|
+
runner = fn.FunctionRunner(cache_size=cache_size)
|
|
38
|
+
sdkcli.run(runner, **kwargs)
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
import functools
|
|
42
|
+
from collections.abc import Callable
|
|
43
|
+
from typing import TypeVar
|
|
44
|
+
|
|
45
|
+
import click
|
|
46
|
+
|
|
47
|
+
from crossplane.function import logging, runtime
|
|
48
|
+
from crossplane.function.proto.v1 import run_function_pb2_grpc as grpcv1
|
|
49
|
+
|
|
50
|
+
F = TypeVar("F", bound=Callable)
|
|
51
|
+
|
|
52
|
+
DEFAULT_ADDRESS = "0.0.0.0:9443"
|
|
53
|
+
DEFAULT_MAX_RECV_MESSAGE_SIZE = 4 # MB
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def standard_options(func: F) -> F:
|
|
57
|
+
"""Apply the standard Composition Function CLI options to a Click command."""
|
|
58
|
+
|
|
59
|
+
@click.option(
|
|
60
|
+
"--max-recv-message-size",
|
|
61
|
+
type=int,
|
|
62
|
+
default=DEFAULT_MAX_RECV_MESSAGE_SIZE,
|
|
63
|
+
show_default=True,
|
|
64
|
+
envvar="MAX_RECV_MESSAGE_SIZE",
|
|
65
|
+
help="Maximum size of received gRPC messages in MB.",
|
|
66
|
+
)
|
|
67
|
+
@click.option(
|
|
68
|
+
"--insecure",
|
|
69
|
+
is_flag=True,
|
|
70
|
+
envvar="INSECURE",
|
|
71
|
+
help="Run without mTLS credentials. "
|
|
72
|
+
"If you supply this flag --tls-server-certs-dir will be ignored.",
|
|
73
|
+
)
|
|
74
|
+
@click.option(
|
|
75
|
+
"--tls-server-certs-dir",
|
|
76
|
+
"--tls-certs-dir",
|
|
77
|
+
"tls_certs_dir",
|
|
78
|
+
envvar="TLS_SERVER_CERTS_DIR",
|
|
79
|
+
help="Serve using mTLS certificates.",
|
|
80
|
+
)
|
|
81
|
+
@click.option(
|
|
82
|
+
"--address",
|
|
83
|
+
default=DEFAULT_ADDRESS,
|
|
84
|
+
show_default=True,
|
|
85
|
+
envvar="ADDRESS",
|
|
86
|
+
help="Address at which to listen for gRPC connections.",
|
|
87
|
+
)
|
|
88
|
+
@click.option(
|
|
89
|
+
"--debug",
|
|
90
|
+
"-d",
|
|
91
|
+
is_flag=True,
|
|
92
|
+
envvar="DEBUG",
|
|
93
|
+
help="Emit debug logs.",
|
|
94
|
+
)
|
|
95
|
+
@functools.wraps(func)
|
|
96
|
+
def wrapper(*args, **kwargs):
|
|
97
|
+
return func(*args, **kwargs)
|
|
98
|
+
|
|
99
|
+
return wrapper
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def run( # noqa: PLR0913
|
|
103
|
+
function_runner: grpcv1.FunctionRunnerServiceServicer,
|
|
104
|
+
*,
|
|
105
|
+
debug: bool,
|
|
106
|
+
address: str,
|
|
107
|
+
tls_certs_dir: str | None,
|
|
108
|
+
insecure: bool,
|
|
109
|
+
max_recv_message_size: int,
|
|
110
|
+
) -> None:
|
|
111
|
+
"""Start a composition function gRPC server with standard options."""
|
|
112
|
+
level = logging.Level.DEBUG if debug else logging.Level.INFO
|
|
113
|
+
logging.configure(level=level)
|
|
114
|
+
|
|
115
|
+
size_bytes = max_recv_message_size * 1024 * 1024
|
|
116
|
+
options = [
|
|
117
|
+
("grpc.max_receive_message_length", size_bytes),
|
|
118
|
+
("grpc.max_send_message_length", size_bytes),
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
runtime.serve(
|
|
122
|
+
function_runner,
|
|
123
|
+
address,
|
|
124
|
+
creds=runtime.load_credentials(tls_certs_dir),
|
|
125
|
+
insecure=insecure,
|
|
126
|
+
options=options,
|
|
127
|
+
)
|
|
@@ -163,13 +163,16 @@ def require_resources( # noqa: PLR0913
|
|
|
163
163
|
namespace: The namespace to search in (optional).
|
|
164
164
|
|
|
165
165
|
Raises:
|
|
166
|
-
ValueError: If both match_name and match_labels are provided
|
|
166
|
+
ValueError: If both match_name and match_labels are provided.
|
|
167
167
|
|
|
168
168
|
This tells Crossplane to fetch the specified resources and include them
|
|
169
169
|
in the next call to the function in req.required_resources[name].
|
|
170
|
+
|
|
171
|
+
If neither match_name nor match_labels is provided, all resources of the
|
|
172
|
+
given api_version and kind are matched.
|
|
170
173
|
"""
|
|
171
|
-
if
|
|
172
|
-
msg = "
|
|
174
|
+
if match_name is not None and match_labels is not None:
|
|
175
|
+
msg = "match_name and match_labels are mutually exclusive"
|
|
173
176
|
raise ValueError(msg)
|
|
174
177
|
|
|
175
178
|
selector = fnv1.ResourceSelector(
|
|
@@ -70,7 +70,7 @@ def load_credentials(tls_certs_dir: str) -> grpc.ServerCredentials:
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def serve(
|
|
73
|
-
function: grpcv1.
|
|
73
|
+
function: grpcv1.FunctionRunnerServiceServicer,
|
|
74
74
|
address: str,
|
|
75
75
|
*,
|
|
76
76
|
creds: grpc.ServerCredentials,
|
|
@@ -95,7 +95,10 @@ def serve(
|
|
|
95
95
|
are supplied.
|
|
96
96
|
"""
|
|
97
97
|
# Define the loop before the server so everything uses the same loop.
|
|
98
|
-
|
|
98
|
+
try:
|
|
99
|
+
loop = asyncio.get_event_loop()
|
|
100
|
+
except RuntimeError:
|
|
101
|
+
loop = asyncio.new_event_loop()
|
|
99
102
|
|
|
100
103
|
server = grpc.aio.server(options=options)
|
|
101
104
|
|
|
@@ -134,20 +137,20 @@ def serve(
|
|
|
134
137
|
loop.close()
|
|
135
138
|
|
|
136
139
|
|
|
137
|
-
class BetaFunctionRunner(grpcv1beta1.
|
|
140
|
+
class BetaFunctionRunner(grpcv1beta1.FunctionRunnerServiceServicer):
|
|
138
141
|
"""A BetaFunctionRunner handles beta gRPC RunFunctionRequests.
|
|
139
142
|
|
|
140
|
-
It handles requests by passing them to a wrapped v1.
|
|
143
|
+
It handles requests by passing them to a wrapped v1.FunctionRunnerServiceServicer.
|
|
141
144
|
Incoming v1beta1 requests are converted to v1 by round-tripping them through
|
|
142
145
|
serialization. Outgoing requests are converted from v1 to v1beta1 the same
|
|
143
146
|
way.
|
|
144
147
|
"""
|
|
145
148
|
|
|
146
|
-
def __init__(self, wrapped: grpcv1.
|
|
149
|
+
def __init__(self, wrapped: grpcv1.FunctionRunnerServiceServicer):
|
|
147
150
|
"""Create a new BetaFunctionRunner."""
|
|
148
151
|
self.wrapped = wrapped
|
|
149
152
|
|
|
150
|
-
async def RunFunction( # noqa: N802 # gRPC requires this name.
|
|
153
|
+
async def RunFunction( # noqa: N802 # gRPC requires this name. # pyright: ignore[reportIncompatibleMethodOverride]
|
|
151
154
|
self, req: fnv1beta1.RunFunctionRequest, context: grpc.aio.ServicerContext
|
|
152
155
|
) -> fnv1beta1.RunFunctionResponse:
|
|
153
156
|
"""Run the underlying function."""
|
{crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/pyproject.toml
RENAMED
|
@@ -18,9 +18,10 @@ classifiers = [
|
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
dependencies = [
|
|
21
|
-
"
|
|
21
|
+
"click==8.*",
|
|
22
|
+
"grpcio==1.84.0",
|
|
22
23
|
"grpcio-reflection==1.*",
|
|
23
|
-
"protobuf==7.
|
|
24
|
+
"protobuf==7.36.1", # Must be compatible with grpcio-tools.
|
|
24
25
|
"pydantic==2.*",
|
|
25
26
|
"structlog==26.*",
|
|
26
27
|
]
|
|
@@ -233,6 +233,21 @@ class TestResponse(unittest.TestCase):
|
|
|
233
233
|
match_name="worker-1",
|
|
234
234
|
),
|
|
235
235
|
),
|
|
236
|
+
TestCase(
|
|
237
|
+
reason="Should match all resources of a kind with no match field.",
|
|
238
|
+
rsp=fnv1.RunFunctionResponse(),
|
|
239
|
+
name="all-pods",
|
|
240
|
+
api_version="v1",
|
|
241
|
+
kind="Pod",
|
|
242
|
+
match_name=None,
|
|
243
|
+
match_labels=None,
|
|
244
|
+
namespace="default",
|
|
245
|
+
want_selector=fnv1.ResourceSelector(
|
|
246
|
+
api_version="v1",
|
|
247
|
+
kind="Pod",
|
|
248
|
+
namespace="default",
|
|
249
|
+
),
|
|
250
|
+
),
|
|
236
251
|
]
|
|
237
252
|
|
|
238
253
|
for case in cases:
|
|
@@ -270,17 +285,6 @@ class TestResponse(unittest.TestCase):
|
|
|
270
285
|
match_labels={"app": "test"},
|
|
271
286
|
)
|
|
272
287
|
|
|
273
|
-
# Should raise ValueError if neither match_name nor match_labels are provided
|
|
274
|
-
with self.assertRaises(ValueError):
|
|
275
|
-
response.require_resources(
|
|
276
|
-
rsp,
|
|
277
|
-
"test",
|
|
278
|
-
"v1",
|
|
279
|
-
"Pod",
|
|
280
|
-
match_name=None,
|
|
281
|
-
match_labels=None,
|
|
282
|
-
)
|
|
283
|
-
|
|
284
288
|
def test_require_schema(self) -> None:
|
|
285
289
|
@dataclasses.dataclass
|
|
286
290
|
class TestCase:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{crossplane_function_sdk_python-0.13.0 → crossplane_function_sdk_python-0.15.0}/renovate.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|