/usr/share/mypaint/lib/glib.py is in mypaint 1.2.0-4.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | # This file is part of MyPaint.
# Copyright (C) 2015-2016 by the MyPaint Development Team.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
"""Pythonic wrappers for some standard GLib routines.
MyPaint is strict about using Unicode internally for everything, but
when GLib returns a filename, all hell can break loose (the data isn't
unicode, and may not even be UTF-8). This module works around that.
"""
## Imports
import sys
import logging
from gi.repository import GLib
logger = logging.getLogger(__name__)
## File path getter functions
def filename_to_unicode(opsysstring):
"""Converts a str representing a filename from GLib to unicode.
:param str opsysstring: a string in the (GLib) encoding for filenames
:returns: the converted filename
:rtype: unicode
>>> filename_to_unicode('/ascii/only/path')
u'/ascii/only/path'
>>> filename_to_unicode(None) is None
True
This is just a more Pythonic wrapper around g_filename_to_utf8() for
now. If there are compatibility reasons to change it, fallbacks
involving sys.getfilesystemencoding exist.
"""
if opsysstring is None:
return None
# On Windows, they're always UTF-8 regardless.
if sys.platform == "win32":
return opsysstring.decode("utf-8")
# Other systems are dependent in opaque ways on the environment.
if not isinstance(opsysstring, str):
raise TypeError("Argument must be bytes")
# This function's annotation seems to vary quite a bit.
# See https://github.com/mypaint/mypaint/issues/634
try:
ustring, _, _ = GLib.filename_to_utf8(opsysstring, -1)
except TypeError:
ustring = GLib.filename_to_utf8(opsysstring, -1, 0, 0)
if ustring is None:
raise UnicodeDecodeError(
"GLib failed to convert %r to a UTF-8 string. "
"Consider setting G_FILENAME_ENCODING if your file system's "
"filename encoding scheme is not UTF-8."
% (opsysstring,)
)
return ustring.decode("utf-8")
def get_user_config_dir():
"""Like g_get_user_config_dir(), but always unicode"""
d_fs = GLib.get_user_config_dir()
return filename_to_unicode(d_fs)
def get_user_data_dir():
"""Like g_get_user_data_dir(), but always unicode"""
d_fs = GLib.get_user_data_dir()
return filename_to_unicode(d_fs)
def get_user_cache_dir():
"""Like g_get_user_cache_dir(), but always unicode"""
d_fs = GLib.get_user_cache_dir()
return filename_to_unicode(d_fs)
def get_user_special_dir(d_id):
"""Like g_get_user_special_dir(), but always unicode"""
d_fs = GLib.get_user_special_dir(d_id)
return filename_to_unicode(d_fs)
## First-import cache forcing
def init_user_dir_caches():
"""Caches the GLib user directories
>>> init_user_dir_caches()
The first time this module is imported is from a particular point in
the launch script, after all the i18n setup is done and before
lib.mypaintlib is imported. If they're not cached up-front in this
manner, get_user_config_dir() & friends may return literal "?"s in
place of non-ASCII characters (Windows systems with non-ASCII user
profile dirs are known to trigger this).
The debugging prints may be useful too.
"""
logger.debug("Init g_get_user_config_dir(): %r", get_user_config_dir())
logger.debug("Init g_get_user_data_dir(): %r", get_user_data_dir())
logger.debug("Init g_get_user_cache_dir(): %r", get_user_cache_dir())
# It doesn't matter if some of these are None
for i in range(GLib.UserDirectory.N_DIRECTORIES):
k = GLib.UserDirectory(i)
logger.debug(
"Init g_get_user_special_dir(%s): %r",
k.value_name,
get_user_special_dir(k),
)
## Filename <-> URI conversion
def filename_to_uri(abspath, hostname=None):
"""More Pythonic & stable g_filename_to_uri(), with OS workarounds.
>>> import os.path
>>> relpath = os.path.join(u'tmp', u'smile (\u263a).ora')
>>> abspath = os.path.abspath(relpath)
>>> uri = filename_to_uri(abspath)
>>> isinstance(uri, str)
True
>>> uri.endswith('/tmp/smile%20(%E2%98%BA).ora')
True
>>> uri.startswith('file:///')
True
"""
if hostname:
raise ValueError("Only NULL hostnames are supported")
# GLib.filename_to_uri is *present* on Windows, for both i686 and
# x64_64 (MSYS2 builds), however attempting to *call* it on the
# 64-bit build results in
# "Error: g-invoke-error-quark: Could not locate g_filename_to_uri"
# as reported in https://github.com/mypaint/mypaint/issues/374
# Use the _utf8 variant instead on platforms where it exists.
try:
g_filename_to_uri = GLib.filename_to_uri_utf8
except AttributeError:
g_filename_to_uri = GLib.filename_to_uri
hostname = ""
return g_filename_to_uri(abspath, hostname)
def filename_from_uri(uri):
"""More Pythonic & stable g_filename_from_uri(), with OS workarounds.
>>> import os.path
>>> relpath = os.path.join(u'tmp', u'smile (\u263a).ora')
>>> abspath1 = os.path.abspath(relpath)
>>> uri = filename_to_uri(abspath1)
>>> abspath2, hostname = filename_from_uri(uri)
>>> isinstance(abspath2, unicode)
True
>>> abspath2.replace('\\\\', "/") == abspath1.replace('\\\\', "/")
True
"""
# First find the right g_filename_from_uri.
# See the note above.
try:
g_filename_from_uri = GLib.filename_from_uri_utf8
except AttributeError:
g_filename_from_uri = GLib.filename_from_uri
# But oh joy. We have to support more than one typelib.
try:
# Newer GLib typelibs on Linux mark it as a return.
abspath, hostname = g_filename_from_uri(uri)
except TypeError:
# Older GLib typelibs,
# including the one shipped with Ubuntu Server 12.04 (Travis!)
# And that windows _utf8 mess still uses it too.
abspath = g_filename_from_uri(uri, "")
hostname = None
assert (not hostname), ("Only URIs without hostnames are supported.")
return (filename_to_unicode(abspath), None)
## Module testing
def _test():
import doctest
doctest.testmod()
if __name__ == '__main__':
_test()
|