Находки в опенсорсе: Python
974 subscribers
4 photos
225 links
Легкие задачки в опенсорсе из мира Python

Чат: @opensource_findings_chat
Download Telegram
🚀 New issue to ag2ai/faststream by @ce1ebrimbor
📝 Feature: Support broker-level ack_policy default with per-subscriber override (#2826)


Problem

Currently ack_policy can only be set per-subscriber:

@broker.subscriber("orders.topic", ack_policy=AckPolicy.NACK_ON_ERROR)
async def handle_order(msg: OrderMessage) -> None:
...

There is no way to set a default ack_policy at the broker (or router) level. In practice, most services want the same policy across all subscribers — typically NACK_ON_ERROR for at-least-once delivery with DLQ. This forces every @broker.subscriber() call to repeat the same ack_policy= argument, which is error-prone: forgetting it on a single subscriber silently falls back to ACK_FIRST (at-most-once), which can cause silent message loss.

Proposed solution

Add an ack_policy parameter to KafkaBroker (and equivalently to RabbitBroker, NatsBroker, etc.) that sets the default for all subscribers registered on that broker. Individual subscribers can still override it.

broker = KafkaBroker("localhost:9092", ack_policy=AckPolicy.NACK_ON_ERROR)

# Inherits NACK_ON_ERROR from broker
@broker.subscriber("orders.topic")
async def handle_order(msg: OrderMessage) -> None:
...

# Overrides to ACK for this specific subscriber
@broker.subscriber("notifications.topic", ack_policy=AckPolicy.ACK)
async def handle_notification(msg: NotificationMessage) -> None:
...

The resolution order would be: subscriber-level > broker-level > built-in default (ACK_FIRST).

Why this matters
Safety: ACK_FIRST as a silent default is dangerous for services that use DLQ or need at-least-once delivery. A broker-level default lets teams enforce their delivery guarantee in one place.
DRY: Services with 10+ subscribers shouldn't need to repeat ack_policy=AckPolicy.NACK_ON_ERROR on every one.
Consistency with other broker-level settings: decoder, middlewares, security, and logger are all broker-level defaults that subscribers inherit. ack_policy is the notable exception.

#enhancement #good_first_issue #faststream #ag2ai
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Optimize `dmr_rf` and `dmr_client` test features for faster tests (#889)


We provide our own fixtures that are subclasses of Django's builtin one.

Django has this code inside: https://github.com/django/django/blob/7dc826b9758d634623a6f5ca05d0ca2048a0ce48/django/test/client.py#L450-L458

    def _encode_json(self, data, content_type):
"""
Return encoded JSON if data is a dict, list, or tuple and content_type
is application/json.
"""
should_encode = JSON_CONTENT_TYPE_RE.match(content_type) and isinstance(
data, (dict, list, tuple)
)
return json.dumps(data, cls=self.json_encoder) if should_encode else data

We need to optimize this method, because json.dumps is slow, but msgspec is fast.
It won't be noticable on 1 tests, but will be on 2k tests (which is the case for our own test base).

See how we conditionally dump our schema here: https://github.com/wemake-services/django-modern-rest/blob/master/dmr/openapi/dump.py

Maybe we should reuse the same for tests?


#good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Add `RefreshTokenSyncController` and `RefreshTokenAsyncController` (#907)


Add RefreshTokenSyncController and RefreshTokenAsyncController

Basically, they should accept refresh_token and return new pairs of access_token and refresh_token. But they should be reusable as well as the existing controllers.

It should be similar to the existing views:

django-modern-rest/dmr/security/jwt/views.py

Lines 99 to 132 in dba07e8

Example from a real project: https://github.com/Griger10/g-pulse/blob/3d520b8444736eaaeffad1cf2221019f3ffad6c4/services/api/apps/accounts/api/views.py#L93


#feature #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @Peopl3s
📝 TagSchema and RoleSchema do not enforce max_length, causing unhandled DB errors (#944)


What's wrong?

The Tag and Role Django models define name = CharField(max_length=100), but the corresponding Pydantic schemas accept any-length strings.

class TagSchema(pydantic.BaseModel):
name: str <!-----------------------------HERE

class RoleSchema(pydantic.BaseModel):
name: str <!-----------------------------HERE

When a client sends a name longer than 100 characters, Pydantic validation passes (HTTP 422 is never raised), and the value reaches the database layer where PostgreSQL raises DataError: value too long for type character varying(100). This results in an unhandled 500 instead of a proper 422 validation error. On SQLite the value is silently stored without truncation, masking the bug in tests.

How it should be?

Add max_length constraints to match the model definition:

                                                                                                                                                                                                            class TagSchema(pydantic.BaseModel):                  
name: str = Field(max_length=100)
class RoleSchema(pydantic.BaseModel):
name: str = Field(max_length=100)

Used versions

0.7.0

OS information

MacOS


#bug #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Test `Valkey` support (#980)


Currently we only test redis as the database for SyncRedis and AsyncRedis throttling backends. We also need to test Valkey, because we claim to support it.


#good_first_issue #help_wanted #ci #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Convert our `Empty` class usage to `typing_extensions.Sentinel` (#995)


Current way:

django-modern-rest/dmr/types.py

Lines 48 to 55 in 5ca7975

New (modern) way: https://typing-extensions.readthedocs.io/en/latest/#typing_extensions.Sentinel

1. We need to change how EmptyObj is defined to be EMPTY: Final = Sentinel('EMPTY')
2. We need to change all isinstance(..., Empty) to check for the sentinel

This is a very easy task for new contributors :)


#feature #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to ag2ai/faststream by @zueve
📝 Bug: (#2868)


Describe the bug
Can't forward client_rack to aiokafka consumer through FastStream Kafka API.

How to reproduce
Include source code:

from faststream import FastStream

from faststream.kafka import KafkaBroker

# Attempt to configure at broker level

broker = KafkaBroker(
"localhost:9092",
client_rack="us-east-1a", # not supported
)
app = FastStream(broker)

And/Or steps to reproduce the behaviour:

1. Create a KafkaBroker.
2. Try to pass client_rack to the broker constructor.
3. Observe that the parameter is not accepted.
4. There is no alternative way to configure it via subscriber(...) either.

Expected behavior
KafkaBroker should allow passing client_rack (or generic consumer kwargs) and forward it to the underlying aiokafka.AIOKafkaConsumer.

Observed behavior
client_rack is not supported in KafkaBroker constructor, nor in subscriber configuration, so it cannot be passed to aiokafka.

Screenshots
N/A.

Environment
Running FastStream 0.6.7 with CPython 3.14.5 on Linux

Additional context
aiokafka.AIOKafkaConsumer supports client_rack since 0.14.0 version


#bug #good_first_issue #aiokafka #faststream #ag2ai
sent via relator
🚀 New issue to ag2ai/faststream by @dzeveloper
📝 Feature: Consumer-Only Mode for KafkaBroker (#2879)


When deploying a subscriber-only service, it's common to provision Kafka credentials scoped strictly to READ + DESCRIBE ACLs on specific topics. Today, KafkaBroker always starts a producer during broker.start(), regardless of whether any @broker.publisher is registered. This causes the producer to attempt a connection using consumer-only credentials, which fails or raises errors at the broker/ACL level.

Proposal:

# Option A: broker-level flag
broker = KafkaBroker("localhost:9092", consumer_only=True)

# Option B: skip producer if no publishers are registered (automatic)
# No API change needed — broker inspects registered publishers at start()


#enhancement #good_first_issue #confluent #aiokafka #faststream #ag2ai
sent via relator
👍1
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Flaky test: `test_redis_sync_leaky_bucket` (#1043)


Output:

 ______________________ test_redis_sync_leaky_bucket[True] ______________________
tests/test_integration/test_throttling/test_backends/test_redis_backend/test_redis_backend.py:110: in test_redis_sync_leaky_bucket
assert response.status_code == HTTPStatus.TOO_MANY_REQUESTS
E assert 200 == <HTTPStatus.TOO_MANY_REQUESTS: 429>
E + where 200 = <HttpResponse status_code=200, "application/json">.status_code
E + and <HTTPStatus.TOO_MANY_REQUESTS: 429> = HTTPStatus.TOO_MANY_REQUESTS
================================ tests coverage ================================

=========================== short test summary info ============================
FAILED tests/test_integration/test_throttling/test_backends/test_redis_backend/test_redis_backend.py::test_redis_sync_leaky_bucket[True] - assert 200 == <HTTPStatus.TOO_MANY_REQUESTS: 429>
+ where 200 = <HttpResponse status_code=200, "application/json">.status_code
+ and <HTTPStatus.TOO_MANY_REQUESTS: 429> = HTTPStatus.TOO_MANY_REQUESTS
============ 1 failed, 2479 passed, 10 skipped in 243.50s (0:04:03) ============


It fails from time to time: https://github.com/wemake-services/django-modern-rest/actions/runs/26490639540/job/78007463856?pr=1042


#bug #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Flaky test: `test_sse_ping_with_last` (#1046)


Happened on mypyc wheels cp314-macosx_x86_64

  =================================== FAILURES ===================================
___________________________ test_sse_ping_with_last ____________________________

dmr_async_rf = <dmr.test.DMRAsyncRequestFactory object at 0x114ddad60>

@pytest.mark.asyncio
async def test_sse_ping_with_last(
dmr_async_rf: DMRAsyncRequestFactory,
) -> None:
"""Ensures that valid sse produces valid results."""
request = dmr_async_rf.post('/whatever/', data={'produce_last': True})

response = await dmr_async_rf.wrap(_PingSSE.as_view()(request))

assert isinstance(response, StreamingResponse)
assert response.streaming
assert response.status_code == HTTPStatus.OK
assert response.headers == {
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
'X-Accel-Buffering': 'no',
'Connection': 'keep-alive',
}
> assert await get_streaming_content(response) == (
b'data: 1\r\n'
b'\r\n'
b': ping\r\n'
b'\r\n'
b'data: 2\r\n'
b'\r\n'
b': ping\r\n'
b'\r\n'
b': ping\r\n'
b'\r\n'
b'data: 3\r\n'
b'\r\n'
)
E AssertionError: assert b'data: 1\r\n...ta: 3\r\n\r\n' == b'data: 1\r\n...ta: 3\r\n\r\n'
E
E At index 42 diff: b'd' != b':'
E
E Full diff:
E - (b'data: 1\r\n\r\n: ping\r\n\r\ndata: 2\r\n\r\n: ping\r\n\r\n: ping\r\n\r\ndata'
E ? --------------
E + (b'data: 1\r\n\r\n: ping\r\n\r\ndata: 2\r\n\r\n: ping\r\n\r\ndata: 3\r\n\r\n')
E ? +++++++++++ +
E - b': 3\r\n\r\n')

For some reason data: 3 was not sent.
Let's fix it.


#bug #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Add default admin page for `dmr/security/jwt/blocklist` (#1054)


Right now our app for jwt blocklisting has a default model: https://github.com/wemake-services/django-modern-rest/blob/master/dmr/security/jwt/blocklist/models.py

But, it does not have a default admin.py file.
Good example: https://github.com/Dresdn/django-modern-rest/blob/3324d0aecf32509b5434df7e8826d7be6ddac7a8/dmr/security/token/admin.py

This is a very easy task :)


#feature #good_first_issue #help_wanted #django_modern_rest
sent via relator
«Институт логики» приглашает разработчиков свободного ПО на конкурс «Код логики»

Стартовал первый этап конкурса Open-Source-проектов разработчиков свободного программного обеспечения «Код логики». Конкурс проводится при финансовой поддержке «Базальт СПО» и частных лиц.
Организатор конкурса — АНО «Институт логики, когнитологии и развития личности».
Кто может участвовать: физические лица — разработчики свободного ПО, граждане РФ старше 18 лет, налоговые резиденты.
Что нужно сделать: предоставить значимый вклад в существующий Open-Source-проект, опубликованный в публичном репозитории под свободной лицензией. Вклад может быть сделан в свой или сторонний проект.
Призовой фонд: денежные премии. Всего 3 призовых места, максимальное количество победителей — до 6 человек. Победитель получит 1 000 000 рублей.
Сроки: заявки принимаются до 15 августа 2026 года на сайте института.
Награждение победителей состоится 2–4 октября на XXII ежегодной конференции разработчиков свободных программ.
Подробности об условиях конкурса доступны на сайте: https://logic.ru/
На протяжении 35 лет институт поддерживает разработчиков свободного ПО и образовательные технологии. Институт развивался как академическая площадка на стыке логики, искусственного интеллекта, образования и моделирования мышления. Миссия АНО «Институт логики» — помогать исследователям, специалистам и учебным учреждениям реализовывать проекты, влияющие на развитие технологий. Конкурс Open-Source-проектов разработчиков свободного программного обеспечения — часть этой работы.

Ссылка: https://logic.ru/
👍2
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 `test_user_create_models_example` is flaky (#1089)


Please fix it :)

=========================== short test summary info ============================
FAILED tests/test_integration/test_model_fk/test_model_fk.py::test_user_create_models_example[False] - AssertionError: assert {'email': 'jd... 'id': 1, ...} == {'email': 'jd...itiveInt, ...}

Omitting 4 identical items, use -vv to show
Differing items:
{'tags': [{'name': 'Jessica Johnson'}]} != {'tags': IsList({'name': 'Jessica Johnson'}, {'name': 'Jessica Johnson'}, check_order=False)}

Full diff:
{
'email': 'jdominguez@example.com',
'role': {
'name': 'Jason Burgess',
},
- 'tags': IsList({'name': 'Jessica Johnson'}, {'name': 'Jessica Johnson'}, check_order=False),
- 'id': IsPositiveInt,
+ 'tags': [
+ {
+ 'name': 'Jessica Johnson',
+ },
+ ],
+ 'id': 1,
'created_at': '2026-06-19T10:39:36.779795Z',
}
============ 1 failed, 2506 passed, 10 skipped in 268.28s (0:04:28) ============


https://github.com/wemake-services/django-modern-rest/actions/runs/27820624206/job/82332576787


#bug #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Setup `lychee` link check tool for `pre-commit` (#1094)


It allows checking that all links are actually valid.
This will helps us finding dead / renamed links in the docs / code.

Hooks: https://github.com/lycheeverse/lychee/blob/master/.pre-commit-hooks.yaml
Docs: https://lychee.cli.rs/
Example config: https://github.com/msgspec/msgspec/blob/main/lychee.toml (but I would prefer to have it in the same folder as zizmor config is).


#documentation #feature #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @ZhdanovAM72
📝 Add a built-in JWT access token verification flow. (#1129)


FEATURE

Thesis

Add a built-in JWT access token verification flow.

For example, django-modern-rest could provide a reusable controller:

from dmr.security.jwt.views import VerifyTokenSyncController


class TokenVerifyController(VerifyTokenSyncController):
pass

Expected behavior:

• accept an encoded token from the request body
• decode and validate the JWT
• reject malformed tokens
• reject expired tokens
• reject refresh tokens when an access token is expected
• verify that the token subject belongs to an existing active user
• return a successful empty response when the token is valid

The exact public API can be different. It could be implemented as a controller,
auth class, or reusable JWT verification component.

Reasoning

django-modern-rest already provides JWT obtain and refresh controllers, but
applications commonly also need a token verification endpoint.

Without built-in support, each project has to implement the same logic manually:

from django.conf import settings
from dmr.exceptions import NotAuthenticatedError
from dmr.security.jwt.token import JWToken


token = JWToken.decode(
encoded_token=encoded_token,
secret=str(settings.SECRET_KEY),
algorithm="HS256",
)

if token.extras.get("type") != "access":
raise NotAuthenticatedError

user = User.objects.get(pk=token.sub)

if not user.is_active:
raise NotAuthenticatedError

This logic is not application-specific. It is part of the common JWT API
surface.

Providing it in django-modern-rest would reduce duplication and make JWT support
more complete. It would also make error handling more consistent with the
existing obtain and refresh controllers.


#feature #good_first_issue #help_wanted #django_modern_rest
sent via relator