crossplane-function-pythonic 0.6.2__py3-none-any.whl → 0.7.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.
@@ -1,2 +1,6 @@
1
- # This is set at build time, using "hatch version"
2
- __version__ = "0.6.2"
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ try:
4
+ __version__ = version("crossplane-function-pythonic")
5
+ except PackageNotFoundError:
6
+ __version__ = "0.0.0"
@@ -1,17 +1,25 @@
1
-
2
-
3
1
  from .composite import BaseComposite
4
- from .protobuf import append, Map, List, Unknown, Yaml, YamlAll, Json, B64Encode, B64Decode
2
+ from .protobuf import (
3
+ B64Decode,
4
+ B64Encode,
5
+ Json,
6
+ List,
7
+ Map,
8
+ Unknown,
9
+ Yaml,
10
+ YamlAll,
11
+ append,
12
+ )
5
13
 
6
14
  __all__ = [
7
- 'BaseComposite',
8
- 'append',
9
- 'Map',
10
- 'List',
11
- 'Unknown',
12
- 'Yaml',
13
- 'YamlAll',
14
- 'Json',
15
- 'B64Encode',
16
- 'B64Decode',
15
+ "B64Decode",
16
+ "B64Encode",
17
+ "BaseComposite",
18
+ "Json",
19
+ "List",
20
+ "Map",
21
+ "Unknown",
22
+ "Yaml",
23
+ "YamlAll",
24
+ "append",
17
25
  ]
@@ -1,2 +1,3 @@
1
1
  from . import main
2
+
2
3
  main.main()
@@ -1,14 +1,24 @@
1
+ from typing import TYPE_CHECKING
1
2
 
2
- def resource_ready(resource):
3
+ if TYPE_CHECKING:
4
+ from . import (
5
+ composite,
6
+ protobuf,
7
+ )
8
+
9
+
10
+ def resource_ready(resource: composite.Resource) -> protobuf.Value | None:
3
11
  if not resource.observed:
4
12
  return None
5
- return _checks.get((resource.observed.apiVersion, resource.observed.kind), _check_default).ready(resource)
13
+ return _checks.get(
14
+ (resource.observed.apiVersion, resource.observed.kind), _check_default
15
+ ).ready(resource)
6
16
 
7
17
 
8
18
  class ReadyCondition:
9
- def ready(self, resource):
19
+ def ready(self, resource: composite.Resource) -> protobuf.Value | None:
10
20
  ready = resource.conditions.Ready
11
- if not ready._find_condition():
21
+ if not ready._get_condition():
12
22
  return None
13
23
  if ready.status:
14
24
  return resource.observed.metadata.name
@@ -16,36 +26,43 @@ class ReadyCondition:
16
26
  return resource.status.notReadyCondition[ready.reason]
17
27
  return resource.status.notReadyCondition
18
28
 
19
- _checks = {}
29
+
30
+ _checks: dict[tuple, Check] = {}
20
31
  _check_default = ReadyCondition()
21
32
 
33
+
22
34
  class Check:
23
35
  @classmethod
24
36
  def __init_subclass__(cls, **kwargs):
25
37
  super().__init_subclass__(**kwargs)
26
- if hasattr(cls, 'apiVersion'):
38
+ if hasattr(cls, "apiVersion"):
27
39
  _checks[(cls.apiVersion, cls.__name__)] = cls()
28
40
 
29
- def ready(self, resource):
41
+ def ready(self, resource: composite.Resource) -> protobuf.Value | None:
30
42
  raise NotImplementedError()
31
43
 
44
+
32
45
  class AlwaysReady(Check):
33
- def ready(self, resource):
46
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
34
47
  return resource.observed.metadata.name
35
48
 
36
49
 
37
50
  class ClusterRole(AlwaysReady):
38
- apiVersion = 'rbac.authorization.k8s.io/v1'
51
+ apiVersion = "rbac.authorization.k8s.io/v1"
52
+
39
53
 
40
54
  class ClusterRoleBinding(AlwaysReady):
41
- apiVersion = 'rbac.authorization.k8s.io/v1'
55
+ apiVersion = "rbac.authorization.k8s.io/v1"
56
+
42
57
 
43
58
  class ConfigMap(AlwaysReady):
44
- apiVersion = 'v1'
59
+ apiVersion = "v1"
60
+
45
61
 
