Skip to content

Commit

Permalink
Removal of boolean type and some updates in the context of PR
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-jaquier authored and cigani committed Sep 20, 2021
1 parent a68bfbf commit 13d5265
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 77 deletions.
76 changes: 46 additions & 30 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ Task help text

You can specifiy help text to be shown alongside the task name in the list of available tasks (such as when executing poe with no arguments), by adding a help key like so:

.. code-block:: toml
.. code-block:: toml
[tool.poe.tasks]
style = {cmd = "black . --check --diff", help = "Check code style"}
Expand All @@ -265,7 +265,7 @@ Environment variables

You can specify arbitrary environment variables to be set for a task by providing the env key like so:

.. code-block:: toml
.. code-block:: toml
[tool.poe.tasks]
serve.script = "myapp:run"
Expand All @@ -275,20 +275,20 @@ Notice this example uses deep keys which can be more convenient but aren't as we

The above example can be modified to only set the `PORT` variable if it is not already set by replacing the last line with the following:

.. code-block:: toml
.. code-block:: toml
serve.env.PORT.default "9001"
You can also specify an env file (with bashlike syntax) to load per task like so:

.. code-block:: bash
.. code-block:: bash
# .env
STAGE=dev
PASSWORD='!@#$%^&*('
.. code-block:: toml
.. code-block:: toml
[tool.poe.tasks]
serve.script = "myapp:run"
Expand Down Expand Up @@ -356,39 +356,55 @@ is also possible as demonstrated in the following example:
[tool.poe.tasks]
build = { script = "project.util:build(dest, build_version=version)", args = ["dest", "version"]
For tasks that require specific types/defaults/help to be applied to arguments they can be constructed from subtables
For tasks that require specific types/defaults/help to be applied to arguments they can be constructed from sub-tables;
omission of variable type declaration will result in a string type.

.. code-block:: toml
[tool.poe.tasks.A]
script = "project.util:build(s_var, f_var, i_var, x_var), args=["s_var, f_var, i_var,x_var]
[tool.poe.tasks.A.args.s_var]
type = 'str'
help = "A string"
default = "Default String Value"
[tool.poe.tasks.A.args.f_var]
type = 'float'
[tool.poe.tasks.A.args.i_var]
type ='int'
default=100
[tool.poe.tasks.A.args.x_var] # Theres no need to define any specific values if not desired
Boolean flags can also be defined like above with omission being taken as False.
Any keyword argument omitted will be removed from the generated kwargs dict
.. code-block:: toml
[tool.poe.tasks.user]
script = "project.util:create_user(role, height, age, name, enabled), args=["role", "name", "age", "name", "enabled"]
[tool.poe.tasks.user.args.role]
type = 'str'
default = 'Client'
[tool.poe.tasks.user.args.height]
type = 'float'
[tool.poe.tasks.user.args.age]
type ='int'
default=-1
[tool.poe.tasks.A.args.name] # Theres no need to define any specific values if not desired
[tool.poe.tasks.user.args.enabled]
help = 'Enable or disable a user'
Flags can be passed as normal options. If your underlying script utilizes the flag in such a fashion:

.. code-block:: python
def create_user(role, height, age, name, enabled):
if enabled:
user = enabled
else:
user = disabled
It is important to keep in mind that the flag is not a boolean but a string so any value passed for enabled will be
evaluated by this script as True.

Example:

.. code-block:: bash
.. code-block:: bash
poe A --s_var='String' --x_var=1234
poe user --name='Jane Doe' --height=1.75
Result:

.. code-block:: python
.. code-block:: python
def A(**kwargs):
print(kwargs) # kwargs = { "s_var":"String", "i_var":100, "x_var":"1234" }
def A(**kwargs):
print(kwargs) # kwargs = { "name":"Jane Doe", "age":-1, "height":1.75, "role": "Client" }
Project-wide configuration options
==================================
Expand All @@ -413,13 +429,13 @@ As for the task level option, you can indicated that a variable should only be s
You can also specify an env file (with bashlike syntax) to load for all tasks like so:

