istr-python 1.1.24__tar.gz → 1.1.26__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.24
3
+ Version: 1.1.26
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
@@ -379,6 +379,22 @@ It is also possible to test for even/odd of an ordinary int:
379
379
  istr.is_even(4) ==> True
380
380
  istr.is_odd(5) ==> True
381
381
  ```
382
+
383
+ #### test for palindrome
384
+
385
+ It is possible to test whether an istr is palindromic, like
386
+ ```
387
+ istr(12321).is_palindrome() ==> True
388
+ istr('aba').is_palindrome() ==> True
389
+ istr(123).is_palindrome() ==> False
390
+ ```
391
+ It is also possible to test for a palindrome for anything that can be converted to a str:
392
+ ```
393
+ istr.is_palindrome(121) ==> True
394
+ istr.is_palindrome('no devil lived on') ==> True
395
+ istr.is_palindrome(min) ==> False
396
+ ```
397
+
382
398
  #### test for divisibility
383
399
 
384
400
  It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
@@ -366,6 +366,22 @@ It is also possible to test for even/odd of an ordinary int:
366
366
  istr.is_even(4) ==> True
367
367
  istr.is_odd(5) ==> True
368
368
  ```
369
+
370
+ #### test for palindrome
371
+
372
+ It is possible to test whether an istr is palindromic, like
373
+ ```
374
+ istr(12321).is_palindrome() ==> True
375
+ istr('aba').is_palindrome() ==> True
376
+ istr(123).is_palindrome() ==> False
377
+ ```
378
+ It is also possible to test for a palindrome for anything that can be converted to a str:
379
+ ```
380
+ istr.is_palindrome(121) ==> True
381
+ istr.is_palindrome('no devil lived on') ==> True
382
+ istr.is_palindrome(min) ==> False
383
+ ```
384
+
369
385
  #### test for divisibility
370
386
 
371
387
  It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
@@ -5,7 +5,7 @@
5
5
  # |_||___/ \__||_|
6
6
  # strings you can count on
7
7
 
8
- __version__ = "1.1.24"
8
+ __version__ = "1.1.26"
9
9
  import functools
10
10
  import itertools
11
11
  import types
@@ -17,7 +17,7 @@ import copy
17
17
  import bisect
18
18
 
