1
+ from typing import Optional
2
+
3
+ from packaging .version import parse as Version , InvalidVersion
4
+
5
+ import requests
6
+
7
+ def get_pypi_xmlrpc_client ():
8
+ """This is actually deprecated client.
9
+ """
10
+ import xmlrpc .client
11
+ return xmlrpc .client .ServerProxy ("https://pypi.python.org/pypi" , use_datetime = True )
12
+
13
+ class PyPIClient :
14
+ def __init__ (self , host : str = "https://pypi.org" ):
15
+ self ._host = host
16
+ self ._session = requests .Session ()
17
+
18
+ def project (self , package_name : str ):
19
+ response = self ._session .get (
20
+ "{host}/pypi/{project_name}/json" .format (
21
+ host = self ._host ,
22
+ project_name = package_name
23
+ )
24
+ )
25
+ response .raise_for_status ()
26
+ return response .json ()
27
+
28
+ def project_release (self , package_name : str , version : str ):
29
+ response = self ._session .get (
30
+ "{host}/pypi/{project_name}/{version}/json" .format (
31
+ host = self ._host ,
32
+ project_name = package_name ,
33
+ version = version
34
+ )
35
+ )
36
+ response .raise_for_status ()
37
+ return response .json ()
38
+
39
+ def get_ordered_versions (self , package_name : str ):
40
+ project = self .project (package_name )
41
+ versions = [
42
+ Version (package_version )
43
+ for package_version
44
+ in project ["releases" ].keys ()
45
+ ]
46
+ versions .sort ()
47
+ return versions
48
+
49
+ def get_relevant_versions (self , package_name : str ):
50
+ """Return a tuple: (latest release, latest stable)
51
+ If there are different, it means the latest is not a stable
52
+ """
53
+ versions = self .get_ordered_versions (package_name )
54
+ pre_releases = [version for version in versions if not version .is_prerelease ]
55
+ return (
56
+ versions [- 1 ],
57
+ pre_releases [- 1 ]
58
+ )
0 commit comments