Skip to content

Commit 21c85b3

Browse files
Merge pull request Pipelex#179 from Pipelex/release/v0.6.2
Release/v0.6.2
2 parents b3fc07f + 2e0a410 commit 21c85b3

9 files changed

Lines changed: 157 additions & 31 deletions

File tree

.github/workflows/manual-trigger-tests-check.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ name: Manual trigger tests check
33
on:
44
pull_request:
55
branches:
6-
- main
7-
- dev
8-
- "release/v[0-9]+.[0-9]+.[0-9]+"
9-
workflow_dispatch:
6+
- manual-trigger-tests-check
7+
# - main
8+
# - dev
9+
# - "release/v[0-9]+.[0-9]+.[0-9]+"
10+
# workflow_dispatch:
1011

1112
jobs:
1213
trigger-tests:

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ reports/
4444
results/
4545

4646
# Pipelex libraries, duplicated from pipelex/libraries/ by `pipelex init-libraries`
47-
pipelex_libraries/
47+
/pipelex_libraries
4848

4949
# personnal pipelex config file that overrides the default one
5050
pipelex_super.toml

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## [v0.6.2] - 2025-07-18
4+
5+
### Added
6+
- New `dry-run-pipe` cli command to dry run a single pipe by its code
7+
- New `show-pipe` cli command to display pipe definitions from the pipe library
8+
- New `dry_run_single_pipe()` function for running individual pipe dry runs
9+
10+
### Changed
11+
- Updated `init-libraries` command to accept a directory argument and create `pipelex_libraries` folder in specified location
12+
- Updated `validate` command to use `-c` flag for the config folder path
13+
314
## [v0.6.1] - 2025-07-16
415

516
- Can execute pipelines with `input_memory`: It is a `CompactMemory: Dict[str, Dict[str, Any]]`

Makefile

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,11 @@ env: check-uv
137137
fi
138138
@echo "Using Python: $$($(VENV_PYTHON) --version) from $$(which $$(readlink -f $(VENV_PYTHON)))"
139139

140-
init: env
141-
$(call PRINT_TITLE,"Running pipelex init-libraries and init-config")
142-
$(VENV_PIPELEX) init-libraries
143-
$(VENV_PIPELEX) init-config
144-
145140
install: env
146141
$(call PRINT_TITLE,"Installing dependencies")
147142
@. $(VIRTUAL_ENV)/bin/activate && \
148143
uv sync --all-extras && \
149-
$(VENV_PIPELEX) init-libraries && \
150-
$(VENV_PIPELEX) init-config && \
151-
echo "Installed Pipelex dependencies in ${VIRTUAL_ENV} with all extras and initialized Pipelex";
144+
echo "Installed Pipelex dependencies in ${VIRTUAL_ENV} with all extras.";
152145

153146
lock: env
154147
$(call PRINT_TITLE,"Resolving dependencies without update")
@@ -161,9 +154,14 @@ update: env
161154
uv sync --all-extras && \
162155
echo "Updated dependencies in ${VIRTUAL_ENV}";
163156

157+
init: env
158+
$(call PRINT_TITLE,"Running pipelex init-libraries and init-config")
159+
$(VENV_PIPELEX) init-libraries
160+
$(VENV_PIPELEX) init-config
161+
164162
validate: env
165163
$(call PRINT_TITLE,"Running setup sequence")
166-
$(VENV_PIPELEX) validate
164+
$(VENV_PIPELEX) validate -c pipelex/libraries
167165

168166
build: env
169167
$(call PRINT_TITLE,"Building the wheels")
@@ -439,16 +437,16 @@ check-unused-imports: env
439437
$(call PRINT_TITLE,"Checking for unused imports without fixing")
440438
$(VENV_RUFF) check --select=F401 --no-fix .
441439

442-
c: init format lint pyright mypy
440+
c: format lint pyright mypy
443441
@echo "> done: c = check"
444442

445-
cc: init cleanderived c
446-
@echo "> done: cc = init cleanderived init format lint pyright mypy"
443+
cc: cleanderived c
444+
@echo "> done: cc = cleanderived format lint pyright mypy"
447445

448446
check: cc check-unused-imports
449447
@echo "> done: check"
450448

451-
v: init validate
449+
v: validate
452450
@echo "> done: v = validate"
453451

454452
li: lock install

pipelex/cli/_cli.py

Lines changed: 97 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,42 @@
1010

1111
from pipelex import log, pretty_print
1212
from pipelex.exceptions import PipelexCLIError, PipelexConfigError
13-
from pipelex.hub import get_pipe_provider
13+
from pipelex.hub import get_pipe_provider, get_pipeline_tracker, get_required_pipe
1414
from pipelex.libraries.library_config import LibraryConfig
15-
from pipelex.pipe_works.pipe_dry import dry_run_all_pipes
15+
from pipelex.pipe_works.pipe_dry import dry_run_all_pipes, dry_run_single_pipe
1616
from pipelex.pipelex import Pipelex
1717
from pipelex.tools.config.manager import config_manager
1818

1919

20+
def is_pipelex_libraries_folder(folder_path: str) -> bool:
21+
"""Check if the given folder path contains a valid pipelex libraries structure.
22+
23+
A valid pipelex libraries folder should contain the following subdirectories:
24+
- pipelines
25+
- llm_deck
26+
- llm_integrations
27+
- plugins
28+
- templates
29+
30+
Args:
31+
folder_path: Path to the folder to check
32+
33+
Returns:
34+
True if the folder contains all required subdirectories, False otherwise
35+
"""
36+
if not os.path.exists(folder_path) or not os.path.isdir(folder_path):
37+
return False
38+
39+
required_subdirs = ["pipelines", "llm_deck", "llm_integrations", "plugins", "templates"]
40+
41+
for subdir in required_subdirs:
42+
subdir_path = os.path.join(folder_path, subdir)
43+
if not os.path.exists(subdir_path) or not os.path.isdir(subdir_path):
44+
return False
45+
46+
return True
47+
48+
2049
class PipelexCLI(TyperGroup):
2150
@override
2251
def get_command(self, ctx: Context, cmd_name: str) -> Optional[Command]:
@@ -38,22 +67,31 @@ def get_command(self, ctx: Context, cmd_name: str) -> Optional[Command]:
3867

