session-adapters 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. session_adapters-0.4.0/.env +1 -0
  2. session_adapters-0.4.0/.github/dependabot.yml +28 -0
  3. {session_adapters-0.2.0 → session_adapters-0.4.0}/.gitignore +1 -0
  4. session_adapters-0.4.0/CHANGELOG.md +64 -0
  5. {session_adapters-0.2.0 → session_adapters-0.4.0}/PKG-INFO +21 -6
  6. {session_adapters-0.2.0 → session_adapters-0.4.0}/README.md +19 -3
  7. {session_adapters-0.2.0 → session_adapters-0.4.0}/Taskfile.yaml +8 -13
  8. {session_adapters-0.2.0 → session_adapters-0.4.0}/pyproject.toml +1 -2
  9. {session_adapters-0.2.0 → session_adapters-0.4.0}/src/session_adapters/__about__.py +1 -1
  10. {session_adapters-0.2.0 → session_adapters-0.4.0}/src/session_adapters/base.py +5 -9
  11. session_adapters-0.4.0/src/session_adapters/bearer_auth_http_adapter.py +31 -0
  12. session_adapters-0.4.0/tests/__init__.py +13 -0
  13. {session_adapters-0.2.0 → session_adapters-0.4.0}/tests/conftest.py +13 -0
  14. {session_adapters-0.2.0 → session_adapters-0.4.0}/tests/test_base_adapter.py +13 -0
  15. session_adapters-0.4.0/tests/test_bearer_auth_http_adapter.py +36 -0
  16. {session_adapters-0.2.0 → session_adapters-0.4.0}/tests/test_file_adapter.py +13 -0
  17. {session_adapters-0.2.0 → session_adapters-0.4.0}/tests/test_oci_adapter.py +14 -0
  18. {session_adapters-0.2.0 → session_adapters-0.4.0}/tests/test_s3_adapter.py +14 -0
  19. session_adapters-0.2.0/tests/__init__.py +0 -3
  20. {session_adapters-0.2.0 → session_adapters-0.4.0}/.github/workflows/package.yaml +0 -0
  21. {session_adapters-0.2.0 → session_adapters-0.4.0}/LICENSE +0 -0
  22. {session_adapters-0.2.0 → session_adapters-0.4.0}/src/session_adapters/__init__.py +0 -0
  23. {session_adapters-0.2.0 → session_adapters-0.4.0}/src/session_adapters/file_adapter.py +0 -0
  24. {session_adapters-0.2.0 → session_adapters-0.4.0}/src/session_adapters/http_conts.py +0 -0
  25. {session_adapters-0.2.0 → session_adapters-0.4.0}/src/session_adapters/oci_adapter.py +0 -0
  26. {session_adapters-0.2.0 → session_adapters-0.4.0}/src/session_adapters/s3_adapter.py +0 -0
@@ -0,0 +1 @@
1
+ TASK_X_REMOTE_TASKFILES=1
@@ -0,0 +1,28 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ version: 2
16
+
17
+ updates:
18
+ - package-ecosystem: "pip"
19
+ directory: "/"
20
+ schedule:
21
+ interval: "daily"
22
+ open-pull-requests-limit: 10
23
+ commit-message:
24
+ prefix: "build"
25
+ labels:
26
+ - "dependencies"
27
+ allow:
28
+ - dependency-type: "direct"
@@ -1,2 +1,3 @@
1
+ .task
1
2
  .venv
2
3
  __pycache__
