1- """Utilities for writing code that runs on Python 2 and 3"""
2-
3- # Copyright (c) 2010-2015 Benjamin Peterson
1+ # Copyright (c) 2010-2020 Benjamin Peterson
42#
53# Permission is hereby granted, free of charge, to any person obtaining a copy
64# of this software and associated documentation files (the "Software"), to deal
2018# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2119# SOFTWARE.
2220
21+ """Utilities for writing code that runs on Python 2 and 3"""
22+
2323from __future__ import absolute_import
2424
2525import functools
2929import types
3030
3131__author__ = "Benjamin Peterson <benjamin@python.org>"
32- __version__ = "1.10 .0"
32+ __version__ = "1.14 .0"
3333
3434
3535# Useful for very coarse version differentiation.
@@ -241,6 +241,7 @@ class _MovedItems(_LazyModule):
241241 MovedAttribute ("map" , "itertools" , "builtins" , "imap" , "map" ),
242242 MovedAttribute ("getcwd" , "os" , "os" , "getcwdu" , "getcwd" ),
243243 MovedAttribute ("getcwdb" , "os" , "os" , "getcwd" , "getcwdb" ),
244+ MovedAttribute ("getoutput" , "commands" , "subprocess" ),
244245 MovedAttribute ("range" , "__builtin__" , "builtins" , "xrange" , "range" ),
245246 MovedAttribute ("reload_module" , "__builtin__" , "importlib" if PY34 else "imp" , "reload" ),
246247 MovedAttribute ("reduce" , "__builtin__" , "functools" ),
@@ -254,18 +255,21 @@ class _MovedItems(_LazyModule):
254255 MovedAttribute ("zip_longest" , "itertools" , "itertools" , "izip_longest" , "zip_longest" ),
255256 MovedModule ("builtins" , "__builtin__" ),
256257 MovedModule ("configparser" , "ConfigParser" ),
258+ MovedModule ("collections_abc" , "collections" , "collections.abc" if sys .version_info >= (3 , 3 ) else "collections" ),
257259 MovedModule ("copyreg" , "copy_reg" ),
258260 MovedModule ("dbm_gnu" , "gdbm" , "dbm.gnu" ),
259- MovedModule ("_dummy_thread" , "dummy_thread" , "_dummy_thread" ),
261+ MovedModule ("dbm_ndbm" , "dbm" , "dbm.ndbm" ),
262+ MovedModule ("_dummy_thread" , "dummy_thread" , "_dummy_thread" if sys .version_info < (3 , 9 ) else "_thread" ),
260263 MovedModule ("http_cookiejar" , "cookielib" , "http.cookiejar" ),
261264 MovedModule ("http_cookies" , "Cookie" , "http.cookies" ),
262265 MovedModule ("html_entities" , "htmlentitydefs" , "html.entities" ),
263266 MovedModule ("html_parser" , "HTMLParser" , "html.parser" ),
264267 MovedModule ("http_client" , "httplib" , "http.client" ),
268+ MovedModule ("email_mime_base" , "email.MIMEBase" , "email.mime.base" ),
269+ MovedModule ("email_mime_image" , "email.MIMEImage" , "email.mime.image" ),
265270 MovedModule ("email_mime_multipart" , "email.MIMEMultipart" , "email.mime.multipart" ),
266271 MovedModule ("email_mime_nonmultipart" , "email.MIMENonMultipart" , "email.mime.nonmultipart" ),
267272 MovedModule ("email_mime_text" , "email.MIMEText" , "email.mime.text" ),
268- MovedModule ("email_mime_base" , "email.MIMEBase" , "email.mime.base" ),
269273 MovedModule ("BaseHTTPServer" , "BaseHTTPServer" , "http.server" ),
270274 MovedModule ("CGIHTTPServer" , "CGIHTTPServer" , "http.server" ),
271275 MovedModule ("SimpleHTTPServer" , "SimpleHTTPServer" , "http.server" ),
@@ -337,10 +341,12 @@ class Module_six_moves_urllib_parse(_LazyModule):
337341 MovedAttribute ("quote_plus" , "urllib" , "urllib.parse" ),
338342 MovedAttribute ("unquote" , "urllib" , "urllib.parse" ),
339343 MovedAttribute ("unquote_plus" , "urllib" , "urllib.parse" ),
344+ MovedAttribute ("unquote_to_bytes" , "urllib" , "urllib.parse" , "unquote" , "unquote_to_bytes" ),
340345 MovedAttribute ("urlencode" , "urllib" , "urllib.parse" ),
341346 MovedAttribute ("splitquery" , "urllib" , "urllib.parse" ),
342347 MovedAttribute ("splittag" , "urllib" , "urllib.parse" ),
343348 MovedAttribute ("splituser" , "urllib" , "urllib.parse" ),
349+ MovedAttribute ("splitvalue" , "urllib" , "urllib.parse" ),
344350 MovedAttribute ("uses_fragment" , "urlparse" , "urllib.parse" ),
345351 MovedAttribute ("uses_netloc" , "urlparse" , "urllib.parse" ),
346352 MovedAttribute ("uses_params" , "urlparse" , "urllib.parse" ),
@@ -416,6 +422,8 @@ class Module_six_moves_urllib_request(_LazyModule):
416422 MovedAttribute ("URLopener" , "urllib" , "urllib.request" ),
417423 MovedAttribute ("FancyURLopener" , "urllib" , "urllib.request" ),
418424 MovedAttribute ("proxy_bypass" , "urllib" , "urllib.request" ),
425+ MovedAttribute ("parse_http_list" , "urllib2" , "urllib.request" ),
426+ MovedAttribute ("parse_keqv_list" , "urllib2" , "urllib.request" ),
419427]
420428for attr in _urllib_request_moved_attributes :
421429 setattr (Module_six_moves_urllib_request , attr .name , attr )
@@ -631,13 +639,16 @@ def u(s):
631639 import io
632640 StringIO = io .StringIO
633641 BytesIO = io .BytesIO
642+ del io
634643 _assertCountEqual = "assertCountEqual"
635644 if sys .version_info [1 ] <= 1 :
636645 _assertRaisesRegex = "assertRaisesRegexp"
637646 _assertRegex = "assertRegexpMatches"
647+ _assertNotRegex = "assertNotRegexpMatches"
638648 else :
639649 _assertRaisesRegex = "assertRaisesRegex"
640650 _assertRegex = "assertRegex"
651+ _assertNotRegex = "assertNotRegex"
641652else :
642653 def b (s ):
643654 return s
@@ -659,6 +670,7 @@ def indexbytes(buf, i):
659670 _assertCountEqual = "assertItemsEqual"
660671 _assertRaisesRegex = "assertRaisesRegexp"
661672 _assertRegex = "assertRegexpMatches"
673+ _assertNotRegex = "assertNotRegexpMatches"
662674_add_doc (b , """Byte literal""" )
663675_add_doc (u , """Text literal""" )
664676
@@ -675,15 +687,23 @@ def assertRegex(self, *args, **kwargs):
675687 return getattr (self , _assertRegex )(* args , ** kwargs )
676688
677689
690+ def assertNotRegex (self , * args , ** kwargs ):
691+ return getattr (self , _assertNotRegex )(* args , ** kwargs )
692+
693+
678694if PY3 :
679695 exec_ = getattr (moves .builtins , "exec" )
680696
681697 def reraise (tp , value , tb = None ):
682- if value is None :
683- value = tp ()
684- if value .__traceback__ is not tb :
685- raise value .with_traceback (tb )
686- raise value
698+ try :
699+ if value is None :
700+ value = tp ()
701+ if value .__traceback__ is not tb :
702+ raise value .with_traceback (tb )
703+ raise value
704+ finally :
705+ value = None
706+ tb = None
687707
688708else :
689709 def exec_ (_code_ , _globs_ = None , _locs_ = None ):
@@ -699,19 +719,19 @@ def exec_(_code_, _globs_=None, _locs_=None):
699719 exec ("""exec _code_ in _globs_, _locs_""" )
700720
701721 exec_ ("""def reraise(tp, value, tb=None):
702- raise tp, value, tb
722+ try:
723+ raise tp, value, tb
724+ finally:
725+ tb = None
703726""" )
704727
705728
706- if sys .version_info [:2 ] == (3 , 2 ):
729+ if sys .version_info [:2 ] > (3 ,):
707730 exec_ ("""def raise_from(value, from_value):
708- if from_value is None:
709- raise value
710- raise value from from_value
711- """ )
712- elif sys .version_info [:2 ] > (3 , 2 ):
713- exec_ ("""def raise_from(value, from_value):
714- raise value from from_value
731+ try:
732+ raise value from from_value
733+ finally:
734+ value = None
715735""" )
716736else :
717737 def raise_from (value , from_value ):
@@ -786,13 +806,33 @@ def print_(*args, **kwargs):
786806_add_doc (reraise , """Reraise an exception.""" )
787807
788808if sys .version_info [0 :2 ] < (3 , 4 ):
809+ # This does exactly the same what the :func:`py3:functools.update_wrapper`
810+ # function does on Python versions after 3.2. It sets the ``__wrapped__``
811+ # attribute on ``wrapper`` object and it doesn't raise an error if any of
812+ # the attributes mentioned in ``assigned`` and ``updated`` are missing on
813+ # ``wrapped`` object.
814+ def _update_wrapper (wrapper , wrapped ,
815+ assigned = functools .WRAPPER_ASSIGNMENTS ,
816+ updated = functools .WRAPPER_UPDATES ):
817+ for attr in assigned :
818+ try :
819+ value = getattr (wrapped , attr )
820+ except AttributeError :
821+ continue
822+ else :
823+ setattr (wrapper , attr , value )
824+ for attr in updated :
825+ getattr (wrapper , attr ).update (getattr (wrapped , attr , {}))
826+ wrapper .__wrapped__ = wrapped
827+ return wrapper
828+ _update_wrapper .__doc__ = functools .update_wrapper .__doc__
829+
789830 def wraps (wrapped , assigned = functools .WRAPPER_ASSIGNMENTS ,
790831 updated = functools .WRAPPER_UPDATES ):
791- def wrapper (f ):
792- f = functools .wraps (wrapped , assigned , updated )(f )
793- f .__wrapped__ = wrapped
794- return f
795- return wrapper
832+ return functools .partial (_update_wrapper , wrapped = wrapped ,
833+ assigned = assigned , updated = updated )
834+ wraps .__doc__ = functools .wraps .__doc__
835+
796836else :
797837 wraps = functools .wraps
798838
@@ -802,10 +842,22 @@ def with_metaclass(meta, *bases):
802842 # This requires a bit of explanation: the basic idea is to make a dummy
803843 # metaclass for one level of class instantiation that replaces itself with
804844 # the actual metaclass.
805- class metaclass (meta ):
845+ class metaclass (type ):
806846
807847 def __new__ (cls , name , this_bases , d ):
808- return meta (name , bases , d )
848+ if sys .version_info [:2 ] >= (3 , 7 ):
849+ # This version introduced PEP 560 that requires a bit
850+ # of extra care (we mimic what is done by __build_class__).
851+ resolved_bases = types .resolve_bases (bases )
852+ if resolved_bases is not bases :
853+ d ['__orig_bases__' ] = bases
854+ else :
855+ resolved_bases = bases
856+ return meta (name , resolved_bases , d )
857+
858+ @classmethod
859+ def __prepare__ (cls , name , this_bases ):
860+ return meta .__prepare__ (name , bases )
809861 return type .__new__ (metaclass , 'temporary_class' , (), {})
810862
811863
@@ -821,13 +873,73 @@ def wrapper(cls):
821873 orig_vars .pop (slots_var )
822874 orig_vars .pop ('__dict__' , None )
823875 orig_vars .pop ('__weakref__' , None )
876+ if hasattr (cls , '__qualname__' ):
877+ orig_vars ['__qualname__' ] = cls .__qualname__
824878 return metaclass (cls .__name__ , cls .__bases__ , orig_vars )
825879 return wrapper
826880
827881
882+ def ensure_binary (s , encoding = 'utf-8' , errors = 'strict' ):
883+ """Coerce **s** to six.binary_type.
884+
885+ For Python 2:
886+ - `unicode` -> encoded to `str`
887+ - `str` -> `str`
888+
889+ For Python 3:
890+ - `str` -> encoded to `bytes`
891+ - `bytes` -> `bytes`
892+ """
893+ if isinstance (s , text_type ):
894+ return s .encode (encoding , errors )
895+ elif isinstance (s , binary_type ):
896+ return s
897+ else :
898+ raise TypeError ("not expecting type '%s'" % type (s ))
899+
900+
901+ def ensure_str (s , encoding = 'utf-8' , errors = 'strict' ):
902+ """Coerce *s* to `str`.
903+
904+ For Python 2:
905+ - `unicode` -> encoded to `str`
906+ - `str` -> `str`
907+
908+ For Python 3:
909+ - `str` -> `str`
910+ - `bytes` -> decoded to `str`
911+ """
912+ if not isinstance (s , (text_type , binary_type )):
913+ raise TypeError ("not expecting type '%s'" % type (s ))
914+ if PY2 and isinstance (s , text_type ):
915+ s = s .encode (encoding , errors )
916+ elif PY3 and isinstance (s , binary_type ):
917+ s = s .decode (encoding , errors )
918+ return s
919+
920+
921+ def ensure_text (s , encoding = 'utf-8' , errors = 'strict' ):
922+ """Coerce *s* to six.text_type.
923+
924+ For Python 2:
925+ - `unicode` -> `unicode`
926+ - `str` -> `unicode`
927+
928+ For Python 3:
929+ - `str` -> `str`
930+ - `bytes` -> decoded to `str`
931+ """
932+ if isinstance (s , binary_type ):
933+ return s .decode (encoding , errors )
934+ elif isinstance (s , text_type ):
935+ return s
936+ else :
937+ raise TypeError ("not expecting type '%s'" % type (s ))
938+
939+
828940def python_2_unicode_compatible (klass ):
829941 """
830- A decorator that defines __unicode__ and __str__ methods under Python 2.
942+ A class decorator that defines __unicode__ and __str__ methods under Python 2.
831943 Under Python 3 it does nothing.
832944
833945 To support Python 2 and 3 with a single code base, define a __str__ method
0 commit comments