Please wait...
PlainTools’ Docs — PlainTools Documentation
Skip to main content
Back to top
PlainTools’ Docs§
Welcome to PlainTools’ documentation!
Current Version: 1.3.241226.0
PlainTools is a Python 3 library designed to streamline simple operations,
loops and contexts with easy to handle classes and functions.
Library’s Github Repo
Library’s PyPi Repo
Author’s Github Profile
This documentation site itself can be accessed from the Python
interpreter | environment with:
import PlainTools as pt
pt.site(pt)
Copy to clipboard
You can easily install & upgrade this package with:
pip install -U plaintools
Copy to clipboard
[Table of Contents]
Numeric Constructor
The base solution for numberic-related problems.
pt.Numeric
pt.pnumber()
Constructor Classes & Custom Objects
Custom object constructors.
pt.Container
pt.Constant
Formatter Functions
Formatted data in an easy way.
pt.plist()
pt.punit()
pt.pnumber()
pt.pdecimals()
pt.pstring()
pt.pistype()
pt.prange()
pt.pinterval()
pt.psequence()
pt.pindex()
pt.pminmax()
pt.plen()
pt.pabs()
pt.psum()
pt.pimport()
pt.pframe()
Statement & Extension Functions
Powerful, close to native syntax and easy to use.
pt.let()
pt.const()
pt.attempt()
pt.printnl()
pt.printc()
pt.doc()
pt.site()
pt.skip()
pt.evinput()
pt.timeout()
pt.loop()
pt.showcall()
pt.namespace()
Debugger & Utility Functions
Easy debugging management with console operations.
pt.debug()
pt.clear()
pt.eof()
pt.deepframe()
Operator & Instantiated Classes
Ready-to-use instances of functional objects.
pt.TIME
pt.STUB
pt.NULL
pt.ERROR
pt.MAIN
pt.SILENCE
pt.LOGGING
pt.TRY
pt.LINES
pt.SEVAL
pt.TEST
Documentation Utilities
Functions designed to retrieve and explore available documentation.
pt.doc()
pt.site()
pt.moduleview()
[Introduction]
The following needs to be considered when reading these docs:
It is encouraged that you use the suggested convention:
import PlainTools as pt
It is assumed that you know the basics of Python’s data types.
Type annotations were made in a more verbose way, with:
X: Integer
Instead of:
X: int
Unfamiliar types like ‘Real’ can be associated with what
meaning they first convey:
Having a variable declared as:
Y: Real
Is the same as:
Y: int | float | decimal.Decimal | fractions.Fraction
And is itself similar or very closely related to ‘numbers.Real’.
Any documentation found here can be similarly provided in the Python
context or environment running this module by the use of the
pt.doc() function as:
pt.doc(*objs)
Where objs is the desired function(s) or class(es) to obtain documentation from.
This will print the target’s documentation, if any, to the current console
or stdout in general. Note that pt.doc() also works with any builtin
object as well as third-party ones, given they have any type of docstring themselves.
[Resources & Credits]
This project would be impossible to make without the
support of my friends and family around me.
Thank you everyone.
Credits & Thanks:
A big thanks to my professor Vitor Tocci, who lectured Introduction to Data Proccessing and introduced me into Python programming when I had little background experience in the matter.
Thanks to my beloved girlfriend Ana Caroline, who tirelessly heard me babble about Python through hours in these past few months where I was still learning and improving much of my understanding of the language. I love you!
Thanks to all of my friends and family, including @CherryGM who helped me revise this documentation and greatly encouraged me. And to everyone who helped me debug this documentation itself when I had zero Sphinx knowledge. I hope I did well enough and hope to do much more in the future!
Disclaimer: LLM (AI) Use:
ChatGPT, Codeium and Gemini (The later not credited as it did not “contribute” directly to the codebase) were used in this project development.
If you, your university or your company (in general, if the target for this library’s use) does have any restrictions, implicit or explicit, against the use of LLMs in production | academic coding, please avert from using this library.
Any code “contributed” by or taken from any LLM (AI) use, prompted directly or indirectly, was heavily debugged and tested (to the best of my personal capacity).
If any code comes across as sluggish, unnoptimized or just bad, please let me know by raising an issue or DMing me at GitHub (@gabrielmsilva00), or email me at @gabrielmaia.silva00@gmail.com.
For a more clear understanding of the above, you will probably find 40~80% LLM-made code wherever attributes from the following libraries were used:
re
ast
itertools
functools
multiprocessing
References & Auxiliary Material:
AutoPEP8, code formatting;
Sphinx, documentation;
Sphinx-Design, styling;
StackOverflow, definitions, concepts;
W3Schools, theories, fundamentals, methods;
OpenAI’s ChatGPT, definitions, debugging;
Claude AI, additional debugging;
Codeium AI, autocompletion, code refactoring & cleaning;
SingleFile, HTML factoring of this Sphinx-generated documentation;
JetBrains Mono, this awesome font!
Google Search Console:
This page is currently verified at Google Search.
No Google Analytics is currently being used anywhere in this project.
Numeric Constructor§
(Goto Table of Contents)
Before anything else, it is important to lay down the documentation for the
base of any numeric-related definition or class. And such is the
pt.Numeric class and pt.pnumber() function.
class pt.Numeric(obj) → Numeric[Number]:§
Numeric Class
This is the base class for the numeric constructor.
It dynamically inherits from its obj object’s class, meaning that
a float object gives a direct inheritance of float to the
pt.Numeric instance, gaining all its properties.
Possible inheritances are defined inside the numbers.Number
standard definition of Python 3.11+ numbers library.
Failure to inherit from a recognizable Number type will default the
instance to pt.Numeric(float(‘nan’))
pt.pnumber(*objs) → Number | List[Number]:§
Plain Numeric Constructor.
For each input, this function constructs a pt.Numeric class
instance which dynamically inherits from the input’s parent class.
This means that all numeric types such as int, float,
complex, decimal.Decimal and fractions.Fraction
given to this function will generate a subclass instance with
inheritance from the object’s own numeric class.
Failure to convert the object to a numeric type (contained into the
numbers.Number definition) will result in an instance of
float(‘nan’) class being returned.
Examples:
Considering x = pt.pnumber(1/3);
print(x)
0.333...
The pt.pnumber() constructor detects repeating decimals.
x.value
0.3333333333333333
This is used for proper arithmetic operations.
x.period
3
This is the detected repeating decimal.
x.fraction
(1, 3)
The fraction part can be used for reconstruction of the numeric object.
x.type
<class 'float'>
The x object dynamically inherited from the float class.
Args:
obj: Any | Iterable[Any]
Object(s) to pt.SEVAL(obj) into a numeric type.
Failure to safely convert to a numeric type will return float('nan').
Returns:
R: Number | List[Number]
Numeric-type instance(s) (of isinstance(obj, numbers.Number)).
The numeric class created dynamically inherits from the obj own class.
Note:
It is computationally expensive: non-ideal for long sequences.
The trade-off [precision <> speed] is comparable to decimal.Decimal’s
implementation, where pt.Numeric(n) takes about 100x more time
to instantiate than i.e. float(n).
However, its default precision of {n:.15g} for any given n and its
capability of detecting repeating decimals etc. make it much more presentable
and workable, eliminating MANY cases of float-imprecison errors.
Constructor Classes & Custom Objects§
(Goto Table of Contents)
Constructor Classes have the purpose of creating Custom Objects that can be
manipulated in specific, useful ways. A more in-depth explanation is provided
in each’s documentation below.
class pt.Container§
Container Class; dict Subclass.
A flexible dict-class that supports various operations and
transformations. Unlike a standard dictionary, a Container
is unpacked by its items rather than by its keys.
Note: Containers can’t have numeric keys due to how their
keys are directly associated to its instance attributes.
However, any String type is a valid key type.
Attempting to update a Container instance with
enumerated dictionaries will raise a TypeError.
The Container supports basic arithmetic operations on a
per-key basis, meaning that you can operate an iterable
to a Container, where each ordered element operates each
key’s value until exhaustion; Where as single, non-iterable
operations are performed on the entire Container.
Containers can have its values accessed as attributes
when calling for their keys. This means that assigned
attributes into this class are also added to the
Container’s keys with the designated value.
Examples:
C1 = Container(a=1, b=2)
Creates a Container as {‘a’: 1, ‘b’: 2}
C2 = Container(‘c’)
Creates a Container as {‘c’: None}
C1(C2) # Same as C1 += C2
Aggregates C1 and C2 for {‘a’: 1, ‘b’: 2, ‘c’: None}
C1.fill(4)
Alocates ‘4’ to the first encounter of None value in C1.
Methods:
.sort(*args, **kwargs): Self
Sorts the keys (or values) of the Container; Optional lambda.
.shove(*vals): Self
Adds the values to the keys following the current order of keys.
.fill(*vals, target=None, exhaust=True): Self
Fills in any target vals in the Container with provided vals.
target argument can be a lambda | function | builtin | singleton.
exhaust argument defines if fill is finite or cyclic infinite.
.order(*keys): Self
Orders the keys of the Container as provided.
.filter(*keys): Self
Filters the keys of the Container as provided.
.remove(*keys): Self
Removes the keys of the Container as provided.
.only(*keys): Container
Returns a Container copy containing only the specified keys.
.without(*keys): Container
Returns a Container copy without the specified keys.
.keyval(): dict
Returns a copy of the dictionary object as {keys: values}.
.key(*keys): list
Returns a list of keys in Container; Optional filter for values.
.val(*vals): list
Returns a list of values in Container; Optional filter for keys.
.sub(): Tuple[Container]
Returns a tuple of each k: v pair in Container, as Containers.
.copy(): Container
Returns a deepcopy of the current Container.
Operators:
Any basic arithmetic operator is supported as in:
Container <> Container;
Container <> other
Operations with non-iterables are valid as long as the operation to every
Container[k:v] <> other is valid for all given (v).
Container(f=1, g=2, h=3) * 2 == Container(f=2, g=4, h=6)
Container(Bob=’Foo’) - 5 == Container(Bob=’Foo’, Bob_1=5)
Operations with iterables are valid as long as the operation to every pair
Container[k:v] <> other[i] is valid for the max possible [i].
Container(R=5, S=10) * (2,3,4) == Container(R=10, S=30)
Container(T=2,U=4,V=6) - {2,3} == Container(T=0, U=1, V=6)
Remainder of Container <> other[i] operations are ignored, as the
result is a Container type with the same keys as the involved Container.
Container(i=2, j=3) * [2, 3, 4] == Container(i=4, j=9)
Remainer of Container <> Container operations aggregate non-similar
keys into the final result, unmodified, as no C1[k] <> C2[k] is valid.
Container(f=5) - Container(g=10) == Container(f=5, g=10)
add (+)
Adds the values of another Container, or from a sequence.
i.e. Container(a=5) + (b=4) == Container(a=5, b=4)
i.e. Container(a=5, b=4) + [3, 4] == Container(a=8, b=8)
sub (-)
Subtracts the values of another Container or from a sequence.
i.e. Container(x=5, y=10) - 3 == Container(x=2, y=7)
i.e. Container(a=5, b=4) - Container(c=3, d=2)
mul (*)
Multiplies the values of another Container or from a sequence.
i.e. Container(x=5) * 2 == Container(x=10)
i.e. Container(x=5, y=4) * (3, 4) == Container(x=15, y=16)
truediv (/)
Divides the values of another Container or from a sequence.
i.e. Container(T=2, U=4, V=6) / [1, 2, 3] == Container(T=2.0, U=2.0, V=2.0)
floordiv (//)
Floor divides the values of another Cont. or from a sequence.
i.e. Container(A=12.5) // Container(A=3.5) == Container(A=3.0)
mod (%)
Modulo operates on the values of another Cont. or from a seq.
i.e. Container(B=7.5) % Container(B=2) == Container(B=1.5)
pow (**)
Raises the values of the Container to the power of.
i.e. Container(C=5) ** Container(C=3) == Container(C=125)
Return:
Container
A dict subclass object that is callable.
class pt.Constant§
Immutable Constants.
Wraps a value and provides a constant, immutable interface to it.
Overrides most of the standard dunder methods to ensure immutability.
Non-dunder methods can be called, but will only return the Constant’s
value and won’t modify the Constant itself or it’s value in any way.
Examples:
x = Constant(5)
Create an immutable constant with a value of 5
i.e. x + 5 == 10
i.e. x += 5 ; x == 5
pi = Constant(math.pi)
Assign ‘math.pi’ to ‘pi’ as an immutable constant
i.e. const(rpi=pi*2) # ‘rpi’ is also a Constant now.
Args:
value: Any
The value to be wrapped as a Constant.
Return:
Constant
An immutable Constant instance wrapping the provided value.
Formatter Functions§
(Goto Table of Contents)
Formatter functions are intended to take a variety of types as input and
output data in a formatted, previsible way.
pt.plist(*vals) → List[Any]:§
Plain List.
Transforms iterable sets into a flat list; Recursive unpacking.
Pseudocode:
If one (List) contains other (Lists) inside:
(Unpack) the (Lists) inside, keeping only the (Values).
This repeats until all (Lists) only contains plain (Values).
Return a final (List) containing only the (Values) of everything given.
Examples:
plist((1, 2), [3, 4], {5, 6})
[1, 2, 3, 4, 5, 6]
plist({0: 10, 1: 20, 2: 40})
[10, 20, 40]
plist({‘A’:10, ‘B’:15, ‘C’:20, ‘D’:{“X”: 100, “Y”: 200, “Z”: 300}})
[10, 15, 20, 100, 200, 300]
Args:
*vals: Any | Iterable[Any]
Data entries to be flattened.
Return:
R: List[Any]
Flat list containing the data entries.
pt.punit(*its) → Any | Tuple[Any]:§
Plain Units.
Unpacks single units inside iterable sets;
Returns a single value if there is only one value in the iterable.
Pseudocode:
If any given (List) contains a (Single) (Value):
(Unpack) the (List), so it becomes it’s plain (Value).
If (Final List) contains (Multiple) (Values):
Return (Final List).
Else, if (Final List) contains a (Single) (Value):
Return (Value).
Examples:
punit([5], [3, 2], [[9]])
(5, [3, 2], 9)
punit([1, 2], 3, (4,))
([1, 2], 3, 4)
punit([[7, 8]], {9})
(7, 8, 9)
Args:
*its: Iterable[Any]
Iterable sets.
Return:
R: Any | Tuple[Any]
A single item or a tuple of items.
pt.pdecimals(*nums) → Integer:§
Plain Decimals.
Identifies the highest number of decimal places in a set.
If the number has a repeating period (detected by pt.pnumber()), the
return value will be float(‘inf’), even if the Python representation of
the float(num) is limited to 16 decimal places.
Pseudocode:
Start (Decimals) as 0.
(For Each) (Value):
If (String) of (Number) in (Value) have (‘.’) character:
(Count) how many (Digits) there is after (‘.’) character.
If (Digits) is greater than (Decimals):(Decimals) become number of (Digits).
Return final (Decimals) value.
Examples:
pdecimals(1.23, 4.5678, 3.1, 5.67890)
4
pdecimals(1/3)
inf
pdecimals(math.pi)
15
Args:
[*]nums: Number | Iterable[Number | String]
Numbers to be formatted.
Return:
R: Integer
Highest quantity of decimal places found.
pt.pstring(*objs, sep=', ') → String:§
Plain String.
More comprehensible ‘str()’ operator; Concatenates elements of iterables.
Pseudocode:
Check (Type) of (Value):
If (Type) is (Dictionary):(Include) the (Keys) and (Values) of (Dictionary) in the (String).
Else, if (Type) is a (List), (Tuple) or (Set):(Include) all (Values) in the (String).
Else, if (Type) is (Something Else):(Include) the String of (Type) in the (String).
Return final version of (String).
Examples:
pstring({0: ‘a’, 1: ‘b’, 2: ‘c’})
‘0: a, 1: b, 2: c’
pstring([1, 2, 3], (4, 5), {6, 7})
‘1, 2, 3, 4, 5, 6, 7’
pstring(‘Hello’, [‘world’, ‘!’], sep = ‘ ‘)
‘Hello world !’
Args:
*objs: Any | Iterable[Any]
Objects to be converted to string.
Kwargs:
sep: String = ‘, ‘
Separator between elements in the final string.
Return:
R: String
Single string containing the concatenated elements.
pt.pistype(obj, *types) → Bool | Tuple[Bool]:§
Plain Type Check.
Checks if the object is an instance of the provided types.
Pseudocode:
Check (Type) of (Value) and (Type) of (Asked Types):
(For Each) (Asked Type):
If (Type) of (Value) is the same as this (Asked Type):(Include) (True) in the final (Result)
Else, if (Type) of (Value) is not the same as this (Asked Type):(Include) (False) in the final (Result)
Return the final (Result).
Examples:
pistype(‘Hello’, String, Iterable, Set)
(True, True, False)
pistype([1, 2, 3], List, Tuple, Iterable)
(True, False, True)
pistype(42.0, Number, Integer, Float)
(True, False, True)
Args:
obj: Any
Object to be checked against.
*types: Type
Types to compare using isinstance(obj, type).
Return:
R: Bool | Tuple[Bool]
Sequence of Booleans according to the checks.
pt.prange(*args, type='list') → Iterable[Number]:§
Plain Range.
Simulates the ‘range()’ function from Python 2.x.
Instead of a range object, returns a plain Iterable of specified type.
Default Iterable type is ‘list’. The ‘chain’ type is also available.
Stop argument is the de-facto stop, being the last value of list.
Args functionality is the same as standard ‘range()’ built-in function.
Pseudocode:
Check for the given (Parameters):
If there is (One) (Parameter):Return a (List) (Starting) at (0) and (Stopping) at
(Parameter) with an (Step) of (1).
Else, if there are (Two) (Parameters):Return a (List) (Starting) at (1st Parameter) and (Stopping)
at (2nd Parameter) with a (Step) of (1).
Else, if there are (Three) (Parameters):Return a (List) (Starting) at (1st Parameter), (Stopping)
at (2nd Parameter) with a (Step) of (3rd Parameter).
Else, if there are (Four) (Parameters):Return an (Iterable) of (Type) (4th Parameter),
(Starting) at (1st Parameter), (Stopping) at
(2nd Parameter) and with a (Step) of (3rd Parameter).
Return the final (Iterable).
Examples:
prange(5)
[0, 1, 2, 3, 4]
prange(5, 2.5, 0.5, ‘tuple’)
(5, 4.5, 4, 3.5, 3, 2.5)
prange(0, 15, 4, ‘dict’)
{0: 0, 1: 4, 2: 8, 3: 12}
Args:
*args: Number
Functionality varies according to arguments:
A single parameter determines the stop; with start of 1.
Two parameters determines start and stop; with step of 1.
Three parameters determines start, stop and step; returning a list.
Four parameters determines start, stop, step and type
Kwargs:
start: Number = None
Start value of the iterable.
stop: Number = None
Stop value of the iterable.
step: Number = None
Step value of the iterable.
type: String = None
Return type (‘tuple’, ‘list’, ‘set’, ‘dict’, ‘chain’).
Return:
R: Iterable[Number] = Iterable (defined in ‘get’) containing the range.
pt.pinterval(*args, type='list') → Iterable[Number]:§
Plain Interval.
Generates a list of numeric elements equidistant between them, from start to stop.
Pseudocode:
Check for the given (Parameters):
If there is (One) (Parameter):Return a (List) (Starting) at (0) and (Stopping) at
(100) with (Parameter) (Values).
Else, if there are (Two) (Parameters):Return a (List) (Starting) at (0) and (Stopping)
at (2nd Parameter) with (1st Parameter) number of (Values).
Else, if there are (Three) (Parameters):Return a (List) (Starting) at (2nd Parameter), (Stopping)
at (3rd Parameter) with (1st Parameter) number of (Values).
Else, if there are (Four) (Parameters):Return an (Iterable) of (Type) (4th Parameter),
(Starting) at (2nd Parameter), (Stopping) at
(3rd Parameter) and with (1st Parameter) number of (Values).
Return the final (Iterable).
Examples:
pinterval(5)
[0, 25, 50, 75, 100]
pinterval(3, 5)
[0, 2.5, 5]
pinterval(5, 10, 0, ‘dict’)
{0: 10, 1: 7.5, 2: 5, 3: 2.5, 4: 0}
Args:
*args: Number
Can contain up to four positional arguments:
One argument: divs;List of [0, 0±n1, 0±n2, (…), 100] with ‘divs’ elements.
Two arguments: divs and stop;List of [0, 0±n1, 0±n2, (…), stop] with ‘divs’ elements.
Three arguments: divs, start and stop;List of [start, start±n1, (…), stop] with ‘divs’ elems.
Four arguments: divs, start, stop and type.Iterable of type(start, (…), stop) with ‘divs’ elements.
Kwargs:
divs: Number = None
Number of elements in the returned Iterable.
start: Number = None
Start value of the interval (default is 0).
stop: Number = None
Stop value of the interval.
type: String = None
Type of the returned collection (‘list’, ‘tuple’, ‘set’, ‘dict’).
Return:
R: Iterable[Number]
List of numeric values with equidistant intervals.
pt.psequence(*nums, abs_lim=None, rel_lim=10e3) → Chain[Real]:§
Plain Sequence.
Generates a numerical sequence based on the provided numbers or patterns.
It supports the use of ellipsis (…) to denote the continuation
of the sequence with a defined step or to an optional limit.
Args:
*nums: Real | Iterable[Real]
The numbers or patterns used to generate the sequence.
Ellipsis (…) can be used to sign continuation of sequence.
Kwargs:
abs_lim: Real = None
The absolute limit for the sequence, if provided.
rel_lim: Real = 10e3
The relative limit, as a multiplier to the last expressed num.
Return:
R: Chain[Real]
A chain of numbers representing the generated sequence.
Examples:
psequence(1, 2, 3, …, 10)
Generates the sequence equivalent to (1, 2, …, 9, 10).
psequence(1, 3, 5, …, abs_lim=150)
Generates the sequence equivalent to (1, 3, …, 147, 149).
psequence(0.1)
Generates the sequence equiv. to (0.1, 0.2, …, 999.9, 1000).
Notes:
If an ellipsis (…) is used, the function will infer the step
from the preceding numbers in the sequence.
If abs_lim is provided, the sequence will stop when it reaches
or exceeds this limit.
If rel_lim is provided, it will be used to calculate the maximum
limit based on the last number in the sequence before the ellipsis.
The sequence continues either until the absolute
or relative limit is met.
pt.pindex(target, *its) → Integer | None | Tuple[Integer | None]:§
Plain Index.
Returns the index of the first occurrence of ‘target’ in ‘its’.
Pseudocode:
Look for (Target) in all (Iterables) provided:
(For Each) (Iterable):
If (Target) is found in this (Iterable):(Include) (Target)’s (Index) in the final (Result).
Else, if (Target) is not found in this (Iterable):(Include) (None) in the final (Result).
Return the final (Result).
Examples:
pindex(True, (False, False, True))
2
pindex(5, range(10))
5
pindex(1, (False, False, True), [‘a’, ‘b’, ‘c’], range(10))
(2, None, 1)
Args:
target: Any
Value to search for in the provided iterables.
*its: Iterable[Any]
One or more iterables to be checked for ‘target’.
Return:
R: Integer | None | Tuple[Integer | None]
Index of the first ‘target’ occurrence into provided iterables.
pt.pminmax(*vals) → Container[String: Number]:§
Plain Min & Max.
Returns the minimum and maximum values from a set of numbers.
Pseudocode:
Given any (Values) or (Iterables[Values]):Return both (Minimum) and (Maximum) from all given
(Values).
Examples:
pminmax([5, 2, -8, ‘15*2’])
{‘min’: -8, ‘max’: 30}
pminmax([5, 2, -8, ‘15*2’]).min
-8
pminmax(1, -2, [‘1.5 * 2’], math.pi)[1][1]
3.141592653589793
Args:
*vals: Number | Iterable[Number]
Objects to be compared for their value.
Return:
R: Container[String: Number]
A Container, derived from dict, containing min & max values.
pt.plen(*iters) → Container[String: Integer]:§
Plain Length.
Returns the minimum and maximum sizes of given iterables.
Pseudocode:
Given any (Iterables):Return both (Minimum) and (Maximum) (Size) from all given
(Iterables).
Examples:
pcount([1, 2, 3], (4, 5), {6})
{‘min’: 1, ‘max’: 3}
pcount([1, 2, 3, [4, 5], 6], (“ABCDEFGHIJ”, “XYZ”), {}).min
0
pcount({0: 1, 1: -2, 2: 4, 3: -8, 4: 16, 5: 32}).max
5
Args:
*iters: Any | Iterable[Any]
Objects to be counted for their sizes.
Return:
R: Container[String: Integer]
A Container , derived from dict, containing min & max lengths.
pt.pabs(*nums) → Container[String: Number]§
Plain Absolutes.
Identifies the lowest or highest absolute number of a set.
Returns a Container with the min, max, original min, original max values.
Pseudocode:
(Flatten) the input (Values).
- Calculate the (Absolute) (Maximum) (Value).
- Calculate the (Absolute) (Minimum) (Value).
- Identify the (Original) (Maximum) and (Minimum) (Values).
Return a (Container) with (Absolute) and (Original) (Minimum) and (Maximum) (Values).
Examples:
x = pabs([5, 8, -2, ‘15*2’])
x == {‘min’:2, ‘max’:30, ‘ogmin’:-2, ‘ogmax’: 30}
x.min == 2
x.ogmin == -2
x.max == x.ogmax == 30
y = pabs(-1, -2, [‘1.5 * 2’], math.pi)
y[‘min’] == 1
y[‘ogmin’] == -2
y[‘max’] == 3.141592653589793
zmin, zmax, ztruemin, ztruemax = pabs(prange(-10, 0, 1))
zmin == 0
zmax == 10
ztruemin == -10
ztruemax == 0
Args:
*nums: Number | Iterable[Number | String]
Objects to be counted.
Return:
R: Container[String: Number]
A Container, with min, max, original min and original max.
pt.psum(*nums) → Real:§
Plain Sum.
Returns the sum of possible numbers from given sets.
Examples:
psum([5, 2, -8, ‘15*2’])
29
psum(prange(-10, 0))
-55
psum(Container(John=2.55, Maria=3.14, Paul=1.75))
7.44
Args:
*nums: Real | Iterable[Real | String]
Objects to be counted.
Return:
R: Real
Sum of numbers.
pt.pimport(libs, funs=None) → Module | Object | Tuple[Module | Object]:§
Plain Import.
Helper function for local scope importation.
Pseudocode:
(Split) (Libs) into individual (Module Names).
(For Each) (Module Name):
Attempt to (Import) the (Module).
If (Funs) are given, attempt to (Import) only the specified (Objects) from the (Module).
Return the (Imported) (Modules) or (Objects) as (Objects).
Examples:
calc = pimport(‘math’)
Allocates ‘calc’ as an alias to the ‘math’ module.
ie: calc.e == math.e
pi, log = pimport(‘math’,’pi, log’)
Allocates to variables the imported objects (math.pi & math.log).
ie: pi == math.pi
Args:
libs: String
Modules to import; separated by comma in the 1st string.
(‘a, b, c’).
funs: String = None
Objects to import; separated by comma in the 2nd string.
(‘a, b, c’).
Return:
R: Module | Object | Tuple[Module | Object]
Imported modules or objects.
pt.pframe(depth, outer=False) → Frame:§
Plain Frame.
Helper function for getting the frame information in the specified depth.
Pseudocode:
(Inspect) all the current (Frames).
Return the (Depth)º (Frame), counting from the current (Frame) outwards.
Examples:
(@file PlainTools.py)
x = pframe()
x.f_code.co_filename == ‘..\path\PlainTools.py’
x.f_lineno == (Line number of pframe() call)
x.f_code.co_names == (Tuple of strings of names used in the program)
x.f_locals == Current frame’s locals() dictionary.
x.f_globals == Current frame’s globals() dictionary.
Args:
depth: Integer = 1
(Default: 1) How many frames to go in;
Note that this is in reverse order, so a depth=2
inspects the currentframe up until currentframe()[-2]
Kwargs:
outer: Bool = False
Determines if the Frame is get from inspect.getouterframes()
Return:
R: Frame
Frame object.
Statement & Extension Functions§
(Goto Table of Contents)
Statement Functions bring new, easy-to-use functions that improve the native,
standard syntax and built-in functions.
pt.let(**kwargs) → Container[Any: Any]:§
Let ‘Statement’.
Note: The ‘let()’ function is unusable inside function definition scopes;
It is neither a bug nor fixable, but a limitation of the Python language.
Assigns and evaluates multiple variables in a single function call.
Keep in mind that real assignment happens after the function call ends;
Doing ‘let(x=5, y=10, z=x+y)’ raises ‘NameError: name ‘x’ is not defined’;
But doing ‘let(x=5, y=10), let(z=x+y)’ works just fine.
Examples:
let(x=5, y=10, z=math.pi)
(5, 10, 3.141592653589793)
x = 5
y = 10
z = 3.141592653589793
let(w=Seval(‘15 ** 5 / 2’))
w = 379687.5
Kwrgs:
**kwargs: Any
Direct assignments to given kwarg variables.
Return:
R: Container[Any: Any]
A Container with the relationed objects assigned.
pt.const(**kwargs) → Container[Constant: Any]:§
Constant ‘Statement’.
Note: The ‘const()’ function is unusable in function definition scopes;
It is neither a bug nor fixable, but a limitation of the Python language.
Assigns and evaluates multiple constant variables in a function call.
Returns Constant objects, being immutable by nature.
Keep in mind that real assignmenet happens after the function call ends;
Doing ‘const(x=5, z=x+5)’ raises ‘NameError: name ‘x’ is not defined’;
But doing ‘const(x=5), const(z=x+5)’ works just fine.
Examples:
const(x=2.5, y=3.5)
(2.5, 3.5)
x == Constant(2.5)
y == Constant(3.5)
const(z=[0, 1, 1, 2, 3, 5, 8, 13])
z == Constant([0, 1, 1, 2, 3, 5, 8, 13])
Kwargs:
**kwargs: dict
Additional constants to assign in the current context.
Return:
R: Container[Constant: Any]
A Container with the relationed objects assigned as Constants.
pt.attempt(fallback, operator, *args, **kwargs) → Any:§
Attempt Operator
Attempts to execute operator(*args, **kwargs),
returns ‘fallback’ if any exceptions occur.
pt.printnl(*args, **kwargs) → None:§
New Line Print.
Rationale:
Prints the input with a new line after each prompt.
pt.printc(*args, fill=' ', **kwargs) → None:§
Centered Print.
Rationale:
Prints the input centered on the window; Fills with (fill) character.
pt.showcall(func) → Function:§
Show Call Information.
This decorator outputs detailed information about the function
call, including the line number, function name, arguments, return
value or error, and execution time. It is useful for debugging and
monitoring function execution.
Examples:
@showcall
def my_function(x, y):
return x + y
my_function(3, 4)
[!-CALL-!]
Ln 10 # Example!
Fn my_function
A* (3, 4)
K* {}
R* 7
Tm 0.0001s
@showcall
def vec_func(i, j, k, op=’div’):
(…)
if op == ‘div’:
return (i * j) / k
vec_func(2, 3, 0) # Division by zero!
[!-CALL-!]
Ln 14 # Example too!
Fn vec_func
A* (2, 3, 0)
K* {‘op’: ‘div’}
R* [!-ERROR-!]
Er ZeroDivisionError
As division by zero
Tm 0.017s
pt.namespace(name) → Container:§
Namespace Viewer.
Returns a Container of a module’s or frame’s attributes and values.
Note that, as the return type is a Container, you can do such as:
calc = namespace(‘math’)
calc.pi # the exact same as math.pi
Examples:
namespace(‘math’)
Returns a Container(k:v) for every ‘k:v’ pair inside ‘math’ module.
i.e. {‘pi’: 3.141592653589793}
i.e. {‘sqrt’: <built-in function sqrt>}
Args:
module: Module | String
Module to be viewed. If String, its imported as a module object.
Return:
R: Container
View of the module as k:v pairs.
pt.skip(n=1, *args, **kwargs) → None:§
Line Skip.
Rationale:
Prints into de console ‘n’ times; Defaults to a 1 line skip.
pt.evinput(*args, **kwargs) → None:§
Evaluated Input.
Rationale:
Performs a Safe Eval (see: Seval@:ref:Instantiable Classes)
into the input, converting to adequate types.
pt.timeout(secs, func, *args, **kwargs) → Any | Error:§
Timeout.
Runs a function in a separate proccess with a time limit;
Raises an exception if it exceeds given limit in seconds.
Examples:
timeout(5, long_running_function, arg1, arg2)
Executes long_running_function(arg1, arg2) with a 5-second limit.
Args:
secs: Number
Time limit in seconds.
func: Callable
Function to execute.
*args: Any
Positional arguments to pass to the function.
**kwargs: Any
Keyword arguments to pass to the function.
Return:
R: Any | Err
The result of the function, or an exception if timed out.
pt.loop(times=0, escape=KeyboardInterrupt, loopif=True, show=False, nl=False) → Decorator:§
Loop Decorator.
A decorator that repeatedly executes the function based on
specified conditions.
It allows for control over the number of iterations,
conditional execution, and exception handling within the loop.
Exceptions raised by the function do not inherently stop the loop
unless their type is specified in the escape parameter. However,
the KeyboardInterrupt exception is guaranteed to always be caught
and interrupt the loop execution.
Examples:
@loop(times=3)
def my_function(x):
⠀⠀⠀⠀print(f”Value: {x}”)
This will print the value of x three times at ‘my_function()’.
@loop(loopif=lambda: some_condition())
def my_function(x):
⠀⠀⠀⠀print(f”Value: {x}”)
This will execute my_function as long as some_condition() returns True.
@loop(escape=KeyboardInterrupt)
def my_function(x):
⠀⠀⠀⠀print(f”Processing {x}”)
This will execute my_function in a loop until a KeyboardInterrupt exception is raised.
@loop(times=5, show=True)
def example_function(x):
⠀⠀⠀⠀print(x)
This will run ‘example_function()’ 5 times, printing the iteration details each time.
Args:
times: Integer = 0
The number of times to execute the decorated function.
If set to 0, the loop will run indefinitely unless broken out.
Default is 0.
escape: Exception | Tuple[Exception, …] = KeyboardInterrupt
Exception(s) that, if raised, will stop the loop.
Default is KeyboardInterrupt (guaranteed even if changed).
loopif: Function | Bool = True
A condition that, if evaluated to False, will break the loop.
It can be a Lambda type with out-scope parameters or conditions.
Default is True.
show: Bool = False
If True, prints the function name, arguments, and iteration.
Default is False.
nl: Bool = False
If True, inserts a newline after each iteration.
Default is False.
Return:
Decorator
A decorator that wraps the provided function.
Debugger & Utility Functions§
(Goto Table of Contents)
Debug functions interact with the environment the script runs in,
and output relevant information to the console.
These functions do accept arguments only as buffers, this being,
arguments given have no impact in the output, but serve the purpose of
executing code in the same line, such as starting a timer for example.
pt.debug(*buffer) → List[String] | None:§
Debug Traceback.
Examples:
Try: (…)
Except: printnl(*debug())
Rationale:
Returns the traceback, if any.
pt.clear(*buffer) → None:§
Clear Screen.
Rationale:
Simple command to clear the console feed.
pt.eof(*buffer) → SystemExit:§
End of File.
Rationale:
Logs into a .log file, waits for user input, and then exits the system.
pt.deepframe(*buffer) → None:§
Deep Frame.
Rationale:
Prints the full depth of the current path and the frame stack.
Operator & Instantiated Classes§
(Goto Table of Contents)
Operator Classes are classes able to be used as functions, objects, contexts
and as the name sugests, come with pre-loaded instances that are ready-to-use.
The class definition for these objects is given in UPPERCASE, as in:
class TIME:(…)
Where the instances are given in PascalCase, as is with other non-operator classes, so:
Time = TIME(std=’now’)
Runtime = TIME(std=’lap’)
Crono = TIME(std=’epoch’)
Are all instance examples of the operator class ‘TIME()’
class pt.TIME§
Execution Timer.
A running timer that starts immediately when instantiated.
Examples:
X = TIME()
Starts ‘X’ as a timer.
with X:
Starts a timed context with ‘X’; prints time on exit.
X.show
Prints the current time in string format.
Args:
add: Float = 0.0
Time to add to the timer.
std: String = ‘now’
Initial standard mode (‘now’, ‘lap’, or ‘epoch’).
Methods:
.mode(std: String = ‘’) -> Class
Changes the standard mode of the timer.
.now -> Float
Returns the time since the last call.
.lap -> Float
Returns the current time.
.reset -> Class
Resets the timer.
.string -> String
Returns the time as a string.
.show -> String
Prints the current time in string format.
.epoch -> List[Float]
Returns recorded times.
Instances:
Time = TIME(std=’now’)
Timer that returns the time since the last call.
Runtime = TIME(std=’lap’)
Timer that returns the total elapsed time.
Crono = TIME(std=’epoch’)
Timer that returns the entire history of recorded times.
Return:
R: Float | List[Float]
Time in seconds.milliseconds (e.g. 1.234).
class pt.STUB§
Decorator @Stub | Object Stub.
Decorates an incomplete function, indicating it has not been implemented yet.
Examples:
@Stub
Prints the stub location when the function is called.
Stub()
Prints the stub status, current line and module of call.
Stub
Null object with empty representation.
Instances:
Stub = STUB()
Return:
R: Class | Callable
Decorated function or Stub object.
class pt.NULL§
Null Object Pattern.
A class that implements the Null Object Pattern by defining methods and operations that return neutral values or perform no actions.
Examples:
Nil = NULL()
Assigns an instance of the NULL class.
Default instance is ‘Null’.
Null + 5
Performs a no-op and returns Null itself.
Null
str(Null)
Returns an empty string.
‘’
Null.attribute
Accesses a non-existent attribute, returns Null.
Null
Null == None
Null has equality to None.
True
print(Null)
Prints nothing.
Same as print().
Instances:
Null = NULL()
class pt.ERROR(NULL, Exception)§
Error Object.
A specialized version of the NULL class that represents an error state,
overriding string and representation methods to return ‘Error’.
Examples:
print(Error)
Error
raise Error:
PlainTools.ERROR: Error
Instances:
Error = ERROR()
class pt.MAIN§
Main script guard.
Evaluates if the script is being executed directly;
Similar to __name__ == ‘__main__’.
Examples:
if Main:
Evaluates if __name__ == ‘__main__’.
with Main:
Enters the ‘Main’ context, only executes if Main.
Main(*args, **kwargs)
Invokes the ‘Main’ context; runs local ‘main(*args, **kwargs)’.
main(*args, **kwargs) # Inside ‘with Main:’ context.
Methods:
.time -> Float
Returns the script execution time.
.showtime -> String
Displays the script execution time.
.clear -> Self
Clears the console; Executed by .start.
.start -> Self
Invokes .time & .clear.
.end -> Self
Ends the program after debugging and logging.
Instances:
Main = MAIN()
Return:
R: Bool = True if the script is being executed directly.
class pt.SILENCE§
Context manager that suppresses console output.
Redirects stdout and stderr to /dev/null, effectively silencing
all output within the context.
Examples:
with Silence:
Silences all console output within the context.
Instances:
Silence = SILENCE()
Return:
R: Class = Context manager that suppresses console output.
class pt.LOGGING§
Functional Logging.
Stores provided strings or objects in an internal list;
Writes them to a (filename).log file.
Examples:
Logging(“message”)
Logs “message” in the internal list.
Logging([1, 2, 3])
Logs each element of the list on separate lines.
Args:
obj: Any
Object(s) to be logged.
Methods:
.get -> List
Returns the internal list of logged entries.
.flush -> Self
Writes the current log to a file and clears the internal list.
This is automatically done at exiting the ‘with Main’ context.
.show -> Self
Displays the stored messages from the log list.
.reset -> list or None
Resets the internal list of logs to empty.
Instances:
Logging = LOGGING()
class pt.TRY§
Try Context.
A simpler ‘try’ context, with no direct error handling; Exits the context instead.
Can be done in a verbose way by the use of ‘with Try.show:’ method.
Examples:
with Try:
Begins execution and tracks its success or failure.
Methods:
.show -> Self
Enables verbose mode to print the context’s progress and results.
Properties:
verbose: Bool = False
Controls whether to print the result to the console.
result: String
Stores the result of the try block, indicating success or failure.
class pt.LINES§
Line Number Context Manager.
A context manager that prefixes each line of output with the line number.
Examples:
with Lines:
print(“Hello, World!”) # Output will be prefixed with line no.
Instances:
Lines = LINES()
class pt.SEVAL§
Safe Expression Evaluator.
A secure alternative to Python’s eval() function, designed to evaluate
mathematical and basic expressions while preventing access to unsafe
operations and functions.
Examples:
Seval(“2 + 2”)
4
Seval(“round(math.pi * 2, 2)”)
6.28 # Only if ‘math’ is imported in the current namespace.
Seval(“”import shutil; shutil.rmtree(‘/.’)”)
Raises UnsafeError.
Raises:
UnsafeError: Raised when tries unsafe operation, function, or module.
Attributes:
UnsafeError: TypeError
Custom error for handling unsafe operations.
blacklist: dict
Defines disallowed functions and modules that are prohibited.
This can be changed by creating a new SEVAL() instance and modfying
its ‘.blacklist’ dictionary.
The original dictionary contains 2 keys: .blacklist[‘functions’]
and .blacklist[‘modules’] each with a set of strings as its value.
Disallowed Functions:
__import__
eval
exec
compile
encode
decode
open
exit
print
input
base64
bytearray
bytes
getattr
main
Main
Disallowed Package Functions:
pt.pimport()
pt.pframe()
pt.printnl()
pt.printc()
pt.timeout()
pt.let()
pt.const()
pt.skip()
pt.clear()
pt.eof()
pt.debug()
pt.deepframe()
pt.evinput()
pt.showcall()
Disallowed Constructor|Instances:
pt.LOGGING
pt.MAIN
pt.Constant
Disallowed Modules:
builtins
os
sys
code
shutils
json
multiprocessing
platform
http
sqlite3
getpass
crypt
ftplib
uuid
turtle
ctypes
atexit
tk
re
mmap
pathlib
compileall
tempfile
faulthandler
stat
urllib
ssl
threading
resource
signal
hashlib
unittest
secrets
grp
dbm
glob
asyncio
pwd
gc
base64
pdb
webbrowser
subprocess
codeop
smtlib
xmlrpc
sysconfig
socket
class pt.TEST§
Test Utility Class.
Provides a context manager and callable functionality for running tests,
checking conditions, and generating pass/fail reports.
The test is based on assert statements and checks for equality of the
first element with the remaining elements for each tuple provided.
Methods:
name(name)
Sets a new title for the test context.
Returns the TEST instance to allow method chaining.
Examples:
with Test.name(“Sample Test”) as t:
t((5, 5), (10, 10)) # Passes
t((1, 2)) # Fails and reports
Test((3, 3), (2, 1)) # Runs the tests and outputs results inline
Instances:
Test = TEST()
Notes:
Boolean tests should pass if the value is True, and fail if False.
Tuple tests are evaluated by comparing the first element to subsequent
elements as a tuple. If they are not equal, the test fails.
Upon context exit or function call, a summary of results is printed.
LLM used: ChatGPT 4o
Documentation Utilities§
(Goto Table of Contents)
These functions have the purpose of expressing available documentation inside Python
modules and objects, such as docstrings etc.
The PlainTools library itself defines the following attributes for these purposes:
__title__ = “PlainTools”
__version__ = “1.2.241008.0”
__author__ = “gabrielmsilva00”
__url__ = “https://gabrielmsilva00.github.io/PlainTools/”
__repo__ = “gabrielmsilva00/PlainTools.git”
__license__ = “Apache License 2.0”
Where each and some more can be accessed and viewed directly by the use of the
pt.moduleview() function as:
import PlainTools as pt
pt.moduleview(pt)
Copy to clipboard
The same effect can be achieved by running the PlainTools.py file directly,
which will also prompt you to open the Documentation
Site or File(PlainToolsDocs.html)
pt.doc(*objs, verbose=True) → List[String] | Null:§
Docstring Printer.
Rationale:
Prints into the console any docstring associated with the given
object(s) or its parent class(es), headed by its origin module.
Prints the current frame’s module docstring if no object is given.
pt.site(module) → None:§
Documentation HTML Viewer.
Rationale:
This function will search for any .html files in the module’s
directory that are named after the module itself, and attempt
to open it in the default browser of the user.
pt.moduleview(module='__main__', verbose=True) → None:§
Module Viewer.
Rationale:
This function will resolve & return every attribute related
to documentation of the analyzed module.
These attributes are:
__name__
__title__
__version__
__author__
__license__
__url__
__repo__
__file__
__doc__
Every pair of {Name = Value} (meaning every
variable and its assigned value) will be stored
under the ‘contents’ Key of the returned Container.
These pairs however are not printed even with verbose=True.
Finally, note that every module and its namespace when evaluated by this
function can include these attributes, meaning authors are encouraged
to do so when looking to better document their libraries.
(Goto Table of Contents)
Version 1.3.241226.0§
Contents
PlainTools’ Docs
Numeric Constructor
pt.Numeric
pt.pnumber()
Constructor Classes & Custom Objects
pt.Container
pt.Constant
Formatter Functions
pt.plist()
pt.punit()
pt.pdecimals()
pt.pstring()
pt.pistype()
pt.prange()
pt.pinterval()
pt.psequence()
pt.pindex()
pt.pminmax()
pt.plen()
pt.pabs()
pt.psum()
pt.pimport()
pt.pframe()
Statement & Extension Functions
pt.let()
pt.const()
pt.attempt()
pt.printnl()
pt.printc()
pt.showcall()
pt.namespace()
pt.skip()
pt.evinput()
pt.timeout()
pt.loop()
Debugger & Utility Functions
pt.debug()
pt.clear()
pt.eof()
pt.deepframe()
Operator & Instantiated Classes
pt.TIME
pt.STUB
pt.NULL
pt.ERROR
pt.MAIN
pt.SILENCE
pt.LOGGING
pt.TRY
pt.LINES
pt.SEVAL
pt.TEST
Documentation Utilities
pt.doc()
pt.site()
pt.moduleview()
Version 1.3.241226.0
By Gabriel Maia Pereira da Silva, @gabrielmsilva00
© Copyright 2024, Gabriel Maia Pereira da Silva, @gabrielmsilva00.
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