3030"""
3131
3232__author__ = "waketzheng@gmail.com"
33- __updated_at__ = "2025.11.22 "
34- __version__ = "0.8.7 "
33+ __updated_at__ = "2025.11.26 "
34+ __version__ = "0.8.9 "
3535import contextlib
3636import functools
3737import os
@@ -608,7 +608,7 @@ def check_installed(self):
608608
609609
610610class UvMirror (Mirror ):
611- GITHUB_PROXY = "https://hub.gitmirror.com /"
611+ GITHUB_PROXY = "https://hk.gh-proxy.org /"
612612 PYTHON_DOWNLOAD_URL = (
613613 "https://github.com/astral-sh/python-build-standalone/releases/download"
614614 )
@@ -622,10 +622,39 @@ def allow_insecure(url):
622622 return ""
623623 return '\n allow-insecure-host=["{}"]' .format (parse_host (url ))
624624
625+ @classmethod
626+ def _get_python_mirror (cls , default ):
627+ # type: (str) -> str
628+ choices = {"default" : default }
629+ for name in ("PIP_CONF_PYTHON_MIRROR" , "UV_PYTHON_INSTALL_MIRROR" ):
630+ value = os .getenv (name )
631+ if value and value not in choices .values ():
632+ choices [name ] = value
633+ if len (choices ) == 1 :
634+ return default
635+ tip = "Which url do you want to set for python install mirror? (Leave blank to use default)"
636+ items = list (choices .items ())
637+ choices_text = "\n " .join (
638+ [
639+ "{i}. {key} ({value})" .format (i = i , key = key , value = value )
640+ for i , (key , value ) in enumerate (items )
641+ ]
642+ )
643+ a = input (tip + "\n " + choices_text + "\n " ).strip ()
644+ if a :
645+ try :
646+ url = items [int (a )][1 ]
647+ except (TypeError , ValueError , IndexError ):
648+ print ("Invalid choice, default will be used." )
649+ else :
650+ return url
651+ return default
652+
625653 @classmethod
626654 def python_install_mirror (cls ):
627655 # type: () -> str
628- return cls .TEMPLATE .format (cls .GITHUB_PROXY + cls .PYTHON_DOWNLOAD_URL )
656+ default = cls .GITHUB_PROXY + cls .PYTHON_DOWNLOAD_URL
657+ return cls .TEMPLATE .format (cls ._get_python_mirror (default ))
629658
630659 def build_content (self , url = None , extra_index = None ):
631660 # type: (Optional[str], Optional[str]) -> str
@@ -660,8 +689,8 @@ def set(self, set_python_mirror=False):
660689 config_toml_path = os .path .join (dirpath , filename )
661690 text = self .build_content ()
662691 if os .path .exists (config_toml_path ):
663- with open (config_toml_path ) as f :
664- content = f .read ().strip ()
692+ with open (config_toml_path , "rb" ) as f :
693+ content = f .read ().strip (). decode ( "utf-8" )
665694 if text in content :
666695 print ("uv mirror set as expected. Skip!" )
667696 return None
@@ -752,8 +781,8 @@ def fix_v1_6_error(cls):
752781 print ("WARNING: plugin file not found {}" .format (file ))
753782 return
754783 s = "semver"
755- with open (file ) as f :
756- text = f .read ()
784+ with open (file , "rb" ) as f :
785+ text = f .read (). decode ( "utf-8" )
757786 if s in text :
758787 text = text .replace (s , "constraints" )
759788 with open (file , "w" ) as f :
@@ -838,8 +867,8 @@ def set(self):
838867 item = "[plugins.pypi_mirror]"
839868 text = item + '{}url = "{}"' .format (os .linesep , self .url )
840869 if os .path .exists (config_toml_path ):
841- with open (config_toml_path ) as f :
842- content = f .read ().strip ()
870+ with open (config_toml_path , "rb" ) as f :
871+ content = f .read ().strip (). decode ( "utf-8" )
843872 if text in content :
844873 print ("poetry mirror set as expected. Skip!" )
845874 return None
@@ -904,8 +933,8 @@ def init_pip_conf(
904933 text = TEMPLATE .format (url , parse_host (url ))
905934 conf_file = get_conf_path (is_windows , at_etc )
906935 if os .path .exists (conf_file ):
907- with open (conf_file ) as fp :
908- s = fp .read ()
936+ with open (conf_file , "rb" ) as fp :
937+ s = fp .read (). decode ( "utf-8" )
909938 if text in s :
910939 print ("Pip source already be configured as expected.\n Skip!" )
911940 return None
@@ -936,8 +965,8 @@ def can_set_global():
936965
937966def read_lines (filename ):
938967 # type: (str) -> list[str]
939- with open (filename ) as f :
940- s = f .read ()
968+ with open (filename , "rb" ) as f :
969+ s = f .read (). decode ( "utf-8" )
941970 return s .splitlines ()
942971
943972
0 commit comments