Passed
Push — master ( c3d045...3525ae )
by Konstantinos
01:55 queued 43s
created

artificial_artwork.cmd_demo   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 60
dl 0
loc 105
rs 10
c 0
b 0
f 0
wmc 11

2 Functions

Rating   Name   Duplication   Size   Complexity  
C validate_and_normalize_path() 0 38 9
A demo() 0 47 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A HandleAlgorithmProgressUpdatesAble.update() 0 1 1
1
from pathlib import Path
2
import typing as t
3
import click
4
5
from ._demo import create_algo_runner as init_algo_infra
6
7
8
class WithStateAttribute(t.Protocol):
9
    """Protocol for classes that have a state attribute."""
10
    state: t.Any
11
12
class HandleAlgorithmProgressUpdatesAble(t.Protocol):
13
    def update(self, subject: WithStateAttribute) -> None: ...
14
15
16
# Ask user what to do depending on whether the output folder already exists
17
def validate_and_normalize_path(ctx, param, value):
18
    """Custom function to validate and normalize a path."""
19
    if value is None:
20
        return None
21
    path = Path(value)
22
23
    if path.is_absolute():
24
        abs_path = path
25
    else:
26
        current_directory = Path.cwd()
27
        abs_path = current_directory / path
28
29
    if not abs_path.exists():
30
        abs_path.mkdir()
31
        click.echo(f'Folder "{abs_path}" created')
32
    else:
33
        # get files inside the folder
34
        folder_files = [f for f in abs_path.iterdir() if f.is_file()]
35
        if len(folder_files) > 0:
36
            # ask user whether to delete everything, process as it is or exit
37
            click.echo(f'Folder "{abs_path}" already exists and is not empty.')
38
            click.echo('What do you want to do?')
39
            click.echo('1. Delete everything and start from scratch')
40
            click.echo('2. Process the existing files')
41
            click.echo('3. Exit')
42
            choice = click.prompt('Enter your choice', type=int)
43
            if choice == 1:
44
                click.echo('Deleting everything...')
45
                for file in folder_files:
46
                    file.unlink()
47
            elif choice == 2:
48
                click.echo('Processing existing files...')
49
            elif choice == 3:
50
                click.echo('Exiting...')
51
                ctx.exit()
52
            else:
53
                raise click.BadParameter(f'Invalid choice "{choice}".')
54
    return abs_path
55
56
57
# DEMO CMD
58
@click.command()
59
@click.option('-it', '--iterations', type=int, default=100, show_default=True,
60
    help='Number of iterations to run the algorithm.')
61
@click.option('-o', '--output', 'output_folder',
62
    # type=click.Path(exists=True),
63
    type=click.Path(
64
        # exists=True,
65
        file_okay=False, dir_okay=True, resolve_path=True),
66
    default='demo-output', show_default=True,
67
    help='Location to save the generated images.',
68
    callback=validate_and_normalize_path,
69
)
70
def demo(iterations, output_folder):
71
    print("[DEBUG] output type: {}".format(type(output_folder)))
72
    click.echo(f"Running demo with {iterations} iterations and location {output_folder}.")
73
    
74
    # By default the backend adds 2 Listeners/Observers to the Subject/State object
75
    # The Subject being an object representing the current state of the Algorithm
76
    # Progress (ie current Cost Values for Jc, Js, Jt, current iteration, etc)
77
    # The backend does it by suscribing the Listeners to the Subject (see below
78
    # the subscribe_to_algorithm_progress method in case you want to add more)
79
    
80
    # One Observer configured by the backend receives updates more frequently
81
    # and it prints the Progress stats/metrics as a formatted message to the
82
    # console
83
84
    # The other Observer configured by the backend receives updates less frequently
85
    # and it saves a snapshot of the Generated image during the current iteration
86
    # to the output folder
87
    backend_objects = init_algo_infra(
88
        iterations=iterations,
89
        output_folder=output_folder
90
    )
91
92
    # destructuring the backend objects
93
    run_algorithm: t.Callable[[], None] = backend_objects['run']
94
    # subscribe_to_algorithm_progress: t.Callable[[HandleAlgorithmProgressUpdatesAble], None] = \
95
    #     backend_objects['subscribe']
96
97
    run_algorithm()
98
99
    # print a stylized message to console informing that program finished suuccessfully :)
100
101
    click.secho('Demo finished successfull :)', fg='green', bold=True)
102
    click.secho('Check the output folder for the generated images.', fg='green', bold=True)
103
    click.secho('xdg-open {}'.format(output_folder), fg='green', bold=True)
104
    click.secho('Bye!', fg='green', bold=True)
105