Skip to content

Commit 5615001

Browse files
committed
Don't touch properties for real.
Old code to avoid properties was totally broken. Also validate that libs are modules or new style class instances.
1 parent 247afcf commit 5615001

File tree

3 files changed

+43
-5
lines changed

3 files changed

+43
-5
lines changed

atest/librarycomponents.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ def not_keyword(self):
2626
def keyword_in_main(self):
2727
raise AssertionError('Should be overridden by the main library!')
2828

29+
@property
30+
def dont_touch_property(self):
31+
raise RuntimeError('Should not touch property!!')
32+
2933

3034
class Arguments(object):
3135

src/robotlibcore.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,23 @@ def _find_keywords(self, *libraries):
3131
yield kw_name, getattr(library, name)
3232

3333
def _get_members(self, library):
34-
# Avoid calling properties by getting members from class, not instance.
34+
if inspect.ismodule(library):
35+
return inspect.getmembers(library)
3536
if inspect.isclass(library):
36-
library = type(library)
37-
return inspect.getmembers(library)
37+
raise TypeError('Libraries must be modules or instances, got '
38+
'class {!r} instead.'.format(library.__name__))
39+
if type(library) != library.__class__:
40+
raise TypeError('Libraries must be modules or new-style class '
41+
'instances, got old-style class {!r} instead.'
42+
.format(library.__class__.__name__))
43+
return self._get_members_from_instannce(library)
44+
45+
def _get_members_from_instannce(self, instance):
46+
# Avoid calling properties by getting members from class, not instance.
47+
cls = type(instance)
48+
for name in dir(instance):
49+
owner = cls if hasattr(cls, name) else instance
50+
yield name, getattr(owner, name)
3851

3952
def __getattr__(self, name):
4053
if name in self.keywords:

utest/test_robotlibcore.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
import sys
2+
13
import pytest
24

5+
from robotlibcore import HybridCore
6+
37
from HybridLibrary import HybridLibrary
48
from DynamicLibrary import DynamicLibrary
59

@@ -60,9 +64,9 @@ def test_getattr():
6064
assert lib.function() == 1
6165
assert lib.method() == 2
6266
assert getattr(lib, 'Custom name')() == 3
63-
with pytest.raises(AttributeError) as excinfo:
67+
with pytest.raises(AttributeError) as exc_info:
6468
lib.attribute
65-
assert str(excinfo.value) == \
69+
assert str(exc_info.value) == \
6670
"'%s' object has no attribute 'attribute'" % type(lib).__name__
6771

6872

@@ -99,3 +103,20 @@ def test_get_keyword_tags():
99103
assert tags('doc_and_tags') == ['tag']
100104
assert doc('tags') == ''
101105
assert doc('doc_and_tags') == 'I got doc!'
106+
107+
108+
def test_library_cannot_be_class():
109+
with pytest.raises(TypeError) as exc_info:
110+
HybridCore([HybridLibrary])
111+
assert str(exc_info.value) == \
112+
"Libraries must be modules or instances, got class 'HybridLibrary' instead."
113+
114+
115+
@pytest.mark.skipif(sys.version_info[0] > 2, reason='Only applicable on Py 2')
116+
def test_library_cannot_be_old_style_class_instance():
117+
class OldStyle:
118+
pass
119+
with pytest.raises(TypeError) as exc_info:
120+
HybridCore([OldStyle()])
121+
assert str(exc_info.value) == \
122+
"Libraries must be modules or new-style class instances, got old-style class 'OldStyle' instead."

0 commit comments

Comments
 (0)