istr-python 1.1.16__tar.gz → 1.1.18__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.16
3
+ Version: 1.1.18
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
@@ -387,6 +387,15 @@ It is also possible to test for divisibility of an ordinary int:
387
387
  istr.is_divisible(18, 3) ==> True
388
388
  istr.is_divisible(19, 3) ==> False
389
389
  ```
390
+ The method `divided_by` not only tests divisibility, but also returns the result of the division. If not possible, None will be returned.
391
+ ```
392
+ istr(18).divided_by(3) ==> 6 (actually istr("6"))
393
+ istr(18).divided_by(istr(3)) ==> 6
394
+ istr(19).divided_by(3) ==> None
395
+ istr(19).divided_by(istr(3)) ==> None
396
+ istr.divided_by(18, 3) ==> 6
397
+ istr.divided_by(19, 3) ==> None
398
+ ```
390
399
  #### test for square
391
400
 
392
401
  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.
@@ -693,17 +702,16 @@ Composing can also be done by prefixing a string with '=', like:
693
702
  ```
694
703
  xyz = istr("=xyz")
695
704
  print(f"{xyx=}") # ==> will print xyz=396
696
-
705
+ ```
697
706
  Note that `str(istr("="))` is "=".
698
707
 
699
708
  Composing and assignment can be done by prefixing a string with ':=', like:
700
709
 
701
710
  ```
702
711
  if istr(":=xyz") > 300:
703
- print(f"{xyx=}") # ==> will print xyz=396
704
-
705
- Note that `str(istr(":="))` is ":=" and does not assign the value to a variable.
712
+ print(f"{xyz=}") # ==> will print xyz=396
706
713
  ```
714
+ Note that `str(istr(":="))` is ":=" and does not assign any value.
707
715
 
708
716
  Usually, composing and decomposing uses the globals namespace, but this can be overridden with the namespace parameter. See the test suite for details.
709
717
 
@@ -374,6 +374,15 @@ It is also possible to test for divisibility of an ordinary int:
374
374
  istr.is_divisible(18, 3) ==> True
375
375
  istr.is_divisible(19, 3) ==> False
376
376
  ```
377
+ The method `divided_by` not only tests divisibility, but also returns the result of the division. If not possible, None will be returned.
378
+ ```
379
+ istr(18).divided_by(3) ==> 6 (actually istr("6"))
380
+ istr(18).divided_by(istr(3)) ==> 6
381
+ istr(19).divided_by(3) ==> None
382
+ istr(19).divided_by(istr(3)) ==> None
383
+ istr.divided_by(18, 3) ==> 6
384
+ istr.divided_by(19, 3) ==> None
385
+ ```
377
386
  #### test for square
378
387
 
379
388
  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.
@@ -680,17 +689,16 @@ Composing can also be done by prefixing a string with '=', like:
680
689
  ```
681
690
  xyz = istr("=xyz")
682
691
  print(f"{xyx=}") # ==> will print xyz=396
683
-
692
+ ```
684
693
  Note that `str(istr("="))` is "=".
685
694
 
686
695
  Composing and assignment can be done by prefixing a string with ':=', like:
687
696
 
688
697
  ```
689
698
  if istr(":=xyz") > 300:
690
- print(f"{xyx=}") # ==> will print xyz=396
691
-
692
- Note that `str(istr(":="))` is ":=" and does not assign the value to a variable.
699
+ print(f"{xyz=}") # ==> will print xyz=396
693
700
  ```
701
+ Note that `str(istr(":="))` is ":=" and does not assign any value.
694
702
 
695
703
  Usually, composing and decomposing uses the globals namespace, but this can be overridden with the namespace parameter. See the test suite for details.
696
704
 
@@ -5,7 +5,7 @@
5
5
  # |_||___/ \__||_|
6
6
  # strings you can count on
7
7
 
8
- __version__ = "1.1.16"
8
+ __version__ = "1.1.18"
9
9
  import functools
10
10
  import itertools
11
11
  import types
@@ -193,7 +193,7 @@ class istr(str):
193
193
  Parameters
194
194
  ----------
195
195
  value : any
196
- if str the value will to be interpreted as an int
196
+ if str, the value will to be interpreted as an int
197
197
  istr('8') ==> istr('8')
198
198
  if numeric, the value will be interpreted as an int
199
199
  istr(8) ==> istr('8')
@@ -296,12 +296,13 @@ class istr(str):
296
296
 
