hugobuddel /
orange3
| 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
Loading history...
|
|||
| 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
Loading history...
|
|||
| 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;
Loading history...
|
|||
| 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;
Loading history...
|
|||
| 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;
Loading history...
|
|||
| 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;
Loading history...
|
|||
| 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 Loading history...
|
|||
| 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 Loading history...
|
|||
| 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 Loading history...
|
|||
| 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 Loading history...
|
|||
| 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
Loading history...
|
|||
| 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: