A collection of different modules for Python that make life a little bit easier.
Project description
Dot Dictionary
Makes a Python dictionary that can access keys with dot notation in addition to brackets ( []).
class DotDict(dict):
A Python dictionary that allows you to access keys in dot notation style.
Example:
mycar = DotDict(
year = 2023,
make = 'Dodge',
model = 'Challenger',
trims = DotDict(
sport = DotDict(horsepower=256),
rt = DotDict(horsepower=425),
demon = DotDict(horsepower=712),
)
)
print(mycar.year, mycar['model'],
mycar.trims.rt.horsepower, 'hp')
Output: 2023 Challenger 425 hp
Attributes can be accessed by dot notation, as well as traditional bracket notation. New attributes can only be added via bracket notation. This essentially creates a dictionary that works like a JavaScript Object.
Grid Data Structure
A data structure to manipulate and traverse a 2-dimensional array in an intutive manner.
class Grid:
Attributes:
width: the width of the gridheight: the height of the gridfocus_xy: a tuple of coordinates within the grid data indicating the cell which is currently in focusfocus_obj: the data within the cell which is currently focusedgrid: the raw 2-D array which stores the data
def __init__(self, width = None, height = None, default = None, data = None):
Parameters:
width: the width of the gridheight: the height of the griddefault: a default value to insert into empty cellsdata: a 2-D array of data to populate the new grid
A Gridobject is a rectangluar 2-dimensional array, meaning that each row has the same number of columns. The size of this structure can be determined either by the provided widthand height, or by the datapassed into it. The widthand heightmust be specified unless datahas been provided. If datais provided without widthor height,the dimensions of the datawill be used as the size of the Gridobject.
NOTE: The datais assumed to be rectangular as well, and the height and width are determined by the first row and first column, respectively. If any rows below the first row are longer, they will be truncated and that data will not be inserted into the Gridobject.
If both dataand the widthor heightis provided, the appropriate dimension of the grid will be sized according to that value. If the value is greater than the dimension of the data, the defaultvalue will be inserted into those cells. If the value is less than the dimension of the data, then those cells will not be copied to the Gridobject. (See the populate()method below for more details)
def populate(self, data):
Parameters:
data: a 2-D array of data to populate the grid
This method fills in the Gridobject with the contents of each cell of the provided dataobject. The insertion to each cell of the Gridobject is a simple assignment. This means that literal values will be copies, but Python objects will be references.
NOTE: Because Python always does pass by reference, the assignment which takes place in populate()places a reference to any Python object which is in the cell of data. If you wish to have shallow or deep copies in the Gridobject, you must do those before passing the datato this method.
def check_bounds(self, value, upper, lower, raise_exc=True):
Parameters:
value: the value to checkupper: the maximum threshold ofvaluelower: the minimum threshold ofvalueraise_exc: a boolean indicating if anIndexErrorshould be raised whenvalueexceeds theupperorlowerbounds
Returns: The value,possibly adjusted by the bounds, or raise an IndexError
Usually, this method simply returns the unaltered value,unless it exceeds one or both of the bounds provided ( upperand lower). However, if raise_excis set to False, then this method will adjust the valueto stay within the bounds. If the valueexceeds one of the bounds, the method returns the bound itself, since it is the furthest value allowed. This can be useful in situations where you implicitly need the value to stay within the bounds without raising an error.
def focus(self, x=None, y=None, stay_in_bounds=False):
Parameters:
x: the horizontal coordinate to focus on in the gridy: the vertical coordinate to focus on in the gridstay_in_bounds: a boolean indicating if this method should automatically correct the focus coordinates if the providedxoryvalues are outside the bounds of the grid
Returns: The content of the cell at ( x, y) in the grid.
A major concept of the Gridis focus, also referred to in some other data structures and data mangement utilities as a "cursor". The focus of the Gridis the specific cell which can be read or manipulated. This method will use the provided xand/or yvalues to set the focus of the Gridto a specific cell. The coordinate system in use with a Gridobject is such that the cell in the top left corner is coordinate (0, 0). and values along the x and y axes are positive integer values. There are no decimal or negative values in a Gridobject's coordinates. If the provided xor yvalues are not within the bounds of the grid, an IndexErrorwill be raised, unless stay_in_boundsis set to True(see below).
If an xor yvalue is not provided, this method will use the current focus xor ycoordinate. Calling focus(), with no arguments, simply retuns the currently focused cell contents. Calling focus(x=2)would move the focus to the third column of the currently focused row.
NOTE: Keep in mind that the Gridcoordinate system starts at (0,0), so the first column is an x-coordinate of 0, not 1.
If stay_in_boundsis set to True, then this method implicitly limits the focus to the bounds of the grid. Any value outside the bounds, will be automatically corrected to the bound(s) that were crossed. This is useful for implementations that may attempt to exceed the grid bounds, but don't necessarily need to raise an exception when it occurs.
def focus_up(self, amount=1, stay_in_bounds=False):
Parameters:
amount: the number of cells to shift the focus upwardsstay_in_bounds: a boolean indicating if this method should automatically correct the focus coordinates if it is outside the bounds of the grid
Returns: The content of the cell that is amountnumber of cells above the currently focused cell.
This a convenience method which shifts the focus of the Gridobject upwards by an amount.It directly calls the focus()method (see above).
def focus_down(self, amount=1, stay_in_bounds=False):
Parameters:
amount: the number of cells to shift the focus downwardsstay_in_bounds: a boolean indicating if this method should automatically correct the focus coordinates if it is outside the bounds of the grid
Returns: The content of the cell that is amountnumber of cells below the currently focused cell.
This a convenience method which shifts the focus of the Gridobject downwards by an amount.It directly calls the focus()method (see above).
def focus_left(self, amount=1, stay_in_bounds=False):
Parameters:
amount: the number of cells to shift the focus to the leftstay_in_bounds: a boolean indicating if this method should automatically correct the focus coordinates if it is outside the bounds of the grid
Returns: The content of the cell that is amountnumber of cells to the left of the currently focused cell.
This a convenience method which shifts the focus of the Gridobject to the left by an amount.It directly calls the focus()method (see above).
def focus_right(self, amount=1, stay_in_bounds=False):
Parameters:
amount: the number of cells to shift the focus to the rightstay_in_bounds: a boolean indicating if this method should automatically correct the focus coordinates if it is outside the bounds of the grid
Returns: The content of the cell that is amountnumber of cells to the right of the currently focused cell.
This a convenience method which shifts the focus of the Gridobject to the right by an amount.It directly calls the focus()method (see above).
def replace_focused(self, newitem):
Replaces the item currently in focus with newitem.
Parameters:
newitem: the data to replace the currently focused item in the grid
def typewriter_traverse(self):
Returns: a TypewriterGridIteratorfor use in a forloop
def serpentine_traverse(self):
Returns: a SerpentineGridIteratorfor use in a forloop
def vertical_typewriter_traverse(self):
Returns: a VerticalTypewriterGridIteratorfor use in a forloop
def vertical_serpentine_traverse(self):
Returns: a VerticalSerpentineGridIteratorfor use in a forloop
def spiral_in_traverse(self):
Returns: a SpiralInGridIteratorfor use in a forloop
class AbstractGridIterator:
An abstract class for deriving iterators for a Gridobject.
GridIteratorclasses are unique in that they don't simply return the content of the cell, they also return the x and y coordinates of the cell. When using a GridIterator, you must account for these extra values:
mygrid = Grid(24, 12)
for x, y, item in mygrid.typwriter_traverse():
# do stuff
class TypewriterGridIterator(AbstractGridIterator):
"Typewriter" traversal is the most common way to traverse a 2-dimensional array. The iterator starts at (0, 0), and moves along the x-axis. When it reaches the end of the row, it goes down to the next row, and begins again at the 0 x-coordinate and travels along the x-axis.
Example:
1234
5678 typwriter
9000 traversal = 123456789000
class SeprentineGridIterator(AbstractGridIterator):
"Serpentine" traversal is another fairly common traversal method. The iterator starts at (0, 0), and moves along the x-axis, just like a typewriter traversal. However, when it reaches the end of the row, it simply changes direction after moving down a row.
Example:
1234
5678 serpentine
9000 traversal = 123487659000
class VerticalTypewriterGridIterator(AbstractGridIterator):
"Vertical Typewriter" traversal is the same as typewriter, except turned vertically. Starting at (0, 0), the iterator moves down the column. When it reaches the end of the column, it goes to the next one and, starting again at the 0 y-coordinate, traverses down teh column.
Example:
1234 vertical
5678 typewriter
9000 traversal = 159260370480
class VerticalSeprentineGridIterator(AbstractGridIterator):
"Vertical Serpentine" traversal is the same as serpentine, except turned vertically. Starting at (0, 0), the iterator moves down the column. When it reaches the end of the column, it changes direction, and traverses up the next column.
Example:
1234 vertical
5678 serpentine
9000 traversal = 159062370084
class SpiralInGridIterator(AbstractGridIterator):
"Spiral In" traversal is concerned with visiting the outermost cells of the grid before visiting those closer to the center. The iterator starts at (0, 0), and moves along the x-axis. However, upon reaching the end of the x-axis, it moves down the column, then backwards across the bottom row, and upwards towards the start. Upon reaching the start, the iterator moves down 1 row and does the same movement again, 1 "layer" deeper (and thus 1 unit closer to the center) than before. This continues until it reaches the center of the grid.
Example:
1234
5678 spiral in
9000 traversal = 123480009567
Indented Text File Reader
Utility for reading indented blocks of text from a file and forming a tree data structure for use in Python. This allows Python programs to use config files and data files which respect whitespace the same as Python itself.
class IndentReader:
Attributes:
filepath: path to the file this readsnode_class: the Python class this uses for its nodes (default is theNodeclass below)preserve_newlines: boolean describing if the reader keeps newlines in the nodedataallowed_indents: a string of characters which are considered valid indentationsindent_char: the character or string the reader has identified for use as indentation in the current filecurrent_line: the current line number the reader is parsingroot: the root node of the tree data structure generated by the reader
def __init__(self, filepath, node_class = None, preserve_newlines = False, allowed_indents = ' \t', root_data='<root>'):
Parameters:
filepath: path to the file this readsnode_class: the Python class this uses for its nodes (default is theNodeclass below)preserve_newlines: boolean describing if the reader keeps newlines in the nodedataallowed_indents: list of strings which are considered valid indentationsroot_data: defaultdataplaced in the root node
When an IndentReaderobject is instantiated, it will immediately attempt to read and parse the file. Once IndentReaderidentifies a valid indent string (via the allowed_indentsvalue), all indents must use that same character or string for their indentation (just like Python, you cannot mix tabs and spaces for indentation).
The completed data structure is available for direct consumption via the rootattribute. In the event that an error occurs during parsing, the reader raises a ReaderError. The exception message indicates the error and line number. The rootdata structure, current_line, and indent_charremain after parsing is complete in order to provide debug information, if necessary.
This class can be subclassed to create a specialized reader for specific file formats or use cases. Typically the only override needed is to change the parse_data()method to use logic that is specific to the use case desired. You may also want to provide a different node_classfor this reader (see the Nodeclass below).
def prepare_for_read(self):
Resets all variables to prepare to read a new file.
def read_file(self):
Reads and parses the file of filenameand stores the result in the rootattribute. This method is automatically called upon object instantiation.
def parse_line(self, line):
Parameters:
line: the raw line of text read from the file
Parses the line, identifies the indentation level, then creates a node and inserts it into the tree.
def find_node(self, indent):
Parameters:
indent: the indent string to match
Returns: The parent node which matches the indentprovided
Starting at the current node, this method traverses back up the parents to find the indentation level that matches, then returns the parent node of that indentation level. If no matching node is found, this raises a ReaderError.
def prepare_node(self, rawline, indent):
Parameters:
rawline: the raw line of text from the fileindent: the indentation string found on the line
Returns: a new Nodeobject with the indentand dataparsed from the rawline
This method calls the parse_data()method to assemble the data for the Nodeobject.
def parse_data(self, line, rawline):
Parameters:
line: the stripped linerawline: the untouched raw text from the file
Returns: Any valid Python data to store in the dataof a Nodeobject.
This method should be overridden in any subclasses to provide more specific logic to parse and prepare data read from the file. By default, this method just returns the linevalue.
def output(self, exclude_root=False):
Parameters:
exclude_root: do not include therootnode in the output string
Returns: A prettified string of the data structure stored within root.
class ReaderError(Exception):
A generic exception class for IndentReader.
class Node:
Attributes:
parent: the parentNodeof this nodeindent: the indentation string this node'sdatawas found at in the filelevel: the indent level of the node (root level is 0)child_indent: the indentation string of this node'schildrenchildren: a list of childNodeobjectsdata: the data stored in this node
The tree data structure in the IndentReaderis formed by connecting Nodeobjects to each other as parents and children. Each node has 1 parent and 0 or more children.
This class can be used to derive subclasses in order to customize the behavior of individual nodes of the IndentReader.Provide the subclass to the node_classparameter of the IndentReaderconstructor.
def __init__(self, parent=None, indent='', data=''):
Parameters:
parent: the parentNodeobjectindent: the indentation string this node'sdatawas found at in the filedata: the data stored in this node
def add_child(self, node):
Parameters:
node: theNodeobject to add as a child
This method sets the child_indentattribute, adds the nodeto this node's children, and assigns this node as the parentor node.
def output(self, level=0, exclude_self=False):
Parameters:
level: indicates how far the prettified data should be indentedexclude_self: do not include thedatain the output string
Returns: A prettified string of the dataand childrenof this node
Indexed Object
A chimera of data structures, this object is an ordered, indexed hashtable with the ability to access attributes by both dot notation and bracket notation.
class IndexedObject():
This object provides the benefits of several data structures simultaneously.
Attribute Access
- Dot notation -
myobj.attr - Bracket notation (key) -
myobj['attr'] - Bracket notation (index) -
myobj[2] - Built-in
getattr()function -getattr(myobj,'attr', None) - Instance
get()method -myobj.get('attr',None) - Can use
len()to get number of attributes
Attribute Storage
- Attributes are ordered
- Attributes can change order
- New attributes can be inserted at any index
- Keys, values, and key-value pairs can be iterated in order
- Can handle both keyed and keyless data in the same object
def __init__(self, *args, **kwargs):
Creates a new IndexedObject. This constructor creates the attributes differently based on the argsor kwargssupplied to it. The constructor cannot accept both argsand kwargstogether. The object must be instantiated with either only args,or only kwargs.All attributes will be inserted into the object in the order they are passed to the constructor.
If argvalues are tuples, it is assumed they are (key, value) tuples, and will assign attributes as such. Any other argvalues are considered keyless values, and will have an automatically generated key assigned to them. kwargsare inserted exactly they are passed, with the attribute name being the kwargname, and the value being the kwargvalue. Because the argscan be read as either key-value tuples, or keyless values, you can get around the arg& kwarglimitation by inserting keyword args as key-value tuples instead.
Keyless data is always given an automatically generated key anytime it is inserted into this object. Generated keys follow the pattern of _x_where xis an auto-incrementing counter that starts at zero. The increment is based on the lifetime of the object. For example, an IndexedObjectwith 8 keyless attributes has a previously generated key of _7_. If a new keyless attribute is added, this will increment to _8_. However, if a keyless attribute is removed, the generated key does not decrement.
NOTE: Objects which will frequently change the number of keyless attributes should not use IndexedObject, since there is a possibility of encountering the upper bounds of Python's built in inttype (typically 2,147,483,647 for most Python interpreters).
def get(self, key, default=None):
Parameters:
key: the attribute name to retrievedefault: the value to return if thekeyis not found
Returns: The attribute indentified by key, or the defaultvalue if the key is not found
def keys(self):
Returns: A list of the keys in this object, in order.
def values(self):
Returns: A list of the values in this object, in order.
def items(self):
Returns: A list of the (key, value) tuples in this object, in order.
def index(self, key):
Parameters:
key: the key to search for
Returns: The index of a given key.
def insert(self, index, arg1, arg2=None):
Parameters:
-
index: the index to insert the attribute -
arg1: either the value, or the key to insert -
arg2: the value to insert -
To insert keyless data:
myobj.insert(2, value) -
To insert keyed data:
myobj.insert(2, key, value)
def append(self, arg1, arg2=None):
Parameters:
-
arg1: either the value, or the key to append -
arg2: the value to append -
To append keyless data:
myobj.append(value) -
To append keyed data:
myobj.append(key, value)
def popindex(self, index):
Parameters:
index: index of the attribute to remove
Returns: A tuple of the key and value at the index
def pop(self, key=None):
Parameters:
key: key of the attribute to remove
Returns: A tuple of the index and value at the key
def extend(self, new_obj):
Parameters:
new_obj: alist,dict, orIndexedObjectto append to this object
Appends all of the attributes of new_objto this object. The attributes will be appended in order with the same keys. If duplicate keys are detected, a KeyErroris raised. When new_objis a list, each value will have a key auto-generated before being appended.
NOTE: Because duplicate keys are not allowed, using extend()with an IndexedObjectthat has keyless attributes will most likely cause a KeyErrorto be raised.
def reverse(self):
Reverses the order attributes in place.
def copy(self):
Returns: A shallow copy of this object.
def clear(self):
Removes all attributes from this object and resets the generated key to zero.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cerrax_py-1.1.0.tar.gz.
File metadata
- Download URL: cerrax_py-1.1.0.tar.gz
- Upload date:
- Size: 20.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.1 CPython/3.13.2 Darwin/24.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
496d8b3ef8cb78be9e6b2d3ab32c75a08444b28b7098fb662795f8f111283236
|
|
| MD5 |
887e954e144d7867df1c602bca26f083
|
|
| BLAKE2b-256 |
9fe39cf07a49ddeda4906ad51a14279814f371729803d4a604e7f36fb0b7b499
|
File details
Details for the file cerrax_py-1.1.0-py3-none-any.whl.
File metadata
- Download URL: cerrax_py-1.1.0-py3-none-any.whl
- Upload date:
- Size: 19.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.1 CPython/3.13.2 Darwin/24.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8c89afe2a9fc083183a2fe5c290c7370c4dcac821e6f3bafcf9d263f2522f58
|
|
| MD5 |
9d4a6a0e6b80c1a328f4527f46137e76
|
|
| BLAKE2b-256 |
145c9a5592150895619b9138098f0e247f5657ddbc9c73a0620b3cabfc6dc35a
|