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
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
- from graphene import Field, Float, Int, List, ObjectType, String
5
+ from graphene import Field, Float, Int, List, NonNull, ObjectType, String
6
6
  from infrahub_sdk.utils import extract_fields_first_node
7
7
 
8
8
  from infrahub.core import registry
@@ -21,8 +21,10 @@ from infrahub.pools.number import NumberUtilizationGetter
21
21
  if TYPE_CHECKING:
22
22
  from graphql import GraphQLResolveInfo
23
23
 
24
+ from infrahub.core.branch import Branch
24
25
  from infrahub.core.node import Node
25
26
  from infrahub.core.protocols import CoreNode
27
+ from infrahub.core.timestamp import Timestamp
26
28
  from infrahub.database import InfrahubDatabase
27
29
  from infrahub.graphql.initialization import GraphqlContext
28
30
 
@@ -69,19 +71,21 @@ def _validate_pool_type(pool_id: str, pool: CoreNode | None = None) -> CoreNode:
69
71
 
70
72
  class PoolAllocated(ObjectType):
71
73
  count = Field(Int, required=True, description="The number of allocations within the selected pool.")
72
- edges = Field(List(of_type=PoolAllocatedEdge, required=True), required=True)
74
+ edges = Field(List(of_type=NonNull(PoolAllocatedEdge), required=True), required=True)
73
75
 
74
76
  @staticmethod
