infrahub-server 1.2.0rc0__py3-none-any.whl → 1.2.1__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.
Files changed (365) hide show
  1. infrahub/api/dependencies.py +6 -6
  2. infrahub/api/diff/validation_models.py +7 -7
  3. infrahub/api/schema.py +1 -1
  4. infrahub/artifacts/models.py +5 -3
  5. infrahub/artifacts/tasks.py +3 -5
  6. infrahub/cli/__init__.py +13 -9
  7. infrahub/cli/constants.py +3 -0
  8. infrahub/cli/db.py +165 -183
  9. infrahub/cli/upgrade.py +146 -0
  10. infrahub/computed_attribute/gather.py +185 -0
  11. infrahub/computed_attribute/models.py +240 -12
  12. infrahub/computed_attribute/tasks.py +77 -441
  13. infrahub/computed_attribute/triggers.py +13 -47
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +58 -58
  18. infrahub/core/branch/tasks.py +74 -22
  19. infrahub/core/changelog/diff.py +95 -36
  20. infrahub/core/changelog/models.py +217 -43
  21. infrahub/core/constants/__init__.py +28 -0
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constants/schema.py +2 -0
  24. infrahub/core/constraint/node/runner.py +9 -8
  25. infrahub/core/diff/branch_differ.py +10 -10
  26. infrahub/core/diff/enricher/cardinality_one.py +5 -0
  27. infrahub/core/diff/enricher/hierarchy.py +17 -4
  28. infrahub/core/diff/enricher/labels.py +5 -0
  29. infrahub/core/diff/enricher/path_identifier.py +4 -0
  30. infrahub/core/diff/ipam_diff_parser.py +4 -5
  31. infrahub/core/diff/model/diff.py +27 -27
  32. infrahub/core/diff/model/path.py +32 -9
  33. infrahub/core/diff/parent_node_adder.py +78 -0
  34. infrahub/core/diff/payload_builder.py +13 -2
  35. infrahub/core/diff/query/filters.py +2 -2
  36. infrahub/core/diff/query/merge.py +20 -17
  37. infrahub/core/diff/query/save.py +188 -182
  38. infrahub/core/diff/query/summary_counts_enricher.py +51 -4
  39. infrahub/core/diff/query_parser.py +4 -4
  40. infrahub/core/diff/repository/deserializer.py +8 -3
  41. infrahub/core/diff/repository/repository.py +156 -38
  42. infrahub/core/diff/tasks.py +4 -4
  43. infrahub/core/graph/__init__.py +1 -1
  44. infrahub/core/graph/index.py +3 -0
  45. infrahub/core/initialization.py +1 -10
  46. infrahub/core/ipam/constants.py +3 -4
  47. infrahub/core/ipam/reconciler.py +12 -12
  48. infrahub/core/ipam/utilization.py +10 -13
  49. infrahub/core/manager.py +36 -36
  50. infrahub/core/merge.py +7 -7
  51. infrahub/core/migrations/__init__.py +2 -3
  52. infrahub/core/migrations/graph/__init__.py +12 -3
  53. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  54. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  55. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  56. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  57. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  58. infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
  59. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  60. infrahub/core/migrations/query/attribute_add.py +2 -2
  61. infrahub/core/migrations/query/node_duplicate.py +43 -26
  62. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  63. infrahub/core/migrations/schema/models.py +19 -4
  64. infrahub/core/migrations/schema/node_remove.py +26 -12
  65. infrahub/core/migrations/schema/tasks.py +2 -2
  66. infrahub/core/migrations/shared.py +16 -16
  67. infrahub/core/models.py +15 -6
  68. infrahub/core/node/__init__.py +43 -39
  69. infrahub/core/node/base.py +2 -4
  70. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  71. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  72. infrahub/core/node/constraints/interface.py +1 -2
  73. infrahub/core/node/delete_validator.py +3 -5
  74. infrahub/core/node/ipam.py +4 -4
  75. infrahub/core/node/permissions.py +7 -7
  76. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  77. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  78. infrahub/core/node/resource_manager/number_pool.py +3 -3
  79. infrahub/core/path.py +12 -12
  80. infrahub/core/property.py +11 -11
  81. infrahub/core/protocols.py +7 -0
  82. infrahub/core/protocols_base.py +21 -21
  83. infrahub/core/query/__init__.py +33 -33
  84. infrahub/core/query/attribute.py +6 -4
  85. infrahub/core/query/diff.py +3 -3
  86. infrahub/core/query/node.py +82 -32
  87. infrahub/core/query/relationship.py +228 -40
  88. infrahub/core/query/resource_manager.py +2 -0
  89. infrahub/core/query/standard_node.py +3 -3
  90. infrahub/core/query/subquery.py +9 -9
  91. infrahub/core/registry.py +13 -15
  92. infrahub/core/relationship/constraints/count.py +3 -4
  93. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  94. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  95. infrahub/core/relationship/model.py +51 -59
  96. infrahub/core/schema/attribute_schema.py +16 -8
  97. infrahub/core/schema/basenode_schema.py +105 -44
  98. infrahub/core/schema/computed_attribute.py +3 -3
  99. infrahub/core/schema/definitions/core/__init__.py +147 -0
  100. infrahub/core/schema/definitions/core/account.py +171 -0
  101. infrahub/core/schema/definitions/core/artifact.py +136 -0
  102. infrahub/core/schema/definitions/core/builtin.py +24 -0
  103. infrahub/core/schema/definitions/core/check.py +68 -0
  104. infrahub/core/schema/definitions/core/core.py +17 -0
  105. infrahub/core/schema/definitions/core/generator.py +100 -0
  106. infrahub/core/schema/definitions/core/graphql_query.py +79 -0
  107. infrahub/core/schema/definitions/core/group.py +108 -0
  108. infrahub/core/schema/definitions/core/ipam.py +193 -0
  109. infrahub/core/schema/definitions/core/lineage.py +19 -0
  110. infrahub/core/schema/definitions/core/menu.py +48 -0
  111. infrahub/core/schema/definitions/core/permission.py +163 -0
  112. infrahub/core/schema/definitions/core/profile.py +18 -0
  113. infrahub/core/schema/definitions/core/propose_change.py +97 -0
  114. infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
  115. infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
  116. infrahub/core/schema/definitions/core/repository.py +286 -0
  117. infrahub/core/schema/definitions/core/resource_pool.py +170 -0
  118. infrahub/core/schema/definitions/core/template.py +27 -0
  119. infrahub/core/schema/definitions/core/transform.py +96 -0
  120. infrahub/core/schema/definitions/core/webhook.py +134 -0
  121. infrahub/core/schema/definitions/internal.py +16 -16
  122. infrahub/core/schema/dropdown.py +3 -4
  123. infrahub/core/schema/generated/attribute_schema.py +15 -18
  124. infrahub/core/schema/generated/base_node_schema.py +12 -14
  125. infrahub/core/schema/generated/node_schema.py +3 -5
  126. infrahub/core/schema/generated/relationship_schema.py +9 -11
  127. infrahub/core/schema/generic_schema.py +2 -2
  128. infrahub/core/schema/manager.py +20 -9
  129. infrahub/core/schema/node_schema.py +4 -2
  130. infrahub/core/schema/relationship_schema.py +14 -6
  131. infrahub/core/schema/schema_branch.py +292 -144
  132. infrahub/core/schema/schema_branch_computed.py +41 -4
  133. infrahub/core/task/task.py +3 -3
  134. infrahub/core/task/user_task.py +15 -15
  135. infrahub/core/timestamp.py +3 -3
  136. infrahub/core/utils.py +20 -18
  137. infrahub/core/validators/__init__.py +1 -3
  138. infrahub/core/validators/aggregated_checker.py +2 -2
  139. infrahub/core/validators/attribute/choices.py +2 -2
  140. infrahub/core/validators/attribute/enum.py +2 -2
  141. infrahub/core/validators/attribute/kind.py +2 -2
  142. infrahub/core/validators/attribute/length.py +2 -2
  143. infrahub/core/validators/attribute/optional.py +2 -2
  144. infrahub/core/validators/attribute/regex.py +2 -2
  145. infrahub/core/validators/attribute/unique.py +2 -2
  146. infrahub/core/validators/checks_runner.py +25 -2
  147. infrahub/core/validators/determiner.py +1 -3
  148. infrahub/core/validators/interface.py +6 -2
  149. infrahub/core/validators/model.py +22 -3
  150. infrahub/core/validators/models/validate_migration.py +17 -4
  151. infrahub/core/validators/node/attribute.py +2 -2
  152. infrahub/core/validators/node/generate_profile.py +2 -2
  153. infrahub/core/validators/node/hierarchy.py +3 -5
  154. infrahub/core/validators/node/inherit_from.py +27 -5
  155. infrahub/core/validators/node/relationship.py +2 -2
  156. infrahub/core/validators/relationship/count.py +4 -4
  157. infrahub/core/validators/relationship/optional.py +2 -2
  158. infrahub/core/validators/relationship/peer.py +2 -2
  159. infrahub/core/validators/shared.py +2 -2
  160. infrahub/core/validators/tasks.py +8 -0
  161. infrahub/core/validators/uniqueness/checker.py +22 -21
  162. infrahub/core/validators/uniqueness/index.py +2 -2
  163. infrahub/core/validators/uniqueness/model.py +11 -11
  164. infrahub/database/__init__.py +27 -22
  165. infrahub/database/metrics.py +7 -1
  166. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  167. infrahub/dependencies/builder/diff/deserializer.py +3 -1
  168. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  169. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  170. infrahub/dependencies/component/registry.py +2 -2
  171. infrahub/events/__init__.py +25 -2
  172. infrahub/events/artifact_action.py +64 -0
  173. infrahub/events/branch_action.py +33 -22
  174. infrahub/events/generator.py +71 -0
  175. infrahub/events/group_action.py +51 -21
  176. infrahub/events/models.py +18 -19
  177. infrahub/events/node_action.py +88 -37
  178. infrahub/events/repository_action.py +5 -18
  179. infrahub/events/schema_action.py +4 -9
  180. infrahub/events/utils.py +16 -0
  181. infrahub/events/validator_action.py +55 -0
  182. infrahub/exceptions.py +32 -24
  183. infrahub/generators/models.py +2 -3
  184. infrahub/generators/tasks.py +24 -4
  185. infrahub/git/base.py +7 -7
  186. infrahub/git/integrator.py +48 -24
  187. infrahub/git/models.py +101 -9
  188. infrahub/git/repository.py +3 -3
  189. infrahub/git/tasks.py +408 -6
  190. infrahub/git/utils.py +48 -0
  191. infrahub/git/worktree.py +1 -2
  192. infrahub/git_credential/askpass.py +1 -2
  193. infrahub/graphql/analyzer.py +12 -0
  194. infrahub/graphql/app.py +13 -15
  195. infrahub/graphql/context.py +39 -0
  196. infrahub/graphql/initialization.py +3 -0
  197. infrahub/graphql/loaders/node.py +2 -12
  198. infrahub/graphql/loaders/peers.py +77 -0
  199. infrahub/graphql/loaders/shared.py +13 -0
  200. infrahub/graphql/manager.py +17 -19
  201. infrahub/graphql/mutations/artifact_definition.py +5 -5
  202. infrahub/graphql/mutations/branch.py +26 -1
  203. infrahub/graphql/mutations/computed_attribute.py +9 -5
  204. infrahub/graphql/mutations/diff.py +23 -11
  205. infrahub/graphql/mutations/diff_conflict.py +5 -0
  206. infrahub/graphql/mutations/generator.py +83 -0
  207. infrahub/graphql/mutations/graphql_query.py +5 -5
  208. infrahub/graphql/mutations/ipam.py +54 -74
  209. infrahub/graphql/mutations/main.py +195 -132
  210. infrahub/graphql/mutations/menu.py +7 -7
  211. infrahub/graphql/mutations/models.py +2 -4
  212. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  213. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  214. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  215. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  216. infrahub/graphql/mutations/proposed_change.py +7 -7
  217. infrahub/graphql/mutations/relationship.py +93 -19
  218. infrahub/graphql/mutations/repository.py +8 -8
  219. infrahub/graphql/mutations/resource_manager.py +3 -3
  220. infrahub/graphql/mutations/schema.py +19 -4
  221. infrahub/graphql/mutations/webhook.py +137 -0
  222. infrahub/graphql/parser.py +4 -4
  223. infrahub/graphql/permissions.py +1 -10
  224. infrahub/graphql/queries/diff/tree.py +19 -14
  225. infrahub/graphql/queries/event.py +5 -2
  226. infrahub/graphql/queries/ipam.py +2 -2
  227. infrahub/graphql/queries/relationship.py +2 -2
  228. infrahub/graphql/queries/search.py +2 -2
  229. infrahub/graphql/resolvers/many_relationship.py +264 -0
  230. infrahub/graphql/resolvers/resolver.py +13 -110
  231. infrahub/graphql/schema.py +2 -0
  232. infrahub/graphql/subscription/graphql_query.py +2 -0
  233. infrahub/graphql/types/context.py +12 -0
  234. infrahub/graphql/types/event.py +84 -17
  235. infrahub/graphql/types/node.py +2 -2
  236. infrahub/graphql/utils.py +2 -2
  237. infrahub/groups/ancestors.py +29 -0
  238. infrahub/groups/parsers.py +107 -0
  239. infrahub/lock.py +20 -20
  240. infrahub/menu/constants.py +0 -1
  241. infrahub/menu/generator.py +9 -21
  242. infrahub/menu/menu.py +17 -38
  243. infrahub/menu/models.py +117 -16
  244. infrahub/menu/repository.py +111 -0
  245. infrahub/menu/utils.py +5 -8
  246. infrahub/message_bus/__init__.py +11 -13
  247. infrahub/message_bus/messages/__init__.py +1 -21
  248. infrahub/message_bus/messages/check_generator_run.py +3 -3
  249. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  250. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  251. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  252. infrahub/message_bus/messages/send_echo_request.py +1 -1
  253. infrahub/message_bus/operations/__init__.py +1 -10
  254. infrahub/message_bus/operations/check/__init__.py +2 -2
  255. infrahub/message_bus/operations/check/generator.py +1 -0
  256. infrahub/message_bus/operations/event/__init__.py +2 -2
  257. infrahub/message_bus/operations/event/worker.py +0 -3
  258. infrahub/message_bus/operations/finalize/validator.py +51 -1
  259. infrahub/message_bus/operations/requests/__init__.py +0 -2
  260. infrahub/message_bus/operations/requests/generator_definition.py +21 -23
  261. infrahub/message_bus/operations/requests/proposed_change.py +14 -10
  262. infrahub/permissions/globals.py +15 -0
  263. infrahub/pools/number.py +2 -4
  264. infrahub/proposed_change/models.py +3 -0
  265. infrahub/proposed_change/tasks.py +58 -45
  266. infrahub/pytest_plugin.py +13 -10
  267. infrahub/server.py +2 -3
  268. infrahub/services/__init__.py +2 -2
  269. infrahub/services/adapters/cache/__init__.py +4 -6
  270. infrahub/services/adapters/cache/nats.py +4 -5
  271. infrahub/services/adapters/cache/redis.py +3 -7
  272. infrahub/services/adapters/event/__init__.py +1 -1
  273. infrahub/services/adapters/message_bus/__init__.py +3 -3
  274. infrahub/services/adapters/message_bus/local.py +2 -2
  275. infrahub/services/adapters/message_bus/nats.py +4 -4
  276. infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
  277. infrahub/services/adapters/workflow/local.py +2 -2
  278. infrahub/services/component.py +5 -5
  279. infrahub/services/protocols.py +7 -7
  280. infrahub/services/scheduler.py +1 -3
  281. infrahub/task_manager/event.py +102 -9
  282. infrahub/task_manager/models.py +27 -7
  283. infrahub/tasks/artifact.py +7 -6
  284. infrahub/telemetry/__init__.py +0 -0
  285. infrahub/telemetry/constants.py +9 -0
  286. infrahub/telemetry/database.py +86 -0
  287. infrahub/telemetry/models.py +65 -0
  288. infrahub/telemetry/task_manager.py +77 -0
  289. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  290. infrahub/telemetry/utils.py +11 -0
  291. infrahub/trace.py +4 -4
  292. infrahub/transformations/tasks.py +2 -2
  293. infrahub/trigger/catalogue.py +4 -6
  294. infrahub/trigger/constants.py +0 -8
  295. infrahub/trigger/models.py +54 -5
  296. infrahub/trigger/setup.py +90 -0
  297. infrahub/trigger/tasks.py +35 -84
  298. infrahub/utils.py +11 -1
  299. infrahub/validators/__init__.py +0 -0
  300. infrahub/validators/events.py +42 -0
  301. infrahub/validators/tasks.py +41 -0
  302. infrahub/webhook/gather.py +17 -0
  303. infrahub/webhook/models.py +176 -44
  304. infrahub/webhook/tasks.py +154 -155
  305. infrahub/webhook/triggers.py +31 -7
  306. infrahub/workers/infrahub_async.py +2 -2
  307. infrahub/workers/utils.py +2 -2
  308. infrahub/workflows/catalogue.py +86 -35
  309. infrahub/workflows/initialization.py +8 -2
  310. infrahub/workflows/models.py +27 -1
  311. infrahub/workflows/utils.py +10 -1
  312. infrahub_sdk/client.py +35 -8
  313. infrahub_sdk/config.py +3 -0
  314. infrahub_sdk/context.py +13 -0
  315. infrahub_sdk/ctl/branch.py +3 -2
  316. infrahub_sdk/ctl/cli_commands.py +5 -1
  317. infrahub_sdk/ctl/utils.py +0 -16
  318. infrahub_sdk/exceptions.py +12 -0
  319. infrahub_sdk/generator.py +4 -1
  320. infrahub_sdk/graphql.py +45 -13
  321. infrahub_sdk/node.py +71 -22
  322. infrahub_sdk/protocols.py +21 -8
  323. infrahub_sdk/protocols_base.py +32 -11
  324. infrahub_sdk/query_groups.py +6 -35
  325. infrahub_sdk/schema/__init__.py +55 -26
  326. infrahub_sdk/schema/main.py +8 -0
  327. infrahub_sdk/task/__init__.py +11 -0
  328. infrahub_sdk/task/constants.py +3 -0
  329. infrahub_sdk/task/exceptions.py +25 -0
  330. infrahub_sdk/task/manager.py +551 -0
  331. infrahub_sdk/task/models.py +74 -0
  332. infrahub_sdk/testing/schemas/animal.py +9 -0
  333. infrahub_sdk/timestamp.py +142 -33
  334. infrahub_sdk/utils.py +29 -1
  335. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +8 -6
  336. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +349 -293
  337. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
  338. infrahub_testcontainers/constants.py +2 -0
  339. infrahub_testcontainers/container.py +157 -12
  340. infrahub_testcontainers/docker-compose.test.yml +31 -6
  341. infrahub_testcontainers/helpers.py +18 -73
  342. infrahub_testcontainers/host.py +41 -0
  343. infrahub_testcontainers/measurements.py +93 -0
  344. infrahub_testcontainers/models.py +38 -0
  345. infrahub_testcontainers/performance_test.py +166 -0
  346. infrahub_testcontainers/plugin.py +136 -0
  347. infrahub_testcontainers/prometheus.yml +30 -0
  348. infrahub/core/schema/definitions/core.py +0 -2286
  349. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  350. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  351. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  352. infrahub/message_bus/messages/event_branch_create.py +0 -11
  353. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  354. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  355. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  356. infrahub/message_bus/messages/event_schema_update.py +0 -9
  357. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  358. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  359. infrahub/message_bus/operations/check/repository.py +0 -293
  360. infrahub/message_bus/operations/event/node.py +0 -20
  361. infrahub/message_bus/operations/event/schema.py +0 -17
  362. infrahub/message_bus/operations/requests/repository.py +0 -133
  363. infrahub/webhook/constants.py +0 -1
  364. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
  365. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Optional, Union
