test_array_from_pyobj.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. import os
  2. import sys
  3. import copy
  4. import platform
  5. import pytest
  6. import numpy as np
  7. from numpy.testing import assert_, assert_equal
  8. from numpy.core.multiarray import typeinfo as _typeinfo
  9. from . import util
  10. wrap = None
  11. # Extend core typeinfo with CHARACTER to test dtype('c')
  12. _ti = _typeinfo['STRING']
  13. typeinfo = dict(
  14. CHARACTER=type(_ti)(('c', _ti.num, 8, _ti.alignment, _ti.type)),
  15. **_typeinfo)
  16. def setup_module():
  17. """
  18. Build the required testing extension module
  19. """
  20. global wrap
  21. # Check compiler availability first
  22. if not util.has_c_compiler():
  23. pytest.skip("No C compiler available")
  24. if wrap is None:
  25. config_code = """
  26. config.add_extension('test_array_from_pyobj_ext',
  27. sources=['wrapmodule.c', 'fortranobject.c'],
  28. define_macros=[])
  29. """
  30. d = os.path.dirname(__file__)
  31. src = [
  32. util.getpath("tests", "src", "array_from_pyobj", "wrapmodule.c"),
  33. util.getpath("src", "fortranobject.c"),
  34. util.getpath("src", "fortranobject.h"),
  35. ]
  36. wrap = util.build_module_distutils(src, config_code,
  37. "test_array_from_pyobj_ext")
  38. def flags_info(arr):
  39. flags = wrap.array_attrs(arr)[6]
  40. return flags2names(flags)
  41. def flags2names(flags):
  42. info = []
  43. for flagname in [
  44. "CONTIGUOUS",
  45. "FORTRAN",
  46. "OWNDATA",
  47. "ENSURECOPY",
  48. "ENSUREARRAY",
  49. "ALIGNED",
  50. "NOTSWAPPED",
  51. "WRITEABLE",
  52. "WRITEBACKIFCOPY",
  53. "UPDATEIFCOPY",
  54. "BEHAVED",
  55. "BEHAVED_RO",
  56. "CARRAY",
  57. "FARRAY",
  58. ]:
  59. if abs(flags) & getattr(wrap, flagname, 0):
  60. info.append(flagname)
  61. return info
  62. class Intent:
  63. def __init__(self, intent_list=[]):
  64. self.intent_list = intent_list[:]
  65. flags = 0
  66. for i in intent_list:
  67. if i == "optional":
  68. flags |= wrap.F2PY_OPTIONAL
  69. else:
  70. flags |= getattr(wrap, "F2PY_INTENT_" + i.upper())
  71. self.flags = flags
  72. def __getattr__(self, name):
  73. name = name.lower()
  74. if name == "in_":
  75. name = "in"
  76. return self.__class__(self.intent_list + [name])
  77. def __str__(self):
  78. return "intent(%s)" % (",".join(self.intent_list))
  79. def __repr__(self):
  80. return "Intent(%r)" % (self.intent_list)
  81. def is_intent(self, *names):
  82. for name in names:
  83. if name not in self.intent_list:
  84. return False
  85. return True
  86. def is_intent_exact(self, *names):
  87. return len(self.intent_list) == len(names) and self.is_intent(*names)
  88. intent = Intent()
  89. _type_names = [
  90. "BOOL",
  91. "BYTE",
  92. "UBYTE",
  93. "SHORT",
  94. "USHORT",
  95. "INT",
  96. "UINT",
  97. "LONG",
  98. "ULONG",
  99. "LONGLONG",
  100. "ULONGLONG",
  101. "FLOAT",
  102. "DOUBLE",
  103. "CFLOAT",
  104. "STRING1",
  105. "STRING5",
  106. "CHARACTER",
  107. ]
  108. _cast_dict = {"BOOL": ["BOOL"]}
  109. _cast_dict["BYTE"] = _cast_dict["BOOL"] + ["BYTE"]
  110. _cast_dict["UBYTE"] = _cast_dict["BOOL"] + ["UBYTE"]
  111. _cast_dict["BYTE"] = ["BYTE"]
  112. _cast_dict["UBYTE"] = ["UBYTE"]
  113. _cast_dict["SHORT"] = _cast_dict["BYTE"] + ["UBYTE", "SHORT"]
  114. _cast_dict["USHORT"] = _cast_dict["UBYTE"] + ["BYTE", "USHORT"]
  115. _cast_dict["INT"] = _cast_dict["SHORT"] + ["USHORT", "INT"]
  116. _cast_dict["UINT"] = _cast_dict["USHORT"] + ["SHORT", "UINT"]
  117. _cast_dict["LONG"] = _cast_dict["INT"] + ["LONG"]
  118. _cast_dict["ULONG"] = _cast_dict["UINT"] + ["ULONG"]
  119. _cast_dict["LONGLONG"] = _cast_dict["LONG"] + ["LONGLONG"]
  120. _cast_dict["ULONGLONG"] = _cast_dict["ULONG"] + ["ULONGLONG"]
  121. _cast_dict["FLOAT"] = _cast_dict["SHORT"] + ["USHORT", "FLOAT"]
  122. _cast_dict["DOUBLE"] = _cast_dict["INT"] + ["UINT", "FLOAT", "DOUBLE"]
  123. _cast_dict["CFLOAT"] = _cast_dict["FLOAT"] + ["CFLOAT"]
  124. _cast_dict['STRING1'] = ['STRING1']
  125. _cast_dict['STRING5'] = ['STRING5']
  126. _cast_dict['CHARACTER'] = ['CHARACTER']
  127. # 32 bit system malloc typically does not provide the alignment required by
  128. # 16 byte long double types this means the inout intent cannot be satisfied
  129. # and several tests fail as the alignment flag can be randomly true or fals
  130. # when numpy gains an aligned allocator the tests could be enabled again
  131. #
  132. # Furthermore, on macOS ARM64, LONGDOUBLE is an alias for DOUBLE.
  133. if ((np.intp().dtype.itemsize != 4 or np.clongdouble().dtype.alignment <= 8)
  134. and sys.platform != "win32"
  135. and (platform.system(), platform.processor()) != ("Darwin", "arm")):
  136. _type_names.extend(["LONGDOUBLE", "CDOUBLE", "CLONGDOUBLE"])
  137. _cast_dict["LONGDOUBLE"] = _cast_dict["LONG"] + [
  138. "ULONG",
  139. "FLOAT",
  140. "DOUBLE",
  141. "LONGDOUBLE",
  142. ]
  143. _cast_dict["CLONGDOUBLE"] = _cast_dict["LONGDOUBLE"] + [
  144. "CFLOAT",
  145. "CDOUBLE",
  146. "CLONGDOUBLE",
  147. ]
  148. _cast_dict["CDOUBLE"] = _cast_dict["DOUBLE"] + ["CFLOAT", "CDOUBLE"]
  149. class Type:
  150. _type_cache = {}
  151. def __new__(cls, name):
  152. if isinstance(name, np.dtype):
  153. dtype0 = name
  154. name = None
  155. for n, i in typeinfo.items():
  156. if not isinstance(i, type) and dtype0.type is i.type:
  157. name = n
  158. break
  159. obj = cls._type_cache.get(name.upper(), None)
  160. if obj is not None:
  161. return obj
  162. obj = object.__new__(cls)
  163. obj._init(name)
  164. cls._type_cache[name.upper()] = obj
  165. return obj
  166. def _init(self, name):
  167. self.NAME = name.upper()
  168. if self.NAME == 'CHARACTER':
  169. info = typeinfo[self.NAME]
  170. self.type_num = getattr(wrap, 'NPY_STRING')
  171. self.elsize = 1
  172. self.dtype = np.dtype('c')
  173. elif self.NAME.startswith('STRING'):
  174. info = typeinfo[self.NAME[:6]]
  175. self.type_num = getattr(wrap, 'NPY_STRING')
  176. self.elsize = int(self.NAME[6:] or 0)
  177. self.dtype = np.dtype(f'S{self.elsize}')
  178. else:
  179. info = typeinfo[self.NAME]
  180. self.type_num = getattr(wrap, 'NPY_' + self.NAME)
  181. self.elsize = info.bits // 8
  182. self.dtype = np.dtype(info.type)
  183. assert self.type_num == info.num
  184. self.type = info.type
  185. self.dtypechar = info.char
  186. def __repr__(self):
  187. return (f"Type({self.NAME})|type_num={self.type_num},"
  188. f" dtype={self.dtype},"
  189. f" type={self.type}, elsize={self.elsize},"
  190. f" dtypechar={self.dtypechar}")
  191. def cast_types(self):
  192. return [self.__class__(_m) for _m in _cast_dict[self.NAME]]
  193. def all_types(self):
  194. return [self.__class__(_m) for _m in _type_names]
  195. def smaller_types(self):
  196. bits = typeinfo[self.NAME].alignment
  197. types = []
  198. for name in _type_names:
  199. if typeinfo[name].alignment < bits:
  200. types.append(Type(name))
  201. return types
  202. def equal_types(self):
  203. bits = typeinfo[self.NAME].alignment
  204. types = []
  205. for name in _type_names:
  206. if name == self.NAME:
  207. continue
  208. if typeinfo[name].alignment == bits:
  209. types.append(Type(name))
  210. return types
  211. def larger_types(self):
  212. bits = typeinfo[self.NAME].alignment
  213. types = []
  214. for name in _type_names:
  215. if typeinfo[name].alignment > bits:
  216. types.append(Type(name))
  217. return types
  218. class Array:
  219. def __repr__(self):
  220. return (f'Array({self.type}, {self.dims}, {self.intent},'
  221. f' {self.obj})|arr={self.arr}')
  222. def __init__(self, typ, dims, intent, obj):
  223. self.type = typ
  224. self.dims = dims
  225. self.intent = intent
  226. self.obj_copy = copy.deepcopy(obj)
  227. self.obj = obj
  228. # arr.dtypechar may be different from typ.dtypechar
  229. self.arr = wrap.call(typ.type_num,
  230. typ.elsize,
  231. dims, intent.flags, obj)
  232. assert isinstance(self.arr, np.ndarray)
  233. self.arr_attr = wrap.array_attrs(self.arr)
  234. if len(dims) > 1:
  235. if self.intent.is_intent("c"):
  236. assert (intent.flags & wrap.F2PY_INTENT_C)
  237. assert not self.arr.flags["FORTRAN"]
  238. assert self.arr.flags["CONTIGUOUS"]
  239. assert (not self.arr_attr[6] & wrap.FORTRAN)
  240. else:
  241. assert (not intent.flags & wrap.F2PY_INTENT_C)
  242. assert self.arr.flags["FORTRAN"]
  243. assert not self.arr.flags["CONTIGUOUS"]
  244. assert (self.arr_attr[6] & wrap.FORTRAN)
  245. if obj is None:
  246. self.pyarr = None
  247. self.pyarr_attr = None
  248. return
  249. if intent.is_intent("cache"):
  250. assert isinstance(obj, np.ndarray), repr(type(obj))
  251. self.pyarr = np.array(obj).reshape(*dims).copy()
  252. else:
  253. self.pyarr = np.array(
  254. np.array(obj, dtype=typ.dtypechar).reshape(*dims),
  255. order=self.intent.is_intent("c") and "C" or "F",
  256. )
  257. assert self.pyarr.dtype == typ
  258. self.pyarr.setflags(write=self.arr.flags["WRITEABLE"])
  259. assert self.pyarr.flags["OWNDATA"], (obj, intent)
  260. self.pyarr_attr = wrap.array_attrs(self.pyarr)
  261. if len(dims) > 1:
  262. if self.intent.is_intent("c"):
  263. assert not self.pyarr.flags["FORTRAN"]
  264. assert self.pyarr.flags["CONTIGUOUS"]
  265. assert (not self.pyarr_attr[6] & wrap.FORTRAN)
  266. else:
  267. assert self.pyarr.flags["FORTRAN"]
  268. assert not self.pyarr.flags["CONTIGUOUS"]
  269. assert (self.pyarr_attr[6] & wrap.FORTRAN)
  270. assert self.arr_attr[1] == self.pyarr_attr[1] # nd
  271. assert self.arr_attr[2] == self.pyarr_attr[2] # dimensions
  272. if self.arr_attr[1] <= 1:
  273. assert self.arr_attr[3] == self.pyarr_attr[3], repr((
  274. self.arr_attr[3],
  275. self.pyarr_attr[3],
  276. self.arr.tobytes(),
  277. self.pyarr.tobytes(),
  278. )) # strides
  279. assert self.arr_attr[5][-2:] == self.pyarr_attr[5][-2:], repr((
  280. self.arr_attr[5], self.pyarr_attr[5]
  281. )) # descr
  282. assert self.arr_attr[6] == self.pyarr_attr[6], repr((
  283. self.arr_attr[6],
  284. self.pyarr_attr[6],
  285. flags2names(0 * self.arr_attr[6] - self.pyarr_attr[6]),
  286. flags2names(self.arr_attr[6]),
  287. intent,
  288. )) # flags
  289. if intent.is_intent("cache"):
  290. assert self.arr_attr[5][3] >= self.type.elsize
  291. else:
  292. assert self.arr_attr[5][3] == self.type.elsize
  293. assert (self.arr_equal(self.pyarr, self.arr))
  294. if isinstance(self.obj, np.ndarray):
  295. if typ.elsize == Type(obj.dtype).elsize:
  296. if not intent.is_intent("copy") and self.arr_attr[1] <= 1:
  297. assert self.has_shared_memory()
  298. def arr_equal(self, arr1, arr2):
  299. if arr1.shape != arr2.shape:
  300. return False
  301. return (arr1 == arr2).all()
  302. def __str__(self):
  303. return str(self.arr)
  304. def has_shared_memory(self):
  305. """Check that created array shares data with input array."""
  306. if self.obj is self.arr:
  307. return True
  308. if not isinstance(self.obj, np.ndarray):
  309. return False
  310. obj_attr = wrap.array_attrs(self.obj)
  311. return obj_attr[0] == self.arr_attr[0]
  312. class TestIntent:
  313. def test_in_out(self):
  314. assert str(intent.in_.out) == "intent(in,out)"
  315. assert intent.in_.c.is_intent("c")
  316. assert not intent.in_.c.is_intent_exact("c")
  317. assert intent.in_.c.is_intent_exact("c", "in")
  318. assert intent.in_.c.is_intent_exact("in", "c")
  319. assert not intent.in_.is_intent("c")
  320. class TestSharedMemory:
  321. @pytest.fixture(autouse=True, scope="class", params=_type_names)
  322. def setup_type(self, request):
  323. request.cls.type = Type(request.param)
  324. request.cls.array = lambda self, dims, intent, obj: Array(
  325. Type(request.param), dims, intent, obj)
  326. @property
  327. def num2seq(self):
  328. if self.type.NAME.startswith('STRING'):
  329. elsize = self.type.elsize
  330. return ['1' * elsize, '2' * elsize]
  331. return [1, 2]
  332. @property
  333. def num23seq(self):
  334. if self.type.NAME.startswith('STRING'):
  335. elsize = self.type.elsize
  336. return [['1' * elsize, '2' * elsize, '3' * elsize],
  337. ['4' * elsize, '5' * elsize, '6' * elsize]]
  338. return [[1, 2, 3], [4, 5, 6]]
  339. def test_in_from_2seq(self):
  340. a = self.array([2], intent.in_, self.num2seq)
  341. assert not a.has_shared_memory()
  342. def test_in_from_2casttype(self):
  343. for t in self.type.cast_types():
  344. obj = np.array(self.num2seq, dtype=t.dtype)
  345. a = self.array([len(self.num2seq)], intent.in_, obj)
  346. if t.elsize == self.type.elsize:
  347. assert a.has_shared_memory(), repr((self.type.dtype, t.dtype))
  348. else:
  349. assert not a.has_shared_memory()
  350. @pytest.mark.parametrize("write", ["w", "ro"])
  351. @pytest.mark.parametrize("order", ["C", "F"])
  352. @pytest.mark.parametrize("inp", ["2seq", "23seq"])
  353. def test_in_nocopy(self, write, order, inp):
  354. """Test if intent(in) array can be passed without copies"""
  355. seq = getattr(self, "num" + inp)
  356. obj = np.array(seq, dtype=self.type.dtype, order=order)
  357. obj.setflags(write=(write == 'w'))
  358. a = self.array(obj.shape,
  359. ((order == 'C' and intent.in_.c) or intent.in_), obj)
  360. assert a.has_shared_memory()
  361. def test_inout_2seq(self):
  362. obj = np.array(self.num2seq, dtype=self.type.dtype)
  363. a = self.array([len(self.num2seq)], intent.inout, obj)
  364. assert a.has_shared_memory()
  365. try:
  366. a = self.array([2], intent.in_.inout, self.num2seq)
  367. except TypeError as msg:
  368. if not str(msg).startswith(
  369. "failed to initialize intent(inout|inplace|cache) array"):
  370. raise
  371. else:
  372. raise SystemError("intent(inout) should have failed on sequence")
  373. def test_f_inout_23seq(self):
  374. obj = np.array(self.num23seq, dtype=self.type.dtype, order="F")
  375. shape = (len(self.num23seq), len(self.num23seq[0]))
  376. a = self.array(shape, intent.in_.inout, obj)
  377. assert a.has_shared_memory()
  378. obj = np.array(self.num23seq, dtype=self.type.dtype, order="C")
  379. shape = (len(self.num23seq), len(self.num23seq[0]))
  380. try:
  381. a = self.array(shape, intent.in_.inout, obj)
  382. except ValueError as msg:
  383. if not str(msg).startswith(
  384. "failed to initialize intent(inout) array"):
  385. raise
  386. else:
  387. raise SystemError(
  388. "intent(inout) should have failed on improper array")
  389. def test_c_inout_23seq(self):
  390. obj = np.array(self.num23seq, dtype=self.type.dtype)
  391. shape = (len(self.num23seq), len(self.num23seq[0]))
  392. a = self.array(shape, intent.in_.c.inout, obj)
  393. assert a.has_shared_memory()
  394. def test_in_copy_from_2casttype(self):
  395. for t in self.type.cast_types():
  396. obj = np.array(self.num2seq, dtype=t.dtype)
  397. a = self.array([len(self.num2seq)], intent.in_.copy, obj)
  398. assert not a.has_shared_memory()
  399. def test_c_in_from_23seq(self):
  400. a = self.array(
  401. [len(self.num23seq), len(self.num23seq[0])], intent.in_,
  402. self.num23seq)
  403. assert not a.has_shared_memory()
  404. def test_in_from_23casttype(self):
  405. for t in self.type.cast_types():
  406. obj = np.array(self.num23seq, dtype=t.dtype)
  407. a = self.array(
  408. [len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
  409. assert not a.has_shared_memory()
  410. def test_f_in_from_23casttype(self):
  411. for t in self.type.cast_types():
  412. obj = np.array(self.num23seq, dtype=t.dtype, order="F")
  413. a = self.array(
  414. [len(self.num23seq), len(self.num23seq[0])], intent.in_, obj)
  415. if t.elsize == self.type.elsize:
  416. assert a.has_shared_memory()
  417. else:
  418. assert not a.has_shared_memory()
  419. def test_c_in_from_23casttype(self):
  420. for t in self.type.cast_types():
  421. obj = np.array(self.num23seq, dtype=t.dtype)
  422. a = self.array(
  423. [len(self.num23seq), len(self.num23seq[0])], intent.in_.c, obj)
  424. if t.elsize == self.type.elsize:
  425. assert a.has_shared_memory()
  426. else:
  427. assert not a.has_shared_memory()
  428. def test_f_copy_in_from_23casttype(self):
  429. for t in self.type.cast_types():
  430. obj = np.array(self.num23seq, dtype=t.dtype, order="F")
  431. a = self.array(
  432. [len(self.num23seq), len(self.num23seq[0])], intent.in_.copy,
  433. obj)
  434. assert not a.has_shared_memory()
  435. def test_c_copy_in_from_23casttype(self):
  436. for t in self.type.cast_types():
  437. obj = np.array(self.num23seq, dtype=t.dtype)
  438. a = self.array(
  439. [len(self.num23seq), len(self.num23seq[0])], intent.in_.c.copy,
  440. obj)
  441. assert not a.has_shared_memory()
  442. def test_in_cache_from_2casttype(self):
  443. for t in self.type.all_types():
  444. if t.elsize != self.type.elsize:
  445. continue
  446. obj = np.array(self.num2seq, dtype=t.dtype)
  447. shape = (len(self.num2seq), )
  448. a = self.array(shape, intent.in_.c.cache, obj)
  449. assert a.has_shared_memory()
  450. a = self.array(shape, intent.in_.cache, obj)
  451. assert a.has_shared_memory()
  452. obj = np.array(self.num2seq, dtype=t.dtype, order="F")
  453. a = self.array(shape, intent.in_.c.cache, obj)
  454. assert a.has_shared_memory()
  455. a = self.array(shape, intent.in_.cache, obj)
  456. assert a.has_shared_memory(), repr(t.dtype)
  457. try:
  458. a = self.array(shape, intent.in_.cache, obj[::-1])
  459. except ValueError as msg:
  460. if not str(msg).startswith(
  461. "failed to initialize intent(cache) array"):
  462. raise
  463. else:
  464. raise SystemError(
  465. "intent(cache) should have failed on multisegmented array")
  466. def test_in_cache_from_2casttype_failure(self):
  467. for t in self.type.all_types():
  468. if t.NAME == 'STRING':
  469. # string elsize is 0, so skipping the test
  470. continue
  471. if t.elsize >= self.type.elsize:
  472. continue
  473. obj = np.array(self.num2seq, dtype=t.dtype)
  474. shape = (len(self.num2seq), )
  475. try:
  476. self.array(shape, intent.in_.cache, obj) # Should succeed
  477. except ValueError as msg:
  478. if not str(msg).startswith(
  479. "failed to initialize intent(cache) array"):
  480. raise
  481. else:
  482. raise SystemError(
  483. "intent(cache) should have failed on smaller array")
  484. def test_cache_hidden(self):
  485. shape = (2, )
  486. a = self.array(shape, intent.cache.hide, None)
  487. assert a.arr.shape == shape
  488. shape = (2, 3)
  489. a = self.array(shape, intent.cache.hide, None)
  490. assert a.arr.shape == shape
  491. shape = (-1, 3)
  492. try:
  493. a = self.array(shape, intent.cache.hide, None)
  494. except ValueError as msg:
  495. if not str(msg).startswith(
  496. "failed to create intent(cache|hide)|optional array"):
  497. raise
  498. else:
  499. raise SystemError(
  500. "intent(cache) should have failed on undefined dimensions")
  501. def test_hidden(self):
  502. shape = (2, )
  503. a = self.array(shape, intent.hide, None)
  504. assert a.arr.shape == shape
  505. assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
  506. shape = (2, 3)
  507. a = self.array(shape, intent.hide, None)
  508. assert a.arr.shape == shape
  509. assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
  510. assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
  511. shape = (2, 3)
  512. a = self.array(shape, intent.c.hide, None)
  513. assert a.arr.shape == shape
  514. assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
  515. assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
  516. shape = (-1, 3)
  517. try:
  518. a = self.array(shape, intent.hide, None)
  519. except ValueError as msg:
  520. if not str(msg).startswith(
  521. "failed to create intent(cache|hide)|optional array"):
  522. raise
  523. else:
  524. raise SystemError(
  525. "intent(hide) should have failed on undefined dimensions")
  526. def test_optional_none(self):
  527. shape = (2, )
  528. a = self.array(shape, intent.optional, None)
  529. assert a.arr.shape == shape
  530. assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
  531. shape = (2, 3)
  532. a = self.array(shape, intent.optional, None)
  533. assert a.arr.shape == shape
  534. assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
  535. assert a.arr.flags["FORTRAN"] and not a.arr.flags["CONTIGUOUS"]
  536. shape = (2, 3)
  537. a = self.array(shape, intent.c.optional, None)
  538. assert a.arr.shape == shape
  539. assert a.arr_equal(a.arr, np.zeros(shape, dtype=self.type.dtype))
  540. assert not a.arr.flags["FORTRAN"] and a.arr.flags["CONTIGUOUS"]
  541. def test_optional_from_2seq(self):
  542. obj = self.num2seq
  543. shape = (len(obj), )
  544. a = self.array(shape, intent.optional, obj)
  545. assert a.arr.shape == shape
  546. assert not a.has_shared_memory()
  547. def test_optional_from_23seq(self):
  548. obj = self.num23seq
  549. shape = (len(obj), len(obj[0]))
  550. a = self.array(shape, intent.optional, obj)
  551. assert a.arr.shape == shape
  552. assert not a.has_shared_memory()
  553. a = self.array(shape, intent.optional.c, obj)
  554. assert a.arr.shape == shape
  555. assert not a.has_shared_memory()
  556. def test_inplace(self):
  557. obj = np.array(self.num23seq, dtype=self.type.dtype)
  558. assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
  559. shape = obj.shape
  560. a = self.array(shape, intent.inplace, obj)
  561. assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
  562. a.arr[1][2] = 54
  563. assert obj[1][2] == a.arr[1][2] == np.array(54, dtype=self.type.dtype)
  564. assert a.arr is obj
  565. assert obj.flags["FORTRAN"] # obj attributes are changed inplace!
  566. assert not obj.flags["CONTIGUOUS"]
  567. def test_inplace_from_casttype(self):
  568. for t in self.type.cast_types():
  569. if t is self.type:
  570. continue
  571. obj = np.array(self.num23seq, dtype=t.dtype)
  572. assert obj.dtype.type == t.type
  573. assert obj.dtype.type is not self.type.type
  574. assert not obj.flags["FORTRAN"] and obj.flags["CONTIGUOUS"]
  575. shape = obj.shape
  576. a = self.array(shape, intent.inplace, obj)
  577. assert obj[1][2] == a.arr[1][2], repr((obj, a.arr))
  578. a.arr[1][2] = 54
  579. assert obj[1][2] == a.arr[1][2] == np.array(54,
  580. dtype=self.type.dtype)
  581. assert a.arr is obj
  582. assert obj.flags["FORTRAN"] # obj attributes changed inplace!
  583. assert not obj.flags["CONTIGUOUS"]
  584. assert obj.dtype.type is self.type.type # obj changed inplace!