19
19
  """
20
- Note: the changelog is now in changelog.md
20
+ Note: the changelog is in changelog.md
21
21
 
22
22
  You can view the changelog on www.salabim.org/istr/changelog
23
23
 
@@ -198,6 +198,10 @@ class istr(str):
198
198
  istr('8') ==> istr('8')
199
199
  if numeric, the value will be interpreted as an int
200
200
  istr(8) ==> istr('8')
201
+ if str and starts with '=', the value will be retrieved from letter variables and other characters unprocessed, e.g.
202
+ if a=4 and b=32, istr('=ab1') will be istr'('4321')
203
+ if str and starts with ':=', the value will be retrieved from letter variables. And the corresponding value will be set, e.g.
204
+ if a=4 and b=32, istr(':=ab') will be istr'('432') and ab will be assigned that value too.
201
205
  if a dict (or subtype of dict), the same type dict will be returned with all values istr'ed
202
206
  istr({0: 0, 1: 1, 2: 4}) ==> {0: istr('0'), 1: istr('1'), 2: istr('4')}
203
207
  if an iterator, the iterator will be mapped with istr
@@ -281,9 +285,9 @@ class istr(str):
281
285
  value = str(cls.compose(value[1:], namespace=get_namespace(namespace)))
282
286
  else: # it's :=
283
287
  var_name = value[2:]
284
- value = str(cls.compose(value[2:], namespace=get_namespace(namespace)))
285
288
  if not var_name.isidentifier():
286
289
  raise ValueError(f"{var_name!r} is not a valid identifier")
290
+ value = str(cls.compose(var_name, namespace=get_namespace(namespace)))
287
291
  get_namespace(namespace)[var_name] = cls(value)
288
292
  as_int = cls._to_int(value, base)
289
293
  if as_int is cls._nan or isinstance(value, str):
@@ -311,7 +315,7 @@ class istr(str):
311
315
  return hash((self.__class__, str(self)))
312
316
 
313
317
  def __eq__(self, other):
314
- if isinstance(other, self.__class__):
318
+ if isinstance(other, istr):
315
319
  if self.is_int() and other.is_int():
316
320
  return self._as_int == other._as_int
317
321
  if isinstance(other, str):
@@ -398,6 +402,9 @@ class istr(str):
398
402
 
399
403
  def is_odd(self):
400
404
  return not istr.is_divisible_by(self, 2)
405
+
406
+ def is_palindrome(self):
407
+ return str(self)==str(self)[::-1]
401
408
 
402
409
  def is_divisible_by(self, divisor):
403
410
  return istr.divided_by(self, divisor) is not None
@@ -410,7 +417,7 @@ class istr(str):
410
417
 
411
418
  def is_prime(self):
412
419
  n = istr.interpret_as_int(self)
413
- if n < 1000000:
420
+ if n < 1_000_000:
414
421
  return n in istr._primes_up_to_1_000_000_as_set()
415
422
 
416
423
  if not n & 1:
@@ -451,7 +458,7 @@ class istr(str):
451
458
  if sieve[i]:
452
459
  sieve[i * i : ub + 1 : i] = b"\x00" * (((ub - i * i) // i) + 1)
453
460
 
454
- return list(map(cls, ([i for i, is_prime in enumerate(sieve) if is_prime and lb <= i < ub])))
461
+ return list(map(cls, ([i for i, is_prime in enumerate(sieve) if is_prime and lb <= i < ub]))) # range check just to be sure
455
462
 
456
463
  @classmethod
457
464
  @functools.lru_cache
@@ -483,11 +490,11 @@ class istr(str):
483
490
  return n == 1
484
491
  case 1:
485
492
  return True
486
- case _ if exponent < 0:
487
- raise ValueError(f"exponent must be >=1; not {exponent}")
493
+ case x if x < 0:
494
+ raise ValueError(f"exponent must be >=0; not {exponent}")
488
495
  case _ if not isinstance(exponent, int):
489
496
  raise TypeError(f"exponent must be int; not {type(exponent)}")
490
- case _ if n < 1000000:
497
+ case _ if n < 1_000_000:
491
498
  return n in istr._power_ofs_up_to_1_000_000_as_set(exponent)
492
499
  case _:
493
500
  ...
@@ -523,7 +530,7 @@ class istr(str):
523
530
  result = []
524
531
  case 1:
525
532
  result = cls(list(range(lb, ub)))
526
- case _ if (exponent % 2 == 0 or lb >= 0) and ub <= 1_000_000:
533
+ case x if (x % 2 == 0 or lb >= 0) and ub <= 1_000_000:
527
534
  result = in_range(cls._power_ofs_up_to_1_000_000(exponent), lb, ub)
528
535
  case _:
529
536
  result = cls._power_ofs(exponent, lb, ub)
@@ -532,10 +539,10 @@ class istr(str):
532
539
  return result
533
540
 
534
541
  @classmethod
535
- def _power_ofs(cls, n, lb, ub):
536
- if n % 2 == 0:
542
+ def _power_ofs(cls, exponent, lb, ub):
543
+ if exponent % 2 == 0:
537
544
  lb = max(0, lb)
538
- match n:
545
+ match exponent:
539
546
  case 0:
540
547
  if lb <= 1 < ub:
541
548
  result = [1]
@@ -546,11 +553,11 @@ class istr(str):
546
553
  case _:
547
554
  result = []
548
555
  if lb < 0: # can't be the case for even n (because of above limiting)
549
- i = -int((-lb) ** (1 / n))
556
+ i = -int((-lb) ** (1 / exponent))
550
557
  else:
551
- i = int(lb ** (1 / n))
552
- while (i_n := i**n) < ub:
553
- if i_n >= lb:
558
+ i = int(lb ** (1 / exponent))
559
+ while (i_n := i**exponent) < ub:
560
+ if i_n >= lb: # just to be sure
554
561
  result.append(i_n)
555
562
  i += 1
556
563
 
@@ -573,8 +580,7 @@ class istr(str):
573
580
  same one-letter variables represent the the same character
574
581
  the istr must have the same length as the letters
575
582
  """
576
- if namespace is None:
577
- namespace = inspect.currentframe().f_back.f_globals
583
+ namespace = get_namespace(namespace)
578
584
 
579
585
  lookup = {}
580
586
  for letter, ch in zip(letters, self):
@@ -592,12 +598,11 @@ class istr(str):
592
598
  """
593
599
  compose an istr from individual letter variables
594
600
  """
