# Water
[![codecov](https://codecov.io/gh/davidventura/water/branch/master/graph/badge.svg?token=m5obuvwZ0I)](https://codecov.io/gh/davidventura/water)
Like [fire](https://github.com/google/python-fire)
This python library parses classes so that they can be executed as commands.
In contrast with fire, there is no "automatic" type casting -- the type casting is 100% based on type hints.
## Type casting
When calling `execute_command` the values passed in the command get casted to the annotated types on the function
signature.
Supported types:
* int, float
* bool: the strings `['true', '1', 't', 'y']` are considered true.
* lists, tuples: input is split by comma (`,`) and each element is casted independently.
* enum
* Union[]: gets casted to all options in order, first success is returned.
* `Optional[type]` is `Union[type, NoneType]`
* `water.Flag`: flag, only denotes the switch was present.
* `water.Repeated[T]`: Effectively the same as `List[T]` but allows flags to be repeated and values will be concatenated
## Utilities
* `exclusive_flags` forbids certain flag combinations to be used at the same time.
* If `--a` and `--b` are exclusive, executing `command --a --b` causes an error.
* `required_together` requires certain flag combinations to be used at the same time.
* If `--a` and `--b` are required together, executing `command --a` or `command --b` causes an error.
# Examples
## Type casting
```python
class Math1:
def add_list(self, items: Optional[List[int]] = None):
if not items:
return 0
return sum(items)
def add_numbers(self, number: Repeated[int]):
return sum(number)
# `items` casted to a list of `int`
res = execute_command(Math1, 'add_list --items 1,2,3')
assert res == 6
# `items` casted to a list of `int`, even though there is only one entry
res = execute_command(Math1, 'add_list --items 1')
assert res == 1
# `number` casted to a list of `int`, even though there is only one entry
res = execute_command(Math1, 'add_numbers --number 1')
assert res == 1
# `number` casted to a list of `int`, even though there is only one entry
res = execute_command(Math1, 'add_numbers --number 1 --number 2')
assert res == 3
```
## Nested commands
```python
class NestedObj:
class Inside1:
def fn1(self, number: int):
return number
res = execute_command(NestedObj, 'Inside1 fn1 --number 1')
assert res == 1
```
# Testing
Python3.9, 3.11:
```
docker build -f dockerfiles/3.9-Dockerfile .
docker build -f dockerfiles/3.11-Dockerfile .
```
Development
```
poetry run pytest
```
# Releasing
```
poetry publish --build --username $PYPI_USERNAME --password $PYPI_PASSWORD
```
Raw data
{
"_id": null,
"home_page": "https://github.com/DavidVentura/water",
"name": "water-cli",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7,<4.0",
"maintainer_email": "",
"keywords": "",
"author": "david",
"author_email": "davidventura27@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/2e/98/8d7abaf437831d651098d438d7eb85b6ac85a6c2ba367367c901e2885a07/water_cli-0.1.15.tar.gz",
"platform": null,
"description": "# Water\n\n[![codecov](https://codecov.io/gh/davidventura/water/branch/master/graph/badge.svg?token=m5obuvwZ0I)](https://codecov.io/gh/davidventura/water)\n\nLike [fire](https://github.com/google/python-fire)\n\nThis python library parses classes so that they can be executed as commands. \nIn contrast with fire, there is no \"automatic\" type casting -- the type casting is 100% based on type hints.\n\n## Type casting\n\nWhen calling `execute_command` the values passed in the command get casted to the annotated types on the function\nsignature.\n\nSupported types:\n\n* int, float\n* bool: the strings `['true', '1', 't', 'y']` are considered true.\n* lists, tuples: input is split by comma (`,`) and each element is casted independently.\n* enum\n* Union[]: gets casted to all options in order, first success is returned.\n * `Optional[type]` is `Union[type, NoneType]`\n* `water.Flag`: flag, only denotes the switch was present.\n* `water.Repeated[T]`: Effectively the same as `List[T]` but allows flags to be repeated and values will be concatenated\n\n## Utilities\n\n* `exclusive_flags` forbids certain flag combinations to be used at the same time.\n * If `--a` and `--b` are exclusive, executing `command --a --b` causes an error.\n* `required_together` requires certain flag combinations to be used at the same time.\n * If `--a` and `--b` are required together, executing `command --a` or `command --b` causes an error.\n\n# Examples\n\n## Type casting\n\n```python\nclass Math1:\n\n def add_list(self, items: Optional[List[int]] = None):\n if not items:\n return 0\n return sum(items)\n\n def add_numbers(self, number: Repeated[int]):\n return sum(number)\n\n# `items` casted to a list of `int`\nres = execute_command(Math1, 'add_list --items 1,2,3')\nassert res == 6\n\n# `items` casted to a list of `int`, even though there is only one entry\nres = execute_command(Math1, 'add_list --items 1')\nassert res == 1\n\n# `number` casted to a list of `int`, even though there is only one entry\nres = execute_command(Math1, 'add_numbers --number 1')\nassert res == 1\n\n# `number` casted to a list of `int`, even though there is only one entry\nres = execute_command(Math1, 'add_numbers --number 1 --number 2')\nassert res == 3\n```\n\n## Nested commands\n\n```python\nclass NestedObj:\n class Inside1:\n def fn1(self, number: int):\n return number\n\nres = execute_command(NestedObj, 'Inside1 fn1 --number 1')\nassert res == 1\n```\n\n\n# Testing\n\nPython3.9, 3.11:\n```\ndocker build -f dockerfiles/3.9-Dockerfile .\ndocker build -f dockerfiles/3.11-Dockerfile .\n```\n\nDevelopment\n```\npoetry run pytest\n```\n\n# Releasing\n\n```\npoetry publish --build --username $PYPI_USERNAME --password $PYPI_PASSWORD\n```\n",
"bugtrack_url": null,
"license": "",
"summary": "",
"version": "0.1.15",
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "6d584b5dc8bc4979d462013b6b51b7598f1ffb109a2c72518aba69be4d0b569f",
"md5": "c48510851b652dc025c58b8246add189",
"sha256": "15214a1b916f15b6fdc6e93b6343e927044370bc622c8d14fd2f3fa709721ea3"
},
"downloads": -1,
"filename": "water_cli-0.1.15-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c48510851b652dc025c58b8246add189",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7,<4.0",
"size": 6620,
"upload_time": "2023-01-15T20:59:34",
"upload_time_iso_8601": "2023-01-15T20:59:34.839654Z",
"url": "https://files.pythonhosted.org/packages/6d/58/4b5dc8bc4979d462013b6b51b7598f1ffb109a2c72518aba69be4d0b569f/water_cli-0.1.15-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2e988d7abaf437831d651098d438d7eb85b6ac85a6c2ba367367c901e2885a07",
"md5": "f1e5800618b30477c10d3a00bbdd24dd",
"sha256": "282cefdf72d4a9370ba9a52d657dfc145231b5228cc949b4ac3a81d89a866025"
},
"downloads": -1,
"filename": "water_cli-0.1.15.tar.gz",
"has_sig": false,
"md5_digest": "f1e5800618b30477c10d3a00bbdd24dd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7,<4.0",
"size": 6367,
"upload_time": "2023-01-15T20:59:36",
"upload_time_iso_8601": "2023-01-15T20:59:36.687471Z",
"url": "https://files.pythonhosted.org/packages/2e/98/8d7abaf437831d651098d438d7eb85b6ac85a6c2ba367367c901e2885a07/water_cli-0.1.15.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-01-15 20:59:36",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "DavidVentura",
"github_project": "water",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "water-cli"
}