Release Notes
0.7.5¶
Fixed¶
- Regression on default values of Option.
0.7.4¶
Changed¶
- Allow default arguments outside of the fields declaration. E.g.: `Option[...] = 2"
- Rename
render_for_help_commandtorender_help.
0.7.3¶
Fixed¶
- Regression getting the help text for the fields.
0.7.2¶
Fixed¶
- Support for hidden commands in custom groups and main.
0.7.1¶
Added¶
- Python 3.14 support.
0.7.0¶
Added¶
- Silent Parameters via silent_param decorator:
- Allows parameters (e.g.
Option,JsonParam) to be parsed, validated, and injected from envvars/defaults without being passed to the command callback. - Hidden from
--helpand usage strings, keeping secrets and auxiliary values invisible to users. - Full support for environment injection (
Env) and complex types (JsonParam).
- Allows parameters (e.g.
Changed¶
- Updated
generate_signatureand usage rendering to exclude hidden (silent_param) options. - Improved error output so invalid options display both
Error:andUsage:consistently. - Reorganise the internals of Sayer and split functionality.
Fixed¶
- Prevented
--secretand other silent parameters from leaking into usage/help output. - Corrected variadic argument handling (
nargs=-1) when combined with defaults. - Fixed duplication and hidden flag inconsistencies in
collect_usage_pieces. - Internal typings that were mismatching in the development.
0.6.0¶
Added¶
with_return_valueflag toSayerTestClient.invoketo capture actual callback return values in tests.- Now test authors can choose between full CLI behavior or direct access to command return values, without breaking either workflow.
- Custom Commands Support:
You can now register your own commands that will appear under a dedicated βCustomβ section in the CLI help output. Example:
@command
def shout():
"""Custom shout command"""
success("HELLO!")
app.add_custom_command("shout", shout)
You can now mark groups as custom (is_custom=True) and provide a custom_command_name.
These groups appear under their own dedicated section in CLI help, making it easier to distinguish framework commands from project-specific ones.
reports = group(
name="reports",
help="Reporting commands",
is_custom=True,
custom_command_name="Reporting Suite"
)
Help output now renders custom groups in titled panels:
Reporting Suite:
reports Reporting commands
Changed¶
- Updated:
SayerCommand.main()and.invoke()ensure return values propagate correctly in tests.
Fixed¶
SayerTestClient.invoke()now returns the actual command return value viares.return_value.
0.5.5¶
Fixed¶
- Correctly handle
Optional(str | None) options: missing flags now yield realNoneinstead of"None". - Prevent duplicate command execution in tests by removing manual
ctx.invoke()fallback. CliRunner.invoke()now reliably captures return values via_return_result.
Changed¶
- Set
standalone_mode = Falseby default to stopsys.exit()propagation in tests. - Improved internal type conversion logic to avoid coercing
Noneinto"None"for string parameters.
Improved¶
- Stability of
SayerTestClientwith Click β₯ 8.3.0. - More consistent return value handling across commands and subcommands.
0.5.4¶
Highlights¶
- Improved CLI type conversion for complex annotations and container types.
- Better integration with Click for list/sequence options (
multiple=Truenow works correctly). - Robust handling of modern typing features like
Annotated,Union, andOptional.
Added¶
- Support for:
list[T],set[T],frozenset[T]with CSV strings or single values.dict[K, V]parsing from["key=value", ...].tuple[T, ...]and heterogeneous tuples.
- Automatic detection of
list[...]andSequence[...]in CLI options:- Maps to
multiple=Truewith correct inner type for Click.
- Maps to
- Safe fallback for single string values in list/set/frozenset (no more character splitting).
Changed¶
command()now uses_safe_get_type_hints()instead ofget_type_hints()for dynamic module safety.convert_cli_value_to_type():- Handles
UnionandOptionalearly, trying inner types in order. - Normalizes annotations only after container checks.
- Prevents
TypeError: cannot create 'types.UnionType' instances.
- Handles
Fixed¶
- Character-splitting bug for
list[str]options whenmultiple=Truewas not applied. - Union/Optional conversion now returns correct types (e.g.,
"42"β42forint | None). - Dynamic module loading no longer breaks type-hint resolution.
0.5.3¶
Highlights¶
- Robust type-hint resolution for dynamic modules.
- Runtime-safe normalization of typing constructs.
- More predictable CLI argument conversion.
Added¶
_safe_get_type_hints(include_extras=True)with multi-strategy resolution._normalize_annotation_to_runtime_type()forAnnotated,Optional/Union,Literal, and subscripted generics.
Changed¶
- Bool parsing,
datetimeβdatedowncast, and container handling.
Fixed¶
KeyErrorfromsys.modules[func.__module__]lookups.TypeErroronisinstancechecks against subscripted generics.
0.5.2¶
Fixed¶
- Fixed variadic arguments (
nargs=-1). Now correctly supported when declared withArgument. They are treated as positional, variadic, and non-required, allowing[]or multiple values to pass. - Improved type handling for
list[...]annotations. WhenArgumentis explicitly provided, the inner type (e.g.,str) is used per item instead of coercing into an option withmultiple=True.
0.5.1¶
Changed¶
Option Handling¶
- Normalized default values for required and optional options to ensure consistent behavior with
None,..., and_empty. - Improved boolean flag defaults (
--verbose/--no-verbose) so that defaultTrueis mapped correctly and reflected in output.
Argument Handling¶
- Added proper support for default values in positional arguments.
- Arguments with defaults are now correctly displayed in
--helpwithshow_default.
Root Callback Behavior¶
- Improved
invoke_without_commandhandling: root callbacks are executed even without subcommands, mirroring Click's behavior while respecting Sayer's callback chain.
0.5.0¶
Added¶
- Allow direct invoke of a function being decorated by
@command. - Allow Sayer syntax annotation for natural direct calls.
- group documentation section updated.
Fixed¶
- Imports from
sayer.
0.4.1¶
Fixed¶
- Error when parsing Boolean values from environment variables.
- Fixed error when Boolean values are parsed from environment variables.
0.4.0¶
Changed¶
In the past, Sayer was using dataclass to manage all the settings but we found out that can be a bit cumbersome for a lot
of people that are more used to slightly cleaner interfaces and therefore, the internal API was updated to stop using @dataclass and
use directly a typed Settings object.
- Replace
Settingsto stop using@dataclassand start using direct objects instead.
Example before
from dataclasses import dataclass, field
from sayer.conf.global_settings import Settings
@dataclass
class MyCustomSettings(Settings):
hosts: list[str] = field(default_factory=lambda: ["example.com"])
Example after
from sayer.conf.global_settings import Settings
class MyCustomSettings(Settings):
hosts: list[str] = ["example.com"]
This makes the code cleaner and readable.
0.3.4¶
Fixed¶
- Displaying the Arguments in the help of subcommands.
0.3.3¶
Note
Version 0.3.2 had issues and it was skipped
Changed¶
- Add
get_helpandformat_helpdirectly via Sayer instance. - Add support to markup, emoji and styles in the default console.
0.3.1¶
Changed¶
- Make the UI help display cleaner and simpler.
0.3.0¶
Added¶
- BaseSayerCommand: Introduced a new base class for commands,
BaseSayerCommand, which provides a more structured way to define commands and allows for easier extension of command functionality. - BaseSayerGroup: Introduced a new base class for groups,
BaseSayerGroup. override_help_text: A new parameter for theadd_appandadd_sayerdecorator that allows you to override the help text for a command, providing more flexibility in how commands are documented.
Changed¶
- SayerCommand: Now inherits from
BaseSayerCommand, this brings some structure and allows an easier way to extend the command functionality. - SayerGroup: Now inherits from
BaseSayerGroup, this brings some structure and allows an easier way to extend the group. - To check the version, you can use
-vinstead of-V.
0.2.7¶
Fixed¶
Argumentwas not declaring the *param_decls properly and the required display was not accurate.
0.2.6¶
Fixed¶
nargsdetection and default.
0.2.5¶
Added¶
display_full_helpanddisplay_help_lengthin the settings andSayerGroupallowing to specifify if the help of commands/subcommands must be displayed in full.
0.2.4¶
Added¶
- Custom typing overrides making sure you can specify your own typing for the
@commanddecorator. SayerCommandnow supports all the parameters ofclick.Command, allowing for more flexibility in command definitions whenapp.add_commandis used.
Fixed¶
- Help text for arguments was not being displayed correctly when using the
@commanddecorator. @commanddecorator was not wrapping the decorator properly and loosing critical information for type checking and for type hints.
0.2.3¶
This was missed from the version 0.2.2 and it should have been included.
Changed¶
- Postpone Annotations and Type Hints: The
@commanddecorator now postpones annotations and type hints until the command is executed, allowing for more dynamic behavior and flexibility in command definitions.
¶
0.2.2¶
Added¶
- Positional & Keyword Naming:
@commandnow accepts a first-positional string or name= kwarg to override CLI names without affecting signature introspection. - Kebab-case Defaults: Functions named in snake_case are automatically converted to kebab-case CLI commands by default.
- Click Attr Forwarding: All extra Click attributes (hidden, short_help, short_help, etc.) passed to @command are forwarded directly into @click.command(...).
- Enhanced add_command:
Sayer.add_commandnow distinguishes between Sayer instances (unwrap β SayerGroup), any click.Group (mounted as-is), and leaf commands (wrapped in SayerCommand).
Fixed¶
- When using
from __future__ import annotationsthis was not parsing the annotations correctly. - Union types were not being parsed correctly.
- Argument conflicts were not being handled properly.
- Nested Sub-app Support: Sub-apps maintain their nested commands and rich help panels when mounted under a root app.
Changed¶
- Error Handling: Eliminated AttributeError when using string-based names in @command.
0.2.1¶
Added¶
- Pass custom context and context class into a Sayer app.
- Callback integration for easy use.
- Invoke without command on a Sayer level.
- Parameter declarations for Option and display
Fixed¶
- Wrapping Sayer apps it was not adding the native SayerGroup.
- SayerGroup and command split.
- Display of help messages was not properly tested.
0.2.0¶
Fixed¶
- Fixed async middleware order
beforeandafterexecution.
0.1.0 β First Release¶
We're proud to announce the first official release of Sayer, a modern, async-native Python CLI framework designed for maintainability, scalability, and expressiveness.
No more glue scripts. No more boilerplate. Just clean commands, smart params, and CLI magic out-of-the-box.
β Decorator-Based Command System¶
@app.command()and@command()support- Command nesting, grouping, and docstring-based help
- Supports both sync and async commands
ποΈ Parameter System¶
- Rich typing with
Option,Argument, andEnv Annotatedsupport for combining types and metadata- Flag handling, lists, enums, and more
π Middleware¶
- Global and named middleware hooks
- Before/after execution
argsinjection and abort support- Perfect for logging, validation, and feature toggling
π§ State Injection¶
- Class-based singleton state via
Stateprotocol - Automatic injection into commands
- Great for sharing config, DB handles, etc.
πͺ΅ Logging¶
loggerproxy with Rich integration- Auto-configured via
settings.logging_level - Fully pluggable backend
π¦ Configuration System¶
SAYER_SETTINGS_MODULEenvironment var- Class-based settings with inheritance
- Rich features like dict/tuple export
π Encoders¶
- Automatic JSON-to-object parsing via
JsonParam - Fully pluggable and overridable
π§ͺ Testing Tools¶
SayerTestClientbased onclick.testing- Simulate CLI calls, inject env vars, assert output
- Test-ready out-of-the-box
π§° CLI Features¶
- Built-in
sayer newfor scaffolding a CLI project - Built-in
sayer docs generateto export docs to Markdown - Clean terminal output via
echo,success,warning,error
π Documentation¶
Extensive documentation available, including: