test_array_from_pyobj.py 23 KB

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