Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.10] - 2025-07-21

### Added
- New parameter in the `Application` class constructor called `show_messages_with_icons` that allows displaying icons in output messages. Default is `True`.
- Added the `__delitem__` method to `config` to remove an item from the configuration dictionary.

### Changed
- In `out`, renamed the `force_icon` parameter to `show_icon` to make it more descriptive.

### Fixed
- Broken links to documentation fixed in `README.md`

## [0.1.9] - 2025-07-15

### Added
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ In action:
![Demo](./docs/docs/assets/records/quick_start_hello.svg)


For more details, see our [Quick Start Guide](https://rlizana.github.io/clifire/en/quick-start.md).
For more details, see our [Quick Start Guide](https://rlizana.github.io/clifire/en/quick-start).

## Documentation

Expand Down Expand Up @@ -129,7 +129,7 @@ To contribute to CliFire:
6. **Update the CHANGELOG.md** with your changes.
7. **Commit and push** your changes, and then create a pull request.

For further contribution details, please see our [Contributing Guide](https://rlizana.github.io/clifire/en/contributing.md).
For further contribution details, please see our [Contributing Guide](https://rlizana.github.io/clifire/en/contributing).

## License

Expand Down
2 changes: 1 addition & 1 deletion fire/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def precommit(cmd):
'''
Launch pre-commit
'''
cmd.app.shell('pre-commit run --all-files', capture_output=False)
cmd.app.shell('rye run pre-commit run --all-files', capture_output=False)


@command.fire
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "CliFire"
version = "0.1.9"
version = "0.1.10"
description = "Minimal CLI framework to build Python commands quickly and elegantly."
authors = [
{ name = "Roberto Lizana", email = "rober.lizana@gmail.com" }
Expand Down
7 changes: 6 additions & 1 deletion src/clifire/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(
command_help=commands.help.CommandHelp,
command_version=commands.version.CommandVersion,
template_folder=None,
show_messages_with_icons: bool = True,
):
App.current_app = self
self.name = name
Expand Down Expand Up @@ -55,6 +56,7 @@ def __init__(
self.template = None
if template_folder:
self.template = template.Template(template_folder)
self.show_messages_with_icons = show_messages_with_icons

def _add_option_verbose(self):
self.add_option(
Expand Down Expand Up @@ -179,7 +181,10 @@ def fire(self, command_line: str = None):
else:
command_line = self._clean_command_line(command_line)
cmd = self.get_command(command_line)
out.setup(not self.get_option('no_ansi'))
out.setup(
not self.get_option('no_ansi'),
show_icons=self.show_messages_with_icons,
)
res = cmd.launch(cmd.command_line)
if type(res) is int and res != 0:
sys.exit(res)
Expand Down
6 changes: 6 additions & 0 deletions src/clifire/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ def __getitem__(self, key):
def __setitem__(self, key, value):
self.__dict__[key] = value

def __delitem__(self, key):
if key in self.__dict__:
del self.__dict__[key]
else:
raise KeyError(f'Key "{key}" not found')

def __contains__(self, key):
return key in self.__dict__

Expand Down
2 changes: 1 addition & 1 deletion src/clifire/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def load_file(filename):


def main(command_line: str = None):
app = application.App(name='CliFire', version='0.1.9')
app = application.App(name='CliFire', version='0.1.10')
current_dir = os.getcwd()
out.debug(f'Search commands in {current_dir} folder and parents')
loaded = False
Expand Down
42 changes: 24 additions & 18 deletions src/clifire/out.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@
COLOR_WARN = 'yellow'
COLOR_ERROR = 'red'

ICON_SHOW = False
ICON_SUCCESS = '✓'
ICON_ERROR = '✗'
ICON_WARN = '▲'


def setup(ansi: bool = True):
def setup(ansi: bool = True, show_icons: bool = None) -> None:
global ICON_SHOW, CONSOLE, CONSOLE_WIDTH
if show_icons is not None:
ICON_SHOW = show_icons
if ansi:
CONSOLE.no_color = False
CONSOLE.highlight = True
Expand Down Expand Up @@ -112,23 +116,23 @@ def info(self, text: str, end=False):
if end:
self.stop()

def warn(self, text: str, end=False, icon: bool = False):
def warn(self, text: str, end=False, icon: bool = None):
self._text = text_color(
text, color=COLOR_WARN, icon=ICON_WARN, force_icon=icon
text, color=COLOR_WARN, icon=ICON_WARN, show_icon=icon
)
if end:
self.stop()

def success(self, text: str, end=True, icon: bool = False):
def success(self, text: str, end=True, icon: bool = None):
self._text = text_color(
text, color=COLOR_SUCCESS, icon=ICON_SUCCESS, force_icon=icon
text, color=COLOR_SUCCESS, icon=ICON_SUCCESS, show_icon=icon
)
if end:
self.stop()

def error(self, text: str, end=True, icon: bool = False):
def error(self, text: str, end=True, icon: bool = None):
self._text = text_color(
text, color=COLOR_ERROR, icon=ICON_ERROR, force_icon=icon
text, color=COLOR_ERROR, icon=ICON_ERROR, show_icon=icon
)
if end:
self.stop()
Expand Down Expand Up @@ -192,11 +196,13 @@ def text_color(
text: str,
color: str = COLOR_NORMAL,
icon: str = None,
force_icon: bool = False,
show_icon: bool = False,
) -> str:
if show_icon is None:
show_icon = ICON_SHOW
text = str(text)
if icon and not text.startswith(icon):
if CONSOLE.no_color is True or force_icon:
if CONSOLE.no_color is True or show_icon:
text = f'{icon} {text}'
return f'[{color}]{text}[/{color}]'

Expand All @@ -205,30 +211,30 @@ def _print(
text: str,
color: str = COLOR_NORMAL,
icon: str = None,
force_icon: bool = False,
show_icon: bool = None,
) -> None:
text = text_color(text, color=color, icon=icon, force_icon=force_icon)
text = text_color(text, color=color, icon=icon, show_icon=show_icon)
CONSOLE.print(text)


def info(text: str) -> None:
_print(text, COLOR_INFO)


def success(text: str, icon: bool = False) -> None:
_print(text, color=COLOR_SUCCESS, icon=ICON_SUCCESS, force_icon=icon)
def success(text: str, icon: bool = None) -> None:
_print(text, color=COLOR_SUCCESS, icon=ICON_SUCCESS, show_icon=icon)


def warn(text: str, icon: bool = False) -> None:
_print(text, color=COLOR_WARN, icon=ICON_WARN, force_icon=icon)
def warn(text: str, icon: bool = None) -> None:
_print(text, color=COLOR_WARN, icon=ICON_WARN, show_icon=icon)


def error(text: str, icon: bool = False) -> None:
_print(text, color=COLOR_ERROR, icon=ICON_ERROR, force_icon=icon)
def error(text: str, icon: bool = None) -> None:
_print(text, color=COLOR_ERROR, icon=ICON_ERROR, show_icon=icon)


def critical(text: str, code: int = 1) -> None:
error(text)
error(text, icon=False)
sys.exit(code)


Expand Down
13 changes: 13 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,16 @@ def test_config_query(temp_dir):
assert conf.query_get('parent.child_1.name', 'Deleted') == 'Deleted'
with pytest.raises(KeyError):
conf.query_del('parent.child_2.name')


def test_config_del(temp_dir):
config_file = os.path.join(temp_dir, 'config.yaml')
test_data = {
'key_1': 1,
'key_2': 2,
}
conf = config.Config(config_file=config_file, create=False, **test_data)
del conf['key_1']
assert 'key_1' not in conf
with pytest.raises(KeyError):
del conf['key_1']
10 changes: 5 additions & 5 deletions tests/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ def test_info(capsys):


def test_success(capsys):
out.success('Success sample message')
out.success('Success sample message', icon=False)
assert 'Success sample message\n' == output(capsys)


def test_warn(capsys):
out.warn('Warn sample message')
out.warn('Warn sample message', icon=False)
assert 'Warn sample message\n' == output(capsys)


def test_error(capsys):
out.warn('Error sample message')
out.warn('Error sample message', icon=False)
assert 'Error sample message\n' == output(capsys)


Expand Down Expand Up @@ -246,7 +246,7 @@ def test_rule(capsys):


def test_no_ansi(capsys):
out.setup(ansi=False)
out.setup(ansi=False, show_icons=False)
assert out.CONSOLE.no_color is True
out.success('Success')
assert '✓ Success' in output(capsys)
Expand All @@ -265,7 +265,7 @@ def test_no_ansi(capsys):
live.cancel()

output(capsys)
out.setup(ansi=True)
out.setup(ansi=True, show_icons=False)
assert out.CONSOLE.no_color is False
out.success('Success')
assert '✓' not in output(capsys)
Expand Down