3968
@app.command("init-libraries")
4069
def init_libraries(
70+
directory: Annotated[str, typer.Argument(help="Directory where to create the pipelex_libraries folder")] = ".",
4171
overwrite: Annotated[bool, typer.Option("--overwrite", "-o", help="Warning: If set, existing files will be overwritten.")] = False,
4272
) -> None:
43-
"""Initialize pipelex libraries in the current directory.
73+
"""Initialize pipelex libraries in a pipelex_libraries folder in the specified directory.
4474
4575
If overwrite is False, only create files that don't exist yet.
4676
If overwrite is True, all files will be overwritten even if they exist.
4777
"""
4878
try:
49-
# TODO: Have a more proper print message regarding the overwrited files (e.g. list of files that were overwritten or not)
50-
LibraryConfig().export_libraries(overwrite=overwrite)
79+
# Always create a pipelex_libraries folder in the specified directory
80+
target_path = os.path.join(directory, "pipelex_libraries")
81+
82+
# Create the target directory if it doesn't exist
83+
os.makedirs(directory, exist_ok=True)
84+
85+
# Create a LibraryConfig instance with the target path
86+
library_config = LibraryConfig(config_folder_path=target_path)
87+
library_config.export_libraries(overwrite=overwrite)
88+
5189
if overwrite:
52-
typer.echo("Successfully initialized pipelex libraries (all files overwritten)")
90+
typer.echo(f"✅ Successfully initialized pipelex libraries at '{target_path}' (all files overwritten)")
5391
else:
54-
typer.echo("Successfully initialized pipelex libraries (only created non-existing files)")
92+
typer.echo(f"✅ Successfully initialized pipelex libraries at '{target_path}' (only created non-existing files)")
5593
except Exception as e:
56-
raise PipelexCLIError(f"Failed to initialize libraries: {e}")
94+
raise PipelexCLIError(f"Failed to initialize libraries at '{directory}': {e}")
5795

5896

5997
@app.command("init-config")
@@ -79,17 +117,49 @@ def init_config(
79117
def validate(
80118
relative_config_folder_path: Annotated[
81119
str, typer.Option("--config-folder-path", "-c", help="Relative path to the config folder path")
82-
] = "pipelex_libraries",
120+
] = "./pipelex_libraries",
83121
) -> None:
84122
"""Run the setup sequence."""
85-
config_folder_path = os.path.join(os.getcwd(), relative_config_folder_path)
86-
LibraryConfig(config_folder_path=config_folder_path).export_libraries()
123+
# Check if pipelex libraries folder exists
124+
if not is_pipelex_libraries_folder(relative_config_folder_path):
125+
typer.echo(f"❌ No pipelex libraries folder found at '{relative_config_folder_path}'")
126+
typer.echo("To create a pipelex libraries folder, run: pipelex init-libraries")
127+
raise typer.Exit(1)
128+
87129
pipelex_instance = Pipelex.make(relative_config_folder_path=relative_config_folder_path, from_file=False)
88130
pipelex_instance.validate_libraries()
89131
asyncio.run(dry_run_all_pipes())
90132
log.info("Setup sequence passed OK, config and pipelines are validated.")
91133

92134

135+
@app.command()
136+
def dry_run_pipe(
137+
pipe_code: Annotated[str, typer.Argument(help="The pipe code to dry run")],
138+
relative_config_folder_path: Annotated[
139+
str, typer.Option("--config-folder-path", "-c", help="Relative path to the config folder path")
140+
] = "./pipelex_libraries",
141+
) -> None:
142+
"""Dry run a single pipe."""
143+
# Check if pipelex libraries folder exists
144+
if not is_pipelex_libraries_folder(relative_config_folder_path):
145+
typer.echo(f"❌ No pipelex libraries folder found at '{relative_config_folder_path}'")
146+
typer.echo("To create a pipelex libraries folder, run: pipelex init-libraries")
147+
raise typer.Exit(1)
148+
149+
try:
150+
# Initialize Pipelex
151+
pipelex_instance = Pipelex.make(relative_config_folder_path=relative_config_folder_path, from_file=False)
152+
pipelex_instance.validate_libraries()
153+
154+
# Run the single pipe dry run
155+
asyncio.run(dry_run_single_pipe(pipe_code))
156+
get_pipeline_tracker().output_flowchart()
157+
158+
except Exception as e:
159+
typer.echo(f"❌ Error running dry run for pipe '{pipe_code}': {e}")
160+
raise typer.Exit(1)
161+
162+
93163
@app.command()
94164
def show_config() -> None:
95165
"""Show the pipelex configuration."""
@@ -116,6 +186,22 @@ def list_pipes(
116186
raise PipelexCLIError(f"Failed to list pipes: {e}")
117187

118188

189+
@app.command("show-pipe")
190+
def show_pipe(
191+
pipe_code: Annotated[
192+
str,
193+
typer.Argument(help="Pipeline code to show definition for"),
194+
],
195+
relative_config_folder_path: Annotated[
196+
str, typer.Option("--config-folder-path", "-c", help="Relative path to the config folder path")
197+
] = "./pipelex_libraries",
198+
) -> None:
199+
"""Show pipe from the pipe library."""
200+
Pipelex.make(relative_config_folder_path=relative_config_folder_path, from_file=False)
201+
pipe = get_required_pipe(pipe_code=pipe_code)
202+
pretty_print(pipe, title=f"Pipe '{pipe_code}'")
203+
204+
119205
def main() -> None:
120206
"""Entry point for the pipelex CLI."""
121207
app()

pipelex/pipe_works/pipe_dry.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,29 @@ async def dry_run_all_pipes():
2121
await dry_run_pipes(pipes=all_pipes)
2222

2323

24+
async def dry_run_single_pipe(pipe_code: str) -> str:
25+
"""
26+
Dry run a single pipe by its code.
27+
28+
Args:
29+
pipe_code: The code of the pipe to dry run
30+
31+
Returns:
32+
Status string: "SUCCESS" or error message
33+
"""
34+
try:
35+
# Get the pipe using the hub function
36+
pipe = get_pipe_provider().get_optional_pipe(pipe_code=pipe_code)
37+
if not pipe:
38+
return f"FAILED: Pipe '{pipe_code}' not found"
39+
40+
# Run the single pipe
41+
result = await dry_run_pipes(pipes=[pipe])
42+
return result.get(pipe_code, f"FAILED: No result for pipe '{pipe_code}'")
43+
except Exception as e:
44+
return f"FAILED: {str(e)}"
45+
46+
2447
# TODO: add a function to dry run a single pipe, make it callable as a param of `pipelex validate`
2548
async def dry_run_pipes(pipes: List[PipeAbstract]) -> Dict[str, str]:
2649
"""

pipelex/pipelex_template.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
[pipelex]
2+
[pipelex.feature_config]
3+
# WIP/Experimental feature flags
4+
is_pipeline_tracking_enabled = true
5+
is_activity_tracking_enabled = true
6+
is_reporting_enabled = true
7+
18
[pipelex.aws_config]
29
api_key_method = "env"
310
# The possible values are "env" and "secret_provider".

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "pipelex"
3-
version = "0.6.1"
3+
version = "0.6.2"
44
description = "Pipelex is an open-source dev tool based on a simple declarative language that lets you define replicable, structured, composable LLM pipelines."
55
authors = [{ name = "Evotis S.A.S.", email = "evotis@pipelex.com" }]
66
maintainers = [{ name = "Pipelex staff", email = "oss@pipelex.com" }]

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)