1 | """ |
||
2 | Orange Canvas Resource Loader |
||
3 | |||
4 | """ |
||
5 | |||
6 | import os |
||
7 | import logging |
||
8 | |||
9 | log = logging.getLogger(__name__) |
||
10 | |||
11 | |||
12 | def package_dirname(package): |
||
0 ignored issues
–
show
|
|||
13 | """Return the directory path where package is located. |
||
14 | |||
15 | """ |
||
16 | if isinstance(package, str): |
||
17 | package = __import__(package, fromlist=[""]) |
||
18 | filename = package.__file__ |
||
19 | dirname = os.path.dirname(filename) |
||
0 ignored issues
–
show
dirname is re-defining a name which is already available in the outer-scope (previously defined on line 48 ).
It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior: param = 5
class Foo:
def __init__(self, param): # "param" would be flagged here
self.param = param
![]() |
|||
20 | return dirname |
||
21 | |||
22 | |||
23 | def package(qualified_name): |
||
24 | """Return the enclosing package name where qualified_name is located. |
||
25 | |||
26 | `qualified_name` can be a module inside the package or even an object |
||
27 | inside the module. If a package name itself is provided it is returned. |
||
28 | |||
29 | """ |
||
30 | try: |
||
31 | module = __import__(qualified_name, fromlist=[""]) |
||
32 | except ImportError: |
||
33 | # qualified_name could name an object inside a module/package |
||
34 | if "." in qualified_name: |
||
35 | qualified_name, attr_name = qualified_name.rsplit(".", 1) |
||
36 | module = __import__(qualified_name, fromlist=[attr_name]) |
||
37 | else: |
||
38 | raise |
||
39 | |||
40 | if module.__package__ is not None: |
||
41 | # the modules enclosing package |
||
42 | return module.__package__ |
||
43 | else: |
||
44 | # 'qualified_name' is itself the package |
||
45 | assert(module.__name__ == qualified_name) |
||
0 ignored issues
–
show
|
|||
46 | return qualified_name |
||
47 | |||
48 | dirname = os.path.abspath(os.path.dirname(__file__)) |
||
49 | |||
50 | DEFAULT_SEARCH_PATHS = \ |
||
51 | [("", dirname), |
||
52 | ("", os.path.join(dirname, "../widgets"))] |
||
53 | |||
54 | del dirname |
||
55 | |||
56 | |||
57 | def default_search_paths(): |
||
58 | return DEFAULT_SEARCH_PATHS |
||
59 | |||
60 | |||
61 | def add_default_search_paths(search_paths): |
||
62 | DEFAULT_SEARCH_PATHS.extend(search_paths) |
||
63 | |||
64 | |||
65 | def search_paths_from_description(desc): |
||
66 | """Return the search paths for the Category/WidgetDescription. |
||
67 | """ |
||
68 | paths = [] |
||
69 | if desc.package: |
||
70 | dirname = package_dirname(desc.package) |
||
0 ignored issues
–
show
dirname is re-defining a name which is already available in the outer-scope (previously defined on line 48 ).
It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior: param = 5
class Foo:
def __init__(self, param): # "param" would be flagged here
self.param = param
![]() |
|||
71 | paths.append(("", dirname)) |
||
72 | elif desc.qualified_name: |
||
73 | dirname = package_dirname(package(desc.qualified_name)) |
||
74 | paths.append(("", dirname)) |
||
75 | |||
76 | if hasattr(desc, "search_paths"): |
||
77 | paths.extend(desc.search_paths) |
||
78 | return paths |
||
79 | |||
80 | |||
81 | class resource_loader(object): |
||
82 | def __init__(self, search_paths=()): |
||
83 | self._search_paths = [] |
||
84 | self.add_search_paths(search_paths) |
||
85 | |||
86 | @classmethod |
||
87 | def from_description(cls, desc): |
||
88 | """Construct an resource from a Widget or Category |
||
89 | description. |
||
90 | |||
91 | """ |
||
92 | paths = search_paths_from_description(desc) |
||
93 | return icon_loader(search_paths=paths) |
||
94 | |||
95 | def add_search_paths(self, paths): |
||
96 | """Add `paths` to the list of search paths. |
||
97 | """ |
||
98 | self._search_paths.extend(paths) |
||
99 | |||
100 | def search_paths(self): |
||
101 | """Return a list of all search paths. |
||
102 | """ |
||
103 | return self._search_paths + default_search_paths() |
||
104 | |||
105 | def split_prefix(self, path): |
||
106 | """Split prefixed path. |
||
107 | """ |
||
108 | if self.is_valid_prefixed(path) and ":" in path: |
||
109 | prefix, path = path.split(":", 1) |
||
110 | else: |
||
111 | prefix = "" |
||
112 | return prefix, path |
||
113 | |||
114 | def is_valid_prefixed(self, path): |
||
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
![]() |
|||
115 | i = path.find(":") |
||
116 | return i != 1 |
||
117 | |||
118 | def find(self, name): |
||
119 | """Find a resource matching `name`. |
||
120 | """ |
||
121 | prefix, path = self.split_prefix(name) |
||
122 | if prefix == "" and self.match(path): |
||
123 | return path |
||
124 | elif self.is_valid_prefixed(path): |
||
125 | for pp, search_path in self.search_paths(): |
||
126 | if pp == prefix and \ |
||
127 | self.match(os.path.join(search_path, path)): |
||
128 | return os.path.join(search_path, path) |
||
129 | |||
130 | return None |
||
131 | |||
132 | def match(self, path): |
||
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
![]() |
|||
133 | return os.path.exists(path) |
||
134 | |||
135 | def get(self, name): |
||
136 | return self.load(name) |
||
137 | |||
138 | def load(self, name): |
||
139 | return self.open(name).read() |
||
140 | |||
141 | def open(self, name): |
||
142 | path = self.find(name) |
||
143 | if path is not None: |
||
144 | return open(path, "rb") |
||
145 | else: |
||
146 | raise IOError(2, "Cannot find %r" % name) |
||
147 | |||
148 | import glob |
||
149 | |||
150 | |||
151 | class icon_loader(resource_loader): |
||
0 ignored issues
–
show
|
|||
152 | DEFAULT_ICON = "icons/Unknown.png" |
||
153 | |||
154 | def match(self, path): |
||
155 | if resource_loader.match(self, path): |
||
156 | return True |
||
157 | return self.is_icon_glob(path) |
||
158 | |||
159 | def icon_glob(self, path): |
||
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
![]() |
|||
160 | name, ext = os.path.splitext(path) |
||
161 | pattern = name + "_*" + ext |
||
162 | return glob.glob(pattern) |
||
163 | |||
164 | def is_icon_glob(self, path): |
||
0 ignored issues
–
show
This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
![]() |
|||
165 | name, ext = os.path.splitext(path) |
||
166 | pattern = name + "_*" + ext |
||
167 | return bool(glob.glob(pattern)) |
||
168 | |||
169 | def get(self, name, default=None): |
||
0 ignored issues
–
show
|
|||
170 | path = self.find(name) |
||
171 | if not path: |
||
172 | path = self.find(self.DEFAULT_ICON if default is None else default) |
||
173 | if not path: |
||
174 | raise IOError(2, "Cannot find %r in %s" % |
||
175 | (name, self.search_paths())) |
||
176 | if self.is_icon_glob(path): |
||
177 | icons = self.icon_glob(path) |
||
178 | else: |
||
179 | icons = [path] |
||
180 | |||
181 | from PyQt4.QtGui import QIcon |
||
0 ignored issues
–
show
The import
PyQt4.QtGui could not be resolved.
This can be caused by one of the following: 1. Missing DependenciesThis error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands. # .scrutinizer.yml
before_commands:
- sudo pip install abc # Python2
- sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use
the command for the correct version.
2. Missing __init__.py filesThis error could also result from missing ![]() |
|||
182 | |||
183 | icon = QIcon() |
||
184 | for path in icons: |
||
185 | icon.addFile(path) |
||
186 | return icon |
||
187 | |||
188 | def open(self, name): |
||
189 | raise NotImplementedError |
||
190 | |||
191 | def load(self, name): |
||
192 | return self.get(name) |
||
193 | |||
194 | |||
195 | import unittest |
||
196 | |||
197 | |||
198 | class TestIconLoader(unittest.TestCase): |
||
199 | def setUp(self): |
||
200 | from PyQt4.QtGui import QApplication |
||
0 ignored issues
–
show
The import
PyQt4.QtGui could not be resolved.
This can be caused by one of the following: 1. Missing DependenciesThis error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands. # .scrutinizer.yml
before_commands:
- sudo pip install abc # Python2
- sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use
the command for the correct version.
2. Missing __init__.py filesThis error could also result from missing ![]() |
|||
201 | self.app = QApplication([]) |
||
202 | |||
203 | def tearDown(self): |
||
204 | self.app.exit() |
||
205 | del self.app |
||
206 | |||
207 | def test_loader(self): |
||
208 | loader = icon_loader() |
||
209 | self.assertEqual(loader.search_paths(), DEFAULT_SEARCH_PATHS) |
||
210 | icon = loader.get("icons/CanvasIcon.png") |
||
211 | self.assertTrue(not icon.isNull()) |
||
212 | |||
213 | path = loader.find(":icons/CanvasIcon.png") |
||
214 | self.assertTrue(os.path.isfile(path)) |
||
215 | icon = loader.get(":icons/CanvasIcon.png") |
||
216 | self.assertTrue(not icon.isNull()) |
||
217 | |||
218 | def test_from_desc(self): |
||
219 | from .registry.description import ( |
||
220 | WidgetDescription, CategoryDescription |
||
221 | ) |
||
222 | |||
223 | desc = WidgetDescription.from_module( |
||
224 | "Orange.OrangeWidgets.Data.OWFile" |
||
225 | ) |
||
226 | |||
227 | loader = icon_loader.from_description(desc) |
||
228 | path = loader.find(desc.icon) |
||
229 | self.assertTrue(os.path.isfile(path)) |
||
230 | icon = loader.get(desc.icon) |
||
231 | self.assertTrue(not icon.isNull()) |
||
232 | |||
233 | desc = CategoryDescription.from_package("Orange.OrangeWidgets.Data") |
||
234 | loader = icon_loader.from_description(desc) |
||
235 | path = loader.find("icons/file.svg") |
||
236 | self.assertTrue(os.path.isfile(path)) |
||
237 | icon = loader.get("icons/file.svg") |
||
238 | self.assertTrue(not icon.isNull()) |
||
239 | |||
240 | def test_package_reflection(self): |
||
241 | from Orange.OrangeWidgets.Data import OWFile |
||
0 ignored issues
–
show
The import
Orange.OrangeWidgets.Data could not be resolved.
This can be caused by one of the following: 1. Missing DependenciesThis error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands. # .scrutinizer.yml
before_commands:
- sudo pip install abc # Python2
- sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use
the command for the correct version.
2. Missing __init__.py filesThis error could also result from missing ![]() |
|||
242 | from Orange.OrangeWidgets import Data |
||
0 ignored issues
–
show
The import
Orange.OrangeWidgets could not be resolved.
This can be caused by one of the following: 1. Missing DependenciesThis error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands. # .scrutinizer.yml
before_commands:
- sudo pip install abc # Python2
- sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use
the command for the correct version.
2. Missing __init__.py filesThis error could also result from missing ![]() |
|||
243 | package_name = Data.__name__ |
||
244 | p1 = package("Orange.OrangeWidgets.Data.OWFile.OWFile") |
||
245 | self.assertEqual(p1, package_name) |
||
246 | |||
247 | p2 = package("Orange.OrangeWidgets.Data.OWFile") |
||
248 | self.assertEqual(p2, package_name) |
||
249 | |||
250 | p3 = package("Orange.OrangeWidgets.Data") |
||
251 | self.assertEqual(p3, package_name) |
||
252 | |||
253 | p4 = package(OWFile.__name__) |
||
254 | self.assertEqual(p4, package_name) |
||
255 | |||
256 | dirname = package_dirname(package_name) |
||
0 ignored issues
–
show
dirname is re-defining a name which is already available in the outer-scope (previously defined on line 48 ).
It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior: param = 5
class Foo:
def __init__(self, param): # "param" would be flagged here
self.param = param
![]() |
|||
257 | self.assertEqual(dirname, os.path.dirname(Data.__file__)) |
||
258 | |||
259 | |||
260 | if __name__ == "__main__": |
||
261 | unittest.main() |
||
262 |
It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior: