crossplane-function-sdk-python 0.12.0__py3-none-any.whl → 0.14.0__py3-none-any.whl

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.
@@ -15,4 +15,4 @@
15
15
  """The version of function-sdk-python."""
16
16
 
17
17
  # This is set at build time, using "hatch version"
18
- __version__ = "0.12.0"
18
+ __version__ = "0.14.0"
@@ -40,12 +40,21 @@ def update(r: fnv1.Resource, source: dict | structpb.Struct | pydantic.BaseModel
40
40
  """
41
41
  match source:
42
42
  case pydantic.BaseModel():
43
- data = source.model_dump(exclude_defaults=True, warnings=False)
44
- # In Pydantic, exclude_defaults=True in model_dump excludes fields
45
- # that have their value equal to the default. If a field like
46
- # apiVersion is set to its default value 's3.aws.upbound.io/v1beta2'
47
- # (and not explicitly provided during initialization), it will be
48
- # excluded from the serialized output.
43
+ # exclude_unset emits only the fields the caller explicitly set.
44
+ # Crossplane treats desired resources as server-side apply intent,
45
+ # so a function should own exactly the fields it has an opinion
46
+ # about and leave the rest to the API server.
47
+ #
48
+ # by_alias emits each field under its alias, which is its real
49
+ # wire name. datamodel-code-generator aliases fields whose KRM
50
+ # name collides with a Python keyword or builtin (e.g. it emits a
51
+ # bool_ attribute aliased to bool, continue_ aliased to continue).
52
+ # Without by_alias those fields serialize under the Python name and
53
+ # don't match the resource's schema. It's a no-op for ordinary
54
+ # fields, which have no alias.
55
+ data = source.model_dump(exclude_unset=True, by_alias=True, warnings=False)
56
+ # apiVersion and kind identify the resource but are rarely passed
57
+ # as kwargs, so they're usually unset. Add them back explicitly.
49
58
  data["apiVersion"] = source.apiVersion
50
59
  data["kind"] = source.kind
51
60
  r.resource.update(data)
@@ -71,11 +80,12 @@ def update_status(
71
80
  status: The status to set, as a dictionary or Pydantic model.
72
81
 
73
82
  Sets ``r.resource.status`` from the supplied status. When the status
74
- is a Pydantic model, fields set to their default value are excluded,
83
+ is a Pydantic model, fields the caller didn't explicitly set are
84
+ excluded and aliased fields are emitted under their wire names,
75
85
  matching the behavior of :func:`update`.
76
86
  """
77
87
  if isinstance(status, pydantic.BaseModel):
78
- status = status.model_dump(exclude_defaults=True, warnings=False)
88
+ status = status.model_dump(exclude_unset=True, by_alias=True, warnings=False)
79
89
  update(r, {"status": status})
80
90
 
81
91
 
@@ -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, or neither.
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 (match_name is None) == (match_labels is None):
172
- msg = "Exactly one of match_name or match_labels must be provided"
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.FunctionRunnerService,
73
+ function: grpcv1.FunctionRunnerServiceServicer,
74
74
  address: str,
75
75
  *,
76
76
  creds: grpc.ServerCredentials,
@@ -134,20 +134,20 @@ def serve(
134
134
  loop.close()
135
135
 
136
136
 
137
- class BetaFunctionRunner(grpcv1beta1.FunctionRunnerService):
137
+ class BetaFunctionRunner(grpcv1beta1.FunctionRunnerServiceServicer):
138
138
  """A BetaFunctionRunner handles beta gRPC RunFunctionRequests.
139
139
 
140
- It handles requests by passing them to a wrapped v1.FunctionRunnerService.
140
+ It handles requests by passing them to a wrapped v1.FunctionRunnerServiceServicer.
141
141
  Incoming v1beta1 requests are converted to v1 by round-tripping them through
142
142
  serialization. Outgoing requests are converted from v1 to v1beta1 the same
143
143
  way.
144
144
  """
145
145
 
146
- def __init__(self, wrapped: grpcv1.FunctionRunnerService):
146
+ def __init__(self, wrapped: grpcv1.FunctionRunnerServiceServicer):
147
147
  """Create a new BetaFunctionRunner."""
148
148
  self.wrapped = wrapped
149
149
 
150
- async def RunFunction( # noqa: N802 # gRPC requires this name.
150
+ async def RunFunction( # noqa: N802 # gRPC requires this name. # pyright: ignore[reportIncompatibleMethodOverride]
151
151
  self, req: fnv1beta1.RunFunctionRequest, context: grpc.aio.ServicerContext
152
152
  ) -> fnv1beta1.RunFunctionResponse:
153
153
  """Run the underlying function."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crossplane-function-sdk-python
3
- Version: 0.12.0
3
+ Version: 0.14.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
@@ -14,10 +14,10 @@ Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Typing :: Typed
15
15
  Requires-Python: >=3.11
16
16
  Requires-Dist: grpcio-reflection==1.*
17
- Requires-Dist: grpcio==1.80.0
17
+ Requires-Dist: grpcio==1.81.0
18
18
  Requires-Dist: protobuf==7.35.0
19
19
  Requires-Dist: pydantic==2.*
20
- Requires-Dist: structlog==25.*
20
+ Requires-Dist: structlog==26.*
21
21
  Description-Content-Type: text/markdown
22
22
 
23
23
  # function-sdk-python
@@ -1,10 +1,10 @@
1
- crossplane/function/__version__.py,sha256=gtv076U2x6TC6KinwdT_-8jd1AkxueHUDZc5tRyideE,705
1
+ crossplane/function/__version__.py,sha256=oKtus0bQUO42aKqWWxuhQxgBpNDRCrC6BLgLMdh_1Vk,705
2
2
  crossplane/function/logging.py,sha256=Zawqq36FBzjkVg4bJ3VGK12-so7N8yAMoSPrhdwpBSA,2503
3
3
  crossplane/function/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  crossplane/function/request.py,sha256=ncgGTyAvBOdZ8M7KPy_H9pL08_cYzKJ3D9q_rnSjPXo,8199
5
- crossplane/function/resource.py,sha256=9tNOsxOzT2mpIbw-tUXfLxH8zs2mGkrkU2JRkFSUN_E,7697
6
- crossplane/function/response.py,sha256=7LR5CFaMOpBU2Fv-TMFe_CFx0mgZXX9WDm7vV8FtwtY,6965
7
- crossplane/function/runtime.py,sha256=2S-AheR2o0pJxJRhDZDoWpJxCleIv_aHTnzRGgrZv_8,5415
5
+ crossplane/function/resource.py,sha256=D9OWyzfQNZhPQFDDFDBqva9bPiKV2nRuivG_L1mBjv4,8386
6
+ crossplane/function/response.py,sha256=H5LnyBBTs6ZGmRfMOXew3o_3DkMEfhi77xG6xGZ8NLo,7072
7
+ crossplane/function/runtime.py,sha256=2Is5E2XuJibWH0CLULhJ_cmMcRYDeBApypZca97l8Xw,5499
8
8
  crossplane/function/proto/v1/run_function.proto,sha256=GbJ0wVUEjfpMsn2DsnhiPvtmL09z3oyMbWwf6viQtiw,16676
9
9
  crossplane/function/proto/v1/run_function_pb2.py,sha256=eeQajHePjvswGCEH2FRxyr8P-K0Go55U5L4rAa32JA8,14440
10
10
  crossplane/function/proto/v1/run_function_pb2.pyi,sha256=MvjcY39d1xJ4ZZmRibhehCKF1mHVGb6qfpoCQO8XYqE,14374
@@ -13,7 +13,7 @@ crossplane/function/proto/v1beta1/run_function.proto,sha256=EVYIEQCiPu1eOdGJQ3tu
13
13
  crossplane/function/proto/v1beta1/run_function_pb2.py,sha256=G4TTK_cYTOQlRN5byADcEFPjTILYYWj3b4m19iiPO4g,14664
14
14
  crossplane/function/proto/v1beta1/run_function_pb2.pyi,sha256=MvjcY39d1xJ4ZZmRibhehCKF1mHVGb6qfpoCQO8XYqE,14374
15
15
  crossplane/function/proto/v1beta1/run_function_pb2_grpc.py,sha256=Hj5KCSTyT_vIpTXWwc5MwiKxwxaOhjbfY5Iedidx9AQ,4033
16
- crossplane_function_sdk_python-0.12.0.dist-info/METADATA,sha256=2l-XG9JHoD_zywEhVUkZQ97iLT05wO4qFEpdeB8Gs3Y,3244
17
- crossplane_function_sdk_python-0.12.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
18
- crossplane_function_sdk_python-0.12.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
19
- crossplane_function_sdk_python-0.12.0.dist-info/RECORD,,
16
+ crossplane_function_sdk_python-0.14.0.dist-info/METADATA,sha256=I3UMTU0jZB9yFSy_w0zy65iIcNgkccljVz2dxGClTUU,3244
17
+ crossplane_function_sdk_python-0.14.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
18
+ crossplane_function_sdk_python-0.14.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
19
+ crossplane_function_sdk_python-0.14.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.29.0
2
+ Generator: hatchling 1.30.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any