3
+ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from infrahub.core.query import QueryNode
6
6
 
@@ -17,16 +17,16 @@ async def build_subquery_filter(
17
17
  filter_name: str,
18
18
  filter_value: Any,
19
19
  branch_filter: str,
20
- field: Optional[Union[AttributeSchema, RelationshipSchema]] = None,
20
+ field: AttributeSchema | RelationshipSchema | None = None,
21
21
  node_alias: str = "n",
22
- name: Optional[str] = None,
22
+ name: str | None = None,
23
23
  branch: Branch = None,
24
24
  subquery_idx: int = 1,
25
25
  partial_match: bool = False,
26
26
  optional_match: bool = False,
27
27
  result_prefix: str = "filter",
28
28
  support_profiles: bool = False,
29
- extra_tail_properties: Optional[dict[str, str]] = None,
29
+ extra_tail_properties: dict[str, str] | None = None,
30
30
  ) -> tuple[str, dict[str, Any], str]:
31
31
  support_profiles = (
32
32
  support_profiles and field and field.is_attribute and filter_name in ("value", "values", "isnull")
@@ -102,16 +102,16 @@ async def build_subquery_filter(
102
102
 
103
103
  async def build_subquery_order(
104
104
  db: InfrahubDatabase,
105
- field: Union[AttributeSchema, RelationshipSchema],
105
+ field: AttributeSchema | RelationshipSchema,
106
106
  order_by: str,
107
107
  branch_filter: str,
108
108
  node_alias: str = "n",
109
- name: Optional[str] = None,
109
+ name: str | None = None,
110
110
  branch: Branch = None,
111
111
  subquery_idx: int = 1,
112
- result_prefix: Optional[str] = None,
112
+ result_prefix: str | None = None,
113
113
  support_profiles: bool = False,
114
- extra_tail_properties: Optional[dict[str, str]] = None,
114
+ extra_tail_properties: dict[str, str] | None = None,
115
115
  ) -> tuple[str, dict[str, Any], str]:
116
116
  support_profiles = support_profiles and field and field.is_attribute and order_by in ("value", "values")
117
117
  params = {}
@@ -143,7 +143,7 @@ async def build_subquery_order(
143
143
  branch_level_str = "reduce(br_lvl = 0, r in relationships(path) | br_lvl + r.branch_level)"
144
144
  froms_str = db.render_list_comprehension(items="relationships(path)", item_name="from")
145
145
  to_return_parts = {f"last.{order_by if order_by != 'values' and '__' not in order_by else 'value'}": prefix}
146
- with_parts: dict[str, Optional[str]] = {
146
+ with_parts: dict[str, str | None] = {
147
147
  "last": None,
148
148
  }
149
149
  if extra_tail_properties:
infrahub/core/registry.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections import defaultdict
4
4
  from dataclasses import dataclass, field
5
- from typing import TYPE_CHECKING, Optional, Union
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from infrahub import lock
8
8
  from infrahub.core.constants import GLOBAL_BRANCH_NAME
@@ -26,21 +26,21 @@ if TYPE_CHECKING:
26
26
 
27
27
  @dataclass
28
28
  class Registry:
29
- id: Optional[str] = None
29
+ id: str | None = None
30
30
  attribute: dict[str, type[BaseAttribute]] = field(default_factory=dict)
31
31
  branch: dict[str, Branch] = field(default_factory=dict)
32
32
  node: dict = field(default_factory=dict)
33
- _default_branch: Optional[str] = None
34
- _default_ipnamespace: Optional[str] = None
35
- _schema: Optional[SchemaManager] = None
33
+ _default_branch: str | None = None
34
+ _default_ipnamespace: str | None = None
35
+ _schema: SchemaManager | None = None
36
36
  default_graphql_type: dict[str, InfrahubObject | type[BaseAttribute]] = field(default_factory=dict)
37
37
  graphql_type: dict = field(default_factory=lambda: defaultdict(dict))
38
38
  data_type: dict[str, type[InfrahubDataType]] = field(default_factory=dict)
39
39
  input_type: dict[str, type[BaseAttributeCreate | BaseAttributeUpdate]] = field(default_factory=dict)
40
40
  attr_group: dict = field(default_factory=dict)
41
- _branch_object: Optional[type[Branch]] = None
42
- _manager: Optional[type[NodeManager]] = None
43
- _storage: Optional[InfrahubObjectStorage] = None
41
+ _branch_object: type[Branch] | None = None
42
+ _manager: type[NodeManager] | None = None
43
+ _storage: InfrahubObjectStorage | None = None
44
44
  permission_backends: list[PermissionBackend] = field(default_factory=list)
45
45
 
46
46
  @property
@@ -113,7 +113,7 @@ class Registry:
113
113
  return True
114
114
  return False
115
115
 
116
- def get_node_schema(self, name: str, branch: Optional[Union[Branch, str]] = None) -> NodeSchema:
116
+ def get_node_schema(self, name: str, branch: Branch | str | None = None) -> NodeSchema:
117
117
  return self.schema.get_node_schema(name=name, branch=branch)
118
118
 
119
119
  def get_data_type(self, name: str) -> type[InfrahubDataType]:
@@ -121,9 +121,7 @@ class Registry:
121
121
  raise DataTypeNotFoundError(name=name)
122
122
  return self.data_type[name]
123
123
 
124
- def get_full_schema(
125
- self, branch: Optional[Union[Branch, str]] = None, duplicate: bool = True
126
- ) -> dict[str, MainSchemaTypes]:
124
+ def get_full_schema(self, branch: Branch | str | None = None, duplicate: bool = True) -> dict[str, MainSchemaTypes]:
127
125
  """Return all the nodes in the schema for a given branch."""
128
126
  return self.schema.get_full(branch=branch, duplicate=duplicate)
129
127
 
@@ -137,7 +135,7 @@ class Registry:
137
135
  self.attribute = {}
138
136
  self.input_type = {}
139
137
 
140
- def get_branch_from_registry(self, branch: Optional[Union[Branch, str]] = None) -> Branch:
138
+ def get_branch_from_registry(self, branch: Branch | str | None = None) -> Branch:
141
139
  """Return a branch object from the registry based on its name.
142
140
 
143
141
  Args:
@@ -168,8 +166,8 @@ class Registry:
168
166
  async def get_branch(
169
167
  self,
170
168
  db: InfrahubDatabase,
171
- session: Optional[AsyncSession] = None,
172
- branch: Optional[Union[Branch, str]] = None,
169
+ session: AsyncSession | None = None,
170
+ branch: Branch | str | None = None,
173
171
  ) -> Branch:
174
172
  """Return a branch object based on its name.
175
173
 
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from infrahub.core import registry
5
4
  from infrahub.core.branch import Branch
@@ -17,12 +16,12 @@ from .interface import RelationshipManagerConstraintInterface
17
16
  class NodeToValidate:
18
17
  uuid: str
19
18
  cardinality: RelationshipCardinality
20
- min_count: Optional[int] = None
21
- max_count: Optional[int] = None
19
+ min_count: int | None = None
20
+ max_count: int | None = None
22
21
 
23
22
 
24
23
  class RelationshipCountConstraint(RelationshipManagerConstraintInterface):
25
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch] = None):
24
+ def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
26
25
  self.db = db
27
26
  self.branch = branch
28
27
 
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from infrahub.core import registry
5
4
  from infrahub.core.branch import Branch
@@ -18,12 +17,12 @@ from .interface import RelationshipManagerConstraintInterface
18
17
  class NodeToValidate:
19
18
  uuid: str
20
19
  cardinality: RelationshipCardinality
21
- min_count: Optional[int] = None
22
- max_count: Optional[int] = None
20
+ min_count: int | None = None
21
+ max_count: int | None = None
23
22
 
24
23
 
25
24
  class RelationshipPeerKindConstraint(RelationshipManagerConstraintInterface):
26
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch] = None):
25
+ def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
27
26
  self.db = db
