Skip to content

Commit 0d0245c

Browse files
authored
Unpin urllib3 (#810)
* Unpin urllib3 * Fix rq instrumentation, change tox deps * Swap in mocket for httpretty * Pin elasticsearch until we can verify compat * Artifact naming, download update * Set up trusted publishing
1 parent b5b7f3a commit 0d0245c

File tree

7 files changed

+73
-108
lines changed

7 files changed

+73
-108
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
python-version:
22-
- "3.8"
2322
- "3.9"
2423
- "3.10"
2524
- "3.11"
@@ -50,57 +49,8 @@ jobs:
5049
REDIS_URL: redis://localhost:6379/0
5150

5251
steps:
53-
- uses: actions/checkout@v3
54-
- uses: actions/setup-python@v4
55-
with:
56-
python-version: ${{ matrix.python-version }}
57-
- name: Upgrade packaging tools
58-
run: python -m pip install --upgrade pip setuptools importlib_metadata virtualenv
59-
- name: Install dependencies
60-
run: python -m pip install --upgrade tox
61-
- name: Run tox targets for ${{ matrix.python-version }}
62-
run: |
63-
ENV_PREFIX=$(tr -C -d "0-9" <<< "${{ matrix.python-version }}" | cut -c -3)
64-
TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') python -m tox
65-
66-
tests-ubuntu-20:
67-
name: Python ${{ matrix.python-version }} Ubuntu 20
68-
runs-on: ubuntu-20.04
69-
70-
strategy:
71-
fail-fast: false
72-
matrix:
73-
python-version:
74-
- "3.8"
75-
- "3.9"
76-
77-
services:
78-
elasticsearch:
79-
image: elasticsearch:7.10.1
80-
ports:
81-
- 9200:9200
82-
env:
83-
discovery.type: single-node
84-
xpack.security.enabled: false
85-
86-
mongodb:
87-
image: mongo:4
88-
ports:
89-
- 27017:27017
90-
91-
redis:
92-
image: redis:6
93-
ports:
94-
- 6379:6379
95-
96-
env:
97-
ELASTICSEARCH_URL: http://localhost:9200/
98-
MONGODB_URL: mongodb://localhost:27017/
99-
REDIS_URL: redis://localhost:6379/0
100-
101-
steps:
102-
- uses: actions/checkout@v3
103-
- uses: actions/setup-python@v4
52+
- uses: actions/checkout@v4
53+
- uses: actions/setup-python@v5
10454
with:
10555
python-version: ${{ matrix.python-version }}
10656
- name: Upgrade packaging tools

.github/workflows/release.yml

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ jobs:
1414
runs-on: ${{ matrix.os }}
1515
strategy:
1616
matrix:
17-
os: [ ubuntu-20.04 ]
17+
os: [ ubuntu-22.04 ]
1818
python: ['3.10']
1919
manylinux_image: [ manylinux2014, manylinux_2_28 ]
2020
# Disable for platforms where pure Python wheels would be generated
21-
cibw_skip: [ "pp38-* pp39-* pp310-* pp311-*" ]
21+
cibw_skip: [ "pp38-* pp39-* pp310-* pp311-* pp312-* pp313-*" ]
2222
steps:
23-
- uses: actions/checkout@v3
23+
- uses: actions/checkout@v4
2424

25-
- uses: actions/setup-python@v4
25+
- uses: actions/setup-python@v5
2626
name: Install Python
2727
with:
2828
python-version: ${{ matrix.python }}
@@ -47,17 +47,18 @@ jobs:
4747
CIBW_ARCHS_LINUX: "auto aarch64"
4848
run: python -m cibuildwheel
4949

50-
- uses: actions/upload-artifact@v3
50+
- uses: actions/upload-artifact@v4
5151
with:
52+
name: ${{ matrix.manylinux_image }}-${{ matrix.python }}-${{ matrix.os }}
5253
path: ./wheelhouse/*.whl
5354

5455
build_macos_wheels:
5556
name: Build macos wheels (cross-compiles arm64)
5657
runs-on: macos-13
5758
steps:
58-
- uses: actions/checkout@v3
59+
- uses: actions/checkout@v4
5960

60-
- uses: actions/setup-python@v4
61+
- uses: actions/setup-python@v5
6162
name: Install Python
6263
with:
6364
python-version: "3.10"
@@ -72,23 +73,24 @@ jobs:
7273
CIBW_ARCHS_MACOS: "x86_64 arm64"
7374
run: python -m cibuildwheel
7475

75-
- uses: actions/upload-artifact@v3
76+
- uses: actions/upload-artifact@v4
7677
with:
78+
name: macos
7779
path: ./wheelhouse/*.whl
7880

7981
build_pure_wheels:
8082
name: Build pure python wheels
81-
runs-on: ubuntu-20.04
83+
runs-on: ubuntu-24.04
8284
strategy:
8385
matrix:
84-
python: [3.9]
86+
python: [3.8, 3.9]
8587
steps:
86-
- uses: actions/checkout@v3
88+
- uses: actions/checkout@v4
8789

88-
- uses: actions/setup-python@v4
90+
- uses: actions/setup-python@v5
8991
name: Install Python
9092
with:
91-
python-version: ${{ matrix.python-version }}
93+
python-version: ${{ matrix.python }}
9294
- name: Install packaging tools
9395
run: |
9496
python -m pip install --upgrade pip setuptools importlib_metadata wheel
@@ -98,49 +100,52 @@ jobs:
98100
SCOUT_DISABLE_EXTENSIONS: "1"
99101
run: python setup.py bdist_wheel
100102

101-
- uses: actions/upload-artifact@v3
103+
- uses: actions/upload-artifact@v4
102104
with:
105+
name: pp${{ matrix.python }}
103106
path: dist/*.whl
104107

105108
build_sdist:
106109
name: Build source distribution
107-
runs-on: ubuntu-20.04
110+
runs-on: ubuntu-22.04
108111
steps:
109-
- uses: actions/checkout@v3
112+
- uses: actions/checkout@v4
110113

111-
- uses: actions/setup-python@v3
114+
- uses: actions/setup-python@v5
112115
name: Install Python
113116
with:
114117
python-version: 3.9
115118

116119
- name: Build sdist
117120
run: python setup.py sdist
118121

119-
- uses: actions/upload-artifact@v3
122+
- uses: actions/upload-artifact@v4
120123
with:
124+
name: sdist
121125
path: dist/*.tar.gz
122126

123127
upload_pypi:
124128
needs: [cibuildwheel_py38plus, build_pure_wheels, build_sdist, build_macos_wheels]
125-
runs-on: ubuntu-20.04
129+
runs-on: ubuntu-24.04
130+
permissions:
131+
id-token: write
126132
steps:
127133
- name: Download distributions for publishing.
128-
uses: actions/download-artifact@v3
134+
uses: actions/download-artifact@v4
129135
with:
130-
name: artifact
131136
path: dist
137+
merge-multiple: true
132138

133139
- name: Publish distributions to Test PyPI
134140
uses: pypa/gh-action-pypi-publish@release/v1
135141
with:
136142
user: __token__
137143
password: ${{ secrets.TEST_TWINE_PASSWORD }}
138-
repository_url: https://test.pypi.org/legacy/
144+
repository-url: https://test.pypi.org/legacy/
139145
skip_existing: true
140146

141147
- name: Publish distributions to PyPI
142148
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
143149
uses: pypa/gh-action-pypi-publish@release/v1
144150
with:
145151
user: __token__
146-
password: ${{ secrets.TWINE_PASSWORD }}

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
install_requires=[
6161
"asgiref",
6262
"psutil>=5",
63-
"urllib3~=2.2.0",
63+
"urllib3",
6464
"certifi",
6565
"wrapt>=1.10,<2.0",
6666
],

src/scout_apm/rq.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ def wrap_perform(wrapped, instance, args, kwargs):
7373
# assumption here.
7474
if instance.enqueued_at.tzinfo is None:
7575
queued_at = instance.enqueued_at.replace(tzinfo=dt.timezone.utc)
76+
else:
77+
queued_at = instance.enqueued_at
7678
queue_time = (dt.datetime.now(dt.timezone.utc) - queued_at).total_seconds()
7779
tracked_request.tag("queue_time", queue_time)
7880
operation = "Job/{}".format(instance.func_name)

tests/integration/core/test_error_service.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
from datetime import datetime, timezone
77
from time import sleep
88

9-
import httpretty
109
import pytest
10+
from mocket import Mocketizer
11+
from mocket.plugins.httpretty import httpretty
1112

1213
from scout_apm.core.config import scout_config
1314
from scout_apm.core.error_service import ErrorServiceThread
@@ -32,6 +33,7 @@ def error_monitor_errors(error_monitor_errors):
3233
return error_monitor_errors
3334

3435

36+
@pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
3537
@pytest.mark.parametrize(
3638
"config, decoded_body, expected_headers, expected_uri",
3739
[
@@ -73,7 +75,7 @@ def test_send(
7375
scout_config.set(**config)
7476

7577
try:
76-
with httpretty.enabled(allow_net_connect=False):
78+
with Mocketizer():
7779
httpretty.register_uri(
7880
httpretty.POST,
7981
expected_uri,
@@ -82,16 +84,18 @@ def test_send(
8284
ErrorServiceThread.send(error={"foo": "BØØM!"})
8385
ErrorServiceThread.wait_until_drained()
8486

85-
request = httpretty.last_request()
86-
assert (
87-
json.loads(gzip_decompress(request.body).decode("utf-8"))
88-
== decoded_body
89-
)
90-
assert request.headers.get("X-Error-Count") == "1"
87+
# TODO - this is a hack to get the request body
88+
request = httpretty.last_request
89+
_ = request.event
90+
raw_body = httpretty.last_request._parser.next_event().data
91+
92+
assert json.loads(gzip_decompress(raw_body).decode("utf-8")) == decoded_body
93+
assert request.headers.get("x-error-count") == "1"
9194
finally:
9295
scout_config.reset_all()
9396

9497

98+
@pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
9599
def test_send_batch(error_service_thread):
96100
decompressed_body = {
97101
"notifier": "scout_apm_python",
@@ -100,7 +104,7 @@ def test_send_batch(error_service_thread):
100104
"problems": [{"foo": 0}, {"foo": 1}, {"foo": 2}, {"foo": 3}, {"foo": 4}],
101105
}
102106
try:
103-
with httpretty.enabled(allow_net_connect=False):
107+
with Mocketizer():
104108
httpretty.register_uri(
105109
httpretty.POST,
106110
"https://errors.scoutapm.com/apps/error.scout",
@@ -110,19 +114,23 @@ def test_send_batch(error_service_thread):
110114
ErrorServiceThread.send(error={"foo": i})
111115
ErrorServiceThread.wait_until_drained()
112116

113-
request = httpretty.last_request()
117+
# TODO - this is a hack to get the request body
118+
request = httpretty.last_request
119+
_ = request.event
120+
raw_body = httpretty.last_request._parser.next_event().data
114121
assert (
115-
json.loads(gzip_decompress(request.body).decode("utf-8"))
122+
json.loads(gzip_decompress(raw_body).decode("utf-8"))
116123
== decompressed_body
117124
)
118-
assert request.headers.get("X-Error-Count") == "5"
125+
assert request.headers.get("x-error-count") == "5"
119126
finally:
120127
scout_config.reset_all()
121128

122129

130+
@pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
123131
def test_send_api_error(error_service_thread, caplog):
124132
try:
125-
with httpretty.enabled(allow_net_connect=False):
133+
with Mocketizer():
126134
httpretty.register_uri(
127135
httpretty.POST,
128136
"https://errors.scoutapm.com/apps/error.scout",
@@ -140,8 +148,9 @@ def test_send_api_error(error_service_thread, caplog):
140148
)
141149

142150

151+
@pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
143152
def test_send_unserializable_data(error_service_thread, caplog):
144-
with httpretty.enabled(allow_net_connect=False):
153+
with Mocketizer():
145154
ErrorServiceThread.send(error={"value": datetime.now(tz=timezone.utc)})
146155
ErrorServiceThread.wait_until_drained()
147156

tests/integration/instruments/test_urllib3.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import logging
44

5-
import httpretty
65
import pytest
6+
from mocket import Mocketizer
7+
from mocket.mockhttp import Entry
8+
from mocket.plugins.httpretty import httprettified, httpretty
79

810
from scout_apm.compat import urllib3_cert_pool_manager
911
from scout_apm.instruments.urllib3 import ensure_installed
@@ -70,13 +72,12 @@ def test_install_fail_no_urlopen_attribute(caplog):
7072
)
7173

7274

75+
@pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
7376
def test_request(tracked_request):
7477
ensure_installed()
75-
with httpretty.enabled(allow_net_connect=False):
76-
httpretty.register_uri(
77-
httpretty.GET, "https://example.com/", body="Hello World!"
78-
)
78+
Entry.single_register(Entry.GET, "https://example.com/", body="Hello World!")
7979

80+
with Mocketizer(strict_mode=True):
8081
http = urllib3_cert_pool_manager()
8182
response = http.request("GET", "https://example.com")
8283

@@ -101,15 +102,16 @@ def test_request_type_error(tracked_request):
101102
assert span.tags["url"] == "https://example.com:443/"
102103

103104

105+
@pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
106+
@httprettified
104107
def test_request_ignore_errors_host(tracked_request):
105108
ensure_installed()
106-
with httpretty.enabled(allow_net_connect=False):
107-
httpretty.register_uri(
108-
httpretty.POST, "https://errors.scoutapm.com", body="Hello World!"
109-
)
109+
httpretty.register_uri(
110+
httpretty.POST, "https://errors.scoutapm.com", body="Hello World!"
111+
)
110112

111-
http = urllib3_cert_pool_manager()
112-
response = http.request("POST", "https://errors.scoutapm.com")
113+
http = urllib3_cert_pool_manager()
114+
response = http.request("POST", "https://errors.scoutapm.com")
113115

114116
assert response.status == 200
115117
assert response.data == b"Hello World!"

0 commit comments

Comments
 (0)