We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
2 parents 8975c02 + 0cca105 commit 5b60248Copy full SHA for 5b60248
Orange/canvas/application/errorreporting.py
@@ -157,14 +157,17 @@ def handle_exception(cls, exc):
157
stacktrace = ''.join(traceback.format_exception(etype, evalue, tb))
158
159
def _find_last_frame(tb):
160
+ if not tb:
161
+ return None
162
while tb.tb_next:
163
tb = tb.tb_next
164
return tb
165
- frame = _find_last_frame(tb)
- err_module = '{}:{}'.format(
166
- frame.tb_frame.f_globals.get('__name__', frame.tb_frame.f_code.co_filename),
167
- frame.tb_lineno)
+ err_module, frame = None, _find_last_frame(tb)
+ if frame:
168
+ err_module = '{}:{}'.format(
169
+ frame.tb_frame.f_globals.get('__name__', frame.tb_frame.f_code.co_filename),
170
+ frame.tb_lineno)
171
172
def _find_widget_frame(tb):
173
while tb:
Orange/data/variable.py
@@ -919,13 +919,21 @@ def _tzre_sub(s, _subtz=re.compile(r'([+-])(\d\d):(\d\d)$').sub):
919
def repr_val(self, val):
920
if isnan(val):
921
return '?'
922
+ if not self.have_date and not self.have_time:
923
+ # The time is relative, unitless. The value is absolute.
924
+ return str(val)
925
+
926
+ # If you know how to simplify this, be my guest
927
seconds = int(val)
928
microseconds = int(round((val - seconds) * 1e6))
929
if val < 0:
930
+ if microseconds:
931
+ seconds, microseconds = seconds - 1, int(1e6) + microseconds
932
date = datetime.fromtimestamp(0, tz=self.timezone) + timedelta(seconds=seconds)
933
else:
934
date = datetime.fromtimestamp(seconds, tz=self.timezone)
935
date = str(date.replace(microsecond=microseconds))
936
937
if self.have_date and not self.have_time:
938
date = date.split()[0]
939
elif not self.have_date and self.have_time:
@@ -956,7 +964,9 @@ def parse(self, datestr):
956
964
if not self._matches_iso_format(datestr):
957
965
try:
958
966
# If it is a number, assume it is a unix timestamp
959
- return float(datestr)
967
+ value = float(datestr)
968
+ self.have_date = self.have_time = 1
969
+ return value
960
970
except ValueError:
961
971
raise ERROR
962
972
Orange/tests/test_util.py
@@ -2,7 +2,7 @@
2
3
import numpy as np
4
5
-from Orange.util import export_globals, flatten, deprecated, try_
+from Orange.util import export_globals, flatten, deprecated, try_, deepgetattr
6
7
8
SOMETHING = 0xf00babe
@@ -30,3 +30,10 @@ def test_try_(self):
30
self.assertTrue(try_(lambda: np.ones(3).any()))
31
self.assertFalse(try_(lambda: np.whatever()))
32
self.assertEqual(try_(len, default=SOMETHING), SOMETHING)
33
34
+ def test_deepgetattr(self):
35
+ class a:
36
+ l = []
37
+ self.assertTrue(deepgetattr(a, 'l.__len__.__call__'), a.l.__len__.__call__)
38
+ self.assertTrue(deepgetattr(a, 'l.__nx__.__x__', 42), 42)
39
+ self.assertRaises(AttributeError, lambda: deepgetattr(a, 'l.__nx__.__x__'))
Orange/tests/test_variable.py
@@ -313,10 +313,10 @@ class TestTimeVariable(VariableTest):
313
('01:01', 3660, '01:01:00'),
314
('1970-01-01 00:00:00', 0, '1970-01-01 00:00:00'),
315
('1969-12-31 23:59:59', -1, '1969-12-31 23:59:59'),
316
+ ('1969-12-31 23:59:58.9', -1.1, '1969-12-31 23:59:58.900000'),
317
('1900-01-01', -2208988800, '1900-01-01'),
318
('nan', np.nan, '?'),
319
('1444651991.81', 1444651991.81, '2015-10-12 12:13:11.810000'),
- (1444651991.81, 1444651991.81, '2015-10-12 12:13:11.810000'),
320
]
321
322
def test_parse_repr(self):
@@ -356,6 +356,9 @@ def test_have_date(self):
356
# observe have datetime
357
self.assertEqual(var.repr_val(ts), '1970-01-01 16:20:00')
358
359
+ def test_no_date_no_time(self):
360
+ self.assertEqual(TimeVariable('relative time').repr_val(1.6), '1.6')
361
362
def test_readwrite_timevariable(self):
363
output_csv = StringIO()
364
input_csv = StringIO("""\
Orange/util.py
@@ -2,6 +2,7 @@
from functools import wraps
from inspect import isfunction
+from operator import attrgetter
from itertools import chain, count
from collections import OrderedDict
import warnings
@@ -129,6 +130,21 @@ def export_globals(globals, module_name):
129
130
not getattr(v, '__name__', k).startswith('_'))] # neither marked internal
131
132
133
+_NOTSET = object()
134
135
136
+def deepgetattr(obj, attr, default=_NOTSET):
137
+ """Works exactly like getattr(), except that attr can be a nested attribute
138
+ (e.g. "attr1.attr2.attr3").
139
+ """
140
+ try:
141
+ return attrgetter(attr)(obj)
142
+ except AttributeError:
143
+ if default is _NOTSET:
144
+ raise
145
+ return default
146
147
148
def color_to_hex(color):
149
return "#{:02X}{:02X}{:02X}".format(*color)
150
Orange/widgets/utils/__init__.py
@@ -1,5 +1,5 @@
1
-from functools import reduce
from Orange.data.variable import TimeVariable
+from Orange.util import deepgetattr
def vartype(var):
@@ -22,14 +22,7 @@ def progress_bar_milestones(count, iterations=100):
22
def getdeepattr(obj, attr, *arg, **kwarg):
23
if isinstance(obj, dict):
24
return obj.get(attr)
25
- try:
26
- return reduce(getattr, attr.split("."), obj)
27
- except AttributeError:
28
- if arg:
29
- return arg[0]
- if kwarg:
- return kwarg["default"]
- raise
+ return deepgetattr(obj, attr, *arg, **kwarg)
def to_html(str):
0 commit comments