46
62
  class CronJob(Check):
47
- apiVersion = 'batch/v1'
48
- def ready(self, resource):
63
+ apiVersion = "batch/v1"
64
+
65
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
49
66
  if resource.observed.spec.suspend and len(resource.observed.spec.suspend):
50
67
  return resource.observed.metadata.name
51
68
  if not resource.status.lastScheduleTime:
@@ -54,17 +71,21 @@ class CronJob(Check):
54
71
  return resource.observed.metadata.name
55
72
  if not resource.status.lastSuccessfulTime:
56
73
  return resource.status.lastSuccessfulTime
57
- if str(resource.status.lastSuccessfulTime) < str(resource.status.lastScheduleTime):
74
+ if str(resource.status.lastSuccessfulTime) < str(
75
+ resource.status.lastScheduleTime
76
+ ):
58
77
  return resource.status.successfulBeforeSchedule
59
78
  return resource.observed.metadata.name
60
79
 
80
+
61
81
  class DaemonSet(Check):
62
- apiVersion = 'apps/v1'
63
- def ready(self, resource):
82
+ apiVersion = "apps/v1"
83
+
84
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
64
85
  scheduled = resource.status.desiredNumberScheduled
65
86
  if not scheduled:
66
87
  return scheduled
67
- for field in ('numberReady', 'updatedNumberScheduled', 'numberAvailable'):
88
+ for field in ("numberReady", "updatedNumberScheduled", "numberAvailable"):
68
89
  value = resource.status[field]
69
90
  if not value:
70
91
  return value
@@ -72,16 +93,18 @@ class DaemonSet(Check):
72
93
  return resource.status[f"{field}NotScheduled"]
73
94
  return resource.observed.metadata.name
74
95
 
96
+
75
97
  class Deployment(Check):
76
- apiVersion = 'apps/v1'
77
- def ready(self, resource):
98
+ apiVersion = "apps/v1"
99
+
100
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
78
101
  replicas = resource.observed.spec.replicas or 1
79
- for field in ('updatedReplicas', 'availableReplicas'):
102
+ for field in ("updatedReplicas", "availableReplicas"):
80
103
  value = resource.status[field]
81
104
  if not value:
82
105
  return value
83
106
  if replicas != value:
84
- return resource.status[F"{field}NotReplicas"]
107
+ return resource.status[f"{field}NotReplicas"]
85
108
  available = resource.conditions.Available
86
109
  if not available:
87
110
  return resource.status.notAvailable
@@ -91,28 +114,39 @@ class Deployment(Check):
91
114
  return resource.status.notAvailable
92
115
  return resource.observed.metadata.name
93
116
 
117
+
94
118
  class HorizontalPodAutoscaler(Check):
95
- apiVersion = 'autoscaling/v2'
96
- def ready(self, resource):
97
- for type in ('FailedGetScale', 'FailedUpdateScale', 'FailedGetResourceMetric', 'InvalidSelector'):
119
+ apiVersion = "autoscaling/v2"
120
+
121
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
122
+ for type in (
123
+ "FailedGetScale",
124
+ "FailedUpdateScale",
125
+ "FailedGetResourceMetric",
126
+ "InvalidSelector",
127
+ ):
98
128
  if resource.conditions[type].status:
99
129
  return resource.status[f"is{type}"]
100
- for type in ('ScalingActive', 'ScalingLimited'):
130
+ for type in ("ScalingActive", "ScalingLimited"):
101
131
  if resource.conditions[type].status:
102
132
  return resource.observed.metadata.name
103
- return resource.status.notScalingActiveOrLimiited
133
+ return resource.status.notScalingActiveOrLimited
134
+
104
135
 
105
136
  class Ingress(Check):
106
- apiVersion = 'networking.k8s.io/v1'
107
- def ready(self, resource):
137
+ apiVersion = "networking.k8s.io/v1"
138
+
139
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
108
140
  if not len(resource.status.loadBalancer.ingress):
109
- return resource.status.noLoadBalanceIngresses
141
+ return resource.status.noLoadBalancerIngresses
110
142
  return resource.observed.metadata.name
111
143
 
144
+
112
145
  class Job(Check):
113
- apiVersion = 'batch/v1'
114
- def ready(self, resource):
115
- for type in ('Failed', 'Suspended'):
146
+ apiVersion = "batch/v1"
147
+
148
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
149
+ for type in ("Failed", "Suspended"):
116
150
  if resource.conditions[type].status:
117
151
  return resource.status[f"is{type}"]
118
152
  complete = resource.conditions.Complete
@@ -124,71 +158,94 @@ class Job(Check):
124
158
  return resource.status.notComplete
125
159
  return resource.observed.metadata.name
126
160
 
161
+
127
162
  class Namespace(AlwaysReady):
128
- apiVersion = 'v1'
163
+ apiVersion = "v1"
164
+
129
165
 
130
166
  class PersistentVolumeClaim(Check):
131
- apiVersion = 'v1'
132
- def ready(self, resource):
133
- if resource.status.phase != 'Bound':
167
+ apiVersion = "v1"
168
+
169
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
170
+ if resource.status.phase != "Bound":
134
171
  return resource.status.phaseNotBound
135
172
  return resource.observed.metadata.name
136
173
 
174
+
137
175
  class Pod(Check):
138
- apiVersion = 'v1'
139
- def ready(self, resource):
140
- if resource.status.phase == 'Succeeded':
176
+ apiVersion = "v1"
177
+
178
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
179
+ if resource.status.phase == "Succeeded":
180
+ return resource.observed.metadata.name
181
+ if (
182
+ resource.status.phase == "Running"
183
+ and resource.observed.spec.restartPolicy == "Always"
184
+ and resource.conditions.Ready.status
185
+ ):
141
186
  return resource.observed.metadata.name
142
- if resource.status.phase == 'Running':
143
- if resource.observed.spec.restartPolicy == 'Always':
144
- if resource.conditions.Ready.status:
145
- return resource.observed.metadata.name
146
187
  return resource.status.notSucceededOrRunning
147
188
 
189
+
148
190
  class ReplicaSet(Check):
149
- apiVersion = 'v1'
150
- def ready(self, resource):
151
- if int(resource.status.observedGeneration) < int(resource.observed.metadata.generation):
191
+ apiVersion = "apps/v1"
192
+
193
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
194
+ if int(resource.status.observedGeneration) < int(
195
+ resource.observed.metadata.generation
196
+ ):
152
197
  return resource.status.priorObservedGeneration
153
198
  if resource.conditions.ReplicaFailure.status:
154
199
  if resource.conditions.ReplicaFailure.reason:
155
- return resource.status.isReplicaFailure[resource.conditions.ReplicaFailure.reason]
200
+ return resource.status.isReplicaFailure[
201
+ resource.conditions.ReplicaFailure.reason
202
+ ]
156
203
  return resource.status.isReplicaFailure
157
- if int(resource.status.availableReplicas) < int(resource.observed.spec.replicas or 1):
158
- return resource.status.tooFewavailableReplicas
204
+ if int(resource.status.availableReplicas) < int(
205
+ resource.observed.spec.replicas or 1
206
+ ):
207
+ return resource.status.tooFewAvailableReplicas
159
208
  return resource.observed.metadata.name
160
209
 
210
+
161
211
  class Role(AlwaysReady):
162
- apiVersion = 'rbac.authorization.k8s.io/v1'
212
+ apiVersion = "rbac.authorization.k8s.io/v1"
213
+
163
214
 
164
215
  class RoleBinding(AlwaysReady):
165
- apiVersion = 'rbac.authorization.k8s.io/v1'
216
+ apiVersion = "rbac.authorization.k8s.io/v1"
217
+
166
218
 
167
219
  class Secret(AlwaysReady):
168
- apiVersion = 'v1'
220
+ apiVersion = "v1"
221
+
169
222
 
170
223
  class Service(Check):
171
- apiVersion = 'v1'
172
- def ready(self, resource):
173
- if resource.observed.spec.type != 'LoadBalancer':
224
+ apiVersion = "v1"
225
+
226
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
227
+ if resource.observed.spec.type != "LoadBalancer":
174
228
  return resource.observed.metadata.name
175
229
  if not len(resource.status.loadBalancer.ingress):
176
230
  return resource.status.noLoadBalancerIngresses
177
231
  return resource.observed.metadata.name
178
232
 
233
+
179
234
  class ServiceAccount(AlwaysReady):
180
- apiVersion = 'v1'
235
+ apiVersion = "v1"
236
+
181
237
 
182
238
  class StatefulSet(Check):
