Skip to content

Commit b9320c5

Browse files
committed
chore: regenerate events catalogue
1 parent 7415b43 commit b9320c5

6 files changed

Lines changed: 2143 additions & 3 deletions

File tree

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
Metadata-Version: 2.4
2+
Name: flagsmith-api
3+
Version: 2.68.0
4+
Summary: The API component for the Flagsmith application.
5+
Author-email: Flagsmith <support@flagsmith.com>
6+
Requires-Python: <3.14,>=3.11
7+
Description-Content-Type: text/markdown
8+
Requires-Dist: django<6,>=5
9+
Requires-Dist: rudder-sdk-python<2.1.0,>=2.0.2
10+
Requires-Dist: segment-analytics-python<2.3.0,>=2.2.3
11+
Requires-Dist: backoff<2.3.0,>=2.2.1
12+
Requires-Dist: appdirs<1.5.0,>=1.4.4
13+
Requires-Dist: django-cors-headers<3.6.0,>=3.5.0
14+
Requires-Dist: djangorestframework<3.16.0,>=3.15.2
15+
Requires-Dist: gunicorn<23.1.0,>=23.0.0
16+
Requires-Dist: pyparsing<2.5.0,>=2.4.7
17+
Requires-Dist: requests<2.34.0,>=2.33.0
18+
Requires-Dist: six<1.17.0,>=1.16.0
19+
Requires-Dist: whitenoise<6.1.0,>=6.0.0
20+
Requires-Dist: dj-database-url<3.1.0,>=3.0.1
21+
Requires-Dist: drf-nested-routers<0.93.0,>=0.92.1
22+
Requires-Dist: shortuuid<1.1.0,>=1.0.1
23+
Requires-Dist: sendgrid-django<4.3.0,>=4.2.0
24+
Requires-Dist: psycopg2-binary<2.10.0,>=2.9.5
25+
Requires-Dist: coreapi<2.4.0,>=2.3.3
26+
Requires-Dist: django-simple-history<2.13.0,>=2.12.0
27+
Requires-Dist: google-api-python-client<1.13.0,>=1.12.5
28+
Requires-Dist: oauth2client<4.2.0,>=4.1.3
29+
Requires-Dist: djangorestframework-recursive<0.2.0,>=0.1.2
30+
Requires-Dist: chargebee<4.0.0,>=3.10.0
31+
Requires-Dist: python-http-client<3.4.0,>=3.3.7
32+
Requires-Dist: django-health-check<3.19.0,>=3.18.2
33+
Requires-Dist: django-admin-sso<5.3.0,>=5.2.0
34+
Requires-Dist: drf-spectacular<0.29.0,>=0.28.0
35+
Requires-Dist: sentry-sdk<3,>=2.24.1
36+
Requires-Dist: environs<15.0.0,>=14.1.1
37+
Requires-Dist: django-lifecycle<1.3.0,>=1.2.4
38+
Requires-Dist: drf-writable-nested<0.7.0,>=0.6.2
39+
Requires-Dist: django-filter<2.5.0,>=2.4.0
40+
Requires-Dist: flagsmith-flag-engine<11.0.0,>=10.1.0
41+
Requires-Dist: boto3<1.36.0,>=1.35.95
42+
Requires-Dist: slack-sdk<3.10.0,>=3.9.0
43+
Requires-Dist: asgiref<3.9.0,>=3.8.1
44+
Requires-Dist: djangorestframework-api-key<2.3.0,>=2.2.0
45+
Requires-Dist: pymemcache<4.1.0,>=4.0.0
46+
Requires-Dist: google-re2<2.0.0,>=1.0
47+
Requires-Dist: django-softdelete<0.12.0,>=0.11.5
48+
Requires-Dist: simplejson<3.20.0,>=3.19.1
49+
Requires-Dist: djoser<3.0.0,>=2.3.0
50+
Requires-Dist: django-storages<1.11.0,>=1.10.1
51+
Requires-Dist: django-environ<0.5.0,>=0.4.5
52+
Requires-Dist: influxdb-client<1.51.0,>=1.50.0
53+
Requires-Dist: django-ordered-model<3.5.0,>=3.4.1
54+
Requires-Dist: django-ses<3.6.0,>=3.5.0
55+
Requires-Dist: django-axes<9.0.0,>=8.1.0
56+
Requires-Dist: pydantic<3.0.0,>=2.12.0
57+
Requires-Dist: pydantic-collections<0.7.0,>=0.6.0
58+
Requires-Dist: pyngo<2.5.0,>=2.4.1
59+
Requires-Dist: flagsmith<6.0.0,>=5.3.0
60+
Requires-Dist: openfeature-sdk<0.10.0,>=0.9.0
61+
Requires-Dist: openfeature-provider-flagsmith>=0.2.0
62+
Requires-Dist: python-gnupg<0.6.0,>=0.5.1
63+
Requires-Dist: django-redis<6.0.0,>=5.4.0
64+
Requires-Dist: pygithub<2.9.0,>=2.8
65+
Requires-Dist: hubspot-api-client<13.0.0,>=12.0.0
66+
Requires-Dist: djangorestframework-dataclasses<2.0.0,>=1.3.1
67+
Requires-Dist: pyotp<3.0.0,>=2.9.0
68+
Requires-Dist: flagsmith-common[common-core,flagsmith-schemas,task-processor]<4,>=3.9.0
69+
Requires-Dist: django-stubs<6.0.0,>=5.1.3
70+
Requires-Dist: tzdata<2025.0.0,>=2024.1
71+
Requires-Dist: djangorestframework-simplejwt<6.0.0,>=5.5.1
72+
Requires-Dist: structlog<25.0.0,>=24.4.0
73+
Requires-Dist: prometheus-client<0.22.0,>=0.21.1
74+
Requires-Dist: django-cockroachdb<4.3.0,>=4.2
75+
Requires-Dist: django-oauth-toolkit<4.0.0,>=3.0.1
76+
Provides-Extra: auth-controller
77+
Requires-Dist: auth-controller; extra == "auth-controller"
78+
Requires-Dist: django-multiselectfield<2,>=1.0.1; extra == "auth-controller"
79+
Provides-Extra: saml
80+
Requires-Dist: pysaml2<8.0.0,>=7.4.2; extra == "saml"
81+
Provides-Extra: ldap
82+
Requires-Dist: flagsmith-ldap; extra == "ldap"
83+
Requires-Dist: django-python3-ldap<1,>=0.15.6; extra == "ldap"
84+
Provides-Extra: workflows
85+
Requires-Dist: workflows-logic; extra == "workflows"
86+
Provides-Extra: licensing
87+
Requires-Dist: licensing; extra == "licensing"
88+
Requires-Dist: cryptography>=44.0.1; extra == "licensing"
89+
Provides-Extra: release-pipelines
90+
Requires-Dist: flagsmith-private<1,>=0.5.1; extra == "release-pipelines"
91+
Provides-Extra: scim
92+
Requires-Dist: flagsmith-private<1,>=0.5.1; extra == "scim"
93+
Provides-Extra: dev
94+
Requires-Dist: django-test-migrations<2.0.0,>=1.2.0; extra == "dev"
95+
Requires-Dist: responses<0.23.0,>=0.22.0; extra == "dev"
96+
Requires-Dist: pre-commit<5.0.0,>=4.0.1; extra == "dev"
97+
Requires-Dist: pytest-mock<3.11.0,>=3.10.0; extra == "dev"
98+
Requires-Dist: pytest-lazy-fixture<0.7.0,>=0.6.3; extra == "dev"
99+
Requires-Dist: moto<4.2.0,>=4.1.3; extra == "dev"
100+
Requires-Dist: pytest-freezegun<0.5.0,>=0.4.2; extra == "dev"
101+
Requires-Dist: setuptools; extra == "dev"
102+
Requires-Dist: pytest-xdist<3.7.0,>=3.6.1; extra == "dev"
103+
Requires-Dist: pylint<2.17.0,>=2.16.2; extra == "dev"
104+
Requires-Dist: pep8<1.8.0,>=1.7.1; extra == "dev"
105+
Requires-Dist: autopep8<2.1.0,>=2.0.1; extra == "dev"
106+
Requires-Dist: pytest<7.3.0,>=7.2.1; extra == "dev"
107+
Requires-Dist: pytest-django<5.0.0,>=4.8.0; extra == "dev"
108+
Requires-Dist: pytest-cov<4.2.0,>=4.1.0; extra == "dev"
109+
Requires-Dist: datamodel-code-generator<0.26.0,>=0.25; extra == "dev"
110+
Requires-Dist: requests-mock<2.0.0,>=1.11.0; extra == "dev"
111+
Requires-Dist: django-extensions<4.0.0,>=3.2.3; extra == "dev"
112+
Requires-Dist: pdbpp<0.11.0,>=0.10.3; extra == "dev"
113+
Requires-Dist: mypy-boto3-dynamodb<2.0.0,>=1.33.0; extra == "dev"
114+
Requires-Dist: pytest-structlog<2.0.0,>=1.1; extra == "dev"
115+
Requires-Dist: pyfakefs<6.0.0,>=5.7.4; extra == "dev"
116+
Requires-Dist: mypy<2.0.0,>=1.15.0; extra == "dev"
117+
Requires-Dist: djangorestframework-stubs<4.0.0,>=3.15.2; extra == "dev"
118+
Requires-Dist: boto3-stubs<2.0.0,>=1.36.20; extra == "dev"
119+
Requires-Dist: types-requests<3.0.0,>=2.32.0.20241016; extra == "dev"
120+
Requires-Dist: types-markdown<4.0.0,>=3.7.0.20241204; extra == "dev"
121+
Requires-Dist: types-pygments<3.0.0,>=2.19.0.20250107; extra == "dev"
122+
Requires-Dist: types-influxdb-client<2.0.0,>=1.45.0.20241221; extra == "dev"
123+
Requires-Dist: types-psycopg2<3.0.0,>=2.9.21.20250121; extra == "dev"
124+
Requires-Dist: types-python-dateutil<3.0.0,>=2.9.0.20241206; extra == "dev"
125+
Requires-Dist: types-pytz<2026.0.0,>=2025.1.0.20250204; extra == "dev"
126+
Requires-Dist: ruff<0.10.0,>=0.9.7; extra == "dev"
127+
Requires-Dist: flagsmith-common[test-tools]; extra == "dev"
128+
Requires-Dist: pytest-responses<0.6.0,>=0.5.1; extra == "dev"
129+
Requires-Dist: diff-cover<11.0.0,>=10.1.0; extra == "dev"
130+
Requires-Dist: django-debug-toolbar; extra == "dev"
131+
Requires-Dist: ipython<10.0.0,>=9.10.0; extra == "dev"
132+
Requires-Dist: email-validator>=2.0.0; extra == "dev"
133+
134+
## Flagsmith API
135+
136+
### Local development
137+
138+
The project assumes the following tools installed:
139+
- [Python](https://www.python.org/downloads/). Any version allowed by `requires-python` in `pyproject.toml` is supported.
140+
- [GNU Make](https://www.gnu.org/software/make/).
141+
- Docker or a compatible tool like [Podman](https://podman.io/). We recommend [OrbStack](https://orbstack.dev/) for macOS.
142+
143+
To install dev dependencies, run `make install`. Only Flagsmith maintainers can run `uv lock` due to private dependencies.
144+
145+
To run linters, run `make lint`.
146+
147+
To run tests, run `make test`.
148+
149+
To run a subset of tests or an individual test, run `make test opts='<pytest args>'`. If the number of test is too low for xdist, consider adding `-n0` to pytest args.
150+
151+
To prepare a dev database, run `make docker-up django-migrate`.
152+
153+
To bring up a dev server, run `make serve`, or `make serve-with-task-processor` to run the Task processor alongside the server.
154+
155+
### Code guidelines: testing
156+
157+
The required diff test coverage for our backend PRs is 100%. This policy gives us more confidence to ship, helps us to find bugs earlier, and promotes the test-driven development (TDD) approach. We encourage you to add new tests, and modify existing ones, ahead of writing the code.
158+
159+
This codebase includes two kinds of tests:
160+
- Black box API tests in `tests/integration` directory. Ideally, these are intended to only invoke API endpoints, and verify their output.
161+
- Tests for individual modules, classes and functions in `tests/unit` directory.
162+
163+
We avoid class-based tests. To manage test lifecycle and dependencies, we rely on Pytest features such as fixtures, markers, parametrisation, and hooks. Read `conftest.py` for commonly used fixtures.
164+
165+
We enforce the `test_{subject}__{condition}__{expected outcome}` template for test names, e.g. `test_get_version__valid_file_contents__returns_version_number`.
166+
167+
We use the Given When Then structure in all our tests.
168+
169+
### Code guidelines: metrics
170+
171+
The Flagsmith backend exports Prometheus metrics. When planning a feature, consider which metrics should cover it — counters for domain events, histograms for latency or sizes, gauges for cardinalities. See [documentation for existing metrics](https://docs.flagsmith.com/deployment-self-hosting/observability/metrics). Metrics code is hosted in `metrics.py` modules.
172+
173+
Name metrics `flagsmith_{domain}_{entity}_{unit}` and give them a comprehensive description.
174+
175+
### Code guidelines: logs
176+
177+
We use structured logging to mark up interesting operational and product events. Events emitted via structlog also flow through an OpenTelemetry pipeline and may be routed to a CDP or a data warehouse for product analytics.
178+
179+
When planning a feature, decide which moments deserve an event: things a product manager would ask about (an integration set up, a workflow committed, an import completed), or that a future oncall engineer would need to debug an incident. One well-shaped event per moment beats a wall of free-form `logging.info` calls.
180+
181+
```python
182+
import structlog
183+
184+
# Use logger name as the event domain:
185+
logger = structlog.get_logger("workflows")
186+
187+
# This will produce a `workflows.change_request.committed` OTLP log event
188+
# with the following attributes:
189+
# - organisation.id
190+
# - environment.id
191+
# - feature_states.count
192+
logger.info(
193+
"change_request.committed",
194+
organisation__id=environment.project.organisation_id,
195+
environment__id=environment.id,
196+
feature_states__count=change_request.feature_states.count(),
197+
)
198+
```
199+
200+
In your tests, verify your logs with the `caplog` fixture:
201+
202+
```python
203+
from pytest_structlog import StructuredLogCapture
204+
205+
def test_my_view__success__logs_expected(
206+
log: StructuredLogCapture,
207+
) -> None:
208+
# Given / When
209+
...
210+
211+
# Then
212+
assert log.events == [
213+
{
214+
"level": "info",
215+
"event": "action.succeeded",
216+
"organisation__id": organisation.id,
217+
}
218+
]
219+
```
220+
221+
Conventions:
222+
223+
- Logger name is the domain namespace — typically the app or package (`workflows`, `code_references`, `feature_health`).
224+
- Event name is `entity.action` in snake_case (`scan.created`, `change_request.committed`). Do not repeat the logger name in the event, i.e `get_logger("saml")` with `"saml.configuration.created"` is redundant.
225+
- Use double underscore to namespace event attributes, i.e. `namespace__property` will be emitted as `namespace.property`. Include the IDs of the entities the event is about (`organisation__id`, `project__id`, `environment__id`, `feature__id`) so events can be correlated with each other.
226+
- Bind shared context once with `logger.bind(...)` rather than repeating attributes at every call site.
227+
- Avoid PII — identify users and organisations by ID.
228+
229+
For errors, use `logger.exception(...)` or pass `exc_info=exc`, and keep the event name actionable (`import.failed`, not `error`).
230+
231+
### Code guidelines: feature flags (Flagsmith on Flagsmith)
232+
233+
To gate and gradually roll out features in the backend, we use the [OpenFeature](https://openfeature.dev/) SDK with a Flagsmith provider running in local evaluation mode:
234+
235+
```python
236+
from integrations.flagsmith.client import get_openfeature_client
237+
238+
client = get_openfeature_client()
239+
ai_enabled = client.get_boolean_value(
240+
"ai",
241+
default_value=False,
242+
evaluation_context=organisation.openfeature_evaluation_context,
243+
)
244+
```
245+
246+
Organisations expose an `openfeature_evaluation_context` property carrying common traits — use it for org-scoped targeting. For other subjects, build an `EvaluationContext` with a stable `targeting_key` and the attributes your targeting rules need.
247+
248+
Add your feature as early as possible to the Flagsmith on Flagsmith project, and run the `updateflagsmithenvironment` management command to synchronise the local cache. You can use [Flagsmith MCP](https://docs.flagsmith.com/integrating-with-flagsmith/mcp-server) to integrate Flagsmith in your development flow.
249+
250+
### Code guidelines: migrations
251+
252+
To auto-generate migrations for your new code, run `make docker-up django-make-migrations`.
253+
254+
The prompt will ask you for a name and not generate one; we avoid auto-generated migration names.
255+
256+
Squash newly added migrations whenever you can.
257+
258+
### Code guidelines: typing
259+
260+
This codebase, including tests, is fully type-checked by Mypy in strict mode. Resolving existing `# type: ignore` comments is always welcome. If you happen to bring a new `# type: ignore` comment, please document the reason, and consider fixing a small number of adjacent `# type: ignore` comments, if possible and appropriate for the scope of your task.
261+
262+
To run a full type check, run `make typecheck`.
263+
264+
### Code guidelines: design and architecture
265+
266+
Core API consists of Django apps with usual Django submodules like:
267+
- `apps.py`
268+
- `middleware.py`
269+
- `models.py`
270+
- `serializers.py`
271+
- `views.py`
272+
- `urls.py`
273+
274+
We tend to add our own layers in the following modules:
275+
- `constants.py` for app-wide constant variables.
276+
- `dataclasses.py` for dataclass definitions, typically used for internal data transfer objects (DTOs).
277+
- `mappers.py` for data mapping logic unrelated to API requests and responses.
278+
- `services.py` for encapsulated business logic. Our goal with this layer is to make the views, models and serialisers leaner, so that the business logic is more clearly defined and easier to compose.
279+
- `tasks.py` for defining asynchronous and recurring tasks.
280+
- `types.py` for custom type definitions, including typed dicts.

0 commit comments

Comments
 (0)