infrahub-server 1.1.6__py3-none-any.whl → 1.2.0rc0__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 (346) hide show
  1. infrahub/api/artifact.py +16 -4
  2. infrahub/api/dependencies.py +8 -0
  3. infrahub/api/oauth2.py +0 -1
  4. infrahub/api/oidc.py +0 -1
  5. infrahub/api/query.py +18 -7
  6. infrahub/api/schema.py +32 -6
  7. infrahub/api/transformation.py +12 -5
  8. infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +2 -4
  9. infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
  10. infrahub/cli/__init__.py +0 -2
  11. infrahub/cli/db.py +6 -7
  12. infrahub/cli/events.py +8 -3
  13. infrahub/cli/git_agent.py +9 -7
  14. infrahub/cli/tasks.py +4 -6
  15. infrahub/computed_attribute/tasks.py +63 -17
  16. infrahub/computed_attribute/triggers.py +90 -0
  17. infrahub/config.py +1 -1
  18. infrahub/context.py +39 -0
  19. infrahub/core/account.py +5 -8
  20. infrahub/core/attribute.py +53 -21
  21. infrahub/core/branch/models.py +4 -4
  22. infrahub/core/branch/tasks.py +89 -130
  23. infrahub/core/changelog/__init__.py +0 -0
  24. infrahub/core/changelog/diff.py +232 -0
  25. infrahub/core/changelog/models.py +488 -0
  26. infrahub/core/constants/__init__.py +19 -2
  27. infrahub/core/constants/infrahubkind.py +1 -0
  28. infrahub/core/diff/combiner.py +12 -8
  29. infrahub/core/diff/coordinator.py +49 -70
  30. infrahub/core/diff/data_check_synchronizer.py +86 -7
  31. infrahub/core/diff/enricher/aggregated.py +3 -3
  32. infrahub/core/diff/enricher/cardinality_one.py +2 -7
  33. infrahub/core/diff/enricher/hierarchy.py +5 -3
  34. infrahub/core/diff/enricher/labels.py +14 -4
  35. infrahub/core/diff/enricher/path_identifier.py +3 -9
  36. infrahub/core/diff/enricher/summary_counts.py +3 -1
  37. infrahub/core/diff/merger/merger.py +8 -4
  38. infrahub/core/diff/model/path.py +47 -29
  39. infrahub/core/diff/query/all_conflicts.py +6 -3
  40. infrahub/core/diff/query/artifact.py +1 -1
  41. infrahub/core/diff/query/delete_query.py +1 -1
  42. infrahub/core/diff/query/diff_get.py +3 -2
  43. infrahub/core/diff/query/diff_summary.py +1 -1
  44. infrahub/core/diff/query/field_specifiers.py +3 -1
  45. infrahub/core/diff/query/field_summary.py +3 -2
  46. infrahub/core/diff/query/filters.py +12 -1
  47. infrahub/core/diff/query/get_conflict_query.py +1 -1
  48. infrahub/core/diff/query/has_conflicts_query.py +6 -3
  49. infrahub/core/diff/query/merge.py +3 -3
  50. infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
  51. infrahub/core/diff/query/roots_metadata.py +9 -2
  52. infrahub/core/diff/query/save.py +151 -66
  53. infrahub/core/diff/query/summary_counts_enricher.py +220 -0
  54. infrahub/core/diff/query/time_range_query.py +3 -2
  55. infrahub/core/diff/query/update_conflict_query.py +1 -1
  56. infrahub/core/diff/query_parser.py +49 -24
  57. infrahub/core/diff/repository/deserializer.py +24 -25
  58. infrahub/core/diff/repository/repository.py +76 -20
  59. infrahub/core/diff/tasks.py +9 -8
  60. infrahub/core/enums.py +1 -1
  61. infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
  62. infrahub/core/ipam/reconciler.py +1 -1
  63. infrahub/core/ipam/tasks.py +2 -3
  64. infrahub/core/manager.py +18 -13
  65. infrahub/core/merge.py +5 -2
  66. infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
  67. infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
  68. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
  69. infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
  70. infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
  71. infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
  72. infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
  73. infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
  74. infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
  75. infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
  76. infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
  77. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
  78. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
  79. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
  80. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
  81. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
  82. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
  83. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
  84. infrahub/core/migrations/query/attribute_add.py +1 -1
  85. infrahub/core/migrations/query/attribute_rename.py +1 -1
  86. infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
  87. infrahub/core/migrations/query/node_duplicate.py +1 -1
  88. infrahub/core/migrations/query/relationship_duplicate.py +1 -1
  89. infrahub/core/migrations/query/schema_attribute_update.py +1 -1
  90. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  91. infrahub/core/migrations/schema/node_remove.py +1 -1
  92. infrahub/core/migrations/schema/tasks.py +5 -5
  93. infrahub/core/migrations/shared.py +4 -4
  94. infrahub/core/models.py +7 -8
  95. infrahub/core/node/__init__.py +161 -40
  96. infrahub/core/node/base.py +1 -1
  97. infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
  98. infrahub/core/node/delete_validator.py +4 -4
  99. infrahub/core/node/ipam.py +13 -8
  100. infrahub/core/node/permissions.py +4 -0
  101. infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
  102. infrahub/core/node/standard.py +3 -5
  103. infrahub/core/property.py +1 -1
  104. infrahub/core/protocols.py +4 -0
  105. infrahub/core/protocols_base.py +4 -2
  106. infrahub/core/query/__init__.py +2 -5
  107. infrahub/core/query/attribute.py +9 -9
  108. infrahub/core/query/branch.py +5 -5
  109. infrahub/core/query/delete.py +1 -1
  110. infrahub/core/query/diff.py +45 -7
  111. infrahub/core/query/ipam.py +4 -4
  112. infrahub/core/query/node.py +19 -14
  113. infrahub/core/query/relationship.py +10 -11
  114. infrahub/core/query/resource_manager.py +13 -11
  115. infrahub/core/query/standard_node.py +6 -6
  116. infrahub/core/query/task.py +3 -3
  117. infrahub/core/query/task_log.py +1 -1
  118. infrahub/core/query/utils.py +5 -5
  119. infrahub/core/registry.py +0 -2
  120. infrahub/core/relationship/constraints/count.py +1 -1
  121. infrahub/core/relationship/constraints/peer_kind.py +1 -1
  122. infrahub/core/relationship/model.py +66 -26
  123. infrahub/core/schema/__init__.py +6 -4
  124. infrahub/core/schema/basenode_schema.py +1 -3
  125. infrahub/core/schema/definitions/core.py +14 -2
  126. infrahub/core/schema/definitions/internal.py +16 -0
  127. infrahub/core/schema/generated/genericnode_schema.py +5 -0
  128. infrahub/core/schema/generated/node_schema.py +5 -0
  129. infrahub/core/schema/generic_schema.py +5 -1
  130. infrahub/core/schema/manager.py +45 -42
  131. infrahub/core/schema/node_schema.py +4 -0
  132. infrahub/core/schema/profile_schema.py +4 -0
  133. infrahub/core/schema/relationship_schema.py +2 -2
  134. infrahub/core/schema/schema_branch.py +248 -14
  135. infrahub/core/schema/template_schema.py +36 -0
  136. infrahub/core/task/user_task.py +7 -5
  137. infrahub/core/timestamp.py +1 -1
  138. infrahub/core/utils.py +3 -2
  139. infrahub/core/validators/attribute/choices.py +1 -1
  140. infrahub/core/validators/attribute/enum.py +1 -1
  141. infrahub/core/validators/attribute/kind.py +1 -1
  142. infrahub/core/validators/attribute/length.py +1 -1
  143. infrahub/core/validators/attribute/optional.py +1 -1
  144. infrahub/core/validators/attribute/regex.py +1 -1
  145. infrahub/core/validators/attribute/unique.py +1 -1
  146. infrahub/core/validators/checks_runner.py +37 -0
  147. infrahub/core/validators/node/generate_profile.py +1 -1
  148. infrahub/core/validators/node/hierarchy.py +1 -1
  149. infrahub/core/validators/query.py +1 -1
  150. infrahub/core/validators/relationship/count.py +1 -1
  151. infrahub/core/validators/relationship/optional.py +1 -1
  152. infrahub/core/validators/relationship/peer.py +1 -1
  153. infrahub/core/validators/tasks.py +8 -6
  154. infrahub/core/validators/uniqueness/query.py +20 -17
  155. infrahub/database/__init__.py +15 -2
  156. infrahub/database/memgraph.py +1 -1
  157. infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
  158. infrahub/dependencies/builder/diff/combiner.py +1 -1
  159. infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
  160. infrahub/dependencies/builder/diff/coordinator.py +0 -2
  161. infrahub/dependencies/builder/diff/deserializer.py +1 -1
  162. infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
  163. infrahub/events/branch_action.py +47 -21
  164. infrahub/events/group_action.py +73 -0
  165. infrahub/events/models.py +159 -51
  166. infrahub/events/node_action.py +74 -8
  167. infrahub/events/repository_action.py +8 -8
  168. infrahub/events/schema_action.py +21 -8
  169. infrahub/generators/tasks.py +12 -13
  170. infrahub/git/base.py +3 -5
  171. infrahub/git/constants.py +0 -1
  172. infrahub/git/integrator.py +36 -35
  173. infrahub/git/repository.py +7 -8
  174. infrahub/git/tasks.py +43 -107
  175. infrahub/git_credential/helper.py +2 -3
  176. infrahub/graphql/analyzer.py +572 -11
  177. infrahub/graphql/app.py +34 -26
  178. infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
  179. infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
  180. infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
  181. infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
  182. infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
  183. infrahub/graphql/enums.py +1 -1
  184. infrahub/graphql/initialization.py +5 -1
  185. infrahub/graphql/loaders/node.py +2 -2
  186. infrahub/graphql/manager.py +59 -54
  187. infrahub/graphql/mutations/account.py +20 -13
  188. infrahub/graphql/mutations/artifact_definition.py +16 -12
  189. infrahub/graphql/mutations/branch.py +61 -40
  190. infrahub/graphql/mutations/computed_attribute.py +19 -13
  191. infrahub/graphql/mutations/diff.py +37 -9
  192. infrahub/graphql/mutations/diff_conflict.py +9 -8
  193. infrahub/graphql/mutations/graphql_query.py +19 -11
  194. infrahub/graphql/mutations/ipam.py +21 -19
  195. infrahub/graphql/mutations/main.py +197 -44
  196. infrahub/graphql/mutations/menu.py +8 -8
  197. infrahub/graphql/mutations/proposed_change.py +36 -28
  198. infrahub/graphql/mutations/relationship.py +302 -105
  199. infrahub/graphql/mutations/repository.py +41 -35
  200. infrahub/graphql/mutations/resource_manager.py +26 -26
  201. infrahub/graphql/mutations/schema.py +51 -33
  202. infrahub/graphql/mutations/tasks.py +16 -10
  203. infrahub/graphql/parser.py +1 -1
  204. infrahub/graphql/permissions.py +6 -4
  205. infrahub/graphql/queries/account.py +22 -18
  206. infrahub/graphql/queries/branch.py +6 -4
  207. infrahub/graphql/queries/diff/tree.py +48 -42
  208. infrahub/graphql/queries/event.py +112 -0
  209. infrahub/graphql/queries/internal.py +3 -3
  210. infrahub/graphql/queries/ipam.py +23 -18
  211. infrahub/graphql/queries/relationship.py +11 -10
  212. infrahub/graphql/queries/resource_manager.py +43 -27
  213. infrahub/graphql/queries/search.py +9 -8
  214. infrahub/graphql/queries/status.py +12 -9
  215. infrahub/graphql/queries/task.py +11 -9
  216. infrahub/graphql/resolvers/resolver.py +69 -43
  217. infrahub/graphql/resolvers/single_relationship.py +16 -10
  218. infrahub/graphql/schema.py +2 -0
  219. infrahub/graphql/subscription/__init__.py +1 -1
  220. infrahub/graphql/subscription/events.py +1 -1
  221. infrahub/graphql/subscription/graphql_query.py +8 -8
  222. infrahub/graphql/types/branch.py +2 -2
  223. infrahub/graphql/types/common.py +6 -1
  224. infrahub/graphql/types/enums.py +2 -0
  225. infrahub/graphql/types/event.py +100 -0
  226. infrahub/graphql/types/interface.py +2 -2
  227. infrahub/graphql/types/node.py +3 -3
  228. infrahub/graphql/types/permission.py +2 -2
  229. infrahub/graphql/types/relationship.py +3 -3
  230. infrahub/graphql/types/standard_node.py +9 -11
  231. infrahub/graphql/utils.py +28 -182
  232. infrahub/groups/tasks.py +2 -3
  233. infrahub/lock.py +1 -1
  234. infrahub/menu/constants.py +1 -0
  235. infrahub/menu/generator.py +14 -3
  236. infrahub/menu/menu.py +116 -127
  237. infrahub/menu/models.py +4 -4
  238. infrahub/message_bus/messages/__init__.py +0 -4
  239. infrahub/message_bus/messages/event_branch_merge.py +3 -0
  240. infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
  241. infrahub/message_bus/operations/__init__.py +3 -5
  242. infrahub/message_bus/operations/check/__init__.py +2 -2
  243. infrahub/message_bus/operations/check/generator.py +1 -3
  244. infrahub/message_bus/operations/check/repository.py +1 -1
  245. infrahub/message_bus/operations/event/branch.py +7 -3
  246. infrahub/message_bus/operations/event/schema.py +1 -1
  247. infrahub/message_bus/operations/finalize/validator.py +1 -1
  248. infrahub/message_bus/operations/git/file.py +2 -2
  249. infrahub/message_bus/operations/git/repository.py +1 -1
  250. infrahub/message_bus/operations/requests/__init__.py +0 -2
  251. infrahub/message_bus/operations/requests/generator_definition.py +1 -1
  252. infrahub/message_bus/operations/requests/proposed_change.py +26 -11
  253. infrahub/message_bus/operations/requests/repository.py +2 -2
  254. infrahub/message_bus/operations/send/echo.py +1 -1
  255. infrahub/message_bus/types.py +1 -1
  256. infrahub/permissions/__init__.py +2 -1
  257. infrahub/permissions/types.py +26 -0
  258. infrahub/pools/prefix.py +29 -165
  259. infrahub/prefect_server/__init__.py +0 -0
  260. infrahub/prefect_server/app.py +18 -0
  261. infrahub/prefect_server/database.py +20 -0
  262. infrahub/prefect_server/events.py +28 -0
  263. infrahub/prefect_server/models.py +46 -0
  264. infrahub/proposed_change/models.py +15 -1
  265. infrahub/proposed_change/tasks.py +173 -35
  266. infrahub/pytest_plugin.py +4 -4
  267. infrahub/server.py +12 -11
  268. infrahub/services/__init__.py +147 -62
  269. infrahub/services/adapters/cache/__init__.py +7 -5
  270. infrahub/services/adapters/cache/nats.py +40 -22
  271. infrahub/services/adapters/cache/redis.py +0 -4
  272. infrahub/services/adapters/event/__init__.py +10 -18
  273. infrahub/services/adapters/http/__init__.py +0 -5
  274. infrahub/services/adapters/http/httpx.py +22 -15
  275. infrahub/services/adapters/message_bus/__init__.py +23 -6
  276. infrahub/services/adapters/message_bus/local.py +8 -6
  277. infrahub/services/adapters/message_bus/nats.py +12 -6
  278. infrahub/services/adapters/message_bus/rabbitmq.py +22 -9
  279. infrahub/services/adapters/workflow/__init__.py +11 -8
  280. infrahub/services/adapters/workflow/local.py +28 -7
  281. infrahub/services/adapters/workflow/worker.py +23 -7
  282. infrahub/services/component.py +38 -35
  283. infrahub/services/scheduler.py +32 -29
  284. infrahub/storage.py +2 -4
  285. infrahub/task_manager/constants.py +1 -1
  286. infrahub/task_manager/event.py +182 -0
  287. infrahub/task_manager/models.py +125 -1
  288. infrahub/task_manager/task.py +1 -1
  289. infrahub/tasks/artifact.py +14 -16
  290. infrahub/tasks/registry.py +1 -1
  291. infrahub/tasks/telemetry.py +13 -14
  292. infrahub/transformations/tasks.py +3 -5
  293. infrahub/trigger/__init__.py +0 -0
  294. infrahub/trigger/catalogue.py +15 -0
  295. infrahub/trigger/constants.py +9 -0
  296. infrahub/trigger/models.py +69 -0
  297. infrahub/trigger/tasks.py +85 -0
  298. infrahub/types.py +1 -1
  299. infrahub/utils.py +1 -1
  300. infrahub/webhook/constants.py +0 -2
  301. infrahub/webhook/models.py +8 -2
  302. infrahub/webhook/tasks.py +20 -73
  303. infrahub/webhook/triggers.py +20 -0
  304. infrahub/workers/infrahub_async.py +36 -25
  305. infrahub/workers/utils.py +63 -0
  306. infrahub/workflows/catalogue.py +13 -37
  307. infrahub/workflows/initialization.py +6 -8
  308. infrahub/workflows/models.py +3 -5
  309. infrahub/workflows/utils.py +1 -1
  310. infrahub_sdk/ctl/check.py +3 -3
  311. infrahub_sdk/ctl/cli_commands.py +11 -10
  312. infrahub_sdk/ctl/exceptions.py +0 -6
  313. infrahub_sdk/ctl/exporter.py +1 -1
  314. infrahub_sdk/ctl/generator.py +5 -5
  315. infrahub_sdk/ctl/importer.py +3 -2
  316. infrahub_sdk/ctl/menu.py +1 -1
  317. infrahub_sdk/ctl/object.py +1 -1
  318. infrahub_sdk/ctl/repository.py +23 -15
  319. infrahub_sdk/ctl/schema.py +2 -2
  320. infrahub_sdk/ctl/utils.py +4 -3
  321. infrahub_sdk/ctl/validate.py +2 -1
  322. infrahub_sdk/exceptions.py +6 -0
  323. infrahub_sdk/generator.py +3 -0
  324. infrahub_sdk/node.py +2 -2
  325. infrahub_sdk/schema/__init__.py +14 -2
  326. infrahub_sdk/schema/main.py +7 -0
  327. infrahub_sdk/utils.py +11 -1
  328. infrahub_sdk/yaml.py +2 -3
  329. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/METADATA +46 -12
  330. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/RECORD +338 -321
  331. infrahub_testcontainers/container.py +14 -6
  332. infrahub_testcontainers/docker-compose.test.yml +24 -5
  333. infrahub_testcontainers/haproxy.cfg +43 -0
  334. infrahub_testcontainers/helpers.py +85 -1
  335. infrahub/core/branch/constants.py +0 -2
  336. infrahub/graphql/query.py +0 -52
  337. infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
  338. infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
  339. infrahub/schema/constants.py +0 -1
  340. infrahub/schema/tasks.py +0 -76
  341. infrahub/services/adapters/database/__init__.py +0 -9
  342. infrahub_sdk/ctl/_file.py +0 -13
  343. /infrahub/{schema → artifacts}/__init__.py +0 -0
  344. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/LICENSE.txt +0 -0
  345. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/WHEEL +0 -0
  346. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0rc0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  from typing import TYPE_CHECKING, Any
