Patchwork [1,of,3] encoding: avoid cyclic dependency around "parsers" in pure Python build

login
register
mail settings
Submitter Katsunori FUJIWARA
Date Oct. 16, 2014, 5:34 p.m.
Message ID <738137a3404922e88789.1413480849@feefifofum>
Download mbox | patch
Permalink /patch/6335/
State Accepted
Headers show

Comments

Katsunori FUJIWARA - Oct. 16, 2014, 5:34 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1413479224 -32400
#      Fri Oct 17 02:07:04 2014 +0900
# Node ID 738137a3404922e887894da69bca6382bc672e44
# Parent  da2758c0aca04fe20fef2797f80c6079099afca5
encoding: avoid cyclic dependency around "parsers" in pure Python build

80f2b63dd83a brought "asciilower" and "import parsers" into
"encoding.py".

This works fine with "parsers" module in C implementation, but doesn't
with one in pure Python implementation, because the latter causes
cyclic dependency below and aborting execution:

    util => i18n => encoding => parsers => util

This patch delays importing "parsers" module until it is really
needed, to avoid cyclic dependency around "parsers" in pure Python
build.
Siddharth Agarwal - Oct. 16, 2014, 6:13 p.m.
On 10/16/2014 10:34 AM, FUJIWARA Katsunori wrote:
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
> # Date 1413479224 -32400
> #      Fri Oct 17 02:07:04 2014 +0900
> # Node ID 738137a3404922e887894da69bca6382bc672e44
> # Parent  da2758c0aca04fe20fef2797f80c6079099afca5
> encoding: avoid cyclic dependency around "parsers" in pure Python build

This is fine and doesn't regress performance.

mpm and I chatted about this problem -- post 3.2, we'll probably want to 
move asciilower into the base85 module, retconned to be the place for 
generic encoding-related functions.

>
> 80f2b63dd83a brought "asciilower" and "import parsers" into
> "encoding.py".
>
> This works fine with "parsers" module in C implementation, but doesn't
> with one in pure Python implementation, because the latter causes
> cyclic dependency below and aborting execution:
>
>      util => i18n => encoding => parsers => util
>
> This patch delays importing "parsers" module until it is really
> needed, to avoid cyclic dependency around "parsers" in pure Python
> build.
>
> diff --git a/mercurial/encoding.py b/mercurial/encoding.py
> --- a/mercurial/encoding.py
> +++ b/mercurial/encoding.py
> @@ -5,7 +5,7 @@
>   # This software may be used and distributed according to the terms of the
>   # GNU General Public License version 2 or any later version.
>   
> -import error, parsers
> +import error
>   import unicodedata, locale, os
>   
>   def _getpreferredencoding():
> @@ -258,14 +258,21 @@
>               return concat(usub.encode(encoding))
>       return ellipsis # no enough room for multi-column characters
>   
> -def asciilower(s):
> +def _asciilower(s):
>       '''convert a string to lowercase if ASCII
>   
>       Raises UnicodeDecodeError if non-ASCII characters are found.'''
>       s.decode('ascii')
>       return s.lower()
>   
> -asciilower = getattr(parsers, 'asciilower', asciilower)
> +def asciilower(s):
> +    # delay importing avoids cyclic dependency around "parsers" in
> +    # pure Python build (util => i18n => encoding => parsers => util)
> +    import parsers
> +    impl = getattr(parsers, 'asciilower', _asciilower)
> +    global asciilower
> +    asciilower = impl
> +    return impl(s)
>   
>   def lower(s):
>       "best-effort encoding-aware case-folding of local string s"
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel

Patch

diff --git a/mercurial/encoding.py b/mercurial/encoding.py
--- a/mercurial/encoding.py
+++ b/mercurial/encoding.py
@@ -5,7 +5,7 @@ 
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import error, parsers
+import error
 import unicodedata, locale, os
 
 def _getpreferredencoding():
@@ -258,14 +258,21 @@ 
             return concat(usub.encode(encoding))
     return ellipsis # no enough room for multi-column characters
 
-def asciilower(s):
+def _asciilower(s):
     '''convert a string to lowercase if ASCII
 
     Raises UnicodeDecodeError if non-ASCII characters are found.'''
     s.decode('ascii')
     return s.lower()
 
-asciilower = getattr(parsers, 'asciilower', asciilower)
+def asciilower(s):
+    # delay importing avoids cyclic dependency around "parsers" in
+    # pure Python build (util => i18n => encoding => parsers => util)
+    import parsers
+    impl = getattr(parsers, 'asciilower', _asciilower)
+    global asciilower
+    asciilower = impl
+    return impl(s)
 
 def lower(s):
     "best-effort encoding-aware case-folding of local string s"