async-solipsism 0.5__tar.gz → 0.6__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 (31) hide show
  1. async-solipsism-0.6/.github/workflows/test.yml +35 -0
  2. {async-solipsism-0.5 → async-solipsism-0.6}/.gitignore +1 -0
  3. async-solipsism-0.6/.pre-commit-config.yaml +12 -0
  4. {async-solipsism-0.5/src/async_solipsism.egg-info → async-solipsism-0.6}/PKG-INFO +38 -13
  5. async-solipsism-0.5/PKG-INFO → async-solipsism-0.6/README.md +29 -23
  6. async-solipsism-0.6/pyproject.toml +35 -0
  7. async-solipsism-0.6/requirements.in +4 -0
  8. async-solipsism-0.6/requirements.txt +46 -0
  9. async-solipsism-0.6/setup.cfg +4 -0
  10. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism/__init__.py +2 -2
  11. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism/loop.py +6 -1
  12. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism/socket.py +27 -13
  13. async-solipsism-0.5/README.md → async-solipsism-0.6/src/async_solipsism.egg-info/PKG-INFO +48 -7
  14. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism.egg-info/SOURCES.txt +2 -1
  15. async-solipsism-0.6/src/async_solipsism.egg-info/requires.txt +6 -0
  16. {async-solipsism-0.5 → async-solipsism-0.6}/test/test_loop.py +31 -17
  17. {async-solipsism-0.5 → async-solipsism-0.6}/test/test_socket.py +41 -1
  18. async-solipsism-0.5/.github/workflows/test.yml +0 -25
  19. async-solipsism-0.5/pyproject.toml +0 -2
  20. async-solipsism-0.5/requirements.txt +0 -4
  21. async-solipsism-0.5/setup.cfg +0 -34
  22. async-solipsism-0.5/src/async_solipsism.egg-info/requires.txt +0 -5
  23. {async-solipsism-0.5 → async-solipsism-0.6}/.flake8 +0 -0
  24. {async-solipsism-0.5 → async-solipsism-0.6}/LICENSE +0 -0
  25. {async-solipsism-0.5 → async-solipsism-0.6}/pytest.ini +0 -0
  26. {async-solipsism-0.5 → async-solipsism-0.6}/setup.py +0 -0
  27. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism/clock.py +0 -0
  28. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism/exceptions.py +0 -0
  29. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism/selector.py +0 -0
  30. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism.egg-info/dependency_links.txt +0 -0
  31. {async-solipsism-0.5 → async-solipsism-0.6}/src/async_solipsism.egg-info/top_level.txt +0 -0
@@ -0,0 +1,35 @@
1
+ name: Run tests
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ lint:
7
+ runs-on: ubuntu-22.04
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ - name: Set up Python 3.8
11
+ uses: actions/setup-python@v5
12
+ with:
13
+ python-version: "3.8"
14
+ - name: Install dependencies
15
+ run: pip install -r requirements.txt
16
+ - name: Run pre-commit
17
+ run: pre-commit run --all-files
18
+
19
+ build:
20
+ runs-on: ubuntu-22.04
21
+ strategy:
22
+ matrix:
23
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - name: Set up Python ${{ matrix.python-version }}
27
+ uses: actions/setup-python@v5
28
+ with:
29
+ python-version: ${{ matrix.python-version }}
30
+ - name: Install dependencies
31
+ run: pip install -r requirements.txt
32
+ - name: Install package
33
+ run: pip install .
34
+ - name: Run pytest
35
+ run: pytest
@@ -1,2 +1,3 @@
1
1
  *.egg-info
2
2
  __pycache__
3
+ /dist
@@ -0,0 +1,12 @@
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,22 +1,25 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: async-solipsism
3
- Version: 0.5
3
+ Version: 0.6
4
4
  Summary: Asyncio event loop that doesn't interact with the outside world
