rapydscript-ns 0.8.4 → 0.9.1

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 (141) 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 +26 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/README.md +716 -169
  8. package/TODO.md +7 -2
  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 +36 -27
  15. package/package.json +1 -1
  16. package/publish.py +37 -37
  17. package/release/baselib-plain-pretty.js +2358 -168
  18. package/release/baselib-plain-ugly.js +73 -3
  19. package/release/compiler.js +6283 -3093
  20. package/release/signatures.json +31 -30
  21. package/session.vim +4 -4
  22. package/setup.cfg +2 -2
  23. package/src/ast.pyj +1 -0
  24. package/src/baselib-builtins.pyj +340 -2
  25. package/src/baselib-bytes.pyj +664 -0
  26. package/src/baselib-errors.pyj +1 -1
  27. package/src/baselib-internal.pyj +267 -60
  28. package/src/baselib-itertools.pyj +110 -97
  29. package/src/baselib-str.pyj +22 -4
  30. package/src/compiler.pyj +36 -36
  31. package/src/errors.pyj +30 -30
  32. package/src/lib/abc.pyj +317 -0
  33. package/src/lib/aes.pyj +646 -646
  34. package/src/lib/contextlib.pyj +379 -0
  35. package/src/lib/copy.pyj +120 -120
  36. package/src/lib/dataclasses.pyj +532 -0
  37. package/src/lib/datetime.pyj +712 -0
  38. package/src/lib/elementmaker.pyj +83 -83
  39. package/src/lib/encodings.pyj +126 -126
  40. package/src/lib/enum.pyj +125 -0
  41. package/src/lib/gettext.pyj +569 -569
  42. package/src/lib/io.pyj +500 -0
  43. package/src/lib/itertools.pyj +580 -580
  44. package/src/lib/json.pyj +227 -0
  45. package/src/lib/math.pyj +193 -193
  46. package/src/lib/operator.pyj +11 -11
  47. package/src/lib/pythonize.pyj +20 -20
  48. package/src/lib/random.pyj +118 -118
  49. package/src/lib/re.pyj +504 -470
  50. package/src/lib/react.pyj +74 -74
  51. package/src/lib/traceback.pyj +63 -63
  52. package/src/lib/typing.pyj +577 -0
  53. package/src/lib/uuid.pyj +77 -77
  54. package/src/monaco-language-service/builtins.js +14 -4
  55. package/src/monaco-language-service/diagnostics.js +19 -20
  56. package/src/monaco-language-service/dts.js +550 -550
  57. package/src/output/classes.pyj +62 -26
  58. package/src/output/comments.pyj +45 -45
  59. package/src/output/exceptions.pyj +201 -201
  60. package/src/output/functions.pyj +78 -5
  61. package/src/output/jsx.pyj +164 -164
  62. package/src/output/loops.pyj +5 -2
  63. package/src/output/operators.pyj +100 -34
  64. package/src/output/treeshake.pyj +182 -182
  65. package/src/output/utils.pyj +72 -72
  66. package/src/parse.pyj +80 -16
  67. package/src/string_interpolation.pyj +72 -72
  68. package/src/tokenizer.pyj +10 -5
  69. package/src/unicode_aliases.pyj +576 -576
  70. package/src/utils.pyj +192 -192
  71. package/test/_import_one.pyj +37 -37
  72. package/test/_import_two/__init__.pyj +11 -11
  73. package/test/_import_two/level2/deep.pyj +4 -4
  74. package/test/_import_two/other.pyj +6 -6
  75. package/test/_import_two/sub.pyj +13 -13
  76. package/test/abc.pyj +291 -0
  77. package/test/aes_vectors.pyj +421 -421
  78. package/test/annotations.pyj +80 -80
  79. package/test/arithmetic_nostrict.pyj +88 -0
  80. package/test/arithmetic_types.pyj +169 -0
  81. package/test/baselib.pyj +91 -0
  82. package/test/bytes.pyj +467 -0
  83. package/test/classes.pyj +1 -0
  84. package/test/comparison_ops.pyj +173 -0
  85. package/test/contextlib.pyj +362 -0
  86. package/test/dataclasses.pyj +253 -0
  87. package/test/datetime.pyj +500 -0
  88. package/test/debugger_stmt.pyj +41 -0
  89. package/test/decorators.pyj +77 -77
  90. package/test/docstrings.pyj +39 -39
  91. package/test/elementmaker_test.pyj +45 -45
  92. package/test/enum.pyj +134 -0
  93. package/test/eval_exec.pyj +56 -0
  94. package/test/format.pyj +148 -0
  95. package/test/functions.pyj +151 -151
  96. package/test/generators.pyj +41 -41
  97. package/test/generic.pyj +370 -370
  98. package/test/imports.pyj +72 -72
  99. package/test/internationalization.pyj +73 -73
  100. package/test/io.pyj +316 -0
  101. package/test/json.pyj +196 -0
  102. package/test/lint.pyj +164 -164
  103. package/test/loops.pyj +85 -85
  104. package/test/numpy.pyj +734 -734
  105. package/test/object.pyj +64 -0
  106. package/test/omit_function_metadata.pyj +20 -20
  107. package/test/python_compat.pyj +17 -15
  108. package/test/python_features.pyj +70 -15
  109. package/test/regexp.pyj +83 -55
  110. package/test/repl.pyj +121 -121
  111. package/test/scoped_flags.pyj +76 -76
  112. package/test/tuples.pyj +96 -0
  113. package/test/typing.pyj +469 -0
  114. package/test/unit/index.js +116 -7
  115. package/test/unit/language-service-dts.js +543 -543
  116. package/test/unit/language-service-hover.js +455 -455
  117. package/test/unit/language-service.js +84 -0
  118. package/test/unit/web-repl.js +1337 -1
  119. package/test/vars_locals_globals.pyj +94 -0
  120. package/tools/cli.js +558 -547
  121. package/tools/compile.js +224 -219
  122. package/tools/completer.js +131 -131
  123. package/tools/embedded_compiler.js +262 -251
  124. package/tools/gettext.js +185 -185
  125. package/tools/ini.js +65 -65
  126. package/tools/lint.js +16 -19
  127. package/tools/msgfmt.js +187 -187
  128. package/tools/repl.js +223 -223
  129. package/tools/test.js +118 -118
  130. package/tools/utils.js +128 -128
  131. package/tools/web_repl.js +95 -95
  132. package/try +41 -41
  133. package/web-repl/env.js +196 -196
  134. package/web-repl/index.html +163 -163
  135. package/web-repl/main.js +252 -252
  136. package/web-repl/prism.css +139 -139
  137. package/web-repl/prism.js +113 -113
  138. package/web-repl/rapydscript.js +224 -224
  139. package/web-repl/sha1.js +25 -25
  140. package/PYTHON_DIFFERENCES_REPORT.md +0 -291
  141. package/PYTHON_FEATURE_COVERAGE.md +0 -200
@@ -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())