django-graphex 1.0.0__tar.gz

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 (231) hide show
  1. django_graphex-1.0.0/.github/workflows/cicd.yaml +358 -0
  2. django_graphex-1.0.0/.github/workflows/docs.yml +61 -0
  3. django_graphex-1.0.0/.gitignore +184 -0
  4. django_graphex-1.0.0/.pre-commit-config.yaml +51 -0
  5. django_graphex-1.0.0/LICENSE +21 -0
  6. django_graphex-1.0.0/MANIFEST.in +3 -0
  7. django_graphex-1.0.0/Makefile +81 -0
  8. django_graphex-1.0.0/PKG-INFO +176 -0
  9. django_graphex-1.0.0/README.md +139 -0
  10. django_graphex-1.0.0/django_graphex/__init__.py +88 -0
  11. django_graphex-1.0.0/django_graphex/_compat.py +105 -0
  12. django_graphex-1.0.0/django_graphex/_graphene_settings.py +140 -0
  13. django_graphex-1.0.0/django_graphex/backends.py +124 -0
  14. django_graphex-1.0.0/django_graphex/base_types.py +318 -0
  15. django_graphex-1.0.0/django_graphex/converter.py +989 -0
  16. django_graphex-1.0.0/django_graphex/cost.py +345 -0
  17. django_graphex-1.0.0/django_graphex/directives/__init__.py +72 -0
  18. django_graphex-1.0.0/django_graphex/directives/base.py +50 -0
  19. django_graphex-1.0.0/django_graphex/directives/date.py +361 -0
  20. django_graphex-1.0.0/django_graphex/directives/list.py +137 -0
  21. django_graphex-1.0.0/django_graphex/directives/numbers.py +178 -0
  22. django_graphex-1.0.0/django_graphex/directives/string.py +647 -0
  23. django_graphex-1.0.0/django_graphex/fields.py +611 -0
  24. django_graphex-1.0.0/django_graphex/filtering/__init__.py +41 -0
  25. django_graphex-1.0.0/django_graphex/filtering/backend.py +112 -0
  26. django_graphex-1.0.0/django_graphex/filtering/lookups.py +141 -0
  27. django_graphex-1.0.0/django_graphex/filtering/schema.py +309 -0
  28. django_graphex-1.0.0/django_graphex/filtering/translate.py +197 -0
  29. django_graphex-1.0.0/django_graphex/middleware.py +81 -0
  30. django_graphex-1.0.0/django_graphex/mutation.py +419 -0
  31. django_graphex-1.0.0/django_graphex/native/__init__.py +1 -0
  32. django_graphex-1.0.0/django_graphex/native/backend.py +204 -0
  33. django_graphex-1.0.0/django_graphex/native/fields.py +207 -0
  34. django_graphex-1.0.0/django_graphex/native/validators.py +135 -0
  35. django_graphex-1.0.0/django_graphex/nested.py +272 -0
  36. django_graphex-1.0.0/django_graphex/paginations/__init__.py +15 -0
  37. django_graphex-1.0.0/django_graphex/paginations/pagination.py +782 -0
  38. django_graphex-1.0.0/django_graphex/paginations/utils.py +161 -0
  39. django_graphex-1.0.0/django_graphex/permissions.py +142 -0
  40. django_graphex-1.0.0/django_graphex/registry.py +158 -0
  41. django_graphex-1.0.0/django_graphex/schema.py +201 -0
  42. django_graphex-1.0.0/django_graphex/security.py +125 -0
  43. django_graphex-1.0.0/django_graphex/settings.py +155 -0
  44. django_graphex-1.0.0/django_graphex/subscriptions/__init__.py +40 -0
  45. django_graphex-1.0.0/django_graphex/subscriptions/_subscription_client.html +305 -0
  46. django_graphex-1.0.0/django_graphex/subscriptions/bindings.py +159 -0
  47. django_graphex-1.0.0/django_graphex/subscriptions/client.py +62 -0
  48. django_graphex-1.0.0/django_graphex/subscriptions/consumers.py +196 -0
  49. django_graphex-1.0.0/django_graphex/subscriptions/mixins.py +111 -0
  50. django_graphex-1.0.0/django_graphex/subscriptions/subscription.py +538 -0
  51. django_graphex-1.0.0/django_graphex/subscriptions/views.py +141 -0
  52. django_graphex-1.0.0/django_graphex/types.py +1261 -0
  53. django_graphex-1.0.0/django_graphex/utils.py +1051 -0
  54. django_graphex-1.0.0/django_graphex/validation.py +221 -0
  55. django_graphex-1.0.0/django_graphex/views.py +692 -0
  56. django_graphex-1.0.0/docs/api/directives.md +793 -0
  57. django_graphex-1.0.0/docs/api/fields.md +476 -0
  58. django_graphex-1.0.0/docs/api/mutations.md +514 -0
  59. django_graphex-1.0.0/docs/api/paginations.md +728 -0
  60. django_graphex-1.0.0/docs/api/types.md +678 -0
  61. django_graphex-1.0.0/docs/api/utils.md +578 -0
  62. django_graphex-1.0.0/docs/changelog.md +87 -0
  63. django_graphex-1.0.0/docs/contributing.md +356 -0
  64. django_graphex-1.0.0/docs/directives.md +690 -0
  65. django_graphex-1.0.0/docs/index.md +79 -0
  66. django_graphex-1.0.0/docs/installation.md +80 -0
  67. django_graphex-1.0.0/docs/migration.md +247 -0
  68. django_graphex-1.0.0/docs/quickstart.md +292 -0
  69. django_graphex-1.0.0/docs/usage/backends.md +125 -0
  70. django_graphex-1.0.0/docs/usage/examples/blog-schema.md +361 -0
  71. django_graphex-1.0.0/docs/usage/examples/directives.md +94 -0
  72. django_graphex-1.0.0/docs/usage/examples/frontend.md +328 -0
  73. django_graphex-1.0.0/docs/usage/examples/mutations.md +187 -0
  74. django_graphex-1.0.0/docs/usage/examples/performance.md +39 -0
  75. django_graphex-1.0.0/docs/usage/examples/queries.md +294 -0
  76. django_graphex-1.0.0/docs/usage/fields.md +266 -0
  77. django_graphex-1.0.0/docs/usage/filtering.md +262 -0
  78. django_graphex-1.0.0/docs/usage/mutations.md +534 -0
  79. django_graphex-1.0.0/docs/usage/nested-lists.md +194 -0
  80. django_graphex-1.0.0/docs/usage/pagination.md +711 -0
  81. django_graphex-1.0.0/docs/usage/permissions.md +114 -0
  82. django_graphex-1.0.0/docs/usage/query-limits.md +203 -0
  83. django_graphex-1.0.0/docs/usage/query-optimization.md +160 -0
  84. django_graphex-1.0.0/docs/usage/security.md +236 -0
  85. django_graphex-1.0.0/docs/usage/settings.md +104 -0
  86. django_graphex-1.0.0/docs/usage/subscriptions.md +473 -0
  87. django_graphex-1.0.0/docs/usage/types.md +598 -0
  88. django_graphex-1.0.0/docs/usage/views.md +83 -0
  89. django_graphex-1.0.0/examples/playground/.gitignore +7 -0
  90. django_graphex-1.0.0/examples/playground/Makefile +36 -0
  91. django_graphex-1.0.0/examples/playground/README.md +433 -0
  92. django_graphex-1.0.0/examples/playground/blog/__init__.py +0 -0
  93. django_graphex-1.0.0/examples/playground/blog/apps.py +6 -0
  94. django_graphex-1.0.0/examples/playground/blog/consumers.py +11 -0
  95. django_graphex-1.0.0/examples/playground/blog/management/__init__.py +0 -0
  96. django_graphex-1.0.0/examples/playground/blog/management/commands/__init__.py +0 -0
  97. django_graphex-1.0.0/examples/playground/blog/management/commands/seed.py +67 -0
  98. django_graphex-1.0.0/examples/playground/blog/migrations/__init__.py +0 -0
  99. django_graphex-1.0.0/examples/playground/blog/models.py +100 -0
  100. django_graphex-1.0.0/examples/playground/blog/schema.py +317 -0
  101. django_graphex-1.0.0/examples/playground/config/__init__.py +0 -0
  102. django_graphex-1.0.0/examples/playground/config/asgi.py +23 -0
  103. django_graphex-1.0.0/examples/playground/config/settings.py +103 -0
  104. django_graphex-1.0.0/examples/playground/config/urls.py +28 -0
  105. django_graphex-1.0.0/examples/playground/config/wsgi.py +9 -0
  106. django_graphex-1.0.0/examples/playground/manage.py +16 -0
  107. django_graphex-1.0.0/examples/playground/pyproject.toml +28 -0
  108. django_graphex-1.0.0/examples/playground/static/playground.txt +2 -0
  109. django_graphex-1.0.0/pyproject.toml +174 -0
  110. django_graphex-1.0.0/scripts/check_base_install.py +45 -0
  111. django_graphex-1.0.0/specs/README.md +11 -0
  112. django_graphex-1.0.0/specs/black-to-ruff-spec.md +82 -0
  113. django_graphex-1.0.0/specs/converter-choices-normalization-spec.md +97 -0
  114. django_graphex-1.0.0/specs/directives-spec.md +99 -0
  115. django_graphex-1.0.0/specs/drop-drf-spec.md +82 -0
  116. django_graphex-1.0.0/specs/error-messages-spec.md +67 -0
  117. django_graphex-1.0.0/specs/extra-schema-union-roots-spec.md +65 -0
  118. django_graphex-1.0.0/specs/field-resolver-honor-spec.md +111 -0
  119. django_graphex-1.0.0/specs/filters-id-spec.md +152 -0
  120. django_graphex-1.0.0/specs/model-rename-validators-spec.md +130 -0
  121. django_graphex-1.0.0/specs/native-backend-prior-art.md +68 -0
  122. django_graphex-1.0.0/specs/native-filtering-spec.md +221 -0
  123. django_graphex-1.0.0/specs/native-pydantic-backend-spec.md +109 -0
  124. django_graphex-1.0.0/specs/nested-filtered-prefetch-spec.md +130 -0
  125. django_graphex-1.0.0/specs/nested-list-shape-spec.md +172 -0
  126. django_graphex-1.0.0/specs/nested-objects-spec.md +142 -0
  127. django_graphex-1.0.0/specs/optimizer-nested-filtered-prefetch-spec.md +82 -0
  128. django_graphex-1.0.0/specs/pagination-default-none-fix-spec.md +48 -0
  129. django_graphex-1.0.0/specs/pagination-max-size-spec.md +119 -0
  130. django_graphex-1.0.0/specs/pagination-pageinfo-spec.md +200 -0
  131. django_graphex-1.0.0/specs/query-cost-analysis-spec.md +183 -0
  132. django_graphex-1.0.0/specs/query-depth-limit-spec.md +63 -0
  133. django_graphex-1.0.0/specs/queryset-optimization-spec.md +268 -0
  134. django_graphex-1.0.0/specs/registry-keys-spec.md +128 -0
  135. django_graphex-1.0.0/specs/remove-graphene-django-spec.md +93 -0
  136. django_graphex-1.0.0/specs/security-middleware-spec.md +227 -0
  137. django_graphex-1.0.0/specs/serialization-backend-analysis.md +179 -0
  138. django_graphex-1.0.0/specs/serializer-backend-seam-spec.md +131 -0
  139. django_graphex-1.0.0/specs/serializer-error-handling-spec.md +123 -0
  140. django_graphex-1.0.0/specs/serializer-permissions-spec.md +155 -0
  141. django_graphex-1.0.0/specs/serializer-queryset-hooks-spec.md +124 -0
  142. django_graphex-1.0.0/specs/serializer-type-custom-fields-spec.md +64 -0
  143. django_graphex-1.0.0/specs/serializer-type-subscription-auth-spec.md +79 -0
  144. django_graphex-1.0.0/specs/serializer-type-subscriptions-spec.md +62 -0
  145. django_graphex-1.0.0/specs/subscriptions-notification-filters-spec.md +86 -0
  146. django_graphex-1.0.0/specs/subscriptions-payload-spec.md +188 -0
  147. django_graphex-1.0.0/specs/subscriptions-spec.md +265 -0
  148. django_graphex-1.0.0/specs/v2-modernization-roadmap.md +22 -0
  149. django_graphex-1.0.0/specs/v2-polish-spec.md +54 -0
  150. django_graphex-1.0.0/specs/views-consolidation-spec.md +84 -0
  151. django_graphex-1.0.0/tests/__init__.py +0 -0
  152. django_graphex-1.0.0/tests/client.py +10 -0
  153. django_graphex-1.0.0/tests/conftest.py +117 -0
  154. django_graphex-1.0.0/tests/factories.py +17 -0
  155. django_graphex-1.0.0/tests/models.py +72 -0
  156. django_graphex-1.0.0/tests/queries.py +63 -0
  157. django_graphex-1.0.0/tests/schema.py +100 -0
  158. django_graphex-1.0.0/tests/subscriptions/__init__.py +0 -0
  159. django_graphex-1.0.0/tests/subscriptions/conftest.py +51 -0
  160. django_graphex-1.0.0/tests/subscriptions/helpers.py +12 -0
  161. django_graphex-1.0.0/tests/subscriptions/schema.py +39 -0
  162. django_graphex-1.0.0/tests/subscriptions/test_binding.py +69 -0
  163. django_graphex-1.0.0/tests/subscriptions/test_client.py +29 -0
  164. django_graphex-1.0.0/tests/subscriptions/test_consumer.py +91 -0
  165. django_graphex-1.0.0/tests/subscriptions/test_e2e.py +233 -0
  166. django_graphex-1.0.0/tests/subscriptions/test_indexed_groups.py +173 -0
  167. django_graphex-1.0.0/tests/subscriptions/test_isolation.py +115 -0
  168. django_graphex-1.0.0/tests/subscriptions/test_native.py +45 -0
  169. django_graphex-1.0.0/tests/subscriptions/test_payload.py +99 -0
  170. django_graphex-1.0.0/tests/subscriptions/test_resolver.py +106 -0
  171. django_graphex-1.0.0/tests/subscriptions/test_serializer_type.py +170 -0
  172. django_graphex-1.0.0/tests/subscriptions/test_unit.py +182 -0
  173. django_graphex-1.0.0/tests/subscriptions/test_view.py +143 -0
  174. django_graphex-1.0.0/tests/templates/custom_graphiql.html +1 -0
  175. django_graphex-1.0.0/tests/test_backends.py +49 -0
  176. django_graphex-1.0.0/tests/test_base_types.py +106 -0
  177. django_graphex-1.0.0/tests/test_base_types_internals.py +134 -0
  178. django_graphex-1.0.0/tests/test_converter.py +348 -0
  179. django_graphex-1.0.0/tests/test_converter_branches.py +351 -0
  180. django_graphex-1.0.0/tests/test_converter_choices.py +137 -0
  181. django_graphex-1.0.0/tests/test_converter_internals.py +170 -0
  182. django_graphex-1.0.0/tests/test_cost_edges.py +171 -0
  183. django_graphex-1.0.0/tests/test_cost_validation_edges.py +153 -0
  184. django_graphex-1.0.0/tests/test_depth_limit.py +156 -0
  185. django_graphex-1.0.0/tests/test_directives.py +221 -0
  186. django_graphex-1.0.0/tests/test_directives_internals.py +383 -0
  187. django_graphex-1.0.0/tests/test_error_messages.py +97 -0
  188. django_graphex-1.0.0/tests/test_field_resolver.py +104 -0
  189. django_graphex-1.0.0/tests/test_fields.py +162 -0
  190. django_graphex-1.0.0/tests/test_fields_resolvers.py +245 -0
  191. django_graphex-1.0.0/tests/test_filtering_internals.py +201 -0
  192. django_graphex-1.0.0/tests/test_filters_id.py +139 -0
  193. django_graphex-1.0.0/tests/test_inline_validators.py +138 -0
  194. django_graphex-1.0.0/tests/test_middleware.py +134 -0
  195. django_graphex-1.0.0/tests/test_mutation_edges.py +86 -0
  196. django_graphex-1.0.0/tests/test_mutations.py +366 -0
  197. django_graphex-1.0.0/tests/test_native_backend.py +248 -0
  198. django_graphex-1.0.0/tests/test_native_filtering.py +329 -0
  199. django_graphex-1.0.0/tests/test_native_internals.py +302 -0
  200. django_graphex-1.0.0/tests/test_nested_edges.py +121 -0
  201. django_graphex-1.0.0/tests/test_nested_lists.py +338 -0
  202. django_graphex-1.0.0/tests/test_nested_objects.py +138 -0
  203. django_graphex-1.0.0/tests/test_optimizer_coverage.py +689 -0
  204. django_graphex-1.0.0/tests/test_pagination_edges.py +177 -0
  205. django_graphex-1.0.0/tests/test_pagination_internals.py +214 -0
  206. django_graphex-1.0.0/tests/test_pagination_limits.py +84 -0
  207. django_graphex-1.0.0/tests/test_paginations.py +279 -0
  208. django_graphex-1.0.0/tests/test_permissions.py +149 -0
  209. django_graphex-1.0.0/tests/test_query_cost.py +226 -0
  210. django_graphex-1.0.0/tests/test_query_optimization.py +267 -0
  211. django_graphex-1.0.0/tests/test_registry.py +147 -0
  212. django_graphex-1.0.0/tests/test_security.py +310 -0
  213. django_graphex-1.0.0/tests/test_serializer_crud_edges.py +74 -0
  214. django_graphex-1.0.0/tests/test_serializer_queryset_hooks.py +91 -0
  215. django_graphex-1.0.0/tests/test_serializer_type_custom_fields.py +172 -0
  216. django_graphex-1.0.0/tests/test_settings.py +77 -0
  217. django_graphex-1.0.0/tests/test_settings_internals.py +73 -0
  218. django_graphex-1.0.0/tests/test_types.py +150 -0
  219. django_graphex-1.0.0/tests/test_types_internals.py +112 -0
  220. django_graphex-1.0.0/tests/test_utils.py +63 -0
  221. django_graphex-1.0.0/tests/test_utils_helpers.py +220 -0
  222. django_graphex-1.0.0/tests/test_validation_edges.py +106 -0
  223. django_graphex-1.0.0/tests/test_view_base.py +204 -0
  224. django_graphex-1.0.0/tests/test_views.py +220 -0
  225. django_graphex-1.0.0/tests/test_views_auth_graphiql.py +93 -0
  226. django_graphex-1.0.0/tests/test_views_branches.py +352 -0
  227. django_graphex-1.0.0/tests/test_views_extra.py +107 -0
  228. django_graphex-1.0.0/tests/urls.py +22 -0
  229. django_graphex-1.0.0/tox.ini +94 -0
  230. django_graphex-1.0.0/uv.lock +2068 -0
  231. django_graphex-1.0.0/zensical.yml +121 -0
