Skip to content

Commit

Permalink
Merge branch '1.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
goFrendiAsgard committed Dec 21, 2024
2 parents 78f4d8f + 5095a46 commit 3fc7edb
Show file tree
Hide file tree
Showing 33 changed files with 1,789 additions and 1,522 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/_zrb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
Run-command:
runs-on: ubuntu-latest
container:
image: stalchmst/zrb:1.0.0a17
image: stalchmst/zrb:1.0.0a19
steps:
- name: Check out repository code
uses: actions/checkout@v3
Expand Down
38 changes: 38 additions & 0 deletions playground/zrb_init.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import asyncio
from decimal import Decimal

from zrb import (
BaseTrigger,
Callback,
CmdTask,
Context,
FloatInput,
Group,
IntInput,
Scheduler,
Expand All @@ -15,6 +17,42 @@
make_task,
)


@make_task(
name="ppn",
input=[
FloatInput(
name="price",
prompt="Original price",
description="Original price",
default_str="100",
),
FloatInput(
name="payed",
prompt="Price payed",
description="Price payed",
default_str=lambda ctx: float(Decimal(ctx.input.price) * Decimal("1.12")),
),
],
group=cli,
)
def ppn(ctx: Context):
"""
This task calculates the discrepancy between the price and the payed amount.
Indonesian's PPN tax sucks BTW
"""
discrepancy = ctx.input.payed - (ctx.input.price * 1.12)
ctx.print(f"Price: {ctx.input.price}")
ctx.print(f"Payed: {ctx.input.payed}")
ctx.print(f"Discrepancy: {discrepancy}")
if discrepancy > 0:
return f"Government is happy, you pay {discrepancy} more"
elif discrepancy < 0:
return f"Government is angry, you owe them {-discrepancy}"
else:
return "Government is happy, You are contributing to the country"


math = cli.add_group(Group("math", description="➕ Math tools"))
math.add_task(
Task(
Expand Down
1,980 changes: 1,014 additions & 966 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "zrb"
version = "1.0.0a17"
version = "1.0.0a19"
description = "Your Automation Powerhouse"
authors = ["Go Frendi Gunawan <gofrendiasgard@gmail.com>"]
license = "AGPL-3.0-or-later"
Expand Down
2 changes: 2 additions & 0 deletions src/zrb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from zrb.input.any_input import AnyInput
from zrb.input.base_input import BaseInput
from zrb.input.bool_input import BoolInput
from zrb.input.float_input import FloatInput
from zrb.input.int_input import IntInput
from zrb.input.option_input import OptionInput
from zrb.input.password_input import PasswordInput
Expand Down Expand Up @@ -73,6 +74,7 @@
assert CmdTask
assert HttpCheck
assert TcpCheck
assert FloatInput
assert IntInput
assert OptionInput
assert PasswordInput
Expand Down
8 changes: 3 additions & 5 deletions src/zrb/builtin/project/add/fastapp/fastapp_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
from zrb.util.string.conversion import to_snake_case
from zrb.util.string.name import get_random_name

_DIR = os.path.dirname(__file__)


@make_task(
name="validate-create-fastapp",
Expand All @@ -42,14 +40,14 @@ async def validate_create_fastapp(ctx: AnyContext):
app_name_input,
],
upstream=validate_create_fastapp,
source_path=os.path.join(_DIR, "fastapp_template"),
source_path=os.path.join(os.path.dirname(__file__), "fastapp_template"),
render_source_path=False,
destination_path="{ctx.input.project_dir}",
transform_path={
"my_app_name": "{to_snake_case(ctx.input.app)}",
},
transform_content=[
# Common transformation
# Common transformation (project_dir/app_dir/**/*)
ContentTransformer(
match=is_in_project_app_dir,
transform={
Expand All @@ -60,7 +58,7 @@ async def validate_create_fastapp(ctx: AnyContext):
"my-secure-password": lambda _: get_random_name(),
},
),
# Register fastapp's tasks to project's zrb_init
# Register fastapp's tasks to project's zrb_init (project_dir/zrb_init.py)
ContentTransformer(
match=is_project_zrb_init_file,
transform=update_project_zrb_init_file,
Expand Down
49 changes: 35 additions & 14 deletions src/zrb/builtin/todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
from typing import Any

from zrb.builtin.group import todo_group
from zrb.config import TODO_DIR, TODO_VISUAL_FILTER
from zrb.config import TODO_DIR, TODO_RETENTION, TODO_VISUAL_FILTER
from zrb.context.any_context import AnyContext
from zrb.input.str_input import StrInput
from zrb.input.text_input import TextInput
from zrb.task.make_task import make_task
from zrb.util.file import read_file, write_file
from zrb.util.todo import (
TodoTaskModel,
add_durations,
add_duration,
cascade_todo_task,
get_visual_todo_card,
get_visual_todo_list,
line_to_todo_task,
load_todo_list,
parse_duration,
save_todo_list,
select_todo_task,
todo_task_to_line,
Expand Down Expand Up @@ -165,11 +166,17 @@ def archive_todo(ctx: AnyContext):
todo_list: list[TodoTaskModel] = []
if os.path.isfile(todo_file_path):
todo_list = load_todo_list(todo_file_path)
working_todo_list = [
todo_task for todo_task in todo_list if not todo_task.completed
]
retention_duration = datetime.timedelta(seconds=parse_duration(TODO_RETENTION))
threshold_date = datetime.date.today() - retention_duration
new_archived_todo_list = [
todo_task for todo_task in todo_list if todo_task.completed
todo_task
for todo_task in todo_list
if todo_task.completed
and todo_task.completion_date is not None
and todo_task.completion_date < threshold_date
]
working_todo_list = [
todo_task for todo_task in todo_list if todo_task not in new_archived_todo_list
]
if len(new_archived_todo_list) == 0:
ctx.print("No completed task to archive")
Expand Down Expand Up @@ -204,10 +211,10 @@ def archive_todo(ctx: AnyContext):
default_str="30m",
),
StrInput(
name="start",
prompt="Working start time (%Y-%m-%d %H:%M:%S)",
description="Working start time",
default_str=lambda _: _get_default_start(),
name="stop",
prompt="Working stop time (%Y-%m-%d %H:%M:%S)",
description="Working stop time",
default_str=lambda _: _get_default_stop_work_time_str(),
),
],
description="🕒 Log work todo",
Expand All @@ -226,8 +233,10 @@ def log_todo(ctx: AnyContext):
return get_visual_todo_list(todo_list, TODO_VISUAL_FILTER)
# Update todo task
todo_task = cascade_todo_task(todo_task)
current_duration = todo_task.keyval.get("duration", "0")
todo_task.keyval["duration"] = add_durations(current_duration, ctx.input.duration)
current_duration_str = todo_task.keyval.get("duration", "0")
todo_task.keyval["duration"] = add_duration(
current_duration_str, ctx.input.duration
)
# Save todo list
save_todo_list(todo_file_path, todo_list)
# Add log work
Expand All @@ -241,8 +250,13 @@ def log_todo(ctx: AnyContext):
else:
log_work_json = "[]"
log_work: list[dict[str, Any]] = json.loads(log_work_json)
start_work_time_str = _get_start_work_time_str(ctx.input.stop, ctx.input.duration)
log_work.append(
{"log": ctx.input.log, "duration": ctx.input.duration, "start": ctx.input.start}
{
"log": ctx.input.log,
"duration": ctx.input.duration,
"start": start_work_time_str,
}
)
# save todo with log work
write_file(log_work_file_path, json.dumps(log_work, indent=2))
Expand All @@ -261,7 +275,14 @@ def log_todo(ctx: AnyContext):
)


def _get_default_start() -> str:
def _get_start_work_time_str(stop_work_time_str: str, work_duration_str: str) -> str:
work_duration = parse_duration(work_duration_str)
stop_work_time = datetime.datetime.strptime(stop_work_time_str, "%Y-%m-%d %H:%M:%S")
start_work_time = stop_work_time - datetime.timedelta(seconds=work_duration)
return start_work_time.strftime("%Y-%m-%d %H:%M:%S")


def _get_default_stop_work_time_str() -> str:
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")


Expand Down
1 change: 1 addition & 0 deletions src/zrb/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def _get_log_level(level: str) -> int:
)
TODO_DIR = os.getenv("ZRB_TODO_DIR", os.path.expanduser(os.path.join("~", "todo")))
TODO_VISUAL_FILTER = os.getenv("ZRB_TODO_FILTER", "")
TODO_RETENTION = os.getenv("ZRB_TODO_RETENTION", "2w")
VERSION = metadata.version("zrb")
WEB_HTTP_PORT = int(os.getenv("ZRB_WEB_HTTP_PORT", "21213"))
LLM_MODEL = os.getenv("ZRB_LLM_MODEL", "ollama_chat/llama3.1")
Expand Down
4 changes: 4 additions & 0 deletions src/zrb/input/any_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ def update_shared_context(
@abstractmethod
def prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:
pass

@abstractmethod
def get_default_str(self, shared_ctx: AnySharedContext) -> str:
pass
8 changes: 4 additions & 4 deletions src/zrb/input/base_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ def prompt_message(self) -> str:
def to_html(self, ctx: AnySharedContext) -> str:
name = self.name
description = self.description
default = self._get_default_str(ctx)
default = self.get_default_str(ctx)
return f'<input name="{name}" placeholder="{description}" value="{default}" />'

def update_shared_context(
self, shared_ctx: AnySharedContext, str_value: str | None = None
):
if str_value is None:
str_value = self._get_default_str(shared_ctx)
str_value = self.get_default_str(shared_ctx)
value = self._parse_str_value(str_value)
if self.name in shared_ctx.input:
raise ValueError(f"Input already defined in the context: {self.name}")
Expand All @@ -75,7 +75,7 @@ def prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:

def _prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:
prompt_message = self.prompt_message
default_value = self._get_default_str(shared_ctx)
default_value = self.get_default_str(shared_ctx)
if default_value != "":
prompt_message = f"{prompt_message} [{default_value}]"
print(f"{prompt_message}: ", end="")
Expand All @@ -84,7 +84,7 @@ def _prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:
value = default_value
return value

def _get_default_str(self, shared_ctx: AnySharedContext) -> str:
def get_default_str(self, shared_ctx: AnySharedContext) -> str:
return get_str_attr(
shared_ctx, self._default_str, auto_render=self._auto_render
)
2 changes: 1 addition & 1 deletion src/zrb/input/bool_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(
def to_html(self, ctx: AnySharedContext) -> str:
name = self.name
description = self.description
default = to_boolean(self._get_default_str(ctx))
default = to_boolean(self.get_default_str(ctx))
selected_true = "selected" if default else ""
selected_false = "selected" if not default else ""
return "\n".join(
Expand Down
4 changes: 2 additions & 2 deletions src/zrb/input/float_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def __init__(
def to_html(self, ctx: AnySharedContext) -> str:
name = self.name
description = self.description
default = self._get_default_str(ctx)
return f'<input type="number" name="{name}" placeholder="{description}" value="{default}" />' # noqa
default = self.get_default_str(ctx)
return f'<input type="number" name="{name}" placeholder="{description}" value="{default}" step="any" />' # noqa

def _parse_str_value(self, str_value: str) -> float:
return float(str_value)
2 changes: 1 addition & 1 deletion src/zrb/input/int_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def __init__(
def to_html(self, ctx: AnySharedContext) -> str:
name = self.name
description = self.description
default = self._get_default_str(ctx)
default = self.get_default_str(ctx)
return f'<input type="number" step="1" name="{name}" placeholder="{description}" value="{default}" />' # noqa

def _parse_str_value(self, str_value: str) -> int:
Expand Down
4 changes: 2 additions & 2 deletions src/zrb/input/option_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def __init__(
def to_html(self, ctx: AnySharedContext) -> str:
name = self.name
description = self.description
default = self._get_default_str(ctx)
default = self.get_default_str(ctx)
html = [f'<select name="{name}" placeholder="{description}">']
for value in get_str_list_attr(ctx, self._options, self._auto_render):
selected = "selected" if value == default else ""
Expand All @@ -38,7 +38,7 @@ def to_html(self, ctx: AnySharedContext) -> str:

def _prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:
prompt_message = self.prompt_message
default_value = self._get_default_str(shared_ctx)
default_value = self.get_default_str(shared_ctx)
options = get_str_list_attr(shared_ctx, self._options, self._auto_render)
option_str = ", ".join(options)
if default_value != "":
Expand Down
4 changes: 2 additions & 2 deletions src/zrb/input/password_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ def __init__(
def to_html(self, ctx: AnySharedContext) -> str:
name = self.name
description = self.description
default = self._get_default_str(ctx)
default = self.get_default_str(ctx)
return f'<input type="password" name="{name}" placeholder="{description}" value="{default}" />' # noqa

def _prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:
prompt_message = self.prompt_message
default_value = self._get_default_str(shared_ctx)
default_value = self.get_default_str(shared_ctx)
value = getpass.getpass(f"{prompt_message}: ")
if value.strip() == "":
value = default_value
Expand Down
4 changes: 2 additions & 2 deletions src/zrb/input/text_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def comment_end(self) -> str:
def to_html(self, ctx: AnySharedContext) -> str:
name = self.name
description = self.description
default = self._get_default_str(ctx)
default = self.get_default_str(ctx)
return "\n".join(
[
f'<textarea name="{name}" placeholder="{description}">',
Expand All @@ -71,7 +71,7 @@ def _prompt_cli_str(self, shared_ctx: AnySharedContext) -> str:
f"{self.comment_start}{super().prompt_message}{self.comment_end}"
)
prompt_message_eol = f"{prompt_message}\n"
default_value = self._get_default_str(shared_ctx)
default_value = self.get_default_str(shared_ctx)
with tempfile.NamedTemporaryFile(
delete=False, suffix=self._extension
) as temp_file:
Expand Down
Loading

0 comments on commit 3fc7edb

Please sign in to comment.