183
- apiVersion = 'apps/v1'
184
- def ready(self, resource):
239
+ apiVersion = "apps/v1"
240
+
241
+ def ready(self, resource: composite.Resource) -> protobuf.Value:
185
242
  replicas = resource.observed.spec.replicas or 1
186
- for field in ('readyReplicas', 'currentReplicas'):
243
+ for field in ("readyReplicas", "currentReplicas"):
187
244
  value = resource.status[field]
188
245
  if not value:
189
246
  return value
190
247
  if replicas != value:
191
- return resource.status[F"{field}NotReplicas"]
248
+ return resource.status[f"{field}NotReplicas"]
192
249
  if resource.status.currentRevision != resource.status.updateRevision:
193
- return resource.status.currentRevisionNotUpdateReivsion
250
+ return resource.status.currentRevisionNotUpdateRevision
194
251
  return resource.observed.metadata.name
@@ -1,76 +1,84 @@
1
-
1
+ import argparse
2
2
  import logging
3
3
  import pathlib
4
4
  import sys
5
5
 
6
6
 
7
7
  class Command:
8
- name = None
9
- command = None
10
- description = None
8
+ name: str | None = None
9
+ command: str | None = None
10
+ help: str | None = None
11
+ description: str | None = None
11
12
 
12
13
  @classmethod
13
- def create(cls, subparsers):
14
- parser = subparsers.add_parser(cls.name, help=cls.help, description=cls.description)
15
- parser.set_defaults(command=cls)
16
- cls.add_parser_arguments(parser)
14
+ def create(
15
+ cls, subparsers: argparse._SubParsersAction[argparse.ArgumentParser]
16
+ ) -> None:
17
+ if cls.name is not None:
18
+ parser: argparse.ArgumentParser = subparsers.add_parser(
19
+ cls.name, help=cls.help, description=cls.description
20
+ )
21
+ parser.set_defaults(command=cls)
22
+ cls.add_parser_arguments(parser)
17
23
 
18
24
  @classmethod
19
- def add_parser_arguments(cls, parser):
25
+ def add_parser_arguments(cls, parser: argparse.ArgumentParser) -> None:
20
26
  pass
21
27
 
22
28
  @classmethod
23
- def add_function_arguments(cls, parser):
29
+ def add_function_arguments(cls, parser: argparse.ArgumentParser) -> None:
24
30
  parser.add_argument(
25
- '--debug', '-d',
26
- action='store_true',
27
- help='Emit debug logs.',
31
+ "--debug",
32
+ "-d",
33
+ action="store_true",
34
+ help="Emit debug logs.",
28
35
  )
29
36
  parser.add_argument(
30
- '--log-name-width',
37
+ "--log-name-width",
31
38
  type=int,
32
39
  default=40,
33
- metavar='WIDTH',
34
- help='Width of the logger name in the log output, default 40.',
40
+ metavar="WIDTH",
41
+ help="Width of the logger name in the log output, default 40.",
35
42
  )
36
43
  parser.add_argument(
37
- '--logger-level',
38
- action='append',
44
+ "--logger-level",
45
+ action="append",
39
46
  default=[],
40
- metavar='LOGGER=LEVEL',
41
- help='Logger level, for example: botocore.hooks=INFO',
47
+ metavar="LOGGER=LEVEL",
48
+ help="Logger level, for example: botocore.hooks=INFO",
42
49
  )
43
50
  parser.add_argument(
44
- '--python-path',
45
- action='append',
51
+ "--python-path",
52
+ action="append",
46
53
  default=[],
47
- metavar='DIRECTORY',
48
- help='Filing system directories to add to the python path.',
54
+ metavar="DIRECTORY",
55
+ help="Filing system directories to add to the python path.",
49
56
  )
50
57
  parser.add_argument(
51
- '--render-unknowns', '-u',
52
- action='store_true',
53
- help='Render resources with unknowns, useful during local development.'
58
+ "--render-unknowns",
59
+ "-u",
60
+ action="store_true",
61
+ help="Render resources with unknowns, useful during local development.",
54
62
  )
55
63
  parser.add_argument(
56
- '--allow-oversize-protos',
57
- action='store_true',
58
- help='Allow oversized protobuf messages',
64
+ "--allow-oversize-protos",
65
+ action="store_true",
66
+ help="Allow oversized protobuf messages",
59
67
  )
60
68
  parser.add_argument(
61
- '--crossplane-v1',
62
- action='store_true',
63
- help='Enable Crossplane V1 compatibility mode',
69
+ "--crossplane-v1",
70
+ action="store_true",
71
+ help="Enable Crossplane V1 compatibility mode",
64
72
  )
65
73
 
66
- def __init__(self, args=None):
67
- self.args = args
74
+ def __init__(self, args: argparse.Namespace | None = None) -> None:
75
+ self.args = args if args is not None else argparse.Namespace()
68
76
  self.initialize()
69
77
 
70
- def initialize(self):
78
+ def initialize(self) -> None:
71
79
  pass
72
80
 
73
- def initialize_function(self):
81
+ def initialize_function(self) -> None:
74
82
  formatter = Formatter(self.args.log_name_width)
75
83
  handler = logging.StreamHandler(sys.stdout)
76
84
  handler.setFormatter(formatter)
@@ -78,14 +86,14 @@ class Command:
78
86
  logger.handlers = [handler]
79
87
  logger.setLevel(logging.DEBUG if self.args.debug else logging.INFO)
80
88
  # Suppress noisy libraries, these can be overriden using --logger-level
81
- logging.getLogger('asyncio').setLevel(logging.INFO)
82
- logging.getLogger('grpc').setLevel(logging.INFO)
83
- logging.getLogger('httpcore').setLevel(logging.INFO)
84
- logging.getLogger('httpx').setLevel(logging.WARNING)
85
- logging.getLogger('kr8s').setLevel(logging.INFO)
86
- for logger_level in self.args.logger_level:
87
- for logger_level in logger_level.split(','):
88
- logger_level = logger_level.split('=')
89
+ logging.getLogger("asyncio").setLevel(logging.INFO)
90
+ logging.getLogger("grpc").setLevel(logging.INFO)
91
+ logging.getLogger("httpcore").setLevel(logging.INFO)
92
+ logging.getLogger("httpx").setLevel(logging.WARNING)
93
+ logging.getLogger("kr8s").setLevel(logging.INFO)
94
+ for logger_levels in self.args.logger_level:
95
+ for logger_level in logger_levels.split(","):
96
+ logger_level = logger_level.split("=")
89
97
  if len(logger_level) == 2:
90
98
  logging.getLogger(logger_level[0]).setLevel(logger_level[1].upper())
91
99
 
@@ -94,32 +102,35 @@ class Command:
94
102
 
95
103
  if self.args.allow_oversize_protos:
96
104
  from google.protobuf.internal import api_implementation
97
- if api_implementation._c_module:
98
- api_implementation._c_module.SetAllowOversizeProtos(True)
99
105
 
100
- async def run(self):
106
+ c_module = getattr(api_implementation, "_c_module", None)
107
+ if c_module:
108
+ c_module.SetAllowOversizeProtos(True)
109
+
110
+ async def run(self) -> None:
101
111
  raise NotImplementedError()
102
112
 
103
113
 
104
114
  class Formatter(logging.Formatter):
105
- def __init__(self, name_width):
106
- super(Formatter, self).__init__(
115
+ def __init__(self, name_width: int):
116
+ super().__init__(
107
117
  f"[{{asctime}}.{{msecs:03.0f}}] {{sname:{name_width}.{name_width}}} [{{levelname:8.8}}] {{message}}",
108
- '%Y-%m-%d %H:%M:%S',
109
- '{',
118
+ "%Y-%m-%d %H:%M:%S",
119
+ "{",
110
120
  )
111
121
  self.name_width = name_width
112
122
 
113
- def format(self, record):
114
- record.sname = record.name
115
- extra = len(record.sname) - self.name_width
123
+ def format(self, record: logging.LogRecord):
124
+ sname = record.name
125
+ extra = len(sname) - self.name_width
116
126
  if extra > 0:
117
- names = record.sname.split('.')
127
+ names = sname.split(".")
118
128
  for ix, name in enumerate(names):
119
129
  if len(name) > extra:
120
130
  names[ix] = name[extra:]
121
131
  break
122
132
  names[ix] = name[:1]
123
133
  extra -= len(name) - 1
124
- record.sname = '.'.join(names)
125
- return super(Formatter, self).format(record)
134
+ sname = ".".join(names)
135
+ record.sname = sname
136
+ return super().format(record)