75
- async def resolve( # pylint: disable=unused-argument
76
- root: dict,
77
+ async def resolve(
78
+ root: dict, # noqa: ARG004
77
79
  info: GraphQLResolveInfo,
78
80
  pool_id: str,
79
81
  resource_id: str,
80
82
  offset: int = 0,
81
83
  limit: int = 10,
82
84
  ) -> dict:
83
- context: GraphqlContext = info.context
84
- pool: CoreNode | None = await NodeManager.get_one(id=pool_id, db=context.db, branch=context.branch)
85
+ graphql_context: GraphqlContext = info.context
86
+ pool: CoreNode | None = await NodeManager.get_one(
87
+ id=pool_id, db=graphql_context.db, branch=graphql_context.branch
88
+ )
85
89
 
86
90
  fields = await extract_fields_first_node(info=info)
87
91
 
@@ -90,14 +94,19 @@ class PoolAllocated(ObjectType):
90
94
  match pool.get_kind():
91
95
  case InfrahubKind.NUMBERPOOL:
92
96
  return await resolve_number_pool_allocation(
93
- db=context.db, context=context, pool=pool, fields=fields, offset=offset, limit=limit
97
+ db=graphql_context.db,
98
+ graphql_context=graphql_context,
99
+ pool=pool,
100
+ fields=fields,
101
+ offset=offset,
102
+ limit=limit,
94
103
  )
95
104
  case InfrahubKind.IPPREFIXPOOL:
96
105
  allocated_kinds.append(InfrahubKind.IPPREFIX)
97
106
  case InfrahubKind.IPADDRESSPOOL:
98
107
  allocated_kinds.append(InfrahubKind.IPADDRESS)
99
108
 
100
- resources = await pool.resources.get_peers(db=context.db) # type: ignore[attr-defined,union-attr]
109
+ resources = await pool.resources.get_peers(db=graphql_context.db) # type: ignore[attr-defined,union-attr]
101
110
  if resource_id not in resources:
102
111
  raise ValidationError(
103
112
  input_value=f"The selected pool_id={pool_id} doesn't contain the requested resource_id={resource_id}"
@@ -106,8 +115,8 @@ class PoolAllocated(ObjectType):
106
115
  resource = resources[resource_id]
107
116
 
108
117
  query = await IPPrefixUtilization.init(
109
- db=context.db,
110
- at=context.at,
118
+ db=graphql_context.db,
119
+ at=graphql_context.at,
111
120
  ip_prefixes=[resource],
112
121
  allocated_kinds=allocated_kinds,
113
122
  offset=offset,
@@ -115,10 +124,10 @@ class PoolAllocated(ObjectType):
115
124
  )
116
125
  response: dict[str, Any] = {}
117
126
  if "count" in fields:
118
- response["count"] = await query.count(db=context.db)
127
+ response["count"] = await query.count(db=graphql_context.db)
119
128
 
120
129
  if edges := fields.get("edges"):
121
- await query.execute(db=context.db)
130
+ await query.execute(db=graphql_context.db)
122
131
 
123
132
  node_fields = edges.get("node", {})
124
133
 
@@ -146,9 +155,9 @@ class PoolAllocated(ObjectType):
146
155
  if not identifier_query_class:
147
156
  raise ValidationError(input_value=f"This query doesn't get support {pool.get_kind()}")
148
157
  identifier_query = await identifier_query_class.init(
149
- db=context.db, at=context.at, pool_id=pool_id, allocated=allocated_ids
158
+ db=graphql_context.db, at=graphql_context.at, pool_id=pool_id, allocated=allocated_ids
150
159
  )
151
- await identifier_query.execute(db=context.db)
160
+ await identifier_query.execute(db=graphql_context.db)
152
161
 
153
162
  reservations = {}
154
163
  for result in identifier_query.get_results():
@@ -171,20 +180,22 @@ class PoolUtilization(ObjectType):
171
180
  utilization_default_branch = Field(
172
181
  Float, required=True, description="The overall utilization of the pool isolated to the default branch."
173
182
  )
174
- edges = Field(List(of_type=IPPrefixUtilizationEdge, required=True), required=True)
183
+ edges = Field(List(of_type=NonNull(IPPrefixUtilizationEdge), required=True), required=True)
175
184
 
176
185
  @staticmethod
177
- async def resolve( # pylint: disable=unused-argument,too-many-branches
178
- root: dict,
186
+ async def resolve(
187
+ root: dict, # noqa: ARG004
179
188
  info: GraphQLResolveInfo,
180
189
  pool_id: str,
181
190
  ) -> dict:
182
- context: GraphqlContext = info.context
183
- db: InfrahubDatabase = context.db
184
- pool: CoreNode | None = await NodeManager.get_one(id=pool_id, db=db, branch=context.branch)
191
+ graphql_context: GraphqlContext = info.context
192
+ db: InfrahubDatabase = graphql_context.db
193
+ pool: CoreNode | None = await NodeManager.get_one(id=pool_id, db=db, branch=graphql_context.branch)
185
194
  pool = _validate_pool_type(pool_id=pool_id, pool=pool)
186
195
  if pool.get_kind() == "CoreNumberPool":
187
- return await resolve_number_pool_utilization(db=db, context=context, pool=pool)
196
+ return await resolve_number_pool_utilization(
197
+ db=db, at=graphql_context.at, pool=pool, branch=graphql_context.branch
198
+ )
188
199
 
189
200
  resources_map: dict[str, Node] = {}
190
201
 
@@ -193,7 +204,9 @@ class PoolUtilization(ObjectType):
193
204
  except SchemaNotFoundError:
194
205
  pass
195
206
 
196
- utilization_getter = PrefixUtilizationGetter(db=db, ip_prefixes=list(resources_map.values()), at=context.at)
207
+ utilization_getter = PrefixUtilizationGetter(
208
+ db=db, ip_prefixes=list(resources_map.values()), at=graphql_context.at
209
+ )
197
210
  fields = await extract_fields_first_node(info=info)
198
211
  response: dict[str, Any] = {}
199
212
  total_utilization = None
@@ -262,11 +275,11 @@ class PoolUtilization(ObjectType):
262
275
 
263
276
 
264
277
  async def resolve_number_pool_allocation(
265
- db: InfrahubDatabase, context: GraphqlContext, pool: CoreNode, fields: dict, offset: int, limit: int
278
+ db: InfrahubDatabase, graphql_context: GraphqlContext, pool: CoreNode, fields: dict, offset: int, limit: int
266
279
  ) -> dict:
267
280
  response: dict[str, Any] = {}
268
281
  query = await NumberPoolGetAllocated.init(
269
- db=db, pool=pool, offset=offset, limit=limit, branch=context.branch, branch_agnostic=True
282
+ db=db, pool=pool, offset=offset, limit=limit, branch=graphql_context.branch, branch_agnostic=True
270
283
  )
271
284
 
272
285
  if "count" in fields:
@@ -290,8 +303,10 @@ async def resolve_number_pool_allocation(
290
303
  return response
291
304
 
292
305
 
293
- async def resolve_number_pool_utilization(db: InfrahubDatabase, context: GraphqlContext, pool: CoreNode) -> dict:
294
- number_pool = NumberUtilizationGetter(db=db, pool=pool, at=context.at, branch=context.branch)
306
+ async def resolve_number_pool_utilization(
307
+ db: InfrahubDatabase, pool: CoreNode, at: Timestamp | str | None, branch: Branch
308
+ ) -> dict:
309
+ number_pool = NumberUtilizationGetter(db=db, pool=pool, at=at, branch=branch)
295
310
  await number_pool.load_data()
296
311
 
297
312
  return {
@@ -322,9 +337,10 @@ InfrahubResourcePoolAllocated = Field(
322
337
  limit=Int(required=False),
323
338
  offset=Int(required=False),
324
339
  resolver=PoolAllocated.resolve,
340
+ required=True,
325
341
  )
326
342
 
327
343
 
328
344
  InfrahubResourcePoolUtilization = Field(
329
- PoolUtilization, pool_id=String(required=True), resolver=PoolUtilization.resolve
345
+ PoolUtilization, pool_id=String(required=True), resolver=PoolUtilization.resolve, required=True
330
346
  )
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import ipaddress
4
4
  from typing import TYPE_CHECKING, Any, Optional
5
5
 
6
- from graphene import Boolean, Field, Int, List, ObjectType, String
6
+ from graphene import Boolean, Field, Int, List, NonNull, ObjectType, String
7
7
  from infrahub_sdk.utils import extract_fields_first_node, is_valid_uuid
8
8
 
9
9
  from infrahub.core.constants import InfrahubKind
@@ -27,7 +27,7 @@ class NodeEdge(ObjectType):
27
27
 
28
28
  class NodeEdges(ObjectType):
29
29
  count = Field(Int, required=True)
30
- edges = Field(List(of_type=NodeEdge, required=True), required=False)
30
+ edges = Field(List(of_type=NonNull(NodeEdge)), required=True)
31
31
 
32
32
 
33
33
  def _collapse_ipv6(s: str) -> str:
@@ -97,13 +97,13 @@ def _collapse_ipv6(s: str) -> str:
97
97
 
98
98
 
99
99
  async def search_resolver(
100
- root: dict, # pylint: disable=unused-argument
100
+ root: dict, # noqa: ARG001
101
101
  info: GraphQLResolveInfo,
102
102
  q: str,
103
103
  limit: int = 10,
104
104
  partial_match: bool = True,
105
105
  ) -> dict[str, Any]:
106
- context: GraphqlContext = info.context
106
+ graphql_context: GraphqlContext = info.context
107
107
  response: dict[str, Any] = {}
108
108
  results: list[CoreNode] = []
109
109
 
@@ -111,7 +111,7 @@ async def search_resolver(
111
111
 
112
112
  if is_valid_uuid(q):
113
113
  matching: Optional[CoreNode] = await NodeManager.get_one(
114
- db=context.db, branch=context.branch, at=context.at, id=q
114
+ db=graphql_context.db, branch=graphql_context.branch, at=graphql_context.at, id=q
115
115
  )
116
116
  if matching:
117
117
  results.append(matching)
@@ -124,8 +124,8 @@ async def search_resolver(
124
124
 
125
125
  for kind in [InfrahubKind.NODE, InfrahubKind.GENERICGROUP]:
126
126
  objs = await NodeManager.query(
127
- db=context.db,
128
- branch=context.branch,
127
+ db=graphql_context.db,
128
+ branch=graphql_context.branch,
129
129
  schema=kind,
130
130
  filters={"any__value": q},
131
131
  limit=limit,
@@ -133,7 +133,7 @@ async def search_resolver(
133
133
  )
134
134
  results.extend(objs)
135
135
 
136
- if "edges" in fields and len(results) > 0:
136
+ if "edges" in fields:
137
137
  response["edges"] = [{"node": {"id": obj.id, "kind": obj.get_kind()}} for obj in results]
138
138
 
139
139
  if "count" in fields:
@@ -148,4 +148,5 @@ InfrahubSearchAnywhere = Field(
148
148
  limit=Int(required=False),
149
149
  partial_match=Boolean(required=False),
150
150
  resolver=search_resolver,
151
+ required=True,
151
152
  )
@@ -2,11 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
- from graphene import Boolean, Field, List, ObjectType, String
5
+ from graphene import Boolean, Field, List, NonNull, ObjectType, String
6
6
  from infrahub_sdk.utils import extract_fields_first_node
7
7
 
8
- from infrahub.services import services
9
-
10
8
  if TYPE_CHECKING:
11
9
  from graphql import GraphQLResolveInfo
12
10
 
@@ -30,7 +28,7 @@ class StatusWorkerEdge(ObjectType):
30
28
 
31
29
 
32
30
  class StatusWorkerEdges(ObjectType):
33
- edges = Field(List(of_type=StatusWorkerEdge, required=True), required=True)
31
+ edges = Field(List(of_type=NonNull(StatusWorkerEdge), required=True), required=True)
34
32
 
35
33
 
36
34
  class Status(ObjectType):
@@ -39,15 +37,18 @@ class Status(ObjectType):
39
37
 
40
38
 
41
39
  async def resolve_status(
42
- root: dict, # pylint: disable=unused-argument
40
+ root: dict, # noqa: ARG001
43
41
  info: GraphQLResolveInfo,
44
42
  ) -> dict:
45
- context: GraphqlContext = info.context
46
- service = context.service or services.service
43
+ graphql_context: GraphqlContext = info.context
44
+ service = graphql_context.service
45
+ if service is None:
46
+ raise ValueError("GraphqlContext.service is None")
47
+
47
48
  fields = await extract_fields_first_node(info)
48
49
  response: dict[str, Any] = {}
49
50
  workers = await service.component.list_workers(
50
- branch=str(context.branch.uuid) or context.branch.name, schema_hash=True
51
+ branch=str(graphql_context.branch.uuid) or graphql_context.branch.name, schema_hash=True
51
52
  )
52
53
 
53
54
  if summary := fields.get("summary"):
@@ -63,4 +64,6 @@ async def resolve_status(
63
64
  return response
64
65
 
65
66
 
66
- InfrahubStatus = Field(Status, resolver=resolve_status)
67
+ InfrahubStatus = Field(
68
+ Status, description="Retrieve the status of all infrahub workers.", resolver=resolve_status, required=True
69
+ )
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
- from graphene import Field, Int, List, ObjectType, String
5
+ from graphene import Field, Int, List, NonNull, ObjectType, String
6
6
  from infrahub_sdk.utils import extract_fields_first_node
7
7
  from prefect.client.schemas.objects import StateType
8
8
 
@@ -17,12 +17,12 @@ if TYPE_CHECKING:
17
17
 
18
18
 
19
19
  class Tasks(ObjectType):
20
- edges = List(TaskNodes)
21
- count = Int()
20
+ edges = List(NonNull(TaskNodes), required=True)
21
+ count = Int(required=True)
22
22
 
23
23
  @staticmethod
24
24
  async def resolve(
25
- root: dict, # pylint: disable=unused-argument
25
+ root: dict, # noqa: ARG004
26
26
  info: GraphQLResolveInfo,
27
27
  limit: int = 10,
28
28
  offset: int = 0,
@@ -49,7 +49,7 @@ class Tasks(ObjectType):
49
49
 
50
50
  @staticmethod
51
51
  async def resolve_branch_status(
52
- root: dict, # pylint: disable=unused-argument
52
+ root: dict, # noqa: ARG004
53
53
  info: GraphQLResolveInfo,
54
54
  branch: str,
55
55
  ) -> dict[str, Any]:
@@ -72,11 +72,11 @@ class Tasks(ObjectType):
72
72
  limit: int | None = None,
73
73
  offset: int | None = None,
74
74
  ) -> dict[str, Any]:
75
- context: GraphqlContext = info.context
75
+ graphql_context: GraphqlContext = info.context
76
76
  fields = await extract_fields_first_node(info)
77
77
 
78
78
  prefect_tasks = await PrefectTask.query(
79
- db=context.db,
79
+ db=graphql_context.db,
80
80
  fields=fields,
81
81
  q=q,
82
82
  ids=ids,
@@ -97,7 +97,6 @@ class Tasks(ObjectType):
97
97
 
98
98
  Task = Field(
99
99
  Tasks,
100
- resolver=Tasks.resolve,
101
100
  limit=Int(required=False),
102
101
  offset=Int(required=False),
103
102
  related_node__ids=List(String),
@@ -106,11 +105,14 @@ Task = Field(
106
105
  workflow=List(String),
107
106
  ids=List(String),
108
107
  q=String(required=False),
108
+ resolver=Tasks.resolve,
109
+ required=True,
109
110
  )
110
111
 
111
112
  TaskBranchStatus = Field(
112
113
  Tasks,
113
- resolver=Tasks.resolve_branch_status,
114
114
  branch=String(required=False),
115
115
  description="Return the list of all pending or running tasks that can modify the data, for a given branch",
116
+ resolver=Tasks.resolve_branch_status,
117
+ required=True,
116
118
  )
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any, Optional
4
4
 
5
+ from graphql.type.definition import GraphQLNonNull
5
6
  from infrahub_sdk.utils import extract_fields
6
7
 
7
8
  from infrahub.core.constants import BranchSupportType, InfrahubKind, RelationshipHierarchyDirection
@@ -17,21 +18,21 @@ from ..types import RELATIONS_PROPERTY_MAP, RELATIONS_PROPERTY_MAP_REVERSED
17
18
  if TYPE_CHECKING:
18
19
  from graphql import GraphQLResolveInfo
19
20
 
20
- from infrahub.core.schema import MainSchemaTypes, NodeSchema
21
+ from infrahub.core.schema import NodeSchema
21
22
  from infrahub.graphql.initialization import GraphqlContext
22
23
 
23
24
 
24
25
  async def account_resolver(
25
- root: dict, # pylint: disable=unused-argument
26
+ root: dict, # noqa: ARG001
26
27
  info: GraphQLResolveInfo,
27
28
  ) -> dict:
28
29
  fields = await extract_fields(info.field_nodes[0].selection_set)
29
- context: GraphqlContext = info.context
30
+ graphql_context: GraphqlContext = info.context
30
31
 
31
- async with context.db.start_session() as db:
32
+ async with graphql_context.db.start_session() as db:
32
33
  results = await NodeManager.query(
33
34
  schema=InfrahubKind.GENERICACCOUNT,
34
- filters={"ids": [context.account_session.account_id]},
35
+ filters={"ids": [graphql_context.account_session.account_id]},
35
36
  fields=fields,
36
37
  db=db,
37
38
  order=OrderModel(disable=True),
@@ -40,7 +41,9 @@ async def account_resolver(
40
41
  account_profile = await results[0].to_graphql(db=db, fields=fields)
41
42
  return account_profile
42
43
 
43
- raise NodeNotFoundError(node_type=InfrahubKind.GENERICACCOUNT, identifier=context.account_session.account_id)
44
+ raise NodeNotFoundError(
45
+ node_type=InfrahubKind.GENERICACCOUNT, identifier=graphql_context.account_session.account_id
46
+ )
44
47
 
45
48
 
46
49
  async def default_resolver(*args: Any, **kwargs) -> dict | list[dict] | None:
@@ -72,14 +75,18 @@ async def default_resolver(*args: Any, **kwargs) -> dict | list[dict] | None:
72
75
  raise ValueError(f"expected either 2 or 4 args for default_resolver, got {len(args)}")
73
76
 
74
77
  # Extract the InfraHub schema by inspecting the GQL Schema
75
- node_schema: NodeSchema = info.parent_type.graphene_type._meta.schema
78
+ node_schema: NodeSchema = (
79
+ info.parent_type.of_type.graphene_type._meta.schema
80
+ if isinstance(info.parent_type, GraphQLNonNull)
81
+ else info.parent_type.graphene_type._meta.schema
82
+ )
76
83
 
77
84
  # If the field is an attribute, return its value directly
78
85
  if field_name not in node_schema.relationship_names:
79
86
  return parent.get(field_name, None)
80
87
 
81
88
  # Extract the contextual information from the request context
82
- context: GraphqlContext = info.context
89
+ graphql_context: GraphqlContext = info.context
83
90
 
84
91
  # Extract the name of the fields in the GQL query
85
92
  fields = await extract_fields(info.field_nodes[0].selection_set)
@@ -94,7 +101,7 @@ async def default_resolver(*args: Any, **kwargs) -> dict | list[dict] | None:
94
101
  if "__" in key and value or key in ["id", "ids"]
95
102
  }
96
103
 
97
- async with context.db.start_session() as db:
104
+ async with graphql_context.db.start_session() as db:
98
105
  objs = await NodeManager.query_peers(
99
106
  db=db,
100
107
  ids=[parent["id"]],
@@ -102,22 +109,23 @@ async def default_resolver(*args: Any, **kwargs) -> dict | list[dict] | None:
102
109
  schema=node_rel,
103
110
  filters=filters,
104
111
  fields=fields,
105
- at=context.at,
106
- branch=context.branch,
112
+ at=graphql_context.at,
113
+ branch=graphql_context.branch,
107
114
  branch_agnostic=node_rel.branch is BranchSupportType.AGNOSTIC,
108
115
  fetch_peers=True,
109
116
  )
110
117
 
111
118
  if node_rel.cardinality == "many":
112
119
  return [
113
- await obj.to_graphql(db=db, fields=fields, related_node_ids=context.related_node_ids) for obj in objs
120
+ await obj.to_graphql(db=db, fields=fields, related_node_ids=graphql_context.related_node_ids)
121
+ for obj in objs
114
122
  ]
115
123
 
116
124
  # If cardinality is one
117
125
  if not objs:
118
126
  return None
119
127
 
120
- return await objs[0].to_graphql(db=db, fields=fields, related_node_ids=context.related_node_ids)
128
+ return await objs[0].to_graphql(db=db, fields=fields, related_node_ids=graphql_context.related_node_ids)
121
129
 
122
130
 
123
131
  async def parent_field_name_resolver(parent: dict[str, dict], info: GraphQLResolveInfo) -> dict:
@@ -130,7 +138,7 @@ async def parent_field_name_resolver(parent: dict[str, dict], info: GraphQLResol
130
138
 
131
139
 
132
140
  async def default_paginated_list_resolver(
133
- root: dict, # pylint: disable=unused-argument
141
+ root: dict, # noqa: ARG001
134
142
  info: GraphQLResolveInfo,
135
143
  offset: int | None = None,
136
144
  limit: int | None = None,
@@ -138,11 +146,16 @@ async def default_paginated_list_resolver(
138
146
  partial_match: bool = False,
139
147
  **kwargs: dict[str, Any],
140
148
  ) -> dict[str, Any]:
141
- schema: MainSchemaTypes = info.return_type.graphene_type._meta.schema
149
+ schema: NodeSchema = (
150
+ info.return_type.of_type.graphene_type._meta.schema
151
+ if isinstance(info.return_type, GraphQLNonNull)
152
+ else info.return_type.graphene_type._meta.schema
153
+ )
154
+
142
155
  fields = await extract_selection(info.field_nodes[0], schema=schema)
143
156
 
144
- context: GraphqlContext = info.context
145
- async with context.db.start_session() as db:
157
+ graphql_context: GraphqlContext = info.context
158
+ async with graphql_context.db.start_session() as db:
146
159
  response: dict[str, Any] = {"edges": []}
147
160
  filters = {
148
161
  key: value for key, value in kwargs.items() if ("__" in key and value is not None) or key in ("ids", "hfid")
@@ -152,7 +165,11 @@ async def default_paginated_list_resolver(
152
165
  node_fields = edges.get("node", {})
153
166
 
154
167
  permission_set: Optional[dict[str, Any]] = None
155
- permissions = await get_permissions(schema=schema, context=context) if context.permissions else None
168
+ permissions = (
169
+ await get_permissions(schema=schema, graphql_context=graphql_context)
170
+ if graphql_context.permissions
171
+ else None
172
+ )
156
173
  if fields.get("permissions"):
157
174
  response["permissions"] = permissions
158
175
 
@@ -168,11 +185,11 @@ async def default_paginated_list_resolver(
168
185
  schema=schema,
169
186
  filters=filters or None,
170
187
  fields=node_fields,
171
- at=context.at,
172
- branch=context.branch,
188
+ at=graphql_context.at,
189
+ branch=graphql_context.branch,
173
190
  limit=limit,
174
191
  offset=offset,
175
- account=context.account_session,
192
+ account=graphql_context.account_session,
176
193
  include_source=True,
177
194
  include_owner=True,
178
195
  partial_match=partial_match,
@@ -187,8 +204,8 @@ async def default_paginated_list_resolver(
187
204
  db=db,
188
205
  schema=schema,
189
206
  filters=filters,
190
- at=context.at,
191
- branch=context.branch,
207
+ at=graphql_context.at,
208
+ branch=graphql_context.branch,
192
209
  partial_match=partial_match,
193
210
  )
194
211
 
@@ -199,7 +216,7 @@ async def default_paginated_list_resolver(
199
216
  "node": await obj.to_graphql(
200
217
  db=db,
201
218
  fields=node_fields,
202
- related_node_ids=context.related_node_ids,
219
+ related_node_ids=graphql_context.related_node_ids,
203
220
  permissions=permission_set,
204
221
  )
205
222
  }
@@ -211,8 +228,8 @@ async def default_paginated_list_resolver(
211
228
 
212
229
 
213
230
  async def single_relationship_resolver(parent: dict, info: GraphQLResolveInfo, **kwargs: Any) -> dict[str, Any]:
214
- context: GraphqlContext = info.context
215
- resolver = context.single_relationship_resolver
231
+ graphql_context: GraphqlContext = info.context
232
+ resolver = graphql_context.single_relationship_resolver
216
233
  return await resolver.resolve(parent=parent, info=info, **kwargs)
217
234
 
218
235
 
@@ -225,9 +242,13 @@ async def many_relationship_resolver(
225
242
  fields by only reusing information below the 'node' key.
226
243
  """
227
244
  # Extract the InfraHub schema by inspecting the GQL Schema
228
- node_schema: NodeSchema = info.parent_type.graphene_type._meta.schema
245
+ node_schema: NodeSchema = (
246
+ info.parent_type.of_type.graphene_type._meta.schema
247
+ if isinstance(info.parent_type, GraphQLNonNull)
248
+ else info.parent_type.graphene_type._meta.schema
249
+ )
229
250
 
230
- context: GraphqlContext = info.context
251
+ graphql_context: GraphqlContext = info.context
231
252
 
232
253
  # Extract the name of the fields in the GQL query
233
254
  fields = await extract_fields(info.field_nodes[0].selection_set)
@@ -255,7 +276,7 @@ async def many_relationship_resolver(
255
276
 
256
277
  source_kind = node_schema.kind
257
278
 
258
- async with context.db.start_session() as db:
279
+ async with graphql_context.db.start_session() as db:
259
280
  ids = [parent["id"]]
260
281
  if include_descendants:
261
282
  query = await NodeGetHierarchyQuery.init(
@@ -263,8 +284,8 @@ async def many_relationship_resolver(
263
284
  direction=RelationshipHierarchyDirection.DESCENDANTS,
264
285
  node_id=parent["id"],
265
286
  node_schema=node_schema,
266
- at=context.at,
267
- branch=context.branch,
287
+ at=graphql_context.at,
288
+ branch=graphql_context.branch,
268
289
  )
269
290
  if node_schema.hierarchy:
270
291
  source_kind = node_schema.hierarchy
@@ -279,8 +300,8 @@ async def many_relationship_resolver(
279
300
  source_kind=source_kind,
280
301
  schema=node_rel,
281
302
  filters=filters,
282
- at=context.at,
283
- branch=context.branch,
303
+ at=graphql_context.at,
304
+ branch=graphql_context.branch,
284
305
  branch_agnostic=node_rel.branch is BranchSupportType.AGNOSTIC,
285
306
  )
286
307
 
@@ -296,8 +317,8 @@ async def many_relationship_resolver(
296
317
  fields=node_fields,
297
318
  offset=offset,
298
319
  limit=limit,
299
- at=context.at,
300
- branch=context.branch,
320
+ at=graphql_context.at,
321
+ branch=graphql_context.branch,
301
322
  branch_agnostic=node_rel.branch is BranchSupportType.AGNOSTIC,
302
323
  fetch_peers=True,
303
324
  )
@@ -305,7 +326,8 @@ async def many_relationship_resolver(
305
326
  if not objs:
306
327
  return response
307
328
  node_graph = [
308
- await obj.to_graphql(db=db, fields=node_fields, related_node_ids=context.related_node_ids) for obj in objs
329
+ await obj.to_graphql(db=db, fields=node_fields, related_node_ids=graphql_context.related_node_ids)
330
+ for obj in objs
309
331
  ]
310
332
 
311
333
  entries = []
@@ -343,9 +365,13 @@ async def hierarchy_resolver(
343
365
  fields by only reusing information below the 'node' key.
344
366
  """
345
367
  # Extract the InfraHub schema by inspecting the GQL Schema
346
- node_schema: NodeSchema = info.parent_type.graphene_type._meta.schema
368
+ node_schema: NodeSchema = (
369
+ info.parent_type.of_type.graphene_type._meta.schema
370
+ if isinstance(info.parent_type, GraphQLNonNull)
371
+ else info.parent_type.graphene_type._meta.schema
372
+ )
347
373
 
348
- context: GraphqlContext = info.context
374
+ graphql_context: GraphqlContext = info.context
349
375
 
350
376
  # Extract the name of the fields in the GQL query
351
377
  fields = await extract_fields(info.field_nodes[0].selection_set)
@@ -364,7 +390,7 @@ async def hierarchy_resolver(
364
390
 
365
391
  response: dict[str, Any] = {"edges": [], "count": None}
366
392
 
367
- async with context.db.start_session() as db:
393
+ async with graphql_context.db.start_session() as db:
368
394
  if "count" in fields:
369
395
  response["count"] = await NodeManager.count_hierarchy(
370
396
  db=db,
@@ -372,8 +398,8 @@ async def hierarchy_resolver(
372
398
  direction=direction,
373
399
  node_schema=node_schema,
374
400
  filters=filters,
375
- at=context.at,
376
- branch=context.branch,
401
+ at=graphql_context.at,
402
+ branch=graphql_context.branch,
377
403
  )
378
404
 
379
405
  if not node_fields:
@@ -388,8 +414,8 @@ async def hierarchy_resolver(
388
414
  fields=node_fields,
389
415
  offset=offset,
390
416
  limit=limit,
391
- at=context.at,
392
- branch=context.branch,
417
+ at=graphql_context.at,
418
+ branch=graphql_context.branch,
393
419
  )
394
420
 
395
421
  if not objs: