66# Licensed under the terms of the MIT License
77# (see winpython/__init__.py for details)
88
9-
109import os
1110from pathlib import Path
1211import re
1312import shutil
13+ from packaging import version
1414from winpython import utils
1515
1616CHANGELOGS_DIR = Path (__file__ ).parent / "changelogs"
1717assert CHANGELOGS_DIR .is_dir ()
1818
19-
20- class Package (object ):
19+ class Package :
2120 # SourceForge Wiki syntax:
2221 PATTERN = r"\[([a-zA-Z\-\:\/\.\_0-9]*)\]\(([^\]\ ]*)\) \| ([^\|]*) \| ([^\|]*)"
2322 # Google Code Wiki syntax:
2423 PATTERN_OLD = r"\[([a-zA-Z\-\:\/\.\_0-9]*) ([^\]\ ]*)\] \| ([^\|]*) \| ([^\|]*)"
2524
2625 def __init__ (self ):
27- self .name = None
28- self .version = None
29- self .description = None
30- self .url = None
26+ self .name = self .version = self .description = self .url = None
3127
3228 def __str__ (self ):
33- text = f"{ self .name } { self .version } "
34- text += f"\r \n { self .description } \r \n Website: { self .url } "
35- return text
29+ return f"{ self .name } { self .version } \r \n { self .description } \r \n Website: { self .url } "
3630
3731 def from_text (self , text ):
38- try :
39- self .url , self .name , self .version , self .description = re .match (
40- self .PATTERN_OLD , text
41- ).groups ()
42- except AttributeError :
43- self .name , self .url , self .version , self .description = re .match (
44- self .PATTERN , text
45- ).groups ()
32+ match = re .match (self .PATTERN_OLD , text ) or re .match (self .PATTERN , text )
33+ if not match :
34+ raise ValueError ("Text does not match expected pattern" )
35+ self .name , self .url , self .version , self .description = match .groups ()
4636
4737 def to_wiki (self ):
4838 return f" * [{ self .name } ]({ self .url } ) { self .version } ({ self .description } )\r \n "
@@ -51,8 +41,7 @@ def upgrade_wiki(self, other):
5141 assert self .name .replace ("-" , "_" ).lower () == other .name .replace ("-" , "_" ).lower ()
5242 return f" * [{ self .name } ]({ self .url } ) { other .version } → { self .version } ({ self .description } )\r \n "
5343
54-
55- class PackageIndex (object ):
44+ class PackageIndex :
5645 WINPYTHON_PATTERN = r"\#\# WinPython\-*[0-9b-t]* ([0-9\.a-zA-Z]*)"
5746 TOOLS_LINE = "### Tools"
5847 PYTHON_PACKAGES_LINE = "### Python packages"
@@ -72,9 +61,8 @@ def from_file(self, basedir):
7261 fname = CHANGELOGS_DIR / f"WinPython{ self .flavor } -{ self .architecture } bit-{ self .version } .md"
7362 if not fname .exists ():
7463 raise FileNotFoundError (f"Changelog file not found: { fname } " )
75- with open (fname , "r" , encoding = 'utf-8' ) as fdesc :
76- text = fdesc .read ()
77- self .from_text (text )
64+ with open (fname , "r" , encoding = utils .guess_encoding (fname )[0 ]) as fdesc :
65+ self .from_text (fdesc .read ())
7866
7967 def from_text (self , text ):
8068 version = re .match (self .WINPYTHON_PATTERN + self .flavor , text ).groups ()[0 ]
@@ -88,12 +76,7 @@ def from_text(self, text):
8876 elif line == self .PYTHON_PACKAGES_LINE :
8977 tools_flag , python_flag = False , True
9078 continue
91- elif line in (
92- self .HEADER_LINE1 ,
93- self .HEADER_LINE2 ,
94- "<details>" ,
95- "</details>" ,
96- ):
79+ elif line in (self .HEADER_LINE1 , self .HEADER_LINE2 , "<details>" , "</details>" ):
9780 continue
9881 if tools_flag or python_flag :
9982 package = Package ()
@@ -103,105 +86,83 @@ def from_text(self, text):
10386 else :
10487 self .python_packages [package .name ] = package
10588
106-
10789def diff_package_dicts (old_packages , new_packages ):
10890 """Return difference between package old and package new"""
10991
11092 # wheel replace '-' per '_' in key
11193 old = {k .replace ("-" , "_" ).lower (): v for k , v in old_packages .items ()}
11294 new = {k .replace ("-" , "_" ).lower (): v for k , v in new_packages .items ()}
11395 text = ""
114- # New packages
96+
11597 if new_keys := sorted (set (new ) - set (old )):
11698 text += "New packages:\r \n \r \n " + "" .join (new [k ].to_wiki () for k in new_keys ) + "\r \n "
11799
118- # Upgraded packages
119100 if upgraded := [new [k ].upgrade_wiki (old [k ]) for k in sorted (set (old ) & set (new )) if old [k ].version != new [k ].version ]:
120101 text += "Upgraded packages:\r \n \r \n " + f"{ '' .join (upgraded )} " + "\r \n "
121102
122- # Removed packages
123103 if removed_keys := sorted (set (old ) - set (new )):
124104 text += "Removed packages:\r \n \r \n " + "" .join (old [k ].to_wiki () for k in removed_keys ) + "\r \n "
125105 return text
126106
127-
128107def find_closer_version (version1 , basedir = None , flavor = "" , architecture = 64 ):
129108 """Find version which is the closest to `version`"""
130- builddir = str (Path (basedir ) / f"bu{ flavor } " )
131- func = lambda name : re .match (
132- r"WinPython%s-%sbit-([0-9\.]*)\.(txt|md)" % (flavor , architecture ),
133- name ,
134- )
135- versions = [func (name ).groups ()[0 ] for name in os .listdir (builddir ) if func (name )]
136- # versions:['3.10.0.1', '3.10.10.0', '3.10.2.0'.... '3.10.8.1', '3.10.9.0']
137- try :
138- index = versions .index (version1 )
139- except ValueError :
109+ builddir = Path (basedir ) / f"bu{ flavor } "
110+ pattern = re .compile (rf"WinPython{ flavor } -{ architecture } bit-([0-9\.]*)\.(txt|md)" )
111+ versions = [pattern .match (name ).groups ()[0 ] for name in os .listdir (builddir ) if pattern .match (name )]
112+
113+ if version1 not in versions :
140114 raise ValueError (f"Unknown version { version1 } " )
141115
142- from packaging import version
143116 version_below = '0.0.0.0'
144117 for v in versions :
145- if version .parse (v ) > version .parse (version_below ) and version .parse (v )< version .parse (version1 ):
118+ if version .parse (version_below ) < version .parse (v ) and version .parse (v ) < version .parse (version1 ):
146119 version_below = v
147- if version_below == '0.0.0.0' :
148- return version1
149- else :
150- return version_below
120+
121+ return version_below if version_below != '0.0.0.0' else version1
151122
152123def compare_package_indexes (version2 , version1 = None , basedir = None , flavor = "" , flavor1 = None ,architecture = 64 ):
153124 """Compare two package index Wiki pages"""
154125 version1 = version1 if version1 else find_closer_version (version2 , basedir , flavor , architecture )
155126 flavor1 = flavor1 if flavor1 else flavor
156127 pi1 = PackageIndex (version1 , basedir , flavor1 , architecture )
157128 pi2 = PackageIndex (version2 , basedir , flavor , architecture )
158-
159- text = "\r \n " .join (
160- [
161- f"## History of changes for WinPython-{ architecture } bit { version2 + flavor } " ,
162- "" ,
163- f"The following changes were made to WinPython-{ architecture } bit"
164- f" distribution since version { version1 + flavor1 } ." ,
165- "" ,
166- "<details>" ,
167- "" ,
168- ]
129+
130+ text = (
131+ f"## History of changes for WinPython-{ architecture } bit { version2 + flavor } \r \n \r \n "
132+ f"The following changes were made to WinPython-{ architecture } bit distribution since version { version1 + flavor1 } .\r \n \r \n "
133+ "<details>\r \n \r \n "
169134 )
170135
171136 tools_text = diff_package_dicts (pi1 .other_packages , pi2 .other_packages )
172137 if tools_text :
173138 text += PackageIndex .TOOLS_LINE + "\r \n \r \n " + tools_text
139+
174140 py_text = diff_package_dicts (pi1 .python_packages , pi2 .python_packages )
175141 if py_text :
176142 text += PackageIndex .PYTHON_PACKAGES_LINE + "\r \n \r \n " + py_text
143+
177144 text += "\r \n </details>\r \n * * *\r \n "
178145 return text
179146
180-
181147def _copy_all_changelogs (version , basedir , flavor = "" , architecture = 64 ):
182148 basever = "." .join (version .split ("." )[:2 ])
149+ pattern = re .compile (rf"WinPython{ flavor } -{ architecture } bit-{ basever } ([0-9\.]*)\.(txt|md)" )
183150 for name in os .listdir (CHANGELOGS_DIR ):
184- if re .match (
185- r"WinPython%s-%sbit-%s([0-9\.]*)\.(txt|md)"
186- % (flavor , architecture , basever ),
187- name ,
188- ):
151+ if pattern .match (name ):
189152 shutil .copyfile (CHANGELOGS_DIR / name , Path (basedir ) / f"bu{ flavor } " / name )
190153
191-
192154def write_changelog (version2 , version1 = None , basedir = None , flavor = "" , architecture = 64 ):
193155 """Write changelog between version1 and version2 of WinPython"""
194156 _copy_all_changelogs (version2 , basedir , flavor , architecture )
195157 print ("comparing_package_indexes" , version2 , basedir , flavor , architecture )
196158 changelog_text = compare_package_indexes (version2 , version1 , basedir , flavor , architecture = architecture )
197159 output_file = Path (basedir ) / f"bu{ flavor } " / f"WinPython{ flavor } -{ architecture } bit-{ version2 } _History.md"
198160
199- with open (output_file , "w" , encoding = "utf-8-sig " ) as fdesc :
161+ with open (output_file , "w" , encoding = "utf-8" ) as fdesc :
200162 fdesc .write (changelog_text )
201163 # Copy to winpython/changelogs
202164 shutil .copyfile (output_file , CHANGELOGS_DIR / output_file .name )
203165
204-
205166if __name__ == "__main__" :
206- print (compare_package_indexes ("3.7.4.0" , "3.7.2.0" , "C:\WinP\b d37" , "Zero" , architecture = 32 ))
167+ print (compare_package_indexes ("3.7.4.0" , "3.7.2.0" , r "C:\WinP\bd37" , "Zero" , architecture = 32 ))
207168 write_changelog ("3.7.4.0" , "3.7.2.0" , r"C:\WinP\bd37" , "Ps2" , architecture = 64 )
0 commit comments