istr-python 1.1.32.post0__tar.gz → 1.1.33__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.
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/PKG-INFO +17 -2
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/README.md +16 -1
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/istr/istr.py +103 -78
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/istr_python.egg-info/PKG-INFO +17 -2
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/pyproject.toml +1 -1
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/tests/test_istr.py +46 -20
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/istr/LICENSE.txt +0 -0
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/istr/__init__.py +0 -0
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/istr_python.egg-info/SOURCES.txt +0 -0
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/istr_python.egg-info/dependency_links.txt +0 -0
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/istr_python.egg-info/top_level.txt +0 -0
- {istr_python-1.1.32.post0 → istr_python-1.1.33}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: istr-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.33
|
|
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
|
|
@@ -367,7 +367,18 @@ to unpack multiple values, e.g.
|
|
|
367
367
|
a, b, c = istr(5, 6, 7) ==> a=istr('5') , b=istr('6'), c=istr('7')
|
|
368
368
|
a, b, c = istr(*range(3)) ==> a=istr('0') , b=istr('1'), c=istr('2')
|
|
369
369
|
```
|
|
370
|
+
#### Alternative way of range specification
|
|
371
|
+
|
|
372
|
+
Instead of `istr(range(..))` it is possible to use `istr,range(..)` instead, like
|
|
373
|
+
|
|
374
|
+
`list(istr.range(3,6))` ==> `[istr('3'), istr('4'), istr('5')]`
|
|
375
|
+
|
|
376
|
+
In contrast to the builtin `range`, `istr.range` supports a non keyword parameter `length`:
|
|
377
|
+
|
|
378
|
+
`list(istr.range(length=3))` is equivalent to `istr.range(100, 1000)`
|
|
379
|
+
|
|
370
380
|
#### test for even/odd
|
|
381
|
+
|
|
371
382
|
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.
|
|
372
383
|
|
|
373
384
|
```
|
|
@@ -754,13 +765,17 @@ In contrast to `math.sumprod()`, `istr.sumprod()` supports a `strict` parameter
|
|
|
754
765
|
Thus, `istr.sumprod("12", (3,4,5), strict=False)` is `istr(11)`, whereas `istr.sumprod("12", (3,4,5))`
|
|
755
766
|
raises a ValueError.
|
|
756
767
|
|
|
757
|
-
#### get all squares, cubes, power ofs or primes in a given range
|
|
768
|
+
#### get all squares, cubes, power ofs or primes in a given range or with a given length
|
|
758
769
|
|
|
759
770
|
The class methods `istr.squares`, `istr.cubes`, `istr.power_ofs` and `istr.primes` can be used to get a list of all squares, cubes, power_ofs or primes up to a given upperbound (non inclusive) or between a given lower bound and upper bound (non inclusive), like:
|
|
760
771
|
|
|
761
772
|
`istr.squares (100)` returns a list of all squares <100
|
|
762
773
|
`istr.squares(50, 100)` returns a list of all squares in the range [50, 100)
|
|
763
774
|
|
|
775
|
+
Alternatively, it is possible to get a list of all squares, cubes, power_ofs or primes with a given length, like:
|
|
776
|
+
|
|
777
|
+
`istr.squares (length=2)` returns a list of all squares of length 2, so between 10 and 99.
|
|
778
|
+
|
|
764
779
|
Unless `cache=False` is specified, the query result is cached.
|
|
765
780
|
|
|
766
781
|
#### generate istr with digits
|
|
@@ -354,7 +354,18 @@ to unpack multiple values, e.g.
|
|
|
354
354
|
a, b, c = istr(5, 6, 7) ==> a=istr('5') , b=istr('6'), c=istr('7')
|
|
355
355
|
a, b, c = istr(*range(3)) ==> a=istr('0') , b=istr('1'), c=istr('2')
|
|
356
356
|
```
|
|
357
|
+
#### Alternative way of range specification
|
|
358
|
+
|
|
359
|
+
Instead of `istr(range(..))` it is possible to use `istr,range(..)` instead, like
|
|
360
|
+
|
|
361
|
+
`list(istr.range(3,6))` ==> `[istr('3'), istr('4'), istr('5')]`
|
|
362
|
+
|
|
363
|
+
In contrast to the builtin `range`, `istr.range` supports a non keyword parameter `length`:
|
|
364
|
+
|
|
365
|
+
`list(istr.range(length=3))` is equivalent to `istr.range(100, 1000)`
|
|
366
|
+
|
|
357
367
|
#### test for even/odd
|
|
368
|
+
|
|
358
369
|
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.
|
|
359
370
|
|
|
360
371
|
```
|
|
@@ -741,13 +752,17 @@ In contrast to `math.sumprod()`, `istr.sumprod()` supports a `strict` parameter
|
|
|
741
752
|
Thus, `istr.sumprod("12", (3,4,5), strict=False)` is `istr(11)`, whereas `istr.sumprod("12", (3,4,5))`
|
|
742
753
|
raises a ValueError.
|
|
743
754
|
|
|
744
|
-
#### get all squares, cubes, power ofs or primes in a given range
|
|
755
|
+
#### get all squares, cubes, power ofs or primes in a given range or with a given length
|
|
745
756
|
|
|
746
757
|
The class methods `istr.squares`, `istr.cubes`, `istr.power_ofs` and `istr.primes` can be used to get a list of all squares, cubes, power_ofs or primes up to a given upperbound (non inclusive) or between a given lower bound and upper bound (non inclusive), like:
|
|
747
758
|
|
|
748
759
|
`istr.squares (100)` returns a list of all squares <100
|
|
749
760
|
`istr.squares(50, 100)` returns a list of all squares in the range [50, 100)
|
|
750
761
|
|
|
762
|
+
Alternatively, it is possible to get a list of all squares, cubes, power_ofs or primes with a given length, like:
|
|
763
|
+
|
|
764
|
+
`istr.squares (length=2)` returns a list of all squares of length 2, so between 10 and 99.
|
|
765
|
+
|
|
751
766
|
Unless `cache=False` is specified, the query result is cached.
|
|
752
767
|
|
|
753
768
|
#### generate istr with digits
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# |_||___/ \__||_|
|
|
6
6
|
# strings you can count on
|
|
7
7
|
|
|
8
|
-
__version__ = "1.1.
|
|
8
|
+
__version__ = "1.1.33"
|
|
9
9
|
import functools
|
|
10
10
|
import itertools
|
|
11
11
|
import types
|
|
@@ -16,6 +16,7 @@ import operator
|
|
|
16
16
|
import copy
|
|
17
17
|
import bisect
|
|
18
18
|
import collections
|
|
19
|
+
import numbers
|
|
19
20
|
|
|
20
21
|
"""
|
|
21
22
|
Note: the changelog is in changelog.md
|
|
@@ -33,12 +34,10 @@ class _range:
|
|
|
33
34
|
based on https://codereview.stackexchange.com/questions/229073/pure-python-range-implementation
|
|
34
35
|
"""
|
|
35
36
|
|
|
36
|
-
def __init__(self, cls, start, stop
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if step == 0:
|
|
41
|
-
raise ValueError("range() arg 3 must not be zero")
|
|
37
|
+
def __init__(self, cls, start, stop, step, length, base, int_format, repr_mode):
|
|
38
|
+
self.start, self.stop, self.step = process_start_stop_step_length(start, stop, step, length)
|
|
39
|
+
if self.step == 0:
|
|
40
|
+
raise ValueError(f"step must not be zero, not {self.step}")
|
|
42
41
|
if self.step < 0:
|
|
43
42
|
step_sign = -1
|
|
44
43
|
else:
|
|
@@ -232,8 +231,8 @@ class istr(str):
|
|
|
232
231
|
_nan = object()
|
|
233
232
|
_digits_cache = {}
|
|
234
233
|
|
|
235
|
-
@
|
|
236
|
-
def _to_base(number, base):
|
|
234
|
+
@classmethod
|
|
235
|
+
def _to_base(cls, number, base):
|
|
237
236
|
if number < 0:
|
|
238
237
|
raise ValueError(f"negative numbers are not allowed for base {base}")
|
|
239
238
|
result = ""
|
|
@@ -298,7 +297,7 @@ class istr(str):
|
|
|
298
297
|
if base == 10:
|
|
299
298
|
as_str = str(as_int)
|
|
300
299
|
else:
|
|
301
|
-
as_str =
|
|
300
|
+
as_str = cls._to_base(as_int, base)
|
|
302
301
|
else:
|
|
303
302
|
as_str = f"{as_int:{int_format}}"
|
|
304
303
|
|
|
@@ -447,24 +446,21 @@ class istr(str):
|
|
|
447
446
|
return True
|
|
448
447
|
|
|
449
448
|
@classmethod
|
|
450
|
-
def primes(cls,
|
|
451
|
-
lb, ub = (0, lb_or_ub) if ub is None else (lb_or_ub, ub)
|
|
452
|
-
if lb < 0:
|
|
453
|
-
lb = 0
|
|
454
|
-
lb = int(lb)
|
|
455
|
-
ub = int(ub)
|
|
449
|
+
def primes(cls, start=None, stop=None, /, length=None, cache=True):
|
|
456
450
|
"""
|
|
457
451
|
returns all primes up to a given upperbound or between a given lowerbound and upperbound
|
|
452
|
+
alternatively, the length can be given
|
|
458
453
|
"""
|
|
459
|
-
|
|
460
|
-
|
|
454
|
+
start, stop, step = process_start_stop_step_length(start, stop, 1, length)
|
|
455
|
+
if (cls, "primes", start, stop) in _cache:
|
|
456
|
+
return _cache[cls, "primes", start, stop]
|
|
461
457
|
|
|
462
|
-
if
|
|
463
|
-
result = in_range(cls._primes_up_to_1_000_000(),
|
|
458
|
+
if stop <= 1_000_000:
|
|
459
|
+
result = in_range(cls._primes_up_to_1_000_000(), start, stop)
|
|
464
460
|
else:
|
|
465
|
-
result = cls._primes(
|
|
461
|
+
result = cls._primes(start, stop)
|
|
466
462
|
if cache:
|
|
467
|
-
_cache[cls, "primes",
|
|
463
|
+
_cache[cls, "primes", start, stop] = result
|
|
468
464
|
return result
|
|
469
465
|
|
|
470
466
|
@classmethod
|
|
@@ -496,8 +492,7 @@ class istr(str):
|
|
|
496
492
|
|
|
497
493
|
def is_power_of(self, exponent):
|
|
498
494
|
n = istr.interpret_as_int(self)
|
|
499
|
-
|
|
500
|
-
exponent = int(exponent)
|
|
495
|
+
exponent = check_integer(exponent, "exponent")
|
|
501
496
|
if n < 0:
|
|
502
497
|
if exponent % 2 == 0:
|
|
503
498
|
return False
|
|
@@ -510,8 +505,6 @@ class istr(str):
|
|
|
510
505
|
return True
|
|
511
506
|
case x if x < 0:
|
|
512
507
|
raise ValueError(f"exponent must be >=0; not {exponent}")
|
|
513
|
-
case _ if not isinstance(exponent, int):
|
|
514
|
-
raise TypeError(f"exponent must be int; not {type(exponent)}")
|
|
515
508
|
case _ if n < 1_000_000:
|
|
516
509
|
return n in istr._power_ofs_up_to_1_000_000_as_set(exponent)
|
|
517
510
|
case _:
|
|
@@ -519,41 +512,46 @@ class istr(str):
|
|
|
519
512
|
return n == round(n ** (1 / exponent)) ** exponent
|
|
520
513
|
|
|
521
514
|
@classmethod
|
|
522
|
-
def squares(cls,
|
|
515
|
+
def squares(cls, start=None, stop=None, /, length=None, cache=True):
|
|
523
516
|
"""
|
|
524
|
-
returns all squares up to a given
|
|
517
|
+
returns all squares up to a given stop or between a given start and stop
|
|
518
|
+
alternatively, the length can be given
|
|
525
519
|
"""
|
|
526
|
-
return cls.power_ofs(2,
|
|
520
|
+
return cls.power_ofs(2, start, stop, length=length, cache=cache)
|
|
527
521
|
|
|
528
522
|
@classmethod
|
|
529
|
-
def cubes(cls,
|
|
530
|
-
|
|
523
|
+
def cubes(cls, start=None, stop=None, /, length=None, cache=True):
|
|
524
|
+
"""
|
|
525
|
+
returns all cubes up to a given stop or between a given start and stop
|
|
526
|
+
alternatively, the length can be given
|
|
527
|
+
"""
|
|
528
|
+
return cls.power_ofs(3, start, stop, length=length, cache=cache)
|
|
531
529
|
|
|
532
530
|
@classmethod
|
|
533
|
-
def power_ofs(cls, exponent,
|
|
531
|
+
def power_ofs(cls, exponent, start=None, stop=None, /, length=None, cache=True):
|
|
534
532
|
"""
|
|
535
|
-
returns all power of n up to a given
|
|
533
|
+
returns all power of n up to a given stop or between a given start and stop
|
|
534
|
+
alternatively, the length can be given
|
|
536
535
|
"""
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
ub = int(ub)
|
|
536
|
+
start, stop, step = process_start_stop_step_length(start, stop, 1, length)
|
|
537
|
+
exponent = check_integer(exponent, "exponent")
|
|
540
538
|
|
|
541
|
-
if (cls, "power_ofs", exponent,
|
|
542
|
-
return _cache[cls, "power_ofs", exponent,
|
|
539
|
+
if (cls, "power_ofs", exponent, start, stop) in _cache:
|
|
540
|
+
return _cache[cls, "power_ofs", exponent, start, stop]
|
|
543
541
|
match exponent:
|
|
544
542
|
case 0:
|
|
545
|
-
if
|
|
543
|
+
if start <= 1 < stop:
|
|
546
544
|
result = [istr(1)]
|
|
547
545
|
else:
|
|
548
546
|
result = []
|
|
549
547
|
case 1:
|
|
550
|
-
result = cls(list(range(
|
|
551
|
-
case x if (x % 2 == 0 or
|
|
552
|
-
result = in_range(cls._power_ofs_up_to_1_000_000(exponent),
|
|
548
|
+
result = cls(list(range(start, stop)))
|
|
549
|
+
case x if (x % 2 == 0 or start >= 0) and stop <= 1_000_000:
|
|
550
|
+
result = in_range(cls._power_ofs_up_to_1_000_000(exponent), start, stop)
|
|
553
551
|
case _:
|
|
554
|
-
result = cls._power_ofs(exponent,
|
|
552
|
+
result = cls._power_ofs(exponent, start, stop)
|
|
555
553
|
if cache:
|
|
556
|
-
_cache[cls, "power_ofs", exponent,
|
|
554
|
+
_cache[cls, "power_ofs", exponent, start, stop] = result
|
|
557
555
|
return result
|
|
558
556
|
|
|
559
557
|
@classmethod
|
|
@@ -728,27 +726,26 @@ class istr(str):
|
|
|
728
726
|
"removesuffix replace rjust rpartition rsplit rstrip split strip swapcase title translate upper zfill"
|
|
729
727
|
).split():
|
|
730
728
|
locals()[name] = functools.partialmethod(_str_method, name)
|
|
731
|
-
|
|
729
|
+
|
|
732
730
|
@classmethod
|
|
733
|
-
def zip(cls, *iterables, strict=False,join=False):
|
|
731
|
+
def zip(cls, *iterables, strict=False, join=False):
|
|
734
732
|
if join:
|
|
735
|
-
return cls.concat(
|
|
733
|
+
return cls.concat(cls(zip(*iterables, strict=strict)))
|
|
736
734
|
else:
|
|
737
|
-
return
|
|
738
|
-
|
|
735
|
+
return cls(zip(*iterables, strict=strict))
|
|
736
|
+
|
|
739
737
|
@classmethod
|
|
740
|
-
def batched(cls,iterable, n, *, strict=False,join=False):
|
|
741
|
-
print("*** batched internal")
|
|
738
|
+
def batched(cls, iterable, n, *, strict=False, join=False): # will be overridden if in itertools and not Python 3.12
|
|
742
739
|
if n < 1:
|
|
743
|
-
raise ValueError(
|
|
740
|
+
raise ValueError("n must be at least one")
|
|
744
741
|
iterator = iter(iterable)
|
|
745
742
|
while batch := tuple(itertools.islice(iterator, n)):
|
|
746
743
|
if strict and len(batch) != n:
|
|
747
|
-
raise ValueError(
|
|
744
|
+
raise ValueError("istr.batched(): incomplete batch")
|
|
748
745
|
if join:
|
|
749
|
-
yield cls.join(
|
|
746
|
+
yield cls.join(cls(batch))
|
|
750
747
|
else:
|
|
751
|
-
yield
|
|
748
|
+
yield cls(batch)
|
|
752
749
|
|
|
753
750
|
@classmethod
|
|
754
751
|
def _itertools_method(cls, name, *args, **kwargs):
|
|
@@ -764,9 +761,9 @@ class istr(str):
|
|
|
764
761
|
match name:
|
|
765
762
|
case "groupby" | "tee":
|
|
766
763
|
locals()[name] = getattr(itertools, name)
|
|
767
|
-
case "permutations" | "combinations" | "combinations_with_replacement" | "product"|"batched"|"pairwise"|"zip_longest":
|
|
768
|
-
if name=="batched" and sys.version_info[:2] == (3, 12):
|
|
769
|
-
continue
|
|
764
|
+
case "permutations" | "combinations" | "combinations_with_replacement" | "product" | "batched" | "pairwise" | "zip_longest":
|
|
765
|
+
if name == "batched" and sys.version_info[:2] == (3, 12):
|
|
766
|
+
continue # version 3.12 does not support the strict parameter, so, we don't use the itertools method
|
|
770
767
|
locals()[name] = functools.partialmethod(_itertools_join_method, name)
|
|
771
768
|
case _:
|
|
772
769
|
locals()[name] = functools.partialmethod(_itertools_method, name)
|
|
@@ -786,12 +783,12 @@ class istr(str):
|
|
|
786
783
|
if iterable is None:
|
|
787
784
|
return istr("").join(self)
|
|
788
785
|
if not isinstance(self, str):
|
|
789
|
-
raise TypeError(f"{self!r} should be str, not {type(self)}")
|
|
786
|
+
raise TypeError(f"{self!r} should be istr, str or iterable, not {type(self)}")
|
|
790
787
|
return istr(self).join(iterable)
|
|
791
788
|
|
|
792
789
|
@classmethod
|
|
793
790
|
def concat(cls, iterable):
|
|
794
|
-
return map(cls.join, cls(iterable))
|
|
791
|
+
return map(cls.join, cls(iterable))
|
|
795
792
|
|
|
796
793
|
def prod(self, *, start=1):
|
|
797
794
|
return math.prod(self, start=istr(start))
|
|
@@ -831,8 +828,7 @@ class istr(str):
|
|
|
831
828
|
|
|
832
829
|
cls._int_format = int_format
|
|
833
830
|
|
|
834
|
-
def __enter__(self):
|
|
835
|
-
...
|
|
831
|
+
def __enter__(self): ...
|
|
836
832
|
|
|
837
833
|
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
838
834
|
self.saved_cls._int_format = self.saved_int_format
|
|
@@ -853,8 +849,7 @@ class istr(str):
|
|
|
853
849
|
self.saved_cls = cls
|
|
854
850
|
cls._repr_mode = mode
|
|
855
851
|
|
|
856
|
-
def __enter__(self):
|
|
857
|
-
...
|
|
852
|
+
def __enter__(self): ...
|
|
858
853
|
|
|
859
854
|
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
860
855
|
self.saved_cls._repr_mode = self.saved_repr_mode
|
|
@@ -873,15 +868,14 @@ class istr(str):
|
|
|
873
868
|
self.saved_cls = cls
|
|
874
869
|
cls._base = base
|
|
875
870
|
|
|
876
|
-
def __enter__(self):
|
|
877
|
-
...
|
|
871
|
+
def __enter__(self): ...
|
|
878
872
|
|
|
879
873
|
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
880
874
|
self.saved_cls._base = self.saved_base
|
|
881
875
|
|
|
882
876
|
@classmethod
|
|
883
|
-
def range(cls, start, stop=None, step=1, base=None, int_format=None, repr_mode=None):
|
|
884
|
-
return _range(cls, start, stop, step, base=base, int_format=int_format, repr_mode=repr_mode)
|
|
877
|
+
def range(cls, start=None, stop=None, step=1, /, length=None, base=None, int_format=None, repr_mode=None):
|
|
878
|
+
return _range(cls, start, stop, step, length, base=base, int_format=int_format, repr_mode=repr_mode)
|
|
885
879
|
|
|
886
880
|
@classmethod
|
|
887
881
|
def digits(cls, *args):
|
|
@@ -991,7 +985,7 @@ def _map(func, *iterables, strict=False):
|
|
|
991
985
|
_cache = {}
|
|
992
986
|
|
|
993
987
|
|
|
994
|
-
def in_range(lst,
|
|
988
|
+
def in_range(lst, start, stop):
|
|
995
989
|
"""
|
|
996
990
|
this function will give all values of lst in the range [lb, ub)
|
|
997
991
|
|
|
@@ -1000,28 +994,60 @@ def in_range(lst, lb, ub):
|
|
|
1000
994
|
lst : list
|
|
1001
995
|
must be sorted!
|
|
1002
996
|
|
|
1003
|
-
|
|
997
|
+
start : int (or istr)
|
|
1004
998
|
lowerbound
|
|
1005
999
|
|
|
1006
|
-
|
|
1000
|
+
stop : int (or istr)
|
|
1007
1001
|
non inclusive upperbound
|
|
1008
1002
|
|
|
1009
1003
|
Returns
|
|
1010
1004
|
-------
|
|
1011
|
-
list of all items in [
|
|
1005
|
+
list of all items in [start, stop)
|
|
1012
1006
|
|
|
1013
1007
|
Note
|
|
1014
1008
|
----
|
|
1015
1009
|
Equivalent to
|
|
1016
|
-
[item for item in lst if
|
|
1010
|
+
[item for item in lst if start <= item < stop], but more efficient.
|
|
1017
1011
|
"""
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
left = bisect.bisect_left(lst,
|
|
1021
|
-
right = bisect.bisect_left(lst,
|
|
1012
|
+
start = int(start)
|
|
1013
|
+
stop = int(stop)
|
|
1014
|
+
left = bisect.bisect_left(lst, start)
|
|
1015
|
+
right = bisect.bisect_left(lst, stop)
|
|
1022
1016
|
return lst[left:right]
|
|
1023
1017
|
|
|
1024
1018
|
|
|
1019
|
+
def check_integer(value, value_description):
|
|
1020
|
+
|
|
1021
|
+
if not isinstance(value, numbers.Number):
|
|
1022
|
+
try:
|
|
1023
|
+
return int(value)
|
|
1024
|
+
except TypeError:
|
|
1025
|
+
raise ValueError(f"{value_description} should be an integer, not {value}")
|
|
1026
|
+
|
|
1027
|
+
if value != int(value):
|
|
1028
|
+
raise ValueError(f"{value_description} should be an integer, not {value}")
|
|
1029
|
+
return int(value)
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
def process_start_stop_step_length(start, stop, step, length):
|
|
1033
|
+
if start is None and length is None:
|
|
1034
|
+
raise ValueError("no bound(s) or length specified")
|
|
1035
|
+
if length is not None:
|
|
1036
|
+
if start is not None:
|
|
1037
|
+
raise ValueError("both bound(s) and length specified")
|
|
1038
|
+
length = check_integer(length, "length")
|
|
1039
|
+
if length < 1:
|
|
1040
|
+
raise ValueError(f"length must be >=1, not {length}")
|
|
1041
|
+
start = 10 ** (length - 1)
|
|
1042
|
+
stop = start * 10
|
|
1043
|
+
else:
|
|
1044
|
+
start, stop = (0, start) if stop is None else (start, stop)
|
|
1045
|
+
start = check_integer(start, "start")
|
|
1046
|
+
stop = check_integer(stop, "upperbound")
|
|
1047
|
+
step = check_integer(step, "step")
|
|
1048
|
+
return start, stop, step
|
|
1049
|
+
|
|
1050
|
+
|
|
1025
1051
|
def get_namespace(namespace):
|
|
1026
1052
|
if namespace is None:
|
|
1027
1053
|
frame = real_caller_frame()
|
|
@@ -1056,4 +1082,3 @@ class istrModule(types.ModuleType):
|
|
|
1056
1082
|
|
|
1057
1083
|
if __name__ != "__main__":
|
|
1058
1084
|
sys.modules["istr"].__class__ = istrModule
|
|
1059
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: istr-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.33
|
|
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
|
|
@@ -367,7 +367,18 @@ to unpack multiple values, e.g.
|
|
|
367
367
|
a, b, c = istr(5, 6, 7) ==> a=istr('5') , b=istr('6'), c=istr('7')
|
|
368
368
|
a, b, c = istr(*range(3)) ==> a=istr('0') , b=istr('1'), c=istr('2')
|
|
369
369
|
```
|
|
370
|
+
#### Alternative way of range specification
|
|
371
|
+
|
|
372
|
+
Instead of `istr(range(..))` it is possible to use `istr,range(..)` instead, like
|
|
373
|
+
|
|
374
|
+
`list(istr.range(3,6))` ==> `[istr('3'), istr('4'), istr('5')]`
|
|
375
|
+
|
|
376
|
+
In contrast to the builtin `range`, `istr.range` supports a non keyword parameter `length`:
|
|
377
|
+
|
|
378
|
+
`list(istr.range(length=3))` is equivalent to `istr.range(100, 1000)`
|
|
379
|
+
|
|
370
380
|
#### test for even/odd
|
|
381
|
+
|
|
371
382
|
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.
|
|
372
383
|
|
|
373
384
|
```
|
|
@@ -754,13 +765,17 @@ In contrast to `math.sumprod()`, `istr.sumprod()` supports a `strict` parameter
|
|
|
754
765
|
Thus, `istr.sumprod("12", (3,4,5), strict=False)` is `istr(11)`, whereas `istr.sumprod("12", (3,4,5))`
|
|
755
766
|
raises a ValueError.
|
|
756
767
|
|
|
757
|
-
#### get all squares, cubes, power ofs or primes in a given range
|
|
768
|
+
#### get all squares, cubes, power ofs or primes in a given range or with a given length
|
|
758
769
|
|
|
759
770
|
The class methods `istr.squares`, `istr.cubes`, `istr.power_ofs` and `istr.primes` can be used to get a list of all squares, cubes, power_ofs or primes up to a given upperbound (non inclusive) or between a given lower bound and upper bound (non inclusive), like:
|
|
760
771
|
|
|
761
772
|
`istr.squares (100)` returns a list of all squares <100
|
|
762
773
|
`istr.squares(50, 100)` returns a list of all squares in the range [50, 100)
|
|
763
774
|
|
|
775
|
+
Alternatively, it is possible to get a list of all squares, cubes, power_ofs or primes with a given length, like:
|
|
776
|
+
|
|
777
|
+
`istr.squares (length=2)` returns a list of all squares of length 2, so between 10 and 99.
|
|
778
|
+
|
|
764
779
|
Unless `cache=False` is specified, the query result is cached.
|
|
765
780
|
|
|
766
781
|
#### generate istr with digits
|
|
@@ -10,7 +10,7 @@ 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.
|
|
13
|
+
version = "1.1.33"
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
requires-python = ">=3.10"
|
|
16
16
|
dependencies = []
|
|
@@ -190,6 +190,12 @@ def test_range():
|
|
|
190
190
|
|
|
191
191
|
assert str(list(istr.range(5, base=2, repr_mode="str"))) == "['0', '1', '10', '11', '100']"
|
|
192
192
|
|
|
193
|
+
assert list(istr.range(length=2)) == list(istr.range(10, 100))
|
|
194
|
+
with pytest.raises(ValueError, match=re.escape("length must be >=1, not 0")):
|
|
195
|
+
istr.range(length=0)
|
|
196
|
+
with pytest.raises(ValueError, match=re.escape("both bound(s) and length specified")):
|
|
197
|
+
istr.range(10, length=2)
|
|
198
|
+
|
|
193
199
|
|
|
194
200
|
def test_misc():
|
|
195
201
|
assert istr("") == ""
|
|
@@ -468,7 +474,7 @@ def test_is_power_of():
|
|
|
468
474
|
assert not istr.is_power_of(2, 3)
|
|
469
475
|
assert istr.is_power_of(8, 3)
|
|
470
476
|
assert istr.is_power_of(27, 3)
|
|
471
|
-
with pytest.raises(
|
|
477
|
+
with pytest.raises(ValueError):
|
|
472
478
|
istr(1).is_power_of(3.1)
|
|
473
479
|
with pytest.raises(ValueError):
|
|
474
480
|
istr(1).is_power_of(-1)
|
|
@@ -502,18 +508,33 @@ def test_primes():
|
|
|
502
508
|
assert istr.primes(17) == [istr("2"), istr("3"), istr("5"), istr("7"), istr("11"), istr("13")]
|
|
503
509
|
assert istr.primes(40, 50) == [istr("41"), istr("43"), istr("47")]
|
|
504
510
|
assert id(istr.primes(100)) == id(istr.primes(100)) # test caching
|
|
511
|
+
assert istr.primes(length=2) == istr.primes(10, 100)
|
|
512
|
+
with pytest.raises(ValueError, match=re.escape("both bound(s) and length specified")):
|
|
513
|
+
istr.primes(12, length=2)
|
|
514
|
+
with pytest.raises(ValueError, match=re.escape("no bound(s) or length specified")):
|
|
515
|
+
istr.primes()
|
|
505
516
|
|
|
506
517
|
|
|
507
518
|
def test_squares():
|
|
508
519
|
assert istr.squares(50) == [istr("0"), istr("1"), istr("4"), istr("9"), istr("16"), istr("25"), istr("36"), istr("49")]
|
|
509
|
-
assert istr.squares(
|
|
520
|
+
assert istr.squares(-27, 27) == [istr("0"), istr("1"), istr("4"), istr("9"), istr("16"), istr("25")]
|
|
510
521
|
assert id(istr.squares(100)) == id(istr.squares(100)) # test caching
|
|
522
|
+
assert istr.squares(length=2) == istr.squares(10, 100)
|
|
523
|
+
with pytest.raises(ValueError, match=re.escape("both bound(s) and length specified")):
|
|
524
|
+
istr.squares(12, length=2)
|
|
525
|
+
with pytest.raises(ValueError, match=re.escape("no bound(s) or length specified")):
|
|
526
|
+
istr.squares()
|
|
511
527
|
|
|
512
528
|
|
|
513
529
|
def test_cubes():
|
|
514
530
|
assert istr.cubes(50) == [istr("0"), istr("1"), istr("8"), istr("27")]
|
|
515
|
-
assert istr.cubes(27,
|
|
531
|
+
assert istr.cubes(-27, 27) == [istr("-27"), istr("-8"), istr("-1"), istr("0"), istr("1"), istr("8")]
|
|
516
532
|
assert id(istr.cubes(100)) == id(istr.cubes(100)) # test caching
|
|
533
|
+
assert istr.cubes(length=2) == istr.cubes(10, 100)
|
|
534
|
+
with pytest.raises(ValueError, match=re.escape("both bound(s) and length specified")):
|
|
535
|
+
istr.cubes(12, length=2)
|
|
536
|
+
with pytest.raises(ValueError, match=re.escape("no bound(s) or length specified")):
|
|
537
|
+
istr.cubes()
|
|
517
538
|
|
|
518
539
|
|
|
519
540
|
def test_power_ofs():
|
|
@@ -881,15 +902,17 @@ def test_digits_cache():
|
|
|
881
902
|
assert id(d) == id(istr.digits())
|
|
882
903
|
assert int(d) == 4886718345
|
|
883
904
|
|
|
905
|
+
|
|
884
906
|
def test_zip():
|
|
885
|
-
assert list(istr.zip("12","34"))==[(istr("1"), istr("3")),(istr("2"), istr("4"))]
|
|
886
|
-
assert list(istr.zip("12","345"))==[(istr("1"), istr("3")),(istr("2"), istr("4"))]
|
|
887
|
-
assert list(istr.zip("12","34", join=True))==[istr("13"),istr("24")]
|
|
888
|
-
assert list(istr.zip("12","345", join=True))==[istr("13"),istr("24")]
|
|
907
|
+
assert list(istr.zip("12", "34")) == [(istr("1"), istr("3")), (istr("2"), istr("4"))]
|
|
908
|
+
assert list(istr.zip("12", "345")) == [(istr("1"), istr("3")), (istr("2"), istr("4"))]
|
|
909
|
+
assert list(istr.zip("12", "34", join=True)) == [istr("13"), istr("24")]
|
|
910
|
+
assert list(istr.zip("12", "345", join=True)) == [istr("13"), istr("24")]
|
|
889
911
|
with pytest.raises(ValueError):
|
|
890
|
-
list(istr.zip("12","345",strict=True))
|
|
912
|
+
list(istr.zip("12", "345", strict=True))
|
|
891
913
|
with pytest.raises(ValueError):
|
|
892
|
-
list(istr.zip("12","345",join=True,strict=True))
|
|
914
|
+
list(istr.zip("12", "345", join=True, strict=True))
|
|
915
|
+
|
|
893
916
|
|
|
894
917
|
def test_itertools():
|
|
895
918
|
def list100(it):
|
|
@@ -899,9 +922,11 @@ def test_itertools():
|
|
|
899
922
|
assert list(istr.accumulate((1, 3, 4))) == [istr("1"), istr("4"), istr("8")]
|
|
900
923
|
assert list(istr.chain(range(2), range(2, 5))) == [istr("0"), istr("1"), istr("2"), istr("3"), istr("4")]
|
|
901
924
|
assert list(istr.combinations(range(5), r=3)) == list(istr(itertools.combinations(range(5), r=3)))
|
|
902
|
-
assert list(istr.combinations(range(5), r=3,join=True)) == list(map(istr.join,istr(itertools.combinations(range(5), r=3)))
|
|
925
|
+
assert list(istr.combinations(range(5), r=3, join=True)) == list(map(istr.join, istr(itertools.combinations(range(5), r=3))))
|
|
903
926
|
assert list(istr.combinations_with_replacement(range(5), r=3)) == list(istr(itertools.combinations_with_replacement(range(5), r=3)))
|
|
904
|
-
assert list(istr.combinations_with_replacement(range(5), r=3,join=True)) == list(
|
|
927
|
+
assert list(istr.combinations_with_replacement(range(5), r=3, join=True)) == list(
|
|
928
|
+
map(istr.join, istr(itertools.combinations_with_replacement(range(5), r=3)))
|
|
929
|
+
)
|
|
905
930
|
assert list(istr.compress("123456", [1, 0, 1, 0, 1, 1])) == [istr("1"), istr("3"), istr("5"), istr("6")]
|
|
906
931
|
assert list100(istr.count()) == list100(istr(itertools.count()))
|
|
907
932
|
assert list100(istr.cycle(range(10))) == list100(istr(itertools.cycle(range(10))))
|
|
@@ -909,21 +934,22 @@ def test_itertools():
|
|
|
909
934
|
assert list(istr.filterfalse(lambda x: x % 2, range(10))) == [istr("0"), istr("2"), istr("4"), istr("6"), istr("8")]
|
|
910
935
|
assert list(istr.islice("123456", 2)) == [istr("1"), istr("2")]
|
|
911
936
|
assert list(istr.permutations(range(5), 3)) == list(istr(itertools.permutations(range(5), 3)))
|
|
912
|
-
assert list(istr.permutations(range(5), 3, join=True)) == list(map(istr.join,istr(itertools.permutations(range(5), 3))))
|
|
937
|
+
assert list(istr.permutations(range(5), 3, join=True)) == list(map(istr.join, istr(itertools.permutations(range(5), 3))))
|
|
913
938
|
assert list(istr.product(range(5), range(4))) == list(istr(itertools.product(range(5), range(4))))
|
|
914
|
-
assert list(istr.product(range(5), range(4),join=True)) == list(map(istr.join,istr(itertools.product(range(5), range(4))))
|
|
939
|
+
assert list(istr.product(range(5), range(4), join=True)) == list(map(istr.join, istr(itertools.product(range(5), range(4)))))
|
|
915
940
|
assert list100(istr.repeat(10)) == list100(istr(itertools.repeat(10)))
|
|
916
941
|
assert list(istr.starmap(pow, [(2, 5), (3, 2), (10, 3)])) == [istr("32"), istr("9"), istr("1000")]
|
|
917
942
|
assert list(istr.takewhile(lambda x: x < 5, [1, 4, 6, 3, 8])) == [istr("1"), istr("4")]
|
|
918
943
|
assert list(istr.zip_longest("123", "56", fillvalue="0")) == [(istr("1"), istr("5")), (istr("2"), istr("6")), (istr("3"), istr("0"))]
|
|
919
|
-
assert list(istr.zip_longest("123", "56", fillvalue="0",join=True)) == [istr("15"),istr("26"), istr("30")]
|
|
944
|
+
assert list(istr.zip_longest("123", "56", fillvalue="0", join=True)) == [istr("15"), istr("26"), istr("30")]
|
|
920
945
|
assert list(istr.pairwise("1234")) == [(istr("1"), istr("2")), (istr("2"), istr("3")), (istr("3"), istr("4"))]
|
|
921
|
-
assert list(istr.pairwise("1234",join=True)) == [istr("12"), istr("23"), istr("34")]
|
|
946
|
+
assert list(istr.pairwise("1234", join=True)) == [istr("12"), istr("23"), istr("34")]
|
|
922
947
|
assert list(istr.batched("12345", n=2)) == [(istr("1"), istr("2")), (istr("3"), istr("4")), (istr("5"),)]
|
|
923
|
-
assert list(istr.batched("12345", n=2,join=True)) == [istr("12"), istr("34"), istr("5")]
|
|
924
|
-
assert list(istr.batched("1234", n=2,strict=True)) == [(istr("1"), istr("2")), (istr("3"), istr("4"))]
|
|
948
|
+
assert list(istr.batched("12345", n=2, join=True)) == [istr("12"), istr("34"), istr("5")]
|
|
949
|
+
assert list(istr.batched("1234", n=2, strict=True)) == [(istr("1"), istr("2")), (istr("3"), istr("4"))]
|
|
925
950
|
with pytest.raises(ValueError):
|
|
926
|
-
list(istr.batched("12345", n=2,strict=True))
|
|
951
|
+
list(istr.batched("12345", n=2, strict=True))
|
|
952
|
+
|
|
927
953
|
|
|
928
954
|
def test_all_distinct():
|
|
929
955
|
assert istr("abcdef").all_distinct()
|
|
@@ -1033,7 +1059,7 @@ def test_tuple_join():
|
|
|
1033
1059
|
assert istr.is_even(istr(1, 2))
|
|
1034
1060
|
assert istr.is_divisible_by(istr(1, 2), 3)
|
|
1035
1061
|
assert istr.is_triangular(istr(1, 0))
|
|
1036
|
-
assert istr.is_consecutive(istr(1,2,3))
|
|
1062
|
+
assert istr.is_consecutive(istr(1, 2, 3))
|
|
1037
1063
|
assert istr.is_increasing(istr(1, 2))
|
|
1038
1064
|
assert istr.is_non_decreasing(istr(1, 2, 2, 3))
|
|
1039
1065
|
assert istr.is_decreasing(istr(2, 1))
|
|
@@ -1047,7 +1073,7 @@ def test_tuple_join():
|
|
|
1047
1073
|
assert not istr.is_even(istr(1, 3))
|
|
1048
1074
|
assert not istr.is_divisible_by(istr(1, 2), 5)
|
|
1049
1075
|
assert not istr.is_triangular(istr(1, 1))
|
|
1050
|
-
assert not istr.is_consecutive(istr(1,2,4))
|
|
1076
|
+
assert not istr.is_consecutive(istr(1, 2, 4))
|
|
1051
1077
|
assert not istr.is_increasing(istr(1, 1))
|
|
1052
1078
|
assert not istr.is_non_decreasing(istr(1, 2, 2, 1))
|
|
1053
1079
|
assert not istr.is_decreasing(istr(2, 2))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|