test_duration.py 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2021, Brandon Nielsen
  3. # All rights reserved.
  4. #
  5. # This software may be modified and distributed under the terms
  6. # of the BSD license. See the LICENSE file for details.
  7. import unittest
  8. import aniso8601
  9. from aniso8601.duration import (
  10. _has_any_component,
  11. _parse_duration_combined,
  12. _parse_duration_prescribed,
  13. _parse_duration_prescribed_notime,
  14. _parse_duration_prescribed_time,
  15. get_duration_resolution,
  16. parse_duration,
  17. )
  18. from aniso8601.exceptions import ISOFormatError
  19. from aniso8601.resolution import DurationResolution
  20. from aniso8601.tests.compat import mock
  21. class TestDurationParserFunctions(unittest.TestCase):
  22. def test_get_duration_resolution_years(self):
  23. self.assertEqual(get_duration_resolution("P1Y"), DurationResolution.Years)
  24. self.assertEqual(get_duration_resolution("P1,5Y"), DurationResolution.Years)
  25. self.assertEqual(get_duration_resolution("P1.5Y"), DurationResolution.Years)
  26. def test_get_duration_resolution_months(self):
  27. self.assertEqual(get_duration_resolution("P1Y2M"), DurationResolution.Months)
  28. self.assertEqual(get_duration_resolution("P1M"), DurationResolution.Months)
  29. self.assertEqual(get_duration_resolution("P1,5M"), DurationResolution.Months)
  30. self.assertEqual(get_duration_resolution("P1.5M"), DurationResolution.Months)
  31. def test_get_duration_resolution_weeks(self):
  32. self.assertEqual(get_duration_resolution("P1W"), DurationResolution.Weeks)
  33. self.assertEqual(get_duration_resolution("P1,5W"), DurationResolution.Weeks)
  34. self.assertEqual(get_duration_resolution("P1.5W"), DurationResolution.Weeks)
  35. def test_get_duration_resolution_days(self):
  36. self.assertEqual(get_duration_resolution("P1Y2M3D"), DurationResolution.Days)
  37. self.assertEqual(get_duration_resolution("P1Y2M3,5D"), DurationResolution.Days)
  38. self.assertEqual(get_duration_resolution("P1Y2M3.5D"), DurationResolution.Days)
  39. self.assertEqual(get_duration_resolution("P1D"), DurationResolution.Days)
  40. self.assertEqual(get_duration_resolution("P1,5D"), DurationResolution.Days)
  41. self.assertEqual(get_duration_resolution("P1.5D"), DurationResolution.Days)
  42. def test_get_duration_resolution_hours(self):
  43. self.assertEqual(
  44. get_duration_resolution("P1Y2M3DT4H"), DurationResolution.Hours
  45. )
  46. self.assertEqual(get_duration_resolution("PT4H"), DurationResolution.Hours)
  47. def test_get_duration_resolution_minutes(self):
  48. self.assertEqual(
  49. get_duration_resolution("P1Y2M3DT4H5M"), DurationResolution.Minutes
  50. )
  51. self.assertEqual(get_duration_resolution("PT4H5M"), DurationResolution.Minutes)
  52. def test_get_duration_resolution_seconds(self):
  53. self.assertEqual(
  54. get_duration_resolution("P1Y2M3DT4H54M6S"), DurationResolution.Seconds
  55. )
  56. self.assertEqual(
  57. get_duration_resolution("P1Y2M3DT4H54M6,5S"), DurationResolution.Seconds
  58. )
  59. self.assertEqual(
  60. get_duration_resolution("P1Y2M3DT4H54M6.5S"), DurationResolution.Seconds
  61. )
  62. self.assertEqual(
  63. get_duration_resolution("PT4H54M6,5S"), DurationResolution.Seconds
  64. )
  65. self.assertEqual(
  66. get_duration_resolution("PT4H54M6.5S"), DurationResolution.Seconds
  67. )
  68. self.assertEqual(
  69. get_duration_resolution("PT0.0000001S"), DurationResolution.Seconds
  70. )
  71. self.assertEqual(
  72. get_duration_resolution("PT2.0000048S"), DurationResolution.Seconds
  73. )
  74. self.assertEqual(
  75. get_duration_resolution("P0003-06-04T12:30:05"), DurationResolution.Seconds
  76. )
  77. self.assertEqual(
  78. get_duration_resolution("P0003-06-04T12:30:05.5"),
  79. DurationResolution.Seconds,
  80. )
  81. self.assertEqual(
  82. get_duration_resolution("P0001-02-03T14:43:59.9999997"),
  83. DurationResolution.Seconds,
  84. )
  85. def test_parse_duration(self):
  86. testtuples = (
  87. (
  88. "P1Y2M3DT4H54M6S",
  89. {
  90. "PnY": "1",
  91. "PnM": "2",
  92. "PnW": None,
  93. "PnD": "3",
  94. "TnH": "4",
  95. "TnM": "54",
  96. "TnS": "6",
  97. },
  98. ),
  99. (
  100. "P1Y2M3DT4H54M6,5S",
  101. {
  102. "PnY": "1",
  103. "PnM": "2",
  104. "PnW": None,
  105. "PnD": "3",
  106. "TnH": "4",
  107. "TnM": "54",
  108. "TnS": "6.5",
  109. },
  110. ),
  111. (
  112. "P1Y2M3DT4H54M6.5S",
  113. {
  114. "PnY": "1",
  115. "PnM": "2",
  116. "PnW": None,
  117. "PnD": "3",
  118. "TnH": "4",
  119. "TnM": "54",
  120. "TnS": "6.5",
  121. },
  122. ),
  123. (
  124. "P1YT4H",
  125. {
  126. "PnY": "1",
  127. "PnM": None,
  128. "PnW": None,
  129. "PnD": None,
  130. "TnH": "4",
  131. "TnM": None,
  132. "TnS": None,
  133. },
  134. ),
  135. (
  136. "P1YT54M",
  137. {
  138. "PnY": "1",
  139. "PnM": None,
  140. "PnW": None,
  141. "PnD": None,
  142. "TnH": None,
  143. "TnM": "54",
  144. "TnS": None,
  145. },
  146. ),
  147. (
  148. "P1YT6S",
  149. {
  150. "PnY": "1",
  151. "PnM": None,
  152. "PnW": None,
  153. "PnD": None,
  154. "TnH": None,
  155. "TnM": None,
  156. "TnS": "6",
  157. },
  158. ),
  159. (
  160. "P1YT4H54M",
  161. {
  162. "PnY": "1",
  163. "PnM": None,
  164. "PnW": None,
  165. "PnD": None,
  166. "TnH": "4",
  167. "TnM": "54",
  168. "TnS": None,
  169. },
  170. ),
  171. (
  172. "P1YT4H6S",
  173. {
  174. "PnY": "1",
  175. "PnM": None,
  176. "PnW": None,
  177. "PnD": None,
  178. "TnH": "4",
  179. "TnM": None,
  180. "TnS": "6",
  181. },
  182. ),
  183. (
  184. "P1YT54M6S",
  185. {
  186. "PnY": "1",
  187. "PnM": None,
  188. "PnW": None,
  189. "PnD": None,
  190. "TnH": None,
  191. "TnM": "54",
  192. "TnS": "6",
  193. },
  194. ),
  195. (
  196. "P1YT4H54M6S",
  197. {
  198. "PnY": "1",
  199. "PnM": None,
  200. "PnW": None,
  201. "PnD": None,
  202. "TnH": "4",
  203. "TnM": "54",
  204. "TnS": "6",
  205. },
  206. ),
  207. (
  208. "P2MT4H",
  209. {
  210. "PnY": None,
  211. "PnM": "2",
  212. "PnW": None,
  213. "PnD": None,
  214. "TnH": "4",
  215. "TnM": None,
  216. "TnS": None,
  217. },
  218. ),
  219. (
  220. "P2MT54M",
  221. {
  222. "PnY": None,
  223. "PnM": "2",
  224. "PnW": None,
  225. "PnD": None,
  226. "TnH": None,
  227. "TnM": "54",
  228. "TnS": None,
  229. },
  230. ),
  231. (
  232. "P2MT6S",
  233. {
  234. "PnY": None,
  235. "PnM": "2",
  236. "PnW": None,
  237. "PnD": None,
  238. "TnH": None,
  239. "TnM": None,
  240. "TnS": "6",
  241. },
  242. ),
  243. (
  244. "P2MT4H54M",
  245. {
  246. "PnY": None,
  247. "PnM": "2",
  248. "PnW": None,
  249. "PnD": None,
  250. "TnH": "4",
  251. "TnM": "54",
  252. "TnS": None,
  253. },
  254. ),
  255. (
  256. "P2MT4H6S",
  257. {
  258. "PnY": None,
  259. "PnM": "2",
  260. "PnW": None,
  261. "PnD": None,
  262. "TnH": "4",
  263. "TnM": None,
  264. "TnS": "6",
  265. },
  266. ),
  267. (
  268. "P2MT54M6S",
  269. {
  270. "PnY": None,
  271. "PnM": "2",
  272. "PnW": None,
  273. "PnD": None,
  274. "TnH": None,
  275. "TnM": "54",
  276. "TnS": "6",
  277. },
  278. ),
  279. (
  280. "P2MT4H54M6S",
  281. {
  282. "PnY": None,
  283. "PnM": "2",
  284. "PnW": None,
  285. "PnD": None,
  286. "TnH": "4",
  287. "TnM": "54",
  288. "TnS": "6",
  289. },
  290. ),
  291. (
  292. "P3DT4H",
  293. {
  294. "PnY": None,
  295. "PnM": None,
  296. "PnW": None,
  297. "PnD": "3",
  298. "TnH": "4",
  299. "TnM": None,
  300. "TnS": None,
  301. },
  302. ),
  303. (
  304. "P3DT54M",
  305. {
  306. "PnY": None,
  307. "PnM": None,
  308. "PnW": None,
  309. "PnD": "3",
  310. "TnH": None,
  311. "TnM": "54",
  312. "TnS": None,
  313. },
  314. ),
  315. (
  316. "P3DT6S",
  317. {
  318. "PnY": None,
  319. "PnM": None,
  320. "PnW": None,
  321. "PnD": "3",
  322. "TnH": None,
  323. "TnM": None,
  324. "TnS": "6",
  325. },
  326. ),
  327. (
  328. "P3DT4H54M",
  329. {
  330. "PnY": None,
  331. "PnM": None,
  332. "PnW": None,
  333. "PnD": "3",
  334. "TnH": "4",
  335. "TnM": "54",
  336. "TnS": None,
  337. },
  338. ),
  339. (
  340. "P3DT4H6S",
  341. {
  342. "PnY": None,
  343. "PnM": None,
  344. "PnW": None,
  345. "PnD": "3",
  346. "TnH": "4",
  347. "TnM": None,
  348. "TnS": "6",
  349. },
  350. ),
  351. (
  352. "P3DT54M6S",
  353. {
  354. "PnY": None,
  355. "PnM": None,
  356. "PnW": None,
  357. "PnD": "3",
  358. "TnH": None,
  359. "TnM": "54",
  360. "TnS": "6",
  361. },
  362. ),
  363. (
  364. "P3DT4H54M6S",
  365. {
  366. "PnY": None,
  367. "PnM": None,
  368. "PnW": None,
  369. "PnD": "3",
  370. "TnH": "4",
  371. "TnM": "54",
  372. "TnS": "6",
  373. },
  374. ),
  375. (
  376. "P1Y2MT4H",
  377. {
  378. "PnY": "1",
  379. "PnM": "2",
  380. "PnW": None,
  381. "PnD": None,
  382. "TnH": "4",
  383. "TnM": None,
  384. "TnS": None,
  385. },
  386. ),
  387. (
  388. "P1Y2MT54M",
  389. {
  390. "PnY": "1",
  391. "PnM": "2",
  392. "PnW": None,
  393. "PnD": None,
  394. "TnH": None,
  395. "TnM": "54",
  396. "TnS": None,
  397. },
  398. ),
  399. (
  400. "P1Y2MT6S",
  401. {
  402. "PnY": "1",
  403. "PnM": "2",
  404. "PnW": None,
  405. "PnD": None,
  406. "TnH": None,
  407. "TnM": None,
  408. "TnS": "6",
  409. },
  410. ),
  411. (
  412. "P1Y2MT4H54M",
  413. {
  414. "PnY": "1",
  415. "PnM": "2",
  416. "PnW": None,
  417. "PnD": None,
  418. "TnH": "4",
  419. "TnM": "54",
  420. "TnS": None,
  421. },
  422. ),
  423. (
  424. "P1Y2MT4H6S",
  425. {
  426. "PnY": "1",
  427. "PnM": "2",
  428. "PnW": None,
  429. "PnD": None,
  430. "TnH": "4",
  431. "TnM": None,
  432. "TnS": "6",
  433. },
  434. ),
  435. (
  436. "P1Y2MT54M6S",
  437. {
  438. "PnY": "1",
  439. "PnM": "2",
  440. "PnW": None,
  441. "PnD": None,
  442. "TnH": None,
  443. "TnM": "54",
  444. "TnS": "6",
  445. },
  446. ),
  447. (
  448. "P1Y2MT4H54M6S",
  449. {
  450. "PnY": "1",
  451. "PnM": "2",
  452. "PnW": None,
  453. "PnD": None,
  454. "TnH": "4",
  455. "TnM": "54",
  456. "TnS": "6",
  457. },
  458. ),
  459. (
  460. "P1Y3DT4H",
  461. {
  462. "PnY": "1",
  463. "PnM": None,
  464. "PnW": None,
  465. "PnD": "3",
  466. "TnH": "4",
  467. "TnM": None,
  468. "TnS": None,
  469. },
  470. ),
  471. (
  472. "P1Y3DT54M",
  473. {
  474. "PnY": "1",
  475. "PnM": None,
  476. "PnW": None,
  477. "PnD": "3",
  478. "TnH": None,
  479. "TnM": "54",
  480. "TnS": None,
  481. },
  482. ),
  483. (
  484. "P1Y3DT6S",
  485. {
  486. "PnY": "1",
  487. "PnM": None,
  488. "PnW": None,
  489. "PnD": "3",
  490. "TnH": None,
  491. "TnM": None,
  492. "TnS": "6",
  493. },
  494. ),
  495. (
  496. "P1Y3DT4H54M",
  497. {
  498. "PnY": "1",
  499. "PnM": None,
  500. "PnW": None,
  501. "PnD": "3",
  502. "TnH": "4",
  503. "TnM": "54",
  504. "TnS": None,
  505. },
  506. ),
  507. (
  508. "P1Y3DT4H6S",
  509. {
  510. "PnY": "1",
  511. "PnM": None,
  512. "PnW": None,
  513. "PnD": "3",
  514. "TnH": "4",
  515. "TnM": None,
  516. "TnS": "6",
  517. },
  518. ),
  519. (
  520. "P1Y3DT54M6S",
  521. {
  522. "PnY": "1",
  523. "PnM": None,
  524. "PnW": None,
  525. "PnD": "3",
  526. "TnH": None,
  527. "TnM": "54",
  528. "TnS": "6",
  529. },
  530. ),
  531. (
  532. "P1Y3DT4H54M6S",
  533. {
  534. "PnY": "1",
  535. "PnM": None,
  536. "PnW": None,
  537. "PnD": "3",
  538. "TnH": "4",
  539. "TnM": "54",
  540. "TnS": "6",
  541. },
  542. ),
  543. (
  544. "P2M3DT4H",
  545. {
  546. "PnY": None,
  547. "PnM": "2",
  548. "PnW": None,
  549. "PnD": "3",
  550. "TnH": "4",
  551. "TnM": None,
  552. "TnS": None,
  553. },
  554. ),
  555. (
  556. "P2M3DT54M",
  557. {
  558. "PnY": None,
  559. "PnM": "2",
  560. "PnW": None,
  561. "PnD": "3",
  562. "TnH": None,
  563. "TnM": "54",
  564. "TnS": None,
  565. },
  566. ),
  567. (
  568. "P2M3DT6S",
  569. {
  570. "PnY": None,
  571. "PnM": "2",
  572. "PnW": None,
  573. "PnD": "3",
  574. "TnH": None,
  575. "TnM": None,
  576. "TnS": "6",
  577. },
  578. ),
  579. (
  580. "P2M3DT4H54M",
  581. {
  582. "PnY": None,
  583. "PnM": "2",
  584. "PnW": None,
  585. "PnD": "3",
  586. "TnH": "4",
  587. "TnM": "54",
  588. "TnS": None,
  589. },
  590. ),
  591. (
  592. "P2M3DT4H6S",
  593. {
  594. "PnY": None,
  595. "PnM": "2",
  596. "PnW": None,
  597. "PnD": "3",
  598. "TnH": "4",
  599. "TnM": None,
  600. "TnS": "6",
  601. },
  602. ),
  603. (
  604. "P2M3DT54M6S",
  605. {
  606. "PnY": None,
  607. "PnM": "2",
  608. "PnW": None,
  609. "PnD": "3",
  610. "TnH": None,
  611. "TnM": "54",
  612. "TnS": "6",
  613. },
  614. ),
  615. (
  616. "P2M3DT4H54M6S",
  617. {
  618. "PnY": None,
  619. "PnM": "2",
  620. "PnW": None,
  621. "PnD": "3",
  622. "TnH": "4",
  623. "TnM": "54",
  624. "TnS": "6",
  625. },
  626. ),
  627. (
  628. "PT4H54M6,5S",
  629. {
  630. "PnY": None,
  631. "PnM": None,
  632. "PnW": None,
  633. "PnD": None,
  634. "TnH": "4",
  635. "TnM": "54",
  636. "TnS": "6.5",
  637. },
  638. ),
  639. (
  640. "PT4H54M6.5S",
  641. {
  642. "PnY": None,
  643. "PnM": None,
  644. "PnW": None,
  645. "PnD": None,
  646. "TnH": "4",
  647. "TnM": "54",
  648. "TnS": "6.5",
  649. },
  650. ),
  651. (
  652. "PT4H",
  653. {
  654. "PnY": None,
  655. "PnM": None,
  656. "PnW": None,
  657. "PnD": None,
  658. "TnH": "4",
  659. "TnM": None,
  660. "TnS": None,
  661. },
  662. ),
  663. (
  664. "PT5M",
  665. {
  666. "PnY": None,
  667. "PnM": None,
  668. "PnW": None,
  669. "PnD": None,
  670. "TnH": None,
  671. "TnM": "5",
  672. "TnS": None,
  673. },
  674. ),
  675. (
  676. "PT6S",
  677. {
  678. "PnY": None,
  679. "PnM": None,
  680. "PnW": None,
  681. "PnD": None,
  682. "TnH": None,
  683. "TnM": None,
  684. "TnS": "6",
  685. },
  686. ),
  687. (
  688. "PT1H2M",
  689. {
  690. "PnY": None,
  691. "PnM": None,
  692. "PnW": None,
  693. "PnD": None,
  694. "TnH": "1",
  695. "TnM": "2",
  696. "TnS": None,
  697. },
  698. ),
  699. (
  700. "PT3H4S",
  701. {
  702. "PnY": None,
  703. "PnM": None,
  704. "PnW": None,
  705. "PnD": None,
  706. "TnH": "3",
  707. "TnM": None,
  708. "TnS": "4",
  709. },
  710. ),
  711. (
  712. "PT5M6S",
  713. {
  714. "PnY": None,
  715. "PnM": None,
  716. "PnW": None,
  717. "PnD": None,
  718. "TnH": None,
  719. "TnM": "5",
  720. "TnS": "6",
  721. },
  722. ),
  723. (
  724. "PT0.0000001S",
  725. {
  726. "PnY": None,
  727. "PnM": None,
  728. "PnW": None,
  729. "PnD": None,
  730. "TnH": None,
  731. "TnM": None,
  732. "TnS": "0.0000001",
  733. },
  734. ),
  735. (
  736. "PT2.0000048S",
  737. {
  738. "PnY": None,
  739. "PnM": None,
  740. "PnW": None,
  741. "PnD": None,
  742. "TnH": None,
  743. "TnM": None,
  744. "TnS": "2.0000048",
  745. },
  746. ),
  747. ("P1Y", {"PnY": "1", "PnM": None, "PnW": None, "PnD": None}),
  748. ("P1,5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}),
  749. ("P1.5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}),
  750. ("P1M", {"PnY": None, "PnM": "1", "PnW": None, "PnD": None}),
  751. ("P1,5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}),
  752. ("P1.5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}),
  753. ("P1W", {"PnY": None, "PnM": None, "PnW": "1", "PnD": None}),
  754. ("P1,5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}),
  755. ("P1.5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}),
  756. ("P1D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1"}),
  757. ("P1,5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}),
  758. ("P1.5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}),
  759. ("P1Y2M3D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3"}),
  760. ("P1Y2M3,5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}),
  761. ("P1Y2M3.5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}),
  762. ("P1Y2M", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": None}),
  763. (
  764. "P0003-06-04T12:30:05",
  765. {
  766. "PnY": "0003",
  767. "PnM": "06",
  768. "PnD": "04",
  769. "TnH": "12",
  770. "TnM": "30",
  771. "TnS": "05",
  772. },
  773. ),
  774. (
  775. "P0003-06-04T12:30:05.5",
  776. {
  777. "PnY": "0003",
  778. "PnM": "06",
  779. "PnD": "04",
  780. "TnH": "12",
  781. "TnM": "30",
  782. "TnS": "05.5",
  783. },
  784. ),
  785. (
  786. "P0001-02-03T14:43:59.9999997",
  787. {
  788. "PnY": "0001",
  789. "PnM": "02",
  790. "PnD": "03",
  791. "TnH": "14",
  792. "TnM": "43",
  793. "TnS": "59.9999997",
  794. },
  795. ),
  796. )
  797. for testtuple in testtuples:
  798. with mock.patch.object(
  799. aniso8601.duration.PythonTimeBuilder, "build_duration"
  800. ) as mockBuildDuration:
  801. mockBuildDuration.return_value = testtuple[1]
  802. result = parse_duration(testtuple[0])
  803. self.assertEqual(result, testtuple[1])
  804. mockBuildDuration.assert_called_once_with(**testtuple[1])
  805. def test_parse_duration_mockbuilder(self):
  806. mockBuilder = mock.Mock()
  807. expectedargs = {
  808. "PnY": "1",
  809. "PnM": "2",
  810. "PnW": None,
  811. "PnD": "3",
  812. "TnH": "4",
  813. "TnM": "54",
  814. "TnS": "6",
  815. }
  816. mockBuilder.build_duration.return_value = expectedargs
  817. result = parse_duration("P1Y2M3DT4H54M6S", builder=mockBuilder)
  818. self.assertEqual(result, expectedargs)
  819. mockBuilder.build_duration.assert_called_once_with(**expectedargs)
  820. def test_parse_duration_badtype(self):
  821. testtuples = (None, 1, False, 1.234)
  822. for testtuple in testtuples:
  823. with self.assertRaises(ValueError):
  824. parse_duration(testtuple, builder=None)
  825. def test_parse_duration_nop(self):
  826. with self.assertRaises(ISOFormatError):
  827. # Duration must start with a P
  828. parse_duration("1Y2M3DT4H54M6S", builder=None)
  829. def test_parse_duration_weekcombination(self):
  830. # Week designator cannot be combined with other time designators
  831. # https://bitbucket.org/nielsenb/aniso8601/issues/2/week-designators-should-not-be-combinable
  832. with self.assertRaises(ISOFormatError):
  833. parse_duration("P1Y2W", builder=None)
  834. with self.assertRaises(ISOFormatError):
  835. parse_duration("P1M2W", builder=None)
  836. with self.assertRaises(ISOFormatError):
  837. parse_duration("P2W3D", builder=None)
  838. with self.assertRaises(ISOFormatError):
  839. parse_duration("P1Y2W3D", builder=None)
  840. with self.assertRaises(ISOFormatError):
  841. parse_duration("P1M2W3D", builder=None)
  842. with self.assertRaises(ISOFormatError):
  843. parse_duration("P1Y1M2W3D", builder=None)
  844. with self.assertRaises(ISOFormatError):
  845. parse_duration("P7WT4H", builder=None)
  846. with self.assertRaises(ISOFormatError):
  847. parse_duration("P7WT54M", builder=None)
  848. with self.assertRaises(ISOFormatError):
  849. parse_duration("P7WT6S", builder=None)
  850. with self.assertRaises(ISOFormatError):
  851. parse_duration("P7WT4H54M", builder=None)
  852. with self.assertRaises(ISOFormatError):
  853. parse_duration("P7WT4H6S", builder=None)
  854. with self.assertRaises(ISOFormatError):
  855. parse_duration("P7WT54M6S", builder=None)
  856. with self.assertRaises(ISOFormatError):
  857. parse_duration("P7WT4H54M6S", builder=None)
  858. def test_parse_duration_negative(self):
  859. with self.assertRaises(ISOFormatError):
  860. parse_duration("P-1Y", builder=None)
  861. with self.assertRaises(ISOFormatError):
  862. parse_duration("P-2M", builder=None)
  863. with self.assertRaises(ISOFormatError):
  864. parse_duration("P-3D", builder=None)
  865. with self.assertRaises(ISOFormatError):
  866. parse_duration("P-T4H", builder=None)
  867. with self.assertRaises(ISOFormatError):
  868. parse_duration("P-T54M", builder=None)
  869. with self.assertRaises(ISOFormatError):
  870. parse_duration("P-T6S", builder=None)
  871. with self.assertRaises(ISOFormatError):
  872. parse_duration("P-7W", builder=None)
  873. with self.assertRaises(ISOFormatError):
  874. parse_duration("P-1Y2M3DT4H54M6S", builder=None)
  875. def test_parse_duration_outoforder(self):
  876. # Ensure durations are required to be in the correct order
  877. # https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t
  878. # https://bitbucket.org/nielsenb/aniso8601/issues/8/durations-with-components-in-wrong-order
  879. with self.assertRaises(ISOFormatError):
  880. parse_duration("P1S", builder=None)
  881. with self.assertRaises(ISOFormatError):
  882. parse_duration("P1D1S", builder=None)
  883. with self.assertRaises(ISOFormatError):
  884. parse_duration("P1H1M", builder=None)
  885. with self.assertRaises(ISOFormatError):
  886. parse_duration("1Y2M3D1SPT1M", builder=None)
  887. with self.assertRaises(ISOFormatError):
  888. parse_duration("P1Y2M3D2MT1S", builder=None)
  889. with self.assertRaises(ISOFormatError):
  890. parse_duration("P2M3D1ST1Y1M", builder=None)
  891. with self.assertRaises(ISOFormatError):
  892. parse_duration("P1Y2M2MT3D1S", builder=None)
  893. with self.assertRaises(ISOFormatError):
  894. parse_duration("P1D1Y1M", builder=None)
  895. with self.assertRaises(ISOFormatError):
  896. parse_duration("PT1S1H", builder=None)
  897. def test_parse_duration_badstr(self):
  898. testtuples = (
  899. "PPPPPPPPPPPPPPPPPPPPPPPPPPPP",
  900. "PTT",
  901. "PX7DDDTX8888UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"
  902. "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU8888888888888888H$H",
  903. "P1Y2M3X.4D",
  904. "P1Y2M3.4XD",
  905. "P1Y2M3DT4H5M6XS",
  906. "PT4H5M6X.2S",
  907. "bad",
  908. "",
  909. )
  910. for testtuple in testtuples:
  911. with self.assertRaises(ISOFormatError):
  912. parse_duration(testtuple, builder=None)
  913. def test_parse_duration_prescribed(self):
  914. testtuples = (
  915. (
  916. "P1Y2M3DT4H54M6S",
  917. {
  918. "PnY": "1",
  919. "PnM": "2",
  920. "PnW": None,
  921. "PnD": "3",
  922. "TnH": "4",
  923. "TnM": "54",
  924. "TnS": "6",
  925. },
  926. ),
  927. (
  928. "P1Y2M3DT4H54M6,5S",
  929. {
  930. "PnY": "1",
  931. "PnM": "2",
  932. "PnW": None,
  933. "PnD": "3",
  934. "TnH": "4",
  935. "TnM": "54",
  936. "TnS": "6.5",
  937. },
  938. ),
  939. (
  940. "P1Y2M3DT4H54M6.5S",
  941. {
  942. "PnY": "1",
  943. "PnM": "2",
  944. "PnW": None,
  945. "PnD": "3",
  946. "TnH": "4",
  947. "TnM": "54",
  948. "TnS": "6.5",
  949. },
  950. ),
  951. (
  952. "PT4H54M6,5S",
  953. {
  954. "PnY": None,
  955. "PnM": None,
  956. "PnW": None,
  957. "PnD": None,
  958. "TnH": "4",
  959. "TnM": "54",
  960. "TnS": "6.5",
  961. },
  962. ),
  963. (
  964. "PT4H54M6.5S",
  965. {
  966. "PnY": None,
  967. "PnM": None,
  968. "PnW": None,
  969. "PnD": None,
  970. "TnH": "4",
  971. "TnM": "54",
  972. "TnS": "6.5",
  973. },
  974. ),
  975. ("P1Y2M3D", {"PnY": "1", "PnM": "2", "" "PnW": None, "PnD": "3"}),
  976. ("P1Y2M3,5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}),
  977. ("P1Y2M3.5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}),
  978. ("P1Y2M", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": None}),
  979. ("P1Y", {"PnY": "1", "PnM": None, "PnW": None, "PnD": None}),
  980. ("P1,5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}),
  981. ("P1.5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}),
  982. ("P1M", {"PnY": None, "PnM": "1", "PnW": None, "PnD": None}),
  983. ("P1,5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}),
  984. ("P1.5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}),
  985. ("P1W", {"PnY": None, "PnM": None, "PnW": "1", "PnD": None}),
  986. ("P1,5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}),
  987. ("P1.5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}),
  988. ("P1D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1"}),
  989. ("P1,5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}),
  990. ("P1.5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}),
  991. )
  992. for testtuple in testtuples:
  993. result = _parse_duration_prescribed(testtuple[0])
  994. self.assertEqual(result, testtuple[1])
  995. def test_parse_duration_prescribed_negative(self):
  996. with self.assertRaises(ISOFormatError):
  997. _parse_duration_prescribed("P-1Y")
  998. with self.assertRaises(ISOFormatError):
  999. _parse_duration_prescribed("P-2M")
  1000. with self.assertRaises(ISOFormatError):
  1001. _parse_duration_prescribed("P-3D")
  1002. with self.assertRaises(ISOFormatError):
  1003. _parse_duration_prescribed("P-4W")
  1004. with self.assertRaises(ISOFormatError):
  1005. _parse_duration_prescribed("P-1Y2M3D")
  1006. with self.assertRaises(ISOFormatError):
  1007. _parse_duration_prescribed("P-T1H")
  1008. with self.assertRaises(ISOFormatError):
  1009. _parse_duration_prescribed("P-T2M")
  1010. with self.assertRaises(ISOFormatError):
  1011. _parse_duration_prescribed("P-T3S")
  1012. with self.assertRaises(ISOFormatError):
  1013. _parse_duration_prescribed("P-1Y2M3DT4H54M6S")
  1014. def test_parse_duration_prescribed_multiplefractions(self):
  1015. with self.assertRaises(ISOFormatError):
  1016. # Multiple fractions are not allowed
  1017. _parse_duration_prescribed("P1Y2M3DT4H5.1234M6.1234S")
  1018. def test_parse_duration_prescribed_middlefraction(self):
  1019. with self.assertRaises(ISOFormatError):
  1020. # Fraction only allowed on final component
  1021. _parse_duration_prescribed("P1Y2M3DT4H5.1234M6S")
  1022. def test_parse_duration_prescribed_suffixgarbage(self):
  1023. # Don't allow garbage after the duration
  1024. # https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed
  1025. with self.assertRaises(ISOFormatError):
  1026. _parse_duration_prescribed("P1Dasdfasdf")
  1027. def test_parse_duration_prescribed_notime(self):
  1028. testtuples = (
  1029. ("P1Y2M3D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3"}),
  1030. ("P1Y2M3,5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}),
  1031. ("P1Y2M3.5D", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": "3.5"}),
  1032. ("P1Y3D", {"PnY": "1", "PnM": None, "PnW": None, "PnD": "3"}),
  1033. ("P1Y2M", {"PnY": "1", "PnM": "2", "PnW": None, "PnD": None}),
  1034. ("P2M3D", {"PnY": None, "PnM": "2", "PnW": None, "PnD": "3"}),
  1035. ("P1Y", {"PnY": "1", "PnM": None, "PnW": None, "PnD": None}),
  1036. ("P1,5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}),
  1037. ("P1.5Y", {"PnY": "1.5", "PnM": None, "PnW": None, "PnD": None}),
  1038. ("P1M", {"PnY": None, "PnM": "1", "PnW": None, "PnD": None}),
  1039. ("P1,5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}),
  1040. ("P1.5M", {"PnY": None, "PnM": "1.5", "PnW": None, "PnD": None}),
  1041. ("P1W", {"PnY": None, "PnM": None, "PnW": "1", "PnD": None}),
  1042. ("P1,5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}),
  1043. ("P1.5W", {"PnY": None, "PnM": None, "PnW": "1.5", "PnD": None}),
  1044. ("P1D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1"}),
  1045. ("P1,5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}),
  1046. ("P1.5D", {"PnY": None, "PnM": None, "PnW": None, "PnD": "1.5"}),
  1047. )
  1048. for testtuple in testtuples:
  1049. result = _parse_duration_prescribed_notime(testtuple[0])
  1050. self.assertEqual(result, testtuple[1])
  1051. def test_parse_duration_prescribed_notime_timepart(self):
  1052. # Ensure no time part is allowed
  1053. with self.assertRaises(ISOFormatError):
  1054. _parse_duration_prescribed_notime("P1S")
  1055. with self.assertRaises(ISOFormatError):
  1056. _parse_duration_prescribed_notime("P1D1S")
  1057. with self.assertRaises(ISOFormatError):
  1058. _parse_duration_prescribed_notime("P1H1M")
  1059. with self.assertRaises(ISOFormatError):
  1060. _parse_duration_prescribed_notime("P1Y2M3D4H")
  1061. with self.assertRaises(ISOFormatError):
  1062. _parse_duration_prescribed_notime("P1Y2M3D4H5S")
  1063. def test_parse_duration_prescribed_notime_outoforder(self):
  1064. # Ensure durations are required to be in the correct order
  1065. # https://bitbucket.org/nielsenb/aniso8601/issues/8/durations-with-components-in-wrong-order
  1066. with self.assertRaises(ISOFormatError):
  1067. _parse_duration_prescribed_notime("P1H1M")
  1068. with self.assertRaises(ISOFormatError):
  1069. _parse_duration_prescribed_notime("P1D1Y1M")
  1070. def test_parse_duration_prescribed_notime_badstr(self):
  1071. with self.assertRaises(ISOFormatError):
  1072. _parse_duration_prescribed_notime("P1S")
  1073. with self.assertRaises(ISOFormatError):
  1074. _parse_duration_prescribed_notime("P1D1S")
  1075. def test_parse_duration_prescribed_time(self):
  1076. testtuples = (
  1077. (
  1078. "P1Y2M3DT4H54M6S",
  1079. {
  1080. "PnY": "1",
  1081. "PnM": "2",
  1082. "PnW": None,
  1083. "PnD": "3",
  1084. "TnH": "4",
  1085. "TnM": "54",
  1086. "TnS": "6",
  1087. },
  1088. ),
  1089. (
  1090. "P1Y2M3DT4H54M6,5S",
  1091. {
  1092. "PnY": "1",
  1093. "PnM": "2",
  1094. "PnW": None,
  1095. "PnD": "3",
  1096. "TnH": "4",
  1097. "TnM": "54",
  1098. "TnS": "6.5",
  1099. },
  1100. ),
  1101. (
  1102. "P1Y2M3DT4H54M6.5S",
  1103. {
  1104. "PnY": "1",
  1105. "PnM": "2",
  1106. "PnW": None,
  1107. "PnD": "3",
  1108. "TnH": "4",
  1109. "TnM": "54",
  1110. "TnS": "6.5",
  1111. },
  1112. ),
  1113. (
  1114. "PT4H54M6,5S",
  1115. {
  1116. "PnY": None,
  1117. "PnM": None,
  1118. "PnW": None,
  1119. "PnD": None,
  1120. "TnH": "4",
  1121. "TnM": "54",
  1122. "TnS": "6.5",
  1123. },
  1124. ),
  1125. (
  1126. "PT4H54M6.5S",
  1127. {
  1128. "PnY": None,
  1129. "PnM": None,
  1130. "PnW": None,
  1131. "PnD": None,
  1132. "TnH": "4",
  1133. "TnM": "54",
  1134. "TnS": "6.5",
  1135. },
  1136. ),
  1137. (
  1138. "PT4H",
  1139. {
  1140. "PnY": None,
  1141. "PnM": None,
  1142. "PnW": None,
  1143. "PnD": None,
  1144. "TnH": "4",
  1145. "TnM": None,
  1146. "TnS": None,
  1147. },
  1148. ),
  1149. (
  1150. "PT5M",
  1151. {
  1152. "PnY": None,
  1153. "PnM": None,
  1154. "PnW": None,
  1155. "PnD": None,
  1156. "TnH": None,
  1157. "TnM": "5",
  1158. "TnS": None,
  1159. },
  1160. ),
  1161. (
  1162. "PT6S",
  1163. {
  1164. "PnY": None,
  1165. "PnM": None,
  1166. "PnW": None,
  1167. "PnD": None,
  1168. "TnH": None,
  1169. "TnM": None,
  1170. "TnS": "6",
  1171. },
  1172. ),
  1173. (
  1174. "PT1H2M",
  1175. {
  1176. "PnY": None,
  1177. "PnM": None,
  1178. "PnW": None,
  1179. "PnD": None,
  1180. "TnH": "1",
  1181. "TnM": "2",
  1182. "TnS": None,
  1183. },
  1184. ),
  1185. (
  1186. "PT3H4S",
  1187. {
  1188. "PnY": None,
  1189. "PnM": None,
  1190. "PnW": None,
  1191. "PnD": None,
  1192. "TnH": "3",
  1193. "TnM": None,
  1194. "TnS": "4",
  1195. },
  1196. ),
  1197. (
  1198. "PT5M6S",
  1199. {
  1200. "PnY": None,
  1201. "PnM": None,
  1202. "PnW": None,
  1203. "PnD": None,
  1204. "TnH": None,
  1205. "TnM": "5",
  1206. "TnS": "6",
  1207. },
  1208. ),
  1209. )
  1210. for testtuple in testtuples:
  1211. result = _parse_duration_prescribed_time(testtuple[0])
  1212. self.assertEqual(result, testtuple[1])
  1213. def test_parse_duration_prescribed_time_timeindate(self):
  1214. # Don't allow time components in date half
  1215. with self.assertRaises(ISOFormatError):
  1216. _parse_duration_prescribed_time("P1Y2M3D4HT54M6S")
  1217. with self.assertRaises(ISOFormatError):
  1218. _parse_duration_prescribed_time("P1Y2M3D6ST4H54M")
  1219. def test_parse_duration_prescribed_time_dateintime(self):
  1220. # Don't allow date components in time half
  1221. with self.assertRaises(ISOFormatError):
  1222. _parse_duration_prescribed_time("P2M3DT1Y4H54M6S")
  1223. with self.assertRaises(ISOFormatError):
  1224. _parse_duration_prescribed_time("P1Y2MT3D4H54M6S")
  1225. def test_parse_duration_prescribed_time_outoforder(self):
  1226. # Ensure durations are required to be in the correct order
  1227. # https://bitbucket.org/nielsenb/aniso8601/issues/7/durations-with-time-components-before-t
  1228. with self.assertRaises(ISOFormatError):
  1229. _parse_duration_prescribed_time("1Y2M3D1SPT1M")
  1230. with self.assertRaises(ISOFormatError):
  1231. _parse_duration_prescribed_time("P1Y2M3D2MT1S")
  1232. with self.assertRaises(ISOFormatError):
  1233. _parse_duration_prescribed_time("P2M3D1ST1Y1M")
  1234. with self.assertRaises(ISOFormatError):
  1235. _parse_duration_prescribed_time("P1Y2M2MT3D1S")
  1236. with self.assertRaises(ISOFormatError):
  1237. _parse_duration_prescribed_time("PT1S1H")
  1238. def test_parse_duration_prescribed_time_badstr(self):
  1239. with self.assertRaises(ISOFormatError):
  1240. _parse_duration_prescribed_time("P1Y")
  1241. with self.assertRaises(ISOFormatError):
  1242. _parse_duration_prescribed_time("P1Y1M")
  1243. def test_parse_duration_combined(self):
  1244. testtuples = (
  1245. (
  1246. "P0003-06-04T12:30:05",
  1247. {
  1248. "PnY": "0003",
  1249. "PnM": "06",
  1250. "PnD": "04",
  1251. "TnH": "12",
  1252. "TnM": "30",
  1253. "TnS": "05",
  1254. },
  1255. ),
  1256. (
  1257. "P0003-06-04T12:30:05,5",
  1258. {
  1259. "PnY": "0003",
  1260. "PnM": "06",
  1261. "PnD": "04",
  1262. "TnH": "12",
  1263. "TnM": "30",
  1264. "TnS": "05.5",
  1265. },
  1266. ),
  1267. (
  1268. "P0003-06-04T12:30:05.5",
  1269. {
  1270. "PnY": "0003",
  1271. "PnM": "06",
  1272. "PnD": "04",
  1273. "TnH": "12",
  1274. "TnM": "30",
  1275. "TnS": "05.5",
  1276. },
  1277. ),
  1278. (
  1279. "P0001-02-03T14:43:59.9999997",
  1280. {
  1281. "PnY": "0001",
  1282. "PnM": "02",
  1283. "PnD": "03",
  1284. "TnH": "14",
  1285. "TnM": "43",
  1286. "TnS": "59.9999997",
  1287. },
  1288. ),
  1289. )
  1290. for testtuple in testtuples:
  1291. result = _parse_duration_combined(testtuple[0])
  1292. self.assertEqual(result, testtuple[1])
  1293. def test_parse_duration_combined_suffixgarbage(self):
  1294. # Don't allow garbage after the duration
  1295. # https://bitbucket.org/nielsenb/aniso8601/issues/9/durations-with-trailing-garbage-are-parsed
  1296. with self.assertRaises(ISOFormatError):
  1297. _parse_duration_combined("P0003-06-04T12:30:05.5asdfasdf")
  1298. def test_has_any_component(self):
  1299. self.assertTrue(_has_any_component("P1Y", ["Y", "M"]))
  1300. self.assertFalse(_has_any_component("P1Y", ["M", "D"]))