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, Optional
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from infrahub.core.ipam.size import get_prefix_space
6
6
  from infrahub.core.ipam.utilization import PrefixUtilizationGetter
@@ -16,10 +16,10 @@ class BuiltinIPPrefix(Node):
16
16
  async def to_graphql(
17
17
  self,
18
18
  db: InfrahubDatabase,
19
- fields: Optional[dict] = None,
20
- related_node_ids: Optional[set] = None,
19
+ fields: dict | None = None,
20
+ related_node_ids: set | None = None,
21
21
  filter_sensitive: bool = False,
22
- permissions: Optional[dict] = None, # noqa: ARG002
22
+ permissions: dict | None = None, # noqa: ARG002
23
23
  include_properties: bool = True,
24
24
  ) -> dict:
25
25
  response = await super().to_graphql(
@@ -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.permissions.constants import PermissionDecisionFlag
6
6
 
@@ -14,10 +14,10 @@ class CoreGlobalPermission(Node):
14
14
  async def to_graphql(
15
15
  self,
16
16
  db: InfrahubDatabase,
17
- fields: Optional[dict] = None,
18
- related_node_ids: Optional[set] = None,
17
+ fields: dict | None = None,
18
+ related_node_ids: set | None = None,
19
19
  filter_sensitive: bool = False,
20
- permissions: Optional[dict] = None,
20
+ permissions: dict | None = None,
21
21
  include_properties: bool = True,
22
22
  ) -> dict:
23
23
  response = await super().to_graphql(
@@ -41,10 +41,10 @@ class CoreObjectPermission(Node):
41
41
  async def to_graphql(
42
42
  self,
43
43
  db: InfrahubDatabase,
44
- fields: Optional[dict] = None,
45
- related_node_ids: Optional[set] = None,
44
+ fields: dict | None = None,
45
+ related_node_ids: set | None = None,
46
46
  filter_sensitive: bool = False,
47
- permissions: Optional[dict] = None,
47
+ permissions: dict | None = None,
48
48
  include_properties: bool = True,
49
49
  ) -> dict:
50
50
  response = await super().to_graphql(
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import ipaddress
4
- from typing import TYPE_CHECKING, Any, Optional
4
+ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from infrahub.core import registry
7
7
  from infrahub.core.ipam.reconciler import IpamReconciler
@@ -26,10 +26,10 @@ class CoreIPAddressPool(Node):
26
26
  self,
27
27
  db: InfrahubDatabase,
28
28
  branch: Branch,
29
- identifier: Optional[str] = None,
30
- data: Optional[dict[str, Any]] = None,
31
- address_type: Optional[str] = None,
32
- prefixlen: Optional[int] = None,
29
+ identifier: str | None = None,
30
+ data: dict[str, Any] | None = None,
31
+ address_type: str | None = None,
32
+ prefixlen: int | None = None,
33
33
  ) -> Node:
34
34
  # Check if there is already a resource allocated with this identifier
35
35
  # if not, pull all existing prefixes and allocated the next available
@@ -80,7 +80,7 @@ class CoreIPAddressPool(Node):
80
80
 
81
81
  return node
82
82
 
83
- async def get_next(self, db: InfrahubDatabase, prefixlen: Optional[int] = None) -> IPAddressType:
83
+ async def get_next(self, db: InfrahubDatabase, prefixlen: int | None = None) -> IPAddressType:
84
84
  # Measure utilization of all prefixes identified as resources
85
85
  resources = await self.resources.get_peers(db=db) # type: ignore[attr-defined]
86
86
  ip_namespace = await self.ip_namespace.get_peer(db=db) # type: ignore[attr-defined]
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import ipaddress
4
- from typing import TYPE_CHECKING, Any, Optional
4
+ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from netaddr import IPSet
7
7
 
@@ -28,11 +28,11 @@ class CoreIPPrefixPool(Node):
28
28
  self,
29
29
  db: InfrahubDatabase,
30
30
  branch: Branch,
31
- identifier: Optional[str] = None,
32
- data: Optional[dict[str, Any]] = None,
33
- prefixlen: Optional[int] = None,
34
- member_type: Optional[str] = None,
35
- prefix_type: Optional[str] = None,
31
+ identifier: str | None = None,
32
+ data: dict[str, Any] | None = None,
33
+ prefixlen: int | None = None,
34
+ member_type: str | None = None,
35
+ prefix_type: str | None = None,
36
36
  ) -> Node:
37
37
  # Check if there is already a resource allocated with this identifier
38
38
  # if not, pull all existing prefixes and allocated the next available
@@ -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.query.resource_manager import NumberPoolGetReserved, NumberPoolGetUsed, NumberPoolSetReserved
6
6
  from infrahub.exceptions import PoolExhaustedError
@@ -18,7 +18,7 @@ class CoreNumberPool(Node):
18
18
  db: InfrahubDatabase,
19
19
  branch: Branch,
20
20
  node: Node,
21
- identifier: Optional[str] = None,
21
+ identifier: str | None = None,
22
22
  ) -> int:
