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

Чат: @opensource_findings_chat
Download Telegram
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Translate `django-modenr-rest` to your native language! (#718)


Docs: https://docs.djangoproject.com/en/6.0/topics/i18n/

How to do it?

1. Run poetry install --all-groups --all-extras
2. Run poetry run django-admin makemessages -l YOUR_LOCALE, for example: poetry run django-admin makemessages -l ru_RU, full list of locales: https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes
3. Translate the new file created in dmr/locale/YOUR_LOCALE/LC_MESSAGES/django.po
4. Run poetry run django-admin compilemessages
5. Done! You are awesome, submit the PR :)

We welcome all contributions!


#enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Support `openapi.yaml` (#745)


Litestar supports openapi.yaml view, so should we: https://docs.litestar.dev/latest/usage/openapi/ui_plugins.html

It should be only available if msgspec is installed, it can dump yaml with msgspec.yaml.
Everything else should be identical to openapi.json view.

This is a rather easy task, so new contributors are very welcome!


#documentation #good_first_issue #help_wanted #django_modern_rest
sent via relator
🔥1
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Test `Controller[BaseSerializer]` corner case (#749)


Currently we don't test that Controller[BaseSerializer] is not a valid way of creating a controller class.
It must accept subclasses for BaseSerializer, but not BaseSerializer itself.

We need:

• a test case here https://github.com/wemake-services/django-modern-rest/blob/master/tests/test_unit/test_controllers/test_extend_controller.py
• a possible fix to raise an error when BaseSerializer is given to a controller here:

 django-modern-rest/dmr/controller.py

 Lines 157 to 164 in acb9c17

This is a very easy task, so new contributors are very welcome!


#bug #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Support `Path` with `*args` (#754)


Right now Path component only supports parsing from request.kwargs. Which is like 99% of cases.
However, parsing from request.args is not supported:

django-modern-rest/dmr/components.py

Lines 655 to 662 in b3f9c08

What should we do instead?

1. When request.args is provided we should require models like:

>>> import pydantic
>>> class UserId(pydantic.BaseModel):
... user_id: int

>>> PathModel = pydantic.RootModel[tuple[tuple[int, ...], UserId]]

>>> PathModel.model_validate((('1', '2', '3'), {'user_id': 10}))
RootModel[tuple[tuple[int, ...], UserId]](root=((1, 2, 3), UserId(user_id=10)))

1. We would return tuple[Args, Kwargs] from this component if request.args is set
2. Test this with unnamed re_path urls https://docs.djangoproject.com/en/6.0/topics/http/urls/#using-unnamed-regular-expression-groups
3. Test this in tests/test_unit/test_components/test_path.py
4. Document this feature in docs/pages/components/path.rst
5. Provide an example in docs/examples/components/path_args.py and include it to path.rst
6. Provide a changelog entry
7. Remove _UNNAMED_PATH_PARAMS_MSG and all translations of this string, recompile all translations with make translations

Contributions are welcome! This is an intermediate level task :)


#enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Use the latest django version by default (#759)


Currently we use 5.2 by default:

django-modern-rest/pyproject.toml

Line 77 in bea5f2d

But, we need to use the latest one. Which is 6.0.
Also, we would need to change this CI job to use 5.2 instead:

django-modern-rest/.github/workflows/test.yml

Lines 71 to 78 in bea5f2d


#good_first_issue #help_wanted #django_modern_rest
sent via relator
1
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Provide our own `settings` fixture (#760)


When using settings fixture from pytest-django we frequently change them.
However, we have dmr_clean_settings fixture, which should be use when we touch our own settings.

So, let's add a new fixture to dmr_pytest.py which will return unchanged settings: LazySettings, but will also use dmr_clean_settings.

Also, remove all dmr_clean_settings from our own tests, where settings is used.


#enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Provide `dmr.cookies.set_cookies` helper function (#773)


Currently we have two places where we duplicate this code:

django-modern-rest/dmr/streaming/controller.py

Lines 172 to 178 in a6bc356

and

django-modern-rest/dmr/response.py

Lines 256 to 259 in a6bc356

So, it can probably be useful to others as well.
Let's move this to cookies.py as a public helper function.

Also, document it in public-api.rst

This is a very easy task for new contributors.


#enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Test and declare officail `NamedTuple` support (#774)


Here's the code:

>>> from typing import NamedTuple
>>> class A(NamedTuple):
... x: int
... y: int
...
>>> import pydantic
>>> pydantic.TypeAdapter(A).validate_python({'x': 1, 'y': 2})
A(x=1, y=2)
>>> pydantic.TypeAdapter(A).validate_python({'x': 1, 'y': 'a'})
Traceback (most recent call last):
File "<python-input-11>", line 1, in <module>
pydantic.TypeAdapter(A).validate_python({'x': 1, 'y': 'a'})
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "/Users/sobolev/Desktop/django-modern-rest/.venv/lib/python3.13/site-packages/pydantic/type_adapter.py", line 441, in validate_python
return self.validator.validate_python(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
object,
^^^^^^^
...<6 lines>...
by_name=by_name,
^^^^^^^^^^^^^^^^
)
^
pydantic_core._pydantic_core.ValidationError: 1 validation error for call[A]
y
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
For further information visit https://errors.pydantic.dev/2.12/v/int_parsing

As we can see, NamedTuple models work well with pydantic. So, here's what we need to do:

1. Add a test case to test_plugins/test_pydantic that it works with NamedTuple
2. Add a doc example here https://django-modern-rest.readthedocs.io/en/latest/pages/getting-started.html#showcase
3. Add a changelog entry, that it is now officially supported

We welcome new contributors :)


#enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🔥1
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Add docs and example about `django-health-check` integration (#831)


One can use https://github.com/codingjoe/django-health-check for health checks.
No special integration from our side is required.

This information can be added here: https://github.com/wemake-services/django-modern-rest/blob/master/docs/pages/integrations.rst


#documentation #enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Support `orjson` as a possible backend for `JsonParser` / `JsonRenderer` (#857)


Currently we always use json as a module in JsonParser and JsonRenderer:

django-modern-rest/dmr/parsers.py

Lines 132 to 134 in 69822ff

But, we can make this module customizable. We can pass orjson module there, since it also has a similar API.

Something like:

class JsonParser(Parser):
__slots__ = ('_json_module', ...)
def __init__(self, json_module: _JsonModule = json, ...) -> None:
self._json_module = json_module

And later self._json_module.loads(...)

This would need multiple test cases: install orjson as unit-test dependency and add unit tests for this new renderer / parser.
And we can document that with an example in the integrations.rst docs.


#enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @sobolevn
📝 Add a Django command to export OpenAPI schemas (#858)


It migth be useful to people who want to share the schema. Or automate something with it.

I propose to add a django command: dmr_export_schema.
Args:

• Where to find schema, I think we should reuse import_string logic from Django. Required
• All json formatting ones: sort_keys and indent
• Format: json or yaml, check that yaml is installed. Default is json

We should print it to the stdout always. Usages:

# regular:
python manage.py dmr_export_schema server.urls:schema

# pretty:
python manage.py dmr_export_schema server.urls:schema --format json --indent=2 --sort-keys

This would need tests, we can test it as a subprocess, it is a django command after all.
And docs.


#enhancement #good_first_issue #help_wanted #django_modern_rest
sent via relator
🚀 New issue to wemake-services/django-modern-rest by @LesPrimus
📝 UnsolvableAnnotationsError when subclassing a concrete Controller subclass` (#873)


What's wrong?

Bug: UnsolvableAnnotationsError when subclassing a concrete Controller subclass

Description

When creating an intermediate concrete controller class and then subclassing it,
__init_subclass__ raises UnsolvableAnnotationsError even though the serializer
is already resolved on the parent.

Reproduction

from dmr import Controller
from dmr.plugins.pydantic import PydanticSerializer
from dmr.serializer import BaseSerializer


class BaseController[T: BaseSerializer](Controller[T]):
pass


class PydanticController(BaseController[PydanticSerializer]):
pass


# This raises UnsolvableAnnotationsError
class UserController(PydanticController):
def get(self) -> ...:
...

Error

dmr.exceptions.UnsolvableAnnotationsError: Type args () are not correct for <class 'UserController'>,
at least 1 type arg must be provided

Expected behavior

UserController should inherit the serializer from its concrete parent PydanticController,
which already has serializer = PydanticSerializer set.


--

Thanks for the awesome library, I just started exploring it and I'm really enjoying it so far!

--

### How it should be?

Subclassing a concrete `Controller` subclass (one that already has a resolved serializer)
should work without requiring the type argument to be re-specified.

`UserController(PydanticController)` should behave the same as `UserController(BaseController[PydanticSerializer])`.

### Used versions

- `django-modern-rest==0.5.0`
- `Python 3.14.0`

### OS information

- `Linux tuxedo-stellaris 6.17.0-111019-tuxedo x86_64 (Ubuntu 24.04)`


#bug #good_first_issue #help_wanted #django_modern_rest
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 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