5
- Home-page: https://github.com/bmerry/async-solipsism
6
- Author: Bruce Merry
7
- Author-email: bmerry@gmail.com
5
+ Author-email: Bruce Merry <bmerry@gmail.com>
6
+ Project-URL: Homepage, https://github.com/bmerry/async-solipsism
8
7
  Classifier: Development Status :: 3 - Alpha
9
8
  Classifier: Framework :: AsyncIO
10
9
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
11
10
  Classifier: Topic :: Software Development :: Testing :: Mocking
12
- Requires-Python: >=3.6
11
+ Requires-Python: >=3.8
13
12
  Description-Content-Type: text/markdown
14
- Provides-Extra: test
15
13
  License-File: LICENSE
14
+ Provides-Extra: test
15
+ Requires-Dist: pre-commit; extra == "test"
16
+ Requires-Dist: pytest; extra == "test"
17
+ Requires-Dist: pytest-asyncio>=0.23; extra == "test"
18
+ Requires-Dist: pytest-mock; extra == "test"
16
19
 
17
20
  # A solipsist event loop
18
21
 
19
- async-solipsism provide a Python asyncio event loop that does not interact with
22
+ async-solipsism provides a Python asyncio event loop that does not interact with
20
23
  the outside world at all. This is ideal for writing unit tests that intend to
21
24
  mock out real-world interactions. It makes for tests that are reliable
22
25
  (unaffected by network outages), reproducible (not affected by random timing
@@ -107,8 +110,17 @@ port number of 0, and async-solipsism will bind the first port number above
107
110
  ### Integration with pytest-asyncio
108
111
 
109
112
  async-solipsism and pytest-asyncio complement each other well: just write a
110
- custom `event_loop` fixture in your test file or `conftest.py` and it will
111
- override the default provided by pytest-asyncio:
113
+ custom `event_loop_policy` fixture in your test file or `conftest.py` and it
114
+ will override the default provided by pytest-asyncio:
115
+
116
+ ```python
117
+ @pytest.fixture
118
+ def event_loop_policy():
119
+ return async_solipsism.EventLoopPolicy()
120
+ ```
121
+
122
+ The above is for pytest-asyncio 0.23+. If you're using an older version, then
123
+ instead you should do this:
112
124
 
113
125
  ```python
114
126
  @pytest.fixture
@@ -130,10 +142,8 @@ from aiohttp import web, test_utils
130
142
 
131
143
 
132
144
  @pytest.fixture
133
- def event_loop():
134
- loop = async_solipsism.EventLoop()
135
- yield loop
136
- loop.close()
145
+ def event_loop_policy():
146
+ return async_solipsism.EventLoopPolicy()
137
147
 
138
148
 
139
149
  def socket_factory(host, port, family):
@@ -183,6 +193,21 @@ Calling functions that are not supported will generally raise
183
193
 
184
194
  ## Changelog
185
195
 
196
+ ### 0.6
197
+
198
+ - Drop support for Python 3.6 and 3.7, which have reached end of life.
199
+ - Add `EventLoopPolicy` to simplify integration with pytest-asyncio 0.23+,
200
+ and use it for the internal tests.
201
+ - Make `Socket.write` and `Socket.recv_into` accept arbitrary buffer-protocol
202
+ objects.
203
+ - Various packaging and developer experience improvements:
204
+ - Put the packaging metadata in pyproject.toml, removing setup.cfg.
205
+ - Pin versions for CI in requirements.txt using pip-compile.
206
+ - Use pre-commit to enforce flake8 and pip-compile.
207
+ - Remove wheel from `build-system.requires` (on setuptools advice).
208
+ - Test against Python 3.11 and 3.12.
209
+ - Run CI workflow against pull requests.
210
+
186
211
  ### 0.5
187
212
 
188
213
  - Map port 0 to an unused port.
@@ -1,22 +1,6 @@
1
- Metadata-Version: 2.1
2
- Name: async-solipsism
3
- Version: 0.5
4
- Summary: Asyncio event loop that doesn't interact with the outside world
5
- Home-page: https://github.com/bmerry/async-solipsism
6
- Author: Bruce Merry
7
- Author-email: bmerry@gmail.com
8
- Classifier: Development Status :: 3 - Alpha
9
- Classifier: Framework :: AsyncIO
10
- Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
11
- Classifier: Topic :: Software Development :: Testing :: Mocking
12
- Requires-Python: >=3.6
13
- Description-Content-Type: text/markdown
14
- Provides-Extra: test
15
- License-File: LICENSE
16
-
17
1
  # A solipsist event loop
18
2
 
19
- async-solipsism provide a Python asyncio event loop that does not interact with
3
+ async-solipsism provides a Python asyncio event loop that does not interact with
20
4
  the outside world at all. This is ideal for writing unit tests that intend to
21
5
  mock out real-world interactions. It makes for tests that are reliable
22
6
  (unaffected by network outages), reproducible (not affected by random timing
@@ -107,8 +91,17 @@ port number of 0, and async-solipsism will bind the first port number above
107
91
  ### Integration with pytest-asyncio
108
92
 
109
93
  async-solipsism and pytest-asyncio complement each other well: just write a
110
- custom `event_loop` fixture in your test file or `conftest.py` and it will
111
- override the default provided by pytest-asyncio:
94
+ custom `event_loop_policy` fixture in your test file or `conftest.py` and it
95
+ will override the default provided by pytest-asyncio:
96
+
97
+ ```python
98
+ @pytest.fixture
99
+ def event_loop_policy():
100
+ return async_solipsism.EventLoopPolicy()
101
+ ```
102
+
103
+ The above is for pytest-asyncio 0.23+. If you're using an older version, then
104
+ instead you should do this:
112
105
 
113
106
  ```python
114
107
  @pytest.fixture
@@ -130,10 +123,8 @@ from aiohttp import web, test_utils
130
123
 
131
124
 
132
125
  @pytest.fixture
133
- def event_loop():
134
- loop = async_solipsism.EventLoop()
135
- yield loop
136
- loop.close()
126
+ def event_loop_policy():
127
+ return async_solipsism.EventLoopPolicy()
137
128
 
138
129
 
139
130
  def socket_factory(host, port, family):
@@ -183,6 +174,21 @@ Calling functions that are not supported will generally raise
183
174
 
184
175
  ## Changelog
185
176
 
177
+ ### 0.6
178
+
179
+ - Drop support for Python 3.6 and 3.7, which have reached end of life.
180
+ - Add `EventLoopPolicy` to simplify integration with pytest-asyncio 0.23+,
181
+ and use it for the internal tests.
182
+ - Make `Socket.write` and `Socket.recv_into` accept arbitrary buffer-protocol
183
+ objects.
184
+ - Various packaging and developer experience improvements:
185
+ - Put the packaging metadata in pyproject.toml, removing setup.cfg.
186
+ - Pin versions for CI in requirements.txt using pip-compile.
187
+ - Use pre-commit to enforce flake8 and pip-compile.
188
+ - Remove wheel from `build-system.requires` (on setuptools advice).
189
+ - Test against Python 3.11 and 3.12.
190
+ - Run CI workflow against pull requests.
191
+
186
192
  ### 0.5
187
193
 
188
194
  - Map port 0 to an unused port.
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "setuptools-scm>=8.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "async-solipsism"
7
+ dynamic = ["version", "readme"]
8
+ description = "Asyncio event loop that doesn't interact with the outside world"
9
+ authors = [
10
+ {name = "Bruce Merry", email = "bmerry@gmail.com"}
11
+ ]
12
+ requires-python = ">=3.8"
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Framework :: AsyncIO",
16
+ "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
17
+ "Topic :: Software Development :: Testing :: Mocking",
18
+ ]
19
+
20
+ [project.urls]
21
+ Homepage = "https://github.com/bmerry/async-solipsism"
22
+
23
+ [project.optional-dependencies]
24
+ test = [
25
+ "pre-commit",
26
+ "pytest",
27
+ "pytest-asyncio>=0.23",
28
+ "pytest-mock",
29
+ ]
30
+
31
+ [tool.setuptools_scm]
32
+
33
+ [tool.setuptools.dynamic]
34
+ version = {attr = "async_solipsism.__version__"}
35
+ readme = {file = ["README.md"], content-type = "text/markdown"}
@@ -0,0 +1,4 @@
1
+ pre-commit
2
+ pytest
3
+ pytest-asyncio>=0.23
4
+ pytest-mock
@@ -0,0 +1,46 @@
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
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -1,4 +1,4 @@
1
- # Copyright 2020-2022 Bruce Merry
1
+ # Copyright 2020-2022, 2024 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.5'
22
+ __version__ = '0.6'
@@ -24,7 +24,7 @@ from . import selector, socket as _socket
24
24
  from .exceptions import SolipsismError
25
25
 
26
26
 
27
- __all__ = ('EventLoop', 'stream_pairs')
27
+ __all__ = ('EventLoop', 'EventLoopPolicy', 'stream_pairs')
28
28
 
29
29
 
30
30
  class EventLoop(asyncio.selector_events.BaseSelectorEventLoop):
@@ -197,6 +197,11 @@ class EventLoop(asyncio.selector_events.BaseSelectorEventLoop):
197
197
  super()._stop_serving(sock)
198
198
 
199
199
 
200
+ class EventLoopPolicy(asyncio.DefaultEventLoopPolicy):
201
+ def new_event_loop(self) -> EventLoop:
202
+ return EventLoop()
203
+
204
+
200
205
  async def stream_pairs(capacity=None):
201
206
  sock1, sock2 = _socket.socketpair(capacity=capacity)
202
207
  streams1 = await asyncio.open_connection(sock=sock1)
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Bruce Merry
1
+ # Copyright 2020, 2024 Bruce Merry
2
2
  #
3
3
  # This file is part of async-solipsism.
4
4
  #
@@ -30,6 +30,11 @@ DEFAULT_CAPACITY = 65536
30
30
  __all__ = ('Socket', 'ListenSocket', 'Queue', 'socketpair')
31
31
 
32
32
 
33
+ def _view(bytes):
34
+ """Get a 1D byte-typed memoryview of an object implementing the buffer protocol."""
35
+ return memoryview(bytes).cast("B")
36
+
37
+
33
38
  class Queue:
34
39
  def __init__(self, capacity=None):
35
40
  self.capacity = capacity or DEFAULT_CAPACITY
@@ -50,11 +55,14 @@ class Queue:
50
55
  raise BrokenPipeError(errno.EPIPE, 'Broken pipe')
51
56
  if len(self) >= self.capacity:
52
57
  return None
53
- n = len(data)
54
- if len(self) + n > self.capacity:
55
- n = self.capacity - len(self)
56
- data = memoryview(data)[:n]
57
- self._buffer += data
58
+ with _view(data) as view:
59
+ n = len(view)
60
+ if len(self) + n > self.capacity:
61
+ n = self.capacity - len(self)
62
+ with view[:n] as prefix:
63
+ self._buffer += prefix
64
+ else:
65
+ self._buffer += view
58
66
  return n
59
67
 
60
68
  def read(self, size=-1):
@@ -68,7 +76,8 @@ class Queue:
68
76
  self._buffer = bytearray()
69
77
  else:
70
78
  n = min(size, len(self._buffer))
71
- ret = bytes(memoryview(self._buffer))[:n]
79
+ with memoryview(self._buffer) as view, view[:n] as prefix:
80
+ ret = bytes(prefix)
72
81
  self._buffer = self._buffer[n:]
73
82
  return ret
74
83
 
@@ -93,7 +102,7 @@ class SocketFd:
93
102
  return hash(self.socket)
94
103
 
95
104
  def __eq__(self, other):
96
- if type(other) == SocketFd:
105
+ if type(other) is SocketFd:
97
106
  return self.socket is other.socket
