lclarkmichalek / pip2arch

Convert pypi packages to arch linux PKGBUILDs
81 stars 15 forks source link

XMLRPC is deprecated / ratelimit #22

Open RubenKelevra opened 2 years ago

RubenKelevra commented 2 years ago

They deprecated the xmlrpc and put a harsh rate limit on it:

The XML-RPC API will be deprecated in the future. Use of this API is not recommended, and existing consumers of the API should migrate to the RSS and/or JSON APIs instead.

As a result, this API has a very restrictive rate limit and it may be necessary to pause between successive requests.

Users of this API are strongly encouraged to subscribe to the pypi-announce mailing list for notices as we begin the process of removing XML-RPC from PyPI.

https://warehouse.pypa.io/api-reference/xml-rpc.html

That's why it's now failing to do anything:

$ pip2arch "packagename"
Traceback (most recent call last):
  File "/usr/bin/pip2arch", line 251, in <module>
    main()
  File "/usr/bin/pip2arch", line 234, in main
    p.get_package(name=args.pkgname, pyversion= args.pyversion,
  File "/usr/bin/pip2arch", line 73, in get_package
    raw_urls = self.client.release_urls(name, version)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1122, in __call__
    return self.__send(self.__name, args)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1464, in __request
    response = self.__transport.request(
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1166, in request
    return self.single_request(host, handler, request_body, verbose)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1182, in single_request
    return self.parse_response(resp)
  File "/usr/lib/python3.10/xmlrpc/client.py", line 1354, in parse_response
    return u.close()
  File "/usr/lib/python3.10/xmlrpc/client.py", line 668, in close
    raise Fault(**self._stack[0])
xmlrpc.client.Fault: <Fault -32500: 'HTTPTooManyRequests: The action could not be performed because there were too many requests by the client. Limit may reset in 1 seconds.'>
miguel9554 commented 1 year ago

I fixed it with this

diff --git a/pip2arch.py b/pip2arch.py
index e0df1e5..d499c7d 100755
--- a/pip2arch.py
+++ b/pip2arch.py
@@ -7,6 +7,7 @@ import datetime
 import logging
 import argparse
 import re
+import time

 # make this script work for python2 and python3
 # the try will fail on python3
@@ -15,6 +16,7 @@ try:
     from xmlrpclib import ServerProxy
 except NameError:
     from xmlrpc.client import ServerProxy
+    import xmlrpc.client

 BLANK_PKGBUILD = """\
 #Automatically generated by pip2arch on {date}
@@ -48,6 +50,10 @@ class pip2archException(Exception): pass
 class VersionNotFound(pip2archException): pass
 class LackOfInformation(pip2archException): pass

+
+max_retries = 5
+retry_delay = 2  # seconds
+
 class Package(object):
     logging.info('Creating Server Proxy object')
     client = ServerProxy('https://pypi.python.org/pypi')
@@ -67,10 +73,38 @@ class Package(object):
         self.version = version
         self.pyversion = pyversion

-        data = self.client.release_data(name, version)
+        for retry in range(max_retries):
+            try:
+                data = self.client.release_data(name, version)
+                # Process the data as needed
+                break  # Exit the loop if the request is successful
+            except xmlrpc.client.Fault as e:
+                if "HTTPTooManyRequests" in str(e):
+                    print(f"Rate limit exceeded. Retrying in {retry_delay} seconds...")
+                    time.sleep(retry_delay)
+                else:
+                    print(f"An error occurred: {e}")
+                    break  # Exit the loop if another error occurs
+        else:
+            print("Max retries reached. Could not fetch data.")
+
         logging.info('Got release_data from PyPi')

-        raw_urls = self.client.release_urls(name, version)
+        for retry in range(max_retries):
+            try:
+                raw_urls = self.client.release_urls(name, version)
+                # Process the data as needed
+                break  # Exit the loop if the request is successful
+            except xmlrpc.client.Fault as e:
+                if "HTTPTooManyRequests" in str(e):
+                    print(f"Rate limit exceeded. Retrying in {retry_delay} seconds...")
+                    time.sleep(retry_delay)
+                else:
+                    print(f"An error occurred: {e}")
+                    break  # Exit the loop if another error occurs
+        else:
+            print("Max retries reached. Could not fetch data.")
+
         logging.info('Got release_urls from PyPi')
         if not len(data):
             raise VersionNotFound('PyPi did not return any information for version {0}'.format(self.version))