##// END OF EJS Templates
resourceutil: start using importlib.resources.files() when possible...
av6 -
r50838:330d8821 stable
parent child Browse files
Show More
@@ -1,108 +1,120 b''
1 # resourceutil.py - utility for looking up resources
1 # resourceutil.py - utility for looking up resources
2 #
2 #
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10
10
11 import imp
11 import imp
12 import os
12 import os
13 import sys
13 import sys
14
14
15 from .. import pycompat
15 from .. import pycompat
16
16
17
17
18 def mainfrozen():
18 def mainfrozen():
19 """return True if we are a frozen executable.
19 """return True if we are a frozen executable.
20
20
21 The code supports py2exe (most common, Windows only) and tools/freeze
21 The code supports py2exe (most common, Windows only) and tools/freeze
22 (portable, not much used).
22 (portable, not much used).
23 """
23 """
24 return (
24 return (
25 pycompat.safehasattr(sys, "frozen") # new py2exe
25 pycompat.safehasattr(sys, "frozen") # new py2exe
26 or pycompat.safehasattr(sys, "importers") # old py2exe
26 or pycompat.safehasattr(sys, "importers") # old py2exe
27 or imp.is_frozen("__main__") # tools/freeze
27 or imp.is_frozen("__main__") # tools/freeze
28 )
28 )
29
29
30
30
31 # the location of data files matching the source code
31 # the location of data files matching the source code
32 if mainfrozen() and getattr(sys, "frozen", None) != "macosx_app":
32 if mainfrozen() and getattr(sys, "frozen", None) != "macosx_app":
33 # executable version (py2exe) doesn't support __file__
33 # executable version (py2exe) doesn't support __file__
34 datapath = os.path.dirname(pycompat.sysexecutable)
34 datapath = os.path.dirname(pycompat.sysexecutable)
35 _rootpath = datapath
35 _rootpath = datapath
36
36
37 # The installers store the files outside of library.zip, like
37 # The installers store the files outside of library.zip, like
38 # C:\Program Files\Mercurial\defaultrc\*.rc. This strips the
38 # C:\Program Files\Mercurial\defaultrc\*.rc. This strips the
39 # leading "mercurial." off of the package name, so that these
39 # leading "mercurial." off of the package name, so that these
40 # pseudo resources are found in their directory next to the
40 # pseudo resources are found in their directory next to the
41 # executable.
41 # executable.
42 def _package_path(package):
42 def _package_path(package):
43 dirs = package.split(b".")
43 dirs = package.split(b".")
44 assert dirs[0] == b"mercurial"
44 assert dirs[0] == b"mercurial"
45 return os.path.join(_rootpath, *dirs[1:])
45 return os.path.join(_rootpath, *dirs[1:])
46
46
47
47
48 else:
48 else:
49 datapath = os.path.dirname(os.path.dirname(pycompat.fsencode(__file__)))
49 datapath = os.path.dirname(os.path.dirname(pycompat.fsencode(__file__)))
50 _rootpath = os.path.dirname(datapath)
50 _rootpath = os.path.dirname(datapath)
51
51
52 def _package_path(package):
52 def _package_path(package):
53 return os.path.join(_rootpath, *package.split(b"."))
53 return os.path.join(_rootpath, *package.split(b"."))
54
54
55
55
56 try:
56 try:
57 # importlib.resources exists from Python 3.7; see fallback in except clause
57 # importlib.resources exists from Python 3.7; see fallback in except clause
58 # further down
58 # further down
59 from importlib import resources # pytype: disable=import-error
59 from importlib import resources # pytype: disable=import-error
60
60
61 # Force loading of the resources module
61 # Force loading of the resources module
62 resources.open_binary # pytype: disable=module-attr
62 if pycompat.safehasattr(resources, 'files'):
63 resources.files # pytype: disable=module-attr
64 else:
65 resources.open_binary # pytype: disable=module-attr
63
66
64 # py2exe raises an AssertionError if uses importlib.resources
67 # py2exe raises an AssertionError if uses importlib.resources
65 if getattr(sys, "frozen", None) in ("console_exe", "windows_exe"):
68 if getattr(sys, "frozen", None) in ("console_exe", "windows_exe"):
66 raise ImportError
69 raise ImportError
67
70
68 except (ImportError, AttributeError):
71 except (ImportError, AttributeError):
69 # importlib.resources was not found (almost definitely because we're on a
72 # importlib.resources was not found (almost definitely because we're on a
70 # Python version before 3.7)
73 # Python version before 3.7)
71
74
72 def open_resource(package, name):
75 def open_resource(package, name):
73 path = os.path.join(_package_path(package), name)
76 path = os.path.join(_package_path(package), name)
74 return open(path, "rb")
77 return open(path, "rb")
75
78
76 def is_resource(package, name):
79 def is_resource(package, name):
77 path = os.path.join(_package_path(package), name)
80 path = os.path.join(_package_path(package), name)
78
81
79 try:
82 try:
80 return os.path.isfile(pycompat.fsdecode(path))
83 return os.path.isfile(pycompat.fsdecode(path))
81 except (IOError, OSError):
84 except (IOError, OSError):
82 return False
85 return False
83
86
84 def contents(package):
87 def contents(package):
85 path = pycompat.fsdecode(_package_path(package))
88 path = pycompat.fsdecode(_package_path(package))
86
89
87 for p in os.listdir(path):
90 for p in os.listdir(path):
88 yield pycompat.fsencode(p)
91 yield pycompat.fsencode(p)
89
92
90
93
91 else:
94 else:
92 from .. import encoding
95 from .. import encoding
93
96
94 def open_resource(package, name):
97 def open_resource(package, name):
95 return resources.open_binary( # pytype: disable=module-attr
98 if pycompat.safehasattr(resources, 'files'):
96 pycompat.sysstr(package), pycompat.sysstr(name)
99 return (
97 )
100 resources.files( # pytype: disable=module-attr
101 pycompat.sysstr(package)
102 )
103 .joinpath(pycompat.sysstr(name))
104 .open('rb')
105 )
106 else:
107 return resources.open_binary( # pytype: disable=module-attr
108 pycompat.sysstr(package), pycompat.sysstr(name)
109 )
98
110
99 def is_resource(package, name):
111 def is_resource(package, name):
100 return resources.is_resource( # pytype: disable=module-attr
112 return resources.is_resource( # pytype: disable=module-attr
101 pycompat.sysstr(package), encoding.strfromlocal(name)
113 pycompat.sysstr(package), encoding.strfromlocal(name)
102 )
114 )
103
115
104 def contents(package):
116 def contents(package):
105 # pytype: disable=module-attr
117 # pytype: disable=module-attr
106 for r in resources.contents(pycompat.sysstr(package)):
118 for r in resources.contents(pycompat.sysstr(package)):
107 # pytype: enable=module-attr
119 # pytype: enable=module-attr
108 yield encoding.strtolocal(r)
120 yield encoding.strtolocal(r)
General Comments 0
You need to be logged in to leave comments. Login now