istr-python 1.1.3__tar.gz → 1.1.4.post0__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.3 → istr_python-1.1.4.post0}/PKG-INFO +24 -2
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/README.md +22 -0
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/istr/istr.py +69 -18
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/istr_python.egg-info/PKG-INFO +24 -2
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/pyproject.toml +1 -1
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/tests/test_istr.py +82 -8
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/istr/LICENSE.txt +0 -0
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/istr/__init__.py +0 -0
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/istr_python.egg-info/SOURCES.txt +0 -0
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/istr_python.egg-info/dependency_links.txt +0 -0
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/istr_python.egg-info/top_level.txt +0 -0
- {istr_python-1.1.3 → istr_python-1.1.4.post0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: istr-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4.post0
|
|
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
|
|
@@ -558,8 +558,30 @@ istr.digits('3-') ==> istr('34567879')
|
|
|
558
558
|
istr.digits('X-') ==> istr('XYZ')
|
|
559
559
|
```
|
|
560
560
|
|
|
561
|
+
#### Decomposing to and composing from letter variables
|
|
562
|
+
|
|
563
|
+
When we have an istr, we can decompose the value into individual one letter (global) variables with the `decompose()` method.
|
|
564
|
+
E.g.
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
istr(485).decompose("abc")
|
|
568
|
+
```
|
|
569
|
+
will set the global variables `a`, `b` and `c` to be set to `istr(4)`. `istr(8)` and` istr(5)`.
|
|
570
|
+
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.
|
|
571
|
+
|
|
572
|
+
With `istr.compose()`, an istr can be constructed from individual (global) variables.
|
|
573
|
+
E.g.
|
|
574
|
+
|
|
575
|
+
```
|
|
576
|
+
x = 3
|
|
577
|
+
y = 9
|
|
578
|
+
z = 6
|
|
579
|
+
test = istr.compose("xyz")
|
|
580
|
+
```
|
|
581
|
+
Now, `test` will be `istr(396)` .
|
|
561
582
|
|
|
562
583
|
#### Subclassing istr
|
|
584
|
+
|
|
563
585
|
When a class is derived from istr, all methods will return that newly derived class.
|
|
564
586
|
|
|
565
587
|
E.g.
|
|
@@ -545,8 +545,30 @@ istr.digits('3-') ==> istr('34567879')
|
|
|
545
545
|
istr.digits('X-') ==> istr('XYZ')
|
|
546
546
|
```
|
|
547
547
|
|
|
548
|
+
#### Decomposing to and composing from letter variables
|
|
549
|
+
|
|
550
|
+
When we have an istr, we can decompose the value into individual one letter (global) variables with the `decompose()` method.
|
|
551
|
+
E.g.
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
istr(485).decompose("abc")
|
|
555
|
+
```
|
|
556
|
+
will set the global variables `a`, `b` and `c` to be set to `istr(4)`. `istr(8)` and` istr(5)`.
|
|
557
|
+
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.
|
|
558
|
+
|
|
559
|
+
With `istr.compose()`, an istr can be constructed from individual (global) variables.
|
|
560
|
+
E.g.
|
|
561
|
+
|
|
562
|
+
```
|
|
563
|
+
x = 3
|
|
564
|
+
y = 9
|
|
565
|
+
z = 6
|
|
566
|
+
test = istr.compose("xyz")
|
|
567
|
+
```
|
|
568
|
+
Now, `test` will be `istr(396)` .
|
|
548
569
|
|
|
549
570
|
#### Subclassing istr
|
|
571
|
+
|
|
550
572
|
When a class is derived from istr, all methods will return that newly derived class.
|
|
551
573
|
|
|
552
574
|
E.g.
|
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
# |_||___/ \__||_|
|
|
6
6
|
# strings you can count on
|
|
7
7
|
|
|
8
|
-
__version__ = "1.1.
|
|
8
|
+
__version__ = "1.1.4"
|
|
9
9
|
import functools
|
|
10
10
|
import math
|
|
11
11
|
import itertools
|
|
12
12
|
import types
|
|
13
13
|
import sys
|
|
14
|
+
import inspect
|
|
14
15
|
|
|
15
16
|
"""
|
|
16
17
|
Note: the changelog is now in changelog.md
|
|
@@ -305,7 +306,7 @@ class istr(str):
|
|
|
305
306
|
# like repr, but if obj is an istr, the as_repr is not used to make sure the
|
|
306
307
|
# the returned value is istr(...) and not infuenced by the repr mode
|
|
307
308
|
if isinstance(obj, self.__class__):
|
|
308
|
-
return f"{obj.__class__.__name__}({super(istr,obj).__repr__()})"
|
|
309
|
+
return f"{obj.__class__.__name__}({super(istr, obj).__repr__()})"
|
|
309
310
|
return repr(obj)
|
|
310
311
|
|
|
311
312
|
def _int_method(self, name, op, *args):
|
|
@@ -365,14 +366,28 @@ class istr(str):
|
|
|
365
366
|
return n % 2 == 1
|
|
366
367
|
|
|
367
368
|
def is_square(self):
|
|
369
|
+
return istr._is_power_of(self, 2)
|
|
370
|
+
|
|
371
|
+
def is_cube(self):
|
|
372
|
+
return istr._is_power_of(self, 3)
|
|
373
|
+
|
|
374
|
+
def is_power_of(self, power_of):
|
|
375
|
+
return istr._is_power_of(self, power_of)
|
|
376
|
+
|
|
377
|
+
@staticmethod
|
|
378
|
+
def _is_power_of(self, power_of):
|
|
368
379
|
if isinstance(self, istr):
|
|
369
380
|
if not self.is_int():
|
|
370
381
|
raise TypeError(f"not interpretable as int: {self._frepr(self)}")
|
|
371
382
|
n = self._as_int
|
|
372
383
|
else:
|
|
373
384
|
n = int(self)
|
|
385
|
+
if power_of < 1:
|
|
386
|
+
raise ValueError(f"power_of must be >=1; not {power_of}")
|
|
387
|
+
if not isinstance(power_of, int):
|
|
388
|
+
raise TypeError(f"power_of must be int; not {type(power_of)}")
|
|
374
389
|
|
|
375
|
-
return n >= 0 and self ==
|
|
390
|
+
return n >= 0 and self == round(n ** (1 / power_of)) ** power_of
|
|
376
391
|
|
|
377
392
|
def is_prime(self):
|
|
378
393
|
if isinstance(self, istr):
|
|
@@ -394,6 +409,27 @@ class istr(str):
|
|
|
394
409
|
return False
|
|
395
410
|
return True
|
|
396
411
|
|
|
412
|
+
def decompose(self, letters, namespace=None):
|
|
413
|
+
"""
|
|
414
|
+
decompose letter variables into local variables
|
|
415
|
+
each letter variable must represent just one character
|
|
416
|
+
same letter variables represent the the same character
|
|
417
|
+
the istr must have the same length as the letters
|
|
418
|
+
"""
|
|
419
|
+
if namespace is None:
|
|
420
|
+
namespace = inspect.currentframe().f_back.f_globals
|
|
421
|
+
lookup = {}
|
|
422
|
+
|
|
423
|
+
for letter, ch in zip(letters, self):
|
|
424
|
+
if letter in lookup and lookup[letter] != ch:
|
|
425
|
+
raise ValueError(f"multiple values found for variable {letter}")
|
|
426
|
+
if not letter.isidentifier():
|
|
427
|
+
raise ValueError(f"{letter} cannot be used as a variable")
|
|
428
|
+
lookup[letter] = ch
|
|
429
|
+
if len(letters) != len(self):
|
|
430
|
+
raise ValueError(f"incorrect number of variables {len(letters)}; should be {len(self)}")
|
|
431
|
+
namespace.update(lookup)
|
|
432
|
+
|
|
397
433
|
def __or__(self, other):
|
|
398
434
|
try:
|
|
399
435
|
return self.__class__(str(self).__add__(other))
|
|
@@ -483,8 +519,7 @@ class istr(str):
|
|
|
483
519
|
|
|
484
520
|
cls._int_format = int_format
|
|
485
521
|
|
|
486
|
-
def __enter__(self):
|
|
487
|
-
...
|
|
522
|
+
def __enter__(self): ...
|
|
488
523
|
|
|
489
524
|
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
490
525
|
self.saved_cls._int_format = self.saved_int_format
|
|
@@ -494,6 +529,8 @@ class istr(str):
|
|
|
494
529
|
def __new__(cls, cls_repr_mode, mode=None):
|
|
495
530
|
if mode is None:
|
|
496
531
|
return cls_repr_mode._repr_mode
|
|
532
|
+
if mode == int:
|
|
533
|
+
mode = "int"
|
|
497
534
|
if mode in ("istr", "str", "int"): # _istr is used only for TypeErrors
|
|
498
535
|
return super().__new__(cls)
|
|
499
536
|
raise TypeError(f"mode not 'istr', 'str' or 'int', but {repr(mode)}")
|
|
@@ -503,8 +540,7 @@ class istr(str):
|
|
|
503
540
|
self.saved_cls = cls
|
|
504
541
|
cls._repr_mode = mode
|
|
505
542
|
|
|
506
|
-
def __enter__(self):
|
|
507
|
-
...
|
|
543
|
+
def __enter__(self): ...
|
|
508
544
|
|
|
509
545
|
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
510
546
|
self.saved_cls._repr_mode = self.saved_repr_mode
|
|
@@ -523,8 +559,7 @@ class istr(str):
|
|
|
523
559
|
self.saved_cls = cls
|
|
524
560
|
cls._base = base
|
|
525
561
|
|
|
526
|
-
def __enter__(self):
|
|
527
|
-
...
|
|
562
|
+
def __enter__(self): ...
|
|
528
563
|
|
|
529
564
|
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
530
565
|
self.saved_cls._base = self.saved_base
|
|
@@ -601,23 +636,39 @@ class istr(str):
|
|
|
601
636
|
result = istr("".join(result))
|
|
602
637
|
cls._digits_cache[key] = result
|
|
603
638
|
return result
|
|
604
|
-
|
|
605
|
-
|
|
639
|
+
|
|
640
|
+
@classmethod
|
|
641
|
+
def compose(cls, letters, namespace=None):
|
|
642
|
+
"""
|
|
643
|
+
compose an istr from individual letter variables
|
|
644
|
+
"""
|
|
645
|
+
if namespace is None:
|
|
646
|
+
namespace = inspect.currentframe().f_back.f_globals
|
|
647
|
+
for letter in letters:
|
|
648
|
+
if letter not in namespace:
|
|
649
|
+
raise ValueError(f"variable {letter} not defined")
|
|
650
|
+
|
|
651
|
+
return istr("").join(istr(namespace[letter]) for letter in letters)
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
istr.type = type(istr(0))
|
|
606
655
|
|
|
607
656
|
|
|
608
|
-
def main():
|
|
609
|
-
|
|
657
|
+
def main(): ...
|
|
658
|
+
|
|
610
659
|
|
|
611
660
|
class istrModule(types.ModuleType):
|
|
612
661
|
def __call__(self, *args, **kwargs):
|
|
613
662
|
return istr.__call__(*args, **kwargs)
|
|
663
|
+
|
|
614
664
|
def __setattr__(self, item, value):
|
|
615
|
-
setattr(istr,item,value)
|
|
616
|
-
|
|
617
|
-
|
|
665
|
+
setattr(istr, item, value)
|
|
666
|
+
|
|
667
|
+
def __getattr__(self, item):
|
|
668
|
+
return getattr(istr, item)
|
|
618
669
|
|
|
619
|
-
sys.modules["istr"].__class__ = istrModule
|
|
620
670
|
|
|
621
671
|
if __name__ == "__main__":
|
|
622
672
|
main()
|
|
623
|
-
|
|
673
|
+
else:
|
|
674
|
+
sys.modules["istr"].__class__ = istrModule
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: istr-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.4.post0
|
|
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
|
|
@@ -558,8 +558,30 @@ istr.digits('3-') ==> istr('34567879')
|
|
|
558
558
|
istr.digits('X-') ==> istr('XYZ')
|
|
559
559
|
```
|
|
560
560
|
|
|
561
|
+
#### Decomposing to and composing from letter variables
|
|
562
|
+
|
|
563
|
+
When we have an istr, we can decompose the value into individual one letter (global) variables with the `decompose()` method.
|
|
564
|
+
E.g.
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
istr(485).decompose("abc")
|
|
568
|
+
```
|
|
569
|
+
will set the global variables `a`, `b` and `c` to be set to `istr(4)`. `istr(8)` and` istr(5)`.
|
|
570
|
+
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.
|
|
571
|
+
|
|
572
|
+
With `istr.compose()`, an istr can be constructed from individual (global) variables.
|
|
573
|
+
E.g.
|
|
574
|
+
|
|
575
|
+
```
|
|
576
|
+
x = 3
|
|
577
|
+
y = 9
|
|
578
|
+
z = 6
|
|
579
|
+
test = istr.compose("xyz")
|
|
580
|
+
```
|
|
581
|
+
Now, `test` will be `istr(396)` .
|
|
561
582
|
|
|
562
583
|
#### Subclassing istr
|
|
584
|
+
|
|
563
585
|
When a class is derived from istr, all methods will return that newly derived class.
|
|
564
586
|
|
|
565
587
|
E.g.
|
|
@@ -5,11 +5,11 @@ import sys
|
|
|
5
5
|
import re
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
if __name__ == "__main__": # to make the tests run without the pytest cli
|
|
9
|
+
file_folder = os.path.dirname(__file__)
|
|
10
|
+
os.chdir(file_folder)
|
|
11
|
+
sys.path.insert(0, file_folder + "/../istr")
|
|
12
|
+
|
|
13
13
|
import pytest
|
|
14
14
|
|
|
15
15
|
import istr
|
|
@@ -330,7 +330,43 @@ def test_is_square():
|
|
|
330
330
|
assert istr.is_square(4)
|
|
331
331
|
assert istr.is_square(16)
|
|
332
332
|
|
|
333
|
-
|
|
333
|
+
def test_is_cube():
|
|
334
|
+
assert not istr(-1).is_cube()
|
|
335
|
+
assert istr(0).is_cube()
|
|
336
|
+
assert istr(1).is_cube()
|
|
337
|
+
assert not istr(2).is_cube()
|
|
338
|
+
assert istr(8).is_cube()
|
|
339
|
+
assert istr(27).is_cube()
|
|
340
|
+
assert not istr(99).is_cube()
|
|
341
|
+
with pytest.raises(TypeError, match=re.escape(f"not interpretable as int")):
|
|
342
|
+
istr("a").is_cube()
|
|
343
|
+
assert istr.is_cube(0)
|
|
344
|
+
assert istr.is_cube(1)
|
|
345
|
+
assert not istr.is_cube(2)
|
|
346
|
+
assert istr.is_cube(8)
|
|
347
|
+
assert istr.is_cube(27)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def test_is_power_of():
|
|
351
|
+
assert not istr(-1).is_power_of(3)
|
|
352
|
+
assert istr(0).is_power_of(3)
|
|
353
|
+
assert istr(1).is_power_of(3)
|
|
354
|
+
assert not istr(2).is_power_of(3)
|
|
355
|
+
assert istr(8).is_power_of(3)
|
|
356
|
+
assert istr(27).is_power_of(3)
|
|
357
|
+
assert not istr(99).is_power_of(3)
|
|
358
|
+
with pytest.raises(TypeError, match=re.escape(f"not interpretable as int")):
|
|
359
|
+
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)
|
|
365
|
+
with pytest.raises(TypeError):
|
|
366
|
+
istr(1).is_power_of(3.1)
|
|
367
|
+
with pytest.raises(ValueError):
|
|
368
|
+
istr(1).is_power_of(-1)
|
|
369
|
+
|
|
334
370
|
def test_is_prime():
|
|
335
371
|
assert not istr(0).is_prime()
|
|
336
372
|
assert not istr(1).is_prime()
|
|
@@ -677,12 +713,50 @@ def test_all_distinct():
|
|
|
677
713
|
|
|
678
714
|
|
|
679
715
|
def test_subclassing():
|
|
680
|
-
class jstr(istr.type):
|
|
681
|
-
...
|
|
716
|
+
class jstr(istr.type): ...
|
|
682
717
|
|
|
683
718
|
assert jstr(5).equals(jstr(5))
|
|
684
719
|
assert repr(jstr(*range(3))) == "(jstr('0'), jstr('1'), jstr('2'))"
|
|
685
720
|
|
|
686
721
|
|
|
722
|
+
def test_decompose():
|
|
723
|
+
istr("123").decompose("xyz")
|
|
724
|
+
assert x == 1
|
|
725
|
+
assert y == 2
|
|
726
|
+
assert z == 3
|
|
727
|
+
istr(456).decompose("xyz")
|
|
728
|
+
assert x == 4
|
|
729
|
+
assert y == 5
|
|
730
|
+
assert z == 6
|
|
731
|
+
istr(1231).decompose("xyzx")
|
|
732
|
+
assert x == 1
|
|
733
|
+
assert y == 2
|
|
734
|
+
assert z == 3
|
|
735
|
+
namespace = {}
|
|
736
|
+
istr(123).decompose("xyz", namespace=namespace)
|
|
737
|
+
assert namespace == dict(x=istr(1), y=istr(2), z=istr(3))
|
|
738
|
+
|
|
739
|
+
with pytest.raises(ValueError):
|
|
740
|
+
istr(1234).decompose("xyzx")
|
|
741
|
+
with pytest.raises(ValueError):
|
|
742
|
+
istr(1234).decompose("xyz")
|
|
743
|
+
with pytest.raises(ValueError):
|
|
744
|
+
istr(12).decompose("xyz")
|
|
745
|
+
with pytest.raises(ValueError):
|
|
746
|
+
istr(123).decompose("xy1")
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
def test_compose():
|
|
750
|
+
x = 1
|
|
751
|
+
y = 2
|
|
752
|
+
z = 3
|
|
753
|
+
s = istr.compose("xyz")
|
|
754
|
+
assert s == 123
|
|
755
|
+
with pytest.raises(ValueError):
|
|
756
|
+
s = istr.compose("wxyz", globals()) # w is not defined
|
|
757
|
+
s = istr.compose("xyz", namespace=dict(x=3, y=istr(4), z="5"))
|
|
758
|
+
assert s == 345
|
|
759
|
+
|
|
760
|
+
|
|
687
761
|
if __name__ == "__main__":
|
|
688
762
|
pytest.main(["-vv", "-s", "-x", __file__])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|