Skip to content

Commit 1e6c937

Browse files
TimPansinolrafeei
andauthored
Add Python 3.11 Support (#654)
* Add py311 tests * Fix typo * Added 3.11 support for aiohttp framework Co-authored-by: Timothy Pansino <[email protected]> * Set up environment to run Python 3.11 Co-authored-by: Timothy Pansino <[email protected]> * Add Python 3.11 support for agent_features Co-authored-by: Timothy Pansino <[email protected]> * Partial Python 3.11 support added for Tornado Co-authored-by: Timothy Pansino <[email protected]> * Adjust postgres versions * Fix tornado install path locally * Remove aioredis py311 tests * Update 3.11 to dev in tests * Fix sanic instrumentation and imp/importlib deprecation Co-authored-by: Timothy Pansino <[email protected]> * Simplify wheel build options * Update cibuildwheel for 3.11 * Remove falconmaster py311 test Co-authored-by: Lalleh Rafeei <[email protected]> Co-authored-by: Timothy Pansino <[email protected]>
1 parent 03131c9 commit 1e6c937

27 files changed

+867
-912
lines changed

.devcontainer/dotfiles

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 4d575e4d60a9f195f9f315dde7f380a5ae26e27d

.github/actions/setup-python-matrix/action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ runs:
3333
python-version: "3.10"
3434
architecture: x64
3535

36+
- uses: actions/setup-python@v3
37+
with:
38+
python-version: "3.11-dev"
39+
architecture: x64
40+
3641
- uses: actions/setup-python@v3
3742
with:
3843
python-version: "2.7"

.github/workflows/deploy-python.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ jobs:
5454
CIBW_ENVIRONMENT: "LD_LIBRARY_PATH=/opt/rh/=vtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib:/opt/rh/devtoolset-8/root/usr/lib64/dyninst:/opt/rh/devtoolset-8/root/usr/lib/dyninst:/usr/local/lib64:/usr/local/lib"
5555

5656
- name: Build Manylinux Wheels (Python 3)
57-
uses: pypa/cibuildwheel@v2.1.3
57+
uses: pypa/cibuildwheel@v2.11.1
5858
env:
5959
CIBW_PLATFORM: linux
60-
CIBW_BUILD: cp37-manylinux_aarch64 cp38-manylinux_aarch64 cp39-manylinux_aarch64 cp310-manylinux_aarch64 cp37-manylinux_x86_64 cp38-manylinux_x86_64 cp39-manylinux_x86_64 cp310-manylinux_x86_64
60+
CIBW_BUILD: cp37-manylinux* cp38-manylinux* cp39-manylinux* cp310-manylinux* cp311-manylinux*
6161
CIBW_ARCHS: x86_64 aarch64
6262
CIBW_ENVIRONMENT: "LD_LIBRARY_PATH=/opt/rh/devtoolset-8/root/usr/lib64:/opt/rh/devtoolset-8/root/usr/lib:/opt/rh/devtoolset-8/root/usr/lib64/dyninst:/opt/rh/devtoolset-8/root/usr/lib/dyninst:/usr/local/lib64:/usr/local/lib"
6363

newrelic/hooks/framework_aiohttp.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
import asyncio
14+
1515
import inspect
1616
import itertools
1717

@@ -163,9 +163,8 @@ def _bind_params(request):
163163

164164
@function_wrapper
165165
def _nr_aiohttp_wrap_middleware_(wrapped, instance, args, kwargs):
166-
@asyncio.coroutine
167-
def _inner():
168-
result = yield from wrapped(*args, **kwargs)
166+
async def _inner():
167+
result = await wrapped(*args, **kwargs)
169168
return function_trace()(result)
170169

171170
return _inner()
@@ -221,10 +220,9 @@ def _nr_aiohttp_add_cat_headers_(wrapped, instance, args, kwargs):
221220

222221
if is_coroutine_callable(wrapped):
223222

224-
@asyncio.coroutine
225-
def new_coro():
223+
async def new_coro():
226224
try:
227-
result = yield from wrapped(*args, **kwargs)
225+
result = await wrapped(*args, **kwargs)
228226
return result
229227
finally:
230228
instance.headers = tmp
@@ -267,10 +265,9 @@ def _nr_aiohttp_request_wrapper_(wrapped, instance, args, kwargs):
267265
method, url = _bind_request(*args, **kwargs)
268266
trace = ExternalTrace("aiohttp", str(url), method)
269267

270-
@asyncio.coroutine
271-
def _coro():
268+
async def _coro():
272269
try:
273-
response = yield from wrapped(*args, **kwargs)
270+
response = await wrapped(*args, **kwargs)
274271

275272
try:
276273
trace.process_response_headers(response.headers.items())
@@ -332,14 +329,10 @@ def _nr_request_wrapper(wrapped, instance, args, kwargs):
332329

333330
coro = wrapped(*args, **kwargs)
334331

335-
if hasattr(coro, "__await__"):
336-
coro = coro.__await__()
337-
338-
@asyncio.coroutine
339-
def _coro(*_args, **_kwargs):
332+
async def _coro(*_args, **_kwargs):
340333
transaction = current_transaction()
341334
if transaction is None:
342-
response = yield from coro
335+
response = await coro
343336
return response
344337

345338
# Patch in should_ignore to all notice_error calls
@@ -352,7 +345,7 @@ def _coro(*_args, **_kwargs):
352345
import aiohttp.web as _web
353346

354347
try:
355-
response = yield from coro
348+
response = await coro
356349
except _web.HTTPException as e:
357350
_nr_process_response(e, transaction)
358351
raise

newrelic/hooks/framework_sanic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,4 +311,4 @@ def instrument_sanic_response(module):
311311

312312
def instrument_sanic_touchup_service(module):
313313
if hasattr(module, "TouchUp") and hasattr(module.TouchUp, "run"):
314-
wrap_function_wrapper(module.TouchUp, "run", _nr_wrap_touchup_run)
314+
wrap_function_wrapper(module, "TouchUp.run", _nr_wrap_touchup_run)

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def build_extension(self, ext):
121121
"Programming Language :: Python :: 3.8",
122122
"Programming Language :: Python :: 3.9",
123123
"Programming Language :: Python :: 3.10",
124+
"Programming Language :: Python :: 3.11",
124125
"Programming Language :: Python :: Implementation :: CPython",
125126
"Programming Language :: Python :: Implementation :: PyPy",
126127
"Topic :: System :: Monitoring",

tests/agent_features/_test_async_coroutine_trace.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import asyncio
1616
import functools
17+
import sys
1718
import time
1819

1920
import pytest
@@ -68,6 +69,7 @@ def _test():
6869
assert full_metrics[metric_key].total_call_time >= 0.1
6970

7071

72+
@pytest.mark.skipif(sys.version_info >= (3, 11), reason="Asyncio decorator was removed in Python 3.11+.")
7173
@pytest.mark.parametrize(
7274
"trace,metric",
7375
[

tests/agent_features/test_async_timing.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,15 @@ def _validate_total_time_value(wrapped, instance, args, kwargs):
4444

4545

4646
@function_trace(name="child")
47-
@asyncio.coroutine
48-
def child():
49-
yield from asyncio.sleep(0.1)
47+
async def child():
48+
await asyncio.sleep(0.1)
5049

5150

5251
@background_task(name="parent")
53-
@asyncio.coroutine
54-
def parent(calls):
52+
async def parent(calls):
5553
coros = [child() for _ in range(calls)]
56-
yield from asyncio.gather(*coros)
57-
yield from asyncio.sleep(0.1)
54+
await asyncio.gather(*coros)
55+
await asyncio.sleep(0.1)
5856

5957

6058
@validate_total_time_value_greater_than(0.2)

tests/agent_features/test_coroutine_trace.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,33 +105,30 @@ def test_coroutine_siblings(event_loop):
105105
# the case if child was a child of child since child is terminal)
106106

107107
@function_trace("child", terminal=True)
108-
@asyncio.coroutine
109-
def child(wait, event=None):
108+
async def child(wait, event=None):
110109
if event:
111110
event.set()
112-
yield from wait.wait()
111+
await wait.wait()
113112

114-
@asyncio.coroutine
115-
def middle():
113+
async def middle():
116114
wait = asyncio.Event()
117115
started = asyncio.Event()
118116

119117
child_0 = asyncio.ensure_future(child(wait, started))
120118

121119
# Wait for the first child to start
122-
yield from started.wait()
120+
await started.wait()
123121

124122
child_1 = asyncio.ensure_future(child(wait))
125123

126124
# Allow children to complete
127125
wait.set()
128-
yield from child_1
129-
yield from child_0
126+
await child_1
127+
await child_0
130128

131129
@function_trace("parent")
132-
@asyncio.coroutine
133-
def parent():
134-
yield from asyncio.ensure_future(middle())
130+
async def parent():
131+
await asyncio.ensure_future(middle())
135132

136133
event_loop.run_until_complete(parent())
137134

@@ -465,15 +462,13 @@ def test_trace_outlives_transaction(event_loop):
465462
running, finish = asyncio.Event(), asyncio.Event()
466463

467464
@function_trace(name="coro")
468-
@asyncio.coroutine
469-
def _coro():
465+
async def _coro():
470466
running.set()
471-
yield from finish.wait()
467+
await finish.wait()
472468

473-
@asyncio.coroutine
474-
def parent():
469+
async def parent():
475470
task.append(asyncio.ensure_future(_coro()))
476-
yield from running.wait()
471+
await running.wait()
477472

478473
@validate_transaction_metrics(
479474
"test_trace_outlives_transaction",

tests/agent_features/test_coroutine_transaction.py

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@
3939

4040
def coroutine_test(event_loop, transaction, nr_enabled=True, does_hang=False, call_exit=False, runtime_error=False):
4141
@transaction
42-
@asyncio.coroutine
43-
def task():
42+
async def task():
4443
txn = current_transaction()
4544

4645
if not nr_enabled:
@@ -55,15 +54,15 @@ def task():
5554

5655
try:
5756
if does_hang:
58-
yield from loop.create_future()
57+
await loop.create_future() # noqa
5958
else:
60-
yield from asyncio.sleep(0.0)
59+
await asyncio.sleep(0.0)
6160
if nr_enabled and txn.enabled:
6261
# Validate loop time is recorded after suspend
6362
assert txn._loop_time > 0.0
6463
except GeneratorExit:
6564
if runtime_error:
66-
yield from asyncio.sleep(0.0)
65+
await asyncio.sleep(0.0)
6766

6867
return task
6968

@@ -160,11 +159,10 @@ def test_async_coroutine_throw_cancel(event_loop, num_coroutines, create_test_ta
160159

161160
tasks = [create_test_task(event_loop, transaction) for _ in range(num_coroutines)]
162161

163-
@asyncio.coroutine
164-
def task_c():
162+
async def task_c():
165163
futures = [asyncio.ensure_future(t()) for t in tasks]
166164

167-
yield from asyncio.sleep(0.0)
165+
await asyncio.sleep(0.0)
168166

169167
[f.cancel() for f in futures]
170168

@@ -195,8 +193,7 @@ def test_async_coroutine_throw_error(event_loop, num_coroutines, create_test_tas
195193

196194
tasks = [create_test_task(event_loop, transaction) for _ in range(num_coroutines)]
197195

198-
@asyncio.coroutine
199-
def task_c():
196+
async def task_c():
200197
coros = [t() for t in tasks]
201198

202199
for coro in coros:
@@ -232,14 +229,13 @@ def test_async_coroutine_close(event_loop, num_coroutines, create_test_task, tra
232229

233230
tasks = [create_test_task(event_loop, transaction) for _ in range(num_coroutines)]
234231

235-
@asyncio.coroutine
236-
def task_c():
232+
async def task_c():
237233
coros = [t() for t in tasks]
238234

239235
if start_coroutines:
240236
[asyncio.ensure_future(coro) for coro in coros]
241237

242-
yield from asyncio.sleep(0.0)
238+
await asyncio.sleep(0.0)
243239

244240
[coro.close() for coro in coros]
245241

@@ -273,13 +269,12 @@ def test_async_coroutine_close_raises_error(event_loop, num_coroutines, create_t
273269

274270
tasks = [create_test_task(event_loop, transaction, runtime_error=True) for _ in range(num_coroutines)]
275271

276-
@asyncio.coroutine
277-
def task_c():
272+
async def task_c():
278273
coros = [t() for t in tasks]
279274

280275
[c.send(None) for c in coros]
281276

282-
yield from asyncio.sleep(0.0)
277+
await asyncio.sleep(0.0)
283278

284279
for coro in coros:
285280
with pytest.raises(RuntimeError):
@@ -313,24 +308,21 @@ def test_deferred_async_background_task(event_loop, transaction, metric, argumen
313308
args, kwargs = arguments("deferred")
314309

315310
@transaction(*args, **kwargs)
316-
@asyncio.coroutine
317-
def child_task():
318-
yield from asyncio.sleep(0)
311+
async def child_task():
312+
await asyncio.sleep(0)
319313

320314
main_metric = (metric % "main", "")
321315

322316
args, kwargs = arguments("main")
323317

324318
@transaction(*args, **kwargs)
325-
@asyncio.coroutine
326-
def parent_task():
327-
yield from asyncio.sleep(0)
319+
async def parent_task():
320+
await asyncio.sleep(0)
328321
return event_loop.create_task(child_task())
329322

330-
@asyncio.coroutine
331-
def test_runner():
332-
child = yield from parent_task()
333-
yield from child
323+
async def test_runner():
324+
child = await parent_task()
325+
await child
334326

335327
metrics = []
336328

@@ -362,18 +354,16 @@ def test_child_transaction_when_parent_is_running(event_loop, transaction, metri
362354
args, kwargs = arguments("deferred")
363355

364356
@transaction(*args, **kwargs)
365-
@asyncio.coroutine
366-
def child_task():
367-
yield from asyncio.sleep(0)
357+
async def child_task():
358+
await asyncio.sleep(0)
368359

369360
main_metric = (metric % "main", "")
370361

371362
args, kwargs = arguments("main")
372363

373364
@transaction(*args, **kwargs)
374-
@asyncio.coroutine
375-
def parent_task():
376-
yield from event_loop.create_task(child_task())
365+
async def parent_task():
366+
await event_loop.create_task(child_task())
377367

378368
metrics = []
379369

@@ -405,9 +395,8 @@ def test_nested_coroutine_inside_sync(event_loop, transaction, metric, arguments
405395
args, kwargs = arguments("child")
406396

407397
@transaction(*args, **kwargs)
408-
@asyncio.coroutine
409-
def child_task():
410-
yield from asyncio.sleep(0)
398+
async def child_task():
399+
await asyncio.sleep(0)
411400

412401
main_metric = (metric % "main", "")
413402
args, kwargs = arguments("main")
@@ -443,22 +432,20 @@ def test_nested_coroutine_task_already_active(event_loop, transaction, metric, a
443432
args, kwargs = arguments("deferred")
444433

445434
@transaction(*args, **kwargs)
446-
@asyncio.coroutine
447-
def child_task():
448-
yield from asyncio.sleep(0)
435+
async def child_task():
436+
await asyncio.sleep(0)
449437

450438
@function_trace()
451-
def child_trace():
452-
yield from child_task()
439+
async def child_trace():
440+
await child_task()
453441

454442
main_metric = (metric % "main", "")
455443

456444
args, kwargs = arguments("main")
457445

458446
@transaction(*args, **kwargs)
459-
@asyncio.coroutine
460-
def parent_task():
461-
yield from event_loop.create_task(child_trace())
447+
async def parent_task():
448+
await event_loop.create_task(child_trace())
462449

463450
metrics = []
464451

0 commit comments

Comments
 (0)