معرفی شرکت ها


cjnfuncs-2.0.1


Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر

توضیحات

A collection of core functions for tool script writing
ویژگی مقدار
سیستم عامل -
نام فایل cjnfuncs-2.0.1
نام cjnfuncs
نسخه کتابخانه 2.0.1
نگهدارنده []
ایمیل نگهدارنده []
نویسنده -
ایمیل نویسنده Chris Nelson <github@cjnaz.com>
آدرس صفحه اصلی -
آدرس اینترنتی https://pypi.org/project/cjnfuncs/
مجوز MIT License Copyright (c) 2019 Chris Nelson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 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: - [lanmonitor](https://pypi.org/project/lanmonitor/) - [wanstatus](https://pypi.org/project/wanstatus/) - [routermonitor](https://pypi.org/project/routermonitor/) - Developed and tested on Python 3.6.8, and supported on all higher Python versions. - Developed on Linux, supported also on Windows (tested on Windows 10). - 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. ## Classes and functions - [setuplogging](#setuplogging) - [set_toolname](#set_toolname) - [mungePath](#mungePath) - [deploy_files](#deploy_files) - [config_item](#config_item) - [loadconfig](#loadconfig) - [getcfg](#getcfg) - [timevalue](#timevalue) - [retime](#retime) - [requestlock](#requestlock) - [releaselock](#releaselock) - [snd_notif](#snd_notif) - [snd_email](#snd_email) <br/> <a id="setuplogging"></a> --- # 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, the `config_logfile` is selected. `config_logfile` - Potential log file passed from loadconfig() if there is a `LogFile` param in the loaded config. Selected by `call_logfile_wins = False`. config_logfile may be absolute path or relative to the tool.log_dir_base directory. `None` specifies the console. ### Returns - NoneType <br/> <a id="set_toolname"></a> --- # 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](https://pypi.org/project/appdirs/), which is a close implementation of the [XDG basedir specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html). - The `user` and `site`-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 a `site` setup.) Thus, for a `user` 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 to `None` 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 <wanstatus>: .toolname : wanstatus .main_module : <module 'wanstatus.wanstatus' from '/<path-to-venv>/lib/python3.9/site-packages/wanstatus/wanstatus.py'> .user_config_dir : /home/me/.config/wanstatus .user_data_dir : /home/me/.local/share/wanstatus .user_state_dir : /home/me/.local/state/wanstatus .user_cache_dir : /home/me/.cache/wanstatus .user_log_dir : /home/me/.cache/wanstatus/log .site_config_dir : /etc/xdg/wanstatus .site_data_dir : /usr/share/wanstatus Based on found user or site dirs: .env_defined : user .config_dir : /home/me/.config/wanstatus .data_dir : /home/me/.local/share/wanstatus .state_dir : /home/me/.local/state/wanstatus .cache_dir : /home/me/.cache/wanstatus .log_dir_base : /home/me/.local/share/wanstatus .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 <wanstatus>: .toolname : wanstatus .main_module : <module 'wanstatus.wanstatus' from '/<path-to-venv>/lib/python3.9/site-packages/wanstatus/wanstatus.py'> .user_config_dir : /root/.config/wanstatus .user_data_dir : /root/.local/share/wanstatus .user_state_dir : /root/.local/state/wanstatus .user_cache_dir : /root/.cache/wanstatus .user_log_dir : /root/.cache/wanstatus/log .site_config_dir : /etc/xdg/wanstatus .site_data_dir : /usr/share/wanstatus Based on found user or site dirs: .env_defined : site .config_dir : /etc/xdg/wanstatus .data_dir : /usr/share/wanstatus .state_dir : /usr/share/wanstatus .cache_dir : /usr/share/wanstatus .log_dir_base : /usr/share/wanstatus .log_dir : None .log_file : None .log_full_path : None ``` <br/> <a id="mungePath"></a> --- # 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 to `in_path` if `in_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 the `base_path` is prepended. - If both `in_path` and `base_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 the `base_path` is ignored. - `in_path` and `base_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 combined `in_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](https://github.com/cjnaz/cjnfuncs) /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 ``` <br/> <a id="deploy_files"></a> --- # 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 a `target_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 pushed `source`. 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 file (default 0o664) - `dir_stat` - Permissions set on each created directory (if not already existing, default 0o775) `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. <br/> <a id="config_item"></a> --- # 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 the `tool.log_dir_base` will be remapped to `tool.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. - config_item.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 the `cfg` dictionary. Also see the loadconfig `import` feature. - Initially in _user_ mode, after the `set_toolname()` call, `tool.log_dir_base` (the log directory) is set to the `tool.user_data_dir`. Once `config_item()` is called the `tool.log_dir_base` is _remapped_ to `tool.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 the `config_item()` call set `remap_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 the `set_toolname()` call and before the `loadconfig()` call, for example `tool.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 ``` <br/> <a id="loadconfig"></a> --- # 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 any `LogFile` 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 raising `ConfigError` if the config file is inaccessible ### Returns - `1` if the config files WAS reloaded - `0` 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` - 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()` calls `setuplogging()`. The `logging` 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 call `setuplogging()` 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 initial `loadconifig()` 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 the `ldcfg_ll` level. - **Log file options** - Where to log has two separate fields: `call_logifle` in the call to loadconfig(), and `LogFile` in the loaded config file, with `call_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 is `None` 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 default format strings for console and file logging. These defaults may be overridden by defining `ConsoleLogFormat` and/or `FileLogFormat` in the config file. - **Import nested config files** - loadconfig() supports `Import` (case insensitive). The imported file path is relative to the `tool.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 of `import` 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`, and `force_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 returns `0`. If the timestamp has changed then the config file will be reloaded, and `1` is returned to indicate to the tool script to do any post-config-load operations. - If `flush_on_reload=True` (default False) then the `cfg` dictionary will be cleaned/purged before the config file is reloaded. If `flush_on_reload=False` then the config file will be reloaded on top of the existing `cfg` dictionary contents (if a param was deleted in the config file it will still exist in `cfg` after the reload). [lanmonitor](https://github.com/cjnaz/lanmonitor) uses these features. - `force_flush_reload=True` (default False) forces both a clear/flush of the `cfg` 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` or `force_flush_reload=True` since the params will disappear briefly. - Changes to imported files are not tracked for changes. - **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. If `tolerate_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 <br/> <a id="getcfg"></a> --- # 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 and `default` value provided - raises ConfigError if param does not exist in cfg and no `default` provided. <br/> <a id="timevalue"></a> --- # 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 the `orig_val` value. 's' for int and float orig_val values. - `.unit_str` - the long-form units of the `orig_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 ``` <br/> <a id="retime"></a> --- # 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 specified `unitC`, 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 ``` <br/> <a id="requestlock"></a> --- # 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 the `lockfile` - `-1` if failed to create the `lockfile` (either file already exists or no write access). A WARNING level message is also logged. <br/> <a id="releaselock"></a> --- # 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 successfully `lockfile` release (lock file deleted) - `-1` if failed to delete the `lockfile`, or the `lockfile` does not exist. A WARNING level message is also logged. <br/> <a id="snd_notif"></a> --- # 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 the `to` 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). Defining `NotifList` in the config is only required if any call to `snd_notif()` uses this default `to` 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()` uses `snd_email()` to send the message. See `snd_email()` for related setup. <br/> <a id="snd_email"></a> --- # 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 the `to` 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`, or `P587TLS`) `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`, or `htmlfile` 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 the `EmailFrom` address be of the same domain as the server, so it may be practical to bundle `EmailFrom` with the server specifics. Place all of these in `~/creds_SMTP`: - `EmailFrom`, `EmailServer`, `EmailServerPort`, `EmailUser`, and `EmailPass` - `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.1 230222 - deploy_files() fix for files from package - 2.0 230208 - Refactored and converted to installed package. Renamed funcs3 to cjnfuncs. - ... - 0.1 180524 - New. First github posting


نیازمندی

مقدار نام
- requests
>=1.4 appdirs
- importlib-resources


زبان مورد نیاز

مقدار نام
>=3.6 Python


نحوه نصب


نصب پکیج whl cjnfuncs-2.0.1:

    pip install cjnfuncs-2.0.1.whl


نصب پکیج tar.gz cjnfuncs-2.0.1:

    pip install cjnfuncs-2.0.1.tar.gz