98
107
  return NotImplemented
99
108
 
@@ -164,11 +173,16 @@ class Socket(_SocketBase):
164
173
 
165
174
  def recv_into(self, buffer, nbytes=0, flags=0):
166
175
  # TODO: implement more efficiently?
167
- if not nbytes:
168
- nbytes = len(buffer)
169
- data = self.recv(nbytes)
170
- buffer[:len(data)] = data
171
- return len(data)
176
+ with _view(buffer) as view:
177
+ if not nbytes:
178
+ nbytes = len(view)
179
+ if nbytes < 0:
180
+ raise ValueError("negative buffersize in recv_into")
181
+ if nbytes > len(view):
182
+ raise ValueError("buffer too small for requested bytes")
183
+ data = self.recv(nbytes)
184
+ view[:len(data)] = data
185
+ return len(data)
172
186
 
173
187
  def send(self, bytes, flags=0):
174
188
  self._check_closed()
@@ -1,6 +1,25 @@
1
+ Metadata-Version: 2.1
2
+ Name: async-solipsism
3
+ Version: 0.6
4
+ Summary: Asyncio event loop that doesn't interact with the outside world
5
+ Author-email: Bruce Merry <bmerry@gmail.com>
6
+ Project-URL: Homepage, https://github.com/bmerry/async-solipsism
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Framework :: AsyncIO
9
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
10
+ Classifier: Topic :: Software Development :: Testing :: Mocking
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Provides-Extra: test
15
+ Requires-Dist: pre-commit; extra == "test"
16
+ Requires-Dist: pytest; extra == "test"
17
+ Requires-Dist: pytest-asyncio>=0.23; extra == "test"
18
+ Requires-Dist: pytest-mock; extra == "test"
19
+
1
20
  # A solipsist event loop
2
21
 
3
- async-solipsism provide a Python asyncio event loop that does not interact with
22
+ async-solipsism provides a Python asyncio event loop that does not interact with
4
23
  the outside world at all. This is ideal for writing unit tests that intend to
5
24
  mock out real-world interactions. It makes for tests that are reliable
