istr-python 1.1.6__tar.gz → 1.1.8__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: istr-python
3
- Version: 1.1.6
3
+ Version: 1.1.8
4
4
  Summary: istr - strings you can count on
5
5
  Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/salabim/istr
@@ -8,7 +8,7 @@ Project-URL: Repository, https://github.com/salabim/istr
8
8
  Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Programming Language :: Python :: 3 :: Only
11
- Requires-Python: >=3.7
11
+ Requires-Python: >=3.8
12
12
  Description-Content-Type: text/markdown
13
13
 
14
14
  <img src="https://www.salabim.org/istr/istr_logo.png" width=500>
@@ -31,20 +31,33 @@ can be nicely, albeit not very efficient, coded as:
31
31
  import istr
32
32
 
33
33
  for s, e, n, d, m, o, r, y in istr.permutations(range(10), 8):
34
- if m and ((s|e|n|d) + (m|o|r|e) == (m|o|n|e|y)):
34
+ if m and ((s|e|n|d) + (m|o|r|e) == (m|o|n|e|y):
35
35
  print(f' {s|e|n|d}')
36
36
  print(f' {m|o|r|e}')
37
37
  print('-----')
38
38
  print(f'{m|o|n|e|y}')
39
39
  ```
40
40
 
41
+ or even
42
+
43
+ ```
44
+ import istr
45
+
46
+ for S, E, N, D, M, O, R, Y in istr.permutations(range(10), 8):
47
+ if m and (istr.compose("SEND") + ist.compose("MORE") == istr.compose("MONEY"):
48
+ print(" ",istr.compose("SEND"))
49
+ print(" ",istr.compose("MORE"))
50
+ print('-----')
51
+ print(istr.compose("MONEY"))
52
+ ```
53
+
41
54
  Of, if we want to add all the digits in a string:
42
55
 
43
56
  ```
44
57
  sum_digits = sum(istr('9282334')) # answer 31
45
58
  ```
46
59
 
47
- And the module is a demonstration of extending a class (str) with extra and changed functionality.
60
+ The module is a demonstration of extending a class (str) with additional and modified functionality.
48
61
 
49
62
  ### Installation
50
63
  Installing istr with pip is easy.
@@ -55,7 +68,7 @@ or when you want to upgrade,
55
68
  ```
56
69
  pip install istr-python --upgrade
57
70
  ```
58
- Alternatively, istr.py can be just copied into you current work directory from GitHub (https://github.com/salabim/istr).
71
+ Alternatively, istr.py can be just copied into your current work directory from GitHub (https://github.com/salabim/istr).
59
72
 
60
73
  No dependencies!
61
74
 
@@ -156,16 +169,16 @@ four, five = istr(4, 5)
156
169
  ```
157
170
 
158
171
  ##### Important
159
- >All calculations are strictly integer calculations. That means that if a float or decimal variable is ever produced it will be converted to an int.
160
- > Also divisions are always floor divisions!
172
+ >All calculations are strictly integer calculations. That means that if a float or decimal variable is ever produced, it will be converted to an int.
173
+ > Also, divisions are always floor divisions!
161
174
 
162
175
  #### Use istr as a string
163
176
 
164
177
  We should realize that istrs are in fact strings.
165
178
 
166
- In order to concatenate two istrs (or an istr and a str), we cannot use the `+` operator (remember `four + five` is `istr('9')`).
179
+ To concatenate two istrs (or an istr and a str), we cannot use the `+` operator (remember `four + five` is `istr('9')`).
167
180
 
168
- In order to concatenate istrs, we use the or operator (`|`). So
181
+ To concatenate strings, we use the or operator (`|`). So
169
182
 
170
183
  ```
171
184
  four | five
@@ -178,9 +191,9 @@ And
178
191
  ```
179
192
  is `istr('9')`.
180
193
 
181
- In order to repeat a string in the usual sense, you cannot use the `*` operator (remember `3 * four` is `istr('12')`.
194
+ To repeat a string in the usual sense, you cannot use the `*` operator (remember `3 * four` is `istr('12')`.
182
195
 
183
- In order to repeat we use the matrix multiplication operator (`@`). So
196
+ To repeat, we use the matrix multiplication operator (`@`). So
184
197
 
185
198
  `3 @ four`
186
199
 
@@ -199,7 +212,7 @@ is also `istr('444')`
199
212
  #### istr that can't be interpreted as an int
200
213
 
201
214
 
202
- Although usualy istrs are to be interpreted as an int, that's not a requirement.
215
+ Although usually istrs are to be interpreted as an int, that's not a requirement.
203
216
 
204
217
  So
205
218
 
@@ -215,7 +228,7 @@ istr('1,2,3')
215
228
 
216
229
  are perfectly acceptable.
217
230
 
218
- But, we can't do any arithmetic or comparison with them.
231
+ However, we cannot perform any arithmetic or comparison operations with them.
219
232
 
220
233
  If we try
221
234
 
@@ -295,9 +308,9 @@ several other types:
295
308
 
296
309
 
297
310
  - if a dict (or subtype of dict), the same type dict will be returned with all *values* istr'ed
298
- ```
311
+ ```
299
312
  istr({'one': 1, 'two':2}) ==> {'one': istr('1'), 'two': istr('2')}
300
- ```
313
+ ```
301
314
 
302
315
  - if an iterator, the iterator will be mapped with istr
303
316
  ```
@@ -313,11 +326,11 @@ several other types:
313
326
 
314
327
  - if an iterable, the same type will be returned with all elements istr'ed
315
328
 
316
- ```
329
+ ```
317
330
  istr([0, 1, 4]) ==> [istr('0'), istr('1'), istr('4')]
318
331
  istr((0, 1, 4)) ==> (istr('0'), istr('1'), istr('4'))
319
332
  istr({0, 1, 4}) ==> `{istr('4'), istr('0'), istr('1')} # or similar
320
- ```
333
+ ```
321
334
 
322
335
  - if a range, an istr.range instance will be returned
323
336
 
@@ -328,26 +341,25 @@ several other types:
328
341
  ```
329
342
 
330
343
  - if an istr.range instance, the same istr.range will be returned
331
- ```
344
+ ```
332
345
  istr(istr.range(5)) ==> istr.range(5)
333
- ```
346
+ ```
334
347
 
335
348
 
336
349
  - if an istr, the same istr will be returned
337
350
 
338
- ```
339
- istr(istr('4')) ==> istr ('4')
340
- ```
351
+ ```
352
+ istr(istr('4')) ==> istr ('4')
353
+ ```
341
354
 
342
355
  #### More than one parameter for istr
343
356
  It is possible to give more than one parameter, in which case a tuple
344
357
  of the istrs of the parameters will be returned, which can be handy
345
358
  to unpack multiple values, e.g.
346
359
 
347
- ```
360
+ ```
348
361
  a, b, c = istr(5, 6, 7) ==> a=istr('5') , b=istr('6'), c=istr('7')
349
- ```
350
-
362
+ ```
351
363
  #### test for even/odd
352
364
  It is possible to test for even/odd (provided the istr can be interpreted as an int) with the `is_even` and `is_odd` method, e.g.
353
365
 
@@ -360,6 +372,21 @@ It is also possible to test for even/odd of an ordinary int:
360
372
  istr.is_even(4) ==> True
361
373
  istr.is_odd(5) ==> True
362
374
  ```
375
+ #### test for divisibility
376
+
377
+ It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
378
+
379
+ ```
380
+ istr(18).is_divisible_by(3) ==> True
381
+ istr(18).is_divisible_by(istr(3)) ==> True
382
+ istr(19).is_divisible_by(3) ==> False
383
+ istr(19).is_divisible_by(istr(3)) == False
384
+ ```
385
+ It is also possible to test for divisibility of an ordinary int:
386
+ ```
387
+ istr.is_divisible(18, 3) ==> True
388
+ istr.is_divisible(19, 3) ==> False
389
+ ```
363
390
  #### test for square
364
391
 
365
392
  It is possible to test whether the value is a perfect square (provided the istr can be interpreted as an int) with the `is_square` method, e.g.
@@ -415,21 +442,6 @@ It is also possible to test for prime of an ordinary int:
415
442
  istr.is_prime(4) ==> False
416
443
  istr.is_prime(5) ==> True
417
444
  ```
418
- #### test for divisibility
419
-
420
- It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
421
-
422
- ```
423
- istr(18).is_divisible_by(3) ==> True
424
- istr(18).is_divisible_by(istr(3)) ==> True
425
- istr(19).is_divisible_by(3) ==> False
426
- istr(19).is_divisible_by(istr(3)) == False
427
- ```
428
- It is also possible to test for divisibility of an ordinary int:
429
- ```
430
- istr.is_divisible(18, 3) ==> True
431
- istr.is_divisible(19, 3) ==> False
432
- ```
433
445
  #### test whether all characters are distinct
434
446
 
435
447
  With the `all_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
@@ -450,7 +462,7 @@ The method `reversed()` will return an istr with the reversed content:
450
462
  istr(456).reversed() ==> istr('654')
451
463
  istr('0456').reversed() ==> istr('6540')
452
464
  ```
453
- The same can -of course- be achieved with
465
+ The same can, of course, be achieved with
454
466
  ```
455
467
  istr(456)[::-1] ==> istr('654')
456
468
  istr('0456')[::-1] ==> istr('6540')
@@ -597,6 +609,12 @@ istr(485).decompose("abc")
597
609
  will set the global variables `a`, `b` and `c` to be set to `istr(4)`. `istr(8)` and` istr(5)`.
598
610
  Note that the length of the letters specifier must be the same as the length of the istr. Furthermore, multiple values for the same variables result in a ValueError.
599
611
 
612
+ To decompose an istr into individual variables, it is arguably easier and safer to unpack the istr, like
613
+
614
+ ```
615
+ a, b, c = istr(485)
616
+ ```
617
+
600
618
  With `istr.compose()`, an istr can be constructed from individual (global) variables.
601
619
  E.g.
602
620
 
@@ -778,7 +796,7 @@ istr('1234')
778
796
 
779
797
  ### Overview of operations
780
798
 
781
- The table below shows whether the string or the int version of istr is applied.
799
+ The table below indicates whether the string or integer version of istr is applied.
782
800
 
783
801
  ```
784
802
  operator/function int str Example
@@ -786,31 +804,30 @@ operator/function int str Example
786
804
  + x istr(20) + 3 ==> istr('23')
787
805
  _ x istr(20) - 3 ==> istr('17')
788
806
  * x istr(20) * 3 ==> istr('60')
789
- / x istr(20) / 3 ==> istr('6')
790
- // x istr(20) // 3 ==> istr('6')
791
- % x istr(20) % 3 ==> istr('2')
792
- divmod x divmod(istr(20), 3) ==> (istr('6'), istr('2'))
793
- ** x istr(2) ** 3 ==> istr('8')
794
- <=, <, >, >= x istr('100') > istr('2') ==> True
795
- abs x abs(istr(-20)) ==> istr('20')
796
- == x x istr(20) == 20 ==> True | istr(20) == '20' ==> True
797
- bool x x *) bool(istr(' 0 ')) ==> False | istr('') ==> False
798
- @ x istr(20) @ 3 ==> istr('202020')
799
- | x istr(20) | '5' ==> istr('205')
800
- slicing x istr(12345)[1:3] ==> istr('23')
801
- iterate x [x for x in istr(20)] ==> [istr('2'), istr('0')]
802
- len x len(istr(' 20 ')) ==> 4
803
- count x istr(100).count('0') ==> 2
804
- index x istr(' 100 ').index('0') ==> 2
805
- split x istr('1 2').split() ==> (istr('1'), istr('2'))
806
- string format x f"|{istr(1234):6}|" ==> '|1234 |'
807
- other string methods x istr('aAbBcC').lower() ==> istr('aabbcc')
807
+ / x istr(20) / 3 ==> istr('6')
808
+ // x istr(20) // 3 ==> istr('6')
809
+ % x istr(20) % 3 ==> istr('2')
810
+ divmod x divmod(istr(20), 3) ==> (istr('6'), istr('2'))
811
+ ** x istr(2) ** 3 ==> istr('8')
812
+ <=, <, >, >= x istr('100') > istr('2') ==> True
813
+ abs x abs(istr(-20)) ==> istr('20')
814
+ == x x istr(20) == 20 ==> True | istr(20) == '20' ==> True
815
+ bool x x *) bool(istr(' 0 ')) ==> False | bool(istr('')) ==> False
816
+ @ x istr(20) @ 3 ==> istr('202020')
817
+ | x istr(20) | '5' ==> istr('205')
818
+ slicing x istr(12345)[1:3] ==> istr('23')
819
+ iterate x [x for x in istr(20)] ==> [istr('2'), istr('0')]
820
+ len x len(istr(' 20 ')) ==> 4
821
+ count x istr(100).count('0') ==> 2
822
+ index x istr(' 100 ').index('0') ==> 2
823
+ split x istr('1 2').split() ==> (istr('1'), istr('2'))
824
+ string format x f"|{istr(1234):6}|" ==> '|1234 |'
825
+ other string methods x istr('aAbBcC').lower() ==> istr('aabbcc')
808
826
  istr('aAbBcC').islower() ==> False
809
827
  istr(' abc ').strip() ==> istr('abc')
810
828
  ...
811
829
  -----------------------------------------------------------------------------------------
812
830
  *) str is applied if is_int() is False
813
-
814
831
  ```
815
832
  ### Test script
816
833
  There's an extensive pytest script in the `\tests` directory.
@@ -18,20 +18,33 @@ can be nicely, albeit not very efficient, coded as:
18
18
  import istr
19
19
 
20
20
  for s, e, n, d, m, o, r, y in istr.permutations(range(10), 8):
21
- if m and ((s|e|n|d) + (m|o|r|e) == (m|o|n|e|y)):
21
+ if m and ((s|e|n|d) + (m|o|r|e) == (m|o|n|e|y):
22
22
  print(f' {s|e|n|d}')
23
23
  print(f' {m|o|r|e}')
24
24
  print('-----')
25
25
  print(f'{m|o|n|e|y}')
26
26
  ```
27
27
 
28
+ or even
29
+
30
+ ```
31
+ import istr
32
+
33
+ for S, E, N, D, M, O, R, Y in istr.permutations(range(10), 8):
34
+ if m and (istr.compose("SEND") + ist.compose("MORE") == istr.compose("MONEY"):
35
+ print(" ",istr.compose("SEND"))
36
+ print(" ",istr.compose("MORE"))
37
+ print('-----')
38
+ print(istr.compose("MONEY"))
39
+ ```
40
+
28
41
  Of, if we want to add all the digits in a string:
29
42
 
30
43
  ```
31
44
  sum_digits = sum(istr('9282334')) # answer 31
32
45
  ```
33
46
 
34
- And the module is a demonstration of extending a class (str) with extra and changed functionality.
47
+ The module is a demonstration of extending a class (str) with additional and modified functionality.
35
48
 
36
49
  ### Installation
37
50
  Installing istr with pip is easy.
@@ -42,7 +55,7 @@ or when you want to upgrade,
42
55
  ```
43
56
  pip install istr-python --upgrade
44
57
  ```
45
- Alternatively, istr.py can be just copied into you current work directory from GitHub (https://github.com/salabim/istr).
58
+ Alternatively, istr.py can be just copied into your current work directory from GitHub (https://github.com/salabim/istr).
46
59
 
47
60
  No dependencies!
48
61
 
@@ -143,16 +156,16 @@ four, five = istr(4, 5)
143
156
  ```
144
157
 
145
158
  ##### Important
146
- >All calculations are strictly integer calculations. That means that if a float or decimal variable is ever produced it will be converted to an int.
147
- > Also divisions are always floor divisions!
159
+ >All calculations are strictly integer calculations. That means that if a float or decimal variable is ever produced, it will be converted to an int.
160
+ > Also, divisions are always floor divisions!
148
161
 
149
162
  #### Use istr as a string
150
163
 
151
164
  We should realize that istrs are in fact strings.
152
165
 
153
- In order to concatenate two istrs (or an istr and a str), we cannot use the `+` operator (remember `four + five` is `istr('9')`).
166
+ To concatenate two istrs (or an istr and a str), we cannot use the `+` operator (remember `four + five` is `istr('9')`).
154
167
 
155
- In order to concatenate istrs, we use the or operator (`|`). So
168
+ To concatenate strings, we use the or operator (`|`). So
156
169
 
157
170
  ```
158
171
  four | five
@@ -165,9 +178,9 @@ And
165
178
  ```
166
179
  is `istr('9')`.
167
180
 
168
- In order to repeat a string in the usual sense, you cannot use the `*` operator (remember `3 * four` is `istr('12')`.
181
+ To repeat a string in the usual sense, you cannot use the `*` operator (remember `3 * four` is `istr('12')`.
169
182
 
170
- In order to repeat we use the matrix multiplication operator (`@`). So
183
+ To repeat, we use the matrix multiplication operator (`@`). So
171
184
 
172
185
  `3 @ four`
173
186
 
@@ -186,7 +199,7 @@ is also `istr('444')`
186
199
  #### istr that can't be interpreted as an int
187
200
 
188
201
 
189
- Although usualy istrs are to be interpreted as an int, that's not a requirement.
202
+ Although usually istrs are to be interpreted as an int, that's not a requirement.
190
203
 
191
204
  So
192
205
 
@@ -202,7 +215,7 @@ istr('1,2,3')
202
215
 
203
216
  are perfectly acceptable.
204
217
 
205
- But, we can't do any arithmetic or comparison with them.
218
+ However, we cannot perform any arithmetic or comparison operations with them.
206
219
 
207
220
  If we try
208
221
 
@@ -282,9 +295,9 @@ several other types:
282
295
 
283
296
 
284
297
  - if a dict (or subtype of dict), the same type dict will be returned with all *values* istr'ed
285
- ```
298
+ ```
286
299
  istr({'one': 1, 'two':2}) ==> {'one': istr('1'), 'two': istr('2')}
287
- ```
300
+ ```
288
301
 
289
302
  - if an iterator, the iterator will be mapped with istr
290
303
  ```
@@ -300,11 +313,11 @@ several other types:
300
313
 
301
314
  - if an iterable, the same type will be returned with all elements istr'ed
302
315
 
303
- ```
316
+ ```
304
317
  istr([0, 1, 4]) ==> [istr('0'), istr('1'), istr('4')]
305
318
  istr((0, 1, 4)) ==> (istr('0'), istr('1'), istr('4'))
306
319
  istr({0, 1, 4}) ==> `{istr('4'), istr('0'), istr('1')} # or similar
307
- ```
320
+ ```
308
321
 
309
322
  - if a range, an istr.range instance will be returned
310
323
 
@@ -315,26 +328,25 @@ several other types:
315
328
  ```
316
329
 
317
330
  - if an istr.range instance, the same istr.range will be returned
318
- ```
331
+ ```
319
332
  istr(istr.range(5)) ==> istr.range(5)
320
- ```
333
+ ```
321
334
 
322
335
 
323
336
  - if an istr, the same istr will be returned
324
337
 
325
- ```
326
- istr(istr('4')) ==> istr ('4')
327
- ```
338
+ ```
339
+ istr(istr('4')) ==> istr ('4')
340
+ ```
328
341
 
329
342
  #### More than one parameter for istr
330
343
  It is possible to give more than one parameter, in which case a tuple
331
344
  of the istrs of the parameters will be returned, which can be handy
332
345
  to unpack multiple values, e.g.
333
346
 
334
- ```
347
+ ```
335
348
  a, b, c = istr(5, 6, 7) ==> a=istr('5') , b=istr('6'), c=istr('7')
336
- ```
337
-
349
+ ```
338
350
  #### test for even/odd
339
351
  It is possible to test for even/odd (provided the istr can be interpreted as an int) with the `is_even` and `is_odd` method, e.g.
340
352
 
@@ -347,6 +359,21 @@ It is also possible to test for even/odd of an ordinary int:
347
359
  istr.is_even(4) ==> True
348
360
  istr.is_odd(5) ==> True
349
361
  ```
362
+ #### test for divisibility
363
+
364
+ It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
365
+
366
+ ```
367
+ istr(18).is_divisible_by(3) ==> True
368
+ istr(18).is_divisible_by(istr(3)) ==> True
369
+ istr(19).is_divisible_by(3) ==> False
370
+ istr(19).is_divisible_by(istr(3)) == False
371
+ ```
372
+ It is also possible to test for divisibility of an ordinary int:
373
+ ```
374
+ istr.is_divisible(18, 3) ==> True
375
+ istr.is_divisible(19, 3) ==> False
376
+ ```
350
377
  #### test for square
351
378
 
352
379
  It is possible to test whether the value is a perfect square (provided the istr can be interpreted as an int) with the `is_square` method, e.g.
@@ -402,21 +429,6 @@ It is also possible to test for prime of an ordinary int:
402
429
  istr.is_prime(4) ==> False
403
430
  istr.is_prime(5) ==> True
404
431
  ```
405
- #### test for divisibility
406
-
407
- It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
408
-
409
- ```
410
- istr(18).is_divisible_by(3) ==> True
411
- istr(18).is_divisible_by(istr(3)) ==> True
412
- istr(19).is_divisible_by(3) ==> False
413
- istr(19).is_divisible_by(istr(3)) == False
414
- ```
415
- It is also possible to test for divisibility of an ordinary int:
416
- ```
417
- istr.is_divisible(18, 3) ==> True
418
- istr.is_divisible(19, 3) ==> False
419
- ```
420
432
  #### test whether all characters are distinct
421
433
 
422
434
  With the `all_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
@@ -437,7 +449,7 @@ The method `reversed()` will return an istr with the reversed content:
437
449
  istr(456).reversed() ==> istr('654')
438
450
  istr('0456').reversed() ==> istr('6540')
439
451
  ```
440
- The same can -of course- be achieved with
452
+ The same can, of course, be achieved with
441
453
  ```
442
454
  istr(456)[::-1] ==> istr('654')
443
455
  istr('0456')[::-1] ==> istr('6540')
@@ -584,6 +596,12 @@ istr(485).decompose("abc")
584
596
  will set the global variables `a`, `b` and `c` to be set to `istr(4)`. `istr(8)` and` istr(5)`.
585
597
  Note that the length of the letters specifier must be the same as the length of the istr. Furthermore, multiple values for the same variables result in a ValueError.
586
598
 
599
+ To decompose an istr into individual variables, it is arguably easier and safer to unpack the istr, like
600
+
601
+ ```
602
+ a, b, c = istr(485)
603
+ ```
604
+
587
605
  With `istr.compose()`, an istr can be constructed from individual (global) variables.
588
606
  E.g.
589
607
 
@@ -765,7 +783,7 @@ istr('1234')
765
783
 
766
784
  ### Overview of operations
767
785
 
768
- The table below shows whether the string or the int version of istr is applied.
786
+ The table below indicates whether the string or integer version of istr is applied.
769
787
 
770
788
  ```
771
789
  operator/function int str Example
@@ -773,31 +791,30 @@ operator/function int str Example
773
791
  + x istr(20) + 3 ==> istr('23')
774
792
  _ x istr(20) - 3 ==> istr('17')
775
793
  * x istr(20) * 3 ==> istr('60')
776
- / x istr(20) / 3 ==> istr('6')
777
- // x istr(20) // 3 ==> istr('6')
778
- % x istr(20) % 3 ==> istr('2')
779
- divmod x divmod(istr(20), 3) ==> (istr('6'), istr('2'))
780
- ** x istr(2) ** 3 ==> istr('8')
781
- <=, <, >, >= x istr('100') > istr('2') ==> True
782
- abs x abs(istr(-20)) ==> istr('20')
783
- == x x istr(20) == 20 ==> True | istr(20) == '20' ==> True
784
- bool x x *) bool(istr(' 0 ')) ==> False | istr('') ==> False
785
- @ x istr(20) @ 3 ==> istr('202020')
786
- | x istr(20) | '5' ==> istr('205')
787
- slicing x istr(12345)[1:3] ==> istr('23')
788
- iterate x [x for x in istr(20)] ==> [istr('2'), istr('0')]
789
- len x len(istr(' 20 ')) ==> 4
790
- count x istr(100).count('0') ==> 2
791
- index x istr(' 100 ').index('0') ==> 2
792
- split x istr('1 2').split() ==> (istr('1'), istr('2'))
793
- string format x f"|{istr(1234):6}|" ==> '|1234 |'
794
- other string methods x istr('aAbBcC').lower() ==> istr('aabbcc')
794
+ / x istr(20) / 3 ==> istr('6')
795
+ // x istr(20) // 3 ==> istr('6')
796
+ % x istr(20) % 3 ==> istr('2')
797
+ divmod x divmod(istr(20), 3) ==> (istr('6'), istr('2'))
798
+ ** x istr(2) ** 3 ==> istr('8')
799
+ <=, <, >, >= x istr('100') > istr('2') ==> True
800
+ abs x abs(istr(-20)) ==> istr('20')
801
+ == x x istr(20) == 20 ==> True | istr(20) == '20' ==> True
802
+ bool x x *) bool(istr(' 0 ')) ==> False | bool(istr('')) ==> False
803
+ @ x istr(20) @ 3 ==> istr('202020')
804
+ | x istr(20) | '5' ==> istr('205')
805
+ slicing x istr(12345)[1:3] ==> istr('23')
806
+ iterate x [x for x in istr(20)] ==> [istr('2'), istr('0')]
807
+ len x len(istr(' 20 ')) ==> 4
808
+ count x istr(100).count('0') ==> 2
809
+ index x istr(' 100 ').index('0') ==> 2
810
+ split x istr('1 2').split() ==> (istr('1'), istr('2'))
811
+ string format x f"|{istr(1234):6}|" ==> '|1234 |'
812
+ other string methods x istr('aAbBcC').lower() ==> istr('aabbcc')
795
813
  istr('aAbBcC').islower() ==> False
796
814
  istr(' abc ').strip() ==> istr('abc')
797
815
  ...
798
816
  -----------------------------------------------------------------------------------------
799
817
  *) str is applied if is_int() is False
800
-
801
818
  ```
802
819
  ### Test script
803
820
  There's an extensive pytest script in the `\tests` directory.
@@ -5,12 +5,14 @@
5
5
  # |_||___/ \__||_|
6
6
  # strings you can count on
7
7
 
8
- __version__ = "1.1.6"
8
+ __version__ = "1.1.8"
9
9
  import functools
10
10
  import itertools
11
11
  import types
12
12
  import sys
13
13
  import inspect
14
+ import math
15
+ import operator
14
16
 
15
17
  """
16
18
  Note: the changelog is now in changelog.md
@@ -230,7 +232,7 @@ class istr(str):
230
232
  return int(value, cls._base)
231
233
  else:
232
234
  return int(value)
233
- except:
235
+ except Exception:
234
236
  return cls._nan
235
237
 
236
238
  def __new__(cls, *value):
@@ -250,6 +252,9 @@ class istr(str):
250
252
  if hasattr(value, "__next__"):
251
253
  return map(functools.partial(cls), value)
252
254
  return type(value)(map(functools.partial(cls), value))
255
+
256
+ if isinstance(value, str) and value.startswith("="):
257
+ value = str(cls.compose(value[1:], inspect.currentframe().f_back.f_back.f_globals))
253
258
  as_int = cls._to_int(value)
254
259
  if isinstance(value, str):
255
260
  as_str = value
@@ -346,10 +351,10 @@ class istr(str):
346
351
  return int(self._as_int)
347
352
 
348
353
  def is_even(self):
349
- return istr.is_divisible_by(self,2)
354
+ return istr.is_divisible_by(self, 2)
350
355
 
351
356
  def is_odd(self):
352
- return not istr.is_divisible_by(self,2)
357
+ return not istr.is_divisible_by(self, 2)
353
358
 
354
359
  def is_divisible_by(self, divisor):
355
360
  return istr.interpret_as_int(self) % int(divisor) == 0
@@ -384,13 +389,14 @@ class istr(str):
384
389
 
385
390
  def decompose(self, letters, namespace=None):
386
391
  """
387
- decompose letter variables into local variables
388
- each letter variable must represent just one character
389
- same letter variables represent the the same character
392
+ decompose one-letter variables into global variables
393
+ each one-letter variable must represent just one character
394
+ same one-letter variables represent the the same character
390
395
  the istr must have the same length as the letters
391
396
  """
392
397
  if namespace is None:
393
398
  namespace = inspect.currentframe().f_back.f_globals
399
+
394
400
  lookup = {}
395
401
 
396
402
  for letter, ch in zip(letters, self):
@@ -485,6 +491,16 @@ class istr(str):
485
491
  def concat(cls, iterable):
486
492
  return map(lambda x: istr("").join(x), istr(iterable))
487
493
 
494
+ @classmethod
495
+ def prod(cls, iterable, *, start=1):
496
+ return math.prod(iterable, start=cls(start))
497
+
498
+ @classmethod
499
+ def sumprod(cls, p, q, /, strict=True):
500
+ if "sumprod" in math.__dict__ and strict:
501
+ return istr(math.sumprod(p, q))
502
+ return sum(_map(operator.__mul__, cls(p), cls(q), strict=strict))
503
+
488
504
  @classmethod
489
505
  def enumerate(cls, iterable, start=0):
490
506
  for i, value in enumerate(iterable, start):
@@ -515,7 +531,7 @@ class istr(str):
515
531
  def __new__(cls, cls_repr_mode, mode=None):
516
532
  if mode is None:
517
533
  return cls_repr_mode._repr_mode
518
- if mode == int:
534
+ if mode is int:
519
535
  mode = "int"
520
536
  if mode in ("istr", "str", "int"): # _istr is used only for TypeErrors
521
537
  return super().__new__(cls)
@@ -624,6 +640,41 @@ class istr(str):
624
640
  return result
625
641
 
626
642
 
643
+ def _map(func, *iterables, strict=False):
644
+ """
645
+ like map, but with a strict parameter (also for Python < 3.14)
646
+ """
647
+ if sys.version_info >= (3, 14):
648
+ yield from map(func, *iterables, strict=strict)
649
+ return
650
+
651
+ if not strict:
652
+ yield from map(func, *iterables)
653
+ return
654
+
655
+ iterators = [iter(it) for it in iterables]
656
+
657
+ while True:
658
+ values = []
659
+ exhausted = []
660
+ for it in iterators:
661
+ try:
662
+ v = next(it)
663
+ values.append(v)
664
+ exhausted.append(False)
665
+ except StopIteration:
666
+ values.append(None)
667
+ exhausted.append(True)
668
+
669
+ if all(exhausted):
670
+ return
671
+
672
+ if any(exhausted) and not all(exhausted):
673
+ raise ValueError("map_strict: iterables have different lengths")
674
+
675
+ yield func(*values)
676
+
677
+
627
678
  istr.type = type(istr(0))
628
679
 
629
680
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: istr-python
3
- Version: 1.1.6
3
+ Version: 1.1.8
4
4
  Summary: istr - strings you can count on
5
5
  Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/salabim/istr
@@ -8,7 +8,7 @@ Project-URL: Repository, https://github.com/salabim/istr
8
8
  Classifier: Development Status :: 5 - Production/Stable
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Programming Language :: Python :: 3 :: Only
11
- Requires-Python: >=3.7
11
+ Requires-Python: >=3.8
12
12
  Description-Content-Type: text/markdown
13
13
 
14
14
  <img src="https://www.salabim.org/istr/istr_logo.png" width=500>
@@ -31,20 +31,33 @@ can be nicely, albeit not very efficient, coded as:
31
31
  import istr
32
32
 
33
33
  for s, e, n, d, m, o, r, y in istr.permutations(range(10), 8):
34
- if m and ((s|e|n|d) + (m|o|r|e) == (m|o|n|e|y)):
34
+ if m and ((s|e|n|d) + (m|o|r|e) == (m|o|n|e|y):
35
35
  print(f' {s|e|n|d}')
36
36
  print(f' {m|o|r|e}')
37
37
  print('-----')
38
38
  print(f'{m|o|n|e|y}')
39
39
  ```
40
40
 
41
+ or even
42
+
43
+ ```
44
+ import istr
45
+
46
+ for S, E, N, D, M, O, R, Y in istr.permutations(range(10), 8):
47
+ if m and (istr.compose("SEND") + ist.compose("MORE") == istr.compose("MONEY"):
48
+ print(" ",istr.compose("SEND"))
49
+ print(" ",istr.compose("MORE"))
50
+ print('-----')
51
+ print(istr.compose("MONEY"))
52
+ ```
53
+
41
54
  Of, if we want to add all the digits in a string:
42
55
 
43
56
  ```
44
57
  sum_digits = sum(istr('9282334')) # answer 31
45
58
  ```
46
59
 
47
- And the module is a demonstration of extending a class (str) with extra and changed functionality.
60
+ The module is a demonstration of extending a class (str) with additional and modified functionality.
48
61
 
49
62
  ### Installation
50
63
  Installing istr with pip is easy.
@@ -55,7 +68,7 @@ or when you want to upgrade,
55
68
  ```
56
69
  pip install istr-python --upgrade
57
70
  ```
58
- Alternatively, istr.py can be just copied into you current work directory from GitHub (https://github.com/salabim/istr).
71
+ Alternatively, istr.py can be just copied into your current work directory from GitHub (https://github.com/salabim/istr).
59
72
 
60
73
  No dependencies!
61
74
 
@@ -156,16 +169,16 @@ four, five = istr(4, 5)
156
169
  ```
157
170
 
158
171
  ##### Important
159
- >All calculations are strictly integer calculations. That means that if a float or decimal variable is ever produced it will be converted to an int.
160
- > Also divisions are always floor divisions!
172
+ >All calculations are strictly integer calculations. That means that if a float or decimal variable is ever produced, it will be converted to an int.
173
+ > Also, divisions are always floor divisions!
161
174
 
162
175
  #### Use istr as a string
163
176
 
164
177
  We should realize that istrs are in fact strings.
165
178
 
166
- In order to concatenate two istrs (or an istr and a str), we cannot use the `+` operator (remember `four + five` is `istr('9')`).
179
+ To concatenate two istrs (or an istr and a str), we cannot use the `+` operator (remember `four + five` is `istr('9')`).
167
180
 
168
- In order to concatenate istrs, we use the or operator (`|`). So
181
+ To concatenate strings, we use the or operator (`|`). So
169
182
 
170
183
  ```
171
184
  four | five
@@ -178,9 +191,9 @@ And
178
191
  ```
179
192
  is `istr('9')`.
180
193
 
181
- In order to repeat a string in the usual sense, you cannot use the `*` operator (remember `3 * four` is `istr('12')`.
194
+ To repeat a string in the usual sense, you cannot use the `*` operator (remember `3 * four` is `istr('12')`.
182
195
 
183
- In order to repeat we use the matrix multiplication operator (`@`). So
196
+ To repeat, we use the matrix multiplication operator (`@`). So
184
197
 
185
198
  `3 @ four`
186
199
 
@@ -199,7 +212,7 @@ is also `istr('444')`
199
212
  #### istr that can't be interpreted as an int
200
213
 
201
214
 
202
- Although usualy istrs are to be interpreted as an int, that's not a requirement.
215
+ Although usually istrs are to be interpreted as an int, that's not a requirement.
203
216
 
204
217
  So
205
218
 
@@ -215,7 +228,7 @@ istr('1,2,3')
215
228
 
216
229
  are perfectly acceptable.
217
230
 
218
- But, we can't do any arithmetic or comparison with them.
231
+ However, we cannot perform any arithmetic or comparison operations with them.
219
232
 
220
233
  If we try
221
234
 
@@ -295,9 +308,9 @@ several other types:
295
308
 
296
309
 
297
310
  - if a dict (or subtype of dict), the same type dict will be returned with all *values* istr'ed
298
- ```
311
+ ```
299
312
  istr({'one': 1, 'two':2}) ==> {'one': istr('1'), 'two': istr('2')}
300
- ```
313
+ ```
301
314
 
302
315
  - if an iterator, the iterator will be mapped with istr
303
316
  ```
@@ -313,11 +326,11 @@ several other types:
313
326
 
314
327
  - if an iterable, the same type will be returned with all elements istr'ed
315
328
 
316
- ```
329
+ ```
317
330
  istr([0, 1, 4]) ==> [istr('0'), istr('1'), istr('4')]
318
331
  istr((0, 1, 4)) ==> (istr('0'), istr('1'), istr('4'))
319
332
  istr({0, 1, 4}) ==> `{istr('4'), istr('0'), istr('1')} # or similar
320
- ```
333
+ ```
321
334
 
322
335
  - if a range, an istr.range instance will be returned
323
336
 
@@ -328,26 +341,25 @@ several other types:
328
341
  ```
329
342
 
330
343
  - if an istr.range instance, the same istr.range will be returned
331
- ```
344
+ ```
332
345
  istr(istr.range(5)) ==> istr.range(5)
333
- ```
346
+ ```
334
347
 
335
348
 
336
349
  - if an istr, the same istr will be returned
337
350
 
338
- ```
339
- istr(istr('4')) ==> istr ('4')
340
- ```
351
+ ```
352
+ istr(istr('4')) ==> istr ('4')
353
+ ```
341
354
 
342
355
  #### More than one parameter for istr
343
356
  It is possible to give more than one parameter, in which case a tuple
344
357
  of the istrs of the parameters will be returned, which can be handy
345
358
  to unpack multiple values, e.g.
346
359
 
347
- ```
360
+ ```
348
361
  a, b, c = istr(5, 6, 7) ==> a=istr('5') , b=istr('6'), c=istr('7')
349
- ```
350
-
362
+ ```
351
363
  #### test for even/odd
352
364
  It is possible to test for even/odd (provided the istr can be interpreted as an int) with the `is_even` and `is_odd` method, e.g.
353
365
 
@@ -360,6 +372,21 @@ It is also possible to test for even/odd of an ordinary int:
360
372
  istr.is_even(4) ==> True
361
373
  istr.is_odd(5) ==> True
362
374
  ```
375
+ #### test for divisibility
376
+
377
+ It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
378
+
379
+ ```
380
+ istr(18).is_divisible_by(3) ==> True
381
+ istr(18).is_divisible_by(istr(3)) ==> True
382
+ istr(19).is_divisible_by(3) ==> False
383
+ istr(19).is_divisible_by(istr(3)) == False
384
+ ```
385
+ It is also possible to test for divisibility of an ordinary int:
386
+ ```
387
+ istr.is_divisible(18, 3) ==> True
388
+ istr.is_divisible(19, 3) ==> False
389
+ ```
363
390
  #### test for square
364
391
 
365
392
  It is possible to test whether the value is a perfect square (provided the istr can be interpreted as an int) with the `is_square` method, e.g.
@@ -415,21 +442,6 @@ It is also possible to test for prime of an ordinary int:
415
442
  istr.is_prime(4) ==> False
416
443
  istr.is_prime(5) ==> True
417
444
  ```
418
- #### test for divisibility
419
-
420
- It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
421
-
422
- ```
423
- istr(18).is_divisible_by(3) ==> True
424
- istr(18).is_divisible_by(istr(3)) ==> True
425
- istr(19).is_divisible_by(3) ==> False
426
- istr(19).is_divisible_by(istr(3)) == False
427
- ```
428
- It is also possible to test for divisibility of an ordinary int:
429
- ```
430
- istr.is_divisible(18, 3) ==> True
431
- istr.is_divisible(19, 3) ==> False
432
- ```
433
445
  #### test whether all characters are distinct
434
446
 
435
447
  With the `all_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
@@ -450,7 +462,7 @@ The method `reversed()` will return an istr with the reversed content:
450
462
  istr(456).reversed() ==> istr('654')
451
463
  istr('0456').reversed() ==> istr('6540')
452
464
  ```
453
- The same can -of course- be achieved with
465
+ The same can, of course, be achieved with
454
466
  ```
455
467
  istr(456)[::-1] ==> istr('654')
456
468
  istr('0456')[::-1] ==> istr('6540')
@@ -597,6 +609,12 @@ istr(485).decompose("abc")
597
609
  will set the global variables `a`, `b` and `c` to be set to `istr(4)`. `istr(8)` and` istr(5)`.
598
610
  Note that the length of the letters specifier must be the same as the length of the istr. Furthermore, multiple values for the same variables result in a ValueError.
599
611
 
612
+ To decompose an istr into individual variables, it is arguably easier and safer to unpack the istr, like
613
+
614
+ ```
615
+ a, b, c = istr(485)
616
+ ```
617
+
600
618
  With `istr.compose()`, an istr can be constructed from individual (global) variables.
601
619
  E.g.
602
620
 
@@ -778,7 +796,7 @@ istr('1234')
778
796
 
779
797
  ### Overview of operations
780
798
 
781
- The table below shows whether the string or the int version of istr is applied.
799
+ The table below indicates whether the string or integer version of istr is applied.
782
800
 
783
801
  ```
784
802
  operator/function int str Example
@@ -786,31 +804,30 @@ operator/function int str Example
786
804
  + x istr(20) + 3 ==> istr('23')
787
805
  _ x istr(20) - 3 ==> istr('17')
788
806
  * x istr(20) * 3 ==> istr('60')
789
- / x istr(20) / 3 ==> istr('6')
790
- // x istr(20) // 3 ==> istr('6')
791
- % x istr(20) % 3 ==> istr('2')
792
- divmod x divmod(istr(20), 3) ==> (istr('6'), istr('2'))
793
- ** x istr(2) ** 3 ==> istr('8')
794
- <=, <, >, >= x istr('100') > istr('2') ==> True
795
- abs x abs(istr(-20)) ==> istr('20')
796
- == x x istr(20) == 20 ==> True | istr(20) == '20' ==> True
797
- bool x x *) bool(istr(' 0 ')) ==> False | istr('') ==> False
798
- @ x istr(20) @ 3 ==> istr('202020')
799
- | x istr(20) | '5' ==> istr('205')
800
- slicing x istr(12345)[1:3] ==> istr('23')
801
- iterate x [x for x in istr(20)] ==> [istr('2'), istr('0')]
802
- len x len(istr(' 20 ')) ==> 4
803
- count x istr(100).count('0') ==> 2
804
- index x istr(' 100 ').index('0') ==> 2
805
- split x istr('1 2').split() ==> (istr('1'), istr('2'))
806
- string format x f"|{istr(1234):6}|" ==> '|1234 |'
807
- other string methods x istr('aAbBcC').lower() ==> istr('aabbcc')
807
+ / x istr(20) / 3 ==> istr('6')
808
+ // x istr(20) // 3 ==> istr('6')
809
+ % x istr(20) % 3 ==> istr('2')
810
+ divmod x divmod(istr(20), 3) ==> (istr('6'), istr('2'))
811
+ ** x istr(2) ** 3 ==> istr('8')
812
+ <=, <, >, >= x istr('100') > istr('2') ==> True
813
+ abs x abs(istr(-20)) ==> istr('20')
814
+ == x x istr(20) == 20 ==> True | istr(20) == '20' ==> True
815
+ bool x x *) bool(istr(' 0 ')) ==> False | bool(istr('')) ==> False
816
+ @ x istr(20) @ 3 ==> istr('202020')
817
+ | x istr(20) | '5' ==> istr('205')
818
+ slicing x istr(12345)[1:3] ==> istr('23')
819
+ iterate x [x for x in istr(20)] ==> [istr('2'), istr('0')]
820
+ len x len(istr(' 20 ')) ==> 4
821
+ count x istr(100).count('0') ==> 2
822
+ index x istr(' 100 ').index('0') ==> 2
823
+ split x istr('1 2').split() ==> (istr('1'), istr('2'))
824
+ string format x f"|{istr(1234):6}|" ==> '|1234 |'
825
+ other string methods x istr('aAbBcC').lower() ==> istr('aabbcc')
808
826
  istr('aAbBcC').islower() ==> False
809
827
  istr(' abc ').strip() ==> istr('abc')
810
828
  ...
811
829
  -----------------------------------------------------------------------------------------
812
830
  *) str is applied if is_int() is False
813
-
814
831
  ```
815
832
  ### Test script
816
833
  There's an extensive pytest script in the `\tests` directory.
@@ -10,9 +10,9 @@ authors = [
10
10
  { name = "Ruud van der Ham", email = "rt.van.der.ham@gmail.com" },
11
11
  ]
12
12
  description = "istr - strings you can count on"
13
- version = "1.1.6"
13
+ version = "1.1.8"
14
14
  readme = "README.md"
15
- requires-python = ">=3.7"
15
+ requires-python = ">=3.8"
16
16
  dependencies = []
17
17
  classifiers = [
18
18
  "Development Status :: 5 - Production/Stable",
@@ -314,6 +314,17 @@ def test_even_odd():
314
314
  assert istr.is_odd(11111111)
315
315
 
316
316
 
317
+ def test_is_divisible_by():
318
+ assert istr(18).is_divisible_by(3)
319
+ assert istr(18).is_divisible_by(istr(3))
320
+ assert not istr(19).is_divisible_by(3)
321
+ assert not istr(19).is_divisible_by(istr(3))
322
+ with pytest.raises(TypeError, match=re.escape(f"not interpretable as int")):
323
+ istr("a").is_divisible_by(3)
324
+ assert istr.is_divisible_by(18, 3)
325
+ assert not istr.is_divisible_by(19, 3)
326
+
327
+
317
328
  def test_is_square():
318
329
  assert not istr(-1).is_square()
319
330
  assert istr(0).is_square()
@@ -330,6 +341,7 @@ def test_is_square():
330
341
  assert istr.is_square(4)
331
342
  assert istr.is_square(16)
332
343
 
344
+
333
345
  def test_is_cube():
334
346
  assert not istr(-1).is_cube()
335
347
  assert istr(0).is_cube()
@@ -357,16 +369,17 @@ def test_is_power_of():
357
369
  assert not istr(99).is_power_of(3)
358
370
  with pytest.raises(TypeError, match=re.escape(f"not interpretable as int")):
359
371
  istr("a").is_power_of(3)
360
- assert istr.is_power_of(0,3)
361
- assert istr.is_power_of(1,3)
362
- assert not istr.is_power_of(2,3)
363
- assert istr.is_power_of(8,3)
364
- assert istr.is_power_of(27,3)
372
+ assert istr.is_power_of(0, 3)
373
+ assert istr.is_power_of(1, 3)
374
+ assert not istr.is_power_of(2, 3)
375
+ assert istr.is_power_of(8, 3)
376
+ assert istr.is_power_of(27, 3)
365
377
  with pytest.raises(TypeError):
366
378
  istr(1).is_power_of(3.1)
367
379
  with pytest.raises(ValueError):
368
380
  istr(1).is_power_of(-1)
369
-
381
+
382
+
370
383
  def test_is_prime():
371
384
  assert not istr(0).is_prime()
372
385
  assert not istr(1).is_prime()
@@ -544,6 +557,12 @@ def test_unpacking():
544
557
  assert x.equals(istr(1))
545
558
  assert y.equals(istr(2))
546
559
  assert z.equals(istr(3))
560
+ del x, y, z
561
+
562
+ x, y, z = a
563
+ assert x.equals(istr(1))
564
+ assert y.equals(istr(2))
565
+ assert z == "3"
547
566
 
548
567
 
549
568
  def test_repr_mode():
@@ -635,17 +654,6 @@ def test_base():
635
654
  assert a * a == 225
636
655
 
637
656
 
638
- def test_is_divisible():
639
- assert istr(18).is_divisible_by(3)
640
- assert istr(18).is_divisible_by(istr(3))
641
- assert not istr(19).is_divisible_by(3)
642
- assert not istr(19).is_divisible_by(istr(3))
643
- with pytest.raises(TypeError, match=re.escape(f"not interpretable as int")):
644
- istr("a").is_divisible_by(3)
645
- assert istr.is_divisible_by(18, 3)
646
- assert not istr.is_divisible_by(19, 3)
647
-
648
-
649
657
  def test_digits():
650
658
  assert istr.digits().equals(istr("0123456789"))
651
659
  assert istr.digits("").equals(istr("0123456789"))
@@ -697,13 +705,16 @@ def test_itertools():
697
705
  assert list(istr.dropwhile(lambda x: x < 5, [1, 4, 6, 4, 1])) == [istr("6"), istr("4"), istr("1")]
698
706
  assert list(istr.filterfalse(lambda x: x % 2, range(10))) == [istr("0"), istr("2"), istr("4"), istr("6"), istr("8")]
699
707
  assert list(istr.islice("123456", 2)) == [istr("1"), istr("2")]
700
- assert list(istr.pairwise("1234")) == [(istr("1"), istr("2")), (istr("2"), istr("3")), (istr("3"), istr("4"))]
701
708
  assert list(istr.permutations(range(5), 3)) == list(istr(itertools.permutations(range(5), 3)))
702
709
  assert list(istr.product(range(5), range(4))) == list(istr(itertools.product(range(5), range(4))))
703
710
  assert list100(istr.repeat(10)) == list100(istr(itertools.repeat(10)))
704
711
  assert list(istr.starmap(pow, [(2, 5), (3, 2), (10, 3)])) == [istr("32"), istr("9"), istr("1000")]
705
712
  assert list(istr.takewhile(lambda x: x < 5, [1, 4, 6, 3, 8])) == [istr("1"), istr("4")]
706
713
  assert list(istr.zip_longest("123", "56", fillvalue="0")) == [(istr("1"), istr("5")), (istr("2"), istr("6")), (istr("3"), istr("0"))]
714
+ if sys.version_info >= (3, 10):
715
+ assert list(istr.pairwise("1234")) == [(istr("1"), istr("2")), (istr("2"), istr("3")), (istr("3"), istr("4"))]
716
+ if sys.version_info >= (3, 12):
717
+ assert list(istr.batched("12345", n=2)) == [(istr("1"), istr("2")), (istr("3"), istr("4")), (istr("5"),)]
707
718
 
708
719
 
709
720
  def test_all_distinct():
@@ -712,6 +723,23 @@ def test_all_distinct():
712
723
  assert istr("").all_distinct()
713
724
 
714
725
 
726
+ def test_prod():
727
+ assert istr.prod(range(1, 5)).equals(istr(24))
728
+ assert istr.prod((1, 2, 3), start=4).equals(istr(24))
729
+
730
+
731
+ def test_sumprod():
732
+ assert istr.sumprod((1, 2), (3, 4)).equals(istr(11))
733
+ assert istr.sumprod(istr("12"), (3, 4)).equals(istr(11))
734
+ assert istr.sumprod(istr("12"), "34").equals(istr(11))
735
+ assert istr.sumprod(istr("12"), "34", strict=False).equals(istr(11))
736
+ assert istr.sumprod(istr("12"), "345", strict=False).equals(istr(11))
737
+ with pytest.raises(ValueError):
738
+ istr.sumprod((1, 2), (3, 4, 5))
739
+ with pytest.raises(ValueError):
740
+ istr.sumprod((1, 2), (3, 4, 5), strict=True)
741
+
742
+
715
743
  def test_subclassing():
716
744
  class jstr(istr.type): ...
717
745
 
File without changes