.. code-block:: bash
.. code-block:: bash
# .env
STAGE=dev
PASSWORD='!@#$%^&*('
.. code-block:: toml
.. code-block:: toml
[tool.poe]
envfile = ".env"
Expand Down
21 changes: 5 additions & 16 deletions poethepoet/task/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@
"type": str,
}

arg_type_lookup: Dict[Any, Type] = {
"string": str,
"float": float,
"integer": int,
"boolean": bool,
}
# Needs to be Any to match what Argparse has defined
arg_type_lookup: Dict[Any, Type] = {"string": str, "float": float, "integer": int}


class PoeTaskArgs:
Expand Down Expand Up @@ -82,16 +78,10 @@ def get_help_content(
return [(arg["options"], arg.get("help", "")) for arg in args]

@classmethod
def _validate_types(
def _validate_type(
cls, params: ArgParams, arg_name: str, task_name: str
) -> Optional[str]:
try:
# Personally I prefer the EAFP style ( https://docs.python.org/3.5/glossary.html#term-eafp ) but this might not fit with the code base at large
arg_type = arg_type_lookup.get(params["type"])
except KeyError:
return None
if arg_type == None:

if "type" in params and params["type"] not in arg_type_lookup:
return (
f"{params['type']!r} is not a valid type for -> arg {arg_name!r} of task {task_name!r}."
f"Choose one of {sorted(str_type for str_type in arg_type_lookup.keys())}"
Expand Down Expand Up @@ -129,7 +119,7 @@ def validate_def(cls, task_name: str, args_def: ArgsDef) -> Optional[str]:
error = cls._validate_params(params, arg_name, task_name)
if error:
return error
error = cls._validate_types(params, arg_name, task_name)
error = cls._validate_type(params, arg_name, task_name)
if error:
return error
return None
Expand Down Expand Up @@ -177,7 +167,6 @@ def build_parser(self) -> argparse.ArgumentParser:
dest=arg["name"],
required=arg.get("required", False),
help=arg.get("help", ""),
# pylint: disable=W0123
type=arg_type_lookup.get(arg.get("type"), str),
)
return parser
Expand Down
15 changes: 4 additions & 11 deletions poethepoet/task/script.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from collections import ChainMap
import re
from typing import (
Any,
Expand Down Expand Up @@ -111,14 +110,8 @@ def resolve_param(param: str):
# test_script_task_omit_kwarg is an example of why this is necessary -- without removing the '' we have inconsistant behavior
# even if the arg isn't passed to poe it will be otherwise created here with an '' value
return {
k: v
for k, v in dict(
ChainMap(
*[
resolve_param(param.strip())
for param in call_params.strip().split(",")
]
)
).items()
if v is not None
key: value
for param in call_params.split(",")
for key, value in resolve_param(param.strip()).items()
if value is not None
}
32 changes: 17 additions & 15 deletions tests/fixtures/dummy_project/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,15 @@ cmd = "echo POE_ROOT:$POE_ROOT ${BEST_PASSWORD}, task_args:"
help = "It says what you say"
env = { BEST_PASSWORD = "Password1" }

[tool.poe.tasks.greet-rekeyed]
script = "dummy_package:args(greeting, user,optional=opt, upper=upper, fvar, ivar)"
[tool.poe.tasks.greet-rekeyed.args.greeting]
type = 'string'
[tool.poe.tasks.greet-rekeyed.args.opt]
[tool.poe.tasks.greet-rekeyed.args.user]
type = 'string'
[tool.poe.tasks.greet-rekeyed.args.upper]
type = 'boolean'
[tool.poe.tasks.greet-rekeyed.args.ivar]
type = 'integer'
[tool.poe.tasks.greet-rekeyed.args.fvar]
type = 'float'
help ='A float'



[tool.poe.tasks]
show_env = "env"
greet = { script = "dummy_package:main" }
greet-shouty = { script = "dummy_package:main(upper=True)" }
greet-keyed = { script ="dummy_package:args(greeting, user, optional, upper, default=default_value)", args = ["greeting", "user", "optional", "upper"]}

greet-automatic = { script="dummy_package:args"}

count = { shell = "echo 1 && echo 2 && echo $(python -c 'print(1 + 2)')" }
also_echo = { ref = "echo" }
Expand Down Expand Up @@ -75,6 +62,21 @@ travel = [
{ script = "dummy_package:print_var('DEST')" }
]

[tool.poe.tasks.greet-rekeyed]
script = "dummy_package:args(greeting, user,optional=opt, upper=upper, fvar, ivar)"
[tool.poe.tasks.greet-rekeyed.args.greeting]
type = 'string'
[tool.poe.tasks.greet-rekeyed.args.opt]
[tool.poe.tasks.greet-rekeyed.args.user]
type = 'string'
[tool.poe.tasks.greet-rekeyed.args.upper]
type = 'string' # For the time being any Flags are represented as Strings
[tool.poe.tasks.greet-rekeyed.args.ivar]
type = 'integer'
[tool.poe.tasks.greet-rekeyed.args.fvar]
type = 'float'
help ='A float'

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
Empty file added tests/test_named_arguments.py
Empty file.
4 changes: 2 additions & 2 deletions tests/test_shell_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ def test_describe_tasks(run_poe_main):
# expect an ordered listing of non-hidden tasks defined in the dummy_project
assert (
result.stdout
== "echo greet-rekeyed show_env greet greet-shouty greet-keyed count also_echo sing part1 composite_task also_composite_task greet-multiple travel\n"
== "echo show_env greet greet-shouty greet-keyed greet-automatic count also_echo sing part1 composite_task also_composite_task greet-multiple travel greet-rekeyed\n"
)
assert result.stderr == ""

Expand All @@ -13,7 +13,7 @@ def test_list_tasks(run_poe_main):
# expect an ordered listing of non-hidden tasks defined in the dummy_project
assert (
result.stdout
== "echo greet-rekeyed show_env greet greet-shouty greet-keyed count also_echo sing part1 composite_task also_composite_task greet-multiple travel\n"
== "echo show_env greet greet-shouty greet-keyed greet-automatic count also_echo sing part1 composite_task also_composite_task greet-multiple travel greet-rekeyed\n"
)
assert result.stderr == ""

Expand Down
13 changes: 10 additions & 3 deletions tests/test_task_running.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ def test_script_task(run_poe_subproc, dummy_project_path, esc_prefix):
assert result.stderr == ""


def test_automatic_kwargs(run_poe_subproc):
result = run_poe_subproc("greet-automatic")
assert result.capture == "Poe => greet-automatic\n"
assert result.stdout == "greetings user default Optional\n"
assert result.stderr == ""


def test_script_task_with_hard_coded_args(
run_poe_subproc, dummy_project_path, esc_prefix
):
Expand Down Expand Up @@ -124,11 +131,11 @@ def test_script_task_renamed_upper(run_poe_subproc, dummy_project_path):
"--greeting=hello",
"--user=nat",
f"--opt=welcome to {dummy_project_path}",
"--upper=True",
"--upper=Any-Value",
)
assert (
result.capture
== f"Poe => greet-rekeyed --greeting=hello --user=nat --opt=welcome to {dummy_project_path} --upper=True\n"
== f"Poe => greet-rekeyed --greeting=hello --user=nat --opt=welcome to {dummy_project_path} --upper=Any-Value\n"
)
assert result.stdout == f"HELLO NAT DEFAULT welcome to {dummy_project_path}\n"
assert result.stderr == ""
Expand All @@ -138,7 +145,7 @@ def test_script_task_bad_type(run_poe_subproc, poe_project_path):
project_path = poe_project_path.joinpath("tests", "fixtures", "malformed_project")
result = run_poe_subproc("bad-type", "--greeting=hello", cwd=project_path)
assert (
"Error: 'datetime' is not a valid type for -> arg 'greeting' of task 'bad-type'.Choose one of ['boolean', 'float', 'integer', 'string']"
"Error: 'datetime' is not a valid type for -> arg 'greeting' of task 'bad-type'.Choose one of ['float', 'integer', 'string']"
in result.capture
)
assert result.stdout == ""
Expand Down

0 comments on commit 13d5265

Please sign in to comment.