async-solipsism 0.7__tar.gz → 0.9__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 (29) hide show
  1. {async_solipsism-0.7 → async_solipsism-0.9}/.github/workflows/test.yml +9 -9
  2. async_solipsism-0.9/.pre-commit-config.yaml +11 -0
  3. {async_solipsism-0.7 → async_solipsism-0.9}/PKG-INFO +19 -3
  4. {async_solipsism-0.7 → async_solipsism-0.9}/README.md +14 -0
  5. {async_solipsism-0.7 → async_solipsism-0.9}/pyproject.toml +7 -3
  6. async_solipsism-0.9/pytest.ini +3 -0
  7. async_solipsism-0.9/requirements.txt +49 -0
  8. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism/__init__.py +2 -2
  9. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism/loop.py +16 -3
  10. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism/socket.py +12 -1
  11. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism.egg-info/PKG-INFO +19 -3
  12. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism.egg-info/SOURCES.txt +0 -1
  13. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism.egg-info/requires.txt +3 -0
  14. {async_solipsism-0.7 → async_solipsism-0.9}/test/test_loop.py +16 -6
  15. async_solipsism-0.7/.pre-commit-config.yaml +0 -12
  16. async_solipsism-0.7/pytest.ini +0 -2
  17. async_solipsism-0.7/requirements.in +0 -4
  18. async_solipsism-0.7/requirements.txt +0 -46
  19. {async_solipsism-0.7 → async_solipsism-0.9}/.flake8 +0 -0
  20. {async_solipsism-0.7 → async_solipsism-0.9}/.gitignore +0 -0
  21. {async_solipsism-0.7 → async_solipsism-0.9}/LICENSE +0 -0
  22. {async_solipsism-0.7 → async_solipsism-0.9}/setup.cfg +0 -0
  23. {async_solipsism-0.7 → async_solipsism-0.9}/setup.py +0 -0
  24. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism/clock.py +0 -0
  25. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism/exceptions.py +0 -0
  26. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism/selector.py +0 -0
  27. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism.egg-info/dependency_links.txt +0 -0
  28. {async_solipsism-0.7 → async_solipsism-0.9}/src/async_solipsism.egg-info/top_level.txt +0 -0
  29. {async_solipsism-0.7 → async_solipsism-0.9}/test/test_socket.py +0 -0
@@ -4,27 +4,27 @@ on: [push, pull_request]
4
4
 
5
5
  jobs:
6
6
  lint:
7
- runs-on: ubuntu-22.04
7
+ runs-on: ubuntu-24.04
8
8
  steps:
9
- - uses: actions/checkout@v4
10
- - name: Set up Python 3.8
11
- uses: actions/setup-python@v5
9
+ - uses: actions/checkout@v6
10
+ - name: Set up Python 3.10
11
+ uses: actions/setup-python@v6
12
12
  with:
13
- python-version: "3.8"
13
+ python-version: "3.10"
14
14
  - name: Install dependencies
15
15
  run: pip install -r requirements.txt
16
16
  - name: Run pre-commit
17
17
  run: pre-commit run --all-files
18
18
 
19
19
  build:
20
- runs-on: ubuntu-22.04
20
+ runs-on: ubuntu-24.04
21
21
  strategy:
22
22
  matrix:
23
- python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
23
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
24
24
  steps:
25
- - uses: actions/checkout@v4
25
+ - uses: actions/checkout@v6
26
26
  - name: Set up Python ${{ matrix.python-version }}
27
- uses: actions/setup-python@v5
27
+ uses: actions/setup-python@v6
28
28
  with:
29
29
  python-version: ${{ matrix.python-version }}
30
30
  allow-prereleases: true
@@ -0,0 +1,11 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.14.10
4
+ hooks:
5
+ - id: ruff-check
6
+ - repo: https://github.com/astral-sh/uv-pre-commit
7
+ rev: 0.9.18
8
+ hooks:
9
+ - id: pip-compile
10
+ args: ["--python-version=3.10", "--universal", "--output-file=requirements.txt", "--extra=test", "pyproject.toml"]
11
+ files: '^(?:pyproject\.toml|requirements\.txt)$'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: async-solipsism
3
- Version: 0.7
3
+ Version: 0.9
4
4
  Summary: Asyncio event loop that doesn't interact with the outside world
