Skip to content

Commit

Permalink
CTX-6123: Created new base_group and base_command that will serve as …
Browse files Browse the repository at this point in the history
…click.group and click.command decorator with slight changes that serve our needs. onBeforeCommandExecute callback is deleted all functionality is now in base_group and base_command. Minor code cleanup in scope of this task (unused imports etc.)
  • Loading branch information
Bogdan Tintor committed Aug 29, 2024
1 parent c6fff72 commit 628274b
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 127 deletions.
76 changes: 76 additions & 0 deletions coretex/cli/commands/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright (C) 2023 Coretex LLC

# This file is part of Coretex.ai

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from typing import Optional, Any, Callable, List, Tuple
from functools import wraps

import click

from ..settings import CLISettings


def base_group(
name: Optional[str] = None,
initFuncs: Optional[List[Tuple[Callable[[], None], List[str]]]] = None,
**attrs: Any
) -> Callable[..., Any]:

def decorator(group: Callable[..., Any]) -> Callable[..., Any]:

@wraps(group)
def wrapper(*args: Any, **kwargs: Any) -> Any:
ctx = click.get_current_context()

# Execute initialization functions if provided
if initFuncs:
for initFunc, excludedSubs in initFuncs:
if ctx.invoked_subcommand not in excludedSubs:
initFunc()

# Call the main group function
return group(*args, **kwargs)

return click.group(name = name, **attrs)(wrapper) # type: ignore

return decorator


def base_command(
name: Optional[str] = None,
cls: Any = None,
initFuncs: Optional[List[Callable[[], None]]] = None,
**attrs: Any
) -> Callable[..., Any]:
def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
f = click.option("--verbose", is_flag = True, help = "Enables verbose mode")(f)

@wraps(f)
def wrapper(*args: Any, **kwargs: Any) -> Any:
# Handle the verbose option
CLISettings.verbose = kwargs.pop("verbose", False)

# Execute initialization functions if provided
if initFuncs:
for initFunc in initFuncs:
initFunc()

# Call the main command function
return f(*args, **kwargs)

return click.command(name = name, cls=cls, **attrs)(wrapper) # type: ignore

return decorator
37 changes: 0 additions & 37 deletions coretex/cli/commands/base_command.py

This file was deleted.

5 changes: 2 additions & 3 deletions coretex/cli/commands/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import click

from .base import base_command
from ..modules import user, ui
from ...configuration import UserConfiguration, InvalidConfiguration, ConfigurationNotFound, utils


@click.command()
@base_command()
def login() -> None:
try:
userConfig = UserConfiguration.load()
Expand Down
7 changes: 3 additions & 4 deletions coretex/cli/commands/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import click

from .base import base_group, base_command
from ..modules import ui
from ..modules.project_utils import getProject
from ..modules.user import initializeUserSession
from ..modules.utils import onBeforeCommandExecute
from ...entities import Model
from ...configuration import UserConfiguration


@click.command()
@base_command()
@click.argument("path", type = click.Path(exists = True, file_okay = False, dir_okay = True))
@click.option("-n", "--name", type = str, required = True)
@click.option("-p", "--project", type = str, required = False, default = None)
Expand All @@ -34,8 +34,7 @@ def create(name: str, path: str, project: Optional[str], accuracy: float) -> Non
ui.stdEcho(f"A new model has been created. You can open it by clicking on this URL {ui.outputUrl(userConfig.frontendUrl, model.entityUrl())}.")


@click.group()
@onBeforeCommandExecute(initializeUserSession)
@base_group(initFuncs = [(initializeUserSession, [])])
def model() -> None:
pass

Expand Down
32 changes: 16 additions & 16 deletions coretex/cli/commands/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from typing import Optional
from pathlib import Path

import click

from .base_command import base_command
from .base import base_group, base_command
from ..modules import ui
from ..modules import node as node_module
from ..modules.node import NodeStatus, getNodeStatus
from ..modules.user import initializeUserSession
from ..modules.utils import onBeforeCommandExecute, checkEnvironment
from ..modules.utils import checkEnvironment
from ..modules.update import activateAutoUpdate
from ...utils import docker
from ...configuration import NodeConfiguration, InvalidConfiguration, ConfigurationNotFound


@base_command()
@base_command(initFuncs = [node_module.initializeNodeConfiguration])
@click.option("--image", type = str, help = "Docker image url")
@onBeforeCommandExecute(node_module.initializeNodeConfiguration)
def start(image: Optional[str]) -> None:
nodeConfig = NodeConfiguration.load()

Expand Down Expand Up @@ -66,7 +64,7 @@ def start(image: Optional[str]) -> None:
activateAutoUpdate()


@click.command()
@base_command()
def stop() -> None:
nodeConfig = NodeConfiguration.load()

Expand All @@ -77,10 +75,9 @@ def stop() -> None:
node_module.stop(nodeConfig.id)


@click.command()
@base_command(initFuncs = [node_module.initializeNodeConfiguration])
@click.option("-y", "autoAccept", is_flag = True, help = "Accepts all prompts.")
@click.option("-n", "autoDecline", is_flag = True, help = "Declines all prompts.")
@onBeforeCommandExecute(node_module.initializeNodeConfiguration)
def update(autoAccept: bool, autoDecline: bool) -> None:
if autoAccept and autoDecline:
ui.errorEcho("Only one of the flags (\"-y\" or \"-n\") can be used at the same time.")
Expand Down Expand Up @@ -142,7 +139,7 @@ def update(autoAccept: bool, autoDecline: bool) -> None:
activateAutoUpdate()


@click.command()
@base_command()
@click.option("--advanced", is_flag = True, help = "Configure node settings manually.")
def config(advanced: bool) -> None:
if node_module.isRunning():
Expand Down Expand Up @@ -181,7 +178,7 @@ def config(advanced: bool) -> None:
activateAutoUpdate()


