<pre style='margin:0'>
Joshua Root (jmroot) pushed a commit to branch master
in repository macports-contrib.

</pre>
<p><a href="https://github.com/macports/macports-contrib/commit/da2eee9cc46c29e42ab04cf8c48c78cb093a5ced">https://github.com/macports/macports-contrib/commit/da2eee9cc46c29e42ab04cf8c48c78cb093a5ced</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'>     new da2eee9  pypi2port: use PyPI's JSON API
</span>da2eee9 is described below

<span style='display:block; white-space:pre;color:#808000;'>commit da2eee9cc46c29e42ab04cf8c48c78cb093a5ced
</span>Author: Joshua Root <jmr@macports.org>
AuthorDate: Tue Jun 20 17:17:12 2023 +1000

<span style='display:block; white-space:pre;color:#404040;'>    pypi2port: use PyPI's JSON API
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    The XML-RPC API is deprecated. Also remove search option since that API
</span><span style='display:block; white-space:pre;color:#404040;'>    has been permanently disabled on PyPI.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Closes: https://trac.macports.org/ticket/51932
</span>---
 pypi2port/pypi2port.py | 107 +++++++++++++++++++++++--------------------------
 1 file changed, 50 insertions(+), 57 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/pypi2port/pypi2port.py b/pypi2port/pypi2port.py
</span><span style='display:block; white-space:pre;color:#808080;'>index a2bb16c..227820e 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/pypi2port/pypi2port.py
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/pypi2port/pypi2port.py
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -25,11 +25,7 @@ import sys
</span> import os
 import hashlib
 import zipfile
<span style='display:block; white-space:pre;background:#ffe0e0;'>-import requests
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-try:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   import xmlrpclib
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-except ImportError:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   import xmlrpc.client as xmlrpclib
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+import json
</span> import textwrap
 import string
 import shutil
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -38,35 +34,36 @@ import difflib
</span> import subprocess
 import time
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+import requests
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-client = xmlrpclib.ServerProxy('https://pypi.org/pypi')
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+simple_baseurl = 'https://pypi.org/simple/'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+json_baseurl = 'https://pypi.org/pypi/'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+package_data = {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+def fetch_as_json(url):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    headers = {'Accept': 'application/vnd.pypi.simple.v1+json'}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    r = requests.get(url, headers=headers)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    r.raise_for_status()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return r.json()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+def populate_package_data(pkgname, pkgvers=None):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if pkgname not in package_data:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        package_data[pkgname] = {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if pkgvers not in package_data[pkgname]:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if pkgvers:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            package_data[pkgname][pkgvers] = fetch_as_json(json_baseurl+pkgname+'/'+pkgvers+'/json')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        else:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            package_data[pkgname][pkgvers] = fetch_as_json(json_baseurl+pkgname+'/json')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+def get_release_urls(pkgname, pkgvers):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    populate_package_data(pkgname, pkgvers)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return package_data[pkgname][pkgvers]['urls']
</span> 
 def list_all():
        """ Lists all packages available in pypi database """
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        list_packages = client.list_packages()
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   for package in list_packages:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           print(package)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for package in fetch_as_json(simple_baseurl)['projects']:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           print(package['name'])
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-class Package_Search:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   def __init__(self, name, summary, version):
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           self.name = name
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           self.version = version
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           self.summary = ""
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           for i in range(0, len(summary), 62):
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   self.summary += summary[i:62+i] + '\n\t\t'
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   def __str__(self):
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           return "Name\t\t" + self.name + "\nVersion\t\t" + self.version + "\nSummary\t\t" + self.summary + "\n"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-def search(pkg_name):
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   """ Searches for a particular package by the name classifier """
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   values = client.search({'name': pkg_name})
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   for value in values:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           package = Package_Search(value['name'], value['summary'], value['version'])
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           print(package)
</span> 
 class Package_release_data:
        def __init__(self, attributes):
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -91,7 +88,8 @@ class Package_release_data:
</span> def release_data(pkg_name, pkg_version):
        """ Fetches the release data for a paticular package based on
        the package_name and package_version """
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        values = client.release_data(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   populate_package_data(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   values = package_data[pkg_name][pkg_version]['info']
</span>   if values:
                package = Package_release_data(values)
                print(package)
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -104,7 +102,7 @@ def release_data(pkg_name, pkg_version):
</span> def fetch(pkg_name, dict):
        """ Fetches the distfile for a particular package name and release_url """
        print("Fetching distfiles...")
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        checksum_sha256 = dict['sha256_digest']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   checksum_sha256 = dict['digests']['sha256']
</span>   parent_dir = './sources'
        home_dir = parent_dir + '/' + 'python'
        src_dir = home_dir + '/py-' + pkg_name
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -195,13 +193,13 @@ def fetch(pkg_name, dict):
</span> def fetch_url(pkg_name, pkg_version, checksum=False, deps=False):
        """ Checks for the checksums and dependecies for a particular python package
        on the basis of package_name and package_version """
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        values = client.release_urls(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   urls = get_release_urls(pkg_name, pkg_version)
</span>   if checksum:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                for value in values:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   if value['filename'].split('.')[-1] in ('gz', 'zip'):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           for value in urls:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if value['packagetype'] == 'sdist':
</span>                           return fetch(pkg_name, value)
        else:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                for value in values:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           for value in urls:
</span>                   return fetch(pkg_name, value)
 
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -211,9 +209,9 @@ def dependencies(pkg_name, pkg_version, deps=False):
</span>   flag = False
        if not deps:
                return
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        values = client.release_urls(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   for value in values:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           if value['filename'].split('.')[-1] in ('gz', 'zip'):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   urls = get_release_urls(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for value in urls:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if value['packagetype'] == 'sdist':
</span>                   fetch(pkg_name, value)
        try:
                with open('./sources/python/py-'
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -314,7 +312,7 @@ def checksums(pkg_name, pkg_version):
</span> def search_distfile(name, version):
        """ Searches if the distfile listed is present or not """
        try:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                url = client.release_urls(name, version)[0]['url']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           url = get_release_urls(name, version)[0]['url']
</span>           r = requests.get(url)
                if not r.status_code == 200:
                        raise Exception('No distfile')
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -557,7 +555,7 @@ def create_portfile(dict, file_name, dict2):
</span>                           zip_set = False
 
                if master_site:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        if re.match('^https?://files\.pythonhosted\.org/packages/', master_site):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                        if re.match(r'^https?://files\.pythonhosted\.org/packages/', master_site):
</span>                             file.write('master_sites        pypi:{0}/{1}\n'.format(dict['name'][0], dict['name']))
                         else:
                             file.write('master_sites        {0}\n'.format(master_site))
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -671,8 +669,9 @@ def print_portfile(pkg_name, pkg_version=None):
</span> 
        print("Attempting to fetch data from pypi...")
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        dict = client.release_data(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   dict2 = client.release_urls(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   populate_package_data(pkg_name, pkg_version)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   dict = package_data[pkg_name][pkg_version]['info']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   dict2 = get_release_urls(pkg_name, pkg_version)
</span>   if dict and dict2:
                print("Data fetched successfully.")
        elif dict:
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -694,10 +693,6 @@ def main(argv):
</span>   parser.add_argument('-l', '--list', action='store_true', dest='list',
                                                default=False, required=False,
                                                help='List all packages')
<span style='display:block; white-space:pre;background:#ffe0e0;'>-# Calls search with the package_name
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-   parser.add_argument('-s', '--search', action='store', type=str,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                           dest='packages_search', nargs='*', required=False,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                                           help='Search for a package')
</span> # Calls release_data with package_name and package_version
        parser.add_argument('-d', '--data', action='store',
                                                dest='packages_data', nargs='*', type=str,
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -720,19 +715,15 @@ def main(argv):
</span>           list_all()
                return
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-        if options.packages_search:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           for pkg_name in options.packages_search:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                   search(pkg_name)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-           return
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span>   if options.packages_data:
                pkg_name = options.packages_data[0]
                if len(options.packages_data) > 1:
                        pkg_version = options.packages_data[1]
                        release_data(pkg_name, pkg_version)
                else:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        if client.package_releases(pkg_name):
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                           pkg_version = client.package_releases(pkg_name)[0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   populate_package_data(pkg_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if package_data[pkg_name][None]['releases']:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           pkg_version = package_data[pkg_name][None]['info']['version']
</span>                           release_data(pkg_name, pkg_version)
                        else:
                                print("No release found\n")
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -744,9 +735,10 @@ def main(argv):
</span>                   pkg_version = options.package_fetch[1]
                        fetch_url(pkg_name, pkg_version)
                else:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        releases = client.package_releases(pkg_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   populate_package_data(pkg_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   releases = package_data[pkg_name][None]['releases']
</span>                   if releases:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                pkg_version = releases[0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           pkg_version = package_data[pkg_name][None]['info']['version']
</span>                           fetch_url(pkg_name, pkg_version)
                        else:
                                print("No release found\n")
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -758,9 +750,10 @@ def main(argv):
</span>                   pkg_version = options.package_portfile[1]
                        print_portfile(pkg_name, pkg_version)
                else:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                        vers = client.package_releases(pkg_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   populate_package_data(pkg_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   vers = package_data[pkg_name][None]['releases']
</span>                   if vers:
<span style='display:block; white-space:pre;background:#ffe0e0;'>-                                pkg_version = vers[0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           pkg_version = package_data[pkg_name][None]['info']['version']
</span>                           print_portfile(pkg_name, pkg_version)
                        else:
                                print("No release found\n")
</pre><pre style='margin:0'>

</pre>