2015-08-30 12:32:26 +01:00
|
|
|
# tests for things that are not implemented, or have non-compliant behaviour
|
|
|
|
|
2017-03-11 00:16:26 +00:00
|
|
|
try:
|
2019-10-22 07:33:23 +01:00
|
|
|
import uarray as array
|
2017-03-11 00:16:26 +00:00
|
|
|
import ustruct
|
|
|
|
except ImportError:
|
|
|
|
print("SKIP")
|
2017-06-10 18:14:16 +01:00
|
|
|
raise SystemExit
|
2015-08-30 12:32:26 +01:00
|
|
|
|
2016-10-11 02:30:32 +01:00
|
|
|
# when super can't find self
|
|
|
|
try:
|
|
|
|
exec('def f(): super()')
|
|
|
|
except SyntaxError:
|
|
|
|
print('SyntaxError')
|
|
|
|
|
2016-10-17 01:43:47 +01:00
|
|
|
# store to exception attribute is not allowed
|
|
|
|
try:
|
|
|
|
ValueError().x = 0
|
|
|
|
except AttributeError:
|
|
|
|
print('AttributeError')
|
|
|
|
|
2015-08-30 12:32:26 +01:00
|
|
|
# array deletion not implemented
|
|
|
|
try:
|
|
|
|
a = array.array('b', (1, 2, 3))
|
|
|
|
del a[1]
|
|
|
|
except TypeError:
|
|
|
|
print('TypeError')
|
|
|
|
|
|
|
|
# slice with step!=1 not implemented
|
|
|
|
try:
|
|
|
|
a = array.array('b', (1, 2, 3))
|
|
|
|
print(a[3:2:2])
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
2016-10-17 01:43:47 +01:00
|
|
|
# containment, looking for integer not implemented
|
|
|
|
try:
|
|
|
|
print(1 in array.array('B', b'12'))
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
2015-08-30 12:32:26 +01:00
|
|
|
# uPy raises TypeError, shold be ValueError
|
|
|
|
try:
|
|
|
|
'%c' % b'\x01\x02'
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
print('TypeError, ValueError')
|
|
|
|
|
|
|
|
# attributes/subscr not implemented
|
|
|
|
try:
|
|
|
|
print('{a[0]}'.format(a=[1, 2]))
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
2015-09-01 15:35:31 +01:00
|
|
|
|
2015-09-03 23:06:18 +01:00
|
|
|
# str(...) with keywords not implemented
|
|
|
|
try:
|
|
|
|
str(b'abc', encoding='utf8')
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
2015-09-01 15:35:31 +01:00
|
|
|
# str.rsplit(None, n) not implemented
|
|
|
|
try:
|
|
|
|
'a a a'.rsplit(None, 1)
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
2015-09-03 23:06:18 +01:00
|
|
|
|
2015-09-04 16:49:56 +01:00
|
|
|
# str.endswith(s, start) not implemented
|
|
|
|
try:
|
|
|
|
'abc'.endswith('c', 1)
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
2016-10-17 01:43:47 +01:00
|
|
|
# str subscr with step!=1 not implemented
|
|
|
|
try:
|
|
|
|
print('abc'[1:2:3])
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
2015-09-03 23:06:18 +01:00
|
|
|
# bytes(...) with keywords not implemented
|
|
|
|
try:
|
|
|
|
bytes('abc', encoding='utf8')
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
|
|
|
# bytes subscr with step!=1 not implemented
|
|
|
|
try:
|
|
|
|
b'123'[0:3:2]
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
2015-10-01 17:57:36 +01:00
|
|
|
|
2016-08-15 01:46:46 +01:00
|
|
|
# tuple load with step!=1 not implemented
|
|
|
|
try:
|
|
|
|
()[2:3:4]
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
|
|
|
# list store with step!=1 not implemented
|
|
|
|
try:
|
|
|
|
[][2:3:4] = []
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
|
|
|
|
|
|
|
# list delete with step!=1 not implemented
|
|
|
|
try:
|
|
|
|
del [][2:3:4]
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
2016-10-07 02:57:25 +01:00
|
|
|
|
|
|
|
# struct pack with too many args, not checked by uPy
|
|
|
|
print(ustruct.pack('bb', 1, 2, 3))
|
|
|
|
|
|
|
|
# struct pack with too few args, not checked by uPy
|
|
|
|
print(ustruct.pack('bb', 1))
|
2016-12-21 06:51:42 +00:00
|
|
|
|
|
|
|
# array slice assignment with unsupported RHS
|
|
|
|
try:
|
|
|
|
bytearray(4)[0:1] = [1, 2]
|
|
|
|
except NotImplementedError:
|
|
|
|
print('NotImplementedError')
|
2017-01-19 12:38:53 +00:00
|
|
|
|
|
|
|
# can't assign attributes to a function
|
|
|
|
def f():
|
|
|
|
pass
|
|
|
|
try:
|
|
|
|
f.x = 1
|
|
|
|
except AttributeError:
|
|
|
|
print('AttributeError')
|
2017-12-14 01:25:30 +00:00
|
|
|
|
|
|
|
# can't call a function type (ie make new instances of a function)
|
|
|
|
try:
|
|
|
|
type(f)()
|
|
|
|
except TypeError:
|
|
|
|
print('TypeError')
|
|
|
|
|
|
|
|
# test when object explicitly listed at not-last position in parent tuple
|
|
|
|
# this is not compliant with CPython because of illegal MRO
|
|
|
|
class A:
|
|
|
|
def foo(self):
|
|
|
|
print('A.foo')
|
|
|
|
class B(object, A):
|
|
|
|
pass
|
|
|
|
B().foo()
|
py/objtype: Optimise instance get/set/del by skipping special accessors.
This patch is a code optimisation, trading text bytes for speed. On
pyboard it's an increase of 0.06% in code size for a gain (in pystone
performance) of roughly 6.5%.
The patch optimises load/store/delete of attributes in user defined classes
by not looking up special accessors (@property, __get__, __delete__,
__set__, __setattr__ and __getattr_) if they are guaranteed not to exist in
the class.
Currently, if you do my_obj.foo() then the runtime has to do a few checks
to see if foo is a property or has __get__, and if so delegate the call.
And for stores things like my_obj.foo = 1 has to first check if foo is a
property or has __set__ defined on it.
Doing all those checks each and every time the attribute is accessed has a
performance penalty. This patch eliminates all those checks for cases when
it's guaranteed that the checks will always fail, ie no attributes are
properties nor have any special accessor methods defined on them.
To make this guarantee it checks all attributes of a user-defined class
when it is first created. If any of the attributes of the user class are
properties or have special accessors, or any of the base classes of the
user class have them, then it sets a flag in the class to indicate that
special accessors must be checked for. Then in the load/store/delete code
it checks this flag to see if it can take the shortcut and optimise the
lookup.
It's an optimisation that's pretty widely applicable because it improves
lookup performance for all methods of user defined classes, and stores of
attributes, at least for those that don't have special accessors. And, it
allows to enable descriptors with minimal additional runtime overhead if
they are not used for a particular user class.
There is one restriction on dynamic class creation that has been introduced
by this patch: a user-defined class cannot go from zero special accessors
to one special accessor (or more) after that class has been subclassed. If
the script attempts this an AttributeError is raised (see addition to
tests/misc/non_compliant.py for an example of this case).
The cost in code space bytes for the optimisation in this patch is:
unix x64: +528
unix nanbox: +508
stm32: +192
cc3200: +200
esp8266: +332
esp32: +244
Performance tests that were done:
- on unix x86-64, pystone improved by about 5%
- on pyboard, pystone improved by about 6.5%, from 1683 up to 1794
- on pyboard, bm_chaos (from CPython benchmark suite) improved by about 5%
- on esp32, pystone improved by about 30% (but there are caching effects)
- on esp32, bm_chaos improved by about 11%
2018-05-25 08:09:54 +01:00
|
|
|
|
|
|
|
# can't assign property (or other special accessors) to already-subclassed class
|
|
|
|
class A:
|
|
|
|
pass
|
|
|
|
class B(A):
|
|
|
|
pass
|
|
|
|
try:
|
|
|
|
A.bar = property()
|
|
|
|
except AttributeError:
|
|
|
|
print('AttributeError')
|