Skip to content

Commit

Permalink
Added quiet output mode option for CLI change command. Added verbose …
Browse files Browse the repository at this point in the history
…and json output mode options for CLI view command.
  • Loading branch information
willynilly committed Apr 8, 2024
1 parent 8f2f9fe commit 157db3b
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 98 deletions.
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ keywords:
- pyproject.toml
- CITATION.cff
license: Apache-2.0
version: "3.1.1"
version: "3.1.2"
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "cff2toml"
version = "3.1.1"
version = "3.1.2"
description = "A module to synchronize metadata between TOML and CFF files, including between pyproject.toml and CITATION.cff files."
readme = "README.md"
requires-python = ">=3.8"
Expand Down
24 changes: 12 additions & 12 deletions src/cff2toml/cli/about_command/about_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,40 @@
from cff2toml.models.agents.authors.cff_person_author import CffPersonAuthor
from cff2toml.models.files.cff_file import CffFile

app_about: typer.Typer = typer.Typer(no_args_is_help=True)
from rich import print


@app_about.command("about")
def about():
def about_command(ctx: typer.Context):
"""
Get version and other information about cff2toml
"""
current_dir: str = os.path.dirname(os.path.abspath(__file__))
citation_cff_file_path: str = os.path.join(
current_dir, '..', 'CITATION.cff') # in distribution folder
current_dir, '..', '..', 'CITATION.cff') # in distribution folder
if not os.path.isfile(path=citation_cff_file_path):
citation_cff_file_path = os.path.join(
current_dir, '..', '..', '..', 'CITATION.cff')
current_dir, '..', '..', '..', '..', 'CITATION.cff')
if not os.path.isfile(path=citation_cff_file_path):
raise Exception('Cannot find the CITATION.cff file.')

cff_file: CffFile = CffFile(
file_path=citation_cff_file_path)
print("")
print(f"[bold green]{cff_file.metadata_title}[/bold green]")
print(
f"[yellow]title[/yellow]: [bold green]{cff_file.metadata_title}[/bold green]")
print(
f"[yellow]version[/yellow]: {cff_file.metadata_version}")
print(f"[yellow]description[/yellow]: {cff_file.metadata_abstract}")
print(f"[yellow]license[/yellow]: {cff_file.metadata_license}")
print(
f"[yellow]repository url[/yellow]: [link={cff_file.metadata_repository_code}]{cff_file.metadata_repository_code}[/link]")
print(f"[yellow]authors:[/yellow]")
author_markups: list[str] = []
for author in cff_file.authors:
print("")
if isinstance(author, CffPersonAuthor):
print(
f"[green]{author.format_full_name()}[/green] {'[yellow]<[/yellow]' + author.email + '[yellow]>[/yellow]' if author.email else ''}")
author_markup = f"[green]{author.format_full_name()}[/green] {'[yellow]<[/yellow]' + author.email + '[yellow]>[/yellow]' if author.email else ''}"
author_markups.append(author_markup)
elif isinstance(author, CffEntityAuthor):
print(
f"[green]{author.name}[/green] {'[yellow]<[/yellow]' + author.email + '[yellow]>[/yellow]' if author.email else ''}")
author_markup = f"[green]{author.name}[/green] {'[yellow]<[/yellow]' + author.email + '[yellow]>[/yellow]' if author.email else ''}"
author_markups.append(author_markup)
print(f"[yellow]authors:[/yellow] " + ' '.join(author_markups))
print("")
24 changes: 20 additions & 4 deletions src/cff2toml/cli/app.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
from typing_extensions import Annotated
import typer
from cff2toml.cli.about_command.about_command import app_about
from cff2toml.cli.about_command.about_command import about_command
from cff2toml.cli.change_command.change_command import app_change
from cff2toml.cli.context_helpers import TyperContextDictionary
from cff2toml.cli.view_command.view_command import app_view

app = typer.Typer(no_args_is_help=True)

app.add_typer(app_about, name="about",
help="View information about cff2toml.")

# if you ever want to add a parameter that works without having to invoke a command
# then you need to use the 'invoke_without_command=True' argument for the callback decorator
# https://typer.tiangolo.com/tutorial/commands/context/

@app.callback()
def main(ctx: typer.Context, quiet: Annotated[bool, typer.Option(help="Hidden output mode (Only for 'change' command)")] = False, verbose: Annotated[bool, typer.Option(help="Verbose output mode")] = False, json: Annotated[bool, typer.Option(help="JSON output mode")] = False):
d = TyperContextDictionary(ctx=ctx)
d.set('quiet', quiet)
d.set('verbose', verbose)
d.set('json', json)


@app.command(name="about", help="View information about cff2toml.")
def about(ctx: typer.Context):
about_command(ctx=ctx)


app.add_typer(app_change, name="change",
help="Change metadata for both CITATION.cff and pyproject.toml files.")
help="Change metadata to specific value for both CITATION.cff and pyproject.toml files.")

app.add_typer(app_view, name="view",
help="View metadata for both CITATION.cff and pyproject.toml files.")
71 changes: 41 additions & 30 deletions src/cff2toml/cli/change_command/change_command.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import typer
from typing_extensions import Annotated