2
2
 
3
3
  from graphql import GraphQLResolveInfo
4
+ from graphql.type.definition import GraphQLNonNull
4
5
  from infrahub_sdk.utils import deep_merge_dict, extract_fields
5
6
 
6
7
  from infrahub.core.branch.models import Branch
@@ -31,9 +32,14 @@ class SingleRelationshipResolver:
31
32
  """
32
33
  # Extract the InfraHub schema by inspecting the GQL Schema
33
34
 
34
- node_schema: NodeSchema = info.parent_type.graphene_type._meta.schema # type: ignore[attr-defined]
35
+ # :
36
+ node_schema: NodeSchema = (
37
+ info.parent_type.of_type.graphene_type._meta.schema
38
+ if isinstance(info.parent_type, GraphQLNonNull)
39
+ else info.parent_type.graphene_type._meta.schema # type: ignore[attr-defined]
40
+ )
35
41
 
36
- context: GraphqlContext = info.context
42
+ graphql_context: GraphqlContext = info.context
37
43
 
38
44
  # Extract the name of the fields in the GQL query
39
45
  fields = await extract_fields(info.field_nodes[0].selection_set)
@@ -53,10 +59,10 @@ class SingleRelationshipResolver:
53
59
 
54
60
  if requires_relationship_metadata:
55
61
  node_graph = await self._get_entities_simple(
56
- db=context.db,
57
- branch=context.branch,
58
- at=context.at,
59
- related_node_ids=context.related_node_ids,
62
+ db=graphql_context.db,
63
+ branch=graphql_context.branch,
64
+ at=graphql_context.at,
65
+ related_node_ids=graphql_context.related_node_ids,
60
66
  field_name=info.field_name,
61
67
  parent_id=parent["id"],
62
68
  source_kind=node_schema.kind,
@@ -66,10 +72,10 @@ class SingleRelationshipResolver:
66
72
  )
67
73
  else:
68
74
  node_graph = await self._get_entities_with_data_loader(
69
- db=context.db,
70
- branch=context.branch,
71
- at=context.at,
72
- related_node_ids=context.related_node_ids,
75
+ db=graphql_context.db,
76
+ branch=graphql_context.branch,
77
+ at=graphql_context.at,
78
+ related_node_ids=graphql_context.related_node_ids,
73
79
  rel_schema=node_rel,
74
80
  parent=parent,
75
81
  node_fields=node_fields,
@@ -48,6 +48,7 @@ from .queries import (
48
48
  Relationship,
49
49
  )
50
50
  from .queries.diff.tree import DiffTreeQuery, DiffTreeSummaryQuery
51
+ from .queries.event import Event
51
52
  from .queries.task import Task, TaskBranchStatus
52
53
 
53
54
 
@@ -67,6 +68,7 @@ class InfrahubBaseQuery(ObjectType):
67
68
  InfrahubSearchAnywhere = InfrahubSearchAnywhere
68
69
 
69
70
  InfrahubTask = Task
71
+ InfrahubEvent = Event
70
72
  InfrahubTaskBranchStatus = TaskBranchStatus
71
73
 
72
74
  IPAddressGetNextAvailable = InfrahubIPAddressGetNextAvailable
@@ -21,7 +21,7 @@ class InfrahubBaseSubscription(ObjectType):
21
21
  @classmethod
22
22
  async def subscribe_query(
23
23
  cls,
24
- parent: dict, # pylint: disable=unused-argument
24
+ parent: dict,
25
25
  info: GraphQLResolveInfo,
26
26
  name: str,
27
27
  params: dict[str, Any] | None = None,
@@ -19,7 +19,7 @@
19
19
 
20
20
  # log = get_logger(name="infrahub.graphql")
21
21
 
22
- # async def resolver_event(root: dict, info: GraphQLResolveInfo, topics: Optional[List] = None): # pylint: disable=unused-argument
22
+ # async def resolver_event(root: dict, info: GraphQLResolveInfo, topics: Optional[List] = None):
23
23
  # pass
24
24
  # connection = await get_broker()
25
25
 
@@ -18,35 +18,35 @@ log = get_logger(name="infrahub.graphql")
18
18
 
19
19
 
20
20
  async def resolver_graphql_query(
21
- parent: dict, # pylint: disable=unused-argument
21
+ parent: dict, # noqa: ARG001
22
22
  info: GraphQLResolveInfo,
23
23
  name: str,
24
24
  graphql_schema: Schema,
25
25
  params: dict[str, Any] | None = None,
26
26
  interval: int = 10,
27
27
  ) -> AsyncGenerator[dict[str, Any], None]:
28
- context: GraphqlContext = info.context
28
+ graphql_context: GraphqlContext = info.context
29
29
  at = Timestamp()
30
30
 
31
- async with context.db.start_session() as db:
31
+ async with graphql_context.db.start_session() as db:
32
32
  # Find the GraphQLQuery and the GraphQL Schema
33
33
  graphql_query = await NodeManager.get_one_by_default_filter(
34
- db=db, id=name, kind=CoreGraphQLQuery, branch=context.branch, at=at
34
+ db=db, id=name, kind=CoreGraphQLQuery, branch=graphql_context.branch, at=at
35
35
  )
36
36
  if not graphql_query:
37
37
  raise ValueError(f"Unable to find the {InfrahubKind.GRAPHQLQUERY} {name}")
38
38
 
39
39
  while True:
40
- async with context.db.start_session() as db:
40
+ async with graphql_context.db.start_session() as db:
41
41
  result = await graphql(
42
42
  schema=graphql_schema,
43
43
  source=graphql_query.query.value,
44
- context_value=context.__class__(
44
+ context_value=graphql_context.__class__(
45
45
  db=db,
46
- branch=context.branch,
46
+ branch=graphql_context.branch,
47
47
  at=Timestamp(),
48
48
  related_node_ids=set(),
49
- types=context.types,
49
+ types=graphql_context.types,
50
50
  single_relationship_resolver=SingleRelationshipResolver(),
51
51
  ),
52
52
  root_value=None,
@@ -34,10 +34,10 @@ class BranchType(InfrahubObjectType):
34
34
  async def get_list(
35
35
  cls,
36
36
  fields: dict,
37
- context: GraphqlContext,
37
+ graphql_context: GraphqlContext,
38
38
  **kwargs: Any,
39
39
  ) -> list[dict[str, Any]]:
40
- async with context.db.start_session() as db:
40
+ async with graphql_context.db.start_session() as db:
41
41
  objs = await Branch.get_list(db=db, **kwargs)
42
42
 
43
43
  if not objs:
@@ -1,7 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- from graphene import InputObjectType, String
3
+ from graphene import InputObjectType, ObjectType, String
4
4
 
5
5
 
6
6
  class IdentifierInput(InputObjectType):
7
7
  id = String(required=True, description="The ID of the requested object")
8
+
9
+
10
+ class RelatedNode(ObjectType):
11
+ id = String(required=True, description="The ID of the requested object")
12
+ kind = String(required=True, description="The ID of the requested object")
@@ -5,6 +5,8 @@ from infrahub.permissions import constants as permission_constants
5
5
 
6
6
  CheckType = Enum.from_enum(constants.CheckType)
7
7
 
8
+ DiffAction = Enum.from_enum(constants.DiffAction)
9
+
8
10
  Severity = Enum.from_enum(constants.Severity)
9
11
 
10
12
  BranchRelativePermissionDecision = Enum.from_enum(permission_constants.BranchRelativePermissionDecision)
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from graphene import Boolean, DateTime, Field, Int, Interface, List, NonNull, ObjectType, String
6
+ from graphene.types.generic import GenericScalar
7
+
8
+ from .common import RelatedNode
9
+ from .enums import DiffAction
10
+
11
+ if TYPE_CHECKING:
12
+ from graphql import GraphQLResolveInfo
13
+
14
+
15
+ class InfrahubMutatedAttribute(ObjectType):
16
+ name = String(required=True)
17
+ action = DiffAction(required=True)
18
+ value = String(required=False)
19
+ kind = String(required=True)
20
+ value_previous = String(required=False)
21
+
22
+
23
+ class EventNodeInterface(Interface):
24
+ id = String(required=True)
25
+ event = String(required=True)
26
+ branch = String(required=False)
27
+ account_id = String(required=False)
28
+ occurred_at = DateTime(required=True)
29
+ level = Int(required=True)
30
+ primary_node = Field(RelatedNode, required=False)
31
+ related_nodes = List(NonNull(RelatedNode), required=True)
32
+ has_children = Boolean(required=True)
33
+ parent_id = String(required=False)
34
+
35
+ @classmethod
36
+ def resolve_type(
37
+ cls,
38
+ instance: dict[str, Any],
39
+ info: GraphQLResolveInfo, # noqa: ARG003
40
+ ) -> type[ObjectType]:
41
+ if "event" in instance:
42
+ return EVENT_TYPES.get(instance["event"], StandardEvent)
43
+ return StandardEvent
44
+
45
+
46
+ class EventNodes(ObjectType):
47
+ node = Field(EventNodeInterface)
48
+
49
+
50
+ # ---------------------------------------
51
+ # Branch events
52
+ # ---------------------------------------
53
+ class BranchCreatedEvent(ObjectType):
54
+ class Meta:
55
+ interfaces = (EventNodeInterface,)
56
+
57
+ payload = Field(GenericScalar, required=True)
58
+
59
+
60
+ class BranchRebasedEvent(ObjectType):
61
+ class Meta:
62
+ interfaces = (EventNodeInterface,)
63
+
64
+ payload = Field(GenericScalar, required=True)
65
+
66
+
67
+ class BranchDeletedEvent(ObjectType):
68
+ class Meta:
69
+ interfaces = (EventNodeInterface,)
70
+
71
+ payload = Field(GenericScalar, required=True)
72
+
73
+
74
+ # ---------------------------------------
75
+ # Node/Object events
76
+ # ---------------------------------------
77
+ class NodeMutatedEvent(ObjectType):
78
+ class Meta:
79
+ interfaces = (EventNodeInterface,)
80
+
81
+ payload = Field(GenericScalar, required=True)
82
+ attributes = Field(List(of_type=NonNull(InfrahubMutatedAttribute), required=True), required=True)
83
+
84
+
85
+ class StandardEvent(ObjectType):
86
+ class Meta:
87
+ interfaces = (EventNodeInterface,)
88
+
89
+ payload = Field(GenericScalar, required=True)
90
+
91
+
92
+ EVENT_TYPES: dict[str, type[ObjectType]] = {
93
+ "infrahub.node.created": NodeMutatedEvent,
94
+ "infrahub.node.updated": NodeMutatedEvent,
95
+ "infrahub.node.deleted": NodeMutatedEvent,
96
+ "infrahub.branch.created": BranchCreatedEvent,
97
+ "infrahub.branch.rebased": BranchRebasedEvent,
98
+ "infrahub.branch.deleted": BranchDeletedEvent,
99
+ "undefined": StandardEvent,
100
+ }
@@ -21,8 +21,8 @@ class InfrahubInterfaceOptions(InterfaceOptions):
21
21
  class InfrahubInterface(Interface):
22
22
  @classmethod
23
23
  def resolve_type(cls, instance: dict[str, Any], info: GraphQLResolveInfo) -> InfrahubObject:
24
- context: GraphqlContext = info.context
24
+ graphql_context: GraphqlContext = info.context
25
25
  if KIND_GRAPHQL_FIELD_NAME in instance:
26
- return context.types[instance[KIND_GRAPHQL_FIELD_NAME]]
26
+ return graphql_context.types[instance[KIND_GRAPHQL_FIELD_NAME]]
27
27
 
28
28
  raise ValueError("Unable to identify the type of the instance.")
@@ -5,7 +5,7 @@ from typing import Any, Optional
5
5
  from graphene import ObjectType
6
6
  from graphene.types.objecttype import ObjectTypeOptions
7
7
 
8
- from infrahub.core.schema import GenericSchema, MainSchemaTypes, NodeSchema, ProfileSchema
8
+ from infrahub.core.schema import GenericSchema, MainSchemaTypes, NodeSchema, ProfileSchema, TemplateSchema
9
9
 
10
10
 
11
11
  class InfrahubObjectOptions(ObjectTypeOptions):
@@ -14,14 +14,14 @@ class InfrahubObjectOptions(ObjectTypeOptions):
14
14
 
15
15
  class InfrahubObject(ObjectType):
16
16
  @classmethod
17
- def __init_subclass_with_meta__( # pylint: disable=arguments-differ
17
+ def __init_subclass_with_meta__(
18
18
  cls,
19
19
  schema: Optional[MainSchemaTypes] = None,
20
20
  interfaces: tuple = (),
21
21
  _meta: InfrahubObjectOptions | None = None,
22
22
  **options: Any,
23
23
  ) -> None:
24
- if not isinstance(schema, (NodeSchema, GenericSchema, ProfileSchema)):
24
+ if not isinstance(schema, NodeSchema | GenericSchema | ProfileSchema | TemplateSchema):
25
25
  raise ValueError(f"You need to pass a valid NodeSchema in '{cls.__name__}.Meta', received '{schema}'")
26
26
 
27
27
  if not _meta:
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from graphene import Field, Int, List, ObjectType, String
3
+ from graphene import Field, Int, List, NonNull, ObjectType, String
4
4
 
5
5
  from infrahub.graphql.types.enums import BranchRelativePermissionDecision
6
6
 
@@ -39,4 +39,4 @@ class PaginatedObjectPermission(ObjectType):
39
39
  required=True,
40
40
  description="The number of permissions applicable, will be 1 for normal nodes or possibly more for generics",
41
41
  )
42
- edges = Field(List(of_type=ObjectPermissionNode, required=True), required=True)
42
+ edges = Field(List(of_type=NonNull(ObjectPermissionNode), required=True), required=True)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from graphene import Field, List, ObjectType, String
3
+ from graphene import Field, List, NonNull, ObjectType, String
4
4
 
5
5
 
6
6
  class RelationshipPeer(ObjectType):
@@ -11,8 +11,8 @@ class RelationshipPeer(ObjectType):
11
11
  class Relationship(ObjectType):
12
12
  id = String(required=False)
13
13
  identifier = String(required=False)
14
- peers = List(RelationshipPeer)
14
+ peers = List(NonNull(RelationshipPeer))
15
15
 
16
16
 
17
17
  class RelationshipNode(ObjectType):
18
- node = Field(Relationship)
18
+ node = Field(Relationship, required=True)
@@ -17,9 +17,7 @@ class InfrahubObjectTypeOptions(ObjectTypeOptions):
17
17
 
18
18
  class InfrahubObjectType(ObjectType):
19
19
  @classmethod
20
- def __init_subclass_with_meta__( # pylint: disable=arguments-differ
21
- cls, model=None, interfaces=(), _meta=None, **options
22
- ) -> None:
20
+ def __init_subclass_with_meta__(cls, model=None, interfaces=(), _meta=None, **options) -> None:
23
21
  if not _meta:
24
22
  _meta = InfrahubObjectTypeOptions(cls)
25
23
 
@@ -28,24 +26,24 @@ class InfrahubObjectType(ObjectType):
28
26
  super().__init_subclass_with_meta__(_meta=_meta, interfaces=interfaces, **options)
29
27
 
30
28
  @classmethod
31
- async def get_list(cls, fields: dict[str, Any], context: GraphqlContext, **kwargs) -> list[dict[str, Any]]:
32
- async with context.db.session(database=config.SETTINGS.database.database_name) as db:
29
+ async def get_list(cls, fields: dict[str, Any], graphql_context: GraphqlContext, **kwargs) -> list[dict[str, Any]]:
30
+ async with graphql_context.db.session(database=config.SETTINGS.database.database_name) as db:
33
31
  filters = {key: value for key, value in kwargs.items() if "__" in key and value}
34
32
 
35
33
  if filters:
36
34
  objs = await cls._meta.model.get_list(
37
35
  filters=filters,
38
- at=context.at,
39
- branch=context.branch,
40
- account=context.account_session,
36
+ at=graphql_context.at,
37
+ branch=graphql_context.branch,
38
+ account=graphql_context.account_session,
41
39
  include_source=True,
42
40
  db=db,
43
41
  )
44
42
  else:
45
43
  objs = await cls._meta.model.get_list(
46
- at=context.at,
47
- branch=context.branch,
48
- account=context.account_session,
44
+ at=graphql_context.at,
45
+ branch=graphql_context.branch,
46
+ account=graphql_context.account_session,
49
47
  include_source=True,
50
48
  db=db,
51
49
  )
infrahub/graphql/utils.py CHANGED
@@ -3,24 +3,16 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Union
4
4
 
5
5
  from graphene.types.definitions import GrapheneInterfaceType, GrapheneObjectType
6
- from graphql import ( # pylint: disable=no-name-in-module
7
- ExecutionContext,
8
- FieldNode,
9
- FragmentSpreadNode,
6
+ from graphql import (
10
7
  GraphQLList,
11
- GraphQLObjectType,
12
- GraphQLResolveInfo,
8
+ GraphQLNonNull,
13
9
  GraphQLSchema,
14
10
  GraphQLUnionType,
15
- InlineFragmentNode,
16
- SelectionSetNode,
17
11
  )
18
12
 
19
13
  from infrahub.exceptions import GraphQLQueryError
20
14
 
21
15
  if TYPE_CHECKING:
22
- import abc
23
-
24
16
  from graphql.execution import ExecutionResult
25
17
 
26
18
 
@@ -42,171 +34,6 @@ def extract_data(query_name: str, result: ExecutionResult) -> dict:
42
34
  return result.data or {}
43
35
 
44
36
 
45
- # --------------------------------------------------------------
46
- # The functions below :
47
- # - selected_field_names_fast
48
- # - selected_field_names_naive
49
- # - selected_field_names
50
- # - selected_field_names_from_context
51
- # Are not currently used and they have been copied from internet as a reference
52
- # >> https://github.com/graphql-python/graphene/issues/57#issuecomment-774227086
53
- #
54
- # --------------------------------------------------------------
55
- def selected_field_names_fast(
56
- selection_set: SelectionSetNode, context: GraphQLResolveInfo, runtime_type: Union[str, GraphQLObjectType] = None
57
- ) -> abc.Iterator[str]:
58
- """Use the fastest available function to provide the list of selected field names
59
-
60
- Note that this function may give false positives because in the absence of fragments it ignores directives.
61
- """
62
- # Any fragments?
63
- no_fragments = all(isinstance(node, FieldNode) for node in selection_set.selections)
64
-
65
- # Choose the function to execute
66
- if no_fragments:
67
- return selected_field_names_naive(selection_set)
68
-
69
- return selected_field_names(selection_set, context, runtime_type)
70
-
71
-
72
- def selected_field_names_naive(selection_set: SelectionSetNode) -> list:
73
- """Get the list of field names that are selected at the current level. Does not include nested names.
74
-
75
- Limitations:
76
- * Does not resolve fragments; throws RuntimeError
77
- * Does not take directives into account. A field might be disabled, and this function wouldn't know
78
-
79
- As a result:
80
- * It will give a RuntimeError if a fragment is provided
81
- * It may give false positives in case directives are used
82
- * It is 20x faster than the alternative
83
-
84
- Benefits:
85
- * Fast!
86
-
87
- Args:
88
- selection_set: the selected fields
89
-
90
- Code copied from https://github.com/graphql-python/graphene/issues/57#issuecomment-774227086
91
- This link also includes a more powerful and complexe alternative.
92
- """
93
- assert isinstance(selection_set, SelectionSetNode)
94
-
95
- field_names = []
96
-
97
- for node in selection_set.selections:
98
- # Field
99
- if isinstance(node, FieldNode):
100
- field_names.append(node.name.value)
101
- # Fragment spread (`... fragmentName`)
102
- elif isinstance(node, (FragmentSpreadNode, InlineFragmentNode)):
103
- raise NotImplementedError("Fragments are not supported by this simplistic function")
104
- # Something new
105
- else:
106
- raise NotImplementedError(str(type(node)))
107
-
108
- return field_names
109
-
110
-
111
- def selected_field_names(
112
- selection_set: SelectionSetNode, info: GraphQLResolveInfo, runtime_type: Union[str, GraphQLObjectType] = None
113
- ) -> abc.Iterator[str]:
114
- """Get the list of field names that are selected at the current level. Does not include nested names.
115
-
116
- This function re-evaluates the AST, but gives a complete list of included fields.
117
- It is 25x slower than `selected_field_names_naive()`, but still, it completes in 7ns or so. Not bad.
118
-
119
- Args:
120
- selection_set: the selected fields
121
- info: GraphQL resolve info
122
- runtime_type: The type of the object you resolve to. Either its string name, or its ObjectType.
123
- If none is provided, this function will fail with a RuntimeError() when resolving fragments
124
- """
125
- # pylint: disable=no-value-for-parameter
126
-
127
- # Create a temporary execution context. This operation is quite cheap, actually.
128
- execution_context = ExecutionContext(
129
- schema=info.schema,
130
- fragments=info.fragments,
131
- root_value=info.root_value,
132
- operation=info.operation,
133
- variable_values=info.variable_values,
134
- # The only purpose of this context is to be able to run the collect_fields() method.
135
- # Therefore, many parameters are actually irrelevant
136
- context_value=None,
137
- field_resolver=None,
138
- type_resolver=None,
139
- errors=[],
140
- middleware_manager=None,
141
- )
142
-
143
- # Use it
144
- return selected_field_names_from_context(selection_set, execution_context, runtime_type)
145
-
146
-
147
- def selected_field_names_from_context(
148
- selection_set: SelectionSetNode, context: ExecutionContext, runtime_type: Union[str, GraphQLObjectType] = None
149
- ) -> abc.Iterator[str]:
150
- """Get the list of field names that are selected at the current level.
151
-
152
- This function is useless because `graphql.ExecutionContext` is not available at all inside resolvers.
153
- Therefore, `selected_field_names()` wraps it and provides one.
154
- """
155
- assert isinstance(selection_set, SelectionSetNode)
156
-
157
- # Resolve `runtime_type`
158
- if isinstance(runtime_type, str):
159
- runtime_type = context.schema.type_map[runtime_type] # raises: KeyError
160
-
161
- # Resolve all fields
162
- fields_map = context.collect_fields(
163
- # Use the provided Object type, or use a dummy object that fails all tests
164
- runtime_type=runtime_type or None,
165
- # runtime_type=runtime_type or graphql.GraphQLObjectType('<temp>', []),
166
- selection_set=selection_set,
167
- fields={}, # out
168
- visited_fragment_names=(visited_fragment_names := set()), # out
169
- )
170
-
171
- # Test fragment resolution
172
- if visited_fragment_names and not runtime_type:
173
- raise RuntimeError(
174
- "The query contains fragments which cannot be resolved "
175
- "because `runtime_type` is not provided by the lazy developer"
176
- )
177
-
178
- # Results!
179
- return (field.name.value for fields_list in fields_map.values() for field in fields_list)
180
-
181
-
182
- def print_query(info: GraphQLResolveInfo) -> None:
183
- """Traverse the query"""
184
- initial_selection_set = info.field_nodes[0].selection_set
185
- print_selection_set(initial_selection_set, 1)
186
-
187
-
188
- def print_selection_set(selection_set: SelectionSetNode, level: int = 1) -> int:
189
- # max_depth = level
190
- tab = " "
191
- for field in getattr(selection_set, "selections", []):
192
- # print(f"in print_selection_set loop {field}")
193
- # The field we are at is already a lever deeper, even if it doesn't have its own selection set.
194
- # max_depth = max(max_depth, level + 1)
195
- print(f"{level * tab}{field.name.value}")
196
- if selection_set := getattr(field, "selection_set", None):
197
- # max_depth = max(max_depth, self._get_query_depth(selection_set, level + 1))
198
- print_selection_set(selection_set, level + 1)
199
-
200
- # """
201
- # MATCH (d:Device)
202
- # WHERE (d)-[]-(:Attribute {name: "name"})-[]-(:AttributeValue {value: "spine1"})
203
- # MAT36CH (d)-[:IS_RELATED]-(r1:Relationship{type: "device_interface"})-[:IS_RELATED]-(n1)
204
- # WHERE (n1)-[]-(:Attribute {name: "enabled"})-[]-(:AttributeValue {value: false})
205
- # OPTIONAL MATCH (d)-[:IS_RELATED]-(r1)-[:IS_RELATED]-(n1)-[:IS_RELATED]-(r2:Relationship {type: "interface_ip"})-[:IS_RELATED]-(n2)
206
- # RETURN d,n1,r1,n2,r2
207
- # """
208
-
209
-
210
37
  def find_types_implementing_interface(
211
38
  interface: GrapheneInterfaceType, root_schema: GraphQLSchema
212
39
  ) -> list[GrapheneObjectType]:
@@ -234,12 +61,19 @@ async def extract_schema_models(
234
61
  if field_name not in schema.fields:
235
62
  continue
236
63
 
237
- if isinstance(schema.fields[field_name].type, GrapheneObjectType):
238
- object_type = schema.fields[field_name].type
239
- elif isinstance(schema.fields[field_name].type, GraphQLList):
240
- object_type = schema.fields[field_name].type.of_type
241
- elif isinstance(schema.fields[field_name].type, GrapheneInterfaceType):
242
- object_type = schema.fields[field_name].type
64
+ gql_type = schema.fields[field_name].type
65
+ if isinstance(schema.fields[field_name].type, GraphQLNonNull):
66
+ gql_type = schema.fields[field_name].type.of_type
67
+
68
+ if isinstance(gql_type, GrapheneObjectType):
69
+ object_type = gql_type
70
+ elif isinstance(gql_type, GraphQLList):
71
+ if isinstance(gql_type.of_type, GraphQLNonNull):
72
+ object_type = gql_type.of_type.of_type
73
+ else:
74
+ object_type = gql_type.of_type
75
+ elif isinstance(gql_type, GrapheneInterfaceType):
76
+ object_type = gql_type
243
77
  sub_types = find_types_implementing_interface(interface=object_type, root_schema=root_schema)
244
78
  for sub_type in sub_types:
245
79
  response.add(sub_type.name)
@@ -247,6 +81,15 @@ async def extract_schema_models(
247
81
  else:
248
82
  continue
249
83
 
84
+ # Ensure that Attribute types are not reported by this function
85
+ if isinstance(object_type, GrapheneObjectType) and object_type.interfaces:
86
+ inherit_from = [intf.name for intf in object_type.interfaces]
87
+ if "AttributeInterface" in inherit_from:
88
+ continue
89
+
90
+ if isinstance(object_type, GraphQLNonNull):
91
+ raise ValueError("object_type shouldn't be a of type GraphQLNonNull")
92
+
250
93
  response.add(object_type.name)
251
94
 
252
95
  if isinstance(value, dict):
@@ -255,6 +98,9 @@ async def extract_schema_models(
255
98
  if isinstance(schema.fields[value].type, GrapheneObjectType):
256
99
  response.add(schema.fields[value].type.name)
257
100
  elif isinstance(schema.fields[value].type, GraphQLList):
258
- response.add(schema.fields[value].type.of_type.name)
101
+ if isinstance(schema.fields[value].type.of_type, GraphQLNonNull):
102
+ response.add(schema.fields[value].type.of_type.of_type.name)
103
+ else:
104
+ response.add(schema.fields[value].type.of_type.name)
259
105
 
260
106
  return response
infrahub/groups/tasks.py CHANGED
@@ -4,12 +4,12 @@ from prefect import flow
4
4
 
5
5
  from infrahub.core.constants import InfrahubKind
6
6
  from infrahub.groups.models import RequestGraphQLQueryGroupUpdate
7
- from infrahub.services import services
7
+ from infrahub.services import InfrahubServices
8
8
  from infrahub.workflows.utils import add_tags
9
9
 
10
10
 
11
11
  @flow(name="graphql-query-group-update", flow_run_name="Update GraphQLQuery Group '{model.query_name}'")
12
- async def update_graphql_query_group(model: RequestGraphQLQueryGroupUpdate) -> None:
12
+ async def update_graphql_query_group(model: RequestGraphQLQueryGroupUpdate, service: InfrahubServices) -> None:
13
13
  """Create or Update a GraphQLQueryGroup."""
14
14
 
15
15
  # If there is only one subscriber, associate the task to it
@@ -19,7 +19,6 @@ async def update_graphql_query_group(model: RequestGraphQLQueryGroupUpdate) -> N
19
19
  related_nodes.append(model.subscribers[0])
20
20
 
21
21
  await add_tags(branches=[model.branch], nodes=related_nodes)
22
- service = services.service
23
22
 
24
23
  params_hash = dict_hash(model.params)
25
24
  group_name = f"{model.query_name}__{params_hash}"
infrahub/lock.py CHANGED
@@ -253,7 +253,7 @@ class InfrahubLockRegistry:
253
253
 
254
254
 
255
255
  def initialize_lock(local_only: bool = False, service: Optional[InfrahubServices] = None) -> None:
256
- global registry # pylint: disable=global-statement
256
+ global registry
257
257
  registry = InfrahubLockRegistry(local_only=local_only, service=service)
258
258
 
259
259