28
27
  self.branch = branch
29
28
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Optional
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from infrahub.core import registry
6
6
  from infrahub.core.schema import NodeSchema
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
18
 
19
19
 
20
20
  class RelationshipProfilesKindConstraint(RelationshipManagerConstraintInterface):
21
- def __init__(self, db: InfrahubDatabase, branch: Optional[Branch] = None):
21
+ def __init__(self, db: InfrahubDatabase, branch: Branch | None = None):
22
22
  self.db = db
23
23
  self.branch = branch
24
24
  self.schema_branch = registry.schema.get_schema_branch(branch.name if branch else registry.default_branch)
@@ -11,10 +11,8 @@ from typing import (
11
11
  Iterator,
12
12
  Literal,
13
13
  Mapping,
14
- Optional,
15
14
  Sequence,
16
15
  TypeVar,
17
- Union,
18
16
  overload,
19
17
  )
20
18
 
@@ -65,14 +63,14 @@ class RelationshipCreateData(BaseModel):
65
63
  uuid: str
66
64
  name: str
67
65
  destination_id: str
68
- branch: Optional[str] = None
66
+ branch: str | None = None
69
67
  branch_level: int
70
- branch_support: Optional[str] = None
68
+ branch_support: str | None = None
71
69
  direction: str
72
70
  status: str