5
5
  Author-email: Bruce Merry <bmerry@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/bmerry/async-solipsism
@@ -8,14 +8,16 @@ Classifier: Development Status :: 5 - Production/Stable
8
8
  Classifier: Framework :: AsyncIO
9
9
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
10
10
  Classifier: Topic :: Software Development :: Testing :: Mocking
11
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Provides-Extra: test
15
+ Requires-Dist: backports.asyncio.runner; python_version < "3.11" and extra == "test"
15
16
  Requires-Dist: pre-commit; extra == "test"
16
17
  Requires-Dist: pytest; extra == "test"
17
18
  Requires-Dist: pytest-asyncio>=0.23; extra == "test"
18
19
  Requires-Dist: pytest-mock; extra == "test"
20
+ Dynamic: license-file
19
21
 
20
22
  # A solipsist event loop
21
23
 
@@ -206,6 +208,20 @@ Calling functions that are not supported will generally raise
206
208
 
207
209
  ## Changelog
208
210
 
211
+ ### 0.9
212
+
213
+ - Drop support for end-of-life Python 3.8 and 3.9.
214
+ - Update versions of dependencies used for testing.
215
+ - Make tests work on latest pytest-asyncio.
216
+ - Replace flake8 with ruff for linting.
217
+ - Replace pip-tools with uv for generating requirements files.
218
+
219
+ ### 0.8
220
+
221
+ - Support `socket.sendmsg`.
222
+ - Support `socket.getpeername` for listening sockets (raises OSError).
223
+ - Make `EventLoop.time` work even after the event loop is closed.
224
+
209
225
  ### 0.7
210
226
 
211
227
  - Add a replacement function for `aiohappyeyeballs.start_connection`.
@@ -187,6 +187,20 @@ Calling functions that are not supported will generally raise
187
187
 
188
188
  ## Changelog
189
189
 
190
+ ### 0.9
191
+
192
+ - Drop support for end-of-life Python 3.8 and 3.9.
193
+ - Update versions of dependencies used for testing.
194
+ - Make tests work on latest pytest-asyncio.
195
+ - Replace flake8 with ruff for linting.
196
+ - Replace pip-tools with uv for generating requirements files.
197
+
198
+ ### 0.8
199
+
200
+ - Support `socket.sendmsg`.
201
+ - Support `socket.getpeername` for listening sockets (raises OSError).
202
+ - Make `EventLoop.time` work even after the event loop is closed.
203
+
190
204
  ### 0.7
191
205
 
192
206
  - Add a replacement function for `aiohappyeyeballs.start_connection`.
@@ -4,12 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "async-solipsism"
7
- dynamic = ["version", "readme"]
7
+ dynamic = ["version"]
8
+ readme = "README.md"
8
9
  description = "Asyncio event loop that doesn't interact with the outside world"
9
10
  authors = [
10
11
  {name = "Bruce Merry", email = "bmerry@gmail.com"}
11
12
  ]
