diff --git a/.pylintrc b/.pylintrc index ae85523c..1205f857 100644 --- a/.pylintrc +++ b/.pylintrc @@ -104,10 +104,6 @@ recursive=no # source root. source-roots= -# When enabled, pylint would attempt to guess common misconfiguration and emit -# user-friendly hints instead of false-positive error messages. -suggestion-mode=yes - # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no @@ -234,6 +230,11 @@ name-group= # not require a docstring. no-docstring-rgx=^_ +# Regular expression matching correct parameter specification variable names. +# If left empty, parameter specification variable names will be checked with +# the set naming style. +#paramspec-rgx= + # List of decorators that produce properties, such as abc.abstractproperty. Add # to this list to register other decorators that produce valid properties. # These decorators are taken in consideration only for invalid-name. @@ -247,6 +248,10 @@ property-classes=abc.abstractproperty # variable names will be checked with the set naming style. #typevar-rgx= +# Regular expression matching correct type variable tuple names. If left empty, +# type variable tuple names will be checked with the set naming style. +#typevartuple-rgx= + # Naming style matching correct variable names. variable-naming-style=snake_case @@ -344,7 +349,9 @@ indent-after-paren=4 # tab). indent-string=' ' -# Maximum number of characters on a single line. +# Maximum number of characters on a single line. Pylint's default of 100 is +# based on PEP 8's guidance that teams may choose line lengths up to 99 +# characters. max-line-length=120 # Maximum number of lines in a module. @@ -456,6 +463,9 @@ timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests. [MISCELLANEOUS] +# Whether or not to search for fixme's in docstrings. +check-fixme-in-docstring=no + # List of note tags to take in consideration, separated by a comma. notes=FIXME, XXX, diff --git a/object_storage_api/auth/jwt_middleware.py b/object_storage_api/auth/jwt_middleware.py index 658055b0..13d4bbb1 100644 --- a/object_storage_api/auth/jwt_middleware.py +++ b/object_storage_api/auth/jwt_middleware.py @@ -48,7 +48,7 @@ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) - if not self._is_jwt_access_token_valid(credentials.credentials): return JSONResponse( - status_code=status.HTTP_403_FORBIDDEN, content={"detail": "Invalid token or expired token"} + status_code=status.HTTP_401_UNAUTHORIZED, content={"detail": "Invalid token or expired token"} ) return await call_next(request) diff --git a/pyproject.toml b/pyproject.toml index 05d09e43..3f04fbe6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,21 +19,21 @@ dependencies = [ [project.optional-dependencies] code-analysis = [ - "black==25.9.0", - "pylint==3.3.9", + "black==26.1.0", + "pylint==4.0.5", "object-storage-api[test]" ] test = [ - "pytest==8.4.2", - "pytest-asyncio==1.2.0", + "pytest==9.0.2", + "pytest-asyncio==1.3.0", "pytest-cov==7.0.0", - "pytest-env==1.2.0", + "pytest-env==1.5.0", "requests==2.32.5" ] scripts = [ - "faker==37.12.0", + "faker==40.4.0", "faker-file[pdf,docx,images]==0.18.4", ] diff --git a/requirements.txt b/requirements.txt index 88300fad..da65a5f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,17 +1,18 @@ -annotated-doc==0.0.3 +annotated-doc==0.0.4 annotated-types==0.7.0 -anyio==4.11.0 +anyio==4.12.1 boto3==1.35.99 botocore==1.35.99 -certifi==2025.10.5 +certifi==2026.1.4 cffi==2.0.0 -click==8.3.0 -cryptography==46.0.3 +click==8.3.1 +cryptography==46.0.5 dnspython==2.8.0 email-validator==2.3.0 -fastapi==0.120.2 -fastapi-cli==0.0.14 -fastapi-cloud-cli==0.3.1 +fastapi==0.129.0 +fastapi-cli==0.0.23 +fastapi-cloud-cli==0.13.0 +fastar==0.8.0 h11==0.16.0 httpcore==1.0.9 httptools==0.7.1 @@ -19,39 +20,38 @@ httpx==0.28.1 idna==3.11 itsdangerous==2.2.0 Jinja2==3.1.6 -jmespath==1.0.1 +jmespath==1.1.0 markdown-it-py==4.0.0 MarkupSafe==3.0.3 mdurl==0.1.2 -orjson==3.11.4 -pillow==12.0.0 -pycparser==2.23 -pydantic==2.12.3 -pydantic-extra-types==2.10.6 -pydantic-settings==2.11.0 -pydantic_core==2.41.4 +orjson==3.11.7 +pillow==12.1.1 +pycparser==3.0 +pydantic==2.12.5 +pydantic-extra-types==2.11.0 +pydantic-settings==2.13.1 +pydantic_core==2.41.5 Pygments==2.19.2 -PyJWT==2.10.1 -pymongo==4.15.3 +PyJWT==2.11.0 +pymongo==4.16.0 python-dateutil==2.9.0.post0 python-dotenv==1.2.1 -python-multipart==0.0.20 +python-multipart==0.0.22 PyYAML==6.0.3 -rich==14.2.0 -rich-toolkit==0.15.1 -rignore==0.7.2 +rich==14.3.3 +rich-toolkit==0.19.4 +rignore==0.7.6 s3transfer==0.10.4 -sentry-sdk==2.43.0 +sentry-sdk==2.53.0 shellingham==1.5.4 six==1.17.0 -sniffio==1.3.1 -starlette==0.49.1 -typer==0.20.0 +starlette==0.52.1 +typer==0.24.0 typing-inspection==0.4.2 typing_extensions==4.15.0 ujson==5.11.0 -urllib3==2.6.0 -uvicorn==0.38.0 +urllib3==2.6.3 +uvicorn==0.41.0 uvloop==0.22.1 watchfiles==1.1.1 -websockets==15.0.1 +websockets==16.0 diff --git a/test/e2e/test_jwt_middleware.py b/test/e2e/test_jwt_middleware.py index 048f1e3b..92dabf2e 100644 --- a/test/e2e/test_jwt_middleware.py +++ b/test/e2e/test_jwt_middleware.py @@ -55,7 +55,7 @@ def test_jwt_middleware_allows_authenticated_request(test_client): ), pytest.param( {"Authorization": f"Invalid-Bearer {VALID_ACCESS_TOKEN}"}, - "Invalid authentication credentials", + "Not authenticated", id="invalid_authorization_scheme", ), ], @@ -72,7 +72,7 @@ def test_jwt_middleware_denies_unauthenticated_requests(test_client, headers, ex for method in ["GET", "DELETE", "PATCH", "POST", "PUT"]: if method in api_route.methods: response = test_client.request(method, api_route.path, headers=headers) - assert response.status_code == 403 + assert response.status_code == 401 assert response.json()["detail"] == expected_response_message diff --git a/test/unit/stores/test_image.py b/test/unit/stores/test_image.py index 6caa0b47..c95ec307 100644 --- a/test/unit/stores/test_image.py +++ b/test/unit/stores/test_image.py @@ -218,7 +218,7 @@ def call_create_presigned_get(self) -> None: `mock_create_presigned_get`. """ - (self._obtained_presigned_view_url, self._obtained_presigned_download_url) = ( + self._obtained_presigned_view_url, self._obtained_presigned_download_url = ( self.image_store.create_presigned_get(self._image_out) )