@@ -0,0 +1,64 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ ### Changed
13
+
14
+ ### Deprecated
15
+
16
+ ### Removed
17
+
18
+ ### Fixed
19
+
20
+ ### Security
21
+
22
+ ## [0.4.0] - 2026-07-15
23
+
24
+ ### Added
25
+
26
+ - Add `BearerAuthHTTPAdapter` to attach a bearer token to HTTP requests.
27
+
28
+ ## [0.3.0] - 2026-04-14
29
+
30
+ ### Changed
31
+
32
+ - Replace `python-magic` MIME detection with the Python standard library's
33
+ `mimetypes` module, removing the external `libmagic` runtime dependency.
34
+
35
+ ### Fixed
36
+
37
+ - Fix file response MIME detection in environments where `libmagic` is not
38
+ available or does not work.
39
+
40
+ ## [0.2.0] - 2026-03-23
41
+
42
+ ### Changed
43
+
44
+ - Create an OCI client for each request and log out after the request completes.
45
+ - Retry OCI operations anonymously when the authenticated login or handshake is
46
+ rejected.
47
+
48
+ ## [0.1.0] - 2026-03-06
49
+
50
+ ### Added
51
+
52
+ - Add `requests` transport adapters for local files, Amazon S3 objects, and OCI
53
+ registry artifacts.
54
+ - Support `GET`, `HEAD`, `PUT`, and `DELETE` operations across the adapters.
55
+ - Support S3 range, object version, delimiter, and maximum-key query options.
56
+ - Support OCI tag and digest references, optional registry authentication, and
57
+ configurable registry hostnames.
58
+ - Support Python 3.10 through 3.14, including CPython and PyPy.
59
+
60
+ [unreleased]: https://github.com/Terradue/session-adapters/compare/v0.4.0...HEAD
61
+ [0.4.0]: https://github.com/Terradue/session-adapters/compare/v0.3.0...v0.4.0
62
+ [0.3.0]: https://github.com/Terradue/session-adapters/compare/v0.2.0...v0.3.0
63
+ [0.2.0]: https://github.com/Terradue/session-adapters/compare/v0.1.0...v0.2.0
64
+ [0.1.0]: https://github.com/Terradue/session-adapters/releases/tag/v0.1.0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: session-adapters
3
- Version: 0.2.0
4
- Summary: Requests transport adapters for file://, s3://, and oci:// URLs.
3
+ Version: 0.4.0
4
+ Summary: Requests transport adapters for bearer-authenticated `http(s)://`, `file://`, `s3://`, and `oci://` URLs.
5
5
  Project-URL: Documentation, https://github.com/Terradue/session-adapters#README.md
6
6
  Project-URL: Issues, https://github.com/Terradue/session-adapters/issues
7
7
  Project-URL: Source, https://github.com/Terradue/session-adapters
@@ -22,7 +22,6 @@ Requires-Dist: boto3
22
22
  Requires-Dist: loguru
23
23
  Requires-Dist: oras
24
24
  Requires-Dist: pydantic
25
- Requires-Dist: python-magic
26
25
  Description-Content-Type: text/markdown
27
26
 
28
27
  # session-adapters