12
- requires-python = ">=3.8"
13
+ requires-python = ">=3.10"
13
14
  classifiers = [
14
15
  "Development Status :: 5 - Production/Stable",
15
16
  "Framework :: AsyncIO",
@@ -22,6 +23,7 @@ Homepage = "https://github.com/bmerry/async-solipsism"
22
23
 
23
24
  [project.optional-dependencies]
24
25
  test = [
26
+ "backports.asyncio.runner; python_version<'3.11'",
25
27
  "pre-commit",
26
28
  "pytest",
27
29
  "pytest-asyncio>=0.23",
@@ -32,4 +34,6 @@ test = [
32
34
 
33
35
  [tool.setuptools.dynamic]
34
36
  version = {attr = "async_solipsism.__version__"}
35
- readme = {file = ["README.md"], content-type = "text/markdown"}
37
+
38
+ [tool.ruff]
39
+ line-length = 120
@@ -0,0 +1,3 @@
1
+ [pytest]
2
+ asyncio_default_fixture_loop_scope=function
3
+ asyncio_mode=auto
@@ -0,0 +1,49 @@
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv pip compile --python-version=3.10 --universal --output-file=requirements.txt --extra=test pyproject.toml
3
+ backports-asyncio-runner==1.2.0 ; python_full_version < '3.11'
4
+ # via async-solipsism (pyproject.toml)
5
+ cfgv==3.5.0
6
+ # via pre-commit
7
+ colorama==0.4.6 ; sys_platform == 'win32'
8
+ # via pytest
9
+ distlib==0.4.0
10
+ # via virtualenv
11
+ exceptiongroup==1.3.1 ; python_full_version < '3.11'
12
+ # via pytest
13
+ filelock==3.20.1
14
+ # via virtualenv
15
+ identify==2.6.15
16
+ # via pre-commit
17
+ iniconfig==2.3.0
18
+ # via pytest
19
+ nodeenv==1.10.0
20
+ # via pre-commit
21
+ packaging==25.0
22
+ # via pytest
23
+ platformdirs==4.5.1
24
+ # via virtualenv
25
+ pluggy==1.6.0
26
+ # via pytest
27
+ pre-commit==4.5.1
28
+ # via async-solipsism (pyproject.toml)
29
+ pygments==2.19.2
30
+ # via pytest
31
+ pytest==8.4.2
32
+ # via
33
+ # async-solipsism (pyproject.toml)
34
+ # pytest-asyncio
35
+ # pytest-mock
36
+ pytest-asyncio==0.26.0
37
+ # via async-solipsism (pyproject.toml)
38
+ pytest-mock==3.15.1
39
+ # via async-solipsism (pyproject.toml)
40
+ pyyaml==6.0.3
41
+ # via pre-commit
42
+ tomli==2.3.0 ; python_full_version < '3.11'
43
+ # via pytest
44
+ typing-extensions==4.15.0 ; python_full_version < '3.11'
45
+ # via
46
+ # exceptiongroup
47
+ # virtualenv
48
+ virtualenv==20.35.4
49
+ # via pre-commit
@@ -1,4 +1,4 @@
1
- # Copyright 2020-2022, 2024 Bruce Merry
1
+ # Copyright 2020-2022, 2024-2025 Bruce Merry
2
2
  #
3
3
  # This file is part of async-solipsism.
4
4
  #
@@ -19,4 +19,4 @@ from .exceptions import * # noqa
19
19
  from .socket import * # noqa
20
20
  from .loop import * # noqa
21
21
 
22
- __version__ = '0.7'
22
+ __version__ = '0.9'
@@ -1,4 +1,4 @@
1
- # Copyright 2020, 2022, 2024 Bruce Merry
1
+ # Copyright 2020, 2022, 2024-2025 Bruce Merry
2
2
  #
3
3
  # This file is part of async-solipsism.
4
4
  #
@@ -30,14 +30,16 @@ __all__ = ('EventLoop', 'EventLoopPolicy', 'aiohappyeyeballs_start_connection',
30
30
  class EventLoop(asyncio.selector_events.BaseSelectorEventLoop):
31
31
  def __init__(self):
32
32
  super().__init__(selector=selector.Selector())
33
- self._selector = selector.Selector()
34
33
  self._clock_resolution = self._selector.clock.resolution
35
34
  # Map from (host, port) pair to ListenSocket
36
35
  self.__listening_sockets = {}
37
36
  self.__next_port = 1
37
+ # Copy this so that time() works even when after the event loop is
38
+ # closed (which clears _selector).
39
+ self.__clock = self._selector.clock
38
40
 
39
41
  def time(self):
40
- return self._selector.clock.time()
42
+ return self.__clock.time()
41
43
 
42
44
  def call_soon_threadsafe(self, callback, *args, context=None):
43
45
  if self._thread_id == threading.get_ident():
@@ -217,6 +219,17 @@ class EventLoop(asyncio.selector_events.BaseSelectorEventLoop):
217
219
  self.__listening_sockets.pop(addr)
218
220
  super()._stop_serving(sock)
219
221
 
222
+ async def shutdown_default_executor(self, timeout=None):
223
+ # The default implementation uses an asyncio timeout, which
224
+ # would complete immediately without giving the executor
225
+ # time to shut down. We ignore the timeout and just shut
226
+ # things down synchronously. This is based on the code in
227
+ # CPython.
228
+ self._executor_shutdown_called = True
229
+ if self._default_executor is None:
230
+ return
231
+ self._default_executor.shutdown(wait=True)
232
+
220
233
 
221
234
  class EventLoopPolicy(asyncio.DefaultEventLoopPolicy):
222
235
  def new_event_loop(self) -> EventLoop:
@@ -1,4 +1,4 @@
1
- # Copyright 2020, 2024 Bruce Merry
1
+ # Copyright 2020, 2024-2025 Bruce Merry
2
2
  #
3
3
  # This file is part of async-solipsism.
4
4
  #
@@ -188,6 +188,14 @@ class Socket(_SocketBase):
188
188
  self._check_closed()
189
189
  return self._write_queue.write(bytes)
190
190
 
191
+ def sendmsg(self, buffers, ancdata=None, flags=0, address=None, /):
192
+ self._check_closed()
193
+ if ancdata is not None:
194
+ raise SolipsismError('ancilliary data is not supported in sendmsg')
195
+ if address is not None:
196
+ raise SolipsismError('address is not supported in sendmsg')
197
+ return self._write_queue.write(b"".join(buffers))
198
+
191
199
  def read_ready(self):
192
200
  return self._read_queue is None or self._read_queue.read_ready()
193
201
 
@@ -217,6 +225,9 @@ class ListenSocket(_SocketBase):
217
225
  def getsockname(self):
218
226
  return self._sockname
219
227
 
228
+ def getpeername(self):
229
+ raise OSError(errno.ENOTCONN, "Transport endpoint is not connected")
230
+
220
231
  def listen(self, backlog=None):
221
232
  pass
222
233
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: async-solipsism
3
- Version: 0.7
3
+ Version: 0.9
4
4
  Summary: Asyncio event loop that doesn't interact with the outside world
5
5
  Author-email: Bruce Merry <bmerry@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/bmerry/async-solipsism
@@ -8,14 +8,16 @@ Classifier: Development Status :: 5 - Production/Stable
8
8
  Classifier: Framework :: AsyncIO
9
9
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
10
10
  Classifier: Topic :: Software Development :: Testing :: Mocking
11
- Requires-Python: >=3.8
11
+ Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Provides-Extra: test
15
+ Requires-Dist: backports.asyncio.runner; python_version < "3.11" and extra == "test"
15
16
  Requires-Dist: pre-commit; extra == "test"
16
17
  Requires-Dist: pytest; extra == "test"
17
18
  Requires-Dist: pytest-asyncio>=0.23; extra == "test"
18
19
  Requires-Dist: pytest-mock; extra == "test"
20
+ Dynamic: license-file
19
21
 
20
22
  # A solipsist event loop
21
23
 
@@ -206,6 +208,20 @@ Calling functions that are not supported will generally raise
206
208
 
207
209
  ## Changelog
208
210
 
211
+ ### 0.9
212
+
213
+ - Drop support for end-of-life Python 3.8 and 3.9.
214
+ - Update versions of dependencies used for testing.
215
+ - Make tests work on latest pytest-asyncio.
216
+ - Replace flake8 with ruff for linting.
217
+ - Replace pip-tools with uv for generating requirements files.
218
+
219
+ ### 0.8
220
+
221
+ - Support `socket.sendmsg`.
222
+ - Support `socket.getpeername` for listening sockets (raises OSError).
223
+ - Make `EventLoop.time` work even after the event loop is closed.
224
+
209
225
  ### 0.7
210
226
 
211
227
  - Add a replacement function for `aiohappyeyeballs.start_connection`.
@@ -5,7 +5,6 @@ LICENSE
5
5
  README.md
6
6
  pyproject.toml
7
7
  pytest.ini
8
- requirements.in
9
8
  requirements.txt
10
9
  setup.py
11
10
  .github/workflows/test.yml
@@ -4,3 +4,6 @@ pre-commit
4
4
  pytest
5
5
  pytest-asyncio>=0.23
6
6
  pytest-mock
7
+
8
+ [test:python_version < "3.11"]
9
+ backports.asyncio.runner
@@ -1,4 +1,4 @@
1
- # Copyright 2020, 2022 Bruce Merry
1
+ # Copyright 2020, 2022, 2025 Bruce Merry
2
2
  #
3
3
  # This file is part of async-solipsism.
4
4
  #
@@ -17,7 +17,12 @@
17
17
 
18
18
  import asyncio
19
19
  import concurrent.futures
20
+ import sys
20
21
  import threading
22
+ if sys.version_info < (3, 11):
23
+ from backports.asyncio.runner import Runner
24
+ else:
25
+ from asyncio import Runner
21
26
 
22
27
  import pytest
23
28
 
@@ -36,19 +41,25 @@ async def test_sleep():
36
41
  assert event_loop.time() == 2.0
37
42
 
38
43
 
39
- def test_sleep_forever(event_loop):
44
+ def test_sleep_forever():
40
45
  async def zzz():
41
46
  await asyncio.Future()
42
47
 
43
- with pytest.raises(async_solipsism.SleepForeverError):
44
- event_loop.run_until_complete(zzz())
48
+ def factory():
49
+ loop = async_solipsism.EventLoop()
50
+ asyncio.set_event_loop(loop)
51
+ return loop
52
+
53
+ with Runner(loop_factory=factory) as runner:
54
+ with pytest.raises(async_solipsism.SleepForeverError):
55
+ runner.run(zzz())
45
56
 
46
57
 
47
58
  @pytest.mark.parametrize(
48
59
  'method',
49
60
  [
50
61
  'recv',
51
- pytest.param('recv_into', marks=pytest.mark.skipif("sys.version_info < (3, 7)"))
62
+ 'recv_into'
52
63
  ]
53
64
  )
54
65
  @pytest.mark.parametrize('delay', [False, True])
@@ -210,7 +221,6 @@ async def test_run_in_executor_explicit():
210
221
  my_executor.shutdown()
211
222
 
212
223
 
213
- @pytest.mark.skipif("sys.version_info < (3, 7)")
214
224
  async def test_sendfile(tmp_path):
215
225
  event_loop = asyncio.get_running_loop()
216
226
  tmp_file = tmp_path / 'test_sendfile.txt'
@@ -1,12 +0,0 @@
1
- repos:
2
- - repo: https://github.com/pycqa/flake8
3
- rev: "7.0.0"
4
- hooks:
5
- - id: flake8
6
- - repo: https://github.com/jazzband/pip-tools
7
- rev: 7.4.1
8
- hooks:
9
- - id: pip-compile
10
- language_version: python3.8
11
- args: ["--output-file=requirements.txt", "--extra=test", "--strip-extras", "pyproject.toml"]
12
- files: '^(?:pyproject\.toml|requirements\.txt)$'
@@ -1,2 +0,0 @@
1
- [pytest]
2
- asyncio_mode=auto
@@ -1,4 +0,0 @@
1
- pre-commit
2
- pytest
3
- pytest-asyncio>=0.23
4
- pytest-mock
@@ -1,46 +0,0 @@
1
- #
2
- # This file is autogenerated by pip-compile with Python 3.8
3
- # by the following command:
4
- #
5
- # pip-compile --extra=test --output-file=requirements.txt --strip-extras pyproject.toml
6
- #
7
- cfgv==3.4.0
8
- # via pre-commit
9
- distlib==0.3.8
10
- # via virtualenv
11
- exceptiongroup==1.2.0
12
- # via pytest
13
- filelock==3.13.1
14
- # via virtualenv
15
- identify==2.5.35
16
- # via pre-commit
17
- iniconfig==2.0.0
18
- # via pytest
19
- nodeenv==1.8.0
20
- # via pre-commit
21
- packaging==24.0
22
- # via pytest
23
- platformdirs==4.2.0
24
- # via virtualenv
25
- pluggy==1.4.0
26
- # via pytest
27
- pre-commit==3.5.0
28
- # via async-solipsism (pyproject.toml)
29
- pytest==8.1.1
30
- # via
31
- # async-solipsism (pyproject.toml)
32
- # pytest-asyncio
33
- # pytest-mock
34
- pytest-asyncio==0.23.6
35
- # via async-solipsism (pyproject.toml)
36
- pytest-mock==3.14.0
37
- # via async-solipsism (pyproject.toml)
38
- pyyaml==6.0.1
39
- # via pre-commit
40
- tomli==2.0.1
41
- # via pytest
42
- virtualenv==20.25.1
43
- # via pre-commit
44
-
45
- # The following packages are considered to be unsafe in a requirements file:
46
- # setuptools
File without changes
File without changes
File without changes
File without changes
File without changes