Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot] 8bc3cc9a44 ⬆️(dependencies) update GitHub Actions dependencies 2026-10-12 02:34:59 +00:00
28 changed files with 65 additions and 490 deletions
+13 -13
View File
@@ -87,7 +87,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -117,11 +117,11 @@ jobs:
timeout 30 sh -c 'until docker exec garage /garage health; do sleep 1; done'
- name: Install Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
python-version: "3.14"
- name: Install uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
- name: Install the dependencies
run: uv sync --locked --all-extras
@@ -160,7 +160,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -170,12 +170,12 @@ jobs:
sudo apt-get install -y ffmpeg
- name: Install Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
python-version: "3.14"
- name: Install uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
- name: Install the project
run: uv sync --locked --all-extras
@@ -189,7 +189,7 @@ jobs:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -208,12 +208,12 @@ jobs:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "24"
@@ -232,7 +232,7 @@ jobs:
working-directory: src/sdk/library
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
@@ -255,7 +255,7 @@ jobs:
working-directory: src/sdk/library
steps:
- name: Checkout repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
-8
View File
@@ -10,17 +10,9 @@ and this project adheres to
### Added
- ⚡️(backend) add UPPER(email) index for case-insensitive user lookups
## [1.35.0] - 2026-10-13
### Added
- ✨(frontend) let users pick the recording encoding
- ✨(backend) introduce a token exchange endpoint for iframe embeds
- ⚡️(backend) send recording notification emails from a Celery task
- ✨(backend) allow static feature flags without an analytics backend #1809
- ⚡️(backend) add an opt-in psycopg connection pool
### Changed
+13 -13
View File
@@ -5,17 +5,17 @@ services:
env_file:
- env.d/development/postgresql
ports:
- "127.0.0.1:15432:5432"
- "15432:5432"
redis:
image: redis:5
ports:
- "127.0.0.1:6379:6379"
- "6379:6379"
mailcatcher:
image: sj26/mailcatcher:latest
ports:
- "127.0.0.1:1081:1080"
- "1081:1080"
garage:
user: ${DOCKER_USER:-1000}
@@ -71,7 +71,7 @@ services:
- env.d/development/common
- env.d/development/postgresql
ports:
- "127.0.0.1:8071:8000"
- "8071:8000"
volumes:
- ./src/backend:/app
- ./data/static:/data/static
@@ -137,7 +137,7 @@ services:
nginx:
image: nginx:1.25
ports:
- "127.0.0.1:8083:8083"
- "8083:8083"
volumes:
- ./docker/files/etc/nginx/conf.d:/etc/nginx/conf.d:ro
depends_on:
@@ -159,7 +159,7 @@ services:
VITE_APP_TITLE: "LaSuite Meet"
image: meet:frontend-development
ports:
- "127.0.0.1:3000:8080"
- "3000:8080"
dockerize:
image: jwilder/dockerize
@@ -185,7 +185,7 @@ services:
kc_postgresql:
image: postgres:14.3
ports:
- "127.0.0.1:5433:5432"
- "5433:5432"
env_file:
- env.d/development/kc_postgresql
@@ -213,7 +213,7 @@ services:
KC_DB_SCHEMA: public
PROXY_ADDRESS_FORWARDING: 'true'
ports:
- "127.0.0.1:8080:8080"
- "8080:8080"
depends_on:
- kc_postgresql
@@ -222,10 +222,10 @@ services:
entrypoint: /livekit-server --dev --bind 0.0.0.0 --config ./config.yaml
ports:
- "7880:7880"
- "127.0.0.1:7881:7881"
- "127.0.0.1:7882:7882/udp"
- "127.0.0.1:3478:3478/udp"
- "127.0.0.1:30000-30100:30000-30100/udp"
- "7881:7881"
- "7882:7882/udp"
- "3478:3478/udp"
- "30000-30100:30000-30100/udp"
volumes:
- ./docker/livekit/config/livekit-server.yaml:/config.yaml
depends_on:
@@ -283,7 +283,7 @@ services:
env_file:
- env.d/development/summary
ports:
- "127.0.0.1:8001:8000"
- "8001:8000"
volumes:
- ./src/summary:/app
depends_on:
+1 -1
View File
@@ -45,4 +45,4 @@ services:
# The local proxy listens on 8080 and collides with Keycloak's published admin port.
keycloak:
ports: !override
- "127.0.0.1:8081:8080"
- "8081:8080"
-20
View File
@@ -120,26 +120,6 @@ DJANGO_EMAIL_BRAND_NAME=<brand name used in email templates> # e.g. "La Suite Nu
DJANGO_EMAIL_LOGO_IMG=<logo image to use in email templates.> # e.g. "https://meet.yourdomain.tld/assets/logo-suite-numerique.png"
```
### Feature flags without an analytics backend
Some features, such as automatic meeting summaries (`summary-enabled`), are gated by a feature flag read from the analytics backend. You do not need an analytics backend to enable them: leave `ANALYTICS_BACKEND` unset and declare the flags in `env.d/common`. No data is sent anywhere.
```env
ANALYTICS_BACKEND_SETTINGS={"feature_flags": {"summary-enabled": True}}
```
You can also set it directly in `compose.yaml`:
```yaml
services:
backend:
environment:
ANALYTICS_BACKEND_SETTINGS: '{"feature_flags": {"summary-enabled": True}}'
```
> [!NOTE]
> The value is a Python dictionary, not JSON: write `True`, not `true`. Set it on every container running the backend image.
## Step 3: Configure your firewall
If you are using a firewall as it is usually recommended in a production environment you will need to allow the webservice traffic on ports 80 and 443 but also to allow UDP traffic for the WebRTC service.
+1 -8
View File
@@ -318,17 +318,12 @@ These are the environmental options available on meet backend.
| DJANGO_SECRET_KEY | Secret key used for Django security | |
| DJANGO_SILENCED_SYSTEM_CHECKS | Silence Django system checks | [] |
| DJANGO_ALLOW_UNSECURE_USER_LISTING | Allow unsecure user listing | false |
| DB_ENGINE | Database engine used | django.db.backends.postgresql |
| DB_ENGINE | Database engine used | django.db.backends.postgresql_psycopg2 |
| DB_NAME | Name of the database | meet |
| DB_USER | User used to connect to database | dinum |
| DB_PASSWORD | Password used to connect to the database | pass |
| DB_HOST | Hostname of the database | localhost |
| DB_PORT | Port to connect to database | 5432 |
| DB_PSYCOPG_POOL_ENABLED | Enable the psycopg connection pool | false |
| DB_PSYCOPG_POOL_MIN_SIZE | Connections each pool keeps open | 1 |
| DB_PSYCOPG_POOL_MAX_SIZE | Maximum connections per pool | 3 |
| DB_PSYCOPG_POOL_TIMEOUT | Seconds a request waits for a free pool connection before failing | 30 |
| DB_PSYCOPG_POOL_MAX_IDLE | Seconds an idle connection above the minimum stays open | 600 |
| STORAGES_STATICFILES_BACKEND | Static file serving engine | whitenoise.storage.CompressedManifestStaticFilesStorage |
| AWS_S3_ENDPOINT_URL | S3 host endpoint | |
| AWS_S3_ACCESS_KEY_ID | S3 access key | |
@@ -421,8 +416,6 @@ These are the environmental options available on meet backend.
| SCREEN_RECORDING_BASE_URL | Screen recording base URL | |
| SUMMARY_SERVICE_ENDPOINT | Summary service endpoint | |
| SUMMARY_SERVICE_API_TOKEN | API token for summary service | |
| ANALYTICS_BACKEND | Analytics backend class, e.g. `core.analytics.posthog.PostHogAnalytics`. Nothing is sent when unset | |
| ANALYTICS_BACKEND_SETTINGS | Analytics backend settings. Without a backend, `{"feature_flags": {"summary-enabled": True}}` sets feature flags statically | {} |
| SIGNUP_NEW_USER_TO_MARKETING_EMAIL | Signup users to marketing emails | false |
| MARKETING_SERVICE_CLASS | Marketing service class | core.services.marketing.BrevoMarketingService |
| BREVO_API_KEY | Brevo API key for marketing emails | |
+1 -2
View File
@@ -8,5 +8,4 @@ DB_HOST=postgresql
DB_NAME=meet
DB_USER=dinum
DB_PASSWORD=pass
DB_PORT=5432
DB_PSYCOPG_POOL_ENABLED=True
DB_PORT=5432
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "agents"
version = "1.35.0"
version = "1.34.0"
requires-python = ">=3.12"
dependencies = [
"livekit-agents==1.7.0",
+1 -1
View File
@@ -9,7 +9,7 @@ resolution-markers = [
[[package]]
name = "agents"
version = "1.35.0"
version = "1.34.0"
source = { virtual = "." }
dependencies = [
{ name = "boto3" },
+1 -1
View File
@@ -39,7 +39,7 @@ def get_analytics() -> AnalyticsBackend:
options = getattr(settings, "ANALYTICS_BACKEND_SETTINGS", {}) or {}
if not dotted_path:
return NoOpAnalytics(**options)
return NoOpAnalytics()
backend_class = import_string(dotted_path)
return backend_class(**options)
+1 -24
View File
@@ -53,23 +53,7 @@ class AnalyticsBackend(ABC):
class NoOpAnalytics(AnalyticsBackend):
"""
Default backend: discards events and serves static feature flags.
Feature flags can be declared without any analytics provider, e.g.:
ANALYTICS_BACKEND_SETTINGS = {"feature_flags": {"summary-enabled": True}}
"""
def __init__(
self,
*,
feature_flags: Mapping[str, bool | str | None] | None = None,
**_kwargs: Any,
) -> None:
# Other settings are ignored, so that settings meant for another
# backend never break an instance running without one.
self._feature_flags = dict(feature_flags or {})
"""Default backend: silently discards everything."""
def identify(self, user: User, properties=None) -> None:
"""No-op: discards identify calls."""
@@ -79,10 +63,3 @@ class NoOpAnalytics(AnalyticsBackend):
def shutdown(self) -> None:
"""No-op: nothing to flush."""
def get_user_feature_flags(
self,
user: User,
) -> Mapping[UserFeatureFlag, bool | str | None]:
"""Return the feature flags declared in settings, for any user."""
return self._feature_flags
@@ -1,23 +0,0 @@
# Generated by Django 5.2.14 on 2026-10-07 18:45
from django.contrib.postgres.operations import AddIndexConcurrently
from django.db import migrations, models
from django.db.models.functions import Upper
class Migration(migrations.Migration):
atomic = False
dependencies = [
('core', '0026_alter_application_scopes'),
]
operations = [
AddIndexConcurrently(
model_name="user",
index=models.Index(
Upper("email"),
name="user_email_upper_idx",
),
),
]
-3
View File
@@ -246,9 +246,6 @@ class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin):
name="unique_email_when_sub_is_null",
)
]
indexes = [
models.Index(models.functions.Upper("email"), name="user_email_upper_idx"),
]
def __str__(self):
return self.email or self.admin_email or str(self.id)
@@ -1,124 +0,0 @@
"""
Unit tests for NoOpAnalytics and the analytics backend loader.
"""
# pylint: disable=redefined-outer-name,unused-argument
import pytest
from core.analytics import get_analytics
from core.analytics.base import NoOpAnalytics
from core.analytics.user_feature_flags import UserFeatureFlag
from core.factories import UserFactory
pytestmark = pytest.mark.django_db
@pytest.fixture(autouse=True)
def clear_analytics_cache():
"""Clear the cached backend before and after each test."""
get_analytics.cache_clear()
yield
get_analytics.cache_clear()
# ==============================
# NoOpAnalytics
# ==============================
def test_noop_has_no_feature_flags_by_default():
"""Should keep every feature flag disabled when none is declared."""
backend = NoOpAnalytics()
user = UserFactory()
assert not backend.get_user_feature_flags(user)
assert (
backend.is_user_feature_enabled(
user, UserFeatureFlag.TRANSCRIPT_SUMMARY_ENABLED
)
is False
)
def test_noop_enables_declared_feature_flags():
"""Should enable a feature flag declared as True."""
backend = NoOpAnalytics(feature_flags={"summary-enabled": True})
user = UserFactory()
assert backend.get_user_feature_flags(user) == {"summary-enabled": True}
assert (
backend.is_user_feature_enabled(
user, UserFeatureFlag.TRANSCRIPT_SUMMARY_ENABLED
)
is True
)
@pytest.mark.parametrize("value", [False, None, "true"])
def test_noop_only_enables_feature_flags_set_to_true(value):
"""Should keep a feature flag disabled unless its value is exactly True."""
backend = NoOpAnalytics(feature_flags={"summary-enabled": value})
user = UserFactory()
assert (
backend.is_user_feature_enabled(
user, UserFeatureFlag.TRANSCRIPT_SUMMARY_ENABLED
)
is False
)
def test_noop_ignores_unrelated_settings():
"""Should accept settings meant for another backend without failing."""
backend = NoOpAnalytics(api_key="my-key", host="https://eu.i.posthog.com")
assert not backend.get_user_feature_flags(UserFactory())
# ==============================
# get_analytics
# ==============================
def test_get_analytics_defaults_to_noop_without_feature_flags(settings):
"""Should return a no-op backend with no feature flag by default."""
settings.ANALYTICS_BACKEND = None
settings.ANALYTICS_BACKEND_SETTINGS = {}
backend = get_analytics()
assert isinstance(backend, NoOpAnalytics)
assert not backend.get_user_feature_flags(UserFactory())
def test_get_analytics_passes_feature_flags_to_noop(settings):
"""Should forward the feature flags when no backend is configured."""
settings.ANALYTICS_BACKEND = None
settings.ANALYTICS_BACKEND_SETTINGS = {"feature_flags": {"summary-enabled": True}}
backend = get_analytics()
assert isinstance(backend, NoOpAnalytics)
assert (
backend.is_user_feature_enabled(
UserFactory(), UserFeatureFlag.TRANSCRIPT_SUMMARY_ENABLED
)
is True
)
def test_get_analytics_instantiates_configured_backend_with_settings(settings):
"""Should instantiate the configured backend with its settings."""
settings.ANALYTICS_BACKEND = "core.analytics.base.NoOpAnalytics"
settings.ANALYTICS_BACKEND_SETTINGS = {"feature_flags": {"summary-enabled": True}}
backend = get_analytics()
assert isinstance(backend, NoOpAnalytics)
assert (
backend.is_user_feature_enabled(
UserFactory(), UserFeatureFlag.TRANSCRIPT_SUMMARY_ENABLED
)
is True
)
@@ -6,7 +6,6 @@ from concurrent.futures import ThreadPoolExecutor
from urllib.parse import parse_qs, urlparse
from uuid import uuid4
from django.db import connection
from django.utils import timezone
import pytest
@@ -362,21 +361,18 @@ def test_api_files_create_file_race_condition():
"""
def create_item(title):
try:
user = factories.UserFactory()
client = APIClient()
client.force_login(user)
return client.post(
"/api/v1.0/files/",
{
"title": title,
"type": FileTypeChoices.BACKGROUND_IMAGE,
"filename": "my_file.png",
},
format="json",
)
finally:
connection.close()
user = factories.UserFactory()
client = APIClient()
client.force_login(user)
return client.post(
"/api/v1.0/files/",
{
"title": title,
"type": FileTypeChoices.BACKGROUND_IMAGE,
"filename": "my_file.png",
},
format="json",
)
with ThreadPoolExecutor(max_workers=2) as executor:
future1 = executor.submit(create_item, "my item 1")
@@ -5,7 +5,6 @@ from concurrent.futures import ThreadPoolExecutor
from io import BytesIO
from django.core.files.storage import default_storage
from django.db import connection
import pytest
from rest_framework.test import APIClient
@@ -296,12 +295,9 @@ def test_api_file_upload_ended_concurrent_calls_are_serialized(settings):
default_storage.save(file.temporary_file_key, BytesIO(b"my prose"))
def call_upload_ended():
try:
client = APIClient()
client.force_login(user)
return client.post(f"/api/v1.0/files/{file.id!s}/upload-ended/")
finally:
connection.close()
client = APIClient()
client.force_login(user)
return client.post(f"/api/v1.0/files/{file.id!s}/upload-ended/")
with ThreadPoolExecutor(max_workers=2) as executor:
futures = [
@@ -1,130 +0,0 @@
"""Unit tests for the opt-in psycopg connection pool settings."""
# pylint: disable=protected-access
from django.core.exceptions import ImproperlyConfigured
import pytest
from meet import settings
def make_configuration(**overrides):
"""Build a throwaway configuration with plain values and its own DATABASES."""
attributes = {
"DATABASES": {
"default": {
"ENGINE": "django.db.backends.postgresql",
"OPTIONS": {"sslmode": "require"},
}
},
"DB_PSYCOPG_POOL_ENABLED": True,
"DB_PSYCOPG_POOL_MIN_SIZE": 1,
"DB_PSYCOPG_POOL_MAX_SIZE": 3,
"DB_PSYCOPG_POOL_TIMEOUT": 30.0,
"DB_PSYCOPG_POOL_MAX_IDLE": 600.0,
**overrides,
}
return type("PoolConfiguration", (settings.Test,), attributes)
def test_database_pool_disabled_leaves_options_untouched():
"""Without the flag, no connection pool is configured."""
configuration = make_configuration(DB_PSYCOPG_POOL_ENABLED=False)
configuration._configure_database_pool()
assert configuration.DATABASES["default"]["OPTIONS"] == {"sslmode": "require"}
assert "CONN_HEALTH_CHECKS" not in configuration.DATABASES["default"]
def test_database_pool_enabled_merges_pool_options():
"""The pool and keepalive options are added next to the existing ones."""
configuration = make_configuration()
configuration._configure_database_pool()
assert configuration.DATABASES["default"]["OPTIONS"] == {
"sslmode": "require",
"keepalives_idle": 60,
"keepalives_interval": 10,
"keepalives_count": 5,
"pool": {"min_size": 1, "max_size": 3, "timeout": 30.0, "max_idle": 600.0},
}
def test_database_pool_enabled_keeps_explicit_keepalives():
"""Keepalive values already set, e.g. from DATABASE_URL, are not overridden."""
configuration = make_configuration(
DATABASES={
"default": {
"ENGINE": "django.db.backends.postgresql",
"OPTIONS": {"keepalives_idle": "30", "keepalives": "0"},
}
}
)
configuration._configure_database_pool()
options = configuration.DATABASES["default"]["OPTIONS"]
assert options["keepalives_idle"] == "30"
assert options["keepalives"] == "0"
assert options["keepalives_interval"] == 10
@pytest.mark.parametrize("health_checks", [None, False])
def test_database_pool_enabled_forces_health_checks(health_checks):
"""Pooled connections are checked on checkout, even if DATABASE_URL said no."""
database = {"ENGINE": "django.db.backends.postgresql"}
if health_checks is not None:
database["CONN_HEALTH_CHECKS"] = health_checks
configuration = make_configuration(DATABASES={"default": database})
configuration._configure_database_pool()
assert configuration.DATABASES["default"]["CONN_HEALTH_CHECKS"] is True
def test_database_pool_enabled_without_options():
"""A database without OPTIONS, as built from DATABASE_URL, gets them created."""
configuration = make_configuration(
DATABASES={"default": {"ENGINE": "django.db.backends.postgresql_psycopg2"}}
)
configuration._configure_database_pool()
assert configuration.DATABASES["default"]["OPTIONS"]["pool"]["max_size"] == 3
@pytest.mark.parametrize(
"overrides,match",
[
(
{"DATABASES": {"default": {"ENGINE": "django.db.backends.sqlite3"}}},
"requires the django.db.backends.postgresql engine",
),
(
{
"DATABASES": {
"default": {
"ENGINE": "django.db.backends.postgresql",
"CONN_MAX_AGE": 60,
}
}
},
"cannot be combined with persistent connections",
),
(
{"DB_PSYCOPG_POOL_MIN_SIZE": 6},
"MIN_SIZE cannot be greater than",
),
({"DB_PSYCOPG_POOL_TIMEOUT": 0.0}, "must be positive"),
({"DB_PSYCOPG_POOL_MAX_IDLE": -1.0}, "must be positive"),
],
)
def test_database_pool_invalid_configuration(overrides, match):
"""An invalid pool setup fails at boot."""
configuration = make_configuration(**overrides)
with pytest.raises(ImproperlyConfigured, match=match):
configuration._configure_database_pool()
+1 -64
View File
@@ -17,7 +17,6 @@ import warnings
from os import path
from socket import gethostbyname, gethostname
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import gettext_lazy as _
import dj_database_url
@@ -140,7 +139,7 @@ class Base(Configuration):
)
else {
"ENGINE": values.Value(
"django.db.backends.postgresql",
"django.db.backends.postgresql_psycopg2",
environ_name="DB_ENGINE",
environ_prefix=None,
),
@@ -155,21 +154,6 @@ class Base(Configuration):
"PORT": values.Value(5432, environ_name="DB_PORT", environ_prefix=None),
}
}
DB_PSYCOPG_POOL_ENABLED = values.BooleanValue(
False, environ_name="DB_PSYCOPG_POOL_ENABLED", environ_prefix=None
)
DB_PSYCOPG_POOL_MIN_SIZE = values.PositiveIntegerValue(
1, environ_name="DB_PSYCOPG_POOL_MIN_SIZE", environ_prefix=None
)
DB_PSYCOPG_POOL_MAX_SIZE = values.PositiveIntegerValue(
3, environ_name="DB_PSYCOPG_POOL_MAX_SIZE", environ_prefix=None
)
DB_PSYCOPG_POOL_TIMEOUT = values.FloatValue(
30.0, environ_name="DB_PSYCOPG_POOL_TIMEOUT", environ_prefix=None
)
DB_PSYCOPG_POOL_MAX_IDLE = values.FloatValue(
600.0, environ_name="DB_PSYCOPG_POOL_MAX_IDLE", environ_prefix=None
)
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
# Static files (CSS, JavaScript, Images)
@@ -1462,52 +1446,6 @@ class Base(Configuration):
stacklevel=2,
)
@classmethod
def _configure_database_pool(cls):
"""Inject the psycopg pool options into the default database when enabled."""
if not cls.DB_PSYCOPG_POOL_ENABLED:
return
database = cls.DATABASES["default"]
if database.get("ENGINE") not in (
"django.db.backends.postgresql",
"django.db.backends.postgresql_psycopg2",
):
raise ImproperlyConfigured(
"DB_PSYCOPG_POOL_ENABLED requires the django.db.backends.postgresql "
f"engine, got {database.get('ENGINE')!r}."
)
if database.get("CONN_MAX_AGE"):
raise ImproperlyConfigured(
"DB_PSYCOPG_POOL_ENABLED cannot be combined with persistent "
"connections; set CONN_MAX_AGE to 0."
)
if cls.DB_PSYCOPG_POOL_MIN_SIZE > cls.DB_PSYCOPG_POOL_MAX_SIZE:
raise ImproperlyConfigured(
"DB_PSYCOPG_POOL_MIN_SIZE cannot be greater than "
"DB_PSYCOPG_POOL_MAX_SIZE."
)
if cls.DB_PSYCOPG_POOL_TIMEOUT <= 0 or cls.DB_PSYCOPG_POOL_MAX_IDLE <= 0:
raise ImproperlyConfigured(
"DB_PSYCOPG_POOL_TIMEOUT and DB_PSYCOPG_POOL_MAX_IDLE must be positive."
)
database["OPTIONS"] = {
"keepalives_idle": 60,
"keepalives_interval": 10,
"keepalives_count": 5,
**database.get("OPTIONS", {}),
"pool": {
"min_size": cls.DB_PSYCOPG_POOL_MIN_SIZE,
"max_size": cls.DB_PSYCOPG_POOL_MAX_SIZE,
"timeout": cls.DB_PSYCOPG_POOL_TIMEOUT,
"max_idle": cls.DB_PSYCOPG_POOL_MAX_IDLE,
},
}
# The pool does not watch idle connections: check each one on checkout
# so a broken connection is replaced instead of failing the request.
database["CONN_HEALTH_CHECKS"] = True
@classmethod
def post_setup(cls):
"""Post setup configuration.
@@ -1522,7 +1460,6 @@ class Base(Configuration):
)
cls._check_recording_encoding_maps()
cls._configure_database_pool()
if (
cls.SUMMARY_SERVICE_VERSION == 1
+2 -2
View File
@@ -7,7 +7,7 @@ build-backend = "uv_build"
[project]
name = "meet"
version = "1.35.0"
version = "1.34.0"
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
classifiers = [
"Development Status :: 5 - Production/Stable",
@@ -51,7 +51,7 @@ dependencies = [
"markdown==3.10.3",
"nested-multipart-parser==1.6.0",
"posthog==7.44.0",
"psycopg[binary,pool]==3.3.4",
"psycopg[binary]==3.3.4",
"pydantic==2.13.4",
"PyJWT==2.14.0",
"python-frontmatter==1.3.0",
+3 -18
View File
@@ -1297,7 +1297,7 @@ wheels = [
[[package]]
name = "meet"
version = "1.35.0"
version = "1.34.0"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
@@ -1331,7 +1331,7 @@ dependencies = [
{ name = "nested-multipart-parser" },
{ name = "phonenumbers" },
{ name = "posthog" },
{ name = "psycopg", extra = ["binary", "pool"] },
{ name = "psycopg", extra = ["binary"] },
{ name = "pydantic" },
{ name = "pyjwt" },
{ name = "python-frontmatter" },
@@ -1396,7 +1396,7 @@ requires-dist = [
{ name = "nested-multipart-parser", specifier = "==1.6.0" },
{ name = "phonenumbers", specifier = "==9.0.37" },
{ name = "posthog", specifier = "==7.44.0" },
{ name = "psycopg", extras = ["binary", "pool"], specifier = "==3.3.4" },
{ name = "psycopg", extras = ["binary"], specifier = "==3.3.4" },
{ name = "pydantic", specifier = "==2.13.4" },
{ name = "pyjwt", specifier = "==2.14.0" },
{ name = "python-frontmatter", specifier = "==1.3.0" },
@@ -1875,9 +1875,6 @@ wheels = [
binary = [
{ name = "psycopg-binary", marker = "implementation_name != 'pypy'" },
]
pool = [
{ name = "psycopg-pool" },
]
[[package]]
name = "psycopg-binary"
@@ -1908,18 +1905,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/eb/e6/5fff07a70d1f945ed90ae131c3bd76cab32beff7c58c6db15ad5820b6d1f/psycopg_binary-3.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:c37e024c07308cd06cf3ec51bfd0e7f6157585a4d84d1bce4a7f5f7913719bf8", size = 3666849, upload-time = "2026-05-01T23:31:51.165Z" },
]
[[package]]
name = "psycopg-pool"
version = "3.3.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/74/5e/c0664b968b102ff68b811d999c728546c48d5c1eec03e3bbaf88c0cb4472/psycopg_pool-3.3.3.tar.gz", hash = "sha256:df87b5d9d0ad7db37f6cdad4fa8ce113d250f5997f6db38e9a99192fb67f9e1d", size = 32006, upload-time = "2026-09-22T15:53:24.947Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5d/b4/452c6607a0f479465cd8a9b0d9956919fcb150050c1f83f9f11e6b8ee8dc/psycopg_pool-3.3.3-py3-none-any.whl", hash = "sha256:9b9cd6a4fcec47a410f7e82d408540e7f77b478509e91b44c1a5457a13e5ff37", size = 40304, upload-time = "2026-09-22T15:53:23.712Z" },
]
[[package]]
name = "ptyprocess"
version = "0.7.0"
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "meet",
"version": "1.35.0",
"version": "1.34.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "meet",
"version": "1.35.0",
"version": "1.34.0",
"dependencies": {
"@fontsource-variable/atkinson-hyperlegible-next": "5.3.0",
"@fontsource-variable/lexend": "5.3.0",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "meet",
"private": true,
"version": "1.35.0",
"version": "1.34.0",
"type": "module",
"scripts": {
"dev": "panda codegen && vite",
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "mail_mjml",
"version": "1.35.0",
"version": "1.34.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mail_mjml",
"version": "1.35.0",
"version": "1.34.0",
"license": "MIT",
"dependencies": {
"@html-to/text-cli": "0.6.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "mail_mjml",
"version": "1.35.0",
"version": "1.34.0",
"description": "An util to generate html and text django's templates from mjml templates",
"type": "module",
"dependencies": {
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "sdk",
"version": "1.35.0",
"version": "1.34.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sdk",
"version": "1.35.0",
"version": "1.34.0",
"license": "ISC",
"workspaces": [
"./library",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "sdk",
"version": "1.35.0",
"version": "1.34.0",
"author": "",
"license": "ISC",
"description": "",
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "summary"
version = "1.35.0"
version = "1.34.0"
requires-python = ">=3.13"
dependencies = [
"fastapi[standard]>=0.105.0",
+1 -1
View File
@@ -1484,7 +1484,7 @@ wheels = [
[[package]]
name = "summary"
version = "1.35.0"
version = "1.34.0"
source = { editable = "." }
dependencies = [
{ name = "boto3" },