<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>