istr-python 1.1.44__tar.gz → 1.1.45__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.44
3
+ Version: 1.1.45
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
@@ -370,14 +370,20 @@ a, b, c = istr(*range(3)) ==> a=istr('0') , b=istr('1'), c=istr('2')
370
370
  ```
371
371
  #### Alternative way of range specification
372
372
 
373
- Instead of `istr(range(..))` it is possible to use `istr,range(..)` instead, like
373
+ Instead of `istr(range(..))` it is possible to use `istr.range(..)` instead, like
374
374
 
375
375
  `list(istr.range(3,6))` ==> `[istr('3'), istr('4'), istr('5')]`
376
376
 
377
- In contrast to the builtin `range`, `istr.range` supports a non keyword parameter `length`:
377
+ In contrast to the builtin `range`, `istr.range` supports a keyword parameter `length`:
378
378
 
379
379
  `list(istr.range(length=3))` is equivalent to `istr.range(100, 1000)`
380
380
 
381
+ On top of this, `istr.range` support a keyword parameter `distinct`, to return a generator that yields only numbers with distinct numbers:
382
+
383
+ `list(istr.range(98,104,distinct=True))` is `[istr('98'), istr('102'), istr('103')]`
384
+
385
+ For `istr.range(length=..., distict=True)` the generation is optimized (not just checking each possible value).
386
+
381
387
  #### square root, cubic root and nth root
382
388
  The methods `sqrt`, `cbrt`, `nth_root`provide the square root, cubic root and nth root of an istr. If there is no integer root, the fallback value (default `istr('0')` will be returned.
383
389
  ```
@@ -547,15 +553,15 @@ istr.divisors(18, False) ==> [istr('1'), istr('18'), istr('2'), istr('9'), istr(
547
553
 
548
554
  #### test whether all characters are distinct
549
555
 
550
- With the `all_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
556
+ With the `is_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
551
557
 
552
558
  ```
553
- istr('01234').all_distict() ==> True
554
- istr('012340').all_distict() ==> False
559
+ istr('01234').is_distict() ==> True
560
+ istr('012340').is_distict() ==> False
555
561
  n98 = istr(98)
556
562
  n100 = n98 + 2
557
- istr(n98).all_distinct() ==> True
558
- istr(n100).all_distinct() ==> False
563
+ istr(n98).is_distinct() ==> True
564
+ istr(n100).is_distinct() ==> False
559
565
  ```
560
566
  #### test if characters are consecutive
561
567
 
@@ -824,8 +830,17 @@ Alternatively, it is possible to get a list of all squares, cubes, power_ofs or
824
830
 
825
831
  `istr.squares (length=2)` returns a list of all squares of length 2, so between 10 and 99.
826
832
 
833
+ If the keyword `distinct` is True, all values that are not distinct, will be excluded, like:
834
+
835
+ `list(istr.primes(list(istr.primes(100,132,distinct=True))` is `[istr('103'), istr('107'), istr('109'), istr('127')]`, thus leaving out 101, 113 and 131
836
+
827
837
  Unless `cache=False` is specified, the query result is cached.
828
838
 
839
+ #### filter distinct_only
840
+
841
+ With `istr.distinct_only` any iterable can skip values that are not distinct:
842
+ `list(istr.distinct_only([10, 11, 100, 123, 'abc', 'aaa']))` is `[istr('10'), istr('123'), istr('abc')]`
843
+
829
844
  #### Safe indexing (getitem)
830
845
 
831
846
  The `istr.getitem` method is essentially, a safe version of indexing an istr.
@@ -357,14 +357,20 @@ a, b, c = istr(*range(3)) ==> a=istr('0') , b=istr('1'), c=istr('2')
357
357
  ```
358
358
  #### Alternative way of range specification
359
359
 
360
- Instead of `istr(range(..))` it is possible to use `istr,range(..)` instead, like
360
+ Instead of `istr(range(..))` it is possible to use `istr.range(..)` instead, like
361
361
 
362
362
  `list(istr.range(3,6))` ==> `[istr('3'), istr('4'), istr('5')]`
363
363
 
364
- In contrast to the builtin `range`, `istr.range` supports a non keyword parameter `length`:
364
+ In contrast to the builtin `range`, `istr.range` supports a keyword parameter `length`:
365
365
 
366
366
  `list(istr.range(length=3))` is equivalent to `istr.range(100, 1000)`
367
367
 
368
+ On top of this, `istr.range` support a keyword parameter `distinct`, to return a generator that yields only numbers with distinct numbers:
369
+
370
+ `list(istr.range(98,104,distinct=True))` is `[istr('98'), istr('102'), istr('103')]`
371
+
372
+ For `istr.range(length=..., distict=True)` the generation is optimized (not just checking each possible value).
373
+
368
374
  #### square root, cubic root and nth root
369
375
  The methods `sqrt`, `cbrt`, `nth_root`provide the square root, cubic root and nth root of an istr. If there is no integer root, the fallback value (default `istr('0')` will be returned.
370
376
  ```
@@ -534,15 +540,15 @@ istr.divisors(18, False) ==> [istr('1'), istr('18'), istr('2'), istr('9'), istr(
534
540
 
535
541
  #### test whether all characters are distinct
536
542
 
537
- With the `all_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
543
+ With the `is_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
538
544
 
539
545
  ```
540
- istr('01234').all_distict() ==> True
541
- istr('012340').all_distict() ==> False
546
+ istr('01234').is_distict() ==> True
547
+ istr('012340').is_distict() ==> False
542
548
  n98 = istr(98)
543
549
  n100 = n98 + 2
544
- istr(n98).all_distinct() ==> True
545
- istr(n100).all_distinct() ==> False
550
+ istr(n98).is_distinct() ==> True
551
+ istr(n100).is_distinct() ==> False
546
552
  ```
547
553
  #### test if characters are consecutive
548
554
 
@@ -811,8 +817,17 @@ Alternatively, it is possible to get a list of all squares, cubes, power_ofs or
811
817
 
812
818
  `istr.squares (length=2)` returns a list of all squares of length 2, so between 10 and 99.
813
819
 
820
+ If the keyword `distinct` is True, all values that are not distinct, will be excluded, like:
821
+
822
+ `list(istr.primes(list(istr.primes(100,132,distinct=True))` is `[istr('103'), istr('107'), istr('109'), istr('127')]`, thus leaving out 101, 113 and 131
823
+
814
824
  Unless `cache=False` is specified, the query result is cached.
815
825
 
826
+ #### filter distinct_only
827
+
828
+ With `istr.distinct_only` any iterable can skip values that are not distinct:
829
+ `list(istr.distinct_only([10, 11, 100, 123, 'abc', 'aaa']))` is `[istr('10'), istr('123'), istr('abc')]`
830
+
816
831
  #### Safe indexing (getitem)
817
832
 
818
833
  The `istr.getitem` method is essentially, a safe version of indexing an istr.
@@ -5,7 +5,7 @@
5
5
  # |_||___/ \__||_|
6
6
  # strings you can count on
7
7
 
8
- __version__ = "1.1.44"
8
+ __version__ = "1.1.45"
9
9
  import functools
10
10
  import itertools
11
11
  import types
@@ -492,21 +492,25 @@ class istr(str):
492
492
  return True
493
493
 
494
494
  @classmethod
495
- def primes(cls, start=None, stop=None, /, length=None, cache=True):
495
+ def primes(cls, start=None, stop=None, /, length=None, distinct=False, cache=True):
496
496
  """
497
497
  returns all primes up to a given upperbound or between a given lowerbound and upperbound
498
498
  alternatively, the length can be given
499
499
  """
500
500
  start, stop, step = process_start_stop_step_length(start, stop, 1, length)
501
- if (cls, "primes", start, stop) in _cache:
502
- return _cache[cls, "primes", start, stop]
501
+ if (cls, "primes", start, stop,distinct) in _cache:
502
+ return _cache[cls, "primes", start, stop,distinct]
503
503
 
504
504
  if stop <= 1_000_000:
505
505
  result = in_range(cls._primes_up_to_1_000_000(), start, stop)
506
506
  else:
507
507
  result = cls._primes(start, stop)
508
+ if distinct:
509
+ result=list(filter(cls.is_distinct,result))
510
+
508
511
  if cache:
509
- _cache[cls, "primes", start, stop] = result
512
+ _cache[cls, "primes", start, stop,distinct] = result
513
+
510
514
  return result
511
515
 
512
516
  @classmethod
@@ -560,23 +564,23 @@ class istr(str):
560
564
  return n == round(n ** (1 / exponent)) ** exponent
561
565
 
562
566
  @classmethod
563
- def squares(cls, start=None, stop=None, /, length=None, cache=True):
567
+ def squares(cls, start=None, stop=None, /, length=None, distinct=False, cache=True):
564
568
  """
565
569
  returns all squares up to a given stop or between a given start and stop
566
570
  alternatively, the length can be given
567
571
  """
568
- return cls.power_ofs(2, start, stop, length=length, cache=cache)
572
+ return cls.power_ofs(2, start, stop, length=length, distinct=distinct, cache=cache)
569
573
 
570
574
  @classmethod
571
- def cubes(cls, start=None, stop=None, /, length=None, cache=True):
575
+ def cubes(cls, start=None, stop=None, /, length=None, distinct=False,cache=True):
572
576
  """
573
577
  returns all cubes up to a given stop or between a given start and stop
574
578
  alternatively, the length can be given
575
579
  """
576
- return cls.power_ofs(3, start, stop, length=length, cache=cache)
580
+ return cls.power_ofs(3, start, stop, length=length, distinct=distinct,cache=cache)
577
581
 
578
582
  @classmethod
579
- def power_ofs(cls, exponent, start=None, stop=None, /, length=None, cache=True):
583
+ def power_ofs(cls, exponent, start=None, stop=None, /, length=None, distinct=None, cache=True):
580
584
  """
581
585
  returns all power of n up to a given stop or between a given start and stop
582
586
  alternatively, the length can be given
@@ -584,8 +588,8 @@ class istr(str):
584
588
  start, stop, step = process_start_stop_step_length(start, stop, 1, length)
585
589
  exponent = check_integer(exponent, "exponent")
586
590
 
587
- if (cls, "power_ofs", exponent, start, stop) in _cache:
588
- return _cache[cls, "power_ofs", exponent, start, stop]
591
+ if (cls, "power_ofs", exponent, start, stop,distinct) in _cache:
592
+ return _cache[cls, "power_ofs", exponent, start, stop,distinct]
589
593
  match exponent:
590
594
  case 0:
591
595
  if start <= 1 < stop:
@@ -598,8 +602,10 @@ class istr(str):
598
602
  result = in_range(cls._power_ofs_up_to_1_000_000(exponent), start, stop)
599
603
  case _:
600
604
  result = cls._power_ofs(exponent, start, stop)
605
+ if distinct:
606
+ result=list(filter(cls.is_distinct,result))
601
607
  if cache:
602
- _cache[cls, "power_ofs", exponent, start, stop] = result
608
+ _cache[cls, "power_ofs", exponent, start, stop, distinct] = result
603
609
  return result
604
610
 
605
611
  @classmethod
@@ -721,8 +727,12 @@ class istr(str):
721
727
  def __getitem__(self, key):
722
728
  return self.__class__(super().__getitem__(key))
723
729
 
724
- def all_distinct(self):
725
- return len(self) == len(set(self))
730
+ def is_distinct(self):
731
+ s = istr.interpret_as_str(self)
732
+ return len(s) == len(set(s))
733
+
734
+ all_distinct=is_distinct
735
+
726
736
 
727
737
  def is_consecutive(self):
728
738
  s = istr.interpret_as_str(self)
@@ -877,6 +887,7 @@ class istr(str):
877
887
  def enumerate(cls, iterable, start=0):
878
888
  for i, value in enumerate(iterable, int(start)):
879
889
  yield cls(i), value
890
+
880
891
 
881
892
  @staticmethod
882
893
  @functools.lru_cache(maxsize=1)
@@ -930,13 +941,26 @@ class istr(str):
930
941
  return istr._long_sqrt(self.number)
931
942
  case "line_lengths":
932
943
  return [*map(len, istr._long_sqrt(self.number))]
944
+ case "indents":
945
+ lines = self.output
946
+ result = []
947
+ for line in lines.splitlines():
948
+ if '-' not in line:
949
+ for i,c in enumerate(line[2:]):
950
+ if c != ' ':
951
+ break
952
+ else:
953
+ i=0
954
+ result.append(i)
955
+ return result
956
+
933
957
  case "output":
934
958
  lines = istr._long_sqrt(self.number)
935
959
  result = []
936
960
  extra = len(number) % 2 == 0
937
961
  result.append(f" {extra*' '}{' '.join(lines[0])}")
938
962
  result.append(f" {len(lines[1])*'-'}")
939
- result.append(f"\/{lines[1]}")
963
+ result.append(f"\\/{lines[1]}")
940
964
 
941
965
  last_len = len(lines[2])
942
966
  for i, line in enumerate(lines):
@@ -970,6 +994,8 @@ class istr(str):
970
994
 
971
995
  return lines
972
996
 
997
+
998
+
973
999
  def long_multiplication(self, number, as_str=False):
974
1000
  class NumbersHolder:
975
1001
  def __init__(self, number0, number1):
@@ -1157,7 +1183,18 @@ class istr(str):
1157
1183
  self.saved_cls._base = self.saved_base
1158
1184
 
1159
1185
  @classmethod
1160
- def range(cls, start=None, stop=None, step=1, /, length=None, base=None, int_format=None, repr_mode=None):
1186
+ def _range_distinct(cls,length):
1187
+ for c0 in range(1,10):
1188
+ for crest in itertools.permutations(itertools.chain(range(0,c0),range(c0+1,10)),length-1):
1189
+ yield cls(c0)|cls.join(cls(crest))
1190
+
1191
+ @classmethod
1192
+ def range(cls, start=None, stop=None, step=1, /, length=None, distinct=False, base=None, int_format=None, repr_mode=None):
1193
+ if distinct:
1194
+ if length is None:
1195
+ return filter(cls.is_distinct,_range(cls,start,stop,step,length,base=base, int_format=int_format, repr_mode=repr_mode))
1196
+ else:
1197
+ return cls._range_distinct(length)
1161
1198
  return _range(cls, start, stop, step, length, base=base, int_format=int_format, repr_mode=repr_mode)
1162
1199
 
1163
1200
  @classmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: istr-python
3
- Version: 1.1.44
3
+ Version: 1.1.45
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
@@ -370,14 +370,20 @@ a, b, c = istr(*range(3)) ==> a=istr('0') , b=istr('1'), c=istr('2')
370
370
  ```
371
371
  #### Alternative way of range specification
372
372
 
373
- Instead of `istr(range(..))` it is possible to use `istr,range(..)` instead, like
373
+ Instead of `istr(range(..))` it is possible to use `istr.range(..)` instead, like
374
374
 
375
375
  `list(istr.range(3,6))` ==> `[istr('3'), istr('4'), istr('5')]`
376
376
 
377
- In contrast to the builtin `range`, `istr.range` supports a non keyword parameter `length`:
377
+ In contrast to the builtin `range`, `istr.range` supports a keyword parameter `length`:
378
378
 
379
379
  `list(istr.range(length=3))` is equivalent to `istr.range(100, 1000)`
380
380
 
381
+ On top of this, `istr.range` support a keyword parameter `distinct`, to return a generator that yields only numbers with distinct numbers:
382
+
383
+ `list(istr.range(98,104,distinct=True))` is `[istr('98'), istr('102'), istr('103')]`
384
+
385
+ For `istr.range(length=..., distict=True)` the generation is optimized (not just checking each possible value).
386
+
381
387
  #### square root, cubic root and nth root
382
388
  The methods `sqrt`, `cbrt`, `nth_root`provide the square root, cubic root and nth root of an istr. If there is no integer root, the fallback value (default `istr('0')` will be returned.
383
389
  ```
@@ -547,15 +553,15 @@ istr.divisors(18, False) ==> [istr('1'), istr('18'), istr('2'), istr('9'), istr(
547
553
 
548
554
  #### test whether all characters are distinct
549
555
 
550
- With the `all_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
556
+ With the `is_distinct` method, it is possible to test whether all characters are distinct (i.e. no character appears more than once).
551
557
 
552
558
  ```
553
- istr('01234').all_distict() ==> True
554
- istr('012340').all_distict() ==> False
559
+ istr('01234').is_distict() ==> True
560
+ istr('012340').is_distict() ==> False
555
561
  n98 = istr(98)
556
562
  n100 = n98 + 2
557
- istr(n98).all_distinct() ==> True
558
- istr(n100).all_distinct() ==> False
563
+ istr(n98).is_distinct() ==> True
564
+ istr(n100).is_distinct() ==> False
559
565
  ```
560
566
  #### test if characters are consecutive
561
567
 
@@ -824,8 +830,17 @@ Alternatively, it is possible to get a list of all squares, cubes, power_ofs or
824
830
 
825
831
  `istr.squares (length=2)` returns a list of all squares of length 2, so between 10 and 99.
826
832
 
833
+ If the keyword `distinct` is True, all values that are not distinct, will be excluded, like:
834
+
835
+ `list(istr.primes(list(istr.primes(100,132,distinct=True))` is `[istr('103'), istr('107'), istr('109'), istr('127')]`, thus leaving out 101, 113 and 131
836
+
827
837
  Unless `cache=False` is specified, the query result is cached.
828
838
 
839
+ #### filter distinct_only
840
+
841
+ With `istr.distinct_only` any iterable can skip values that are not distinct:
842
+ `list(istr.distinct_only([10, 11, 100, 123, 'abc', 'aaa']))` is `[istr('10'), istr('123'), istr('abc')]`
843
+
829
844
  #### Safe indexing (getitem)
830
845
 
831
846
  The `istr.getitem` method is essentially, a safe version of indexing an istr.
@@ -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.44"
13
+ version = "1.1.45"
14
14
  readme = "README.md"
15
15
  requires-python = ">=3.10"
16
16
  dependencies = []
@@ -3,6 +3,8 @@ import itertools
3
3
  import os
4
4
  import sys
5
5
  import re
6
+ import time
7
+ from collections.abc import Iterator
6
8
 
7
9
  if __name__ == "__main__": # to make the tests run without the pytest cli
8
10
  import os, sys # three lines to use the local package and chdir
@@ -196,7 +198,30 @@ def test_range():
196
198
  with pytest.raises(ValueError, match=re.escape("both bound(s) and length specified")):
197
199
  istr.range(10, length=2)
198
200
 
199
-
201
+ assert list(map(int,istr.range(98,124,distinct=True)))==[98, 102, 103, 104, 105, 106, 107, 108, 109, 120, 123]
202
+ assert sorted(map(int,set(istr.range(length=2))-set(istr.range(length=2,distinct=True))))==[11, 22, 33, 44, 55, 66, 77, 88, 99]
203
+
204
+ assert type(istr.range(12)).__name__=='_range'
205
+ assert isinstance(istr.range(12,distinct=True),Iterator)
206
+ assert type(istr.range(length=2)).__name__=='_range'
207
+ assert isinstance(istr.range(length=2,distinct=True),Iterator)
208
+
209
+ t0=time.perf_counter()
210
+ result0=istr.range(length=4,distinct=True)
211
+ duration0=time.perf_counter()-t0
212
+ t0=time.perf_counter()
213
+ result1=istr.range(1000,10000,distinct=True)
214
+ duration1=time.perf_counter()-t0
215
+ assert list(result0)==list(result1)
216
+ assert duration1>duration0*2
217
+
218
+
219
+ def test_various_distinct():
220
+ assert sorted(set(istr.primes(80,140))-set(istr.primes(80,140,distinct=True)))==istr([101, 113, 131])
221
+ assert sorted(set(istr.squares(150))-set(istr.squares(150,distinct=True)))==istr([100, 121,144])
222
+ assert sorted(set(istr.cubes(10000))-set(istr.cubes(10000,distinct=True)))==istr([343, 1000, 1331,2744,3375,8000])
223
+ assert sorted(set(istr.power_ofs(4,50000))-set(istr.power_ofs(4,50000,distinct=True)))==istr([6561,10000,14641])
224
+
200
225
  def test_misc():
201
226
  assert istr("") == ""
202
227
  assert istr("") != 0
@@ -1128,8 +1153,26 @@ def test_decompose():
1128
1153
  istr(12).decompose("xyz")
1129
1154
  with pytest.raises(ValueError):
1130
1155
  istr(123).decompose("xy1")
1156
+
1157
+ def test_eval():
1158
+ global a,b,c
1159
+ a = 3
1160
+ b = istr('4')
1161
+ c=istr(7)
1162
+ assert istr.eval('a + b')==7
1163
+ assert istr.eval('a + b = c')
1164
+ assert istr.eval('a + b > 6')
1165
+ assert not istr.eval('a + b < 6')
1166
+ with pytest.raises(ValueError):
1167
+ assert istr.eval('d')
1131
1168
 
1132
-
1169
+ assert istr('?a + b')==7
1170
+ assert istr('?a + b = c')
1171
+ assert istr('?a + b > 6')
1172
+ assert not istr('?a + b < 6')
1173
+ with pytest.raises(ValueError):
1174
+ assert istr('?d')
1175
+
1133
1176
  def test_ceil():
1134
1177
  assert istr(1000).ceil() == 1000
1135
1178
  assert istr(1000).ceil(1) == 1000
File without changes