[GRASS-dev] [GRASS GIS] #3790: Cleanup gettext usage for python code

GRASS GIS trac at osgeo.org
Wed Mar 27 03:49:34 PDT 2019


#3790: Cleanup gettext usage for python code
--------------------------+-------------------------
  Reporter:  pmav99       |      Owner:  grass-dev@…
      Type:  enhancement  |     Status:  closed
  Priority:  normal       |  Milestone:  7.8.0
 Component:  Python       |    Version:  svn-trunk
Resolution:  fixed        |   Keywords:
       CPU:  Unspecified  |   Platform:  Unspecified
--------------------------+-------------------------

Comment (by pmav99):

 Disclaimer: The real goal of this refactoring was to get rid of
 {{{os.getenv("GISBASE")}}} calls at the module level. This is a
 prerequisite for #3772. The scripts and the GUI code didn't really need to
 be touched, but I did them too for uniformity.

 Replying to [comment:4 wenzeslaus]:
 > The things in lib/python are potentially (and actually) used as Python
 modules by other applications or scripts. Thus from
 https://pymotw.com/2/gettext/index.html#module-localization, it is
 actually the second option which applies:
 >
 > > //For a library, or individual module, modifying `__builtins__` is not
 a good idea because you don’t know what conflicts you might introduce with
 an application global value. You can import or re-bind the names of
 translation functions by hand at the top of your module.//

 I really like it when things are explicit. I dislike the idea of injecting
 things into builtins and I do found the convention of using {{{_()}}} as
 an alias for {{{gettext.gettext()}}} rather unfortunate. Consequently, I
 don't have any objections with getting rid of {{{gettext.install()}}}
 and/or even {{{_()}}}.

 Regardless, I am not sure that GRASS was actually following Doug Helman's
 advice. More specifically, almost all GRASS modules used to import the
 {{{grass}}} library before actually calling {{{gettext.install()}}} on
 their own ([https://github.com/GRASS-GIS/grass-
 ci/pull/9/commits/0983ca068d6f7363d2fede26f77b8aed76c87bcc source]). The
 {{{grass}}} library was already calling {{{gettext.install}}}
 ([https://github.com/GRASS-GIS/grass-
 ci/pull/9/commits/b589754aa497ac8ad067ed8258b12caaa0bf1e17#diff-
 15e2e35efef103adc7f77c0a3afe4a63 source]). {{{grass.temporal}}} was doing
 the same for no apparent reason though, since it was just re-registering
 the "grasslibs" domain ([https://github.com/GRASS-GIS/grass-
 ci/pull/9/commits/b589754aa497ac8ad067ed8258b12caaa0bf1e17#diff-
 e36b6b10b67c75c0d7c159b273854ef1 source]). Anyway, the end result is that
 most of the time, if not always, as soon as you imported the {{{grass}}}
 lib, the {{{builtins}}} were modified anyway.

 In other words, I don't think that the proposed patch really changes what
 the {{{grass}}} library was doing. The builtin injection continues to
 happen just like it used before.

 That being said, I am completely open to any improvements. I am also
 perfectly fine with following Mr. Helman's advice (i.e. by adding explicit
 imports in each and every {{{grass}}} lib module) if someone wants to
 contribute that. But IMHV the proposed implementation is cleaner than the
 previous one.

 > So far we were relatively successful in keeping the GUI separate
 (whether for performance or code organization reasons).

 I don't really see any coupling of the GUI code with the {{{grass}}}
 library. All the {{{grass}}} library does is registering the "grasswxpy"
 domain. It doesn't import anything.

 TBH, I did consider moving the {{{gettext.install("grasswxpy", ...)}}}
 code inside {{{./gui/wxpython}}}, but the way it is structured doesn't
 allow to do that cleanly and I didn't want to make changes there too. It
 is doable though.

 > Finally, is there any overhead in centralizing the tr string
 installation?

 I haven't measured it. Obviously there is some overhead. Previously when
 you were importing  {{{grass}}} for the first time in a process, you were
 registering 2 domains. "grasslibs" + "grassmods" when using the CLI and
 "grasslibs" + "grasswxpy" when using the GUI. Now 3 domains are being
 registered. So there is overhead.

 TBH I haven't read the whole {{{gettext}}} module line by line, but I
 think that the gist of {{{gettext.install()}}} is
 [https://github.com/python/cpython/blob/ead15795986972690217e52087eb946b8a5bbcda/Lib/gettext.py#L512-L552
 these lines]. Line 552 calls the method that does the builtin injection
 (check lines 314-316) while line 551 calls the function that registers the
 domain in a "private" dictionary named {{{_translations}}}. AFAI can tell
 from just reading the code, the only overhead to really speak of is the
 parsing of the {{{*.mo}}} files which in GRASS are a few hundred KBs. On
 SSDs this overhead should be negligible while on mechanical drives the
 bottleneck is not going to be the code anyway. Re-registering a domain
 should incur any overhead since the results are cached.

 That being said, if you feel that it is necessary, it should be possible
 to avoid registering "grasswxpy" and "grassmods" inside grass lib. E.g. by
 adding a couple of functions in {{{./lib/python/__init__.py}}}:
 {{{

 # ...
 _LOCALE_DIR = os.path.join(os.getenv("GISBASE"), 'locale')
 gettext.install('grasslibs', _LOCALE_DIR)


 def register_grassmods():
     gettext.install('grassmods', _LOCALE_DIR)


 def register_grasswxpy():
     gettext.install('grasswxpy', _LOCALE_DIR)



 }}}

 and making sure that they are imported by each and every module that needs
 them. But I am curious if the impact is that significant to make it worth
 it.

-- 
Ticket URL: <https://trac.osgeo.org/grass/ticket/3790#comment:5>
GRASS GIS <https://grass.osgeo.org>



More information about the grass-dev mailing list