@click.command()
@base_command()
def status() -> None:
nodeStatus = getNodeStatus()
statusColors = {
Expand All @@ -194,7 +191,7 @@ def status() -> None:
click.echo(f"Node is {statusEcho}.")


@click.command()
@base_command()
@click.option("--tail", "-n", type = int, help = "Shows N last logs.")
@click.option("--follow", "-f", is_flag = True, help = "Displays logs realtime.")
@click.option("--timestamps", "-t", is_flag = True, help = "Displays timestamps for logs.")
Expand All @@ -206,11 +203,14 @@ def logs(tail: Optional[int], follow: bool, timestamps: bool) -> None:
node_module.showLogs(tail, follow, timestamps)


@click.group()
@onBeforeCommandExecute(docker.isDockerAvailable, excludeSubcommands = ["status"])
@onBeforeCommandExecute(initializeUserSession)
@onBeforeCommandExecute(node_module.checkResourceLimitations, excludeSubcommands = ["status"])
@onBeforeCommandExecute(checkEnvironment)
@base_group(
initFuncs = [
(docker.isDockerAvailable, ["status"]),
(initializeUserSession, []),
(node_module.checkResourceLimitations, ["status"]),
(checkEnvironment, [])
]
)
def node() -> None:
pass

Expand Down
11 changes: 5 additions & 6 deletions coretex/cli/commands/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@

import click

from .base import base_group, base_command
from ..modules import ui, project_utils
from ..modules.user import initializeUserSession
from ..modules.utils import onBeforeCommandExecute
from ...entities import Project, ProjectVisibility
from ...networking import RequestFailedError
from ...configuration import UserConfiguration


@click.command()
@base_command()
@click.option("--name", "-n", type = str, help = "Project name")
@click.option("--type", "-t", "projectType", type = int, help = "Project type")
@click.option("--description", "-d", type = str, help = "Project description")
Expand All @@ -41,7 +41,7 @@ def create(name: Optional[str], projectType: Optional[int], description: Optiona
ui.successEcho(f"Project \"{project.name}\" successfully selected.")


@click.command()
@base_command()
@click.option("--project", "-p", type = str, help = "Project name")
@click.option("--name", "-n", type = str, help = "New Project name")
@click.option("--description", "-d", type = str, help = "New Project description")
Expand Down Expand Up @@ -72,7 +72,7 @@ def edit(project: Optional[str], name: Optional[str], description: Optional[str]
raise click.ClickException(f"Failed to edit project \"{selectedProject.name}\".")


@click.command()
@base_command()
@click.argument("name", type = str)
def select(name: str) -> None:
project: Optional[Project] = None
Expand All @@ -97,8 +97,7 @@ def select(name: str) -> None:
userConfig.selectProject(project.id)


@click.group()
@onBeforeCommandExecute(initializeUserSession)
@base_group(initFuncs = [(initializeUserSession, [])])
def project() -> None:
pass

Expand Down
9 changes: 3 additions & 6 deletions coretex/cli/commands/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@
import click
import webbrowser

from .base import base_group, base_command
from ..modules import ui
from ..modules.project_utils import getProject
from ..modules.user import initializeUserSession
from ..modules.utils import onBeforeCommandExecute
from ..modules.project_utils import getProject
from ..._folder_manager import folder_manager
from ..._task import TaskRunWorker, executeRunLocally, readTaskConfig, runLogger
from ...configuration import UserConfiguration
from ...entities import TaskRun, TaskRunStatus
from ...resources import PYTHON_ENTRY_POINT_PATH
Expand All @@ -37,7 +35,7 @@ class RunException(Exception):
pass


@click.command()
@base_command()
@click.argument("path", type = click.Path(exists = True, dir_okay = False))
@click.option("--name", type = str, default = None)
@click.option("--description", type = str, default = None)
Expand Down Expand Up @@ -112,8 +110,7 @@ def run(path: str, name: Optional[str], description: Optional[str], snapshot: bo
folder_manager.clearTempFiles()


@click.group()
@onBeforeCommandExecute(initializeUserSession)
@base_group(initFuncs = [(initializeUserSession, [])])
def task() -> None:
pass

Expand Down
10 changes: 4 additions & 6 deletions coretex/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from typing import Optional
from importlib.metadata import version as getLibraryVersion

import click

from .commands.base import base_group, base_command
from .commands.login import login
from .commands.model import model
from .commands.node import node
Expand All @@ -31,13 +31,13 @@
from ..utils.process import CommandException


@click.command()
@base_command()
def version() -> None:
version = getLibraryVersion("coretex")
ui.stdEcho(f"Coretex {version}")


@click.command()
@base_command()
def update() -> None:
currentVersion = utils.fetchCurrentVersion()
latestVersion = utils.fetchLatestVersion()
Expand All @@ -59,9 +59,7 @@ def update() -> None:
ui.stdEcho("Coretex version is up to date.")


# @click.group(cls = ClickExceptionInterceptor)
@click.group()
@utils.onBeforeCommandExecute(utils.checkLibVersion, excludeSubcommands = ["update"])
@base_group(cls = ClickExceptionInterceptor, initFuncs = [(utils.checkLibVersion, ["update"])])
@click.version_option(getLibraryVersion("coretex"), "--version", "-v", message = "Coretex %(version)s")
def cli() -> None:
pass
Expand Down
6 changes: 2 additions & 4 deletions coretex/cli/modules/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@

from . import ui
from .utils import isGPUAvailable
from .ui import progressEcho, successEcho
from ...node import NodeMode
from ..settings import CLISettings
from ...cryptography import rsa
from ...networking import networkManager, NetworkRequestError
Expand All @@ -51,10 +49,10 @@ class ImageType(Enum):

def pull(image: str) -> None:
try:
progressEcho(f"Fetching image {image}...")
ui.progressEcho(f"Fetching image {image}...")
docker.imagePull(image, CLISettings.verbose)

successEcho(f"Image {image} successfully fetched.")
ui.successEcho(f"Image {image} successfully fetched.")
except BaseException as ex:
logging.getLogger("cli").debug(ex, exc_info = ex)
raise NodeException("Failed to fetch latest node version.")
Expand Down
Loading

0 comments on commit 628274b

Please sign in to comment.