Skip to content

Commit 021604b

Browse files
authored
Merge pull request #3645 from janezd/pylint-owfeatureconstructor
OWFeatureConstructor: PyLint
2 parents 3589f0b + a7b07c9 commit 021604b

File tree

1 file changed

+32
-35
lines changed

1 file changed

+32
-35
lines changed

Orange/widgets/data/owfeatureconstructor.py

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
of other variables.
66
77
"""
8-
import sys
98
import re
109
import copy
1110
import functools
@@ -28,7 +27,7 @@
2827
QHBoxLayout, QVBoxLayout, QStackedWidget, QStyledItemDelegate,
2928
QPushButton, QMenu, QListView, QFrame
3029
)
31-
from AnyQt.QtGui import QIcon, QKeySequence
30+
from AnyQt.QtGui import QKeySequence
3231
from AnyQt.QtCore import Qt, pyqtSignal as Signal, pyqtProperty as Property
3332

3433
import Orange
@@ -160,7 +159,7 @@ def __init__(self, *args, **kwargs):
160159
self._modified = False
161160

162161
def setModified(self, modified):
163-
if not type(modified) is bool:
162+
if not isinstance(modified, bool):
164163
raise TypeError
165164

166165
if self._modified != modified:
@@ -280,14 +279,12 @@ def editorData(self):
280279
@functools.lru_cache(20)
281280
def variable_icon(dtype):
282281
vtype = _VarMap.get(dtype, dtype)
283-
try:
284-
return gui.attributeIconDict[vtype]
285-
except Exception:
286-
return QIcon()
282+
return gui.attributeIconDict[vtype]
287283

288284

289285
class FeatureItemDelegate(QStyledItemDelegate):
290-
def displayText(self, value, locale):
286+
@staticmethod
287+
def displayText(value, _):
291288
return value.name + " := " + value.expression
292289

293290

@@ -303,18 +300,20 @@ def data(self, index, role=Qt.DisplayRole):
303300
class FeatureConstructorHandler(DomainContextHandler):
304301
"""Context handler that filters descriptors"""
305302

306-
def is_valid_item(self, setting, descriptor, attrs, metas):
307-
"""Check if descriptor can be used with given domain.
303+
def is_valid_item(self, setting, item, attrs, metas):
304+
"""Check if descriptor `item` can be used with given domain.
308305
309306
Return True if descriptor's expression contains only
310307
available variables and descriptors name does not clash with
311308
existing variables.
312309
"""
313-
if descriptor.name in attrs or descriptor.name in metas:
310+
if item.name in attrs or item.name in metas:
314311
return False
315312

316313
try:
317-
exp_ast = ast.parse(descriptor.expression, mode="eval")
314+
exp_ast = ast.parse(item.expression, mode="eval")
315+
# ast.parse can return arbitrary errors, not only SyntaxError
316+
# pylint: disable=broad-except
318317
except Exception:
319318
return False
320319

@@ -550,9 +549,9 @@ def removeFeature(self, index):
550549
index = selected_row(self.featureview)
551550
if index is not None:
552551
self.setCurrentIndex(index)
553-
elif index is None and len(self.featuremodel) > 0:
552+
elif index is None and self.featuremodel.rowCount():
554553
# Deleting the last item clears selection
555-
self.setCurrentIndex(len(self.featuremodel) - 1)
554+
self.setCurrentIndex(self.featuremodel.rowCount() - 1)
556555

557556
def removeSelectedFeature(self):
558557
if self.currentIndex >= 0:
@@ -562,7 +561,8 @@ def duplicateFeature(self):
562561
desc = self.featuremodel[self.currentIndex]
563562
self.addFeature(copy.deepcopy(desc))
564563

565-
def check_attrs_values(self, attr, data):
564+
@staticmethod
565+
def check_attrs_values(attr, data):
566566
for i in range(len(data)):
567567
for var in attr:
568568
if not math.isnan(data[i, var]) \
@@ -575,6 +575,8 @@ def _validate_descriptors(self, desc):
575575
def validate(source):
576576
try:
577577
return validate_exp(ast.parse(source, mode="eval"))
578+
# ast.parse can return arbitrary errors, not only SyntaxError
579+
# pylint: disable=broad-except
578580
except Exception:
579581
return False
580582

@@ -613,6 +615,8 @@ def apply(self):
613615

614616
try:
615617
data = self.data.transform(new_domain)
618+
# user's expression can contain arbitrary errors
619+
# pylint: disable=broad-except
616620
except Exception as err:
617621
log = logging.getLogger(__name__)
618622
log.error("", exc_info=True)
@@ -661,6 +665,7 @@ def freevars(exp, env):
661665
ast
662666
663667
"""
668+
# pylint: disable=too-many-return-statements,too-many-branches
664669
etype = type(exp)
665670
if etype in [ast.Expr, ast.Expression]:
666671
return freevars(exp.body, env)
@@ -708,25 +713,18 @@ def freevars(exp, env):
708713
elif etype == ast.Compare:
709714
return sum((freevars(v, env)
710715
for v in [exp.left] + exp.comparators), [])
711-
elif etype == ast.Call and sys.version_info < (3, 5):
712-
return sum((freevars(e, env)
713-
for e in [exp.func] + (exp.args or []) +
714-
([k.value for k in exp.keywords or []]) +
715-
([exp.starargs] if exp.starargs else []) +
716-
([exp.kwargs] if exp.kwargs else [])),
717-
[])
718716
elif etype == ast.Call:
719717
return sum(map(lambda e: freevars(e, env),
720718
chain([exp.func],
721719
exp.args or [],
722720
[k.value for k in exp.keywords or []])),
723721
[])
724-
elif sys.version_info >= (3, 5) and etype == ast.Starred:
722+
elif etype == ast.Starred:
725723
# a 'starred' call parameter (e.g. a and b in `f(x, *a, *b)`
726724
return freevars(exp.value, env)
727725
elif etype in [ast.Num, ast.Str, ast.Ellipsis, ast.Bytes]:
728726
return []
729-
elif sys.version_info >= (3, 4) and etype == ast.NameConstant:
727+
elif etype == ast.NameConstant:
730728
return []
731729
elif etype == ast.Attribute:
732730
return freevars(exp.value, env)
@@ -765,6 +763,7 @@ def validate_exp(exp):
765763
A parsed abstract syntax tree
766764
767765
"""
766+
# pylint: disable=too-many-branches
768767
if not isinstance(exp, ast.AST):
769768
raise TypeError("exp is not a 'ast.AST' instance")
770769

@@ -788,16 +787,13 @@ def validate_exp(exp):
788787
elif etype == ast.Call:
789788
subexp = chain([exp.func], exp.args or [],
790789
[k.value for k in exp.keywords or []])
791-
if sys.version_info < (3, 5):
792-
extra = [exp.starargs, exp.kwargs]
793-
subexp = chain(subexp, *filter(None, extra))
794790
return all(map(validate_exp, subexp))
795-
elif sys.version_info >= (3, 5) and etype == ast.Starred:
791+
elif etype == ast.Starred:
796792
assert isinstance(exp.ctx, ast.Load)
797793
return validate_exp(exp.value)
798794
elif etype in [ast.Num, ast.Str, ast.Bytes, ast.Ellipsis]:
799795
return True
800-
elif sys.version_info >= (3, 4) and etype == ast.NameConstant:
796+
elif etype == ast.NameConstant:
801797
return True
802798
elif etype == ast.Attribute:
803799
return True
@@ -859,7 +855,7 @@ def bind_variable(descriptor, env):
859855
return descriptor, FeatureFunc(descriptor.expression, source_vars, values)
860856

861857

862-
def make_lambda(expression, args, env={}):
858+
def make_lambda(expression, args, env=None):
863859
# type: (ast.Expression, List[str], Dict[str, Any]) -> types.FunctionType
864860
"""
865861
Create an lambda function from a expression AST.
@@ -870,7 +866,7 @@ def make_lambda(expression, args, env={}):
870866
The body of the lambda.
871867
args : List[str]
872868
A list of positional argument names
873-
env : Dict[str, Any]
869+
env : Optional[Dict[str, Any]]
874870
Extra environment to capture in the lambda's closure.
875871
876872
Returns
@@ -894,7 +890,7 @@ def make_lambda(expression, args, env={}):
894890
# lambda **{env}** : lambda *{args}*: EXPRESSION
895891
outer = ast.Lambda(
896892
args=ast.arguments(
897-
args=[ast.arg(arg=name, annotation=None) for name in env],
893+
args=[ast.arg(arg=name, annotation=None) for name in (env or {})],
898894
varargs=None,
899895
varargannotation=None,
900896
kwonlyargs=[],
@@ -909,6 +905,7 @@ def make_lambda(expression, args, env={}):
909905
ast.fix_missing_locations(exp)
910906
GLOBALS = __GLOBALS.copy()
911907
GLOBALS["__builtins__"] = {}
908+
# pylint: disable=eval-used
912909
fouter = eval(compile(exp, "<lambda>", "eval"), GLOBALS)
913910
assert isinstance(fouter, types.FunctionType)
914911
finner = fouter(**env)
@@ -980,14 +977,14 @@ class FeatureFunc:
980977
a variable as used in `expression`, and `variable` is the variable
981978
instance used to extract the corresponding column/value from a
982979
Table/Instance.
983-
extra_env : Dict[str, Any]
980+
extra_env : Optional[Dict[str, Any]]
984981
Extra environment specifying constant values to be made available
985982
in expression. It must not shadow names in `args`
986983
"""
987-
def __init__(self, expression, args, extra_env={}):
984+
def __init__(self, expression, args, extra_env=None):
988985
self.expression = expression
989986
self.args = args
990-
self.extra_env = dict(extra_env)
987+
self.extra_env = dict(extra_env or {})
991988
self.func = make_lambda(ast.parse(expression, mode="eval"),
992989
[name for name, _ in args], self.extra_env)
993990

0 commit comments

Comments
 (0)