73
71
  is_protected: bool
74
72
  is_visible: bool
75
- hierarchical: Optional[str] = None
73
+ hierarchical: str | None = None
76
74
  source_prop: list[NodePropertyData] = Field(default_factory=list)
77
75
  owner_prop: list[NodePropertyData] = Field(default_factory=list)
78
76
 
@@ -92,9 +90,9 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
92
90
  self,
93
91
  schema: RelationshipSchema,
94
92
  branch: Branch,
95
- at: Optional[Timestamp] = None,
96
- node: Optional[Node] = None,
97
- node_id: Optional[str] = None,
93
+ at: Timestamp | None = None,
94
+ node: Node | None = None,
95
+ node_id: str | None = None,
98
96
  **kwargs: Any,
99
97
  ) -> None:
100
98
  if not node and not node_id:
@@ -107,18 +105,18 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
107
105
  self.at = Timestamp(at)
108
106
 
109
107
  self._node = node
110
- self._node_id: Optional[str] = node_id
108
+ self._node_id: str | None = node_id
111
109
 
112
- self.id: Optional[UUID] = None
113
- self.db_id: Optional[str] = None
114
- self.updated_at: Optional[Timestamp] = None
110
+ self.id: UUID | None = None
111
+ self.db_id: str | None = None
112
+ self.updated_at: Timestamp | None = None
115
113
 
116
- self._peer: Optional[Union[Node, str]] = None
117
- self.peer_id: Optional[str] = None
118
- self.peer_hfid: Optional[list[str]] = None
119
- self.data: Optional[Union[dict, RelationshipPeerData, str]] = None
114
+ self._peer: Node | str | None = None
115
+ self.peer_id: str | None = None
116
+ self.peer_hfid: list[str] | None = None
117
+ self.data: dict | RelationshipPeerData | str | None = None
120
118
 
121
- self.from_pool: Optional[dict[str, Any]] = None
119
+ self.from_pool: dict[str, Any] | None = None
122
120
 
123
121
  self._init_node_property_mixin(kwargs=kwargs)
124
122
  self._init_flag_property_mixin(kwargs=kwargs)
@@ -166,7 +164,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
166
164
  return registry.get_global_branch()
167
165
  return self.branch
168
166
 
169
- async def _process_data(self, data: Union[dict, RelationshipPeerData, str]) -> None:
167
+ async def _process_data(self, data: dict | RelationshipPeerData | str) -> None:
170
168
  self.data = data
171
169
 
172
170
  if isinstance(data, RelationshipPeerData):
@@ -203,7 +201,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
203
201
  async def new(
204
202
  self,
205
203
  db: InfrahubDatabase, # noqa: ARG002
206
- data: Union[dict, RelationshipPeerData, Any] = None,
204
+ data: dict | RelationshipPeerData | Any = None,
207
205
  **kwargs: Any, # noqa: ARG002
208
206
  ) -> Relationship:
209
207
  await self._process_data(data=data)
@@ -213,10 +211,10 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
213
211
  async def load(
214
212
  self,
215
213
  db: InfrahubDatabase, # noqa: ARG002
216
- id: Optional[UUID] = None,
217
- db_id: Optional[str] = None,
218
- updated_at: Optional[Union[Timestamp, str]] = None,
219
- data: Union[dict, RelationshipPeerData, Any] = None,
214
+ id: UUID | None = None,
215
+ db_id: str | None = None,
216
+ updated_at: Timestamp | str | None = None,
217
+ data: dict | RelationshipPeerData | Any = None,
220
218
  ) -> Self:
221
219
  hash_before = hash(self)
222
220
 
@@ -252,7 +250,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
252
250
  self._node_id = self._node.id
253
251
  return node
254
252
 
255
- async def set_peer(self, value: Union[str, Node]) -> None:
253
+ async def set_peer(self, value: str | Node) -> None:
256
254
  if isinstance(value, str):
257
255
  self.peer_id = value
258
256
  else:
@@ -337,7 +335,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
337
335
 
338
336
  return different_properties
339
337
 
340
- async def _create(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> None:
338
+ async def _create(self, db: InfrahubDatabase, at: Timestamp | None = None) -> None:
341
339
  """Add a relationship with another object by creating a new relationship node."""
342
340
 
343
341
  create_at = Timestamp(at)
@@ -364,7 +362,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
364
362
  db: InfrahubDatabase,
365
363
  properties_to_update: list[str],
366
364
  data: RelationshipPeerData,
367
- at: Optional[Timestamp] = None,
365
+ at: Timestamp | None = None,
368
366
  ) -> None:
369
367
  """Update the properties of an existing relationship."""
370
368
 
@@ -392,7 +390,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
392
390
  )
393
391
  await query.execute(db=db)
394
392
 
395
- async def delete(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> None:
393
+ async def delete(self, db: InfrahubDatabase, at: Timestamp | None = None) -> None:
396
394
  delete_at = Timestamp(at)
397
395
 
398
396
  node = await self.get_node(db=db)
@@ -476,7 +474,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
476
474
  await self.set_peer(value=assigned_peer)
477
475
  self.set_source(value=pool.id)
478
476
 
479
- async def save(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> Self:
477
+ async def save(self, db: InfrahubDatabase, at: Timestamp | None = None) -> Self:
480
478
  """Create or Update the Relationship in the database."""
481
479
 
482
480
  save_at = Timestamp(at)
@@ -487,9 +485,7 @@ class Relationship(FlagPropertyMixin, NodePropertyMixin):
487
485
 
488
486
  return self
489
487
 
490
- async def to_graphql(
491
- self, fields: Optional[dict], db: InfrahubDatabase, related_node_ids: Optional[set] = None
492
- ) -> dict:
488
+ async def to_graphql(self, fields: dict | None, db: InfrahubDatabase, related_node_ids: set | None = None) -> dict:
493
489
  """Generate GraphQL Payload for the associated Peer."""
494
490
 
495
491
  if not fields:
@@ -726,7 +722,7 @@ class RelationshipManager:
726
722
  min_count=0 if self.schema.optional else self.schema.min_count,
727
723
  max_count=self.schema.max_count,
728
724
  )
729
- self._relationship_id_details: Optional[RelationshipUpdateDetails] = None
725
+ self._relationship_id_details: RelationshipUpdateDetails | None = None
730
726
  self.has_fetched_relationships: bool = False
731
727
  self.lock = asyncio.Lock()
732
728
 
@@ -738,7 +734,7 @@ class RelationshipManager:
738
734
  branch: Branch,
739
735
  at: Timestamp,
740
736
  node: Node,
741
- data: Optional[Union[dict, list, str]] = None,
737
+ data: dict | list | str | None = None,
742
738
  ) -> RelationshipManager:
743
739
  rm = cls(schema=schema, branch=branch, at=at, node=node)
744
740
 
@@ -892,6 +888,8 @@ class RelationshipManager:
892
888
  """If the attribute is branch aware, return the Branch object associated with this attribute
893
889
  If the attribute is branch agnostic return the Global Branch
894
890
 
891
+ Note that if this relationship is Aware and source node is Agnostic, it will return -global- branch.
892
+
895
893
  Returns:
896
894
  Branch:
897
895
  """
@@ -902,7 +900,7 @@ class RelationshipManager:
902
900
  async def fetch_relationship_ids(
903
901
  self,
904
902
  db: InfrahubDatabase,
905
- at: Optional[Timestamp] = None,
903
+ at: Timestamp | None = None,
906
904
  branch_agnostic: bool = False,
907
905
  force_refresh: bool = True,
908
906
  ) -> RelationshipUpdateDetails:
@@ -944,7 +942,7 @@ class RelationshipManager:
944
942
  async def _fetch_relationships(
945
943
  self,
946
944
  db: InfrahubDatabase,
947
- at: Optional[Timestamp] = None,
945
+ at: Timestamp | None = None,
948
946
  branch_agnostic: bool = False,
949
947
  force_refresh: bool = True,
950
948
  ) -> None:
@@ -967,7 +965,7 @@ class RelationshipManager:
967
965
  self.has_fetched_relationships = True
968
966
 
969
967
  for peer_id in details.peer_ids_present_local_only:
970
- await self.remove(peer_id=peer_id, db=db)
968
+ await self.remove_locally(peer_id=peer_id, db=db)
971
969
 
972
970
  async def get(self, db: InfrahubDatabase) -> Relationship | list[Relationship] | None:
973
971
  rels = await self.get_relationships(db=db)
@@ -1006,12 +1004,10 @@ class RelationshipManager:
1006
1004
 
1007
1005
  return self._relationships.as_list()
1008
1006
 
1009
- async def update(
1010
- self, data: Union[list[Union[str, Node]], dict[str, Any], str, Node, None], db: InfrahubDatabase
1011
- ) -> bool:
1007
+ async def update(self, data: list[str | Node] | dict[str, Any] | str | Node | None, db: InfrahubDatabase) -> bool:
1012
1008
  """Replace and Update the list of relationships with this one."""
1013
1009
  if not isinstance(data, list):
1014
- list_data: Sequence[Union[str, Node, dict[str, Any], None]] = [data]
1010
+ list_data: Sequence[str | Node | dict[str, Any] | None] = [data]
1015
1011
  else:
1016
1012
  list_data = data
1017
1013
 
@@ -1069,7 +1065,7 @@ class RelationshipManager:
1069
1065
 
1070
1066
  return changed
1071
1067
 
1072
- async def add(self, data: Union[dict[str, Any], Node], db: InfrahubDatabase) -> bool:
1068
+ async def add(self, data: dict[str, Any] | Node, db: InfrahubDatabase) -> bool:
1073
1069
  """Add a new relationship to the list of existing ones, avoid duplication."""
1074
1070
  if not isinstance(data, self.rel_class | dict) and not hasattr(data, "_schema"):
1075
1071
  raise ValidationError({self.name: f"Invalid data provided to form a relationship {data}"})
@@ -1098,22 +1094,17 @@ class RelationshipManager:
1098
1094
  for rel in self._relationships:
1099
1095
  await rel.resolve(db=db)
1100
1096
 
1101
- async def remove(
1097
+ async def remove_locally(
1102
1098
  self,
1103
- peer_id: Union[str, UUID],
1099
+ peer_id: str | UUID,
1104
1100
  db: InfrahubDatabase,
1105
- update_db: bool = False,
1106
1101
  ) -> bool:
1107
- """Remove a peer id from the local relationships list,
1108
- need to investigate if and when we should update the relationship in the database."""
1102
+ """Remove a peer id from the local relationships list"""
1109
1103
 
1110
1104
  for idx, rel in enumerate(await self.get_relationships(db=db)):
1111
1105
  if str(rel.peer_id) != str(peer_id):
1112
1106
  continue
1113
1107
 
1114
- if update_db:
1115
- await rel.delete(db=db)
1116
-
1117
1108
  self._relationships.pop(idx)
1118
1109
  return True
1119
1110
 
@@ -1123,21 +1114,20 @@ class RelationshipManager:
1123
1114
  self,
1124
1115
  db: InfrahubDatabase,
1125
1116
  peer_data: RelationshipPeerData,
1126
- at: Optional[Timestamp] = None,
1117
+ at: Timestamp | None = None,
1127
1118
  ) -> None:
1128
1119
  remove_at = Timestamp(at)
1129
1120
  branch = self.get_branch_based_on_support_type()
1130
1121
 
1131
1122
  # - Update the existing relationship if we are on the same branch
1132
1123
  rel_ids_per_branch = peer_data.rel_ids_per_branch()
1124
+
1125
+ # In which cases do we end up here and do not want to set `to` time?
1133
1126
  if branch.name in rel_ids_per_branch:
1134
1127
  await update_relationships_to([str(ri) for ri in rel_ids_per_branch[branch.name]], to=remove_at, db=db)
1135
1128
 
1136
1129
  # - Create a new rel of type DELETED if the existing relationship is on a different branch
1137
- rel_branches: set[str] = set()
1138
- if peer_data.rels:
1139
- rel_branches = {r.branch for r in peer_data.rels}
1140
- if rel_branches == {peer_data.branch}:
1130
+ if peer_data.rels and {r.branch for r in peer_data.rels} == {peer_data.branch}:
1141
1131
  return
1142
1132
 
1143
1133
  query = await RelationshipDataDeleteQuery.init(
@@ -1152,7 +1142,7 @@ class RelationshipManager:
1152
1142
  await query.execute(db=db)
1153
1143
 
1154
1144
  async def save(
1155
- self, db: InfrahubDatabase, at: Optional[Timestamp] = None
1145
+ self, db: InfrahubDatabase, at: Timestamp | None = None
1156
1146
  ) -> RelationshipCardinalityManyChangelog | RelationshipCardinalityOneChangelog:
1157
1147
  """Create or Update the Relationship in the database."""
1158
1148
 
@@ -1198,7 +1188,7 @@ class RelationshipManager:
1198
1188
  return relationship_mapper.changelog
1199
1189
 
1200
1190
  async def delete(
1201
- self, db: InfrahubDatabase, at: Optional[Timestamp] = None
1191
+ self, db: InfrahubDatabase, at: Timestamp | None = None
1202
1192
  ) -> RelationshipCardinalityManyChangelog | RelationshipCardinalityOneChangelog:
1203
1193
  """Delete all the relationships."""
1204
1194
 
@@ -1208,14 +1198,16 @@ class RelationshipManager:
1208
1198
  await self._fetch_relationships(at=delete_at, db=db, force_refresh=True)
1209
1199
 
1210
1200
  for rel in await self.get_relationships(db=db):
1211
- relationship_mapper.delete_relationship(relationship=rel)
1201
+ relationship_mapper.delete_relationship(
1202
+ peer_kind=rel.get_peer_kind(), peer_id=rel.get_peer_id(), rel_schema=rel.schema
1203
+ )
1212
1204
  await rel.delete(at=delete_at, db=db)
1213
1205
 
1214
1206
  return relationship_mapper.changelog
1215
1207
 
1216
1208
  async def to_graphql(
1217
- self, db: InfrahubDatabase, fields: Optional[dict] = None, related_node_ids: Optional[set] = None
1218
- ) -> Union[dict, None]:
1209
+ self, db: InfrahubDatabase, fields: dict | None = None, related_node_ids: set | None = None
1210
+ ) -> dict | None:
1219
1211
  # NOTE Need to investigate when and why we are passing the peer directly here, how do we account for many relationship
1220
1212
  if self.schema.cardinality == "many":
1221
1213
  raise TypeError("to_graphql is not available for relationship with multiple cardinality")
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import enum
4
- from typing import TYPE_CHECKING, Any, Optional, Union
4
+ from enum import Enum
5
+ from typing import TYPE_CHECKING, Any
5
6
 
6
7
  from pydantic import field_validator, model_validator
7
8
 
@@ -22,7 +23,7 @@ if TYPE_CHECKING:
22
23
 
23
24
  class AttributeSchema(GeneratedAttributeSchema):
24
25
  _sort_by: list[str] = ["name"]
25
- _enum_class: Optional[type[enum.Enum]] = None
26
+ _enum_class: type[enum.Enum] | None = None
26
27
 
27
28
  @property
28
29
  def is_attribute(self) -> bool:
@@ -36,6 +37,13 @@ class AttributeSchema(GeneratedAttributeSchema):
36
37
  def is_deprecated(self) -> bool:
37
38
  return bool(self.deprecation)
38
39
 
40
+ def to_dict(self) -> dict:
41
+ data = self.model_dump(exclude_unset=True, exclude_none=True)
42
+ for field_name, value in data.items():
43
+ if isinstance(value, Enum):
44
+ data[field_name] = value.value
45
+ return data
46
+
39
47
  @field_validator("kind")
40
48
  @classmethod
41
49
  def kind_options(cls, v: str) -> str:
@@ -48,7 +56,7 @@ class AttributeSchema(GeneratedAttributeSchema):
48
56
  def validate_dropdown_choices(cls, values: dict[str, Any]) -> dict[str, Any]:
49
57
  """Validate that choices are defined for a dropdown but not for other kinds."""
50
58
  if values.get("kind") != "Dropdown" and values.get("choices"):
51
- raise ValueError(f"Can only specify 'choices' for kind=Dropdown: {values['kind'] }")
59
+ raise ValueError(f"Can only specify 'choices' for kind=Dropdown: {values['kind']}")
52
60
 
53
61
  if values.get("kind") == "Dropdown" and not values.get("choices"):
54
62
  raise ValueError("The property 'choices' is required for kind=Dropdown")
@@ -74,7 +82,7 @@ class AttributeSchema(GeneratedAttributeSchema):
74
82
  self._enum_class = generate_python_enum(name=f"{self.name.title()}Enum", options=self.enum)
75
83
  return self._enum_class
76
84
 
77
- def convert_value_to_enum(self, value: Any) -> Optional[enum.Enum]:
85
+ def convert_value_to_enum(self, value: Any) -> enum.Enum | None:
78
86
  if isinstance(value, enum.Enum) or value is None:
79
87
  return value
80
88
  enum_class = self.get_enum_class()
@@ -113,11 +121,11 @@ class AttributeSchema(GeneratedAttributeSchema):
113
121
  self,
114
122
  name: str,
115
123
  filter_name: str,
116
- branch: Optional[Branch] = None,
117
- filter_value: Optional[Union[str, int, bool, list]] = None,
124
+ branch: Branch | None = None,
125
+ filter_value: str | int | bool | list | None = None,
118
126
  include_match: bool = True,
119
- param_prefix: Optional[str] = None,
120
- db: Optional[InfrahubDatabase] = None,
127
+ param_prefix: str | None = None,
128
+ db: InfrahubDatabase | None = None,
121
129
  partial_match: bool = False,
122
130
  support_profiles: bool = False,
123
131
  ) -> tuple[list[QueryElement], dict[str, Any], list[str]]: