Skip to content

Commit

Permalink
[feat] Revamp CLI and add CLI tests (#44)
Browse files Browse the repository at this point in the history
* Working 'main' typer app

* Working on integration tests for the CLI app

* Move fixtures into conftest

* Update documentation

* Update changelog
  • Loading branch information
qTipTip authored Oct 8, 2024
1 parent 0088a7e commit ffd63af
Show file tree
Hide file tree
Showing 9 changed files with 823 additions and 591 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

# Released

## [4.0.0] 08/10/2024

### Changed

- Overhauled the CLI to use the `typer` library for a more user-friendly experience. Note this is a breaking change for CLI users. Run `pylette --help` for more information.

## [3.0.2] 04/10/2024

### Fixed
Expand Down
116 changes: 57 additions & 59 deletions Pylette/cmd.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,66 @@
import argparse
import pathlib
from enum import Enum

import typer

from Pylette import extract_colors


def main():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
group = parser.add_mutually_exclusive_group(required=True)

group.add_argument("--filename", help="path to image file", type=str, default=None)
group.add_argument("--image-url", help="url to the image file", type=str, default=None)

parser.add_argument(
"--mode",
help="extraction_mode (KMeans/MedianCut",
type=str,
default="KM",
choices=["KM", "MC"],
)
parser.add_argument("--n", help="the number of colors to extract", type=int, default=5)
parser.add_argument(
"--sort_by",
help="sort by luminance or frequency",
default="luminance",
type=str,
choices=["luminance", "frequency"],
)
parser.add_argument(
"--stdout",
help="whether to display the extracted color values in the stdout",
type=bool,
default=True,
)
parser.add_argument(
"--colorspace",
help="color space to represent colors in",
default="rgb",
type=str,
choices=["rgb", "hsv", "hls"],
)
parser.add_argument("--out_filename", help="where to save the csv file", default=None, type=str)
parser.add_argument(
"--display-colors",
help="Open a window displaying the extracted palette",
default=False,
type=bool,
)
args = parser.parse_args()

if args.filename is None and args.image_url is None:
raise ValueError("Please provide either a filename or an image-url.")

if args.filename is not None and args.image_url is not None:
raise ValueError("Please provide either a filename or an image-url, not both.")

if args.filename is not None and args.image_url is None:
image = args.filename
class ExtractionMode(str, Enum):
KM = "KM"
MC = "MC"


class SortBy(str, Enum):
frequency = "frequency"
luminance = "luminance"


class ColorSpace(str, Enum):
rgb = "rgb"
hsv = "hsv"
hls = "hls"


pylette_app = typer.Typer()


@pylette_app.command(no_args_is_help=True)
def main(
filename: pathlib.Path | None = None,
image_url: str | None = None,
mode: ExtractionMode = ExtractionMode.KM,
n: int = 5,
sort_by: SortBy = SortBy.luminance,
stdout: bool = True,
out_filename: pathlib.Path | None = None,
display_colors: bool = False,
colorspace: ColorSpace = ColorSpace.rgb,
):
if filename is None and image_url is None:
typer.echo("Please provide either a filename or an image-url.")
raise typer.Exit(code=1)

if filename is not None and image_url is not None:
typer.echo("Please provide either a filename or an image-url, but not both.")
raise typer.Exit(code=1)

image: pathlib.Path | str | None
if filename is not None and image_url is None:
image = filename
else:
image = args.image_url
image = image_url

palette = extract_colors(image=image, palette_size=args.n, sort_mode=args.sort_by)
palette.to_csv(filename=args.out_filename, frequency=True, stdout=args.stdout, colorspace=args.colorspace)
if args.display_colors:
output_file_path = str(out_filename) if out_filename is not None else None
palette = extract_colors(image=image, palette_size=n, sort_mode=sort_by.value, mode=mode.value)
palette.to_csv(filename=output_file_path, frequency=True, stdout=stdout, colorspace=colorspace.value)
if display_colors:
palette.display()


if __name__ == "__main__":
main()
def docs():
typer.launch("https://qtiptip.github.io/Pylette/")


def main_typer() -> None:
pylette_app()
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,28 @@ random_colors = palette.random_color(N=100, mode='frequency')
This will give you a palette of 10 colors, sorted by frequency.
The image is automatically resized to 256x256 pixels for faster processing.
See the [documentation](https://qtiptip.github.io/Pylette) for a complete list of available methods and attributes.

## Command Line Interface:

Pylette also comes with a command-line interface for quick palette extraction:

```shell
pylette --help

Usage: pylette [OPTIONS]

╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --filename PATH [default: None] │
│ --image-url TEXT [default: None] │
│ --mode [KM|MC] [default: KM] │
│ --n INTEGER [default: 5] │
│ --sort-by [frequency|luminance] [default: luminance] │
│ --stdout --no-stdout [default: stdout] │
│ --out-filename PATH [default: None] │
│ --display-colors --no-display-colors [default: no-display-colors] │
│ --colorspace [rgb|hsv|hls] [default: rgb] │
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or customize the installation. │
│ --help Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
54 changes: 29 additions & 25 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,39 +89,43 @@ See the [reference documentation](reference.md) for a complete list of available
Pylette also comes with a handy command-line tool. Here's a quick overview of its usage:

!!! example "Command Line Usage"

=== "Extracting a Color Palette using the CLI"
=== "Options"

```bash
pylette --filename image.jpg --mode KM --n 5 --sort_by luminance --colorspace rgb --display-colors True
```

=== "Options"
pylette --help

Usage: pylette [OPTIONS]

╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --filename PATH [default: None] │
│ --image-url TEXT [default: None] │
│ --mode [KM|MC] [default: KM] │
│ --n INTEGER [default: 5] │
│ --sort-by [frequency|luminance] [default: luminance] │
│ --stdout --no-stdout [default: stdout] │
│ --out-filename PATH [default: None] │
│ --display-colors --no-display-colors [default: no-display-colors] │
│ --colorspace [rgb|hsv|hls] [default: rgb] │
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or customize the installation. │
│ --help Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```
=== "Example"

```bash
╰─❯ pylette --help
usage: pylette [-h] (--filename FILENAME | --image-url IMAGE_URL) [--mode {KM,MC}] [--n N] [--sort_by {luminance,frequency}] [--stdout STDOUT] [--colorspace {rgb,hsv,hls}] [--out_filename OUT_FILENAME]
[--display-colors DISPLAY_COLORS]

options:
-h, --help show this help message and exit
--filename FILENAME path to image file (default: None)
--image-url IMAGE_URL
url to the image file (default: None)
--mode {KM,MC} extraction_mode (KMeans/MedianCut (default: KM)
--n N the number of colors to extract (default: 5)
--sort_by {luminance,frequency}
sort by luminance or frequency (default: luminance)
--stdout STDOUT whether to display the extracted color values in the stdout (default: True)
--colorspace {rgb,hsv,hls}
color space to represent colors in (default: RGB)
--out_filename OUT_FILENAME
where to save the csv file (default: None)
--display-colors DISPLAY_COLORS
Open a window displaying the extracted palette (default: False)

pylette --filename image.jpg \
--mode KM \
--n 5 \
--sort-by luminance \
--colorspace rgb \
--display-colors
```



## Example Palettes

Check out these palettes extracted using Pylette! The top row corresponds to extraction using K-Means, and the bottom
Expand Down
Loading

0 comments on commit ffd63af

Please sign in to comment.