297
297
  self = super().__new__(cls, as_str)
298
298
  self._as_int = as_int
299
- if repr_mode == "istr":
300
- self._as_repr = f"{cls.__name__}({repr(as_str)})"
301
- elif repr_mode == "int":
302
- self._as_repr = "?" if as_int is self._nan else repr(as_int)
303
- else:
304
- self._as_repr = repr(as_str)
299
+ match repr_mode:
300
+ case "istr":
301
+ self._as_repr = f"{cls.__name__}({repr(as_str)})"
302
+ case "int":
303
+ self._as_repr = "?" if as_int is self._nan else repr(as_int)
304
+ case _:
305
+ self._as_repr = repr(as_str)
305
306
  self._this_base = base
306
307
  self._this_int_format = int_format
307
308
  self._this_repr_mode = repr_mode
@@ -397,38 +398,45 @@ class istr(str):
397
398
  return not istr.is_divisible_by(self, 2)
398
399
 
399
400
  def is_divisible_by(self, divisor):
400
- return divisor!=0 and istr.interpret_as_int(self) % int(divisor) == 0
401
+ return istr.divided_by(self, divisor) is not None
402
+
403
+ def divided_by(self, divisor):
404
+ if divisor == 0:
405
+ return None
406
+ quotient, remainder = divmod(istr.interpret_as_int(self), int(divisor))
407
+ return istr(quotient) if remainder == 0 else None
401
408
 
402
409
  def is_square(self):
403
- n = istr.interpret_as_int(self)
404
- if n < 1000000:
405
- return n in _squares_up_to_1_000_000()
406
- return n == round(n ** (1 / 2)) ** 2
410
+ return istr.is_power_of(self, 2)
407
411
 
408
412
  def is_cube(self):
409
- n = istr.interpret_as_int(self)
410
- if n < 1000000:
411
- return n in _cubes_up_to_1_000_000()
412
- return n == round(n ** (1 / 3)) ** 3
413
+ return istr.is_power_of(self, 3)
413
414
 
414
415
  def is_power_of(self, exponent):
415
416
  n = istr.interpret_as_int(self)
416
- if exponent < 1:
417
- raise ValueError(f"exponent must be >=1; not {exponent}")
418
- if not isinstance(exponent, int):
419
- raise TypeError(f"exponent must be int; not {type(exponent)}")
417
+ match exponent:
418
+ case 2:
419
+ if n < 1000000:
420
+ return n in _squares_up_to_1_000_000()
421
+ case 3:
422
+ if n < 1000000:
423
+ return n in _cubes_up_to_1_000_000()
424
+ case 0:
425
+ return n == 1
426
+ case _ if exponent < 0:
427
+ raise ValueError(f"exponent must be >=1; not {exponent}")
428
+ case _ if not isinstance(exponent, int):
429
+ raise TypeError(f"exponent must be int; not {type(exponent)}")
420
430
  return n >= 0 and n == round(n ** (1 / exponent)) ** exponent
421
431
 
422
432
  def is_prime(self):
423
433
  n = istr.interpret_as_int(self)
424
- if n < 2:
425
- return False
426
- if n == 2:
427
- return True
428
- if not n & 1:
429
- return False
430
434
  if n < 1000000:
431
435
  return n in _primes_up_to_1_000_000()
436
+
437
+ if not n & 1:
438
+ return False
439
+
432
440
  for x in range(3, int(n**0.5) + 1, 2):
433
441
  if n % x == 0:
434
442
  return False
@@ -441,35 +449,33 @@ class istr(str):
441
449
  """
442
450
  if ("primes", lb_or_ub, ub) in _cache:
443
451
  return _cache["primes", lb_or_ub, ub]
444
- result = sorted(map(cls, _primes(lb_or_ub, ub)))
452
+ result = list(map(cls, _primes(lb_or_ub, ub)))
445
453
  if cache:
446
- _cache["primes", lb_or_ub, ub]=result
447
- return result
454
+ _cache["primes", lb_or_ub, ub] = result
455
+ return result
448
456
 
449
457
  @classmethod
450
458
  def squares(cls, lb_or_ub, ub=None, cache=True):
451
459
  """
452
460
  returns all squares up to a given upperbound or between a given lowerbound and upperbound