@@ -0,0 +1,358 @@
1
+ name: Continuous Integration & Delivery
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ tags:
8
+ - 'v*.*.*'
9
+ pull_request:
10
+ branches:
11
+ - main
12
+ workflow_dispatch:
13
+ inputs:
14
+ repository:
15
+ description: "Choose repository to publish"
16
+ required: true
17
+ default: "testpypi"
18
+ type: choice
19
+ options:
20
+ - testpypi
21
+ - pypi
22
+
23
+ permissions:
24
+ contents: write
25
+ packages: write
26
+ pull-requests: read
27
+
28
+ jobs:
29
+ test:
30
+ runs-on: ubuntu-latest
31
+ strategy:
32
+ fail-fast: false
33
+ matrix:
34
+ include:
35
+ # Python 3.12 — Django floor is declared >=4.0 but CI tests from 4.2 (SPEC OQ2)
36
+ - python-version: '3.12'
37
+ toxenv: 'py312-django42'
38
+ - python-version: '3.12'
39
+ toxenv: 'py312-django50'
40
+ - python-version: '3.12'
41
+ toxenv: 'py312-django51'
42
+ - python-version: '3.12'
43
+ toxenv: 'py312-django52'
44
+ - python-version: '3.12'
45
+ toxenv: 'py312-django60'
46
+ # Python 3.13
47
+ - python-version: '3.13'
48
+ toxenv: 'py313-django42'
49
+ - python-version: '3.13'
50
+ toxenv: 'py313-django50'
51
+ - python-version: '3.13'
52
+ toxenv: 'py313-django51'
53
+ - python-version: '3.13'
54
+ toxenv: 'py313-django52'
55
+ - python-version: '3.13'
56
+ toxenv: 'py313-django60'
57
+ # Python 3.14
58
+ - python-version: '3.14-dev'
59
+ toxenv: 'py314-django42'
60
+ - python-version: '3.14-dev'
61
+ toxenv: 'py314-django50'
62
+ - python-version: '3.14-dev'
63
+ toxenv: 'py314-django51'
64
+ - python-version: '3.14-dev'
65
+ toxenv: 'py314-django52'
66
+ - python-version: '3.14-dev'
67
+ toxenv: 'py314-django60'
68
+
69
+ steps:
70
+ - name: Checkout code
71
+ uses: actions/checkout@v6
72
+
73
+ - name: Set up Python ${{ matrix.python-version }}
74
+ uses: actions/setup-python@v6
75
+ with:
76
+ python-version: ${{ matrix.python-version }}
77
+
78
+ - name: Install uv
79
+ uses: astral-sh/setup-uv@v7
80
+ with:
81
+ enable-cache: true
82
+
83
+ - name: Run tests
84
+ run: uvx --with tox-uv tox -e ${{ matrix.toxenv }}
85
+
86
+ - name: Upload test results
87
+ uses: actions/upload-artifact@v7
88
+ if: failure()
89
+ with:
90
+ name: test-results-${{ matrix.toxenv }}
91
+ path: .tox/*/log/
92
+
93
+ base-install:
94
+ # Proves the base install (no [subscriptions] extra) never imports channels.
95
+ runs-on: ubuntu-latest
96
+ steps:
97
+ - name: Checkout code
98
+ uses: actions/checkout@v6
99
+
100
+ - name: Set up Python
101
+ uses: actions/setup-python@v6
102
+ with:
103
+ python-version: '3.12'
104
+
105
+ - name: Install uv
106
+ uses: astral-sh/setup-uv@v7
107
+ with:
108
+ enable-cache: true
109
+
110
+ - name: Assert channels is absent without the extra
111
+ run: uvx --with tox-uv tox -e base-install
112
+
113
+ lint-and-security:
114
+ runs-on: ubuntu-latest
115
+ steps:
116
+ - name: Checkout code
117
+ uses: actions/checkout@v6
118
+
119
+ - name: Set up Python
120
+ uses: actions/setup-python@v6
121
+ with:
122
+ python-version: '3.12'
123
+
124
+ - name: Install uv
125
+ uses: astral-sh/setup-uv@v7
126
+ with:
127
+ enable-cache: true
128
+
129
+ - name: Run code quality checks
130
+ run: uvx --with tox-uv tox -e quality
131
+
132
+ - name: Run security checks
133
+ run: uvx --with tox-uv tox -e security
134
+
135
+ coverage:
136
+ runs-on: ubuntu-latest
137
+ steps:
138
+ - name: Checkout code
139
+ uses: actions/checkout@v6
140
+
141
+ - name: Set up Python
142
+ uses: actions/setup-python@v6
143
+ with:
144
+ python-version: '3.12'
145
+
146
+ - name: Install uv
147
+ uses: astral-sh/setup-uv@v7
148
+ with:
149
+ enable-cache: true
150
+
151
+ - name: Run tests with coverage
152
+ run: |
153
+ uv sync
154
+ uv run coverage run -m pytest
155
+ uv run coverage xml
156
+ uv run coverage report
157
+
158
+ - name: Upload coverage to Codecov
159
+ uses: codecov/codecov-action@v7
160
+ with:
161
+ files: ./coverage.xml
162
+ fail_ci_if_error: false
163
+ verbose: true
164
+
165
+ get-version:
166
+ runs-on: ubuntu-latest
167
+ outputs:
168
+ version: ${{ steps.get_version.outputs.version }}
169
+ is_prerelease: ${{ steps.get_version.outputs.is_prerelease }}
170
+ steps:
171
+ - name: Checkout code
172
+ uses: actions/checkout@v6
173
+
174
+ - name: Set up Python
175
+ uses: actions/setup-python@v6
176
+ with:
177
+ python-version: '3.12'
178
+
179
+ - name: Get version from pyproject.toml
180
+ id: get_version
181
+ run: |
182
+ VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
183
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
184
+
185
+ if [[ $VERSION =~ (alpha|beta|rc|dev) ]]; then
186
+ echo "is_prerelease=true" >> $GITHUB_OUTPUT
187
+ else
188
+ echo "is_prerelease=false" >> $GITHUB_OUTPUT
189
+ fi
190
+
191
+ echo "Detected version: $VERSION"
192
+
193
+ publish:
194
+ needs: [ test, lint-and-security, coverage, get-version ]
195
+ runs-on: ubuntu-latest
196
+ # Publish only when a version tag is pushed, or when triggered manually.
197
+ if: |
198
+ startsWith(github.ref, 'refs/tags/v') ||
199
+ github.event_name == 'workflow_dispatch'
200
+ environment:
201
+ name: ${{ startsWith(github.ref, 'refs/tags/v') && 'production' || 'staging' }}
202
+
203
+ steps:
204
+ - name: Checkout code
205
+ uses: actions/checkout@v6
206
+ with:
207
+ fetch-depth: 0
208
+
209
+ - name: Install uv
210
+ uses: astral-sh/setup-uv@v7
211
+ with:
212
+ enable-cache: true
213
+
214
+ - name: Determine target repository
215
+ id: target_repo
216
+ run: |
217
+ # A pushed tag publishes to PyPI; a manual run uses the chosen repo.
218
+ if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
219
+ REPO="${{ github.event.inputs.repository }}"
220
+ else
221
+ REPO="pypi"
222
+ fi
223
+
224
+ echo "repository=$REPO" >> $GITHUB_OUTPUT
225
+ echo "Publishing to: $REPO"
226
+
227
+ - name: Verify the tag matches the package version
228
+ if: startsWith(github.ref, 'refs/tags/v')
229
+ run: |
230
+ TAG_VERSION="${GITHUB_REF_NAME#v}"
231
+ PKG_VERSION="${{ needs.get-version.outputs.version }}"
232
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
233
+ echo "::error::Tag ${GITHUB_REF_NAME} does not match pyproject.toml version ${PKG_VERSION}."
234
+ exit 1
235
+ fi
236
+ echo "Tag matches package version: $PKG_VERSION"
237
+
238
+ - name: Build package
239
+ run: uv build
240
+
241
+ - name: Publish to PyPI
242
+ if: steps.target_repo.outputs.repository == 'pypi'
243
+ run: uv publish --token ${{ secrets.PYPI_TOKEN }}
244
+
245
+ - name: Publish to TestPyPI
246
+ if: steps.target_repo.outputs.repository == 'testpypi'
247
+ run: uv publish --publish-url https://test.pypi.org/legacy/ --token ${{ secrets.TESTPYPI_TOKEN }}
248
+
249
+ create-release:
250
+ needs: [ publish, get-version ]
251
+ runs-on: ubuntu-latest
252
+ # Only cut a GitHub Release for a real version tag.
253
+ if: |
254
+ needs.publish.result == 'success' &&
255
+ startsWith(github.ref, 'refs/tags/v')
256
+
257
+ steps:
258
+ - name: Checkout code
259
+ uses: actions/checkout@v6
260
+ with:
261
+ fetch-depth: 0
262
+
263
+ - name: Generate changelog
264
+ id: changelog
265
+ run: |
266
+ VERSION="${{ needs.get-version.outputs.version }}"
267
+ TAG_NAME="v$VERSION"
268
+
269
+ PREVIOUS_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' | sed -n '2p')
270
+
271
+ if [ -z "$PREVIOUS_TAG" ]; then
272
+ echo "No previous tag found, generating changelog from first commit"
273
+ CHANGELOG=$(git log --pretty=format:"- %s (%h)" --no-merges)
274
+ else
275
+ echo "Generating changelog from $PREVIOUS_TAG to $TAG_NAME"
276
+ CHANGELOG=$(git log $PREVIOUS_TAG..HEAD --pretty=format:"- %s (%h)" --no-merges)
277
+ fi
278
+
279
+ if [ -z "$CHANGELOG" ]; then
280
+ CHANGELOG="- Initial release"
281
+ fi
282
+
283
+ cat << EOF > changelog.md
284
+ ## What's Changed
285
+
286
+ $CHANGELOG
287
+
288
+ ## Installation
289
+
290
+ \`\`\`bash
291
+ pip install django-graphex==$VERSION
292
+ \`\`\`
293
+
294
+ **Full Changelog**: https://github.com/${{ github.repository }}/compare/$PREVIOUS_TAG...$TAG_NAME
295
+ EOF
296
+
297
+ - name: Create GitHub Release
298
+ uses: softprops/action-gh-release@v3
299
+ with:
300
+ tag_name: v${{ needs.get-version.outputs.version }}
301
+ name: Release v${{ needs.get-version.outputs.version }}
302
+ body_path: changelog.md
303
+ draft: false
304
+ prerelease: ${{ needs.get-version.outputs.is_prerelease == 'true' }}
305
+ files: |
306
+ dist/*
307
+ generate_release_notes: true
308
+ env:
309
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
310
+
311
+ - name: Release summary
312
+ run: |
313
+ echo "✅ Release v${{ needs.get-version.outputs.version }} created successfully!"
314
+ echo "🔗 https://github.com/${{ github.repository }}/releases/tag/v${{ needs.get-version.outputs.version }}"
315
+
316
+ deploy-docs:
317
+ # Build and publish the documentation to GitHub Pages, but only after the
318
+ # package was successfully published to PyPI for this version tag.
319
+ needs: [ publish ]
320
+ runs-on: ubuntu-latest
321
+ if: startsWith(github.ref, 'refs/tags/v')
322
+ permissions:
323
+ contents: read
324
+ pages: write
325
+ id-token: write
326
+ environment:
327
+ name: github-pages
328
+ url: ${{ steps.deployment.outputs.page_url }}
329
+ concurrency:
330
+ group: "pages"
331
+ cancel-in-progress: false
332
+
333
+ steps:
334
+ - name: Checkout code
335
+ uses: actions/checkout@v6
336
+
337
+ - name: Install uv
338
+ uses: astral-sh/setup-uv@v7
339
+ with:
340
+ enable-cache: true
341
+
342
+ - name: Install dependencies
343
+ run: uv sync
344
+
345
+ - name: Build documentation
346
+ run: uv run zensical build --clean -f zensical.yml
347
+
348
+ - name: Setup Pages
349
+ uses: actions/configure-pages@v6
350
+
351
+ - name: Upload artifact
352
+ uses: actions/upload-pages-artifact@v5
353
+ with:
354
+ path: ./site
355
+
356
+ - name: Deploy to GitHub Pages
357
+ id: deployment
358
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,61 @@
1
+ name: Documentation (manual)
2
+
3
+ # Automatic docs deployment happens in the release pipeline (cicd.yaml's
4
+ # `deploy-docs` job, which runs after a successful PyPI publish on a version
5
+ # tag). This workflow is only for rebuilding/redeploying the docs on demand
6
+ # (e.g. a docs-only fix between releases).
7
+ on:
8
+ workflow_dispatch: # Manual trigger only
9
+
10
+ permissions:
11
+ contents: read
12
+ pages: write
13
+ id-token: write
14
+
15
+ # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
16
+ # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
17
+ concurrency:
18
+ group: "pages"
19
+ cancel-in-progress: false
20
+
21
+ jobs:
22
+ build:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v6
27
+
28
+ - name: Set up Python
29
+ uses: actions/setup-python@v6
30
+ with:
31
+ python-version: '3.12'
32
+
33
+ - name: Install uv
34
+ uses: astral-sh/setup-uv@v7
35
+ with:
36
+ enable-cache: true
37
+
38
+ - name: Install dependencies
39
+ run: uv sync
40
+
41
+ - name: Setup Pages
42
+ uses: actions/configure-pages@v6
43
+
44
+ - name: Build documentation
45
+ run: uv run zensical build --clean -f zensical.yml
46
+
47
+ - name: Upload artifact
48
+ uses: actions/upload-pages-artifact@v5
49
+ with:
50
+ path: ./site
51
+
52
+ deploy:
53
+ environment:
54
+ name: github-pages
55
+ url: ${{ steps.deployment.outputs.page_url }}
56
+ runs-on: ubuntu-latest
57
+ needs: build
58
+ steps:
59
+ - name: Deploy to GitHub Pages
60
+ id: deployment
61
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,184 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # Distribution / packaging
8
+ .Python
9
+ build/
10
+ develop-eggs/
11
+ dist/
12
+ downloads/
13
+ eggs/
14
+ .eggs/
15
+ lib/
16
+ lib64/
17
+ parts/
18
+ sdist/
19
+ var/
20
+ wheels/
21
+ pip-wheel-metadata/
22
+ share/python-wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+ MANIFEST
27
+
28
+ # PyInstaller
29
+ *.manifest
30
+ *.spec
31
+
32
+ # Installer logs
33
+ pip-log.txt
34
+ pip-delete-this-directory.txt
35
+
36
+ # Unit test / coverage reports
37
+ htmlcov/
38
+ .tox/
39
+ .nox/
40
+ .coverage
41
+ .coverage.*
42
+ .cache
43
+ nosetests.xml
44
+ coverage.xml
45
+ *.cover
46
+ *.py,cover
47
+ .hypothesis/
48
+ .pytest_cache/
49
+
50
+ # Translations
51
+ *.mo
52
+ *.pot
53
+
54
+ # Django stuff:
55
+ *.log
56
+ local_settings.py
57
+ db.sqlite3
58
+ db.sqlite3-journal
59
+
60
+ # Flask stuff:
61
+ instance/
62
+ .webassets-cache
63
+
64
+ # Scrapy stuff:
65
+ .scrapy
66
+
67
+ # Sphinx documentation
68
+ docs/_build/
69
+
70
+ # MkDocs documentation
71
+ site/
72
+
73
+ # PyBuilder
74
+ target/
75
+
76
+ # Jupyter Notebook
77
+ .ipynb_checkpoints
78
+
79
+ # IPython
80
+ profile_default/
81
+ ipython_config.py
82
+
83
+ # pyenv
84
+ .python-version
85
+
86
+ # pipenv
87
+ Pipfile.lock
88
+
89
+ # PEP 582
90
+ __pypackages__/
91
+
92
+ # Celery stuff
93
+ celerybeat-schedule
94
+ celerybeat.pid
95
+
96
+ # SageMath parsed files
97
+ *.sage.py
98
+
99
+ # Environments
100
+ .env
101
+ .venv
102
+ env/
103
+ venv/
104
+ ENV/
105
+ env.bak/
106
+ venv.bak/
107
+
108
+ # Spyder project settings
109
+ .spyderproject
110
+ .spyproject
111
+
112
+ # Rope project settings
113
+ .ropeproject
114
+
115
+ # mkdocs documentation
116
+ /site
117
+
118
+ # mypy
119
+ .mypy_cache/
120
+ .dmypy.json
121
+ dmypy.json
122
+
123
+ # Pyre type checker
124
+ .pyre/
125
+
126
+ # IDEs
127
+ .idea/
128
+ .vscode/
129
+ *.swp
130
+ *.swo
131
+ *~
132
+
133
+ # OS generated files
134
+ .DS_Store
135
+ .DS_Store?
136
+ ._*
137
+ .Spotlight-V100
138
+ .Trashes
139
+ ehthumbs.db
140
+ Thumbs.db
141
+
142
+ # Security reports
143
+ bandit-report.json
144
+
145
+ # Poetry virtual environments
146
+ # Note: poetry.lock should be committed to ensure reproducible builds
147
+
148
+ # Temporary files
149
+ *.tmp
150
+ *.temp
151
+
152
+ # Log files
153
+ *.log
154
+
155
+ # Database files
156
+ *.sqlite3
157
+ *.db
158
+
159
+ # Project-specific
160
+ .flake8
161
+
162
+ # Editor and system files
163
+ *.sublime-project
164
+ *.sublime-workspace
165
+ .vscode/settings.json
166
+ .vscode/launch.json
167
+ .vscode/extensions.json
168
+
169
+ # Coverage HTML reports
170
+ htmlcov/
171
+
172
+ # Documentation builds
173
+ docs/site/
174
+ docs/_build/
175
+
176
+ # Backup files
177
+ *.bak
178
+ *.backup
179
+ *~
180
+
181
+ # MacOS specific
182
+ .DS_Store
183
+ .AppleDouble
184
+ .LSOverride
@@ -0,0 +1,51 @@
1
+ repos:
2
+ - repo: https://github.com/commitizen-tools/commitizen
3
+ rev: v4.9.0
4
+ hooks:
5
+ - id: commitizen
6
+ stages:
7
+ - commit-msg
8
+
9
+ # Lint + format with ruff (replaces isort, black, flake8 and autoflake).
10
+ # Configuration (rule selection, per-file ignores, pydocstyle convention) is
11
+ # read from pyproject.toml's [tool.ruff] section, so `examples/*` and
12
+ # `tests/*` are exempt from docstring (D) rules here too.
13
+ - repo: https://github.com/astral-sh/ruff-pre-commit
14
+ rev: v0.13.1
15
+ hooks:
16
+ - id: ruff
17
+ args:
18
+ - --fix
19
+ - id: ruff-format
20
+
21
+ # Generic hygiene hooks.
22
+ - repo: https://github.com/pre-commit/pre-commit-hooks
23
+ rev: v6.0.0
24
+ hooks:
25
+ - id: check-yaml
26
+ - id: end-of-file-fixer
27
+ - id: trailing-whitespace
28
+ - id: check-merge-conflict
29
+ - id: check-added-large-files
30
+ - id: check-case-conflict
31
+ - id: debug-statements
32
+
33
+ # Security checks (library code only).
34
+ - repo: https://github.com/PyCQA/bandit
35
+ rev: 1.8.6
36
+ hooks:
37
+ - id: bandit
38
+ args:
39
+ - --skip=B101,B311,B324
40
+ - --exclude=tests,migrations
41
+ files: ^django_graphex/
42
+
43
+ # Type checking (library code only).
44
+ - repo: https://github.com/pre-commit/mirrors-mypy
45
+ rev: v1.17.1
46
+ hooks:
47
+ - id: mypy
48
+ additional_dependencies:
49
+ - types-six
50
+ - types-python-dateutil
51
+ files: ^django_graphex/
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Ernesto Perez Amigo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include README.rst
3
+ include LICENSE