23
23
  identifier = identifier or node.get_id()
24
24
  # Check if there is already a resource allocated with this identifier
@@ -55,7 +55,7 @@ class CoreNumberPool(Node):
55
55
  return next_number
56
56
 
57
57
 
58
- def find_next_free(start: int, end: int, taken: list[int | None]) -> Optional[int]:
58
+ def find_next_free(start: int, end: int, taken: list[int | None]) -> int | None:
59
59
  used_numbers = [number for number in taken if number is not None]
60
60
  used_set = set(used_numbers)
61
61
 
infrahub/core/path.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections import defaultdict
4
4
  from itertools import chain
5
- from typing import TYPE_CHECKING, Any, Optional, Union
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from pydantic import BaseModel, Field
8
8
  from typing_extensions import Self
@@ -56,12 +56,12 @@ class DataPath(InfrahubPath):
56
56
  path_type: PathType
57
57
  node_id: str = Field(..., description="Kind of the model in the schema")
58
58
  kind: str = Field(..., description="Kind of the main node")
59
- field_name: Optional[str] = Field(
59
+ field_name: str | None = Field(
60
60
  default=None, description="Name of the field (either an attribute or a relationship)"
61
61
  )
62
- property_name: Optional[str] = Field(default=None, description="Name of the property")
63
- peer_id: Optional[str] = Field(default=None, description="")
64
- value: Optional[Any] = Field(default=None, description="Optional value of the resource")
62
+ property_name: str | None = Field(default=None, description="Name of the property")
63
+ peer_id: str | None = Field(default=None, description="")
64
+ value: Any | None = Field(default=None, description="Optional value of the resource")
65
65
 
66
66
  @property
67
67
  def resource_type(self) -> PathResourceType:
@@ -109,11 +109,11 @@ class GroupedDataPaths:
109
109
  class SchemaPath(InfrahubPath):
110
110
  path_type: SchemaPathType
111
111
  schema_kind: str = Field(..., description="Kind of the model in the schema")
112
- schema_id: Optional[str] = Field(default=None, description="UUID of the model in the schema")
113
- field_name: Optional[str] = Field(
112
+ schema_id: str | None = Field(default=None, description="UUID of the model in the schema")
113
+ field_name: str | None = Field(
114
114
  default=None, description="Name of the field (either an attribute or a relationship)"
115
115
  )
116
- property_name: Optional[str] = Field(default=None, description="Name of the property")
116
+ property_name: str | None = Field(default=None, description="Name of the property")
117
117
 
118
118
  @property
119
119
  def resource_type(self) -> PathResourceType:
@@ -133,10 +133,10 @@ class SchemaPath(InfrahubPath):
133
133
  @classmethod
134
134
  def init(
135
135
  cls,
136
- schema: Union[NodeSchema, GenericSchema],
137
- schema_id: Optional[str] = None,
138
- field_name: Optional[str] = None,
139
- property_name: Optional[str] = None,
136
+ schema: NodeSchema | GenericSchema,
137
+ schema_id: str | None = None,
138
+ field_name: str | None = None,
139
+ property_name: str | None = None,
140
140
  ) -> Self:
141
141
  if field_name and not schema.get_field(name=field_name, raise_on_error=False):
142
142
  raise ValueError(f"Field : {field_name} is not valid for {schema.kind}")
infrahub/core/property.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Optional, Union
3
+ from typing import TYPE_CHECKING
4
4
  from uuid import UUID
5
5
 
6
6
  from pydantic import BaseModel
@@ -32,7 +32,7 @@ class FlagPropertyMixin:
32
32
  is_visible = True
33
33
  is_protected = False
34
34
 
35
- def _init_flag_property_mixin(self, kwargs: Optional[dict] = None) -> None:
35
+ def _init_flag_property_mixin(self, kwargs: dict | None = None) -> None:
36
36
  if not kwargs:
37
37
  return
38
38
 
@@ -47,7 +47,7 @@ class NodePropertyMixin:
47
47
  branch: Branch
48
48
  at: Timestamp
49
49
 
50
- def _init_node_property_mixin(self, kwargs: Optional[dict] = None) -> None:
50
+ def _init_node_property_mixin(self, kwargs: dict | None = None) -> None:
51
51
  for node in self._node_properties:
52
52
  setattr(self, f"_{node}", None)
53
53
  setattr(self, f"{node}_id", None)
@@ -66,7 +66,7 @@ class NodePropertyMixin:
66
66
  return self._get_node_property_from_cache(name="source")
67
67
 
68
68
  @source.setter
69
- def source(self, value: Union[str, Node, UUID]) -> None:
69
+ def source(self, value: str | Node | UUID) -> None:
70
70
  self._set_node_property(name="source", value=value)
71
71
 
72
72
  @property
@@ -74,25 +74,25 @@ class NodePropertyMixin:
74
74
  return self._get_node_property_from_cache(name="owner")
75
75
 
76
76
  @owner.setter
77
- def owner(self, value: Optional[Union[str, Node, UUID]]) -> None:
77
+ def owner(self, value: str | Node | UUID | None) -> None:
78
78
  self._set_node_property(name="owner", value=value)
79
79
 
80
80
  def clear_owner(self) -> None:
81
81
  self._set_node_property(name="owner", value=None)
82
82
 
83
- async def get_source(self, db: InfrahubDatabase) -> Optional[Node]:
83
+ async def get_source(self, db: InfrahubDatabase) -> Node | None:
84
84
  return await self._get_node_property(name="source", db=db)
85
85
 
86
86
  def clear_source(self) -> None:
87
87
  self._set_node_property(name="source", value=None)
88
88
 
89
- def set_source(self, value: Union[str, Node, UUID]) -> None:
89
+ def set_source(self, value: str | Node | UUID) -> None:
90
90
  self._set_node_property(name="source", value=value)
91
91
 
92
- async def get_owner(self, db: InfrahubDatabase) -> Optional[Node]:
92
+ async def get_owner(self, db: InfrahubDatabase) -> Node | None:
93
93
  return await self._get_node_property(name="owner", db=db)
94
94
 
95
- def set_owner(self, value: Union[str, Node, UUID]) -> None:
95
+ def set_owner(self, value: str | Node | UUID) -> None:
96
96
  self._set_node_property(name="owner", value=value)
97
97
 
98
98
  def _get_node_property_from_cache(self, name: str) -> Node:
@@ -107,7 +107,7 @@ class NodePropertyMixin:
107
107
 
108
108
  return item
109
109
 
110
- async def _get_node_property(self, db: InfrahubDatabase, name: str) -> Optional[Node]:
110
+ async def _get_node_property(self, db: InfrahubDatabase, name: str) -> Node | None:
111
111
  """Return the node attribute.
112
112
  If the node is already present in cache, serve from the cache
113
113
  If the node is not present, query it on the fly using the node_id
@@ -117,7 +117,7 @@ class NodePropertyMixin:
117
117
 
118
118
  return getattr(self, f"_{name}", None)
119
119
 
120
- def _set_node_property(self, name: str, value: Optional[Union[str, Node, UUID]]) -> None:
120
+ def _set_node_property(self, name: str, value: str | Node | UUID | None) -> None:
121
121
  """Set the value of the node_property.
122
122
  If the value is a string, we assume it's an ID and we'll save it to query it later (if needed)
123
123
  If the value is a Node, we save the node and we extract the ID
@@ -148,6 +148,10 @@ class CoreMenu(CoreNode):
148
148
  children: RelationshipManager
149
149
 
150
150
 
151
+ class CoreObjectComponentTemplate(CoreNode):
152
+ template_name: String
153
+
154
+
151
155
  class CoreObjectTemplate(CoreNode):
152
156
  template_name: String
153
157
 
@@ -197,6 +201,9 @@ class CoreValidator(CoreNode):
197
201
 
198
202
  class CoreWebhook(CoreNode):
199
203
  name: String
204
+ event_type: Enum
205
+ branch_scope: Dropdown
206
+ node_kind: StringOptional
200
207
  description: StringOptional
201
208
  url: URL
202
209
  validate_certificates: BooleanOptional
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Optional, Protocol, Union, runtime_checkable
3
+ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
4
4
 
5
5
  from typing_extensions import Self
6
6
 
@@ -38,23 +38,23 @@ class InfrahubDatabase(Protocol):
38
38
  @property
39
39
  def is_transaction(self) -> bool: ...
40
40
 
41
- def add_schema(self, schema: SchemaBranch, name: Optional[str] = None) -> None: ...
42
- def start_session(self, read_only: bool = False, schemas: Optional[list[SchemaBranch]] = None) -> Self: ...
43
- def start_transaction(self, schemas: Optional[list[SchemaBranch]] = None) -> Self: ...
41
+ def add_schema(self, schema: SchemaBranch, name: str | None = None) -> None: ...
42
+ def start_session(self, read_only: bool = False, schemas: list[SchemaBranch] | None = None) -> Self: ...
43
+ def start_transaction(self, schemas: list[SchemaBranch] | None = None) -> Self: ...
44
44
  async def session(self) -> AsyncSession: ...
45
- async def transaction(self, name: Optional[str]) -> AsyncTransaction: ...
45
+ async def transaction(self, name: str | None) -> AsyncTransaction: ...
46
46
  async def close(self) -> None: ...
47
47
 
48
48
  async def execute_query(
49
- self, query: str, params: Optional[dict[str, Any]] = None, name: str = "undefined"
49
+ self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
50
50
  ) -> list[Record]: ...
51
51
 
52
52
  async def execute_query_with_metadata(
53
- self, query: str, params: Optional[dict[str, Any]] = None, name: str = "undefined"
53
+ self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
54
54
  ) -> tuple[list[Record], dict[str, Any]]: ...
55
55
 
56
56
  async def run_query(
57
- self, query: str, params: Optional[dict[str, Any]] = None, name: str = "undefined"
57
+ self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
58
58
  ) -> AsyncResult: ...
59
59
 
60
60
  def render_list_comprehension(self, items: str, item_name: str) -> str: ...
@@ -73,29 +73,29 @@ class CoreNode(Protocol):
73
73
  @classmethod
74
74
  async def init(
75
75
  cls,
76
- schema: Union[NodeSchema, ProfileSchema, str],
76
+ schema: NodeSchema | ProfileSchema | str,
77
77
  db: InfrahubDatabase,
78
- branch: Optional[Union[Branch, str]] = None,
79
- at: Optional[Union[Timestamp, str]] = None,
78
+ branch: Branch | str | None = None,
79
+ at: Timestamp | str | None = None,
80
80
  ) -> Self: ...
81
- async def new(self, db: InfrahubDatabase, id: Optional[str] = None, **kwargs: Any) -> Self: ...
82
- async def save(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> Self: ...
83
- async def delete(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> None: ...
81
+ async def new(self, db: InfrahubDatabase, id: str | None = None, **kwargs: Any) -> Self: ...
82
+ async def save(self, db: InfrahubDatabase, at: Timestamp | None = None) -> Self: ...
83
+ async def delete(self, db: InfrahubDatabase, at: Timestamp | None = None) -> None: ...
84
84
  async def load(
85
85
  self,
86
86
  db: InfrahubDatabase,
87
- id: Optional[str] = None,
88
- db_id: Optional[str] = None,
89
- updated_at: Optional[Union[Timestamp, str]] = None,
87
+ id: str | None = None,
88
+ db_id: str | None = None,
89
+ updated_at: Timestamp | str | None = None,
90
90
  **kwargs: Any,
91
91
  ) -> Self: ...
92
92
  async def to_graphql(
93
93
  self,
94
94
  db: InfrahubDatabase,
95
- fields: Optional[dict] = None,
96
- related_node_ids: Optional[set] = None,
95
+ fields: dict | None = None,
96
+ related_node_ids: set | None = None,
97
97
  filter_sensitive: bool = False,
98
- permissions: Optional[dict] = None,
98
+ permissions: dict | None = None,
99
99
  ) -> dict: ...
100
- async def render_display_label(self, db: Optional[InfrahubDatabase] = None) -> str: ...
100
+ async def render_display_label(self, db: InfrahubDatabase | None = None) -> str: ...
101
101
  async def from_graphql(self, data: dict, db: InfrahubDatabase) -> bool: ...
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
4
4
  from collections import defaultdict
5
5
  from dataclasses import dataclass, field
6
6
  from enum import Enum
7
- from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, Optional, TypeVar, Union
7
+ from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, TypeVar
8
8
 
9
9
  import ujson
10
10
  from neo4j.graph import Node as Neo4jNode
@@ -68,9 +68,9 @@ class QueryRelDirection(Enum):
68
68
  @dataclass
69
69
  class QueryElement:
70
70
  type: QueryElementType
71
- name: Optional[str] = None
72
- labels: Optional[list[str]] = None
73
- params: Optional[dict] = None
71
+ name: str | None = None
72
+ labels: list[str] | None = None
73
+ params: dict | None = None
74
74
 
75
75
  def __str__(self) -> str:
76
76
  main_str = "%s%s%s" % (self.name or "", self.labels_as_str, self.params_as_str)
@@ -112,7 +112,7 @@ class QueryRel(QueryElement):
112
112
  type: QueryElementType = QueryElementType.RELATIONSHIP
113
113
  direction: QueryRelDirection = QueryRelDirection.BIDIR
114
114
  length_min: int = 1
115
- length_max: Optional[int] = None
115
+ length_max: int | None = None
116
116
 
117
117
  def __str__(self) -> str:
118
118
  length_str = ""
@@ -160,7 +160,7 @@ def cleanup_return_labels(labels: list[str]) -> list[str]:
160
160
 
161
161
 
162
162
  class QueryResult:
163
- def __init__(self, data: list[Union[Neo4jNode, Neo4jRelationship, list[Neo4jNode]]], labels: list[str]):
163
+ def __init__(self, data: list[Neo4jNode | Neo4jRelationship | list[Neo4jNode]], labels: list[str]):
164
164
  self.data = data
165
165
  self.labels = labels
166
166
  self.branch_score: int = 0
@@ -212,23 +212,23 @@ class QueryResult:
212
212
  self.has_deleted_rels = True
213
213
  return
214
214
 
215
- def _get(self, label: str) -> Union[Neo4jNode, Neo4jRelationship, list[Neo4jNode]]:
215
+ def _get(self, label: str) -> Neo4jNode | Neo4jRelationship | list[Neo4jNode]:
216
216
  if label not in self.labels:
217
217
  raise ValueError(f"{label} is not a valid value for this query, must be one of {self.labels}")
218
218
 
219
219
  return_id = self.labels.index(label)
220
220
  return self.data[return_id]
221
221
 
222
- def get(self, label: str) -> Union[Neo4jNode, Neo4jRelationship]:
222
+ def get(self, label: str) -> Neo4jNode | Neo4jRelationship:
223
223
  return self._get(label=label)
224
224
 
225
- def get_as_str(self, label: str) -> Optional[str]:
225
+ def get_as_str(self, label: str) -> str | None:
226
226
  item = self._get(label=label)
227
227
  if item:
228
228
  return str(item)
229
229
  return None
230
230
 
231
- def get_as_optional_type(self, label: str, return_type: Callable[..., RETURN_TYPE]) -> Optional[RETURN_TYPE]:
231
+ def get_as_optional_type(self, label: str, return_type: Callable[..., RETURN_TYPE]) -> RETURN_TYPE | None:
232
232
  """Return a label as a given type.
233
233
 
234
234
  For example if an integer is needed the caller would use:
@@ -305,7 +305,7 @@ class QueryResult:
305
305
  class QueryStats:
306
306
  stats: list[QueryStat] = field(default_factory=list)
307
307
 
308
- def add(self, data: Optional[dict[str, Any]]) -> None:
308
+ def add(self, data: dict[str, Any] | None) -> None:
309
309
  if data:
310
310
  self.stats.append(QueryStat.from_metadata(data))
311
311
 
@@ -322,13 +322,13 @@ class QueryStats:
322
322
  @dataclass
323
323
  class QueryStat:
324
324
  contains_updates: bool = False
325
- labels_added: Optional[int] = None
326
- labels_removed: Optional[int] = None
327
- nodes_created: Optional[int] = None
328
- nodes_deleted: Optional[int] = None
329
- properties_set: Optional[int] = None
330
- relationships_created: Optional[int] = None
331
- relationships_deleted: Optional[int] = None
325
+ labels_added: int | None = None
326
+ labels_removed: int | None = None
327
+ nodes_created: int | None = None
328
+ nodes_deleted: int | None = None
329
+ properties_set: int | None = None
330
+ relationships_created: int | None = None
331
+ relationships_deleted: int | None = None
332
332
 
333
333
  @classmethod
334
334
  def from_metadata(cls, data: dict[str, Any]) -> Self:
@@ -346,11 +346,11 @@ class Query(ABC):
346
346
 
347
347
  def __init__(
348
348
  self,
349
- branch: Optional[Branch] = None,
350
- at: Optional[Union[Timestamp, str]] = None,
351
- limit: Optional[int] = None,
352
- offset: Optional[int] = None,
353
- order_by: Optional[list[str]] = None,
349
+ branch: Branch | None = None,
350
+ at: Timestamp | str | None = None,
351
+ limit: int | None = None,
352
+ offset: int | None = None,
353
+ order_by: list[str] | None = None,
354
354
  branch_agnostic: bool = False,
355
355
  ):
356
356
  if branch:
@@ -379,7 +379,7 @@ class Query(ABC):
379
379
 
380
380
  self.stats: QueryStats = QueryStats()
381
381
 
382
- def update_return_labels(self, value: Union[str, list[str]]) -> None:
382
+ def update_return_labels(self, value: str | list[str]) -> None:
383
383
  if isinstance(value, str) and value not in self.return_labels:
384
384
  self.return_labels.append(value)
385
385
  return
@@ -391,10 +391,10 @@ class Query(ABC):
391
391
  async def init(
392
392
  cls,
393
393
  db: InfrahubDatabase,
394
- branch: Optional[Branch] = None,
395
- at: Optional[Union[Timestamp, str]] = None,
396
- limit: Optional[int] = None,
397
- offset: Optional[int] = None,
394
+ branch: Branch | None = None,
395
+ at: Timestamp | str | None = None,
396
+ limit: int | None = None,
397
+ offset: int | None = None,
398
398
  **kwargs: Any,
399
399
  ) -> Self:
400
400
  query = cls(branch=branch, at=at, limit=limit, offset=offset, **kwargs)
@@ -412,7 +412,7 @@ class Query(ABC):
412
412
  Right now it's mainly used to add more labels to the metrics."""
413
413
  return {}
414
414
 
415
- def add_to_query(self, query: Union[str, list[str]]) -> None:
415
+ def add_to_query(self, query: str | list[str]) -> None:
416
416
  """Add a new section at the end of the query.
417
417
 
418
418
  A string with multiple lines will be broken down into multiple entries in self.query_lines
@@ -424,7 +424,7 @@ class Query(ABC):
424
424
  else:
425
425
  self.query_lines.extend([line.strip() for line in query.split("\n") if line.strip()])
426
426
 
427
- def add_subquery(self, subquery: str, with_clause: Optional[str] = None) -> None:
427
+ def add_subquery(self, subquery: str, with_clause: str | None = None) -> None:
428
428
  self.add_to_query("CALL {")
429
429
  self.add_to_query(subquery)
430
430
  self.add_to_query("}")
@@ -435,8 +435,8 @@ class Query(ABC):
435
435
  self,
436
436
  var: bool = False,
437
437
  inline: bool = False,
438
- limit: Optional[int] = None,
439
- offset: Optional[int] = None,
438
+ limit: int | None = None,
439
+ offset: int | None = None,
440
440
  ) -> str:
441
441
  # Make a local copy of the _query_lines
442
442
  limit = limit or self.limit
@@ -602,7 +602,7 @@ class Query(ABC):
602
602
 
603
603
  return results[0][0]
604
604
 
605
- def get_result(self) -> Optional[QueryResult]:
605
+ def get_result(self) -> QueryResult | None:
606
606
  """Return a single Result."""
607
607
 
608
608
  if not self.has_been_executed:
@@ -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.constants import AttributeDBNodeType
6
6
  from infrahub.core.constants.relationship_label import RELATIONSHIP_TO_NODE_LABEL, RELATIONSHIP_TO_VALUE_LABEL
@@ -20,9 +20,9 @@ class AttributeQuery(Query):
20
20
  def __init__(
21
21
  self,
22
22
  attr: BaseAttribute,
23
- attr_id: Optional[str] = None,
24
- at: Optional[Union[Timestamp, str]] = None,
25
- branch: Optional[Branch] = None,
23
+ attr_id: str | None = None,
24
+ at: Timestamp | str | None = None,
25
+ branch: Branch | None = None,
26
26
  **kwargs: Any,
27
27
  ):
28
28
  self.attr = attr
@@ -66,6 +66,8 @@ class AttributeUpdateValueQuery(AttributeQuery):
66
66
  query = """
67
67
  MATCH (a:Attribute { uuid: $attr_uuid })
68
68
  MERGE (av:%(labels)s { %(props)s } )
69
+ WITH av, a
70
+ LIMIT 1
69
71
  CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(av)
70
72
  """ % {"rel_label": self.attr._rel_to_value_label, "labels": ":".join(labels), "props": ", ".join(prop_list)}
71
73
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Union
3
+ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from infrahub import config
6
6
  from infrahub.core.constants import GLOBAL_BRANCH_NAME, BranchSupportType
@@ -21,8 +21,8 @@ class DiffQuery(Query):
21
21
  def __init__(
22
22
  self,
23
23
  branch: Branch,
24
- diff_from: Union[Timestamp, str] = None,
25
- diff_to: Union[Timestamp, str] = None,
24
+ diff_from: Timestamp | str = None,
25
+ diff_to: Timestamp | str = None,
26
26
  **kwargs,
27
27
  ):
28
28
  """A diff is always in the context of a branch"""