Skip to content

Release: Updates coming in v0.5.1 #362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a291b1a
chore: package version update
0hsn Feb 20, 2025
1676a7f
feat: test code for in template datatype conversion
0hsn Feb 21, 2025
c8cab08
refactor: remove cast_actual_to feature
0hsn Feb 22, 2025
eecb2e8
refactor: update tests to remove cast_actual_to
0hsn Feb 22, 2025
5406db0
Merge pull request #363 from 0hsn/feat/casting-with-jinja
0hsn Feb 22, 2025
2c75dc6
refactor: update tests
0hsn Feb 22, 2025
71f0b35
feat: new jinja fromjson filter added
0hsn Feb 25, 2025
11c65b2
Merge pull request #364 from 0hsn/feat/json-to-dict
0hsn Feb 25, 2025
91d4fbe
chore: setuptool version update
0hsn Mar 2, 2025
7552ee6
feat: add env builder to JinjaTemplate
0hsn Mar 5, 2025
4206f89
feat: add render feature to JinjaTemplate
0hsn Mar 5, 2025
1bc5bd8
refactor: improve template compile feature
0hsn Mar 5, 2025
fcfc377
feat: recursively resolve composite variables
0hsn Mar 5, 2025
6f09592
chore: pytest version update
0hsn Mar 5, 2025
7a17890
refactor: check if "exceptions" were passed before processing
0hsn Mar 6, 2025
5dd849f
Merge pull request #368 from 0hsn/feat/variabels-module-improved
0hsn Mar 6, 2025
738c0bf
feat: add feature for local context variable handling
0hsn Mar 6, 2025
f647a29
refactor: task variable features
0hsn Mar 6, 2025
94ad7c5
refactor: remove debug stmts
0hsn Mar 6, 2025
934dc22
fix: expectation in wf tests
0hsn Mar 6, 2025
bfb4c8d
Merge pull request #370 from 0hsn/refactor/workflow-task-variabels
0hsn Mar 6, 2025
9bdf346
refactor: add argument.data processing capability
0hsn Mar 9, 2025
13b6f13
refactor: general refactor on formatting
0hsn Mar 9, 2025
dfa3a89
Merge pull request #371 from 0hsn/fix/344-AttributeError
0hsn Mar 9, 2025
619eed7
feat: Improve version information
0hsn Mar 11, 2025
85cef26
chore: package version update
0hsn Mar 11, 2025
2596ff9
Merge pull request #373 from 0hsn/feat/setup-semantic-release
0hsn Mar 14, 2025
b47a0f1
refactor: fix formatting with ruff
0hsn Mar 15, 2025
d80e030
refactor: update ruff config
0hsn Mar 15, 2025
ad10c24
chore: install pre-commit
0hsn Mar 15, 2025
d3102ba
feat: add a pre-commit config
0hsn Mar 15, 2025
6412a5f
refactor: remove document formatting and incr line-len
0hsn Mar 16, 2025
7843bab
refactor: code formatting refactor by ruff
0hsn Mar 16, 2025
801badb
Merge pull request #374 from 0hsn/feat/setup-pre-commit
0hsn Mar 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.11.0
hooks:
# Run the linter.
- id: ruff
args: [ --fix ]
files: ^chk/.*\.py$
# Run the formatter.
- id: ruff-format
files: ^chk/.*\.py$
4 changes: 1 addition & 3 deletions chk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
"""
chk command-line app
"""
"""chk command-line app"""
28 changes: 9 additions & 19 deletions chk/console/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@

# root command
@click.group()
@click.option(
"--debug/--no-debug", is_flag=True, default=True, help="Enable debug logging"
)
@click.version_option()
@click.option("--debug/--no-debug", is_flag=True, default=True, help="Enable debug logging")
@click.pass_context
def chk(ctx: click.Context, debug: bool) -> None:
"""\b
Expand All @@ -35,10 +34,11 @@ def chk(ctx: click.Context, debug: bool) -> None:
░░█████████ █████ █████ █████ ░░████ ░░████░████ ░░████████ █████ ░░██████
░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░ ░░░░ ░░░░ ░░░░░░░░ ░░░░░ ░░░░░░


\b
Low-code API quality testing, and automation toolbox.
Version 0.5.0
"""

ctx.ensure_object(dict)
ctx.obj["debug"] = debug

Expand All @@ -48,9 +48,7 @@ def chk(ctx: click.Context, debug: bool) -> None:
# run fetch sub-command
@chk.command()
@click.argument("file", type=click.Path(exists=True))
@click.option(
"-nf", "--no-format", is_flag=True, help="No formatting to show the output"
)
@click.option("-nf", "--no-format", is_flag=True, help="No formatting to show the output")
@click.option("-V", "--variables", type=str, help="Pass variable(s) as JSON object")
@click.pass_context
def fetch(cctx: click.Context, file: str, no_format: bool, variables: str) -> None:
Expand Down Expand Up @@ -83,9 +81,7 @@ def fetch(cctx: click.Context, file: str, no_format: bool, variables: str) -> No
# run validate sub-command
@chk.command()
@click.argument("file", type=click.Path(exists=True))
@click.option(
"-nf", "--no-format", is_flag=True, help="No formatting to show the output"
)
@click.option("-nf", "--no-format", is_flag=True, help="No formatting to show the output")
@click.option("-V", "--variables", type=str, help="Pass variable(s) as JSON object")
@click.option("-D", "--data", type=str, help="Pass data as JSON")
@click.option("-Di", "--data-in", is_flag=True, help="Pass data as JSON [from pipe]")
Expand All @@ -109,13 +105,9 @@ def validate(

with with_catch_log():
_data = (
load_variables_as_dict(
get_stdin(), except_msg="-Di, --data-in: Pass data as JSON [from pipe]"
)
load_variables_as_dict(get_stdin(), except_msg="-Di, --data-in: Pass data as JSON [from pipe]")
if data_in
else load_variables_as_dict(
data, except_msg="-D, --data: Pass data as JSON"
)
else load_variables_as_dict(data, except_msg="-D, --data: Pass data as JSON")
)

execution_ctx = ExecuteContext(
Expand All @@ -139,9 +131,7 @@ def validate(
# run validate sub-command
@chk.command()
@click.argument("file", type=click.Path(exists=True))
@click.option(
"-nf", "--no-format", is_flag=True, help="No formatting to show the output"
)
@click.option("-nf", "--no-format", is_flag=True, help="No formatting to show the output")
@click.option("-V", "--variables", type=str, help="Pass variable(s) as JSON object")
@click.pass_context
def workflow(cctx: click.Context, file: str, no_format: bool, variables: str) -> None:
Expand Down
12 changes: 3 additions & 9 deletions chk/infrastructure/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ class VersionedDocumentSupport:
"""DocumentVersionSupport"""

@staticmethod
def validate_with_schema(
schema: dict, doc: VersionedDocument | VersionedDocumentV2
) -> bool:
def validate_with_schema(schema: dict, doc: VersionedDocument | VersionedDocumentV2) -> bool:
"""Validate a document with given schema

Args:
Expand All @@ -54,12 +52,8 @@ def validate_with_schema(

try:
if not validator.validate(file_ctx.document, schema):
raise RuntimeError(
f"File exception: Validation failed: {str(validator.errors)}"
)
raise RuntimeError(f"File exception: Validation failed: {str(validator.errors)}")
except cerberus.validator.DocumentError as doc_err:
raise RuntimeError(
f"Document exception: `version` string not found: {str(doc_err)}"
) from doc_err
raise RuntimeError(f"Document exception: `version` string not found: {str(doc_err)}") from doc_err

return True
12 changes: 3 additions & 9 deletions chk/infrastructure/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ def data_set(data: dict | list, keymap: str, value: Any) -> Any:

if isinstance(data, dict):
if current_item.isnumeric():
raise IndexError(
f"Trying to set numeric key `{current_item}` on dict `{data}`"
)
raise IndexError(f"Trying to set numeric key `{current_item}` on dict `{data}`")

if len(keymap_list) == 0:
data[current_item] = value
Expand All @@ -42,9 +40,7 @@ def data_set(data: dict | list, keymap: str, value: Any) -> Any:

if isinstance(data, list):
if not current_item.isnumeric():
raise IndexError(
f"Trying to set non-numeric index `{current_item}` on list `{data}`"
)
raise IndexError(f"Trying to set non-numeric index `{current_item}` on list `{data}`")
current_item_i = int(current_item)

if len(data) < current_item_i:
Expand Down Expand Up @@ -170,9 +166,7 @@ def try_dict(to_dict: Any, say_exception: bool = False) -> dict | Any:
return to_dict


def formatter(
message: object, cb: Callable = str, dump: bool = True, is_err: bool = False
) -> str:
def formatter(message: object, cb: Callable = str, dump: bool = True, is_err: bool = False) -> str:
"""Format message with given callback

Args:
Expand Down
42 changes: 27 additions & 15 deletions chk/infrastructure/symbol_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ def replace_value(doc: dict | list, var_s: dict) -> dict | list:
:param var_s:
:return:
"""
env = JinjaTemplate.build_env()

for key, val in list(doc.items() if isinstance(doc, dict) else enumerate(doc)):
if isinstance(val, str):
str_tpl = JinjaTemplate.make(val)
doc[key] = str_tpl.render(var_s)
doc[key] = JinjaTemplate.render(env, val, var_s)
elif isinstance(val, (dict, list)):
doc[key] = replace_value(doc[key], var_s)
return doc
Expand Down Expand Up @@ -135,6 +135,24 @@ def handle(
if variables:
cls.handle_composite(variable_doc, variables)

@classmethod
def handle_variable_doc(
cls,
variables: Variables,
variable_doc: dict,
) -> None:
"""Handles variable handling

Args:
variable_doc: VariableDocument to add values to
variables: VersionedDocument of document data
"""

cls.handle_absolute(variables, variable_doc)

if variables:
cls.handle_composite(variables, variable_doc)

@classmethod
def handle_absolute(cls, variable_doc: Variables, document: dict) -> None:
"""Handles absolute variables and values from document
Expand Down Expand Up @@ -171,16 +189,13 @@ def handle_composite(
composite_values[key] = val

if composite_values:
replaced_values: dict = replace_callback(
composite_values, variable_doc.data
)
for key, val in replaced_values.items():
variable_doc[key] = val
replaced_values: dict = replace_callback(composite_values, variable_doc.data)

cls.handle_absolute(variable_doc, replaced_values)
cls.handle_composite(variable_doc, replaced_values)

@classmethod
def handle_execute_context(
cls, variable_doc: Variables, exec_ctx: ExecuteContext
) -> None:
def handle_execute_context(cls, variable_doc: Variables, exec_ctx: ExecuteContext) -> None:
"""Handle variables passed from external context

Args:
Expand Down Expand Up @@ -257,12 +272,9 @@ def get_exposed_replaced_data(document: VersionedDocumentV2, store: dict) -> dic

if expose_doc := ExposeManager.get_expose_doc(file_ctx.document):
exposed_doc_t = copy.copy(expose_doc)
exposed_doc_t = [
str(key).replace("%>", "").replace("<%", "").strip()
for key in exposed_doc_t
]
exposed_doc_t = [str(key).replace("%>", "").replace("<%", "").strip() for key in exposed_doc_t]

expose_val = ExposeManager.replace_values(expose_doc, store)
return dict(zip(exposed_doc_t, expose_val))
return dict(zip(exposed_doc_t, expose_val, strict=False))

return {}
60 changes: 57 additions & 3 deletions chk/infrastructure/templating.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
Templating module
"""

import json
import typing

from jinja2 import TemplateError
from jinja2.environment import Template
from jinja2.meta import find_undeclared_variables
from jinja2.nativetypes import NativeEnvironment

from chk.infrastructure.logging import error
Expand All @@ -11,6 +16,22 @@
class JinjaTemplate:
"""JinjaTemplate is wrapper class for JinjaNativeTemplate"""

@staticmethod
def build_env() -> NativeEnvironment:
"""Build a native env"""

env = NativeEnvironment(
variable_start_string="<%",
variable_end_string="%>",
block_start_string="<@",
block_end_string="@>",
comment_start_string="<#",
comment_end_string="#>",
)

env.filters["fromjson"] = filter_fromjson
return env

@staticmethod
def make(template: str) -> Template:
"""Create a NativeEnvironment with default settings"""
Expand All @@ -20,7 +41,7 @@ def make(template: str) -> Template:
error(e_msg)
raise ValueError(e_msg)

n_env = NativeEnvironment(
env = NativeEnvironment(
variable_start_string="<%",
variable_end_string="%>",
block_start_string="<@",
Expand All @@ -29,11 +50,44 @@ def make(template: str) -> Template:
comment_end_string="#>",
)

return n_env.from_string(template)
env.filters["fromjson"] = filter_fromjson

return env.from_string(template)

@staticmethod
def render(env: NativeEnvironment, template: str, data: dict) -> typing.Any:
"""Create a NativeEnvironment with default settings"""

if not template or not isinstance(template, str):
e_msg = f"Template error: {type(template)} {template}"
error(e_msg)
raise ValueError(e_msg)

# handle undefined vars
undeclared_vars = find_undeclared_variables(env.parse(template))

if all(_var in data for _var in undeclared_vars):
return env.from_string(template).render(data)
else:
return template


def is_template_str(tpl: str) -> bool:
"""Check given string is templated string or not"""

_dm_sets = [("<%", "%>"), ("<@", "@>"), ("<#", "#>")]
return any([_dm_set[0] in tpl and _dm_set[1] in tpl for _dm_set in _dm_sets])
return any(_dm_set[0] in tpl and _dm_set[1] in tpl for _dm_set in _dm_sets)


######################################
# Jinja Filters
######################################


def filter_fromjson(value: typing.Any) -> str:
"""Convert a JSON string to a Python dictionary."""

try:
return json.loads(value)
except json.JSONDecodeError as e:
raise TemplateError(f"Invalid JSON string: {e}") from e
6 changes: 1 addition & 5 deletions chk/infrastructure/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,7 @@ def parse(self) -> None:
ver_l[-1],
)

if (
len(self.provider) == 0
or len(self.doc_type) == 0
or len(self.doc_type_ver) == 0
):
if len(self.provider) == 0 or len(self.doc_type) == 0 or len(self.doc_type_ver) == 0:
raise ValueError("Invalid version string")

def validate(self) -> bool:
Expand Down
4 changes: 1 addition & 3 deletions chk/infrastructure/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ def display(
formatter(wfp.dump_json(), dump=exec_ctx.options["dump"])


def die_with_error(
err: Exception, Presenter: type[PresentationBuilder], is_fmt: bool
) -> None:
def die_with_error(err: Exception, Presenter: type[PresentationBuilder], is_fmt: bool) -> None:
"""die_with_error"""

prs = Presenter(data=None)
Expand Down
8 changes: 2 additions & 6 deletions chk/modules/fetch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ def call(file_ctx: FileContext, exec_ctx: ExecuteContext) -> ExecResponse:
http_doc = HttpDocumentSupport.from_file_context(file_ctx)
debug(http_doc.model_dump_json())

VersionedDocumentSupport.validate_with_schema(
HttpDocumentSupport.build_schema(), http_doc
)
VersionedDocumentSupport.validate_with_schema(HttpDocumentSupport.build_schema(), http_doc)
except Exception as ex:
error_trace(exception=sys.exc_info()).error(ex)
return ExecResponse(
Expand Down Expand Up @@ -96,9 +94,7 @@ def call(file_ctx: FileContext, exec_ctx: ExecuteContext) -> ExecResponse:


@with_catch_log
def execute(
ctx: FileContext, exec_ctx: ExecuteContext, cb: abc.Callable = lambda *args: ...
) -> None:
def execute(ctx: FileContext, exec_ctx: ExecuteContext, cb: abc.Callable = lambda *args: ...) -> None:
"""Call with a http document

Args:
Expand Down
Loading