crossplane-function-pythonic 0.6.1__py3-none-any.whl → 0.6.2__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.
@@ -1,2 +1,2 @@
1
1
  # This is set at build time, using "hatch version"
2
- __version__ = "0.6.1"
2
+ __version__ = "0.6.2"
@@ -112,6 +112,7 @@ class BaseComposite:
112
112
  self.context = self.response.context
113
113
  self.environment = self.context['apiextensions.crossplane.io/environment']
114
114
  self.requireds = Requireds(self)
115
+ self.watched = self.requireds['ops.crossplane.io/watched-resource'][0]
115
116
  self.schemas = Schemas(self)
116
117
  self.resources = Resources(self)
117
118
  self.autoReady = True
@@ -43,19 +43,26 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
43
43
 
44
44
  async def run_function(self, request):
45
45
  composite = request.observed.composite.resource
46
- name = list(reversed(composite['apiVersion'].split('/')[0].split('.')))
47
- name.append(composite['kind'])
48
- name.append(composite['metadata']['name'])
49
- logger = logging.getLogger('.'.join(name))
50
-
51
- if 'inlined' in request.input and request.input['inlined']:
52
- if 'spec' not in composite or request.input['inlined'] not in composite['spec']:
53
- return self.fatal(request, logger, f"Missing inlined spec.{request.input['inlined']}")
54
- composite = composite['spec'][request.input['inlined']]
46
+ if composite and composite.fields:
47
+ name = list(reversed(composite['apiVersion'].split('/')[0].split('.')))
48
+ name.append(composite['kind'])
49
+ name.append(composite['metadata']['name'])
50
+ logger = logging.getLogger('.'.join(name))
51
+ if 'inlined' in request.input and request.input['inlined']:
52
+ if 'spec' not in composite or request.input['inlined'] not in composite['spec']:
53
+ return self.fatal(request, logger, f"Missing inlined spec.{request.input['inlined']}")
54
+ composite = composite['spec'][request.input['inlined']]
55
+ else:
56
+ if 'composite' not in request.input:
57
+ return self.fatal(request, logger, 'Missing composition input "composite"')
58
+ composite = request.input['composite']
59
+ operation = False
55
60
  else:
61
+ logger = logging.getLogger('operation')
56
62
  if 'composite' not in request.input:
57
- return self.fatal(request, logger, 'Missing input "composite"')
63
+ return self.fatal(request, logger, 'Missing operation input "composite"')
58
64
  composite = request.input['composite']
65
+ operation = True
59
66
 
60
67
  # Ideally this is something the Function API provides
61
68
  if 'step' in request.input:
@@ -97,6 +104,12 @@ class FunctionRunner(grpcv1.FunctionRunnerService):
97
104
  return self.fatal(request, logger, f"{composite} is not a subclass of BaseComposite")
98
105
  self.clazzes[composite] = clazz
99
106
 
107
+ if operation:
108
+ if '\n' in composite:
109
+ logger = logging.getLogger(f"operation.{clazz.__name__}")
110
+ else:
111
+ logger = logging.getLogger(f"operation.{composite}")
112
+
100
113
  try:
101
114
  composite = clazz(self.crossplane_v1, request, logger)
102
115
  except Exception as e:
@@ -158,19 +158,23 @@ def package_delete(action, package_dir, package, logger):
158
158
 
159
159
  def validate_entry(name, value, logger):
160
160
  if isinstance(value, str):
161
- if not name.endswith('.py'):
162
- if '.' in name or '/' in name:
163
- logger.error(f"Python package file name is not valid: {name}")
161
+ if name.endswith('.py'):
162
+ name = name[:-3]
163
+ if not name.isidentifier():
164
+ logger.error(f"Python module name is not an identifier: {name}")
164
165
  return False
165
- return True
166
- name = name[:-3]
167
- elif not isinstance(value, dict):
166
+ else:
167
+ if '/' in name:
168
+ logger.error(f"Python file name is not valid: {name}")
169
+ return False
170
+ elif isinstance(value, dict):
171
+ if not name.isidentifier():
172
+ logger.error(f"Python package name is not an identifier: {name}")
173
+ return False
174
+ else:
168
175
  logger.error(f"Python package \"{name}\" value is not a valid type: {value.__class__}")
169
176
  return False
170
- if name.isidentifier():
171
- return True
172
- logger.error(f"Python package name is not an identifier: {name}")
173
- return False
177
+ return True
174
178
 