from cff2toml.cli.context_helpers import is_quiet_output
from cff2toml.models.files.cff_file import DEFAULT_CITATION_CFF_FILE_PATH, CffFile
from cff2toml.models.files.pyproject_toml_file import DEFAULT_PYPROJECT_TOML_FILE_PATH, PyprojectTomlFile
from cff2toml.models.files.synchronizers.cff_and_pyproject_toml_file_synchronizer import CffAndPyprojectTomlFileSynchronizer

from rich import print

app_change = typer.Typer(no_args_is_help=True)


@app_change.command("version")
def change_version(version: Annotated[str, typer.Argument()],
def change_version(ctx: typer.Context, version: Annotated[str, typer.Argument(help="version")],
cff_file_path: Annotated[str, typer.Option(help="CFF file path"
)] = DEFAULT_CITATION_CFF_FILE_PATH,
pyproject_toml_path: Annotated[str, typer.Option(help="pyproject.toml file path")] = DEFAULT_PYPROJECT_TOML_FILE_PATH):
Expand All @@ -24,15 +27,16 @@ def change_version(version: Annotated[str, typer.Argument()],
cff_file=cff_file, pyproject_toml_file=pyproject_toml_file)
file_sync.set_version(version=version)
file_sync.save()
print(f"[yellow]changing version metadata...[/yellow]")
print(
f"[green]changed version for[/green] {cff_file.file_path} to [green]{version}[/green]")
print(
f"[green]changed version for[/green] {pyproject_toml_file.file_path} to [green]{version}[/green]")
if not is_quiet_output(ctx=ctx):
print(f"[yellow]changing version metadata...[/yellow]")
print(
f"[green]changed version for[/green] {cff_file.file_path} to [green]{version}[/green]")
print(
f"[green]changed version for[/green] {pyproject_toml_file.file_path} to [green]{version}[/green]")


@app_change.command("license")
def change_license(license: Annotated[str, typer.Argument()],
def change_license(ctx: typer.Context, license: Annotated[str, typer.Argument()],
cff_file_path: Annotated[str, typer.Option(help="CFF file path"
)] = DEFAULT_CITATION_CFF_FILE_PATH,
pyproject_toml_path: Annotated[str, typer.Option(help="pyproject.toml file path")] = DEFAULT_PYPROJECT_TOML_FILE_PATH):
Expand All @@ -47,15 +51,17 @@ def change_license(license: Annotated[str, typer.Argument()],
cff_file=cff_file, pyproject_toml_file=pyproject_toml_file)
file_sync.set_license(license=license)
file_sync.save()
print(f"[yellow]changing license metadata...[/yellow]")
print(
f"[green]changed license for[/green] {cff_file.file_path} to [green]{license}[/green]")
print(
f"[green]changed license for [/green] {pyproject_toml_file.file_path} to [green]{license}[/green]")
if not is_quiet_output(ctx=ctx):
print(f"[yellow]changing license metadata...[/yellow]")
print(
f"[green]changed license for[/green] {cff_file.file_path} to [green]{license}[/green]")
print(
f"[green]changed license for [/green] {pyproject_toml_file.file_path} to [green]{license}[/green]")


@app_change.command("title")
def change_title(title: Annotated[str, typer.Argument()],
def change_title(ctx: typer.Context,
title: Annotated[str, typer.Argument()],
cff_file_path: Annotated[str, typer.Option(help="CFF file path"
)] = DEFAULT_CITATION_CFF_FILE_PATH,
pyproject_toml_path: Annotated[str, typer.Option(help="pyproject.toml file path")] = DEFAULT_PYPROJECT_TOML_FILE_PATH):
Expand All @@ -70,15 +76,17 @@ def change_title(title: Annotated[str, typer.Argument()],
cff_file=cff_file, pyproject_toml_file=pyproject_toml_file)
file_sync.set_title(title=title)
file_sync.save()
print(f"[yellow]changing title metadata...[/yellow]")
print(
f"[green]changed title for[/green] {cff_file.file_path} to [green]{title}[/green]")
print(
f"[green]changed title for [/green] {pyproject_toml_file.file_path} to [green]{title}[/green]")
if not is_quiet_output(ctx=ctx):
print(f"[yellow]changing title metadata...[/yellow]")
print(
f"[green]changed title for[/green] {cff_file.file_path} to [green]{title}[/green]")
print(
f"[green]changed title for [/green] {pyproject_toml_file.file_path} to [green]{title}[/green]")


@app_change.command("description")
def change_description(description: Annotated[str, typer.Argument()],
def change_description(ctx: typer.Context,
description: Annotated[str, typer.Argument()],
cff_file_path: Annotated[str, typer.Option(help="CFF file path"
)] = DEFAULT_CITATION_CFF_FILE_PATH,
pyproject_toml_path: Annotated[str, typer.Option(help="pyproject.toml file path")] = DEFAULT_PYPROJECT_TOML_FILE_PATH):
Expand All @@ -93,15 +101,17 @@ def change_description(description: Annotated[str, typer.Argument()],
cff_file=cff_file, pyproject_toml_file=pyproject_toml_file)
file_sync.set_description(description=description)
file_sync.save()
print(f"[yellow]changing description metadata...[/yellow]")
print(
f"[green]changed description for[/green] {cff_file.file_path} to [green]{description}[/green]")
print(
f"[green]changed description for [/green] {pyproject_toml_file.file_path} to [green]{description}[/green]")
if not is_quiet_output(ctx=ctx):
print(f"[yellow]changing description metadata...[/yellow]")
print(
f"[green]changed description for[/green] {cff_file.file_path} to [green]{description}[/green]")
print(
f"[green]changed description for [/green] {pyproject_toml_file.file_path} to [green]{description}[/green]")


@app_change.command("repo")
def change_code_repository_url(code_repository_url: Annotated[str, typer.Argument()],
def change_code_repository_url(ctx: typer.Context,
code_repository_url: Annotated[str, typer.Argument()],
cff_file_path: Annotated[str, typer.Option(help="CFF file path"
)] = DEFAULT_CITATION_CFF_FILE_PATH,
pyproject_toml_path: Annotated[str, typer.Option(help="pyproject.toml file path")] = DEFAULT_PYPROJECT_TOML_FILE_PATH):
Expand All @@ -117,8 +127,9 @@ def change_code_repository_url(code_repository_url: Annotated[str, typer.Argumen
file_sync.set_code_repository_url(
code_repository_url=code_repository_url)
file_sync.save()
print(f"[yellow]changing code_repository_url metadata...[/yellow]")
print(
f"[green]changed code_repository_url for[/green] {cff_file.file_path} to [green]{code_repository_url}[/green]")
print(
f"[green]changed code_repository_url for [/green] {pyproject_toml_file.file_path} to [green]{code_repository_url}[/green]")
if not is_quiet_output(ctx=ctx):
print(f"[yellow]changing code_repository_url metadata...[/yellow]")
print(
f"[green]changed code_repository_url for[/green] {cff_file.file_path} to [green]{code_repository_url}[/green]")
print(
f"[green]changed code_repository_url for [/green] {pyproject_toml_file.file_path} to [green]{code_repository_url}[/green]")
36 changes: 36 additions & 0 deletions src/cff2toml/cli/command_metadata_output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import Any

from pydantic import BaseModel
from cff2toml.models.files.cff_file import CffFile
from cff2toml.models.files.pyproject_toml_file import PyprojectTomlFile
from cff2toml.models.files.synchronizers.cff_and_pyproject_toml_file_synchronizer import PROPERTY_MAPPINGS


class CommandMetadataOutput(BaseModel):
command: str
cff_file_path: str
pyproject_toml_file_path: str
common_metadata_name: str
cff_file_metadata_name: str = ''
cff_file_metadata_value_before_command: Any = ''
cff_file_metadata_value_after_command: Any = ''
pyproject_toml_file_metadata_name: str = ''
pyproject_toml_file_metadata_value_before_command: Any = ''
pyproject_toml_file_metadata_value_after_command: Any = ''

def setup(self):
cff_file = CffFile(file_path=self.cff_file_path)
pyproject_toml_file = PyprojectTomlFile(
file_path=self.pyproject_toml_file_path)
self.pyproject_toml_file_metadata_name = PROPERTY_MAPPINGS[self.common_metadata_name][0]
self.cff_file_metadata_name = PROPERTY_MAPPINGS[self.common_metadata_name][1]
self.cff_file_metadata_value_before_command = cff_file.get_metadata(
self.cff_file_metadata_name, '')
self.pyproject_toml_file_metadata_value_before_command = pyproject_toml_file.get_metadata(
self.pyproject_toml_file_metadata_name)
self.cff_file_metadata_value_after_command = self.cff_file_metadata_value_before_command
self.pyproject_toml_file_metadata_value_after_command = self.pyproject_toml_file_metadata_value_before_command

def set_after_value(self, value: Any) -> None:
self.cff_file_metadata_value_after_command = value
self.pyproject_toml_file_metadata_value_after_command = value
39 changes: 39 additions & 0 deletions src/cff2toml/cli/context_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from typing import Any
import typer


class TyperContextDictionary:

_d: dict

def __init__(self, ctx: typer.Context):
if not isinstance(ctx.obj, dict):
ctx.obj = dict()
self._d = ctx.obj

def has(self, key: str) -> bool:
return key in self._d

def get(self, key: str, default_value: Any = None):
if key in self._d:
return self._d[key]
else:
return default_value

def set(self, key: str, value: Any):
self._d[key] = value


def is_quiet_output(ctx: typer.Context):
d = TyperContextDictionary(ctx=ctx)
return d.get(key='quiet', default_value=False)


def is_verbose_output(ctx: typer.Context):
d = TyperContextDictionary(ctx=ctx)
return d.get(key='verbose', default_value=False)


def is_json_output(ctx: typer.Context):
d = TyperContextDictionary(ctx=ctx)
return d.get(key='json', default_value=False)
Loading

0 comments on commit 157db3b

Please sign in to comment.