Name | BB_AppUtils JSON |
Version |
0.5.3
JSON |
| download |
home_page | |
Summary | Python development tools |
upload_time | 2024-02-19 03:54:43 |
maintainer | |
docs_url | None |
author | Erik Beebe |
requires_python | >=3.11,<4.0 |
license | |
keywords |
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# BB_AppUtils
> Utilities for developing python applications/scripts
> README is incomplete!
## Contents
- [Shell Script 'apputils'](#shell-script) - terminal commands
- [AppUtils](#apputils)
- package of handy functions and tools
- [AppData](#appdata) - tools for using system directories
- Classes
- AgeInfo - class to make readable strings from timedelta objects
- [AppData](#appdata) - application directories tool
- [Date](#date) - Date imports with added functions
- [Path](#path) - os.path imports with added functions
- Functions
- [appendFile](#appendfile)
- [attribNameFromString](#attribnamefromstring)
- [filterList](#filterlist)
- [filter_dir](#filter_dir)
- [getBoolFromString](#getboolfromstring)
- [getIndexed](#getindexed)
- [isBinary](#isbinary)
- [isSafeAttribName](#issafeattribname)
- [listDepth](#listdepth)
- [listFlatten](#listflatten)
- [matchSimilar](#matchsimilar)
- [mkData](#mkdata)
- [moveListItem](#movelistitem)
- [parseDate](#parsedate)
- [readFile](#readfile)
- [sortDiverseList](#sortdiverselist)
- [stringFilter](#stringfilter)
- [timeDeltaString](#timedeltastring)
- [tupleCalc](#tuplecalc)
- [uniqueName](#uniquename)
- [writeFile](#writefile)
- attributes
- FileLock - Threading type lock for writing/reading files
- GlobalLock - Threading lock for global use
- [BBLogger](#bblogger)
- custom Logger and Formatter class for the built-in python logging module
- [Shell Options](#environment-variables) - set logging options via shell environment
- [Get Logger](#getlogger) - initial call to bblogger
- [BBLogger Class](#logger-class)
- [BBFormatter Class](#custom-formatter)
- [Logger Example](#logger-example)
- [TextTools](#texttools)
- collection of tools for modifying console text
- [Ansi](#ansi) - work with escaped strings
- [AnsiList](#ansilist)
- [TextTools Class](#texttools-class) - collection of classmethods
- [Attributes](#texttools-attributes)
- [Functions](#texttools-classmethods)
- [ansi2rgb](#ansi2rgb)
- [blockTxt](#blocktxt)
- [hex2rgb](#hex2rgb)
- [rgb2ansi](#rgb2ansi)
- [rgb2hex](#rgb2hex)
- [rgbString](#rgbString)
- [money_fmt](#money_fmt)
- [t2a](#t2a)
- [from16](#from16)
- [to16color](#to16color)
- [help](#texttools-help)
- [Escape Types](#ansi-escape-types)
- [Styles](#styles)
- [Using Ansi Colors](#working-with-color-types)
- Color Functions
- [Brightened](#brightened)
- [Dimmed](#dimmed)
- [Inverted](#inverted) - needs work
- [Blended](#blended)
- [AnsiCombo](#ansicombo)
- [Cursor Controls](#cursor-controls)
- [ChangeLog](#changelog)
## Shell Script
```sh
apputils --help
```
## AppUtils
module apputils
> Multiple functions/tools for various tasks in python applications
### AppData
apputils.appdata.AppData
```python
class AppData:
def __init__(self, appname = PROJECT_APP_NAME):
"""
'appname': set application name for base directory of app files
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### AppData Functions
AppData.appdir()
- Locates and creates application directories as needed according to application name
AppData.sysdata()
- Retrieve default system folders and info
```python
def appdir( self, d, *folders, file = '', datefile = '',
create_dir = True, unique = False, move_existing = False):
"""
*args
'd': system directory type
- varies on different operating systems - see sysdata
- 'cache' : users cache directory
- 'config': users config directory
- 'data' : main app directory
- 'launch': directory where app launchers are placed
'*folders': path names to append to returned path
**kwargs
'create_dir': create directories before they're returned
'datefile': strftime format to add to filename if file != None
- adds date data before extension or at end of filename
- if set to 'timestamp', the standard timestamp (without
nanoseconds) is used
- if set to True, the default dating format is used
- default date format: '_%Y-%m-%d_%H-%M-%S'
'file': add a filename to the end of the returned path
'move_existing': if file is set and exists, will move the old file to
'~filename'. If that already exists, then '~filename (n)',
'n' being the first number to make a unique pathname
- only applies if 'file' is set
'unique': avoid overwriting a file by setting unique to True
- renames file by adding an integer to the end
- does nothing if 'file' is not set
"""
def sysdata(self, *args, as_tuple = False):
"""
Return systeminfo
*args:
app : [ 'cache'||'data'||'config'||'launch' ]
home : [ 'home'||'userhome' ]
user name: [ 'user'||'username' ]
os type : [ 'os'||'system' ]
**kwargs:
'as_tuple': if getting a directory and True, return as a tuple instead
of using os.path.join
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Date
Imports for working with datetime objects
```python
def __call__(self, *args, **kwargs):
"""
Use date functions
kwargs:
'date' : assign date otherwise date is set to now
- must be a datetime object
'strftime': datetime.strftime()
'strptime': datetime.strptime()
'parse' : parse a date with dateutil.parser
- ignored if 'date' is in kwargs
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Path
apputils._import.Path
Imports for working with system files and directories
```python
class Path:
"""
File path modification tools
- contains mostly builtins ... mostly (some aliased)
"""
from os import ( access as __access__,
environ as env,
getcwd as pwd,
getlogin,
link as ln,
listdir as ls,
makedirs as mkdir,
readlink,
remove as rm,
removedirs as rmdir_R,
rmdir,
stat,
walk,
R_OK as __R_OK__,
W_OK as __W_OK__,
X_OK as __X_OK__ )
from shutil import ( copyfile as cp,
copytree as cp_R,
move as mv )
from os.path import ( abspath as abs,
basename as bn,
dirname as dn,
exists,
expanduser,
isabs,
isfile,
isdir,
islink,
join as jn,
sep as pathsep,
splitext )
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Tools
apputils.tools
> MISSING DOCUMENTATION
##### appendFile
apputils.tools.appendFile
```python
def appendFile( path, data, *, mode = 'a', encoding = 'utf-8', **kwargs ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### attribNameFromString
apputils.tools.attribNameFromString
```python
def attribNameFromString( string ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### filterList
apputils.tools.filterList
```python
def filterList( _list, match, index = None, *,
not_in = False, _type = None):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### filter_dir
apputils.tools.filter_dir
```python
def filter_dir(attr, **kwargs):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### getBoolFromString
apputils.tools.getBoolFromString
```python
def getBoolFromString(s):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### getIndexed
apputils.tools.getIndexed
```python
def getIndexed(item, args):
"""
getIndexed(item, args) >>> ( item, args )
Get item from list of arguments. Returns ( indexed item, args minus item )
if found else ( None, original args )
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### isBinary
apputils.tools.isBinary
```python
def isBinary(filename):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### isSafeAttribName
apputils.tools.isSafeAttribName
```python
def isSafeAttribName(name):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### listDepth
apputils.tools.listDepth
```python
def listDepth( L: list, *, tuples = False ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### listFlatten
apputils.tools.listFlatten
```python
def listFlatten( *L, depth: int = 1, tuples = False ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### matchSimilar
apputils.tools.matchSimilar
```python
def matchSimilar( find, _list, *,
ratio = STRING_SEQUENCE_MATCH_RATIO,
getall = False, getalldata = False ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### mkData
apputils.tools.mkData
```python
def mkData(obj):
"""
Make data dictionary from dataclass, ignoring keys that start with '_'
- embedded dataclasses are recursively moved to a dict() object as well
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### moveListItem
apputils.tools.moveListItem
```python
def moveListItem( L: list, from_index, to_index, *, items = False ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### parseDate
apputils.tools.parseDate
```python
def parseDate(s, fmt = ''):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### readFile
apputils.tools.readFile
```python
def readFile( path, *, mode = None, encoding = 'utf-8', **kwargs ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### sortDiverseList
apputils.tools.sortDiverseList
```python
def sortDiverseList( L: list|tuple, *,
reverse = False, unknowns_last = False ):
"""
Sorts lists|tuples containing both str and int
- integers are returned before strings
- always returns a list object
Types other than int|float|str are sorted by their '__name__'
attribute if existing. These will come before the unkown types,
which will be first in the list, unless 'unknowns_last' is set
to True, and sorted by their __repr__ value.
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### stringFilter
apputils.tools.stringFilter
```python
def stringFilter( obj: Any, *,
func = None, start = [], end = [],
re_search: re.compile = None, re_match: re.compile = None ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### timeDeltaString
apputils.tools.timeDeltaString
```python
def timeDeltaString(t):
"""
Convert time from timedelta object to xx:xx:xx
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### tupleCalc
apputils.tools.tupleCalc
```python
def tupleCalc( a, b, op, *, diff = False, round_int = False ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### uniqueName
apputils.tools.uniqueName
```python
def uniqueName(path, *, move_existing = False):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### writeFile
apputils.tools.writeFile
```python
def writeFile( path, data, *, mode = 'w', encoding = 'utf-8', **kwargs ):
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
## BBLogger
module bblogger
> Custom log formatting and file handling
> Subclasses of the python logging module
#### Environment Variables
> Set logging options using shell variables
```python
"""
User Shell Options:
'BBLOGGER_APPNAME' : (string) set a name for the root logger
'BBLOGGER_AVOID_OVERWRITE' : (bool value) don't overwrite log file [default = True]
'BBLOGGER_COLORED_OUTPUT' : (bool value) use color in console logging [default = True]
'BBLOGGER_CONSOLE_FORMAT' : 'debug'|'basic' provide more info on each line with 'debug' [default = 'basic']
'BBLOGGER_CONSOLE_STREAM' : output stream - 'stderr'[default] or 'stdout'
'BBLOGGER_FILE_FORMAT' : 'html'|'plaintext' [default = 'html']
'BBLOGGER_FILE_ROTATE_TIME': amount of seconds before log file is overwritten (default -1)
- ignored if less than 0
'BBLOGGER_FILE_VERBOSITY' : (1 - 5) logging level for file output [default = 1]
'BBLOGGER_FILE_WRITE_MODE' : (string) 'a' - append, 'b' - backup, or 'w' - write
'BBLOGGER_FILEPATH' : path to log file to [default = None]
'BBLOGGER_MAX_FILE_SIZE' : maximum size for logfile in bytes before rotation
'BBLOGGER_ROOT_VERBOSITY' : (1 - 5) log level to set the root logger [default = 1]
'BBLOGGER_VERBOSITY' : (1 - 5) log level for console output [default = 3]
"""
```
- run script in shell `bblogger-shell-settings` to view available environment variables
### getLogger
bblogger.logger.getLogger
> Use this for initial logger to set the logging class and load environment variables
```python
def getLogger( name, level = None, **opts ):
"""
Set custom logger class and return logger
- only use this for initial call to logger. Use logging.getLogger() for
further logging modules
'name' = Name of returned logger
'level' = Log level for the returned logger. Defaults to 1.
**opts:
More options for logger. To print the log to a file, 'filepath'
must be present in the opts.
'appname' : [ DEFAULT 'BB-Logger' ] Application name
'console' : [ DEFAULT = True ] Print logging to console
'consoleformat' : [ DEFAULT = 'basic' ] Console formatting. Options are
'basic' or 'debug'.
'color' : [ DEFAULT = True ] colorized console logging
'filepath' : [ DEFAULT None ] The path for a file to be written to. The
directory for the file must exist.
- shell var =
'filelevel' : [ DEFAULT = 1 ] Set log level for file. Default is 1, DEBUGGING
- must be set with initial call to logger.getLogger()
- shell var =
'rootlevel' : [ DEFAULT = 1 ] Set the root logger level
- usually best to keep this default
'fileformat' : [ DEFAULT = 'html' ] Text formatting for file - 'plaintext'
or 'html'
- shell var =
'file_write_mode' : [ DEFAULT = 'a' ] write mode for file stream
- 'a': append, 'b': backup old logfile, 'w': overwrite old logfile
'overwrite_time' : [ DEFAULT = -1 ] Ignored if < 0. Amount of seconds before logfile
is overwritten
- shell var =
'avoid_overwrite' : [ DEFAULT = True ] Don't overwrite the logfile if existing
A new file will be created if not existing as long as the directory
already exists. If only a filename is given for 'path', the file will
be written in the user's HOME folder. Extra options should only need
applied for the first time initiating a logger in your app/script.
NOTE: Shell environment variables will override programatic calls to BBLogger
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
#### Logger Class
bblogger.logger.BBLogger
```python
class BBLogger( logging.getLoggerClass() ):
"""
Console and file logging, formatted with BBFormatter
- options are set through logger.getLogger() with initial call
- subsequent loggers should be called with python's logging
module: logging.getLogger()
"""
# Added (or overridden) functions
def setLevel(self, level = None, *opts, set_global = False):
"""
Set logging level for individual log object
'set_global': set global verbosity level
- optionally use 'opts'
'opts':
'file_level': include setting file log level
'ignore_console': don't set level of already initiated
console loggers
- acceptable modes:
'debug' | logging.DEBUG | 10 | 1 <or> 0
'info' | logging.INFO | 20 | 2
'warning' | logging.WARNING | 30 | 3
'error' | logging.ERROR | 40 | 4
'critical' | logging.CRITICAL | 50 | 5
"""
def set_format(self, formatting):
"""
Change formatting for console logging
'basic' - simple, nicely formatted messaging
'debug' - more info pertaining to each message
* defaults to log level 1
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
#### Custom Formatter
bblogger.logger.BBFormatter
```python
class BBFormatter(logging.Formatter):
"""
BBFormatter - Color logging output with ansi or html
mode = 'basic' (console)
Basic logging for end user messages
'debug' (console)
More output information for debugging
'html' (file)
Uses html format to color logs to send to an html file or gui
program that supports html formatting
'plaintext' (file)
No escapes inserted for logging plaintext to a file
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Logger Example
```python
# __init__.py
from bblogger import getLogger
log = getLogger( __name__, 3,
appname = "The_Awesomest_Application_Ever",
filepath = "/path/to/logfile",
filelevel = 1,
consoleformat = 'basic',
fileformat = 'html' )
# NOTE subsequent calls to bblogger.getLogger will return a logger with initial options
# -------------------------------------------------------------
# __main__.py
import logging
log = logging.getLogger(__name__)
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
## TextTools
module texttools
- Collection of console text and ansi manipulation tools
- Add/create text colors for console
- Includes limited html formatting
- Adds a custom color template to user app folder that is loaded on import
- Some consoles may not accept all available attributes
- [Ansi](#ansi) and [AnsiList](#ansilist) for working with strings containing ansi escapes
### Ansi
texttools.ansitools.Ansi
> Work with strings containing ansi escape codes
- Reports accurate (printed) string length
- Built in method to convert to an html `<span>` string
- wrapper for TextTools classmethod `esc2html`
- Provides a 'clean' (escapes removed) version of the string
- Will not throw an 'IndexError' with __getitem__, instead will return an empty string
- Overloaded Constructor
- If multiple strings are passed to Ansi(), an [AnsiList](#ansilist) is returned
- Tries to always return an Ansi object when standard strings are inserted/added
- This won't work when using an Ansi object in an f-string
```python
class Ansi(str):
"""
Holds a string object with escapes while still reporting an accurate
length. also provides a cleaned version (no escapes).
Using f-strings will 're-class' the object to a standard str() object.
It is recommended to use the '+' operator to join standard string objects
with Ansi objects so that they remain Ansi types.
"""
def __init__(self, string = '', **kwargs):
"""
Create an Ansi string
========================================================================
**kwargs:
'last_esc_on_slices': add last ansi escape to end of string if
slice leaves it out
- DEFAULT = False
'reset_on_slice' : add ansi text reset to end of slices
- overrides 'last_esc_on_slices' if True
- DEFAULT = False
'strsep' : passed to AnsiList if split is used
* Also will look for environment variables 'LAST_ESC_ON_SLICES' and
'RESET_ON_SLICES' in os.environ. Boolean values are expected.
Anything other than 'false', '0', or 'no' will set these values
to True.
"""
```
> Ansi is a subclass of `str`, made to facilitate the formatting and printing of strings containing
> ansi escape codes. Because escape codes, on terminals that accept escapes, don't use any columns
> when printed, it makes it hard to do print formatting and text coloring. This attempts to account
> for that by manipulating the character count. This greatly changes iteration, indexing, and slicing
> of an Ansi object.
>
> It can be confusing to use __getitem__ and __iter__ methods. Iterating through 'string' will separate
> the escapes as single characters. In the case of 'string', the last yielded item is `'\x1b[0m'`, yet
> `string[-1]` returns `'!\x1b[0m'`, prepending the last non escaped character to the ansi escape. This
> is by design because the Ansi and AnsiList classes are specifically made to assist in printing and print
> formatting with strings containing ansi escapes. The attributes `clean` and `string` are provided in
> Ansi() as native `str` objects for more complicated uses. Another attribute `escapes` will list all the
> escapes in the string. This was the best I could come up with for handling iteration, indexing, and
> slicing.
>
> Because of the complications of iteration and slicing, it will never throw an IndexError when using
> __getitem__. Instead, an empty string `''` will be returned.
>
> Here is showing some characteristics of Ansi objects:
```python
>>> from texttools import Ansi
>>> string = Ansi( '\x1b[38;2;51;153;255mHello\x1b[38;2;102;255;102m World!\x1b[0m' )
# Actual length
>>> string.rlen()
53
# Normal reported length
>>> len(string)
12
# Iteration
>>> string_list = list(string)
>>> string_list
['\x1b[38;2;51;153;255m',
'H',
'e',
'l',
'l',
'o',
'\x1b[38;2;102;255;102m',
' ',
'W',
'o',
'r',
'l',
'd',
'!',
'\x1b[0m']
>>> len(string_list)
15
# indexing and slicing
>>> string[-1]
'!\x1b[0m'
>>> string[:5]
'\x1b[38;2;51;153;255mHello'
>>> string[:6]
'\x1b[38;2;51;153;255mHello\x1b[38;2;102;255;102m '
# notice the space after the escape code
>>> string[:7]
'\x1b[38;2;51;153;255mHello\x1b[38;2;102;255;102m W'
```
> Because of the characteristics of Ansi strings, splitting is also a bit different.
> Ansi.split() with no arguments will split the string using the value in Ansi.strsep
> and return an AnsiList containing the same `strsep` value. This works vice-versa as
> well when using the added list method `join` in AnsiList.
```python
>>> from texttools import Ansi
>>> string = Ansi( '\x1b[38;2;51;153;255mHello\x1b[38;2;102;255;102m World!\x1b[0m' )
>>> string.split()
[ '\x1b[38;2;51;153;255mHello\x1b[38;2;102;255;102m',
'World!\x1b[0m' ]
# let's try setting the 'strsep' kwarg to 'l'
>>> string = Ansi( '\x1b[38;2;51;153;255mHello\x1b[38;2;102;255;102m World!\x1b[0m', strsep = 'l' )
>>> split_string = string.split()
>>> split_string
[ '\x1b[38;2;51;153;255mHe',
'',
'o\x1b[38;2;102;255;102m Wor',
'd!\x1b[0m' ]
>>> type(split_string)
texttools.ansitools.AnsiList
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### AnsiList
texttools.ansitools.AnsiList
- subclass of `list`
- Accepts 0 or more string arguments to form a list of [Ansi](#ansi) strings
- Shares the same keyword arguments as [Ansi](#ansi)
- Returns [Ansi](#ansi) objects with `join` and `__str__`
Added methods:
```python
def iterclean(self):
"""
A generator of this list with all ansi escapes removed
"""
def join(self, s = None, **kwargs):
"""
Join items in the list with the character in self.strsep
- returns an Ansi object
"""
def strip(self, item = None, *, strip_none = False ):
"""
Removes any list items matching 'item'
- returns a new AnsiList object
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### TextTools Class
texttools.TextTools
> Most of the attributes/functions can be imported directly from the texttools package
```python
class TextTools:
"""
Tools for getting and printing colorized/styled text
"""
# All functions in this class are classmethods
```
#### TextTools Attributes
- FG - foreground RGB ansi escape types
- BG - background RGB ansi escape types
- Styles - text styles (bold, italic, underline, strikethrough, blink)
#### TextTools Classmethods
##### ansi2rgb
texttools.TextTools.ansi2rgb
```python
@classmethod
def ansi2rgb(cls, ansi, *, fg_color = True, bg_color = True):
"""
ansi2rgb( ansi, *, fg_color = True, bg_color = True ) >>> tuple()
Returns a 5 or 10 part tuple from a string containing ansi escapes
*args
'ansi': string containing ansi escape patterns
**kwargs
'fg_color': include foreground tuple in results
- default = True
'bg_color': include background color in results
- default = True
Foreground color is always at the beginning of the tuple if both
'fg_color' and 'bg_color' are True and both values are found
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### blockTxt
texttools.TextTools.blockTxt
```python
@classmethod
def blockTxt( cls, txt, *,
fill_indent = False,
fill_width = False,
indent = 0,
indent_first = 0,
keep_newlines = False,
line_break = ' ',
push = 0,
push_first = False,
split_escapes = True,
start_column = 0,
width = 0,
width_includes_indent = True ):
"""
Indents text for neater printing
*args:
'indent' : amount of indenting to use after 1st line
- 'txt' is split by newlines and 'line_break' value
- if 'keep_newlines' == True, only 'line_break' value is
used to split 'txt'
- default = 0
'push' : push all indent values (does not include width)
to the right [n] amount of columns
- default = 0
'txt' : full text string
'width' : total width of text block
- if negative, subtract from the width found
using os.get_terminal_size
- does not include indent if width_includes_indent == False
**kwargs:
'indent_first' : Amount of columns to indent to first line
- 'indent' to matches the indent value
- a negative value subtracts from indent value
( minumum value will be 0 )
- default = 0
'width_includes_indent': If True (default), includes indent in total width,
otherwise total width = width + indent
'start_column' : Column that first line starts on
- use 'indent' to match the indent value
- default = 0
'split_escapes' : Resets text at end of lines and uses escapes from
the previous line to reset it.
- default = True
'keep_newlines' : Doesn't remove newlines from provided text
- might have double newlines in result
'line_break' : Provide a string pattern to try to break lines on
- default = ' '
'push_first' : Include the first line when using 'push' argument
- default = False
** use fill options to make sure background colors, if used, will cover before
and/or after the text characters
'fill_width' : Fill the remaining width in each line with a space
- default = False
'fill_indent' : Insert escape code before the indent spaces when using
'split_escapes'
- default = False
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### hex2rgb
texttools.TextTools.hex2rgb
```python
@classmethod
def hex2rgb(cls, HEX):
"""
Returns an RGB tuple from a hexidecimal code
'HEX': hexidecimal value representing a color
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### rgb2ansi
texttools.TextTools.rgb2ansi
```python
@classmethod
def rgb2ansi(cls, R = 0, G = 0, B = 0, *, bg = False):
"""
Returns an ansi escape string from RGB values
'R': integer for Red [0-255]
'G': integer for Green [0-255]
'B': integer for Blue [0-255]
* default values are set to Black - (0,0,0)
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### rgb2hex
texttools.TextTools.rgb2hex
```python
@classmethod
def rgb2hex(cls, RGB):
"""
Returns a hexidecimal code from an rgb code
'RGB': tuple|list of 3 integers
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### rgbString
texttools.TextTools.rgbString
```python
@classmethod
def rgbString(cls, value):
"""
Create an rgb string
'value': hex, string of integers, list|tuple, or FG_Color|BG_Color
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### money_fmt
texttools.TextTools.money_fmt
```python
@classmethod
def money_fmt(cls, n, *, color_type = 'term'):
"""
Return formatted number to money string
accepted color_type:
'term', 'term_reverse', 'html', or 'html_reverse'
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### t2a
texttools.TextTools.t2a
```python
@classmethod
def t2a(cls, t: tuple|list, *, end = 'm'):
"""
Tuple to ansi escape
- provide a tuple or list of ansi escape integers
- returns an ansi escape string
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### from16
texttools.TextTools.from16
```python
@classmethod
def from16(cls, color, *, return_data = False):
"""
16 color tuple to rgb tuple
- if len(tup) == 1, assumes 0 for first value
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
##### to16color
texttools.TextTools.to16color
```python
@classmethod
def to16color(cls, rgb, *, bg = False, color_dict = False, diff_key = COLORS_RGB_DIFF_KEY, all_results = False ):
"""
Rgb to 16 color tuple
- rgb length can be 3 or 5
- if rgb doesn't match color, tries to find the closest match
- if len(rgb) != 5, a fg color is returned by default
'bg' : True to force or set to return a bg color
'data' : True to return a dict
'diff_key' : key to sort matches by
[ 'mean'||'median'||'max'||'min'||'min_max_avg' ]
'all_results': return a list of all result data
- assumes 'data' == True
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
#### TextTools Help
texttools.TextTools.help
```python
@classmethod
def help(cls, *, return_list = False):
"""
TextTools help message
- prints detailed list of available colors
'return_list': return as a list instead of printing
- default = False
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
#### Ansi Escape Types
- types of ansi escape objects - subclasses of `str`
- FG_Color
- BG_Color
- Style
- Reset
- AnsiCombo
#### Color Modifiers
- functions defined in escape types that have a color attributes
- Dimmed
- Brightened
- Blended
- Inverted
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Styles
> Blink:
Ansi style: Blink
- Set text to blinking
Attribute Name: Bl|blink
Ansi Code: (5,)
> Remove Blink:
Ansi style: Remove Blink
- Remove the blinking text escape
Attribute Name: Bl_|remove_blink
Ansi Code: (25,)
> Bold:
Ansi style: Bold
- Set text to bold
Attribute Name: B|bold
Ansi Code: (1,)
> Remove Bold:
Ansi style: Remove Bold
- Remove the bold text option
Attribute Name: B_|remove_bold
Ansi Code: (21,)
> Italic:
Ansi style: Italic
- Set text to italic
Attribute Name: I|italic
Ansi Code: (3,)
> Remove Italic:
Ansi style: Remove Italic
- Remove the italic text option
Attribute Name: I_|remove_italic
Ansi Code: (23,)
> Strikethrough:
Ansi style: Strikethrough
- Set strikethrough decoration to text
Attribute Name: S|strikethrough
Ansi Code: (9,)
> Remove Strikethrough:
Ansi style: Remove Strikethrough
- Remove the strike-through text option
Attribute Name: S_|remove_strikethrough
Ansi Code: (29,)
> Underline:
Ansi style: Underline
- Set underline decoration to text
Attribute Name: U|underline
Ansi Code: (4,)
> Remove Underline:
Ansi style: Remove Underline
- Remove the underline text option
Attribute Name: U_|remove_underline
Ansi Code: (24,)
> Reset:
Ansi style: Reset
- Reset all ansi styles and colors
Attribute Name: _|reset
Ansi Code: (0,)
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Working With Color Types
> View a list of all default colors from FG or BG escape group
```python
>>> from texttools import FG
>>> FG.help()
"""
Colors:
Attributes can be 'stacked' using the BITAND '&' to create an AnsiCombo
Example:
FG.white & BG.charcoal & S.Bold
You can only have a Reset object at the beginning of an AnsiCombo
S._ & FG.red
Only one of each color type or Style type is accepted when combining. If 2
or more objects of the same type are detected, a ValueError will be raised. If a Reset
object is added anywhere except the beginning of the combo, a TypeError is raised
NOTE: all color groups share a Reset ('\x1b[0m') object
Colors in class:
...
"""
```
```python
# Import colors
>>> from texttools import ( FG as c,
>>> BG as bg,
>>> Styles as S )
# Get colors by full name or 'code' name
>>> color = c.charcoal
>>> color
AnsiColor(< Charcoal (Fg) >)
>>> color = c.ch
>>> color
AnsiColor(< Charcoal (Fg) >)
>>> str(color)
'\x1b[38;2;26;26;26m'
# AnsiColor attributes
>>> color.rgb # RGB tuple
(26, 26, 26)
>>> ch.name # object name
'Charcoal (Fg)'
>>> ch.hex # hexidecimal value
'#1a1a1a'
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Color Functions
> Use functions in color objects to modify RGB values
> - AnsiCombos that have color attributes will also have these functions
> - If an AnsiCombo has both foreground and background colors, both will be affected
#### Brightened
texttools.types.Brightened
> Lighten AnsiColor with 'bright' function
> - Optionally add a percentage of brightness (default is 15%)
```python
>>> gray = c.dark_gray
>>> gray.rgb
(56, 56, 56)
>>> gray_brightened = color.bright(20)
>>> gray_brightened
'Brightened(< Dark Gray (Fg) - %20 >)'
>>> gray_brightened.rgb
(96, 96, 96)
# You can also use the '+' operator to add the default (15%) bright value
>>> +gray
'Brightened(< Dark Gray (Fg) - %15 >)'
# Doing this more than once will exponentially brighten the object
>>> (+gray).rgb
(86, 86, 86)
>>> (+++gray).rgb
(133, 133, 133)
# NOTE when using operators like this in AnsiCombo creation, the expressions
# need to be wrapped in parentheses.
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
#### Dimmed
texttools.types.Dimmed
> Darken AnsiColor with 'dim' function
> - Optionally add a percentage of dimness (default is 15%)
```python
>>> blue = c.light_blue
>>> blue.rgb
(51, 153, 255)
>>> blue_dimmed = blue.dim(20)
>>> blue_dimmed
'Dimmed(< Light Blue (Fg) - %20 >)'
>>> blue_dimmed.rgb
(41, 122, 204)
# You can also use the '-' operator to subtract the default (15%) dim value
>>> (-blue).rgb
(43, 130, 217)
# Doing this more than once will exponentially dim the object
>>> (---blue).rgb
(31, 94, 156)
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
#### Inverted
texttools.types.Inverted
> Invert AnsiColor with the 'invert' function
> - this function takes no arguments
> - This still needs work and will change in the future, but for now...
```python
>>> blue = c.light_blue
>>> blue.rgb
(51, 153, 255)
>>> blue_inverted = blue.invert()
>>> blue_inverted
'Inverted(< Light Blue (Fg) >)'
>>> blue_inverted.rgb
(204, 102, 0)
# You can also use the '~' operator to invert
>>> (~blue).rgb
(204, 102, 0)
# Doing this more than once or using invert() on the inverted object
# will just revert back to the original AnsiColor
>>> blue_inverted.invert()
AnsiColor(< Light Blue (Fg) >)
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
#### Blended
texttools.types.Blended
> Blend 2 or more AnsiColors or AnsiCombos with the 'blend' function
> - probably the coolest function :)
> - first argument is the color to blend
> - optional 2nd argument to set the blend percentage
> - default blend value = 15%
> - usually requires a higher percentage to notice a difference
> I've written a linear gradient string function that will be incorporated in TextTools in a future release
```python
>>> white = c.white
>>> white.rgb
(255, 255, 255)
>>> orange = c.orange
>>> orange.rgb
(255, 128, 0)
>>> white_orange_blend = white.blend( orange, 40 )
>>> white_orange_blend
'Blended(< White||Orange- %40 >)'
>>> white_orange_blend.rgb
(255, 204, 153)
# AnsiColors can also be blended using the BITOR '|' operator
# - this uses the default 15% blend value
>>> white_orange = white|orange
>>> white_orange
'Blended(< White||Orange- %15 >)'
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### AnsiCombo
texttools.types.AnsiCombo
> AnsiColors can be combined using the BITAND operator `&`. Only one of each color type
> ( `FG_Color`, `BG_Color` ) can be combined. Every `Style` object can also be added as
> long as the 'remove' version isn't combined with the non 'removed' version. A `Reset`
> object can be used in the combination but must be the first to the list or else a
> `TypeError` is raised. Multiple objects that conflict will raise a `ValueError`.
>
> Example:
```python
>>> from texttools import FG, BG, Styles as S
>>> combo = FG.yellow & BG.blue
>>> combo
"AnsiCombo(< Yellow (Fg) + Bg Blue (Bg) >)"
# here, FG._ is actually a Reset object, not an FG_Color
>>> combo = FG._ & FG.gold & BG.dark_gray & S.italic
>>> combo
"AnsiCombo(< Reset + Gold (Fg) + Bg Silver (Bg) + Italic >)"
# trying to add a Reset in the middle of Combo
>>> combo = FG.gold & FG._ & BG.dark_gray & S.italic
"TypeError: Can't add 'Reset' type to another attribute"
# adding 2 conflicting objects
>>> combo = FG.gold & S.remove_italic & BG.dark_gray & S.italic
"ValueError: 'AnsiCombo' already contains 'italic' attributes"
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
### Cursor Controls
texttools.cursorcontrols.CursorControls
```python
>>> from texttools import Cursor
>>> Cursor.Clear.__doc__
"""
Clear screen or line
- alias = 'Cursor.clr'
- clear entire screen (2J)
Clear.line
- clear current line (2K)
L: clear line left of cursor (1K)
R: clear line right of cursor (0K)
Clear.screen
- clear entire screen (2J)
up: clear screen above cursor (1J)
dn: clear screen below cursor (0J)
"""
>>> Cursor.L.__doc__
"""
Cursor Left
'n': Number of columns
"""
>>> Cursor.R.__doc__
"""
Cursor Right
'n': Number of columns
"""
>>> Cursor.col.__doc__
"""
Cursor To Column
'n': column number
"""
>>> Cursor.dn.__doc__
"""
Cursor Down
'n': Number of lines
"""
>>> Cursor.getpos.__doc__
"""
Get cursor position
- returns tuple( [line], [column] )
"""
>>> Cursor.help.__doc__
""" Help message """
>>> Cursor.hide.__doc__
""" Cursor Invisible """
>>> Cursor.pos.__doc__
"""
Set cursor position
- PositionCursor( [line], [column] )
"""
>>> Cursor.show.__doc__
""" Cursor Visible """
>>> Cursor.up.__doc__
"""
Cursor Up
'n': Number of lines
"""
```
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
## Changelog
- 0.3.5
- modified BBLogger and getLogger to hopefully maintain the right level across modules
- added 'rootlogger' level option
- 0.3.8
- changed formatter to include filename instead of logger name
- 0.3.9
- fixed logging error when not in terminal
- 0.3.91
- fixed typo in basic logging.... maybe
- 0.3.92
- 2nd attempt at fixing basic logging
- 0.3.95
- yet another attempt to get basic log formatting right
- 0.4.0
- re-wrote the basic log formatter
- 0.5.0
- completely rebuilt bblogger, texttools, and apputils
- full overhaul of AnsiColors
- added types:
- FG_Color
- BG_Color
- Style
- AnsiCombo
- Brightened
- Dimmed
- Inverted
- Blended
- added functions to apputils
- removed bbargparser (working on new version)
- added user colors and template
- added a lot to documentation
- 0.5.1
- fixed a typo in texttools.types
- 0.5.2
- fixed (hopefully) AnsiCombo
- AnsiCombo was broken when combining certain types
- 0.5.3
- fixed `Colors.new()` (texttools.newColor)
- added functionality to Colors.get (texttools.getColor)
- can now create color from get function
- fixed bblogger
- didn't set handler level with setLevel
- sets the logger class last to avoid recursive errors
- added TypeSet - class that acts like sets for type objects
- changes in apputils
- sets `PROJECT_APP_NAME` to project name if `pyproject.toml` is found
- fix for dividing by 0 in `tupleCalc`
- changes in texttools
- changes to how `__repr__` represents object names
- separated type functions to separate file to clean code
- AnsiCombo now derives methods from `ComboFuncs`
- AnsiEscape now derives methods from `EscapeFuncs`
- added `__dir__` method to `AnsiEscapeMeta`
- added `base` attribute to `Dimmed` and `Brightened` types
- added `bases` attribute to `Blended` type
- added methods to `AnsiCombo`
- `bg`, `fg`, `hasAttr`, `hasBG`, `hasBlink`, `hasBold`, `hasFG`, `hasItalic`, `hasReset`, `hasStrikethrough`, `hasUnderline`
- added `hsv` method and `hsv_to_rgb` class method to AnsiColor objects
- changes to `apputils-shell-variables` script
- tag showing if variable is found in `os.environ`
- `-h`|`--help` message added
- some fixes to bblogger
## Thanks To:
<p>Thread at <a href="https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output">Stack Overflow</a> on python log formatting</p>
> And everyone else on forums across the web for being the sole source of my development learnings :)
<p style="text-align: right;"><a href="#contents"><i>return to contents<i></a></p>
Raw data
{
"_id": null,
"home_page": "",
"name": "BB_AppUtils",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.11,<4.0",
"maintainer_email": "",
"keywords": "",
"author": "Erik Beebe",
"author_email": "beebeapps_debugging@tuta.io",
"download_url": "https://files.pythonhosted.org/packages/20/7c/718ee530a74ab8dcc453b1f8081a6fadf57c104ac8914fd3ccc03ed397b4/bb_apputils-0.5.3.tar.gz",
"platform": null,
"description": "# BB_AppUtils\n\n> Utilities for developing python applications/scripts\n\n> README is incomplete!\n\n## Contents\n\n- [Shell Script 'apputils'](#shell-script) - terminal commands\n\n- [AppUtils](#apputils)\n - package of handy functions and tools\n - [AppData](#appdata) - tools for using system directories\n - Classes\n - AgeInfo - class to make readable strings from timedelta objects\n - [AppData](#appdata) - application directories tool\n - [Date](#date) - Date imports with added functions\n - [Path](#path) - os.path imports with added functions\n - Functions\n - [appendFile](#appendfile)\n - [attribNameFromString](#attribnamefromstring)\n - [filterList](#filterlist)\n - [filter_dir](#filter_dir)\n - [getBoolFromString](#getboolfromstring)\n - [getIndexed](#getindexed)\n - [isBinary](#isbinary)\n - [isSafeAttribName](#issafeattribname)\n - [listDepth](#listdepth)\n - [listFlatten](#listflatten)\n - [matchSimilar](#matchsimilar)\n - [mkData](#mkdata)\n - [moveListItem](#movelistitem)\n - [parseDate](#parsedate)\n - [readFile](#readfile)\n - [sortDiverseList](#sortdiverselist)\n - [stringFilter](#stringfilter)\n - [timeDeltaString](#timedeltastring)\n - [tupleCalc](#tuplecalc)\n - [uniqueName](#uniquename)\n - [writeFile](#writefile)\n - attributes\n - FileLock - Threading type lock for writing/reading files\n - GlobalLock - Threading lock for global use\n\n- [BBLogger](#bblogger)\n - custom Logger and Formatter class for the built-in python logging module\n - [Shell Options](#environment-variables) - set logging options via shell environment\n - [Get Logger](#getlogger) - initial call to bblogger\n - [BBLogger Class](#logger-class)\n - [BBFormatter Class](#custom-formatter)\n - [Logger Example](#logger-example)\n\n- [TextTools](#texttools)\n - collection of tools for modifying console text\n - [Ansi](#ansi) - work with escaped strings\n - [AnsiList](#ansilist)\n - [TextTools Class](#texttools-class) - collection of classmethods\n - [Attributes](#texttools-attributes)\n - [Functions](#texttools-classmethods)\n - [ansi2rgb](#ansi2rgb)\n - [blockTxt](#blocktxt)\n - [hex2rgb](#hex2rgb)\n - [rgb2ansi](#rgb2ansi)\n - [rgb2hex](#rgb2hex)\n - [rgbString](#rgbString)\n - [money_fmt](#money_fmt)\n - [t2a](#t2a)\n - [from16](#from16)\n - [to16color](#to16color)\n - [help](#texttools-help)\n - [Escape Types](#ansi-escape-types)\n - [Styles](#styles)\n - [Using Ansi Colors](#working-with-color-types)\n - Color Functions\n - [Brightened](#brightened)\n - [Dimmed](#dimmed)\n - [Inverted](#inverted) - needs work\n - [Blended](#blended)\n - [AnsiCombo](#ansicombo)\n - [Cursor Controls](#cursor-controls)\n\n- [ChangeLog](#changelog)\n\n## Shell Script\n\n```sh\napputils --help\n\n\n```\n## AppUtils\n\n module apputils\n\n> Multiple functions/tools for various tasks in python applications\n\n### AppData\napputils.appdata.AppData\n\n```python\nclass AppData:\n def __init__(self, appname = PROJECT_APP_NAME):\n \"\"\"\n 'appname': set application name for base directory of app files\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### AppData Functions\n\n AppData.appdir()\n - Locates and creates application directories as needed according to application name\n\n AppData.sysdata()\n - Retrieve default system folders and info\n\n```python\n def appdir( self, d, *folders, file = '', datefile = '',\n create_dir = True, unique = False, move_existing = False):\n \"\"\"\n *args\n 'd': system directory type\n - varies on different operating systems - see sysdata\n - 'cache' : users cache directory\n - 'config': users config directory\n - 'data' : main app directory\n - 'launch': directory where app launchers are placed\n '*folders': path names to append to returned path\n\n **kwargs\n 'create_dir': create directories before they're returned\n 'datefile': strftime format to add to filename if file != None\n - adds date data before extension or at end of filename\n - if set to 'timestamp', the standard timestamp (without\n nanoseconds) is used\n - if set to True, the default dating format is used\n - default date format: '_%Y-%m-%d_%H-%M-%S'\n 'file': add a filename to the end of the returned path\n 'move_existing': if file is set and exists, will move the old file to\n '~filename'. If that already exists, then '~filename (n)',\n 'n' being the first number to make a unique pathname\n - only applies if 'file' is set\n\n 'unique': avoid overwriting a file by setting unique to True\n - renames file by adding an integer to the end\n - does nothing if 'file' is not set\n \"\"\"\n\n def sysdata(self, *args, as_tuple = False):\n \"\"\"\n Return systeminfo\n *args:\n app : [ 'cache'||'data'||'config'||'launch' ]\n home : [ 'home'||'userhome' ]\n user name: [ 'user'||'username' ]\n os type : [ 'os'||'system' ]\n\n **kwargs:\n 'as_tuple': if getting a directory and True, return as a tuple instead\n of using os.path.join\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Date\n\n Imports for working with datetime objects\n\n```python\n def __call__(self, *args, **kwargs):\n \"\"\"\n Use date functions\n kwargs:\n 'date' : assign date otherwise date is set to now\n - must be a datetime object\n 'strftime': datetime.strftime()\n 'strptime': datetime.strptime()\n 'parse' : parse a date with dateutil.parser\n - ignored if 'date' is in kwargs\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Path\napputils._import.Path\n\n Imports for working with system files and directories\n\n```python\nclass Path:\n \"\"\"\n File path modification tools\n - contains mostly builtins ... mostly (some aliased)\n \"\"\"\n from os import ( access as __access__,\n environ as env,\n getcwd as pwd,\n getlogin,\n link as ln,\n listdir as ls,\n makedirs as mkdir,\n readlink,\n remove as rm,\n removedirs as rmdir_R,\n rmdir,\n stat,\n walk,\n R_OK as __R_OK__,\n W_OK as __W_OK__,\n X_OK as __X_OK__ )\n from shutil import ( copyfile as cp,\n copytree as cp_R,\n move as mv )\n from os.path import ( abspath as abs,\n basename as bn,\n dirname as dn,\n exists,\n expanduser,\n isabs,\n isfile,\n isdir,\n islink,\n join as jn,\n sep as pathsep,\n splitext )\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Tools\n apputils.tools\n\n> MISSING DOCUMENTATION\n\n##### appendFile\n apputils.tools.appendFile\n\n```python\ndef appendFile( path, data, *, mode = 'a', encoding = 'utf-8', **kwargs ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### attribNameFromString\n apputils.tools.attribNameFromString\n\n```python\ndef attribNameFromString( string ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### filterList\n apputils.tools.filterList\n\n```python\ndef filterList( _list, match, index = None, *,\n not_in = False, _type = None):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### filter_dir\n apputils.tools.filter_dir\n\n```python\ndef filter_dir(attr, **kwargs):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### getBoolFromString\n apputils.tools.getBoolFromString\n\n```python\ndef getBoolFromString(s):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### getIndexed\n apputils.tools.getIndexed\n\n```python\ndef getIndexed(item, args):\n \"\"\"\n getIndexed(item, args) >>> ( item, args )\n Get item from list of arguments. Returns ( indexed item, args minus item )\n if found else ( None, original args )\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### isBinary\n apputils.tools.isBinary\n\n```python\ndef isBinary(filename):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### isSafeAttribName\n apputils.tools.isSafeAttribName\n\n```python\ndef isSafeAttribName(name):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### listDepth\n apputils.tools.listDepth\n\n```python\ndef listDepth( L: list, *, tuples = False ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### listFlatten\n apputils.tools.listFlatten\n\n```python\ndef listFlatten( *L, depth: int = 1, tuples = False ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### matchSimilar\n apputils.tools.matchSimilar\n\n```python\ndef matchSimilar( find, _list, *,\n ratio = STRING_SEQUENCE_MATCH_RATIO,\n getall = False, getalldata = False ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### mkData\n apputils.tools.mkData\n\n```python\ndef mkData(obj):\n \"\"\"\n Make data dictionary from dataclass, ignoring keys that start with '_'\n - embedded dataclasses are recursively moved to a dict() object as well\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### moveListItem\n apputils.tools.moveListItem\n\n```python\ndef moveListItem( L: list, from_index, to_index, *, items = False ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### parseDate\n apputils.tools.parseDate\n\n```python\ndef parseDate(s, fmt = ''):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### readFile\n apputils.tools.readFile\n\n```python\ndef readFile( path, *, mode = None, encoding = 'utf-8', **kwargs ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### sortDiverseList\n apputils.tools.sortDiverseList\n\n```python\ndef sortDiverseList( L: list|tuple, *,\n reverse = False, unknowns_last = False ):\n \"\"\"\n Sorts lists|tuples containing both str and int\n - integers are returned before strings\n - always returns a list object\n\n Types other than int|float|str are sorted by their '__name__'\n attribute if existing. These will come before the unkown types,\n which will be first in the list, unless 'unknowns_last' is set\n to True, and sorted by their __repr__ value.\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### stringFilter\n apputils.tools.stringFilter\n\n```python\ndef stringFilter( obj: Any, *,\n func = None, start = [], end = [],\n re_search: re.compile = None, re_match: re.compile = None ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### timeDeltaString\n apputils.tools.timeDeltaString\n\n```python\ndef timeDeltaString(t):\n \"\"\"\n Convert time from timedelta object to xx:xx:xx\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### tupleCalc\n apputils.tools.tupleCalc\n\n```python\ndef tupleCalc( a, b, op, *, diff = False, round_int = False ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### uniqueName\n apputils.tools.uniqueName\n\n```python\ndef uniqueName(path, *, move_existing = False):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### writeFile\n apputils.tools.writeFile\n\n```python\ndef writeFile( path, data, *, mode = 'w', encoding = 'utf-8', **kwargs ):\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n## BBLogger\n\n module bblogger\n\n> Custom log formatting and file handling\n\n> Subclasses of the python logging module\n\n#### Environment Variables\n\n> Set logging options using shell variables\n\n```python\n\"\"\"\nUser Shell Options:\n\n 'BBLOGGER_APPNAME' : (string) set a name for the root logger\n 'BBLOGGER_AVOID_OVERWRITE' : (bool value) don't overwrite log file [default = True]\n 'BBLOGGER_COLORED_OUTPUT' : (bool value) use color in console logging [default = True]\n 'BBLOGGER_CONSOLE_FORMAT' : 'debug'|'basic' provide more info on each line with 'debug' [default = 'basic']\n 'BBLOGGER_CONSOLE_STREAM' : output stream - 'stderr'[default] or 'stdout'\n 'BBLOGGER_FILE_FORMAT' : 'html'|'plaintext' [default = 'html']\n 'BBLOGGER_FILE_ROTATE_TIME': amount of seconds before log file is overwritten (default -1)\n - ignored if less than 0\n 'BBLOGGER_FILE_VERBOSITY' : (1 - 5) logging level for file output [default = 1]\n 'BBLOGGER_FILE_WRITE_MODE' : (string) 'a' - append, 'b' - backup, or 'w' - write\n 'BBLOGGER_FILEPATH' : path to log file to [default = None]\n 'BBLOGGER_MAX_FILE_SIZE' : maximum size for logfile in bytes before rotation\n 'BBLOGGER_ROOT_VERBOSITY' : (1 - 5) log level to set the root logger [default = 1]\n 'BBLOGGER_VERBOSITY' : (1 - 5) log level for console output [default = 3]\n\n\"\"\"\n```\n\n- run script in shell `bblogger-shell-settings` to view available environment variables\n\n### getLogger\n bblogger.logger.getLogger\n\n> Use this for initial logger to set the logging class and load environment variables\n\n```python\ndef getLogger( name, level = None, **opts ):\n \"\"\"\n Set custom logger class and return logger\n - only use this for initial call to logger. Use logging.getLogger() for\n further logging modules\n\n 'name' = Name of returned logger\n 'level' = Log level for the returned logger. Defaults to 1.\n\n **opts:\n More options for logger. To print the log to a file, 'filepath'\n must be present in the opts.\n\n 'appname' : [ DEFAULT 'BB-Logger' ] Application name\n 'console' : [ DEFAULT = True ] Print logging to console\n 'consoleformat' : [ DEFAULT = 'basic' ] Console formatting. Options are\n 'basic' or 'debug'.\n 'color' : [ DEFAULT = True ] colorized console logging\n 'filepath' : [ DEFAULT None ] The path for a file to be written to. The\n directory for the file must exist.\n - shell var =\n 'filelevel' : [ DEFAULT = 1 ] Set log level for file. Default is 1, DEBUGGING\n - must be set with initial call to logger.getLogger()\n - shell var =\n 'rootlevel' : [ DEFAULT = 1 ] Set the root logger level\n - usually best to keep this default\n 'fileformat' : [ DEFAULT = 'html' ] Text formatting for file - 'plaintext'\n or 'html'\n - shell var =\n 'file_write_mode' : [ DEFAULT = 'a' ] write mode for file stream\n - 'a': append, 'b': backup old logfile, 'w': overwrite old logfile\n 'overwrite_time' : [ DEFAULT = -1 ] Ignored if < 0. Amount of seconds before logfile\n is overwritten\n - shell var =\n 'avoid_overwrite' : [ DEFAULT = True ] Don't overwrite the logfile if existing\n\n\n A new file will be created if not existing as long as the directory\n already exists. If only a filename is given for 'path', the file will\n be written in the user's HOME folder. Extra options should only need\n applied for the first time initiating a logger in your app/script.\n\n NOTE: Shell environment variables will override programatic calls to BBLogger\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n#### Logger Class\n bblogger.logger.BBLogger\n\n```python\n\nclass BBLogger( logging.getLoggerClass() ):\n \"\"\"\n Console and file logging, formatted with BBFormatter\n - options are set through logger.getLogger() with initial call\n - subsequent loggers should be called with python's logging\n module: logging.getLogger()\n \"\"\"\n\n # Added (or overridden) functions\n\n def setLevel(self, level = None, *opts, set_global = False):\n \"\"\"\n Set logging level for individual log object\n 'set_global': set global verbosity level\n - optionally use 'opts'\n 'opts':\n 'file_level': include setting file log level\n 'ignore_console': don't set level of already initiated\n console loggers\n\n - acceptable modes:\n 'debug' | logging.DEBUG | 10 | 1 <or> 0\n 'info' | logging.INFO | 20 | 2\n 'warning' | logging.WARNING | 30 | 3\n 'error' | logging.ERROR | 40 | 4\n 'critical' | logging.CRITICAL | 50 | 5\n \"\"\"\n\n def set_format(self, formatting):\n \"\"\"\n Change formatting for console logging\n 'basic' - simple, nicely formatted messaging\n 'debug' - more info pertaining to each message\n * defaults to log level 1\n \"\"\"\n\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n#### Custom Formatter\n bblogger.logger.BBFormatter\n\n```python\nclass BBFormatter(logging.Formatter):\n \"\"\"\n BBFormatter - Color logging output with ansi or html\n\n mode = 'basic' (console)\n Basic logging for end user messages\n\n 'debug' (console)\n More output information for debugging\n\n 'html' (file)\n Uses html format to color logs to send to an html file or gui\n program that supports html formatting\n\n 'plaintext' (file)\n No escapes inserted for logging plaintext to a file\n\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Logger Example\n\n```python\n\n# __init__.py\n\nfrom bblogger import getLogger\nlog = getLogger( __name__, 3,\n appname = \"The_Awesomest_Application_Ever\",\n filepath = \"/path/to/logfile\",\n filelevel = 1,\n consoleformat = 'basic',\n fileformat = 'html' )\n\n # NOTE subsequent calls to bblogger.getLogger will return a logger with initial options\n\n# -------------------------------------------------------------\n\n# __main__.py\n\nimport logging\nlog = logging.getLogger(__name__)\n\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n## TextTools\n module texttools\n\n- Collection of console text and ansi manipulation tools\n- Add/create text colors for console\n- Includes limited html formatting\n- Adds a custom color template to user app folder that is loaded on import\n- Some consoles may not accept all available attributes\n- [Ansi](#ansi) and [AnsiList](#ansilist) for working with strings containing ansi escapes\n\n### Ansi\n texttools.ansitools.Ansi\n\n> Work with strings containing ansi escape codes\n\n - Reports accurate (printed) string length\n - Built in method to convert to an html `<span>` string\n - wrapper for TextTools classmethod `esc2html`\n - Provides a 'clean' (escapes removed) version of the string\n - Will not throw an 'IndexError' with __getitem__, instead will return an empty string\n - Overloaded Constructor\n - If multiple strings are passed to Ansi(), an [AnsiList](#ansilist) is returned\n - Tries to always return an Ansi object when standard strings are inserted/added\n - This won't work when using an Ansi object in an f-string\n\n```python\nclass Ansi(str):\n \"\"\"\n Holds a string object with escapes while still reporting an accurate\n length. also provides a cleaned version (no escapes).\n\n Using f-strings will 're-class' the object to a standard str() object.\n It is recommended to use the '+' operator to join standard string objects\n with Ansi objects so that they remain Ansi types.\n \"\"\"\n def __init__(self, string = '', **kwargs):\n \"\"\"\n Create an Ansi string\n ========================================================================\n **kwargs:\n 'last_esc_on_slices': add last ansi escape to end of string if\n slice leaves it out\n - DEFAULT = False\n 'reset_on_slice' : add ansi text reset to end of slices\n - overrides 'last_esc_on_slices' if True\n - DEFAULT = False\n 'strsep' : passed to AnsiList if split is used\n\n * Also will look for environment variables 'LAST_ESC_ON_SLICES' and\n 'RESET_ON_SLICES' in os.environ. Boolean values are expected.\n Anything other than 'false', '0', or 'no' will set these values\n to True.\n \"\"\"\n```\n\n> Ansi is a subclass of `str`, made to facilitate the formatting and printing of strings containing\n> ansi escape codes. Because escape codes, on terminals that accept escapes, don't use any columns\n> when printed, it makes it hard to do print formatting and text coloring. This attempts to account\n> for that by manipulating the character count. This greatly changes iteration, indexing, and slicing\n> of an Ansi object.\n>\n> It can be confusing to use __getitem__ and __iter__ methods. Iterating through 'string' will separate\n> the escapes as single characters. In the case of 'string', the last yielded item is `'\\x1b[0m'`, yet\n> `string[-1]` returns `'!\\x1b[0m'`, prepending the last non escaped character to the ansi escape. This\n> is by design because the Ansi and AnsiList classes are specifically made to assist in printing and print\n> formatting with strings containing ansi escapes. The attributes `clean` and `string` are provided in\n> Ansi() as native `str` objects for more complicated uses. Another attribute `escapes` will list all the\n> escapes in the string. This was the best I could come up with for handling iteration, indexing, and\n> slicing.\n>\n> Because of the complications of iteration and slicing, it will never throw an IndexError when using\n> __getitem__. Instead, an empty string `''` will be returned.\n>\n> Here is showing some characteristics of Ansi objects:\n\n```python\n>>> from texttools import Ansi\n>>> string = Ansi( '\\x1b[38;2;51;153;255mHello\\x1b[38;2;102;255;102m World!\\x1b[0m' )\n\n# Actual length\n>>> string.rlen()\n53\n\n# Normal reported length\n>>> len(string)\n12\n\n# Iteration\n>>> string_list = list(string)\n>>> string_list\n['\\x1b[38;2;51;153;255m',\n 'H',\n 'e',\n 'l',\n 'l',\n 'o',\n '\\x1b[38;2;102;255;102m',\n ' ',\n 'W',\n 'o',\n 'r',\n 'l',\n 'd',\n '!',\n '\\x1b[0m']\n>>> len(string_list)\n15\n\n# indexing and slicing\n>>> string[-1]\n'!\\x1b[0m'\n\n>>> string[:5]\n'\\x1b[38;2;51;153;255mHello'\n\n>>> string[:6]\n'\\x1b[38;2;51;153;255mHello\\x1b[38;2;102;255;102m '\n # notice the space after the escape code\n\n>>> string[:7]\n'\\x1b[38;2;51;153;255mHello\\x1b[38;2;102;255;102m W'\n```\n\n> Because of the characteristics of Ansi strings, splitting is also a bit different.\n> Ansi.split() with no arguments will split the string using the value in Ansi.strsep\n> and return an AnsiList containing the same `strsep` value. This works vice-versa as\n> well when using the added list method `join` in AnsiList.\n\n```python\n>>> from texttools import Ansi\n\n>>> string = Ansi( '\\x1b[38;2;51;153;255mHello\\x1b[38;2;102;255;102m World!\\x1b[0m' )\n>>> string.split()\n[ '\\x1b[38;2;51;153;255mHello\\x1b[38;2;102;255;102m',\n 'World!\\x1b[0m' ]\n\n# let's try setting the 'strsep' kwarg to 'l'\n>>> string = Ansi( '\\x1b[38;2;51;153;255mHello\\x1b[38;2;102;255;102m World!\\x1b[0m', strsep = 'l' )\n>>> split_string = string.split()\n>>> split_string\n[ '\\x1b[38;2;51;153;255mHe',\n '',\n 'o\\x1b[38;2;102;255;102m Wor',\n 'd!\\x1b[0m' ]\n\n>>> type(split_string)\ntexttools.ansitools.AnsiList\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### AnsiList\n texttools.ansitools.AnsiList\n\n- subclass of `list`\n- Accepts 0 or more string arguments to form a list of [Ansi](#ansi) strings\n- Shares the same keyword arguments as [Ansi](#ansi)\n- Returns [Ansi](#ansi) objects with `join` and `__str__`\n\nAdded methods:\n\n```python\n def iterclean(self):\n \"\"\"\n A generator of this list with all ansi escapes removed\n \"\"\"\n\n def join(self, s = None, **kwargs):\n \"\"\"\n Join items in the list with the character in self.strsep\n - returns an Ansi object\n \"\"\"\n\n def strip(self, item = None, *, strip_none = False ):\n \"\"\"\n Removes any list items matching 'item'\n - returns a new AnsiList object\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### TextTools Class\n texttools.TextTools\n\n> Most of the attributes/functions can be imported directly from the texttools package\n\n```python\nclass TextTools:\n \"\"\"\n Tools for getting and printing colorized/styled text\n \"\"\"\n\n # All functions in this class are classmethods\n\n```\n\n#### TextTools Attributes\n\n- FG - foreground RGB ansi escape types\n- BG - background RGB ansi escape types\n- Styles - text styles (bold, italic, underline, strikethrough, blink)\n\n#### TextTools Classmethods\n\n##### ansi2rgb\n texttools.TextTools.ansi2rgb\n\n```python\n@classmethod\ndef ansi2rgb(cls, ansi, *, fg_color = True, bg_color = True):\n \"\"\"\n ansi2rgb( ansi, *, fg_color = True, bg_color = True ) >>> tuple()\n\n Returns a 5 or 10 part tuple from a string containing ansi escapes\n *args\n 'ansi': string containing ansi escape patterns\n\n **kwargs\n 'fg_color': include foreground tuple in results\n - default = True\n 'bg_color': include background color in results\n - default = True\n\n Foreground color is always at the beginning of the tuple if both\n 'fg_color' and 'bg_color' are True and both values are found\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### blockTxt\n texttools.TextTools.blockTxt\n\n```python\n @classmethod\n def blockTxt( cls, txt, *,\n fill_indent = False,\n fill_width = False,\n indent = 0,\n indent_first = 0,\n keep_newlines = False,\n line_break = ' ',\n push = 0,\n push_first = False,\n split_escapes = True,\n start_column = 0,\n width = 0,\n width_includes_indent = True ):\n \"\"\"\n Indents text for neater printing\n *args:\n 'indent' : amount of indenting to use after 1st line\n - 'txt' is split by newlines and 'line_break' value\n - if 'keep_newlines' == True, only 'line_break' value is\n used to split 'txt'\n - default = 0\n 'push' : push all indent values (does not include width)\n to the right [n] amount of columns\n - default = 0\n 'txt' : full text string\n 'width' : total width of text block\n - if negative, subtract from the width found\n using os.get_terminal_size\n - does not include indent if width_includes_indent == False\n\n **kwargs:\n 'indent_first' : Amount of columns to indent to first line\n - 'indent' to matches the indent value\n - a negative value subtracts from indent value\n ( minumum value will be 0 )\n - default = 0\n 'width_includes_indent': If True (default), includes indent in total width,\n otherwise total width = width + indent\n 'start_column' : Column that first line starts on\n - use 'indent' to match the indent value\n - default = 0\n 'split_escapes' : Resets text at end of lines and uses escapes from\n the previous line to reset it.\n - default = True\n 'keep_newlines' : Doesn't remove newlines from provided text\n - might have double newlines in result\n 'line_break' : Provide a string pattern to try to break lines on\n - default = ' '\n 'push_first' : Include the first line when using 'push' argument\n - default = False\n ** use fill options to make sure background colors, if used, will cover before\n and/or after the text characters\n\n 'fill_width' : Fill the remaining width in each line with a space\n - default = False\n 'fill_indent' : Insert escape code before the indent spaces when using\n 'split_escapes'\n - default = False\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### hex2rgb\n texttools.TextTools.hex2rgb\n\n```python\n @classmethod\n def hex2rgb(cls, HEX):\n \"\"\"\n Returns an RGB tuple from a hexidecimal code\n 'HEX': hexidecimal value representing a color\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### rgb2ansi\n texttools.TextTools.rgb2ansi\n\n```python\n @classmethod\n def rgb2ansi(cls, R = 0, G = 0, B = 0, *, bg = False):\n \"\"\"\n Returns an ansi escape string from RGB values\n 'R': integer for Red [0-255]\n 'G': integer for Green [0-255]\n 'B': integer for Blue [0-255]\n\n * default values are set to Black - (0,0,0)\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### rgb2hex\n texttools.TextTools.rgb2hex\n\n```python\n @classmethod\n def rgb2hex(cls, RGB):\n \"\"\"\n Returns a hexidecimal code from an rgb code\n 'RGB': tuple|list of 3 integers\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### rgbString\n texttools.TextTools.rgbString\n\n```python\n @classmethod\n def rgbString(cls, value):\n \"\"\"\n Create an rgb string\n 'value': hex, string of integers, list|tuple, or FG_Color|BG_Color\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### money_fmt\n texttools.TextTools.money_fmt\n\n```python\n @classmethod\n def money_fmt(cls, n, *, color_type = 'term'):\n \"\"\"\n Return formatted number to money string\n accepted color_type:\n 'term', 'term_reverse', 'html', or 'html_reverse'\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### t2a\n texttools.TextTools.t2a\n\n```python\n @classmethod\n def t2a(cls, t: tuple|list, *, end = 'm'):\n \"\"\"\n Tuple to ansi escape\n - provide a tuple or list of ansi escape integers\n - returns an ansi escape string\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### from16\n texttools.TextTools.from16\n\n```python\n @classmethod\n def from16(cls, color, *, return_data = False):\n \"\"\"\n 16 color tuple to rgb tuple\n - if len(tup) == 1, assumes 0 for first value\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n##### to16color\n texttools.TextTools.to16color\n\n```python\n @classmethod\n def to16color(cls, rgb, *, bg = False, color_dict = False, diff_key = COLORS_RGB_DIFF_KEY, all_results = False ):\n \"\"\"\n Rgb to 16 color tuple\n - rgb length can be 3 or 5\n - if rgb doesn't match color, tries to find the closest match\n - if len(rgb) != 5, a fg color is returned by default\n\n 'bg' : True to force or set to return a bg color\n 'data' : True to return a dict\n 'diff_key' : key to sort matches by\n [ 'mean'||'median'||'max'||'min'||'min_max_avg' ]\n 'all_results': return a list of all result data\n - assumes 'data' == True\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n#### TextTools Help\n texttools.TextTools.help\n\n```python\n @classmethod\n def help(cls, *, return_list = False):\n \"\"\"\n TextTools help message\n - prints detailed list of available colors\n\n 'return_list': return as a list instead of printing\n - default = False\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n#### Ansi Escape Types\n\n- types of ansi escape objects - subclasses of `str`\n - FG_Color\n - BG_Color\n - Style\n - Reset\n - AnsiCombo\n\n#### Color Modifiers\n\n- functions defined in escape types that have a color attributes\n - Dimmed\n - Brightened\n - Blended\n - Inverted\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Styles\n\n> Blink:\n Ansi style: Blink\n - Set text to blinking\n\n Attribute Name: Bl|blink\n Ansi Code: (5,)\n\n> Remove Blink:\n Ansi style: Remove Blink\n - Remove the blinking text escape\n\n Attribute Name: Bl_|remove_blink\n Ansi Code: (25,)\n\n> Bold:\n Ansi style: Bold\n - Set text to bold\n\n Attribute Name: B|bold\n Ansi Code: (1,)\n\n> Remove Bold:\n Ansi style: Remove Bold\n - Remove the bold text option\n\n Attribute Name: B_|remove_bold\n Ansi Code: (21,)\n\n> Italic:\n Ansi style: Italic\n - Set text to italic\n\n Attribute Name: I|italic\n Ansi Code: (3,)\n\n> Remove Italic:\n Ansi style: Remove Italic\n - Remove the italic text option\n\n Attribute Name: I_|remove_italic\n Ansi Code: (23,)\n\n> Strikethrough:\n Ansi style: Strikethrough\n - Set strikethrough decoration to text\n\n Attribute Name: S|strikethrough\n Ansi Code: (9,)\n\n> Remove Strikethrough:\n Ansi style: Remove Strikethrough\n - Remove the strike-through text option\n\n Attribute Name: S_|remove_strikethrough\n Ansi Code: (29,)\n\n> Underline:\n Ansi style: Underline\n - Set underline decoration to text\n\n Attribute Name: U|underline\n Ansi Code: (4,)\n\n> Remove Underline:\n Ansi style: Remove Underline\n - Remove the underline text option\n\n Attribute Name: U_|remove_underline\n Ansi Code: (24,)\n\n> Reset:\n Ansi style: Reset\n - Reset all ansi styles and colors\n\n Attribute Name: _|reset\n Ansi Code: (0,)\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Working With Color Types\n\n> View a list of all default colors from FG or BG escape group\n\n```python\n>>> from texttools import FG\n>>> FG.help()\n\"\"\"\n Colors:\n\n Attributes can be 'stacked' using the BITAND '&' to create an AnsiCombo\n Example:\n FG.white & BG.charcoal & S.Bold\n\n You can only have a Reset object at the beginning of an AnsiCombo\n S._ & FG.red\n\n Only one of each color type or Style type is accepted when combining. If 2\n or more objects of the same type are detected, a ValueError will be raised. If a Reset\n object is added anywhere except the beginning of the combo, a TypeError is raised\n\n NOTE: all color groups share a Reset ('\\x1b[0m') object\n\n Colors in class:\n ...\n\"\"\"\n```\n\n```python\n# Import colors\n\n>>> from texttools import ( FG as c,\n>>> BG as bg,\n>>> Styles as S )\n\n# Get colors by full name or 'code' name\n\n>>> color = c.charcoal\n>>> color\nAnsiColor(< Charcoal (Fg) >)\n\n>>> color = c.ch\n>>> color\nAnsiColor(< Charcoal (Fg) >)\n\n>>> str(color)\n'\\x1b[38;2;26;26;26m'\n\n# AnsiColor attributes\n\n>>> color.rgb # RGB tuple\n(26, 26, 26)\n>>> ch.name # object name\n'Charcoal (Fg)'\n>>> ch.hex # hexidecimal value\n'#1a1a1a'\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Color Functions\n\n> Use functions in color objects to modify RGB values\n> - AnsiCombos that have color attributes will also have these functions\n> - If an AnsiCombo has both foreground and background colors, both will be affected\n\n#### Brightened\n texttools.types.Brightened\n\n> Lighten AnsiColor with 'bright' function\n> - Optionally add a percentage of brightness (default is 15%)\n\n```python\n>>> gray = c.dark_gray\n>>> gray.rgb\n(56, 56, 56)\n\n>>> gray_brightened = color.bright(20)\n>>> gray_brightened\n'Brightened(< Dark Gray (Fg) - %20 >)'\n\n>>> gray_brightened.rgb\n(96, 96, 96)\n\n# You can also use the '+' operator to add the default (15%) bright value\n>>> +gray\n'Brightened(< Dark Gray (Fg) - %15 >)'\n\n# Doing this more than once will exponentially brighten the object\n>>> (+gray).rgb\n(86, 86, 86)\n\n>>> (+++gray).rgb\n(133, 133, 133)\n\n# NOTE when using operators like this in AnsiCombo creation, the expressions\n# need to be wrapped in parentheses.\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n#### Dimmed\n texttools.types.Dimmed\n\n> Darken AnsiColor with 'dim' function\n> - Optionally add a percentage of dimness (default is 15%)\n\n```python\n>>> blue = c.light_blue\n>>> blue.rgb\n(51, 153, 255)\n\n>>> blue_dimmed = blue.dim(20)\n>>> blue_dimmed\n'Dimmed(< Light Blue (Fg) - %20 >)'\n\n>>> blue_dimmed.rgb\n(41, 122, 204)\n\n# You can also use the '-' operator to subtract the default (15%) dim value\n>>> (-blue).rgb\n(43, 130, 217)\n\n# Doing this more than once will exponentially dim the object\n>>> (---blue).rgb\n(31, 94, 156)\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n#### Inverted\n texttools.types.Inverted\n\n> Invert AnsiColor with the 'invert' function\n> - this function takes no arguments\n> - This still needs work and will change in the future, but for now...\n\n```python\n>>> blue = c.light_blue\n>>> blue.rgb\n(51, 153, 255)\n\n>>> blue_inverted = blue.invert()\n>>> blue_inverted\n'Inverted(< Light Blue (Fg) >)'\n\n>>> blue_inverted.rgb\n(204, 102, 0)\n\n# You can also use the '~' operator to invert\n>>> (~blue).rgb\n(204, 102, 0)\n\n# Doing this more than once or using invert() on the inverted object\n# will just revert back to the original AnsiColor\n\n>>> blue_inverted.invert()\nAnsiColor(< Light Blue (Fg) >)\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n#### Blended\n texttools.types.Blended\n\n> Blend 2 or more AnsiColors or AnsiCombos with the 'blend' function\n> - probably the coolest function :)\n> - first argument is the color to blend\n> - optional 2nd argument to set the blend percentage\n> - default blend value = 15%\n> - usually requires a higher percentage to notice a difference\n> I've written a linear gradient string function that will be incorporated in TextTools in a future release\n\n```python\n>>> white = c.white\n>>> white.rgb\n(255, 255, 255)\n\n>>> orange = c.orange\n>>> orange.rgb\n(255, 128, 0)\n\n>>> white_orange_blend = white.blend( orange, 40 )\n>>> white_orange_blend\n'Blended(< White||Orange- %40 >)'\n\n>>> white_orange_blend.rgb\n(255, 204, 153)\n\n# AnsiColors can also be blended using the BITOR '|' operator\n# - this uses the default 15% blend value\n\n>>> white_orange = white|orange\n>>> white_orange\n'Blended(< White||Orange- %15 >)'\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### AnsiCombo\n texttools.types.AnsiCombo\n\n> AnsiColors can be combined using the BITAND operator `&`. Only one of each color type\n> ( `FG_Color`, `BG_Color` ) can be combined. Every `Style` object can also be added as\n> long as the 'remove' version isn't combined with the non 'removed' version. A `Reset`\n> object can be used in the combination but must be the first to the list or else a\n> `TypeError` is raised. Multiple objects that conflict will raise a `ValueError`.\n>\n> Example:\n\n```python\n>>> from texttools import FG, BG, Styles as S\n\n>>> combo = FG.yellow & BG.blue\n>>> combo\n\"AnsiCombo(< Yellow (Fg) + Bg Blue (Bg) >)\"\n\n # here, FG._ is actually a Reset object, not an FG_Color\n>>> combo = FG._ & FG.gold & BG.dark_gray & S.italic\n>>> combo\n\"AnsiCombo(< Reset + Gold (Fg) + Bg Silver (Bg) + Italic >)\"\n\n # trying to add a Reset in the middle of Combo\n>>> combo = FG.gold & FG._ & BG.dark_gray & S.italic\n\"TypeError: Can't add 'Reset' type to another attribute\"\n\n # adding 2 conflicting objects\n>>> combo = FG.gold & S.remove_italic & BG.dark_gray & S.italic\n\"ValueError: 'AnsiCombo' already contains 'italic' attributes\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n### Cursor Controls\n texttools.cursorcontrols.CursorControls\n\n```python\n>>> from texttools import Cursor\n\n>>> Cursor.Clear.__doc__\n \"\"\"\n Clear screen or line\n - alias = 'Cursor.clr'\n - clear entire screen (2J)\n\n Clear.line\n - clear current line (2K)\n L: clear line left of cursor (1K)\n R: clear line right of cursor (0K)\n\n Clear.screen\n - clear entire screen (2J)\n up: clear screen above cursor (1J)\n dn: clear screen below cursor (0J)\n \"\"\"\n\n>>> Cursor.L.__doc__\n \"\"\"\n Cursor Left\n 'n': Number of columns\n \"\"\"\n\n>>> Cursor.R.__doc__\n \"\"\"\n Cursor Right\n 'n': Number of columns\n \"\"\"\n\n>>> Cursor.col.__doc__\n \"\"\"\n Cursor To Column\n 'n': column number\n \"\"\"\n\n>>> Cursor.dn.__doc__\n \"\"\"\n Cursor Down\n 'n': Number of lines\n \"\"\"\n\n>>> Cursor.getpos.__doc__\n \"\"\"\n Get cursor position\n - returns tuple( [line], [column] )\n \"\"\"\n\n>>> Cursor.help.__doc__\n \"\"\" Help message \"\"\"\n\n>>> Cursor.hide.__doc__\n \"\"\" Cursor Invisible \"\"\"\n\n>>> Cursor.pos.__doc__\n \"\"\"\n Set cursor position\n - PositionCursor( [line], [column] )\n \"\"\"\n\n>>> Cursor.show.__doc__\n \"\"\" Cursor Visible \"\"\"\n\n>>> Cursor.up.__doc__\n \"\"\"\n Cursor Up\n 'n': Number of lines\n \"\"\"\n```\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n\n## Changelog\n\n- 0.3.5\n - modified BBLogger and getLogger to hopefully maintain the right level across modules\n - added 'rootlogger' level option\n\n- 0.3.8\n - changed formatter to include filename instead of logger name\n\n- 0.3.9\n - fixed logging error when not in terminal\n\n- 0.3.91\n - fixed typo in basic logging.... maybe\n\n- 0.3.92\n - 2nd attempt at fixing basic logging\n\n- 0.3.95\n - yet another attempt to get basic log formatting right\n\n- 0.4.0\n - re-wrote the basic log formatter\n\n- 0.5.0\n - completely rebuilt bblogger, texttools, and apputils\n - full overhaul of AnsiColors\n - added types:\n - FG_Color\n - BG_Color\n - Style\n - AnsiCombo\n - Brightened\n - Dimmed\n - Inverted\n - Blended\n - added functions to apputils\n - removed bbargparser (working on new version)\n - added user colors and template\n - added a lot to documentation\n\n- 0.5.1\n - fixed a typo in texttools.types\n\n- 0.5.2\n - fixed (hopefully) AnsiCombo\n - AnsiCombo was broken when combining certain types\n\n- 0.5.3\n - fixed `Colors.new()` (texttools.newColor)\n - added functionality to Colors.get (texttools.getColor)\n - can now create color from get function\n - fixed bblogger\n - didn't set handler level with setLevel\n - sets the logger class last to avoid recursive errors\n - added TypeSet - class that acts like sets for type objects\n - changes in apputils\n - sets `PROJECT_APP_NAME` to project name if `pyproject.toml` is found\n - fix for dividing by 0 in `tupleCalc`\n - changes in texttools\n - changes to how `__repr__` represents object names\n - separated type functions to separate file to clean code\n - AnsiCombo now derives methods from `ComboFuncs`\n - AnsiEscape now derives methods from `EscapeFuncs`\n - added `__dir__` method to `AnsiEscapeMeta`\n - added `base` attribute to `Dimmed` and `Brightened` types\n - added `bases` attribute to `Blended` type\n - added methods to `AnsiCombo`\n - `bg`, `fg`, `hasAttr`, `hasBG`, `hasBlink`, `hasBold`, `hasFG`, `hasItalic`, `hasReset`, `hasStrikethrough`, `hasUnderline`\n - added `hsv` method and `hsv_to_rgb` class method to AnsiColor objects\n - changes to `apputils-shell-variables` script\n - tag showing if variable is found in `os.environ`\n - `-h`|`--help` message added\n - some fixes to bblogger\n\n## Thanks To:\n\n<p>Thread at <a href=\"https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output\">Stack Overflow</a> on python log formatting</p>\n\n> And everyone else on forums across the web for being the sole source of my development learnings :)\n\n<p style=\"text-align: right;\"><a href=\"#contents\"><i>return to contents<i></a></p>\n",
"bugtrack_url": null,
"license": "",
"summary": "Python development tools",
"version": "0.5.3",
"project_urls": null,
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "23487c46d4bcb11df7e81292a3652a775b4fcdb5f9d9c62cdcdb0ecff75b215a",
"md5": "cdcdc088ab1a6821c6f03c56e7e52912",
"sha256": "f320d621031b834ca26412d757f1df7bfb2f343f0622c20da6e00bda09047de5"
},
"downloads": -1,
"filename": "bb_apputils-0.5.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cdcdc088ab1a6821c6f03c56e7e52912",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11,<4.0",
"size": 293685,
"upload_time": "2024-02-19T03:54:41",
"upload_time_iso_8601": "2024-02-19T03:54:41.004505Z",
"url": "https://files.pythonhosted.org/packages/23/48/7c46d4bcb11df7e81292a3652a775b4fcdb5f9d9c62cdcdb0ecff75b215a/bb_apputils-0.5.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "207c718ee530a74ab8dcc453b1f8081a6fadf57c104ac8914fd3ccc03ed397b4",
"md5": "02e3f3c9b7543ba9863fd7932db4dbf7",
"sha256": "808e4163623d411e467328e8a2c2f314d9166f9e10a84b478f5161ae4502d4be"
},
"downloads": -1,
"filename": "bb_apputils-0.5.3.tar.gz",
"has_sig": false,
"md5_digest": "02e3f3c9b7543ba9863fd7932db4dbf7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11,<4.0",
"size": 304858,
"upload_time": "2024-02-19T03:54:43",
"upload_time_iso_8601": "2024-02-19T03:54:43.045946Z",
"url": "https://files.pythonhosted.org/packages/20/7c/718ee530a74ab8dcc453b1f8081a6fadf57c104ac8914fd3ccc03ed397b4/bb_apputils-0.5.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-02-19 03:54:43",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "bb_apputils"
}