595
- if namespace is None:
596
- namespace = inspect.currentframe().f_back.f_globals
597
- namespace |= {ch: ch for ch in "0123456789"}
601
+ namespace = get_namespace(namespace) | {ch: ch for ch in "0123456789_"}
598
602
  for letter in letters:
599
- if letter not in namespace:
600
- raise ValueError(f"variable {repr(letter)} not defined")
603
+ if letter.isidentifier():
604
+ if letter not in namespace:
605
+ raise ValueError(f"variable {repr(letter)} not defined")
601
606
  s = "".join(str(namespace[letter]) for letter in letters)
602
607
  return cls(s)
603
608
 
@@ -924,16 +929,22 @@ def in_range(lst, lb, ub):
924
929
 
925
930
  def get_namespace(namespace):
926
931
  if namespace is None:
927
- frame = sys._getframe().f_back
928
- while frame:
929
- module_name = frame.f_globals.get("__name__")
930
- if module_name != __name__:
931
- break
932
- frame = frame.f_back
932
+ frame = real_caller_frame()
933
933
  namespace = frame.f_globals
934
934
  return namespace
935
935
 
936
936
 
937
+ def real_caller_frame():
938
+ # this will return the frame of the first frame on the stack that does not belong to this module,
939
+ # so in the 'user' space
940
+ frame = inspect.currentframe()
941
+ frame_name = frame.f_globals.get("__name__")
942
+ frame = frame.f_back
943
+ while frame is not None and frame_name == frame.f_globals.get("__name__"):
944
+ frame = frame.f_back
945
+ return frame
946
+
947
+
937
948
  istr.type = type(istr(0))
938
949
 
939
950
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: istr-python
3
- Version: 1.1.24
3
+ Version: 1.1.26
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
@@ -379,6 +379,22 @@ It is also possible to test for even/odd of an ordinary int:
379
379
  istr.is_even(4) ==> True
380
380
  istr.is_odd(5) ==> True
381
381
  ```
382
+
383
+ #### test for palindrome
384
+
385
+ It is possible to test whether an istr is palindromic, like
386
+ ```
387
+ istr(12321).is_palindrome() ==> True
388
+ istr('aba').is_palindrome() ==> True
389
+ istr(123).is_palindrome() ==> False
390
+ ```
391
+ It is also possible to test for a palindrome for anything that can be converted to a str:
392
+ ```
393
+ istr.is_palindrome(121) ==> True
394
+ istr.is_palindrome('no devil lived on') ==> True
395
+ istr.is_palindrome(min) ==> False
396
+ ```
397
+
382
398
  #### test for divisibility
383
399
 
384
400
  It is possible to test whether an istr is divisible by a given value with the `is_divisible_by method,` e.g.
@@ -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.24"
13
+ version = "1.1.26"
14
14
  readme = "README.md"
15
15
  requires-python = ">=3.10"
16
16
  dependencies = []
@@ -332,6 +332,16 @@ def test_even_odd():
332
332
  assert istr.is_odd(11111111)
333
333
 
334
334
 
335
+ def test_is_palindrome():
336
+ assert istr(121).is_palindrome()
337
+ assert istr(1234321).is_palindrome()
338
+ assert not istr(123).is_palindrome()
339
+ assert istr('aba').is_palindrome()
340
+ assert not istr('abc').is_palindrome()
341
+ assert istr('').is_palindrome()
342
+ assert istr.is_palindrome('121')
343
+ assert istr.is_palindrome(121)
344
+
335
345
  def test_is_divisible_by():
336
346
  assert istr(18).is_divisible_by(3)
337
347
  assert istr(18).is_divisible_by(istr(3))
@@ -964,9 +974,10 @@ def test_compose():
964
974
  assert istr(":=xyz").equals(istr(123))
965
975
  assert xyz.equals(istr(123))
966
976
 
967
- assert istr(":=xyz0").equals(istr(1230))
968
- assert xyz0.equals(istr(1230))
969
-
977
+ assert istr(":=xyz_000").equals(istr('123_000'))
978
+ assert xyz_000.equals(istr('123_000'))
979
+ assert xyz_000==123000
980
+
970
981
  with pytest.raises(ValueError, match=re.escape(f"'0xyz' is not a valid identifier")):
971
982
  istr(":=0xyz")
972
983
 
File without changes