Grampslocale: Fix minor PyLint complaints.

Short/duplicate variable names, missing docstrings, gratuitous
semicolons, excess returns, etc.
This commit is contained in:
John Ralls 2023-07-14 13:33:50 -07:00 committed by Nick Hall
parent a89faa85e0
commit 354e191ea0

View File

@ -20,6 +20,13 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# #
"""
GrampsLocale encapsulates localization and locale
initialization. There's a default locale object but more can be
created with a different locale and translation binding to enable
generating reports in languages and locales other than the one used
for the user interface.
"""
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -47,23 +54,24 @@ if sys.platform == 'win32':
LOG = logging.getLogger("." + __name__) LOG = logging.getLogger("." + __name__)
LOG.propagate = True LOG.propagate = True
HAVE_ICU = False HAVE_ICU = False
_icu_err = None _ICU_ERR = None
_hdlr = None _HDLR = None
# GrampsLocale initialization comes before command-line argument # GrampsLocale initialization comes before command-line argument
# passing, so one must set the log level directly. The default is # passing, so one must set the log level directly. The default is
# logging.WARN. Uncomment the following to change it to logging.DEBUG: # logging.WARN. Uncomment the following to change it to logging.DEBUG:
# LOG.setLevel(logging.DEBUG) # LOG.setLevel(logging.DEBUG)
try: try:
from icu import Locale, Collator from icu import Locale, Collator, ICUError
HAVE_ICU = True HAVE_ICU = True
except ImportError: except ImportError:
try: try:
from PyICU import Locale, Collator from PyICU import Locale, Collator, ICUError
HAVE_ICU = True HAVE_ICU = True
except ImportError as err: except ImportError as err:
ERRSTR = str(err)
# No logger, save the warning message for later. # No logger, save the warning message for later.
_icu_err = ("ICU not loaded because %s. Localization will be impaired. " _ICU_ERR = (f"ICU not loaded because {ERRSTR}. Localization will be "
"Use your package manager to install PyICU" % str(err)) "impaired. Use your package manager to install PyICU")
ICU_LOCALES = None ICU_LOCALES = None
if HAVE_ICU: if HAVE_ICU:
@ -75,7 +83,9 @@ if HAVE_ICU:
# get xgettext to include the string in gramps.pot; actual translation # get xgettext to include the string in gramps.pot; actual translation
# is done in _get_language_string() below. # is done in _get_language_string() below.
# (The gramps officially-supported language list is ALL_LINGUAS in setup.py) # (The gramps officially-supported language list is ALL_LINGUAS in setup.py)
_ = lambda x: x def _(msgid):
return msgid
_LOCALE_NAMES = { _LOCALE_NAMES = {
'ar': ('Arabic_Saudi Arabia', '1256', _("Arabic")), 'ar': ('Arabic_Saudi Arabia', '1256', _("Arabic")),
'bg': ('Bulgrian_Bulgaria', '1251', _("Bulgarian")), 'bg': ('Bulgrian_Bulgaria', '1251', _("Bulgarian")),
@ -139,23 +149,23 @@ def _check_mswin_locale(loc):
msloc = None msloc = None
try: try:
msloc = _LOCALE_NAMES[loc[:5]][:2] msloc = _LOCALE_NAMES[loc[:5]][:2]
loc = loc[:5] newloc = loc[:5]
except KeyError: except KeyError:
try: try:
msloc = _LOCALE_NAMES[loc[:2]][:2] msloc = _LOCALE_NAMES[loc[:2]][:2]
loc = loc[:2] newloc = loc[:2]
except KeyError: except KeyError:
#US English is the outlier, all other English locales want #US English is the outlier, all other English locales want
#real English: #real English:
if loc[:2] == ('en') and loc[:5] != 'en_US': if loc[:2] == ('en') and loc[:5] != 'en_US':
return ('en_GB', '1252') return ('en_GB', '1252')
return (None, None) return (None, None)
return (loc, msloc) return (newloc, msloc)
def _check_mswin_locale_reverse(loc): def _check_mswin_locale_reverse(loc):
for (loc, msloc) in _LOCALE_NAMES.items(): for (newloc, msloc) in _LOCALE_NAMES.items():
if msloc and loc == msloc[0]: if msloc and newloc == msloc[0]:
return (loc, msloc[1]) return (newloc, msloc[1])
#US English is the outlier, all other English locales want real English: #US English is the outlier, all other English locales want real English:
if loc.startswith('English') and loc != 'English_United States': if loc.startswith('English') and loc != 'English_United States':
return ('en_GB', '1252') return ('en_GB', '1252')
@ -171,15 +181,14 @@ def _check_gformat():
# Gramps treats dates with '-' as ISO format, so replace separator # Gramps treats dates with '-' as ISO format, so replace separator
# on locale dates that use '-' to prevent confict # on locale dates that use '-' to prevent confict
gformat = gformat.replace('-', '/') gformat = gformat.replace('-', '/')
except: except locale.Error:
''' # Depending on the locale, the value returned for 20th Feb 2009
Depending on the locale, the value returned for 20th Feb 2009 # could be '20/2/2009', '20/02/2009', '20.2.2009', '20.02.2009',
could be '20/2/2009', '20/02/2009', '20.2.2009', '20.02.2009', # '20-2-2009', '20-02-2009', '2009/02/20', '2009.02.20',
'20-2-2009', '20-02-2009', '2009/02/20', '2009.02.20', # '2009-02-20', or '09-02-20' so to reduce the possible values to
'2009-02-20', or '09-02-20' so to reduce the possible values to # test for, make sure both the month and the day are double digits,
test for, make sure both the month and the day are double digits, # preferably greater than 12 for human readablity
preferably greater than 12 for human readablity
'''
timestr = time.strftime('%x',(2005,10,25,1,1,1,1,1,1)) timestr = time.strftime('%x',(2005,10,25,1,1,1,1,1,1))
# Gramps treats dates with '-' as ISO format, so replace separator # Gramps treats dates with '-' as ISO format, so replace separator
@ -245,16 +254,18 @@ class GrampsLocale:
if not cls.__first_instance.initialized: if not cls.__first_instance.initialized:
raise RuntimeError("Second GrampsLocale created before " raise RuntimeError("Second GrampsLocale created before "
"first one was initialized") "first one was initialized")
if ((lang is None or lang == cls.__first_instance.lang) if cls.__first_instance._matches(localedir, lang, domain, languages):
and (localedir is None or
localedir == cls.__first_instance.localedir)
and (domain is None or domain == cls.__first_instance.localedomain)
and (languages is None or len(languages) == 0 or
languages == cls.__first_instance.language)):
return cls.__first_instance return cls.__first_instance
return super(GrampsLocale, cls).__new__(cls) return super(GrampsLocale, cls).__new__(cls)
def _matches(self, localedir, lang, domain, languages):
matches = localedir is None or self.localedir == localedir
matches = matches and (lang is None or self.lang == lang)
matches = matches and (domain is None or self.localedomain == domain)
return matches and (languages is None or len(languages) == 0 or
self.languages == languages)
def _win_init_environment(self): def _win_init_environment(self):
""" """
The Windows implementation of Python ignores environment The Windows implementation of Python ignores environment
@ -449,15 +460,15 @@ class GrampsLocale:
available. We only do this once, and the resulting available. We only do this once, and the resulting
GrampsLocale is returned by default. GrampsLocale is returned by default.
""" """
global _hdlr global _HDLR
_hdlr = logging.StreamHandler() _HDLR = logging.StreamHandler()
_hdlr.setFormatter(logging.Formatter(fmt="%(name)s.%(levelname)s: " _HDLR.setFormatter(logging.Formatter(fmt="%(name)s.%(levelname)s: "
"%(message)s")) "%(message)s"))
LOG.addHandler(_hdlr) LOG.addHandler(_HDLR)
#Now that we have a logger set up we can issue the icu error if needed. #Now that we have a logger set up we can issue the icu error if needed.
if not HAVE_ICU: if not HAVE_ICU:
LOG.warning(_icu_err) LOG.warning(_ICU_ERR)
# Even the first instance can be overridden by passing lang # Even the first instance can be overridden by passing lang
# and languages to the constructor. If it isn't (which is the # and languages to the constructor. If it isn't (which is the
@ -529,7 +540,7 @@ class GrampsLocale:
# GtkBuilder uses GLib's g_dgettext wrapper, which oddly is bound # GtkBuilder uses GLib's g_dgettext wrapper, which oddly is bound
# with locale instead of gettext. Win32 doesn't support bindtextdomain. # with locale instead of gettext. Win32 doesn't support bindtextdomain.
if self.localedir: if self.localedir:
if not sys.platform == 'win32': if sys.platform != 'win32':
# bug12278, _build_popup_ui() under linux and macOS # bug12278, _build_popup_ui() under linux and macOS
locale.textdomain(self.localedomain) locale.textdomain(self.localedomain)
locale.bindtextdomain(self.localedomain, self.localedir) locale.bindtextdomain(self.localedomain, self.localedir)
@ -554,13 +565,13 @@ class GrampsLocale:
if not self.localedir: if not self.localedir:
LOG.warning("No Localedir provided, unable to find translations") LOG.warning("No Localedir provided, unable to find translations")
_first = self._GrampsLocale__first_instance
if not self.localedomain: if not self.localedomain:
if _firstlocaledomain: # TODO this variable is nowhere else if _first.localedomain:
self.localedomain = _first.localedomain self.localedomain = _first.localedomain
else: else:
self.localedomain = "gramps" self.localedomain = "gramps"
_first = self._GrampsLocale__first_instance
if not self.lang and _first.lang: if not self.lang and _first.lang:
self.lang = _first.lang self.lang = _first.lang
@ -585,14 +596,18 @@ class GrampsLocale:
environment if this is the first run. Return __first_instance environment if this is the first run. Return __first_instance
otherwise if called without arguments. otherwise if called without arguments.
""" """
global _hdlr global _HDLR
#initialized is special, used only for the "first instance", #initialized is special, used only for the "first instance",
#and created by __new__(). It's used to prevent re-__init__ing #and created by __new__(). It's used to prevent re-__init__ing
#__first_instance when __new__() returns its pointer. #__first_instance when __new__() returns its pointer.
if hasattr(self, 'initialized') and self.initialized: if hasattr(self, 'initialized') and self.initialized:
return return
_first = self._GrampsLocale__first_instance
self.localedir = None self.localedir = None
self.collator = None
self.collation = None
self.calendar = None
self.rtl_locale = False
_first = self._GrampsLocale__first_instance
# Everything breaks without localedir, so get that set up # Everything breaks without localedir, so get that set up
# first. Warnings are logged in __init_first_instance or # first. Warnings are logged in __init_first_instance or
# _init_secondary_locale if this comes up empty. # _init_secondary_locale if this comes up empty.
@ -619,7 +634,6 @@ class GrampsLocale:
self._init_secondary_locale() self._init_secondary_locale()
self.icu_locales = {} self.icu_locales = {}
self.collator = None
if HAVE_ICU: if HAVE_ICU:
self.icu_locales["default"] = Locale.createFromName(self.lang) self.icu_locales["default"] = Locale.createFromName(self.lang)
if self.collation and self.collation != self.lang: if self.collation and self.collation != self.lang:
@ -642,18 +656,18 @@ class GrampsLocale:
LOG.warning("Unable to find translation for languages in %s, " LOG.warning("Unable to find translation for languages in %s, "
"using US English", ':'.join(self.language)) "using US English", ':'.join(self.language))
self.translation = GrampsNullTranslations() self.translation = GrampsNullTranslations()
self.translation._language = "en" self.translation.lang = "en"
if _hdlr: if _HDLR:
LOG.removeHandler(_hdlr) LOG.removeHandler(_HDLR)
_hdlr = None _HDLR = None
self._dd = self._dp = None self._dd = self._dp = None
#Guards against running twice on the first instance. #Guards against running twice on the first instance.
self.initialized = True self.initialized = True
def _get_translation(self, domain = None, def _get_translation(self, domain = None,
localedir = None, localedir = None,
languages=None): languages = None):
""" """
Get a translation of one of our classes. Doesn't return the Get a translation of one of our classes. Doesn't return the
singleton so that it can be used by get_addon_translation() singleton so that it can be used by get_addon_translation()
@ -670,21 +684,22 @@ class GrampsLocale:
translator = gettext.translation(domain, localedir=localedir, translator = gettext.translation(domain, localedir=localedir,
languages=[lang], languages=[lang],
class_ = GrampsTranslations) class_ = GrampsTranslations)
translator._language = lang translator.lang = lang
return translator return translator
elif lang.startswith("en") or lang.startswith("C"): if lang.startswith("en") or lang.startswith("C"):
translator = GrampsNullTranslations() translator = GrampsNullTranslations()
translator._language = "en" translator.lang = "en"
return translator return translator
if not languages or len(languages) == 0: if not languages or len(languages) == 0:
LOG.warning("No language provided, using US English") LOG.warning("No language provided, using US English")
else: else:
raise ValueError("No usable translations in %s for " % lang_str = ':'.join(languages)
':'.join(languages)) raise ValueError(f"No usable translations in {lang_str}"
f" for {domain}" )
translator = GrampsNullTranslations() translator = GrampsNullTranslations()
translator._language = "en" translator.lang = "en"
return translator return translator
def _get_language_string(self, lang_code): def _get_language_string(self, lang_code):
@ -701,7 +716,7 @@ class GrampsLocale:
LOG.debug("Gramps has no translation for %s", lang_code) LOG.debug("Gramps has no translation for %s", lang_code)
lang = None lang = None
except IndexError: except IndexError:
LOG.debug("Bad Index for tuple %s\n" % _LOCALE_NAMES[lang_code][0]) LOG.debug("Bad Index for tuple %s\n", _LOCALE_NAMES[lang_code][0])
lang = None lang = None
if lang: if lang:
@ -733,16 +748,17 @@ class GrampsLocale:
try: try:
val = config.get('preferences.date-format') val = config.get('preferences.date-format')
except AttributeError: except AttributeError:
val = 0; val = 0
_first = self._GrampsLocale__first_instance _first = self._GrampsLocale__first_instance
if self.calendar in displayers: if self.calendar in displayers:
self._dd = displayers[self.calendar](val) self._dd = displayers[self.calendar](val)
elif self.calendar[:2] in displayers: elif self.calendar and self.calendar[:2] in displayers:
self._dd = displayers[self.calendar[:2]](val) self._dd = displayers[self.calendar[:2]](val)
elif self != _first and _first.calendar in displayers: elif self != _first and _first.calendar in displayers:
self._dd = displayers[_first.calendar](val, blocale=self) self._dd = displayers[_first.calendar](val, blocale=self)
elif self != _first and _first.calendar[:2] in displayers: elif (self != _first and _first.calendar and
q_first.calendar[:2] in displayers):
self._dd = displayers[_first.calendar[:2]](val, blocale=self) self._dd = displayers[_first.calendar[:2]](val, blocale=self)
else: else:
self._dd = displayers['C'](val, blocale=self) self._dd = displayers['C'](val, blocale=self)
@ -768,11 +784,12 @@ class GrampsLocale:
_first = self._GrampsLocale__first_instance _first = self._GrampsLocale__first_instance
if self.calendar in parsers: if self.calendar in parsers:
self._dp = parsers[self.calendar]() self._dp = parsers[self.calendar]()
elif self.calendar[:2] in parsers: elif self.calendar and self.calendar[:2] in parsers:
self._dp = parsers[self.calendar]() self._dp = parsers[self.calendar]()
elif self != _first and _first.calendar in parsers: elif self != _first and _first.calendar in parsers:
self._dp = parsers[_first.calendar]() self._dp = parsers[_first.calendar]()
elif self != _first and _first.calendar[:2] in parsers: elif (self != _first and _first.calendar and
_first.calendar[:2] in parsers):
self._dp = parsers[_first.calendar[:2]]() self._dp = parsers[_first.calendar[:2]]()
else: else:
self._dp = parsers['C']() self._dp = parsers['C']()
@ -801,6 +818,9 @@ class GrampsLocale:
return self.language return self.language
def locale_code(self): def locale_code(self):
"""
Return the locale code.
"""
return self.lang return self.lang
def get_addon_translator(self, filename, domain="addon", def get_addon_translator(self, filename, domain="addon",
@ -860,7 +880,7 @@ class GrampsLocale:
for langdir in os.listdir(self.localedir): for langdir in os.listdir(self.localedir):
mofilename = os.path.join(localedir, langdir, mofilename = os.path.join(localedir, langdir,
"LC_MESSAGES", "LC_MESSAGES",
"%s.mo" % localedomain ) f"{localedomain}.mo" )
if os.path.exists(mofilename): if os.path.exists(mofilename):
languages.append(langdir) languages.append(langdir)
@ -910,27 +930,29 @@ class GrampsLocale:
_ = self.translation.gettext _ = self.translation.gettext
objclass = objclass_str.lower() objclass = objclass_str.lower()
if objclass == "person": if objclass == "person":
return _("the person") retval = _("the person")
elif objclass == "family": elif objclass == "family":
return _("the family") retval = _("the family")
elif objclass == "place": elif objclass == "place":
return _("the place") retval = _("the place")
elif objclass == "event": elif objclass == "event":
return _("the event") retval = _("the event")
elif objclass == "repository": elif objclass == "repository":
return _("the repository") retval = _("the repository")
elif objclass == "note": elif objclass == "note":
return _("the note") retval = _("the note")
elif objclass == "media": elif objclass == "media":
return _("the media") retval = _("the media")
elif objclass == "source": elif objclass == "source":
return _("the source") retval = _("the source")
elif objclass == "filter": elif objclass == "filter":
return _("the filter") retval = _("the filter")
elif objclass == "citation": elif objclass == "citation":
return _("the citation") retval = _("the citation")
else: else:
return _("See details") retval = _("See details")
return retval
def sort_key(self, string): def sort_key(self, string):
""" """
@ -942,22 +964,24 @@ class GrampsLocale:
# Use hexlify() as to make a consistent string, fixing bug #10077 # Use hexlify() as to make a consistent string, fixing bug #10077
key = self.collator.getCollationKey(string) key = self.collator.getCollationKey(string)
return hexlify(key.getByteArray()).decode() return hexlify(key.getByteArray()).decode()
else:
if isinstance(string, bytes): if isinstance(string, bytes):
string = string.decode("utf-8", "replace") string = string.decode("utf-8", "replace")
try: try:
key = locale.strxfrm(string) key = locale.strxfrm(string)
except Exception as icu_err: except ICUError as icu_err:
LOG.warning("Failed to obtain key for %s because %s", LOG.warning("Failed to obtain key for %s because %s",
self.collation, str(icu_err)) self.collation, str(icu_err))
return string return string
return key return key
def get_collation(self): def get_collation(self):
""" """
Return the collation without any character encoding. Return the collation without any character encoding.
""" """
return self.collation.split('.')[0] if self.collation is not None:
return self.collation.split('.')[0]
return "C"
def strcoll(self, string1, string2): def strcoll(self, string1, string2):
""" """
@ -1018,9 +1042,8 @@ class GrampsLocale:
try: try:
if point == ',': if point == ',':
return locale.atof(val.replace(' ', sep).replace('.', sep)) return locale.atof(val.replace(' ', sep).replace('.', sep))
elif point == '.': if point == '.':
return locale.atof(val.replace(' ', sep).replace(',', sep)) return locale.atof(val.replace(' ', sep).replace(',', sep))
else: return None
return None
except ValueError: except ValueError:
return None return None