@@ -30,12 +29,15 @@ Description-Content-Type: text/markdown
30
29
  [![PyPI - Version](https://img.shields.io/pypi/v/session-adapters.svg)](https://pypi.org/project/session-adapters)
31
30
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/session-adapters.svg)](https://pypi.org/project/session-adapters)
32
31
 
33
- Requests transport adapters for `file://`, `s3://`, and `oci://` URLs.
32
+ Requests transport adapters for bearer-authenticated `http(s)://`, `file://`,
33
+ `s3://`, and `oci://` URLs.
34
34
 
35
35
  ## Why This Project
36
36
 
37
- `session-adapters` lets you use a standard `requests.Session` with non-HTTP backends:
37
+ `session-adapters` lets you use a standard `requests.Session` with authenticated
38
+ HTTP requests and non-HTTP backends:
38
39
 
40
+ - `http://` and `https://` with bearer token authentication
39
41
  - `file://` for local filesystem artifacts
40
42
  - `s3://` for AWS S3 objects and prefix listings
41
43
  - `oci://` for OCI registry artifacts (via ORAS client)
@@ -53,15 +55,21 @@ pip install session-adapters
53
55
  ```python
54
56
  import requests
55
57
 
58
+ from session_adapters.bearer_auth_http_adapter import BearerAuthHTTPAdapter
56
59
  from session_adapters.file_adapter import FileAdapter
57
- from session_adapters.s3_adapter import S3Adapter
58
60
  from session_adapters.oci_adapter import OCIAdapter
61
+ from session_adapters.s3_adapter import S3Adapter
59
62
 
60
63
  session = requests.Session()
64
+ session.mount("https://", BearerAuthHTTPAdapter("my-token"))
61
65
  session.mount("file://", FileAdapter())
62
66
  session.mount("s3://", S3Adapter())
63
67
  session.mount("oci://", OCIAdapter())
64
68
 
69
+ # Bearer-authenticated HTTPS request
70
+ resp = session.get("https://api.example.com/resource")
71
+ print(resp.status_code)
72
+
65
73
  # Local file
66
74
  resp = session.get("file:///tmp/example.txt")
67
75
  print(resp.status_code)
@@ -77,6 +85,13 @@ print(resp.status_code)
77
85
 
78
86
  ## Adapter Notes
79
87
 
88
+ ### Bearer Auth HTTP Adapter
89
+
90
+ - Adds an `Authorization: Bearer <token>` header to every request it handles
91
+ - Replaces an existing `Authorization` header
92
+ - Can be mounted on a specific URL prefix to limit where the token is sent
93
+ - Mount separate adapters for `http://` and `https://` if both schemes are needed
94
+
80
95
  ### File Adapter
81
96
 
82
97
  - Supports `GET`, `HEAD`, `PUT`, `DELETE`
@@ -3,12 +3,15 @@
3
3
  [![PyPI - Version](https://img.shields.io/pypi/v/session-adapters.svg)](https://pypi.org/project/session-adapters)
4
4
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/session-adapters.svg)](https://pypi.org/project/session-adapters)
5
5
 
6
- Requests transport adapters for `file://`, `s3://`, and `oci://` URLs.
6
+ Requests transport adapters for bearer-authenticated `http(s)://`, `file://`,
7
+ `s3://`, and `oci://` URLs.
7
8
 
8
9
  ## Why This Project
9
10
 
10
- `session-adapters` lets you use a standard `requests.Session` with non-HTTP backends:
11
+ `session-adapters` lets you use a standard `requests.Session` with authenticated
12
+ HTTP requests and non-HTTP backends:
11
13
 
14
+ - `http://` and `https://` with bearer token authentication
12
15
  - `file://` for local filesystem artifacts
13
16
  - `s3://` for AWS S3 objects and prefix listings
14
17
  - `oci://` for OCI registry artifacts (via ORAS client)
@@ -26,15 +29,21 @@ pip install session-adapters
26
29
  ```python
27
30
  import requests
28
31
 
32
+ from session_adapters.bearer_auth_http_adapter import BearerAuthHTTPAdapter
29
33
  from session_adapters.file_adapter import FileAdapter
30
- from session_adapters.s3_adapter import S3Adapter
31
34
  from session_adapters.oci_adapter import OCIAdapter
35
+ from session_adapters.s3_adapter import S3Adapter
32
36
 
33
37
  session = requests.Session()
38
+ session.mount("https://", BearerAuthHTTPAdapter("my-token"))
34
39
  session.mount("file://", FileAdapter())
35
40
  session.mount("s3://", S3Adapter())
36
41
  session.mount("oci://", OCIAdapter())
37
42
 
43
+ # Bearer-authenticated HTTPS request
44
+ resp = session.get("https://api.example.com/resource")
45
+ print(resp.status_code)
46
+
38
47
  # Local file
39
48
  resp = session.get("file:///tmp/example.txt")
40
49
  print(resp.status_code)
@@ -50,6 +59,13 @@ print(resp.status_code)
50
59
 
51
60
  ## Adapter Notes
52
61
 
62
+ ### Bearer Auth HTTP Adapter
63
+
64
+ - Adds an `Authorization: Bearer <token>` header to every request it handles
65
+ - Replaces an existing `Authorization` header
66
+ - Can be mounted on a specific URL prefix to limit where the token is sent
67
+ - Mount separate adapters for `http://` and `https://` if both schemes are needed
68
+
53
69
  ### File Adapter
54
70
 
55
71
  - Supports `GET`, `HEAD`, `PUT`, `DELETE`
@@ -14,19 +14,14 @@
14
14
 
15
15
  version: '3'
16
16
 
17
- tasks:
18
-
19
- test:
20
- desc: Run tests
21
- cmds:
22
- - hatch run test:test-show-setup
17
+ includes:
18
+ quality: https://raw.githubusercontent.com/Terradue/taskfile-utils/refs/heads/main/quality.yaml
23
19
 
24
- check:
25
- desc: Run code quality checks
26
- cmds:
27
- - hatch run dev:check
20
+ tasks:
28
21
 
29
- lint:
30
- desc: Run linters
22
+ default:
31
23
  cmds:
32
- - hatch run dev:lint
24
+ - task: quality:test
25
+ - task: quality:check
26
+ - task: quality:lint
27
+
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  name = "session-adapters"
7
7
  dynamic = ["version"]
8
- description = "Requests transport adapters for file://, s3://, and oci:// URLs."
8
+ description = "Requests transport adapters for bearer-authenticated `http(s)://`, `file://`, `s3://`, and `oci://` URLs."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  license = "MIT"
@@ -30,7 +30,6 @@ dependencies = [
30
30
  "loguru",
31
31
  "oras",
32
32
  "pydantic",
33
- "python-magic",
34
33
  ]
35
34
 
36
35
  [project.urls]
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = "0.2.0"
15
+ __version__ = "0.4.0"
@@ -20,7 +20,6 @@ from session_adapters.http_conts import (
20
20
  )
21
21
  from abc import abstractmethod
22
22
  from http import HTTPStatus
23
- from magic import Magic
24
23
  from pathlib import Path
25
24
  from requests import PreparedRequest, Response
26
25
  from typing import Any, Dict, final, Generic, TypeVar, Union
@@ -36,8 +35,6 @@ __DATE_HEADER_FORMAT__ = "%a, %d %b %Y %H:%M:%S GMT"
36
35
 
37
36
  AdapterRequest = TypeVar("AdapterRequest")
38
37
 
39
- magic = Magic(mime=True, uncompress=True)
40
-
41
38
  # Ensure YAML extensions are known by the stdlib
42
39
  mimetypes.add_type(ContentType.YAML.value, ".yaml")
43
40
  mimetypes.add_type(ContentType.YAML.value, ".yml")
@@ -80,13 +77,12 @@ class ExtendedResponse(Response):
80
77
  self.send_status(HTTPStatus.OK)
81
78
  self.send_date_header(HTTPHeader.LAST_MODIFIED, mod_time)
82
79
 
83
- mime = magic.from_file(path)
84
- if not mime or ContentType.PLAIN == ContentType(mime):
85
- guess_mime = mimetypes.guess_type(path)
86
- if guess_mime:
87
- mime = guess_mime[0]
80
+ guess_mime = mimetypes.guess_type(path)
88
81
 
89
- self.send_header(HTTPHeader.CONTENT_TYPE, mime)
82
+ for mime in guess_mime:
83
+ if mime:
84
+ self.send_header(HTTPHeader.CONTENT_TYPE, mime)
85
+ break
90
86
 
91
87
  @final
92
88
  def send_error(self, http_status: HTTPStatus, error: Any):
@@ -0,0 +1,31 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from requests import PreparedRequest, Response
16
+ from requests.adapters import HTTPAdapter
17
+
18
+
19
+ class BearerAuthHTTPAdapter(HTTPAdapter):
20
+ def __init__(self, token: str, *args, **kwargs) -> None:
21
+ super().__init__(*args, **kwargs)
22
+ self.token = token
23
+
24
+ def send(
25
+ self,
26
+ request: PreparedRequest,
27
+ *args,
28
+ **kwargs,
29
+ ) -> Response:
30
+ request.headers["Authorization"] = f"Bearer {self.token}"
31
+ return super().send(request, *args, **kwargs)
@@ -0,0 +1,13 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -1,3 +1,16 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
1
14
  import sys
2
15
  import types
3
16
 
@@ -1,3 +1,16 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
1
14
  from http import HTTPStatus
2
15
 
3
16
  from requests import PreparedRequest, Request
@@ -0,0 +1,36 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ from unittest.mock import patch
15
+
16
+ from requests import Request, Response
17
+ from requests.adapters import HTTPAdapter
18
+
19
+ from session_adapters.bearer_auth_http_adapter import BearerAuthHTTPAdapter
20
+
21
+
22
+ def test_send_sets_bearer_authorization_header_and_delegates():
23
+ adapter = BearerAuthHTTPAdapter("test-token")
24
+ request = Request(
25
+ "GET",
26
+ "https://example.com/resource",
27
+ headers={"Authorization": "Basic old-credentials"},
28
+ ).prepare()
29
+ expected_response = Response()
30
+
31
+ with patch.object(HTTPAdapter, "send", return_value=expected_response) as send:
32
+ response = adapter.send(request, timeout=10)
33
+
34
+ assert request.headers["Authorization"] == "Bearer test-token"
35
+ send.assert_called_once_with(request, timeout=10)
36
+ assert response is expected_response
@@ -1,3 +1,16 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
1
14
  from http import HTTPStatus
2
15
 
3
16
  from requests import Request
@@ -1,3 +1,17 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
1
15
  from http import HTTPStatus
2
16
 
3
17
  from requests import Request
@@ -1,3 +1,17 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
1
15
  import json
2
16
  from http import HTTPStatus
3
17
 
@@ -1,3 +0,0 @@
1
- # SPDX-FileCopyrightText: 2026-present stripodi <simone.tripodi@terradue.com>
2
- #
3
- # SPDX-License-Identifier: MIT