453
461
  """
454
- return istr.power_ofs(2,lb_or_ub, ub, cache=cache)
462
+ return istr.power_ofs(2, lb_or_ub, ub, cache=cache)
455
463
 
456
464
  @classmethod
457
465
  def cubes(cls, lb_or_ub, ub=None, cache=True):
458
- return istr.power_ofs(3,lb_or_ub, ub, cache=cache)
466
+ return istr.power_ofs(3, lb_or_ub, ub, cache=cache)
459
467
 
460
468
  @classmethod
461
- def power_ofs(cls, n,lb_or_ub, ub=None, cache=True):
469
+ def power_ofs(cls, n, lb_or_ub, ub=None, cache=True):
462
470
  """
463
471
  returns all power of n up to a given upperbound or between a given lowerbound and upperbound
464
472
  """
465
473
  if ("power_ofs", n, lb_or_ub, ub) in _cache:
466
474
  return _cache["power_ofs", n, lb_or_ub, ub]
467
- result = sorted(map(cls, _power_ofs(n,lb_or_ub, ub)))
475
+ result = list(map(cls, _power_ofs(n, lb_or_ub, ub)))
468
476
  if cache:
469
- _cache["power_ofs", n, lb_or_ub, ub]=result
470
- return result
471
-
472
-
477
+ _cache["power_ofs", n, lb_or_ub, ub] = result
478
+ return result
473
479
 
474
480
  def decompose(self, letters, namespace=None):
475
481
  """
@@ -796,52 +802,62 @@ def _map(func, *iterables, strict=False):
796
802
 
797
803
  yield func(*values)
798
804
 
799
- _cache={}
805
+
806
+ _cache = {}
807
+
800
808
 
801
809
  def _primes(lb_or_ub, ub=None):
802
810
  lb, ub = (0, lb_or_ub) if ub is None else (lb_or_ub, ub)
811
+ if lb < 0:
812
+ lb = 0
803
813
  sieve = bytearray(b"\x01") * (ub + 1)
804
814
  sieve[0:2] = b"\x00\x00"
805
815
 
806
- for i in range(2, int(ub**0.5)+1 ):
816
+ for i in range(2, int(ub**0.5) + 1):
807
817
  if sieve[i]:
808
818
  sieve[i * i : ub + 1 : i] = b"\x00" * (((ub - i * i) // i) + 1)
809
819
 
810
- return {i for i, is_prime in enumerate(sieve) if is_prime and lb<=i<ub}
820
+ return [i for i, is_prime in enumerate(sieve) if is_prime and lb <= i < ub]
811
821
 
812
822
 
813
823
  @functools.lru_cache(maxsize=1)
814
824
  def _primes_up_to_1_000_000():
815
- return _primes(1000000)
825
+ return set(_primes(1000000))
816
826
 
817
827
 
818
828
  @functools.lru_cache(maxsize=1)
819
829
  def _squares_up_to_1_000_000():
820
- return _power_ofs(2,1000000)
830
+ return set(_power_ofs(2, 1000000))
831
+
821
832
 
822
833
  @functools.lru_cache(maxsize=1)
823
834
  def _cubes_up_to_1_000_000():
824
- return _power_ofs(3,1000000)
835
+ return set(_power_ofs(3, 1000000))
825
836
 
826
837
 
827
838
  def _power_ofs(n, lb_or_ub, ub=None):
828
839
  lb, ub = (0, lb_or_ub) if ub is None else (lb_or_ub, ub)
829
- result = set()
830
- if n==0:
831
- if lb<=1<ub:
832
- result.add(1)
833
- elif n==1:
834
- result={*range(lb,ub)}
835
- else:
836
- i = int(lb ** (1 / n))
837
- while (in_ := i**n) < ub:
838
- if in_ >= lb:
839
- result.add(in_)
840
- i += 1
840
+ if lb < 0:
841
+ lb = 0
842
+ result = []
843
+ match n:
844
+ case 0:
845
+ if lb <= 1 < ub:
846
+ result.append(1)
847
+ case 1:
848
+ result = {*range(lb, ub)}
849
+ case _:
850
+ i = int(lb ** (1 / n))
851
+ while (i_n := i**n) < ub:
852
+ if i_n >= lb:
853
+ result.append(i_n)
854
+ i += 1
841
855
  return result
842
856
 
857
+
843
858
  istr.type = type(istr(0))
844
859
 
860
+
845
861
  class istrModule(types.ModuleType):
846
862
  def __call__(self, *args, **kwargs):
847
863
  return istr(*args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: istr-python
3
- Version: 1.1.16
3
+ Version: 1.1.18
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
@@ -387,6 +387,15 @@ It is also possible to test for divisibility of an ordinary int:
387
387
  istr.is_divisible(18, 3) ==> True
388
388
  istr.is_divisible(19, 3) ==> False
389
389
  ```
390
+ The method `divided_by` not only tests divisibility, but also returns the result of the division. If not possible, None will be returned.
391
+ ```
392
+ istr(18).divided_by(3) ==> 6 (actually istr("6"))
393
+ istr(18).divided_by(istr(3)) ==> 6
394
+ istr(19).divided_by(3) ==> None
395
+ istr(19).divided_by(istr(3)) ==> None
396
+ istr.divided_by(18, 3) ==> 6
397
+ istr.divided_by(19, 3) ==> None
398
+ ```
390
399
  #### test for square
391
400
 
392
401
  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.
@@ -693,17 +702,16 @@ Composing can also be done by prefixing a string with '=', like:
693
702
  ```
694
703
  xyz = istr("=xyz")
695
704
  print(f"{xyx=}") # ==> will print xyz=396
696
-
705
+ ```
697
706
  Note that `str(istr("="))` is "=".
698
707
 
699
708
  Composing and assignment can be done by prefixing a string with ':=', like:
700
709
 
701
710
  ```
702
711
  if istr(":=xyz") > 300:
703
- print(f"{xyx=}") # ==> will print xyz=396
704
-
705
- Note that `str(istr(":="))` is ":=" and does not assign the value to a variable.
712
+ print(f"{xyz=}") # ==> will print xyz=396
706
713
  ```
714
+ Note that `str(istr(":="))` is ":=" and does not assign any value.
707
715
 
708
716
  Usually, composing and decomposing uses the globals namespace, but this can be overridden with the namespace parameter. See the test suite for details.
709
717
 
@@ -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.16"
13
+ version = "1.1.18"
14
14
  readme = "README.md"
15
15
  requires-python = ">=3.8"
16
16
  dependencies = []
@@ -343,6 +343,17 @@ def test_is_divisible_by():
343
343
  assert not istr.is_divisible_by(19, 3)
344
344
 
345
345
 
346
+ def test_divided_by():
347
+ assert istr(18).divided_by(3).equals(istr(6))
348
+ assert istr(18).divided_by(istr(3)).equals(istr(6))
349
+ assert istr(19).divided_by(3) is None
350
+ assert istr(19).divided_by(istr(3)) is None
351
+ with pytest.raises(TypeError, match=re.escape(f"not interpretable as int")):
352
+ istr("a").divided_by(3)
353
+ assert istr.divided_by(18, 3).equals(istr(6))
354
+ assert istr.divided_by(19, 3) is None
355
+
356
+
346
357
  def test_is_square():
347
358
  assert not istr(-1).is_square()
348
359
  assert istr(0).is_square()
@@ -441,11 +452,16 @@ def test_cubes():
441
452
  assert istr.cubes(27, 50) == [istr("27")]
442
453
  assert id(istr.cubes(100)) == id(istr.cubes(100)) # test caching
443
454
 
455
+
444
456
  def test_power_ofs():
445
- assert istr.power_ofs(3,1,50) == [istr("1"), istr("8"), istr("27")]
446
- assert istr.power_ofs(5,1, 500) == [istr('1'), istr('32'), istr('243')]
447
- assert id(istr.power_ofs(3,2000)) != id(istr.cubes(3,2000)) # test caching
448
- assert id(istr.power_ofs(3,1000,cache=False)) != id(istr.cubes(3,1000,cache=False)) # test caching
457
+ assert istr.power_ofs(0, 1, 5) == [istr("1")]
458
+ assert istr.power_ofs(0, 1) == []
459
+ assert istr.power_ofs(1, -1, 5) == [istr("0"), istr("1"), istr("2"), istr("3"), istr("4")]
460
+ assert istr.power_ofs(1, 0) == []
461
+ assert istr.power_ofs(3, 1, 50) == [istr("1"), istr("8"), istr("27")]
462
+ assert istr.power_ofs(5, 1, 500) == [istr("1"), istr("32"), istr("243")]
463
+ assert id(istr.power_ofs(3, 2000)) != id(istr.cubes(3, 2000)) # test caching
464
+ assert id(istr.power_ofs(3, 1000, cache=False)) != id(istr.cubes(3, 1000, cache=False)) # test caching
449
465
 
450
466
 
451
467
  def test_join():
File without changes