-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix flaky fetch tests #255
Conversation
Codecov Report
@@ Coverage Diff @@
## main #255 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 37 37
Lines 2806 2806
=========================================
Hits 2806 2806
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
Not sure why Maybe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem with the code changes, but you'll need to fix the napari tests before merging. As discussed offline, I think one way to do this is make a PR to napari/napari
that moves disable_notification_dismiss_timer
to test_qt_notifications.py
, so that it's only auto-used in that test module (which shouldn't be run here).
I don't really know why I ended up looking into this, but it looks like the issue is scraping PyPI defaulting to "Most Relevant" sorting which seems to be unstable. This might ultimately be a warehouse bug because that kinda sucks even if you're using a browser. Ordering by "Date last updated" seems to fix it (at least I was able to run 331 times in a row without the failure): diff --git a/npe2/_inspection/_fetch.py b/npe2/_inspection/_fetch.py
index 23e2d76..bf4a5b0 100644
--- a/npe2/_inspection/_fetch.py
+++ b/npe2/_inspection/_fetch.py
@@ -384,7 +384,7 @@ def _get_packages_by_classifier(classifier: str) -> Dict[str, str]:
packages = {}
page = 1
- url = f"https://pypi.org/search/?c={parse.quote_plus(classifier)}&page="
+ url = f"https://pypi.org/search/?q=&o=-created&c={parse.quote_plus(classifier)}&page="
while True:
try:
with request.urlopen(f"{url}{page}") as response: With the above change (note 264 is the number of plugins the web interface reports as well):
Without this change:
|
Another option would be to use the (to-be-deprecated) XML RPC API: |
This might be the way - it's also super fast (~300 ms vs ~6s). The results seem to already be sorted but I'm not sure this is guaranteed and it's diff --git a/npe2/_inspection/_fetch.py b/npe2/_inspection/_fetch.py
index 23e2d76..d1a1b69 100644
--- a/npe2/_inspection/_fetch.py
+++ b/npe2/_inspection/_fetch.py
@@ -6,6 +6,7 @@ import os
import re
import subprocess
import tempfile
+import xmlrpc.client
from concurrent.futures import ProcessPoolExecutor
from contextlib import contextmanager
from functools import lru_cache
@@ -376,27 +377,11 @@ def _get_packages_by_classifier(classifier: str) -> Dict[str, str]:
Returns
-------
- packages : List[str]
+ packages : Dict[str, str]
name of all packages at pypi that declare ``classifier``
"""
- PACKAGE_NAME_PATTERN = re.compile('class="package-snippet__name">(.+)</span>')
- PACKAGE_VERSION_PATTERN = re.compile('class="package-snippet__version">(.+)</span>')
-
- packages = {}
- page = 1
- url = f"https://pypi.org/search/?c={parse.quote_plus(classifier)}&page="
- while True:
- try:
- with request.urlopen(f"{url}{page}") as response:
- html = response.read().decode()
- names = PACKAGE_NAME_PATTERN.findall(html)
- versions = PACKAGE_VERSION_PATTERN.findall(html)
- packages.update(dict(zip(names, versions)))
- page += 1
- except error.HTTPError:
- break
-
- return dict(sorted(packages.items()))
+ client = xmlrpc.client.ServerProxy('https://pypi.org/pypi')
+ return dict(client.browse([classifier])) Sample output
|
napari/napari#5388 fixed the last remaining issue I was having |
@aganders3 Thanks for looking into the xmlrpc api! Given that it's on the way to deprecation, do you still think that's the right approach? Is there a simple api equivalent? |
I'm not sure - there's a bit of history here including past requests from napari: pypi/warehouse#9156. Their timeline is very vague but I would suspect they will not remove it until there is an equivalent new API. If not I would hope for a concrete deprecation period to be announced at some point. One idea is to use the XML RPC API and fall back on the current method. The XML RPC API has some methods already deprecated that now raise a Regardless I think it could be saved for another PR - for now I guess I would just recommend adding the change proposed in my other comment above #255 (comment). It's small and could be added here or I can make another PR for that. |
Two test issues here:
It seems like hitting the pypi and hub api's failed to return napari-svg sometimes. For pypi this is about 1 out of every 2 or 3 attempts. For hub it's rarer. Not quite sure why it's happening. There's meaningful data in the response either way, but sometimes
napari-svg
isn't in the return. Not sure what the best fix is here. For now, I just check that the response data is non-empty.The fetch-cli test was failing because it's looking at
napari-omero
which has a unicode red exclamation mark in it's package metadata. This causes character validation errors where the encoding of the string is unspecified. This is fixed by specifying 'utf-8' in a couple places in the pr.