<!--- Top of README Badges (automated) --->
[![PyPI](https://img.shields.io/pypi/v/wipac-dev-tools)](https://pypi.org/project/wipac-dev-tools/) [![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/WIPACrepo/wipac-dev-tools?include_prereleases)](https://github.com/WIPACrepo/wipac-dev-tools/) [![PyPI - License](https://img.shields.io/pypi/l/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/blob/main/LICENSE) [![Lines of code](https://img.shields.io/tokei/lines/github/WIPACrepo/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/) [![GitHub issues](https://img.shields.io/github/issues/WIPACrepo/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aopen) [![GitHub pull requests](https://img.shields.io/github/issues-pr/WIPACrepo/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Aopen)
<!--- End of README Badges (automated) --->
# wipac-dev-tools
Common, basic, and reusable development tools
## Utilities
### Logging Tools
#### `wipac_dev_tools.logging_tools.set_level()`
_Available for Python 3.6+_
```
def set_level(
level: LoggerLevel,
first_party_loggers: Union[
None, LogggerObjectOrName, List[LogggerObjectOrName]
] = None,
third_party_level: LoggerLevel = "WARNING",
future_third_parties: Union[None, str, List[str]] = None,
specialty_loggers: Optional[Dict[LogggerObjectOrName, LoggerLevel]] = None,
use_coloredlogs: bool = False,
) -> None:
"""Set the level of loggers of various precedence.
The root logger and first-party logger(s) are set to the same level (`level`).
Args:
`level`
the desired logging level (first-party), case-insensitive
`first_party_loggers`
a list (or a single instance) of `logging.Logger` or the loggers' names
`third_party_level`
the desired logging level for any other (currently) available loggers, case-insensitive
`future_third_parties`
additional third party logger(s) which have not yet been created (at call time)
`specialty_loggers`
additional loggers, each paired with a logging level, which are not
considered first-party nor third-party loggers. **These have the highest precedence**
`use_coloredlogs`
if True, will import and use the `coloredlogs` package.
This will set the logger format and use colored text.
"""
```
#### `wipac_dev_tools.logging_tools.log_argparse_args()`
_Available for Python 3.6+_
```
def log_argparse_args(
args: argparse.Namespace,
logger: Union[None, str, logging.Logger] = None,
level: LoggerLevel = "WARNING",
) -> argparse.Namespace:
"""Log the argparse args and their values at the given level.
Return the args (Namespace) unchanged.
Example:
2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING in_file: in_msg.pkl
2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING out_file: out_msg.pkl
2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING log: DEBUG
2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING log_third_party: WARNING
"""
```
### Environment Variable Tool(s)
#### `wipac_dev_tools.from_environment()`
_Available for Python 3.6+_
```
def from_environment(keys: KeySpec) -> Dict[str, RetVal]:
"""Obtain configuration values from the OS environment.
Parsing Details:
Types are inferred from the default values, and casted as such:
`bool`: *(case-insensitive)*:
- `True` => ("y", "yes", "t", "true", "on", or "1")
- `False` => ("n", "no", "f", "false", "off", or "0")
- `Error` => any other string
`int`: normal cast (`int(str)`)
`float`: normal cast (`float(str)`)
`other`: no change (`str`)
Arguments:
keys - Specify the configuration values to obtain.
This can be a string, specifying a single key, such as:
config_dict = from_environment("LANGUAGE")
This can be a list of strings, specifying multiple keys,
such as:
config_dict = from_environment(["HOME", "LANGUAGE"])
This can be a dictionary that provides some default values,
and will accept overrides from the environment:
default_config = {
"HOST": "localhost",
"PORT": 8080,
"REQUIRED_FROM_ENVIRONMENT": None
}
config_dict = from_environment(default_config)
Note in this case that if 'HOST' or 'PORT' were defined in the
environment, those values would be returned in config_dict. If
the values were not defined in the environment, the default values
from default_config would be returned in config_dict.
Also note, that if 'REQUIRED_FROM_ENVIRONMENT' is not defined,
an OSError will be raised. The sentinel value of None indicates
that the configuration parameter MUST be sourced from the
environment.
Returns:
a dictionary mapping configuration keys to configuration values
Raises:
OSError - If a configuration value is requested and no default
value is provided (via a dict), to indicate that the
component's configuration is incomplete due to missing
data from the OS.
ValueError - If a type-indicated value is not a legal value
"""
```
#### `wipac_dev_tools.from_environment_as_dataclass()`
_Available for Python 3.7+_
```
def from_environment_as_dataclass(
dclass: Type[T],
collection_sep: Optional[str] = None,
dict_kv_joiner: str = "=",
log_vars: Optional[logging_tools.LoggerLevel] = "WARNING",
) -> T:
"""Obtain configuration values from the OS environment formatted in a
dataclass.
Environment variables are matched to a dataclass field's name. The
matching environment string is cast using the dataclass field's type
(there are some special cases for built-in types, see below). Then,
the values are used to create a dataclass instance. All normal
dataclass init-behavior is expected, like required fields
(positional arguments), optional fields with defaults, default
factories, post-init processing, etc.
If a field's type is a bool, `wipac_dev_tools.strtobool` is applied.
If a field's type is a `list`, `dict`, `set`, `frozenset`, or
an analogous type alias from the 'typing' module, then a conversion
is made (see `collection_sep` and `dict_kv_joiner`). Sub-types
are cast if using a typing-module type alias. The typing-module's
alias types must resolve to `type` within 1 nesting (eg: List[bool]
and Dict[int, float] are okay; List[Dict[int, float]] is not), or
2 if using 'Final' or 'Optional' (ex: Final[Dict[int, float]]).
If a field's type is a class that accepts 1 argument, it is
instantiated as such.
Arguments:
dclass - a (non-instantiated) dataclass, aka a type
collection_sep - the delimiter to split collections on ("1 2 5")
dict_kv_joiner - the delimiter that joins key-value pairs ("a=1 b=2 c=1")
log_vars - what level to log the collected environment variables (set to `None` to not log)
Returns:
a dataclass instance mapping configuration keys to configuration values
Example:
env:
FPATH=/home/example/path
PORT=9999
HOST=localhost
MSGS_PER_CLIENTS=alpha=0 beta=55 delta=3
USE_EVEN=22
RETRIES=3
python:
@dataclasses.dataclass(frozen=True)
class Config:
FPATH: pathlib.Path
PORT: int
HOST: str
MSGS_PER_CLIENTS: Dict[str, int]
USE_EVEN: EvenState
RETRIES: Optional[int] = None
TIMEOUT: int = 30
def __post_init__(self) -> None:
if self.PORT <= 0:
raise ValueError("'PORT' is non-positive")
class EvenState:
def __init__(self, arg: str):
self.is_even = not bool(int(arg) % 2) # 1%2 -> 1 -> T -> F
def __repr__(self) -> str:
return f"EvenState(is_even={self.is_even})"
config = from_environment_as_dataclass(Config)
print(config)
stdout:
Config(
FPATH=PosixPath('/home/example/path'),
PORT=9999,
HOST='localhost',
MSGS_PER_CLIENTS={'alpha': 0, 'beta': 55, 'delta': 3},
USE_EVEN=EvenState(is_even=True),
RETRIES=3,
TIMEOUT=30)
Raises:
OSError - If a configuration value is requested and no default
value is provided, to indicate that the component's
configuration is incomplete due to missing data from
the OS.
ValueError - If an indicated value is not a legal value
TypeError - If an argument or indicated value is not a legal type
"""
```
#### `wipac_dev_tools.strtobool()`
```
def strtobool(string: str) -> bool:
"""Smart-cast a string to a bool using common-sense interpretations.
Unlike the since deprecated `distutils.util.strtobool`, this
returns an actual bool.
True: 'y', 'yes', 't', 'true', 'on', '1'
False: 'n', 'no', 'f', 'false', 'off', '0'
Raises:
ValueError: if the string does not match any of the about
"""
```
Raw data
{
"_id": null,
"home_page": "https://github.com/WIPACrepo/wipac-dev-tools",
"name": "wipac-dev-tools",
"maintainer": "",
"docs_url": null,
"requires_python": "<3.13,>=3.8",
"maintainer_email": "",
"keywords": "python,tools,utilities,WIPAC,IceCube",
"author": "WIPAC Developers",
"author_email": "developers@icecube.wisc.edu",
"download_url": "https://files.pythonhosted.org/packages/ca/e4/badbeca56f3fb7424ac4f308e04bafbda242dbfd0f7248df702ed7111c2f/wipac-dev-tools-1.9.1.tar.gz",
"platform": null,
"description": "<!--- Top of README Badges (automated) --->\n[![PyPI](https://img.shields.io/pypi/v/wipac-dev-tools)](https://pypi.org/project/wipac-dev-tools/) [![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/WIPACrepo/wipac-dev-tools?include_prereleases)](https://github.com/WIPACrepo/wipac-dev-tools/) [![PyPI - License](https://img.shields.io/pypi/l/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/blob/main/LICENSE) [![Lines of code](https://img.shields.io/tokei/lines/github/WIPACrepo/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/) [![GitHub issues](https://img.shields.io/github/issues/WIPACrepo/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/issues?q=is%3Aissue+sort%3Aupdated-desc+is%3Aopen) [![GitHub pull requests](https://img.shields.io/github/issues-pr/WIPACrepo/wipac-dev-tools)](https://github.com/WIPACrepo/wipac-dev-tools/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Aopen) \n<!--- End of README Badges (automated) --->\n# wipac-dev-tools\nCommon, basic, and reusable development tools\n\n\n## Utilities\n\n### Logging Tools\n\n#### `wipac_dev_tools.logging_tools.set_level()`\n_Available for Python 3.6+_\n```\ndef set_level(\n level: LoggerLevel,\n first_party_loggers: Union[\n None, LogggerObjectOrName, List[LogggerObjectOrName]\n ] = None,\n third_party_level: LoggerLevel = \"WARNING\",\n future_third_parties: Union[None, str, List[str]] = None,\n specialty_loggers: Optional[Dict[LogggerObjectOrName, LoggerLevel]] = None,\n use_coloredlogs: bool = False,\n) -> None:\n \"\"\"Set the level of loggers of various precedence.\n\n The root logger and first-party logger(s) are set to the same level (`level`).\n\n Args:\n `level`\n the desired logging level (first-party), case-insensitive\n `first_party_loggers`\n a list (or a single instance) of `logging.Logger` or the loggers' names\n `third_party_level`\n the desired logging level for any other (currently) available loggers, case-insensitive\n `future_third_parties`\n additional third party logger(s) which have not yet been created (at call time)\n `specialty_loggers`\n additional loggers, each paired with a logging level, which are not\n considered first-party nor third-party loggers. **These have the highest precedence**\n `use_coloredlogs`\n if True, will import and use the `coloredlogs` package.\n This will set the logger format and use colored text.\n \"\"\"\n```\n\n#### `wipac_dev_tools.logging_tools.log_argparse_args()`\n_Available for Python 3.6+_\n```\ndef log_argparse_args(\n args: argparse.Namespace,\n logger: Union[None, str, logging.Logger] = None,\n level: LoggerLevel = \"WARNING\",\n) -> argparse.Namespace:\n \"\"\"Log the argparse args and their values at the given level.\n\n Return the args (Namespace) unchanged.\n\n Example:\n 2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING in_file: in_msg.pkl\n 2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING out_file: out_msg.pkl\n 2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING log: DEBUG\n 2022-05-13 22:37:21 fv-az136-643 my-logs[61] WARNING log_third_party: WARNING\n \"\"\"\n```\n\n\n### Environment Variable Tool(s)\n\n#### `wipac_dev_tools.from_environment()`\n_Available for Python 3.6+_\n```\ndef from_environment(keys: KeySpec) -> Dict[str, RetVal]:\n \"\"\"Obtain configuration values from the OS environment.\n\n Parsing Details:\n Types are inferred from the default values, and casted as such:\n `bool`: *(case-insensitive)*:\n - `True` => (\"y\", \"yes\", \"t\", \"true\", \"on\", or \"1\")\n - `False` => (\"n\", \"no\", \"f\", \"false\", \"off\", or \"0\")\n - `Error` => any other string\n `int`: normal cast (`int(str)`)\n `float`: normal cast (`float(str)`)\n `other`: no change (`str`)\n\n Arguments:\n keys - Specify the configuration values to obtain.\n\n This can be a string, specifying a single key, such as:\n\n config_dict = from_environment(\"LANGUAGE\")\n\n This can be a list of strings, specifying multiple keys,\n such as:\n\n config_dict = from_environment([\"HOME\", \"LANGUAGE\"])\n\n This can be a dictionary that provides some default values,\n and will accept overrides from the environment:\n\n default_config = {\n \"HOST\": \"localhost\",\n \"PORT\": 8080,\n \"REQUIRED_FROM_ENVIRONMENT\": None\n }\n config_dict = from_environment(default_config)\n\n Note in this case that if 'HOST' or 'PORT' were defined in the\n environment, those values would be returned in config_dict. If\n the values were not defined in the environment, the default values\n from default_config would be returned in config_dict.\n\n Also note, that if 'REQUIRED_FROM_ENVIRONMENT' is not defined,\n an OSError will be raised. The sentinel value of None indicates\n that the configuration parameter MUST be sourced from the\n environment.\n\n Returns:\n a dictionary mapping configuration keys to configuration values\n\n Raises:\n OSError - If a configuration value is requested and no default\n value is provided (via a dict), to indicate that the\n component's configuration is incomplete due to missing\n data from the OS.\n ValueError - If a type-indicated value is not a legal value\n \"\"\"\n```\n\n#### `wipac_dev_tools.from_environment_as_dataclass()`\n_Available for Python 3.7+_\n```\ndef from_environment_as_dataclass(\n dclass: Type[T],\n collection_sep: Optional[str] = None,\n dict_kv_joiner: str = \"=\",\n log_vars: Optional[logging_tools.LoggerLevel] = \"WARNING\",\n) -> T:\n \"\"\"Obtain configuration values from the OS environment formatted in a\n dataclass.\n\n Environment variables are matched to a dataclass field's name. The\n matching environment string is cast using the dataclass field's type\n (there are some special cases for built-in types, see below). Then,\n the values are used to create a dataclass instance. All normal\n dataclass init-behavior is expected, like required fields\n (positional arguments), optional fields with defaults, default\n factories, post-init processing, etc.\n\n If a field's type is a bool, `wipac_dev_tools.strtobool` is applied.\n\n If a field's type is a `list`, `dict`, `set`, `frozenset`, or\n an analogous type alias from the 'typing' module, then a conversion\n is made (see `collection_sep` and `dict_kv_joiner`). Sub-types\n are cast if using a typing-module type alias. The typing-module's\n alias types must resolve to `type` within 1 nesting (eg: List[bool]\n and Dict[int, float] are okay; List[Dict[int, float]] is not), or\n 2 if using 'Final' or 'Optional' (ex: Final[Dict[int, float]]).\n\n If a field's type is a class that accepts 1 argument, it is\n instantiated as such.\n\n Arguments:\n dclass - a (non-instantiated) dataclass, aka a type\n collection_sep - the delimiter to split collections on (\"1 2 5\")\n dict_kv_joiner - the delimiter that joins key-value pairs (\"a=1 b=2 c=1\")\n log_vars - what level to log the collected environment variables (set to `None` to not log)\n\n Returns:\n a dataclass instance mapping configuration keys to configuration values\n\n Example:\n env:\n FPATH=/home/example/path\n PORT=9999\n HOST=localhost\n MSGS_PER_CLIENTS=alpha=0 beta=55 delta=3\n USE_EVEN=22\n RETRIES=3\n\n python:\n @dataclasses.dataclass(frozen=True)\n class Config:\n FPATH: pathlib.Path\n PORT: int\n HOST: str\n MSGS_PER_CLIENTS: Dict[str, int]\n USE_EVEN: EvenState\n RETRIES: Optional[int] = None\n TIMEOUT: int = 30\n\n def __post_init__(self) -> None:\n if self.PORT <= 0:\n raise ValueError(\"'PORT' is non-positive\")\n\n class EvenState:\n def __init__(self, arg: str):\n self.is_even = not bool(int(arg) % 2) # 1%2 -> 1 -> T -> F\n def __repr__(self) -> str:\n return f\"EvenState(is_even={self.is_even})\"\n\n config = from_environment_as_dataclass(Config)\n print(config)\n\n stdout:\n Config(\n FPATH=PosixPath('/home/example/path'),\n PORT=9999,\n HOST='localhost',\n MSGS_PER_CLIENTS={'alpha': 0, 'beta': 55, 'delta': 3},\n USE_EVEN=EvenState(is_even=True),\n RETRIES=3,\n TIMEOUT=30)\n\n\n Raises:\n OSError - If a configuration value is requested and no default\n value is provided, to indicate that the component's\n configuration is incomplete due to missing data from\n the OS.\n ValueError - If an indicated value is not a legal value\n TypeError - If an argument or indicated value is not a legal type\n \"\"\"\n```\n\n#### `wipac_dev_tools.strtobool()`\n```\ndef strtobool(string: str) -> bool:\n \"\"\"Smart-cast a string to a bool using common-sense interpretations.\n\n Unlike the since deprecated `distutils.util.strtobool`, this\n returns an actual bool.\n\n True: 'y', 'yes', 't', 'true', 'on', '1'\n False: 'n', 'no', 'f', 'false', 'off', '0'\n\n Raises:\n ValueError: if the string does not match any of the about\n \"\"\"\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Common, basic, and reusable development tools",
"version": "1.9.1",
"project_urls": {
"Download": "https://pypi.org/project/wipac-dev-tools/",
"Homepage": "https://github.com/WIPACrepo/wipac-dev-tools",
"Source": "https://github.com/WIPACrepo/wipac-dev-tools",
"Tracker": "https://github.com/WIPACrepo/wipac-dev-tools/issues"
},
"split_keywords": [
"python",
"tools",
"utilities",
"wipac",
"icecube"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "df8ec3ba7c9b44125f1b3f0c2249170ecddedccc08db49f3ffaf6c264c08fbb6",
"md5": "fba6afceb8a600c98e0d34cb245900cd",
"sha256": "7e023a4f3d86a950c53c508b20767fa5585351ea02910eb7502e962cfeb84e55"
},
"downloads": -1,
"filename": "wipac_dev_tools-1.9.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "fba6afceb8a600c98e0d34cb245900cd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.13,>=3.8",
"size": 20538,
"upload_time": "2024-02-08T16:32:04",
"upload_time_iso_8601": "2024-02-08T16:32:04.638577Z",
"url": "https://files.pythonhosted.org/packages/df/8e/c3ba7c9b44125f1b3f0c2249170ecddedccc08db49f3ffaf6c264c08fbb6/wipac_dev_tools-1.9.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "cae4badbeca56f3fb7424ac4f308e04bafbda242dbfd0f7248df702ed7111c2f",
"md5": "1bb640231300ea3f4183f9fb51a6b324",
"sha256": "fa94e53c2284886824a98fdc4be7293b4eca3dc39ac734b52ebcd0ec5c78e2f3"
},
"downloads": -1,
"filename": "wipac-dev-tools-1.9.1.tar.gz",
"has_sig": false,
"md5_digest": "1bb640231300ea3f4183f9fb51a6b324",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.13,>=3.8",
"size": 19101,
"upload_time": "2024-02-08T16:32:06",
"upload_time_iso_8601": "2024-02-08T16:32:06.636066Z",
"url": "https://files.pythonhosted.org/packages/ca/e4/badbeca56f3fb7424ac4f308e04bafbda242dbfd0f7248df702ed7111c2f/wipac-dev-tools-1.9.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-02-08 16:32:06",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "WIPACrepo",
"github_project": "wipac-dev-tools",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "wipac-dev-tools"
}