rapydscript-ns 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +10 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/README.md +7 -6
  8. package/TODO.md +116 -1
  9. package/add-toc-to-readme +2 -2
  10. package/bin/export +75 -75
  11. package/bin/rapydscript +70 -70
  12. package/bin/web-repl-export +102 -102
  13. package/build +2 -2
  14. package/language-service/index.js +9 -9
  15. package/language-service/language-service.d.ts +1 -1
  16. package/package.json +6 -2
  17. package/publish.py +37 -37
  18. package/release/compiler.js +246 -231
  19. package/release/signatures.json +23 -23
  20. package/session.vim +4 -4
  21. package/setup.cfg +2 -2
  22. package/src/compiler.pyj +36 -36
  23. package/src/errors.pyj +30 -30
  24. package/src/lib/aes.pyj +646 -646
  25. package/src/lib/contextlib.pyj +379 -0
  26. package/src/lib/copy.pyj +120 -120
  27. package/src/lib/datetime.pyj +712 -0
  28. package/src/lib/elementmaker.pyj +83 -83
  29. package/src/lib/encodings.pyj +126 -126
  30. package/src/lib/gettext.pyj +569 -569
  31. package/src/lib/io.pyj +500 -0
  32. package/src/lib/itertools.pyj +580 -580
  33. package/src/lib/json.pyj +227 -0
  34. package/src/lib/math.pyj +193 -193
  35. package/src/lib/operator.pyj +11 -11
  36. package/src/lib/pythonize.pyj +20 -20
  37. package/src/lib/random.pyj +118 -118
  38. package/src/lib/react.pyj +74 -74
  39. package/src/lib/traceback.pyj +63 -63
  40. package/src/lib/uuid.pyj +77 -77
  41. package/src/monaco-language-service/diagnostics.js +4 -4
  42. package/src/monaco-language-service/dts.js +550 -550
  43. package/src/monaco-language-service/index.js +2 -2
  44. package/src/output/comments.pyj +45 -45
  45. package/src/output/exceptions.pyj +201 -201
  46. package/src/output/jsx.pyj +164 -164
  47. package/src/output/loops.pyj +9 -0
  48. package/src/output/treeshake.pyj +182 -182
  49. package/src/output/utils.pyj +72 -72
  50. package/src/string_interpolation.pyj +72 -72
  51. package/src/tokenizer.pyj +1 -1
  52. package/src/unicode_aliases.pyj +576 -576
  53. package/src/utils.pyj +192 -192
  54. package/test/_import_one.pyj +37 -37
  55. package/test/_import_two/__init__.pyj +11 -11
  56. package/test/_import_two/level2/deep.pyj +4 -4
  57. package/test/_import_two/other.pyj +6 -6
  58. package/test/_import_two/sub.pyj +13 -13
  59. package/test/aes_vectors.pyj +421 -421
  60. package/test/annotations.pyj +80 -80
  61. package/test/contextlib.pyj +362 -0
  62. package/test/datetime.pyj +500 -0
  63. package/test/debugger_stmt.pyj +41 -0
  64. package/test/decorators.pyj +77 -77
  65. package/test/docstrings.pyj +39 -39
  66. package/test/elementmaker_test.pyj +45 -45
  67. package/test/functions.pyj +151 -151
  68. package/test/generators.pyj +41 -41
  69. package/test/generic.pyj +370 -370
  70. package/test/imports.pyj +72 -72
  71. package/test/internationalization.pyj +73 -73
  72. package/test/io.pyj +316 -0
  73. package/test/json.pyj +196 -0
  74. package/test/lint.pyj +164 -164
  75. package/test/loops.pyj +85 -85
  76. package/test/numpy.pyj +734 -734
  77. package/test/omit_function_metadata.pyj +20 -20
  78. package/test/repl.pyj +121 -121
  79. package/test/scoped_flags.pyj +76 -76
  80. package/test/unit/index.js +66 -0
  81. package/test/unit/language-service-dts.js +543 -543
  82. package/test/unit/language-service-hover.js +455 -455
  83. package/test/unit/language-service.js +1 -1
  84. package/test/unit/web-repl.js +533 -0
  85. package/tools/compiler.d.ts +367 -0
  86. package/tools/completer.js +131 -131
  87. package/tools/gettext.js +185 -185
  88. package/tools/ini.js +65 -65
  89. package/tools/msgfmt.js +187 -187
  90. package/tools/repl.js +223 -223
  91. package/tools/test.js +118 -118
  92. package/tools/utils.js +128 -128
  93. package/tools/web_repl.js +95 -95
  94. package/try +41 -41
  95. package/web-repl/env.js +196 -196
  96. package/web-repl/index.html +163 -163
  97. package/web-repl/prism.css +139 -139
  98. package/web-repl/prism.js +113 -113
  99. package/web-repl/rapydscript.js +224 -224
  100. package/web-repl/sha1.js +25 -25
