A collection of core functions for tool script writing
Project description
cjnfuncs - A collection of core functions for script writing
Logging, Configuration files, Email, Lock files, Deploying tool script template files, ...
-
A package template using cjnfuncs is available at https://github.com/cjnaz/tool_template, which is the basis of PyPI posted tools such as:
-
Developed and tested on Python 3.6.8, and supported on all higher Python versions
-
In this documentation, "tool script" refers to a Python project that imports and uses cjnfuncs.
Some may be simple scripts, and others may themselves be installed packages. -
Developed on Linux, supported also on Windows (tested on Windows 10)
Classes and functions
- setuplogging
- set_toolname
- mungePath
- deploy_files
- config_item
- loadconfig
- getcfg
- timevalue
- retime
- requestlock
- releaselock
- snd_notif
- snd_email
setuplogging (call_logfile=None, call_logfile_wins=False, config_logfile=None) - Set up the root logger
Logging may be directed to the console (stdout), or to a file. Each time setuplogging() is called the current/active log file (or console) may be reassigned.
setuplogging() works standalone or in conjunction with loadconfig().
If a loaded config file has a LogFile
parameter then loadconfig() passes it thru
config_logfile
. loadconfig() also passes along any call_logfile
and call_logfile_wins
that were passed to loadconfig() from the tool script. This mechanism allows the tool script
to override any config LogFile
, such as for directing output to the console for a tool script's
interactive use, eg:
setuplogging (call_logfile=None, call_logfile_wins=True, config_logfile='some_logfile.txt')
Parameters
call_logfile
- Potential log file passed from the tool script. Selected by
call_logfile_wins = True
. call_logfile may be an absolute path or relative to the tool.log_dir_base directory.
None
specifies the console.
call_logfile_wins
- If True, the
call_logfile
is selected. If False, theconfig_logfile
is selected.
config_logfile
- Potential log file passed from loadconfig() if there is a
LogFile
param in the loaded config. Selected bycall_logfile_wins = False
. config_logfile may be absolute path or relative to the tool.log_dir_base directory.
None
specifies the console.
Returns
- NoneType
Class set_toolname (toolname) - Set target directories for config and data storage
set_toolname() centralizes and establishes a set of base directory path variables for use in
the tool script. It looks for existing directories, based on the specified toolname, in
the site-wide (system-wide) and then user-specific locations. Specifically, site-wide
config and/or data directories are looked for at (eg) /etc/xdg/cjnfuncs_testenv
and/or
/usr/share/cjnfuncs_testenv
. If site-wide directories are not
found then user-specific is assumed. No directories are created.
Parameter
toolname
- Name of the tool, type str()
Returns
- Handle to the
set_toolname()
instance
Member function
stats()
- Returns a str() listing of the available attributes of the instance
Behaviors, rules, and variances from the XDG spec and/or the appdirs package
-
set_toolname() uses the appdirs package, which is a close implementation of the XDG basedir specification.
-
The
user
andsite
-prefixed attributes are as defined by the XDG spec and/or the appdirs package. The non-such-prefixed attributes are resolved based on the existing user or site environment, and are the attributes that generally should be used within tool scripts. -
For a
user
setup, the.log_dir_base
is initially set to the.user_data_dir
(variance from XDG spec). If a config file is subsequently loaded then the.log_dir_base
is changed to the.user_config_dir
. (Not changed for asite
setup.) Thus, for auser
setup, logging is done to the default configuration directory. This is a style variance, and can be reset in the tool script by reassigning:tool.log_dir_base = tool.user_log_dir
(or any other directory) before calling loadconfig() or setuplogging(). (The XDG spec says logging goes to the.user_state_dir
, while appdirs sets it to the.user_cache_dir/log
.) -
The
.log_dir
,.log_file
, and.log_full_path
attributes are set by calls to setuplogging() or loadconfig(), and are initially set toNone
by set_toolname(). -
For a
site
setup, the.site_data_dir
is set to/usr/share/toolname
. The XDG spec states that the.cache_dir
and.state_dir
should be in the root user tree; however, set_toolname() sets these two also to the.site_data_dir
.
Examples
Given:
tool = set_toolname("cjnfuncs_testenv")
print (tool.stats())
Example stats() for a user-specific setup:
Stats for set_toolname <cjnfuncs_testenv>:
.toolname : cjnfuncs_testenv
.user_config_dir : /home/me/.config/cjnfuncs_testenv
.user_data_dir : /home/me/.local/share/cjnfuncs_testenv
.user_state_dir : /home/me/.local/state/cjnfuncs_testenv
.user_cache_dir : /home/me/.cache/cjnfuncs_testenv
.user_log_dir : /home/me/.cache/cjnfuncs_testenv/log
.site_config_dir : /etc/xdg/cjnfuncs_testenv
.site_data_dir : /usr/share/cjnfuncs_testenv
Based on found user or site dirs:
.env_defined : user
.config_dir : /home/me/.config/cjnfuncs_testenv
.data_dir : /home/me/.local/share/cjnfuncs_testenv
.state_dir : /home/me/.local/state/cjnfuncs_testenv
.cache_dir : /home/me/.cache/cjnfuncs_testenv
.log_dir_base : /home/me/.local/share/cjnfuncs_testenv
.log_dir : None
.log_file : None
.log_full_path : None
Example stats() for a site setup (.site_config_dir and/or .site_data_dir exist):
Stats for set_toolname <cjnfuncs_testenv>:
.toolname : cjnfuncs_testenv
.user_config_dir : /home/me/.config/cjnfuncs_testenv
.user_data_dir : /home/me/.local/share/cjnfuncs_testenv
.user_state_dir : /home/me/.local/state/cjnfuncs_testenv
.user_cache_dir : /home/me/.cache/cjnfuncs_testenv
.user_log_dir : /home/me/.cache/cjnfuncs_testenv/log
.site_config_dir : /etc/xdg/cjnfuncs_testenv
.site_data_dir : /usr/share/cjnfuncs_testenv
Based on found user or site dirs:
.env_defined : site
.config_dir : /etc/xdg/cjnfuncs_testenv
.data_dir : /usr/share/cjnfuncs_testenv
.state_dir : /usr/share/cjnfuncs_testenv
.cache_dir : /usr/share/cjnfuncs_testenv
.log_dir_base : /usr/share/cjnfuncs_testenv
.log_dir : None
.log_file : None
.log_full_path : None
Class mungePath (in_path="", base_path="", mkdir=False) - A clean interface for dealing with filesystem paths
mungePath()
is based on pathlib, producing Path type attributes and status booleans which may be used with all
pathlib.Path methods, such as .open(). mungePath()
accepts paths in two parts - the tool script specific
portion in_path
and a base_path
(prepended if in_path
is relative), and returns an instance that may
be cleanly used in the tool script code.
User (~user/) and environment vars ($HOME/) are supported and expanded.
Parameters
in_path
- An absolute or relative path to a file or directory, such as
mydir/myfile.txt
.
base_path
- An absolute or relative path to a file or directory, such as
~/.config/mytool
, prepended toin_path
ifin_path
is a relative path.
mkdir
- Force-make a full directory path.
in_path
/base_path
is understood to be to a directory.
Returns
- Handle to
mungePath()
instance
Instance attributes
.full_path Path The full expanduser/expandvars path to a file or directory (may not exist)
.parent Path The directory above the .full_path
.name str Just the name.suffix of the .full_path
.is_absolute Boolean True if the .full_path starts from the filesystem root (isn't a relative path)
.is_relative Boolean Not .is_absolute
.exists Boolean True if the .full_path item (file or dir) actually exists
.is_file Boolean True if the .full_path item exists and is a file
.is_dir Boolean True if the .full_path item exists and is a directory
Member functions
- mungePath.stats() - Return a str() listing all stats for the object
- mungePath.refresh_stats() - Update the boolean state attributes for the object. Returns the object so that it may be used directly/immediately in the code.
Behaviors and rules
- If
in_path
is a relative path (eg,mydir/myfile.txt
) portion then thebase_path
is prepended. - If both
in_path
andbase_path
are relative then the combined path will also be relative, usually to the tool script directory (generally not useful). - If
in_path
is an absolute path (eg,/tmp/mydir/myfile.txt
) then thebase_path
is ignored. in_path
andbase_path
may be type str(), Path(), or PurePath().- Symlinks are followed (not resolved).
- User and environment vars are expanded, eg
~/.config
>>/home/me/.config
, as does$HOME/.config
. - The
.parent
is the directory containing (above) the.full_path
. If the object.is_file
then.parent
is the directory containing the file. If the object.is_dir
then the.full_path
includes the end-point directory, and.parent
is the directory above the end-point directory. - When using
mkdir=True
the combinedin_path
/base_path
is understood to be a directory path (not to a file), and will be created if it does not already exist. (Uses pathlib.Path.mkdir()). A FileExistsError is raised if you attempt to mkdir on top of an existing file. - See GitHub repo /tests/demo-mungePath.py for numerous application examples.
Example
Given:
tool = set_toolname("mytool")
xx = mungePath ("mysubdir/file.txt", tool.data_dir)
mungePath (xx.parent, mkdir=True)
if not xx.exists:
with xx.full_path.open('w') as outfile:
file_contents = outfile.write("Hello")
print (xx.refresh_stats().stats()) # Refresh needed else prints stats from when xx was created (before file.txt was created)
What gets printed:
.full_path : /home/me/.local/share/mytool/mysubdir/file.txt
.parent : /home/me/.local/share/mytool/mysubdir
.name : file.txt
.is_absolute : True
.is_relative : False
.exists : True
.is_dir : False
.is_file : True
deploy_files (files_list, overwrite=False, missing_ok=False) - Install initial tool script files in user or site space
deploy_files()
is used to install initial setup files (and directory trees) from the module to the user
or site config and data directories. Suggested usage is with the CLI --setup-user
or --setup-site
switches.
Distribution files and directory trees are hosted in <module_root>/deployment_files/
.
deploy_files()
accepts a list of dictionaries to be pushed to user or site space.
If deployment fails then execution aborts. This functions is intended for interactive use.
Parameters
files_list
- A list of dictionaries, each specifying a
source
file or directory tree to be copied to atarget_dir
.source
- Either an individual file or directory tree within and relative to<module_root>/deployment_files/
. No wildcard support.target_dir
- A directory target for the pushedsource
. It is expanded for user and environment vars, and supports these substitutions (per set_toolname()):- USER_CONFIG_DIR, USER_DATA_DIR, USER_STATE_DIR, USER_CACHE_DIR
- SITE_CONFIG_DIR, SITE_DATA_DIR
- Also absolute paths
file_stat
- Permissions set on each created filedir_stat
- Permissions set on each created directory (if not already existing)
overwrite
- If overwrite=False (default) then only missing files will be copied. If overwrite=True then all files will be overwritten if they exist - data may be lost!
missing_ok
- If missing_ok=True then a missing source file or directory is tolerated (non-fatal). This feature is used for testing.
Returns
- NoneType
Example
deploy_files( [
{ "source": "creds_test", "target_dir": "USER_CONFIG_DIR/example", "file_stat": 0o600, "dir_stat": 0o707},
{ "source": "test_dir", "target_dir": "USER_DATA_DIR", "file_stat": 0o633, "dir_stat": 0o770},
...
], overwrite=True )
The first line will push the <module_root>/deployment_files/creds_test
file to ~/.config/mytool/example/creds_test
.
The toolname mytool
was set by a prior call to set_toolname("mytool")
, in this example.
The directories ~/.config/mytool/
and ~/.config/mytool/example
will have permissions 0o707 and files will have
permission 0o600.
Directory and file owner:group settings will be user:user, or root:root if called under sudo.
The second line pushes a directory (with possible subdirectories) to ~/.local/share/mytool/
.
The target_dir may specify a subdirectory, such as "target_dir": "USER_DATA_DIR/mydirs"
.
Any new directories in the target_dir
path will be created with the dir_stat
permissions,
and files will be created with the file_stat
permissions.
Class config_item (config_file, remap_logdirbase=True) - Create a configuration instance for use with loadconfig()
Several attributes are kept for use by the tool script, including the name, path, and the timestamp of the config file (timestamp once loaded).
The config file may be loaded and reloaded with successive calls to loadconfig().
Parameters
config_file
- Path to the configuration file, relative to the
tool.config_dir
directory, or an absolute path.
remap_logdirbase
(default True)
- If
remap_logdirbase=True
and the tool script is running in user mode (not site mode) then thetool.log_dir_base
will be remapped totool.user_config_dir
.
Returns
- Handle to the
config_item()
instance - Raises a
ConfigError
if the specified config file is not found
Member functions
- config_item.stats() - Return a str() listing all stats for the instance, plus the
tool.log_dir_base
value. - load_config() - Load the config file to the
cfg
dictionary. See below.
Behaviors and rules
- More than one
config_item()
may be created and loaded. This allows for configuration data to be partitioned as desired. All configs are loaded to thecfg
dictionary. Also see the loadconfigimport
feature. - Initially in user mode, after the
set_toolname()
call,tool.log_dir_base
(the log directory) is set to thetool.user_data_dir
. Onceconfig_item()
is called thetool.log_dir_base
is remapped totool.user_config_dir
. This is the author's style preference (centralize user files, and reduce spreading files around the file system). To disable this remap, in theconfig_item()
call setremap_logdirbase=False
. This remapping is not done in site mode. - A different log base directory may be set by user code by setting
tool.log_dir_base
to a different path after theset_toolname()
call and before theloadconfig()
call, for exampletool.log_dir_base = "/var/log"
may be desireable in site mode.
Example
Given
tool = set_toolname("testcfg")
print (f"tool.log_dir_base : {tool.log_dir_base}")
config = config_item("demo_config.cfg", remap_logdirbase=True)
print (config.stats())
config.loadconfig()
print (config.stats())
Output
tool.log_dir_base : /home/me/.local/share/testcfg
Stats for config file <demo_config.cfg>:
.config_file : demo_config.cfg
.config_dir : /home/me/.config/testcfg
.config_full_path : /home/me/.config/testcfg/demo_config.cfg
.config_timestamp : 0
tool.log_dir_base : /home/me/.config/testcfg
Stats for config file <demo_config.cfg>:
.config_file : demo_config.cfg
.config_dir : /home/me/.config/testcfg
.config_full_path : /home/me/.config/testcfg/demo_config.cfg
.config_timestamp : 1675529660.7154639
tool.log_dir_base : /home/me/.config/testcfg
loadconfig () (config_item() class member function) - Load a configuration file into the cfg dictionary
loadconfig(
ldcfg_ll = DEFAULT_LOGGING_LEVEL,
call_logfile = None,
call_logfile_wins = False,
flush_on_reload = False,
force_flush_reload = False,
isimport = False,
tolerate_missing = False)
loadconfig() is a member function of the config_item()
class. Create a config_item()
instance
and then invoke loadconfig()
on that instance. Config file parameters are loaded to the cfg
dictionary, and can be accessed directly or via getcfg()
.
loadconfig()
initializes the root logger for logging either to 1) the LogFile
specified in
the loaded config file, 2) the call_logfile
in the loadconfig()
call, or 3) the console.
loadconfig()
supports dynamic reloading of config files, hierarchy of config data via the import
feature, and intermittent loss of access to the config file.
Parameters
ldcfg_ll
(default 30/WARNING)
- Logging level used within
loadconfig()
code for debugging loadconfig() itself
call_logfile
(default None)
- A relative or absolute path to a log file
call_logfile_wins
(default False)
- If True, the
call_logfile
overrides anyLogFile
in the config file
flush_on_reload
(default False)
- If the config file will be reloaded (due to a changed timestamp) then clean out
cfg
first
force_flush_reload
(default False)
- Forces cfg to be cleaned out and the config file to be reloaded, regardless of whether the config file timestamp has changed
isimport
(default False)
- Internally set True when handling imports. Not used by tool script calls.
tolerate_missing
(default False)
- Used in a tool script service loop, return
-1
rather than raisingConfigError
if the config file is inaccessible
Returns
1
if the config files WAS reloaded0
if the config file was NOT reloaded- If the config file cannot be accessed
- If tolerate_missing == False (default), then raises
ConfigError
- If tolerate_missing == True, then returns
-1
- If tolerate_missing == False (default), then raises
- A ConfigError is raised if there are parsing issues
- A ConfigError is also raised if an imported config file cannot be loaded (non-existent)
Behaviors and rules
-
See
getcfg()
, below, for accessing loaded config data.cfg
is a global dictionary which may be directly accessed as well. -
The format of a config file is param=value pairs (with no section or default as in the Python configparser module). Separating the param and value may be whitespace,
=
or:
. -
Native int, bool, and str support - Integer values in the config file are stored as integers in the cfg dictionary, True and False values (case insensitive) are stored as booleans, and all other entries are stored as strings. This avoids most explicit type casting clutter in the tool script.
-
Logging setup -
loadconfig()
callssetuplogging()
. Thelogging
handle is available for import by other modules (from cjnfuncs.cjnfuncs import logging
). By default, logging will go to the console (stdout) filtered at the WARNING/30 level. Don't callsetuplogging()
directly if using loadconfig. -
Logging level control - Optional
LogLevel
in the config file will set the logging level after the config file has been loaded. If LogLevel is not specified in the config file, then the logging level is set to the Python default logging level, 30/WARNING. The tool script code may also manually/explicitly set the logging level - after the initialloadconifig()
call - and this value will be retained over later calls to loadconfig, thus allowing for a command line--verbose
switch feature. Note that logging done within loadconfig() code is always done at theldcfg_ll
level. -
Log file options - Where to log has two separate fields:
call_logifle
in the call to loadconfig(), andLogFile
in the loaded config file, withcall_logfile_wins
selecting which is used. This mechanism allows for a command line--log-file
switch to override a default log file defined in the config file. If the selected logging location isNone
then output goes to the console (stdout).call_logfile_wins call_logfile Config LogFile Results False (default) ignored None (default) Console False (default) ignored file_path To the config LogFile True None (default) ignored Console True file_path ignored To the call_logfile -
Logging format - cjnfuncs has built-in format strings for console and file logging. These defaults may be overridden by defining
CONSOLE_LOGGING_FORMAT
and/orFILE_LOGGING_FORMAT
constants in the tool script file. -
Import nested config files - loadconfig() supports
Import
(case insensitive). The imported file path is relative to thetool.config_dir
if not an absolute path. The specified file is imported as if the params were in the main config file. Nested imports are allowed. A prime usage ofimport
is to place email server credentials in your home directory with user-only readability, then import them in the tool script config file as such:import ~/creds_SMTP
. -
Config reload if changed,
flush_on_reload
, andforce_flush_reload
- loadconfig() may be called periodically by the tool script, such as in a service loop. If the config file timestamp is unchanged then loadconfig() immediately returns0
. If the timestamp has changed then the config file will be reloaded, and1
is returned to indicate to the tool script to do any post-config-load operations.- If
flush_on_reload=True
(default False) then thecfg
dictionary will be cleaned/purged before the config file is reloaded. Ifflush_on_reload=False
then the config file will be reloaded on top of the existingcfg
dictionary contents (if a param was deleted in the config file it will still exist incfg
after the reload). lanmonitor uses these features. force_flush_reload=True
(default False) forces both a clear/flush of thecfg
dictionary and then a fresh reload of the config file.- Note that if using threading then a thread should be paused while the config file
is being reloaded with
flush_on_reload=True
orforce_flush_reload=True
since the params will disappear briefly. - Changes to imported files are not tracked for changes.
- If
-
Tolerating intermittent config file access - When implementing a service loop, if
tolerate_missing=True
(default False) then loadconfig() will return-1
if the config file cannot be accessed, informing the tool script of the problem for appropriate handling. Iftolerate_missing=False
then loadconfig() will raise a ConfigError if the config file cannot be accessed. -
Comparison to Python's configparser module - configparser contains many customizable features. Here are a few key comparisons:
Feature loadconfig Python configparser Native types int, bool (true/false case insensitive), str str only, requires explicit type casting via getter functions Reload on config file change built-in not built-in Import sub-config files Yes No Section support No Yes Default support No Yes Fallback support Yes (getcfg default) Yes Whitespace in params No Yes Case sensitive params Yes (always) Default No, customizable Param/value delimiter whitespace, ':', or '=' ':' or '=', customizable Param only (no value) No Yes Multi-line values No Yes Comment prefix '#' fixed, thus can't be part of the param or value '#' or ';', customizable Interpolation No Yes Mapping Protocol Access No Yes Save to file No Yes
getcfg (param, default=None) - Get a param from the cfg dictionary.
Returns the value of param from the cfg dictionary. Equivalent to just referencing cfg[] but with handling if the item does not exist.
NOTE: getcfg()
is almost equivalent to cfg.get()
, except that getcfg()
does not default to None
.
Rather, getcfg()
raises a ConfigError if the param does not exist and no default
is specified.
This can lead to cleaner tool script code. Either access method may be used, along with x = cfg["param"]
.
Parameters
param
- String name of param to be fetched from cfg
default
(default None)
- if provided, is returned if
param
does not exist in cfg
Returns
- param value (cfg[param]), if param is in cfg
default
value if param not in cfg anddefault
value provided- raises ConfigError if param does not exist in cfg and no
default
provided.
Class timevalue (orig_val) - Convert time value strings of various resolutions to seconds
timevalue()
provides a convenience mechanism for working with time values and time/datetime calculations.
timevalues are generally an integer value with an attached single character time resolution, such as "5m".
Supported timevalue units are 's'econds, 'm'inutes, 'h'ours, 'd'ays, and 'w'eeks, and are case insensitive.
timevalue()
also accepts integer and float values, which are interpreted as seconds resolution. Also see retime().
Parameters
orig_val
- The original, passed-in value of type str, int, or float
Returns
- Handle to instance
- Raises ValueError if given an unsupported time unit suffix.
Instance attributes
.orig_val
- orig_val value passed in, type str (converted to str if int or float passed in).seconds
- time value in seconds resolution, type float, useful for time calculations.unit_char
- the single character suffix unit of theorig_val
value. 's' for int and float orig_val values..unit_str
- the long-form units of theorig_val
value useful for printing/logging ("secs", "mins", "hours", "days", or "weeks")
Member functions
- timevalue.stats() - Return a str() listing all attributes of the instance
Example
Given
xx = timevalue("1m")
print (xx.stats())
print (f"Sleep <{xx.seconds}> seconds")
time.sleep(xx.seconds)
Output:
.orig_val : 1m <class 'str'>
.seconds : 60.0 <class 'float'>
.unit char : m <class 'str'>
.unit_str : mins <class 'str'>
Sleep <60.0> seconds
retime (time_sec, unitC) - Convert time value in seconds to unitC resolution
retime()
translates a value is resolution seconds into a new target resolution
Parameters
time_sec
- Time value in resolution seconds, type int or float.
unitC
- Target time resolution: "s", "m", "h", "d", or "w" (case insensitive)
Returns
time_sec
value scaled for the specifiedunitC
, type float- Raises ValueError if not given an int or float value for
time_sec
, or given an unsupported unitC time unit suffix.
Example
Given
xx = timevalue("210H")
print (f"{xx.orig_val} = {xx.seconds} seconds = {retime(xx.seconds, 'W')} weeks")
Output
210H = 756000.0 seconds = 1.25 weeks
requestlock (caller, lockfile, timeout=5) - Lock file request
For tool scripts that may take a long time to run and are run by CRON, the possibility exists that a job is still running when CRON wants to run it again, which may create a real mess. This lock file mechanism is used in https://github.com/cjnaz/rclonesync-V2, as an example.
requestlock()
places a file to indicate that the current process is busy.
Other processes then attempt to requestlock()
the same lockfile
before doing an operation
that would conflict with the process that set the lock.
The lockfile
is written with caller
information that indicates which tool script set the lock, and when.
Multiple lock files may be used simultaneously by specifying unique lockfile
names.
Parameters
caller
- Info written to the lock file and displayed in any error messages
lockfile
(default /tmp/<toolname>_LOCK)
- Lock file name, relative to the system tempfile.gettempdir(), or absolute path
timeout
(default 5s)
- Time in seconds to wait for the lockfile to be removed by another process before returning with a
-1
result.timeout
may be an int, float or timevalue string (eg, '5s').
Returns
0
on successfully creating thelockfile
-1
if failed to create thelockfile
(either file already exists or no write access). A WARNING level message is also logged.
releaselock (lockfile) - Release a lock file
Any code can release a lock, even if that code didn't request the lock. Generally, only the requester should issue the releaselock. A common use is with a tool script that runs periodically by CRON, but may take a long time to complete. Using file locks ensures that the tool script does not run if the prior run has not completed.
Parameters
lockfile
(default /tmp/<toolname>_LOCK)
- Lock file name, relative to the system tempfile.gettempdir(), or absolute path
Returns
0
on successfullylockfile
release (lock file deleted)-1
if failed to delete thelockfile
, or thelockfile
does not exist. A WARNING level message is also logged.
snd_notif (subj="Notification message, msg="", to="NotifList", log=False) - Send a text message using info from the config file
Intended for use of your mobile provider's email-to-text bridge email address, eg, 5405551212@vzwtxt.com for Verizon, but any eamil address will work.
The to
string may be the name of a confg param (who's value is one or more email addresses, default
"NotifList"), or a string with one or more email addresses. Using a config param name allows for customizing the
to
addresses without having to edit the code.
The messages to send is passed in the msg
parameter as a text string.
Parameters
subj
(default "Notification message")
- Text message subject field
msg
(default "")
- Text message body
to
(default "NotifList")
- To whom to send the message.
to
may be either an explicit string list of email addresses (whitespace or comma separated) or a config param name (also listing one or more whitespace or comma separated email addresses). If theto
parameter does not contain an '@' it is assumed to be a config param.
log
(default False)
- If True, logs that the message was sent at the WARNING level. If False, logs
at the DEBUG level. Useful for eliminating separate logging messages in the tool script code.
The
subj
field is part of the log message.
cfg dictionary params
NotifList
(optional)
- string list of email addresses (whitespace or comma separated).
DefiningNotifList
in the config is only required if any call tosnd_notif()
uses this defaultto
parameter value.
DontNotif
(default False)
- If True, notification messages are not sent. Useful for debug. All email and notification
messages are also blocked if
DontEmail
is True.
Returns
- NoneType
- Raises SndEmailError on error
Behaviors and rules
snd_notif()
usessnd_email()
to send the message. Seesnd_email()
for related setup.
snd_email (subj, to, body=None, filename=None, htmlfile=None, log=False)) - Send an email message using info from the config file
The to
string may be the name of a confg param (who's value is one or more email addresses),
or a string with one or more email addresses. Using a config param name allows for customizing the
to
addresses without having to edit the code.
What to send may be a body
string, the text contents of filename
, or the HTML-formatted contents
of htmlfile
, in this order of precendent.
Parameters
subj
- Email subject text
to
- To whom to send the message.
to
may be either an explicit string list of email addresses (whitespace or comma separated) or a config param name (also listing one or more whitespace or comma separated email addresses). If theto
parameter does not contain an '@' it is assumed to be a config param.
body
(default None)
- A string message to be sent
filename
(default None)
- A str or Path to the file to be sent, relative to the
tool.cache_dir
, or an absolute path.
htmlfile
(default None)
- A str or Path to the html formatted file to be sent, relative to the
tool.cache_dir
, or an absolute path.
log
(default False)
- If True, logs that the message was sent at the WARNING level. If False, logs
at the DEBUG level. Useful for eliminating separate logging messages in the tool script code.
The
subj
field is part of the log message.
cfg dictionary params
EmailFrom
- An email address, such as
me@myserver.com
EmailServer
- The SMTP server name, such as
mail.myserver.com
EmailServerPort
- The SMTP server port (one of
P25
,P465
,P587
, orP587TLS
)
EmailUser
- Username for
EmailServer
login, if required by the server
EmailPass
- Password for
EmailServer
login, if required by the server
DontEmail
(default False)
- If True, messages are not sent. Useful for debug. Also blocks
snd_notif()
messages.
EmailVerbose
(default False)
- If True, detailed transactions with the SMTP server are sent to stdout. Useful for debug.
Returns
- NoneType
- Raises SndEmailError on error
Behaviors and rules
- One of
body
,filename
, orhtmlfile
must be specified. Looked for in this order, and the first found is used. - EmailServerPort must be one of the following:
- P25: SMTP to port 25 without any encryption
- P465: SMTP_SSL to port 465
- P587: SMTP to port 587 without any encryption
- P587TLS: SMTP to port 587 and with TLS encryption
- It is recommneded (not required) that the email server params be placed in a user-read-only
file in the user's home directory, such as
~/creds_SMTP
, and imported by the main config file. Some email servers require that theEmailFrom
address be of the same domain as the server, so it may be practical to bundleEmailFrom
with the server specifics. Place all of these in~/creds_SMTP
:EmailFrom
,EmailServer
,EmailServerPort
,EmailUser
, andEmailPass
snd_email()
does not support multi-part MIME (an html send wont have a plain text part).- Checking the validity of email addresses is very basic... an email address must contain an '@'.
Revision history
- 2.0 230208 - Refactored and converted to installed package. Renamed funcs3 to cjnfuncs.
- ...
- 0.1 180524 - New. First github posting
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.