6
25
  (unaffected by network outages), reproducible (not affected by random timing
@@ -91,8 +110,17 @@ port number of 0, and async-solipsism will bind the first port number above
91
110
  ### Integration with pytest-asyncio
92
111
 
93
112
  async-solipsism and pytest-asyncio complement each other well: just write a
94
- custom `event_loop` fixture in your test file or `conftest.py` and it will
95
- override the default provided by pytest-asyncio:
113
+ custom `event_loop_policy` fixture in your test file or `conftest.py` and it
114
+ will override the default provided by pytest-asyncio:
115
+
116
+ ```python
117
+ @pytest.fixture
118
+ def event_loop_policy():
119
+ return async_solipsism.EventLoopPolicy()
120
+ ```
121
+
122
+ The above is for pytest-asyncio 0.23+. If you're using an older version, then
123
+ instead you should do this:
96
124
 
97
125
  ```python
98
126
  @pytest.fixture
@@ -114,10 +142,8 @@ from aiohttp import web, test_utils
114
142
 
115
143
 
116
144
  @pytest.fixture
117
- def event_loop():
118
- loop = async_solipsism.EventLoop()
119
- yield loop
120
- loop.close()
145
+ def event_loop_policy():
146
+ return async_solipsism.EventLoopPolicy()
121
147
 
122
148
 
123
149
  def socket_factory(host, port, family):
@@ -167,6 +193,21 @@ Calling functions that are not supported will generally raise
167
193
 
168
194
  ## Changelog
169
195
 
196
+ ### 0.6
197
+
198
+ - Drop support for Python 3.6 and 3.7, which have reached end of life.
199
+ - Add `EventLoopPolicy` to simplify integration with pytest-asyncio 0.23+,
200
+ and use it for the internal tests.
201
+ - Make `Socket.write` and `Socket.recv_into` accept arbitrary buffer-protocol
202
+ objects.
203
+ - Various packaging and developer experience improvements:
204
+ - Put the packaging metadata in pyproject.toml, removing setup.cfg.
205
+ - Pin versions for CI in requirements.txt using pip-compile.
206
+ - Use pre-commit to enforce flake8 and pip-compile.
207
+ - Remove wheel from `build-system.requires` (on setuptools advice).
208
+ - Test against Python 3.11 and 3.12.
209
+ - Run CI workflow against pull requests.
210
+
170
211
  ### 0.5
171
212
 
172
213
  - Map port 0 to an unused port.
@@ -1,11 +1,12 @@
1
1
  .flake8
2
2
  .gitignore
3
+ .pre-commit-config.yaml
3
4
  LICENSE
4
5
  README.md
5
6
  pyproject.toml
6
7
  pytest.ini
8
+ requirements.in
7
9
  requirements.txt
8
- setup.cfg
9
10
  setup.py
10
11
  .github/workflows/test.yml
11
12
  src/async_solipsism/__init__.py
@@ -0,0 +1,6 @@
1
+
2
+ [test]
3
+ pre-commit
4
+ pytest
5
+ pytest-asyncio>=0.23
6
+ pytest-mock
@@ -25,13 +25,12 @@ import async_solipsism
25
25
 
26
26
 
27
27
  @pytest.fixture
28
- def event_loop():
29
- loop = async_solipsism.EventLoop()
30
- yield loop
31
- loop.close()
28
+ def event_loop_policy():
29
+ return async_solipsism.EventLoopPolicy()
32
30
 
33
31
 
34
- async def test_sleep(event_loop):
32
+ async def test_sleep():
33
+ event_loop = asyncio.get_running_loop()
35
34
  assert event_loop.time() == 0.0
36
35
  await asyncio.sleep(2)
37
36
  assert event_loop.time() == 2.0
@@ -53,7 +52,9 @@ def test_sleep_forever(event_loop):
53
52
  ]
54
53
  )
55
54
  @pytest.mark.parametrize('delay', [False, True])
56
- async def test_delayed_sock_recv(method, delay, event_loop):
55
+ async def test_delayed_sock_recv(method, delay):
56
+ event_loop = asyncio.get_running_loop()
57
+
57
58
  async def delayed_write(wsock):
58
59
  await asyncio.sleep(1)
59
60
  wsock.send(b'Hello')
@@ -76,7 +77,9 @@ async def test_delayed_sock_recv(method, delay, event_loop):
76
77
 
77
78
 
78
79
  @pytest.mark.parametrize('size', [10, 10**7])
79
- async def test_sock_sendall(size, event_loop):
80
+ async def test_sock_sendall(size):
81
+ event_loop = asyncio.get_running_loop()
82
+
80
83
  async def delayed_read(rsock):
81
84
  n = 0
82
85
  while True:
@@ -99,7 +102,8 @@ async def test_sock_sendall(size, event_loop):
99
102
  assert n == size
100
103
 
101
104
 
102
- async def test_connect_existing(event_loop, mocker):
105
+ async def test_connect_existing(mocker):
106
+ event_loop = asyncio.get_running_loop()
103
107
  sock1, sock2 = async_solipsism.socketpair()
104
108
  transport1, protocol1 = await event_loop.connect_accepted_socket(
105
109
  mocker.MagicMock, sock1)
@@ -128,7 +132,9 @@ async def test_stream():
128
132
 
129
133
 
130
134
  @pytest.mark.parametrize('manual_socket', [False, True])
131
- async def test_server(event_loop, manual_socket):
135
+ async def test_server(manual_socket):
136
+ event_loop = asyncio.get_running_loop()
137
+
132
138
  def callback(reader, writer):
133
139
  server_conn.set_result((reader, writer))
134
140
 
@@ -156,7 +162,7 @@ async def test_server(event_loop, manual_socket):
156
162
  await server.wait_closed()
157
163
 
158
164
 
159
- async def test_unused_port(event_loop):
165
+ async def test_unused_port():
160
166
  def callback(reader, writer):
161
167
  pass
162
168
 
@@ -172,7 +178,8 @@ async def test_unused_port(event_loop):
172
178
  await server2.wait_closed()
173
179
 
174
180
 
175
- async def test_close_server(event_loop):
181
+ async def test_close_server():
182
+ event_loop = asyncio.get_running_loop()
176
183
  server = await asyncio.start_server(lambda reader, writer: None, 'test.invalid', 1234)
177
184
  server.close()
178
185
  await server.wait_closed()
@@ -180,18 +187,21 @@ async def test_close_server(event_loop):
180
187
  await event_loop.create_connection('test.invalid', 1234)
181
188
 
182
189
 
183
- async def test_create_connection_no_listener(event_loop):
190
+ async def test_create_connection_no_listener():
191
+ event_loop = asyncio.get_running_loop()
184
192
  with pytest.raises(ConnectionRefusedError):
185
193
  await event_loop.create_connection('test.invalid', 1234)
186
194
 
187
195
 
188
- async def test_run_in_executor_implicit(event_loop):
196
+ async def test_run_in_executor_implicit():
197
+ event_loop = asyncio.get_running_loop()
189
198
  thread_id = await event_loop.run_in_executor(None, threading.get_ident)
190
199
  assert isinstance(thread_id, int)
191
200
  assert thread_id != threading.get_ident()
192
201
 
193
202
 
194
- async def test_run_in_executor_explicit(event_loop):
203
+ async def test_run_in_executor_explicit():
204
+ event_loop = asyncio.get_running_loop()
195
205
  my_executor = concurrent.futures.ThreadPoolExecutor(1)
196
206
  expected_thread_id = my_executor.submit(threading.get_ident).result()
197
207
  assert isinstance(expected_thread_id, int)
@@ -201,7 +211,8 @@ async def test_run_in_executor_explicit(event_loop):
201
211
 
202
212
 
203
213
  @pytest.mark.skipif("sys.version_info < (3, 7)")
204
- async def test_sendfile(event_loop, tmp_path):
214
+ async def test_sendfile(tmp_path):
215
+ event_loop = asyncio.get_running_loop()
205
216
  tmp_file = tmp_path / 'test_sendfile.txt'
206
217
  tmp_file.write_bytes(b'Hello world\n')
207
218
  ((reader1, writer1), (reader2, writer2)) = await async_solipsism.stream_pairs()
@@ -215,14 +226,17 @@ async def test_sendfile(event_loop, tmp_path):
215
226
  await writer2.wait_closed()
216
227
 
217
228
 
218
- async def test_call_soon_threadsafe(event_loop):
229
+ async def test_call_soon_threadsafe():
230
+ event_loop = asyncio.get_running_loop()
219
231
  future = event_loop.create_future()
220
232
  event_loop.call_soon_threadsafe(future.set_result, 3)
221
233
  result = await future
222
234
  assert result == 3
223
235
 
224
236
 
225
- async def test_call_soon_threadsafe_wrong_thread(event_loop):
237
+ async def test_call_soon_threadsafe_wrong_thread():
238
+ event_loop = asyncio.get_running_loop()
239
+
226
240
  def thread_func():
227
241
  event_loop.call_soon_threadsafe(lambda: None)
228
242
 
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Bruce Merry
1
+ # Copyright 2020, 2024 Bruce Merry
2
2
  #
3
3
  # This file is part of async-solipsism.
4
4
  #
@@ -15,7 +15,9 @@
15
15
  # You should have received a copy of the GNU General Public License
16
16
  # along with async-solipsism. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
+ import array
18
19
  import socket
20
+ import struct
19
21
 
20
22
  import pytest
21
23
 
@@ -69,3 +71,41 @@ def test_use_after_shutdown(end):
69
71
  assert sock0.recv(1) == b''
70
72
  with pytest.raises(BrokenPipeError):
71
73
  sock1.send(b'hello')
74
+
75
+
76
+ def test_recv_into_array():
77
+ sock1, sock2 = async_solipsism.socketpair()
78
+ data = array.array("I", [1, 2, 3])
79
+ sock1.send(b"\xDE\xAD\xBE\xEF")
80
+ nbytes = sock2.recv_into(data)
81
+ assert nbytes == 4
82
+ assert data[0] == struct.unpack("I", b"\xDE\xAD\xBE\xEF")[0]
83
+ assert data[1] == 2
84
+ assert data[2] == 3
85
+
86
+
87
+ def test_recv_into_array_partial():
88
+ sock1, sock2 = async_solipsism.socketpair()
89
+ data = array.array("I", [1, 2, 3])
90
+ sock1.send(b"\xDE\xAD\xBE\xEF\xCA\xFE")
91
+ nbytes = sock2.recv_into(data, 4)
92
+ assert nbytes == 4
93
+ assert data[0] == struct.unpack("I", b"\xDE\xAD\xBE\xEF")[0]
94
+ assert data[1] == 2
95
+ assert data[2] == 3
96
+
97
+
98
+ def test_write_array():
99
+ sock1, sock2 = async_solipsism.socketpair(capacity=100)
100
+ data = array.array("I", range(64))
101
+ nbytes = sock1.send(data)
102
+ assert nbytes == 100
103
+ received = sock2.recv(-1)
104
+ assert len(received) == 100
105
+ assert memoryview(received) == memoryview(data).cast("B")[:100]
106
+
107
+
108
+ @pytest.mark.parametrize("nbytes", [-1, 5])
109
+ def test_recv_into_bad_nbytes(sock, nbytes):
110
+ with pytest.raises(ValueError):
111
+ sock.recv_into(bytearray(4), nbytes=nbytes)
@@ -1,25 +0,0 @@
1
- name: Run tests
2
-
3
- on: [push]
4
-
5
- jobs:
6
- build:
7
- runs-on: ubuntu-latest
8
- strategy:
9
- matrix:
10
- python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
11
-
12
- steps:
13
- - uses: actions/checkout@v2
14
- - name: Set up Python ${{ matrix.python-version }}
15
- uses: actions/setup-python@v2
16
- with:
17
- python-version: ${{ matrix.python-version }}
18
- - name: Install dependencies
19
- run: pip install -r requirements.txt
20
- - name: Run flake8
21
- run: flake8
22
- - name: Install package
23
- run: pip install .
24
- - name: Run pytest
25
- run: pytest
@@ -1,2 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools", "wheel", "setuptools-scm"]
@@ -1,4 +0,0 @@
1
- flake8
2
- pytest
3
- pytest-asyncio
4
- pytest-mock
@@ -1,34 +0,0 @@
1
- [metadata]
2
- name = async-solipsism
3
- version = attr: src.async_solipsism.__version__
4
- description = Asyncio event loop that doesn't interact with the outside world
5
- long_description = file:README.md
6
- long_description_content_type = text/markdown
7
- author = Bruce Merry
8
- author_email = bmerry@gmail.com
9
- url = https://github.com/bmerry/async-solipsism
10
- classifiers =
11
- Development Status :: 3 - Alpha
12
- Framework :: AsyncIO
13
- License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
14
- Topic :: Software Development :: Testing :: Mocking
15
-
16
- [options]
17
- package_dir =
18
- = src
19
- packages = find:
20
- python_requires = >= 3.6
21
-
22
- [options.packages.find]
23
- where = src
24
-
25
- [options.extras_require]
26
- test =
27
- pytest
28
- pytest-asyncio
29
- pytest-mock
30
-
31
- [egg_info]
32
- tag_build =
33
- tag_date = 0
34
-
@@ -1,5 +0,0 @@
1
-
2
- [test]
3
- pytest
4
- pytest-asyncio
5
- pytest-mock
File without changes
File without changes
File without changes
File without changes