175
179
 
176
180
  def package_file_name(package_name):
@@ -287,7 +287,7 @@ class Command(command.Command):
287
287
  context[key_value[0]] = protobuf.Yaml(key_value[1])
288
288
  return context
289
289
 
290
- async def render(self, composite, observed=[], composition=None, resources=[], schemas=[], context=None, api=None, render_unknowns=False, crossplane_v1=False, composite_observeds=True):
290
+ async def render(self, composite, observed=[], composition=None, resources=[], schemas=[], context=None, api=None, render_unknowns=False, crossplane_v1=False, composite_observeds=False):
291
291
  # Create the request used when running Composition steps.
292
292
  request = protobuf.Message(None, 'request', fnv1.RunFunctionRequest.DESCRIPTOR, fnv1.RunFunctionRequest())
293
293
  if context is not None:
@@ -491,7 +491,7 @@ class Command(command.Command):
491
491
  for condition in conditions:
492
492
  composite.status.conditions[protobuf.append] = condition
493
493
 
494
- return protobuf.Map(
494
+ response = protobuf.Map(
495
495
  composite=composite,
496
496
  connection=protobuf.Map(
497
497
  apiVersion='render.crossplane.io/v1beta1',
@@ -506,6 +506,10 @@ class Command(command.Command):
506
506
  values=request.context,
507
507
  ),
508
508
  )
509
+ if composite_observeds:
510
+ for name, resource in request.observed.resources:
511
+ response.observed[name] = resource.resource
512
+ return response
509
513
 
510
514
  async def get_composite_ref(self, composite, ref, request, resources, api):
511
515
  namespace = ref.namespace
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: crossplane-function-pythonic
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: A Python centric Crossplane Function
5
5
  Project-URL: Documentation, https://github.com/crossplane-contrib/function-pythonic#readme
6
6
  Project-URL: Issues, https://github.com/crossplane-contrib/function-pythonic/issues
@@ -14,15 +14,15 @@ Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Classifier: Programming Language :: Python :: 3.14
16
16
  Requires-Python: <3.15,>=3.12
17
- Requires-Dist: grpcio==1.80.0
17
+ Requires-Dist: grpcio==1.83.0
18
18
  Requires-Dist: inflect==7.5.0
19
19
  Requires-Dist: kr8s==0.20.15
20
- Requires-Dist: protobuf==7.35.0
20
+ Requires-Dist: protobuf==7.35.1
21
21
  Requires-Dist: pyyaml==6.0.3
22
22
  Provides-Extra: packages
23
- Requires-Dist: kopf==1.44.5; extra == 'packages'
23
+ Requires-Dist: kopf==1.44.6; extra == 'packages'
24
24
  Provides-Extra: pip-install
25
- Requires-Dist: pip==26.1.1; extra == 'pip-install'
25
+ Requires-Dist: pip==26.2.1; extra == 'pip-install'
26
26
  Description-Content-Type: text/markdown
27
27
 
28
28
  # function-pythonic
@@ -315,6 +315,7 @@ The BaseComposite also provides access to the following Crossplane Function leve
315
315
  | self.context | Map | The response context, initialized from the request context |
316
316
  | self.environment | Map | The response environment, initialized from the request context environment |
317
317
  | self.requireds | Requireds | Request and read additional local Kubernetes resources |
318
+ | self.watched | RequiredResource | THe WatchOperation's changed resource |
318
319
  | self.schemas | Schemas | Request and read CustomResourceDefinition schemas |
319
320
  | self.resources | Resources | Define and process composed resources |
320
321
  | self.usages| Boolean | Generate Crossplane Usages for resource dependencies, default False |
@@ -1,22 +1,22 @@
1
- crossplane/pythonic/__about__.py,sha256=BmpWZgjXb-VKaTW2Ok13c3aMep0Fd7G8hL8yn1f5Ak0,73
1
+ crossplane/pythonic/__about__.py,sha256=lp1cncWqqXnp4alb9n5yMYyDvn1-wYEyjOf2hb-LSkU,73
2
2
  crossplane/pythonic/__init__.py,sha256=cRk12kc18RLhc9s5dW6sQqZSCEp80fooRO5zxXqc1oA,292
3
3
  crossplane/pythonic/__main__.py,sha256=6vYRlYDJtqFgLyiTamnl3htiNOtz8QlDl5WlIP98I8o,31
4
4
  crossplane/pythonic/auto_ready.py,sha256=sPetUuJRhwZbg9muaDmbdqmtTIIUDmY4qoadoJA0EtQ,7201
5
5
  crossplane/pythonic/command.py,sha256=aT58WBrhU_scaOGeqmsBfofIDnXyW1CQOpCktVGBj5s,4211
6
- crossplane/pythonic/composite.py,sha256=jEMXPy9PchOLZxWDGq5ni6lq3g9guItU5hMZi98ZO34,34440
7
- crossplane/pythonic/function.py,sha256=sea1BJ9_lOPlhYyD8tO9PV6ieeRb-iQOeez07pG2vZk,18535
6
+ crossplane/pythonic/composite.py,sha256=Ckfma16upi7Kb9J2wTANzUO_493FAL_tjxeKYRTvMaQ,34519
7
+ crossplane/pythonic/function.py,sha256=wJv6NRIqQiY3Nbm4on8zJa-UOBkRShnnrb-3S4lJ8Hg,19170
8
8
  crossplane/pythonic/grpc.py,sha256=F3BrfjISGRS2TKeoxUjWeA1LopBaFlZ6nCq_Hei4Di8,5681
9
9
  crossplane/pythonic/main.py,sha256=ujUa_FYElQSGqnhZ-0NJrD3kSyYjfRbIp79FV2Yl7hs,599
10
- crossplane/pythonic/packages.py,sha256=cOlF-wo2CzknwFPAfuwgCiwdT5vDE4n7oBMfQErVzbA,7023
10
+ crossplane/pythonic/packages.py,sha256=xUXJwcG9VFQPNXLJbhdLelUxLehXVATxpehgux03FM8,7166
11
11
  crossplane/pythonic/protobuf.py,sha256=1Yj8Cgku0w0UYU3dOh6QIaE8HFtkdkhL9b5UERzwAQ0,53978
12
- crossplane/pythonic/render.py,sha256=lz65rwcg3EvzdWMTUMMA6PvSHqMVTTkrEK11lLe-0XY,33804
12
+ crossplane/pythonic/render.py,sha256=hv1WOheBx7pXjUwuO17N7aS_qG0mWWu72xt7WzaMXxg,33987
13
13
  crossplane/pythonic/version.py,sha256=-RiB0p146ayqJj0SXfYxTNv49u9Fx9pPgm59Ji2blhc,214
14
14
  crossplane/pythonic/proto/v1/run_function.proto,sha256=GbJ0wVUEjfpMsn2DsnhiPvtmL09z3oyMbWwf6viQtiw,16676
15
15
  crossplane/pythonic/proto/v1/run_function_pb2.py,sha256=adoDilRP8JNSsNWtvLQv8egrlnmpnZk8qbo3REMR8EY,14440
16
16
  crossplane/pythonic/proto/v1/run_function_pb2.pyi,sha256=MvjcY39d1xJ4ZZmRibhehCKF1mHVGb6qfpoCQO8XYqE,14374
17
17
  crossplane/pythonic/proto/v1/run_function_pb2_grpc.py,sha256=mwfE6i_TQHEfh-KemCT10fKA6jlyZ1A0Ih1z6nELkXk,3968
18
- crossplane_function_pythonic-0.6.1.dist-info/METADATA,sha256=4RBD7g6NimpRSnPQ_qj54B7-k4uk8iSH5Xc7EzHOFfQ,36686
19
- crossplane_function_pythonic-0.6.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
20
- crossplane_function_pythonic-0.6.1.dist-info/entry_points.txt,sha256=jJ4baywFDviB9WyAhyhNYF2VOCb6XtbRSjKf7bnBwhg,68
21
- crossplane_function_pythonic-0.6.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
- crossplane_function_pythonic-0.6.1.dist-info/RECORD,,
18
+ crossplane_function_pythonic-0.6.2.dist-info/METADATA,sha256=W6QDxA8GUWQ7CJEzKdqsnjEHJyKfXCs8mOG1O3W3vxY,36762
19
+ crossplane_function_pythonic-0.6.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
20
+ crossplane_function_pythonic-0.6.2.dist-info/entry_points.txt,sha256=jJ4baywFDviB9WyAhyhNYF2VOCb6XtbRSjKf7bnBwhg,68
21
+ crossplane_function_pythonic-0.6.2.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
22
+ crossplane_function_pythonic-0.6.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.29.0
2
+ Generator: hatchling 1.32.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any