@@ -0,0 +1,500 @@
1
+ # globals: assrt
2
+ # vim:fileencoding=utf-8
3
+ #
4
+ # datetime.pyj
5
+ # Tests for the datetime standard library (from datetime import ...).
6
+
7
+ from datetime import date, time, datetime, timedelta, MINYEAR, MAXYEAR
8
+
9
+ ae = assrt.equal
10
+ ade = assrt.deepEqual
11
+ ok = assrt.ok
12
+ throws = assrt.throws
13
+
14
+ # ── 1. Constants ──────────────────────────────────────────────────────────────
15
+ # STATUS: ✓ WORKS
16
+
17
+ ae(MINYEAR, 1)
18
+ ae(MAXYEAR, 9999)
19
+
20
+ # ── 2. timedelta construction and normalisation ────────────────────────────────
21
+ # STATUS: ✓ WORKS
22
+
23
+ # Basic positional args
24
+ _td0 = timedelta(0)
25
+ ae(_td0.days, 0)
26
+ ae(_td0.seconds, 0)
27
+ ae(_td0.microseconds, 0)
28
+
29
+ _td1 = timedelta(1)
30
+ ae(_td1.days, 1)
31
+ ae(_td1.seconds, 0)
32
+
33
+ # Keyword args
34
+ _td_kw = timedelta(days=2, seconds=3661)
35
+ ae(_td_kw.days, 2)
36
+ ae(_td_kw.seconds, 3661)
37
+
38
+ # Normalisation: seconds overflow into days
39
+ _td_norm = timedelta(0, 90061) # 25h 1m 1s
40
+ ae(_td_norm.days, 1)
41
+ ae(_td_norm.seconds, 3661)
42
+
43
+ # Normalisation: milliseconds folded in
44
+ _td_ms = timedelta(0, 0, 0, 1500) # 1500 ms
45
+ ae(_td_ms.seconds, 1)
46
+ ae(_td_ms.microseconds, 500000)
47
+
48
+ # Negative timedelta
49
+ _td_neg = timedelta(-1)
50
+ ae(_td_neg.days, -1)
51
+ ae(_td_neg.seconds, 0)
52
+
53
+ # Negative seconds normalised: days=-1, seconds=86399
54
+ _td_neg_s = timedelta(0, -1)
55
+ ae(_td_neg_s.days, -1)
56
+ ae(_td_neg_s.seconds, 86399)
57
+
58
+ # Float days folded into seconds
59
+ _td_frac = timedelta(0, 0, 0, 0, 0, 0, 0) # all zeros
60
+ ae(_td_frac.days, 0)
61
+
62
+ # ── 3. timedelta.total_seconds() ──────────────────────────────────────────────
63
+ # STATUS: ✓ WORKS
64
+
65
+ ae(timedelta(1).total_seconds(), 86400)
66
+ ae(timedelta(0, 3600).total_seconds(), 3600)
67
+ ae(timedelta(0, 0, 500000).total_seconds(), 0.5)
68
+ ae(timedelta(-1).total_seconds(), -86400)
69
+
70
+ # ── 4. timedelta arithmetic (direct method calls) ─────────────────────────────
71
+ # STATUS: ✓ WORKS
72
+
73
+ _a = timedelta(1)
74
+ _b = timedelta(0, 3600)
75
+ _sum = _a.__add__(_b)
76
+ ae(_sum.days, 1)
77
+ ae(_sum.seconds, 3600)
78
+
79
+ _diff = _a.__sub__(_b)
80
+ ae(_diff.days, 0)
81
+ ae(_diff.seconds, 82800) # 86400 - 3600
82
+
83
+ # __neg__
84
+ _neg = _a.__neg__()
85
+ ae(_neg.days, -1)
86
+ ae(_neg.seconds, 0)
87
+
88
+ # __mul__
89
+ _mul = _a.__mul__(3)
90
+ ae(_mul.days, 3)
91
+
92
+ # ── 5. timedelta comparisons ──────────────────────────────────────────────────
93
+ # STATUS: ✓ WORKS
94
+
95
+ _td_a = timedelta(1)
96
+ _td_b = timedelta(2)
97
+ _td_c = timedelta(1)
98
+
99
+ ok(_td_a.__eq__(_td_c))
100
+ ok(not _td_a.__eq__(_td_b))
101
+ ok(_td_a.__lt__(_td_b))
102
+ ok(not _td_b.__lt__(_td_a))
103
+ ok(_td_a.__le__(_td_c))
104
+ ok(_td_b.__gt__(_td_a))
105
+ ok(_td_b.__ge__(_td_b))
106
+
107
+ # ── 6. timedelta str and repr ─────────────────────────────────────────────────
108
+ # STATUS: ✓ WORKS
109
+
110
+ ae(str(timedelta(0)), '0:00:00')
111
+ ae(str(timedelta(1)), '1 day, 0:00:00')
112
+ ae(str(timedelta(2)), '2 days, 0:00:00')
113
+ ae(str(timedelta(-1)), '-1 day, 0:00:00')
114
+ ae(str(timedelta(-2)), '-2 days, 0:00:00')
115
+ ae(str(timedelta(0, 3661)), '1:01:01')
116
+ ae(str(timedelta(0, 0, 100000)), '0:00:00.100000')
117
+
118
+ ae(repr(timedelta(0)), 'datetime.timedelta(0)')
119
+ ae(repr(timedelta(1)), 'datetime.timedelta(days=1)')
120
+ ae(repr(timedelta(0, 3661)), 'datetime.timedelta(seconds=3661)')
121
+ ae(repr(timedelta(0, 0, 1)), 'datetime.timedelta(microseconds=1)')
122
+ ae(repr(timedelta(1, 3661, 1)), 'datetime.timedelta(days=1, seconds=3661, microseconds=1)')
123
+
124
+ # ── 7. timedelta class attributes ─────────────────────────────────────────────
125
+ # STATUS: ✓ WORKS
126
+
127
+ ok(isinstance(timedelta.min, timedelta))
128
+ ok(isinstance(timedelta.max, timedelta))
129
+ ok(isinstance(timedelta.resolution, timedelta))
130
+ ae(timedelta.min.days, -999999999)
131
+ ae(timedelta.max.days, 999999999)
132
+ ae(timedelta.resolution.microseconds, 1)
133
+
134
+ # ── 8. date construction ──────────────────────────────────────────────────────
135
+ # STATUS: ✓ WORKS
136
+
137
+ _d1 = date(2024, 1, 15)
138
+ ae(_d1.year, 2024)
139
+ ae(_d1.month, 1)
140
+ ae(_d1.day, 15)
141
+
142
+ # Min/max class attributes
143
+ ae(date.min.year, MINYEAR)
144
+ ae(date.min.month, 1)
145
+ ae(date.min.day, 1)
146
+ ae(date.max.year, MAXYEAR)
147
+ ae(date.max.month, 12)
148
+ ae(date.max.day, 31)
149
+
150
+ # ── 9. date.fromisoformat ────────────────────────────────────────────────────
151
+ # STATUS: ✓ WORKS
152
+
153
+ _d_iso = date.fromisoformat('2024-01-15')
154
+ ae(_d_iso.year, 2024)
155
+ ae(_d_iso.month, 1)
156
+ ae(_d_iso.day, 15)
157
+
158
+ # ── 10. date.fromordinal / toordinal round-trip ───────────────────────────────
159
+ # STATUS: ✓ WORKS
160
+
161
+ _d_ref = date(2024, 6, 15)
162
+ ae(date.fromordinal(_d_ref.toordinal()).__eq__(_d_ref), True)
163
+
164
+ ae(date(1, 1, 1).toordinal(), 1)
165
+ ae(date.fromordinal(1).year, 1)
166
+ ae(date.fromordinal(1).month, 1)
167
+ ae(date.fromordinal(1).day, 1)
168
+
169
+ # ── 11. date.weekday / isoweekday ────────────────────────────────────────────
170
+ # STATUS: ✓ WORKS
171
+
172
+ # 2024-01-01 is Monday
173
+ ae(date(2024, 1, 1).weekday(), 0) # Monday
174
+ ae(date(2024, 1, 1).isoweekday(), 1)
175
+ ae(date(2024, 1, 7).weekday(), 6) # Sunday
176
+ ae(date(2024, 1, 7).isoweekday(), 7)
177
+
178
+ # ── 12. date.isoformat / str / repr ──────────────────────────────────────────
179
+ # STATUS: ✓ WORKS
180
+
181
+ ae(str(date(2024, 1, 15)), '2024-01-15')
182
+ ae(date(2024, 1, 15).isoformat(), '2024-01-15')
183
+ ae(repr(date(2024, 1, 15)), 'datetime.date(2024, 1, 15)')
184
+
185
+ # ── 13. date arithmetic (direct method calls) ─────────────────────────────────
186
+ # STATUS: ✓ WORKS
187
+
188
+ _d_base = date(2024, 1, 15)
189
+ _d_plus = _d_base.__add__(timedelta(10))
190
+ ae(_d_plus.year, 2024)
191
+ ae(_d_plus.month, 1)
192
+ ae(_d_plus.day, 25)
193
+
194
+ _d_minus = _d_base.__sub__(timedelta(15))
195
+ ae(_d_minus.year, 2023)
196
+ ae(_d_minus.month, 12)
197
+ ae(_d_minus.day, 31)
198
+
199
+ # date - date → timedelta
200
+ _delta = date(2024, 1, 15).__sub__(date(2024, 1, 1))
201
+ ae(_delta.days, 14)
202
+
203
+ # Month boundary
204
+ _d_end = date(2024, 1, 31).__add__(timedelta(1))
205
+ ae(_d_end.month, 2)
206
+ ae(_d_end.day, 1)
207
+
208
+ # Leap year: 2024 is a leap year
209
+ _d_leap = date(2024, 2, 28).__add__(timedelta(1))
210
+ ae(_d_leap.month, 2)
211
+ ae(_d_leap.day, 29)
212
+
213
+ _d_leap2 = date(2024, 2, 29).__add__(timedelta(1))
214
+ ae(_d_leap2.month, 3)
215
+ ae(_d_leap2.day, 1)
216
+
217
+ # ── 14. date comparisons ──────────────────────────────────────────────────────
218
+ # STATUS: ✓ WORKS
219
+
220
+ _da = date(2024, 1, 1)
221
+ _db = date(2024, 1, 15)
222
+ _dc = date(2024, 1, 1)
223
+
224
+ ok(_da.__eq__(_dc))
225
+ ok(not _da.__eq__(_db))
226
+ ok(_da.__lt__(_db))
227
+ ok(not _db.__lt__(_da))
228
+ ok(_da.__le__(_dc))
229
+ ok(_db.__gt__(_da))
230
+ ok(_da.__ge__(_dc))
231
+
232
+ # ── 15. date.replace ─────────────────────────────────────────────────────────
233
+ # STATUS: ✓ WORKS
234
+
235
+ _d_orig = date(2024, 6, 15)
236
+ _d_rep = _d_orig.replace(year=2025)
237
+ ae(_d_rep.year, 2025)
238
+ ae(_d_rep.month, 6)
239
+ ae(_d_rep.day, 15)
240
+
241
+ _d_rep2 = _d_orig.replace(month=12, day=31)
242
+ ae(_d_rep2.year, 2024)
243
+ ae(_d_rep2.month, 12)
244
+ ae(_d_rep2.day, 31)
245
+
246
+ # ── 16. date.strftime ────────────────────────────────────────────────────────
247
+ # STATUS: ✓ WORKS
248
+
249
+ _ds = date(2024, 1, 5)
250
+ ae(_ds.strftime('%Y-%m-%d'), '2024-01-05')
251
+ ae(_ds.strftime('%d/%m/%Y'), '05/01/2024')
252
+ ae(_ds.strftime('%B %d, %Y'), 'January 05, 2024')
253
+ ae(_ds.strftime('%a %b %d'), 'Fri Jan 05')
254
+ ae(_ds.strftime('%%'), '%')
255
+ ae(_ds.strftime('%j'), '005')
256
+
257
+ # ── 17. time construction ─────────────────────────────────────────────────────
258
+ # STATUS: ✓ WORKS
259
+
260
+ _t0 = time(0)
261
+ ae(_t0.hour, 0)
262
+ ae(_t0.minute, 0)
263
+ ae(_t0.second, 0)
264
+ ae(_t0.microsecond, 0)
265
+
266
+ _t1 = time(14, 30, 5, 123456)
267
+ ae(_t1.hour, 14)
268
+ ae(_t1.minute, 30)
269
+ ae(_t1.second, 5)
270
+ ae(_t1.microsecond, 123456)
271
+
272
+ # Min / max
273
+ ae(time.min.hour, 0)
274
+ ae(time.max.hour, 23)
275
+ ae(time.max.minute, 59)
276
+ ae(time.max.second, 59)
277
+ ae(time.max.microsecond, 999999)
278
+
279
+ # ── 18. time.isoformat / str / repr ──────────────────────────────────────────
280
+ # STATUS: ✓ WORKS
281
+
282
+ ae(str(time(0)), '00:00:00')
283
+ ae(str(time(14, 30, 5)), '14:30:05')
284
+ ae(str(time(14, 30, 5, 123456)), '14:30:05.123456')
285
+ ae(time(9).isoformat(), '09:00:00')
286
+ ae(repr(time(14, 30, 5)), 'datetime.time(14, 30, 5)')
287
+ ae(repr(time(14, 30, 5, 123456)), 'datetime.time(14, 30, 5, 123456)')
288
+ ae(repr(time(14)), 'datetime.time(14)')
289
+
290
+ # ── 19. time comparisons ──────────────────────────────────────────────────────
291
+ # STATUS: ✓ WORKS
292
+
293
+ _ta = time(9, 0)
294
+ _tb = time(17, 30)
295
+ _tc = time(9, 0)
296
+
297
+ ok(_ta.__eq__(_tc))
298
+ ok(not _ta.__eq__(_tb))
299
+ ok(_ta.__lt__(_tb))
300
+ ok(_tb.__gt__(_ta))
301
+ ok(_ta.__le__(_tc))
302
+ ok(_tb.__ge__(_tb))
303
+
304
+ # ── 20. time.replace ─────────────────────────────────────────────────────────
305
+ # STATUS: ✓ WORKS
306
+
307
+ _t_orig = time(9, 30, 0)
308
+ _t_rep = _t_orig.replace(hour=17)
309
+ ae(_t_rep.hour, 17)
310
+ ae(_t_rep.minute, 30)
311
+ ae(_t_rep.second, 0)
312
+
313
+ # ── 21. time.strftime ────────────────────────────────────────────────────────
314
+ # STATUS: ✓ WORKS
315
+
316
+ _ts = time(14, 5, 9)
317
+ ae(_ts.strftime('%H:%M:%S'), '14:05:09')
318
+ ae(_ts.strftime('%I %p'), '02 PM')
319
+
320
+ # ── 22. datetime construction ─────────────────────────────────────────────────
321
+ # STATUS: ✓ WORKS
322
+
323
+ _dt = datetime(2024, 1, 15, 9, 30, 45, 123456)
324
+ ae(_dt.year, 2024)
325
+ ae(_dt.month, 1)
326
+ ae(_dt.day, 15)
327
+ ae(_dt.hour, 9)
328
+ ae(_dt.minute, 30)
329
+ ae(_dt.second, 45)
330
+ ae(_dt.microsecond, 123456)
331
+
332
+ # Defaults for time components
333
+ _dt2 = datetime(2024, 6, 1)
334
+ ae(_dt2.hour, 0)
335
+ ae(_dt2.minute, 0)
336
+ ae(_dt2.second, 0)
337
+ ae(_dt2.microsecond, 0)
338
+
339
+ # ── 23. datetime.fromisoformat ───────────────────────────────────────────────
340
+ # STATUS: ✓ WORKS
341
+
342
+ _dti = datetime.fromisoformat('2024-01-15T09:30:45')
343
+ ae(_dti.year, 2024)
344
+ ae(_dti.hour, 9)
345
+ ae(_dti.minute, 30)
346
+ ae(_dti.second, 45)
347
+
348
+ _dti2 = datetime.fromisoformat('2024-01-15 09:30:45.123456')
349
+ ae(_dti2.microsecond, 123456)
350
+
351
+ _dti3 = datetime.fromisoformat('2024-01-15')
352
+ ae(_dti3.hour, 0)
353
+ ae(_dti3.minute, 0)
354
+
355
+ # ── 24. datetime.isoformat / str / repr ──────────────────────────────────────
356
+ # STATUS: ✓ WORKS
357
+
358
+ _dt3 = datetime(2024, 1, 15, 9, 30, 45)
359
+ ae(_dt3.isoformat(), '2024-01-15T09:30:45')
360
+ ae(_dt3.isoformat(' '), '2024-01-15 09:30:45')
361
+ ae(str(_dt3), '2024-01-15 09:30:45')
362
+ ae(repr(_dt3), 'datetime.datetime(2024, 1, 15, 9, 30, 45)')
363
+
364
+ _dt4 = datetime(2024, 1, 15, 9, 30, 45, 123456)
365
+ ae(repr(_dt4), 'datetime.datetime(2024, 1, 15, 9, 30, 45, 123456)')
366
+
367
+ # ── 25. datetime.combine ─────────────────────────────────────────────────────
368
+ # STATUS: ✓ WORKS
369
+
370
+ _dc = datetime.combine(date(2024, 1, 15), time(9, 30))
371
+ ae(_dc.year, 2024)
372
+ ae(_dc.month, 1)
373
+ ae(_dc.day, 15)
374
+ ae(_dc.hour, 9)
375
+ ae(_dc.minute, 30)
376
+
377
+ # ── 26. datetime.date() / datetime.time() ─────────────────────────────────────
378
+ # STATUS: ✓ WORKS
379
+
380
+ _dt5 = datetime(2024, 1, 15, 9, 30, 45)
381
+ _dt5_date = _dt5.date()
382
+ _dt5_time = _dt5.time()
383
+ ok(isinstance(_dt5_date, date))
384
+ ok(not isinstance(_dt5_date, datetime))
385
+ ok(isinstance(_dt5_time, time))
386
+ ae(_dt5_date.year, 2024)
387
+ ae(_dt5_time.hour, 9)
388
+
389
+ # ── 27. datetime arithmetic (direct method calls) ─────────────────────────────
390
+ # STATUS: ✓ WORKS
391
+
392
+ _dt_base = datetime(2024, 1, 15, 12, 0, 0)
393
+
394
+ # + timedelta
395
+ _dt_plus = _dt_base.__add__(timedelta(1))
396
+ ae(_dt_plus.year, 2024)
397
+ ae(_dt_plus.month, 1)
398
+ ae(_dt_plus.day, 16)
399
+ ae(_dt_plus.hour, 12)
400
+
401
+ # - timedelta
402
+ _dt_minus = _dt_base.__sub__(timedelta(0, 3600)) # subtract 1 hour
403
+ ae(_dt_minus.day, 15)
404
+ ae(_dt_minus.hour, 11)
405
+
406
+ # - datetime → timedelta
407
+ _dt_other = datetime(2024, 1, 10, 12, 0, 0)
408
+ _dt_diff = _dt_base.__sub__(_dt_other)
409
+ ok(isinstance(_dt_diff, timedelta))
410
+ ae(_dt_diff.days, 5)
411
+ ae(_dt_diff.seconds, 0)
412
+
413
+ # Cross-midnight arithmetic
414
+ _dt_night = datetime(2024, 1, 15, 23, 30, 0)
415
+ _dt_next = _dt_night.__add__(timedelta(0, 3600)) # +1 hour → next day
416
+ ae(_dt_next.day, 16)
417
+ ae(_dt_next.hour, 0)
418
+ ae(_dt_next.minute, 30)
419
+
420
+ # Cross-month
421
+ _dt_jan31 = datetime(2024, 1, 31, 23, 0, 0)
422
+ _dt_feb1 = _dt_jan31.__add__(timedelta(0, 3600))
423
+ ae(_dt_feb1.month, 2)
424
+ ae(_dt_feb1.day, 1)
425
+ ae(_dt_feb1.hour, 0)
426
+
427
+ # ── 28. datetime comparisons ──────────────────────────────────────────────────
428
+ # STATUS: ✓ WORKS
429
+
430
+ _dta = datetime(2024, 1, 1, 0, 0, 0)
431
+ _dtb = datetime(2024, 1, 1, 0, 0, 1)
432
+ _dtc = datetime(2024, 1, 1, 0, 0, 0)
433
+
434
+ ok(_dta.__eq__(_dtc))
435
+ ok(not _dta.__eq__(_dtb))
436
+ ok(_dta.__lt__(_dtb))
437
+ ok(_dtb.__gt__(_dta))
438
+ ok(_dta.__le__(_dtc))
439
+ ok(_dtb.__ge__(_dtb))
440
+
441
+ # ── 29. datetime.replace ─────────────────────────────────────────────────────
442
+ # STATUS: ✓ WORKS
443
+
444
+ _dt_r = datetime(2024, 1, 15, 9, 30, 0)
445
+ _dt_r2 = _dt_r.replace(hour=17, minute=0)
446
+ ae(_dt_r2.year, 2024)
447
+ ae(_dt_r2.month, 1)
448
+ ae(_dt_r2.day, 15)
449
+ ae(_dt_r2.hour, 17)
450
+ ae(_dt_r2.minute, 0)
451
+
452
+ # ── 30. datetime.strftime ────────────────────────────────────────────────────
453
+ # STATUS: ✓ WORKS
454
+
455
+ _dtf = datetime(2024, 1, 15, 14, 5, 9)
456
+ ae(_dtf.strftime('%Y-%m-%d %H:%M:%S'), '2024-01-15 14:05:09')
457
+ ae(_dtf.strftime('%A, %B %d, %Y'), 'Monday, January 15, 2024')
458
+ ae(_dtf.strftime('%I:%M %p'), '02:05 PM')
459
+
460
+ # ── 31. datetime class min/max/resolution ────────────────────────────────────
461
+ # STATUS: ✓ WORKS
462
+
463
+ ok(isinstance(datetime.min, datetime))
464
+ ok(isinstance(datetime.max, datetime))
465
+ ae(datetime.min.year, MINYEAR)
466
+ ae(datetime.max.year, MAXYEAR)
467
+ ae(datetime.max.hour, 23)
468
+ ae(datetime.max.microsecond, 999999)
469
+
470
+ # ── 32. isinstance and subclass checks ───────────────────────────────────────
471
+ # STATUS: ✓ WORKS
472
+
473
+ ok(isinstance(date(2024, 1, 1), date))
474
+ ok(isinstance(datetime(2024, 1, 1), date)) # datetime IS-A date
475
+ ok(isinstance(datetime(2024, 1, 1), datetime))
476
+ ok(not isinstance(date(2024, 1, 1), datetime)) # date is NOT-A datetime
477
+ ok(isinstance(time(12, 0), time))
478
+ ok(isinstance(timedelta(1), timedelta))
479
+
480
+ # ── 33. date.ctime ───────────────────────────────────────────────────────────
481
+ # STATUS: ✓ WORKS
482
+
483
+ ae(date(2024, 1, 15).ctime(), 'Mon Jan 15 00:00:00 2024')
484
+
485
+ # ── 34. datetime.ctime ───────────────────────────────────────────────────────
486
+ # STATUS: ✓ WORKS
487
+
488
+ ae(datetime(2024, 1, 15, 9, 5, 3).ctime(), 'Mon Jan 15 09:05:03 2024')
489
+
490
+ # ── 35. Validation errors ────────────────────────────────────────────────────
491
+ # STATUS: ✓ WORKS
492
+ # assrt.throws(fn) returns undefined on success; call it directly (not ok-wrapped)
493
+
494
+ throws(def(): date(0, 1, 1);) # year < MINYEAR
495
+ throws(def(): date(2024, 0, 1);) # month < 1
496
+ throws(def(): date(2024, 13, 1);) # month > 12
497
+ throws(def(): date(2023, 2, 29);) # Feb 29 in non-leap year
498
+ throws(def(): time(24, 0, 0);) # hour > 23
499
+ throws(def(): time(0, 60, 0);) # minute > 59
500
+ throws(def(): datetime(2024, 1, 1, 0, 0, 60);) # second > 59
@@ -0,0 +1,41 @@
1
+ # vim:fileencoding=utf-8
2
+ # globals: assrt
3
+
4
+ ae = assrt.equal
5
+ ok = assrt.ok
6
+
7
+ # debugger statement is a no-op when no debugger is attached; verify it
8
+ # compiles and executes without throwing
9
+
10
+ before = 1
11
+ debugger
12
+ after = 2
13
+
14
+ ae(before, 1)
15
+ ae(after, 2)
16
+
17
+ # inside a function
18
+ def fn_with_debugger():
19
+ x = 10
20
+ debugger
21
+ return x
22
+
23
+ ae(fn_with_debugger(), 10)
24
+
25
+ # inside a loop
26
+ total = 0
27
+ for i in range(3):
28
+ debugger
29
+ total += i
30
+
31
+ ae(total, 3)
32
+
33
+ # inside a conditional
34
+ def conditional_debugger(flag):
35
+ if flag:
36
+ debugger
37
+ return True
38
+ return False
39
+
40
+ ae(conditional_debugger(True), True)
41
+ ae(conditional_debugger(False), False)
@@ -1,77 +1,77 @@
1
- # vim:fileencoding=utf-8
2
- # License: BSD Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
3
-
4
- def double(f):
5
- return def (x):
6
- return 2 * f(x)
7
-
8
- def triple(f):
9
- return def(x):
10
- return 3 * f(x)
11
-
12
- @double
13
- def half(x):
14
- return x // 2
15
-
16
- @double
17
- def f1(x):
18
- return x
19
-
20
- @double
21
- @triple
22
- def f2(x):
23
- return x
24
-
25
- def append_one(f):
26
- return def(x):
27
- ans = f(x)
28
- ans.push(1)
29
- return ans
30
-
31
- def append_two(f):
32
- return def(x):
33
- ans = f(x)
34
- ans.push(2)
35
- return ans
36
-
37
- @append_two
38
- @append_one
39
- def f3():
40
- return []
41
-
42
- o = {'double':double}
43
-
44
- @o.double
45
- def f4():
46
- return 1
47
-
48
- assrt.equal(2, half(2))
49
- assrt.equal(4, f1(2))
50
- assrt.equal(12, f2(2))
51
- assrt.equal(2, f4())
52
- assrt.deepEqual([1, 2], f3())
53
-
54
- def multiply(amt):
55
-
56
- def wrapper(f):
57
- return def ():
58
- return amt * f()
59
-
60
- return wrapper
61
-
62
- @multiply(2)
63
- def two():
64
- return 1
65
-
66
- @multiply(3)
67
- def three():
68
- return 1
69
-
70
- @multiply(2)
71
- @multiply(2)
72
- def four():
73
- return 1
74
-
75
- assrt.equal(2, two())
76
- assrt.equal(3, three())
77
- assrt.equal(4, four())
1
+ # vim:fileencoding=utf-8
2
+ # License: BSD Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
3
+
4
+ def double(f):
5
+ return def (x):
6
+ return 2 * f(x)
7
+
8
+ def triple(f):
9
+ return def(x):
10
+ return 3 * f(x)
11
+
12
+ @double
13
+ def half(x):
14
+ return x // 2
15
+
16
+ @double
17
+ def f1(x):
18
+ return x
19
+
20
+ @double
21
+ @triple
22
+ def f2(x):
23
+ return x
24
+
25
+ def append_one(f):
26
+ return def(x):
27
+ ans = f(x)
28
+ ans.push(1)
29
+ return ans
30
+
31
+ def append_two(f):
32
+ return def(x):
33
+ ans = f(x)
34
+ ans.push(2)
35
+ return ans
36
+
37
+ @append_two
38
+ @append_one
39
+ def f3():
40
+ return []
41
+
42
+ o = {'double':double}
43
+
44
+ @o.double
45
+ def f4():
46
+ return 1
47
+
48
+ assrt.equal(2, half(2))
49
+ assrt.equal(4, f1(2))
50
+ assrt.equal(12, f2(2))
51
+ assrt.equal(2, f4())
52
+ assrt.deepEqual([1, 2], f3())
53
+
54
+ def multiply(amt):
55
+
56
+ def wrapper(f):
57
+ return def ():
58
+ return amt * f()
59
+
60
+ return wrapper
61
+
62
+ @multiply(2)
63
+ def two():
64
+ return 1
65
+
66
+ @multiply(3)
67
+ def three():
68
+ return 1
69
+
70
+ @multiply(2)
71
+ @multiply(2)
72
+ def four():
73
+ return 1
74
+
75
+ assrt.equal(2, two())
76
+ assrt.equal(3, three())
77
+ assrt.equal(4, four())