From d73d140405fdb6db9ae8f2c2ce4b22484ccf750d Mon Sep 17 00:00:00 2001 From: Reinder Vos de Wael Date: Tue, 19 Dec 2023 14:04:56 -0500 Subject: [PATCH] Fixes the version detection, renames to cloai (#6) --- CONTRIBUTING.md | 4 ++-- README.md | 24 ++++++++++++------------ pyproject.toml | 8 ++++---- src/{oai => cloai}/__init__.py | 0 src/{oai => cloai}/__main__.py | 4 ++-- src/{oai => cloai}/cli/__init__.py | 0 src/{oai => cloai}/cli/commands.py | 6 +++--- src/{oai => cloai}/cli/parser.py | 13 +++++++------ src/{oai => cloai}/cli/utils.py | 2 +- src/cloai/core/__init__.py | 1 + src/{oai => cloai}/core/config.py | 15 ++++++++++++--- src/{oai => cloai}/core/exceptions.py | 2 +- src/{oai => cloai}/openai_api.py | 2 +- src/oai/core/__init__.py | 1 - tests/unit/test___main__.py | 19 +++++++++++++++++++ tests/unit/test_cli_utils.py | 8 +++----- tests/unit/test_openai_api.py | 7 +++++-- tests/unit/test_parser.py | 24 +++++++++++------------- 18 files changed, 84 insertions(+), 56 deletions(-) rename src/{oai => cloai}/__init__.py (100%) rename src/{oai => cloai}/__main__.py (81%) rename src/{oai => cloai}/cli/__init__.py (100%) rename src/{oai => cloai}/cli/commands.py (97%) rename src/{oai => cloai}/cli/parser.py (97%) rename src/{oai => cloai}/cli/utils.py (98%) create mode 100644 src/cloai/core/__init__.py rename src/{oai => cloai}/core/config.py (81%) rename src/{oai => cloai}/core/exceptions.py (95%) rename src/{oai => cloai}/openai_api.py (99%) delete mode 100644 src/oai/core/__init__.py create mode 100644 tests/unit/test___main__.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5e39e3e..d774e82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# cli-oai pull request guidelines +# cli-cloai pull request guidelines -Pull requests are always welcome, and we appreciate any help you give. Note that a code of conduct applies to all spaces managed by the cli-oai project, including issues and pull requests. Please see the [Code of Conduct](CODE_OF_CONDUCT.md) for details. +Pull requests are always welcome, and we appreciate any help you give. Note that a code of conduct applies to all spaces managed by the cli-cloai project, including issues and pull requests. Please see the [Code of Conduct](CODE_OF_CONDUCT.md) for details. When submitting a pull request, we ask you to check the following: diff --git a/README.md b/README.md index ff4071f..60b0e06 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,30 @@ -# CLI-OAI +# CLI-cloai -CLI-OAI is a Python command-line interface for interacting with the OpenAI API. It provides a set of commands to interact with various OpenAI services such as Speech-to-Text (STT), Text-to-Speech (TTS), and Image Generation. +CLI-cloai is a Python command-line interface for interacting with the OpenAI API. It provides a set of commands to interact with various OpenAI services such as Speech-to-Text (STT), Text-to-Speech (TTS), and Image Generation. ## Installation -To install CLI-OAI, you can use the following command: +To install CLI-cloai, you can use the following command: ```sh -poetry add git+https://github.com/cmi-dair/cli-oai +poetry add git+https://github.com/cmi-dair/cli-cloai ``` ## Usage -Before running CLI-OAI, make sure the environment variable `OPENAI_API_KEY` is set to your OpenAI API key. +Before running CLI-cloai, make sure the environment variable `OPENAI_API_KEY` is set to your OpenAI API key. -To use the CLI, run `oai --help` in your terminal. This will display a list of available commands and their descriptions. +To use the CLI, run `cloai --help` in your terminal. This will display a list of available commands and their descriptions. Here is a brief overview of the main commands: -- `oai stt `: Transcribes audio files with OpenAI's STT models. The `filename` argument is the file to transcribe. It can be any format that ffmpeg supports. Use the `--clip` option to clip the file if it is too large. +- `cloai stt `: Transcribes audio files with OpenAI's STT models. The `filename` argument is the file to transcribe. It can be any format that ffmpeg supports. Use the `--clip` option to clip the file if it is too large. -- `oai tts `: Generates audio files with OpenAI's Text to Speech models. The `text` argument is the text to convert to speech. +- `cloai tts `: Generates audio files with OpenAI's Text to Speech models. The `text` argument is the text to convert to speech. -- `oai image `: Generates images with OpenAI's DALL-E. The `prompt` argument is the text prompt to generate the image from. +- `cloai image `: Generates images with OpenAI's DALL-E. The `prompt` argument is the text prompt to generate the image from. -Each command has additional options that can be viewed by running `oai --help`. +Each command has additional options that can be viewed by running `cloai --help`. ## Contributing @@ -32,8 +32,8 @@ Contributions are welcome! Please see the [contributing guidelines](CONTRIBUTING ## License -CLI-OAI is licensed under the terms of the [L-GPLv2.1 license](LICENSE). +CLI-cloai is licensed under the terms of the [L-GPLv2.1 license](LICENSE). ## Support -If you encounter any issues or have any questions, please report them on our [issues page](https://github.com/cmi-dair/cli-oai/issues). +If you encounter any issues or have any questions, please report them on our [issues page](https://github.com/cmi-dair/cli-cloai/issues). diff --git a/pyproject.toml b/pyproject.toml index 3be72f0..d9c51c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,13 +3,13 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.poetry] -name = "cmi-oai-cli" -version = "0.0.1a6" +name = "cloai" +version = "0.0.1a7" description = "A CLI for OpenAI's API" authors = ["Reinder Vos de Wael "] license = "LGPL-2.1" readme = "README.md" -packages = [{include = "oai", from = "src"}] +packages = [{include = "cloai", from = "src"}] [tool.poetry.dependencies] python = ">3.8, <4.0" @@ -43,7 +43,7 @@ pythonpath = [ ] [tool.poetry.scripts] -oai = 'oai.__main__:main' +cloai = 'cloai.__main__:main' [tool.tox] legacy_tox_ini = """ diff --git a/src/oai/__init__.py b/src/cloai/__init__.py similarity index 100% rename from src/oai/__init__.py rename to src/cloai/__init__.py diff --git a/src/oai/__main__.py b/src/cloai/__main__.py similarity index 81% rename from src/oai/__main__.py rename to src/cloai/__main__.py index adf130b..1731142 100644 --- a/src/oai/__main__.py +++ b/src/cloai/__main__.py @@ -1,4 +1,4 @@ -"""Entry point of the OAI package.""" +"""Entry point of the cloai package.""" import asyncio import os import sys @@ -10,7 +10,7 @@ def main() -> None: sys.stderr.write("Error: Please set the OPENAI_API_KEY environment variable.") sys.exit(1) - from oai.cli import parser + from cloai.cli import parser asyncio.run(parser.parse_args()) diff --git a/src/oai/cli/__init__.py b/src/cloai/cli/__init__.py similarity index 100% rename from src/oai/cli/__init__.py rename to src/cloai/cli/__init__.py diff --git a/src/oai/cli/commands.py b/src/cloai/cli/commands.py similarity index 97% rename from src/oai/cli/commands.py rename to src/cloai/cli/commands.py index 9d4d52e..5f8dcfa 100644 --- a/src/oai/cli/commands.py +++ b/src/cloai/cli/commands.py @@ -9,9 +9,9 @@ import ffmpeg -from oai import openai_api -from oai.cli import utils -from oai.core import config +from cloai import openai_api +from cloai.cli import utils +from cloai.core import config settings = config.get_settings() logger = logging.getLogger(settings.LOGGER_NAME) diff --git a/src/oai/cli/parser.py b/src/cloai/cli/parser.py similarity index 97% rename from src/oai/cli/parser.py rename to src/cloai/cli/parser.py index 55335b0..3b5dfad 100644 --- a/src/oai/cli/parser.py +++ b/src/cloai/cli/parser.py @@ -4,16 +4,15 @@ import argparse import pathlib import sys -from importlib import metadata -from oai.cli import commands -from oai.core import config, exceptions +from cloai.cli import commands +from cloai.core import config, exceptions logger = config.get_logger() PARSER_DEFAULTS = { - "epilog": "Please report issues at https://github.com/cmi-dair/cli-oai.", + "epilog": "Please report issues at https://github.com/cmi-dair/cli-cloai.", "formatter_class": argparse.ArgumentDefaultsHelpFormatter, } @@ -21,14 +20,16 @@ async def parse_args() -> None: """Parse command line arguments and execute the corresponding command.""" parser = argparse.ArgumentParser( - prog="oai", + prog="cloai", description=""" CLI wrapper for OpenAI's API. All commands require the OPENAI_API_KEY environment variable to be set to a valid OpenAI API key.""", **PARSER_DEFAULTS, # type: ignore[arg-type] ) - version = metadata.version(__package__ or __name__) + + version = config.get_version() parser.add_argument("--version", action="version", version=f"%(prog)s {version}") + subparsers = parser.add_subparsers(dest="command") _add_stt_parser(subparsers) _add_tts_parser(subparsers) diff --git a/src/oai/cli/utils.py b/src/cloai/cli/utils.py similarity index 98% rename from src/oai/cli/utils.py rename to src/cloai/cli/utils.py index 5e86895..a97301d 100644 --- a/src/oai/cli/utils.py +++ b/src/cloai/cli/utils.py @@ -9,7 +9,7 @@ import ffmpeg import requests -from oai.core import config +from cloai.core import config if TYPE_CHECKING: from collections.abc import Generator diff --git a/src/cloai/core/__init__.py b/src/cloai/core/__init__.py new file mode 100644 index 0000000..bf1c83c --- /dev/null +++ b/src/cloai/core/__init__.py @@ -0,0 +1 @@ +"""Core modules of the cloai package.""" diff --git a/src/oai/core/config.py b/src/cloai/core/config.py similarity index 81% rename from src/oai/core/config.py rename to src/cloai/core/config.py index d363d12..21ab8dc 100644 --- a/src/oai/core/config.py +++ b/src/cloai/core/config.py @@ -1,16 +1,25 @@ -"""Configuration for the oai module.""" +"""Configuration for the cloai module.""" import functools import logging +from importlib import metadata from typing import Literal import pydantic import pydantic_settings +def get_version() -> str: + """Return the version of the package.""" + try: + return metadata.version("cloai") + except metadata.PackageNotFoundError: + return "unknown" + + class Settings(pydantic_settings.BaseSettings): - """Represents the settings for the oai module.""" + """Represents the settings for the cloai module.""" - LOGGER_NAME: str = "oai" + LOGGER_NAME: str = "cloai" LOGGER_VERBOSITY: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "DEBUG" OPENAI_API_KEY: pydantic.SecretStr = pydantic.Field( diff --git a/src/oai/core/exceptions.py b/src/cloai/core/exceptions.py similarity index 95% rename from src/oai/core/exceptions.py rename to src/cloai/core/exceptions.py index b6fe183..8cb6cc2 100644 --- a/src/oai/core/exceptions.py +++ b/src/cloai/core/exceptions.py @@ -1,5 +1,5 @@ """Custom exceptions.""" -from oai.core import config +from cloai.core import config logger = config.get_logger() diff --git a/src/oai/openai_api.py b/src/cloai/openai_api.py similarity index 99% rename from src/oai/openai_api.py rename to src/cloai/openai_api.py index 42ebc46..d56db11 100644 --- a/src/oai/openai_api.py +++ b/src/cloai/openai_api.py @@ -8,7 +8,7 @@ import openai -from oai.core import config +from cloai.core import config settings = config.get_settings() OPENAI_API_KEY = settings.OPENAI_API_KEY diff --git a/src/oai/core/__init__.py b/src/oai/core/__init__.py deleted file mode 100644 index 2c257ca..0000000 --- a/src/oai/core/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Core modules of the OAI package.""" diff --git a/tests/unit/test___main__.py b/tests/unit/test___main__.py new file mode 100644 index 0000000..bdd8f46 --- /dev/null +++ b/tests/unit/test___main__.py @@ -0,0 +1,19 @@ +"""Tests for the entrypoint.""" +import os + +import pytest + +from cloai import __main__ as main + + +def test_main_no_key() -> None: + """Test case for the main function when OPENAI_API_KEY is not set. + + It verifies that the main function raises a SystemExit exception with exit code 1. + """ + del os.environ["OPENAI_API_KEY"] + + with pytest.raises(SystemExit) as exc: + main.main() + + assert exc.value.code == 1 diff --git a/tests/unit/test_cli_utils.py b/tests/unit/test_cli_utils.py index 7beeb70..5375e06 100644 --- a/tests/unit/test_cli_utils.py +++ b/tests/unit/test_cli_utils.py @@ -1,17 +1,15 @@ """Tests for the CLI utility functions.""" - - import tempfile import pytest_mock -from oai.cli import utils +from cloai.cli import utils def test_clip_audio(mocker: pytest_mock.MockerFixture) -> None: """Tests that the audio file is clipped.""" magic = mocker.MagicMock() - mock_ffmpeg = mocker.patch("oai.cli.utils.ffmpeg", magic) + mock_ffmpeg = mocker.patch("cloai.cli.utils.ffmpeg", magic) mock_ffmpeg.input.return_value = magic mock_ffmpeg.output.return_value = magic target_size = 100000 @@ -30,7 +28,7 @@ def test_clip_audio(mocker: pytest_mock.MockerFixture) -> None: def test_download_audio(mocker: pytest_mock.MockerFixture) -> None: """Tests that a file is downloaded.""" magic = mocker.MagicMock() - mock_requests = mocker.patch("oai.cli.utils.requests") + mock_requests = mocker.patch("cloai.cli.utils.requests") mock_requests.get.return_value = magic magic.raise_for_status.return_value = None magic.content = b"mock_content" diff --git a/tests/unit/test_openai_api.py b/tests/unit/test_openai_api.py index b5c1cd1..b1066ef 100644 --- a/tests/unit/test_openai_api.py +++ b/tests/unit/test_openai_api.py @@ -6,7 +6,7 @@ import pytest import pytest_mock -from oai import openai_api +from cloai import openai_api @pytest.fixture() @@ -25,7 +25,10 @@ def mock_openai(mocker: pytest_mock.MockFixture) -> mock.MagicMock: audio=mock_audio, images=mock_images, ) - return mocker.patch("oai.openai_api.openai.OpenAI", return_value=mock_client) + return mocker.patch( + "cloai.openai_api.openai.OpenAI", + return_value=mock_client, + ) class ConcreteOpenAiBaseClass(openai_api.OpenAIBaseClass): diff --git a/tests/unit/test_parser.py b/tests/unit/test_parser.py index 62540c1..1c03183 100644 --- a/tests/unit/test_parser.py +++ b/tests/unit/test_parser.py @@ -2,23 +2,23 @@ from __future__ import annotations import argparse +import os import pathlib import sys from typing import TYPE_CHECKING import pytest -from oai.cli import parser -from oai.core import exceptions +from cloai.cli import parser +from cloai.core import exceptions if TYPE_CHECKING: import pytest_mock -@pytest.fixture() -def _mock_package_metadata(mocker: pytest_mock.MockFixture) -> None: - """Mocks the package metadata.""" - mocker.patch("oai.cli.parser.metadata.version", return_value="0.0.0") +@pytest.fixture(autouse=True) +def _set_environment() -> None: + os.environ["OPENAI_API_KEY"] = "test" @pytest.mark.parametrize( @@ -182,7 +182,7 @@ async def test_run_command_with_whisper(mocker: pytest_mock.MockFixture) -> None "model": "whisper-1", } args = argparse.Namespace(**arg_dict) - mock = mocker.patch("oai.cli.commands.speech_to_text") + mock = mocker.patch("cloai.cli.commands.speech_to_text") await parser.run_command(args) @@ -206,7 +206,7 @@ async def test_run_command_with_dalle(mocker: pytest_mock.MockFixture) -> None: "n": 1, } args = argparse.Namespace(**arg_dict) - mock = mocker.patch("oai.cli.commands.image_generation") + mock = mocker.patch("cloai.cli.commands.image_generation") await parser.run_command(args) @@ -231,7 +231,7 @@ async def test_run_command_with_tts(mocker: pytest_mock.MockFixture) -> None: "voice": "onyx", } args = argparse.Namespace(**arg_dict) - mock = mocker.patch("oai.cli.commands.text_to_speech") + mock = mocker.patch("cloai.cli.commands.text_to_speech") await parser.run_command(args) @@ -244,10 +244,9 @@ async def test_run_command_with_tts(mocker: pytest_mock.MockFixture) -> None: @pytest.mark.asyncio() -@pytest.mark.usefixtures("_mock_package_metadata") async def test_parse_args_without_arguments() -> None: """Tests the parse_args function with no arguments.""" - sys.argv = ["oai"] + sys.argv = ["cloai"] expected_error_code = 1 with pytest.raises(SystemExit) as excinfo: @@ -264,12 +263,11 @@ async def test_parse_args_without_arguments() -> None: "tts", ], ) -@pytest.mark.usefixtures("_mock_package_metadata") async def test_parse_args_with_command_no_other_arguments( command: str, ) -> None: """Tests the parse_args function with a command but no other arguments.""" - sys.argv = ["oai", command] + sys.argv = ["cloai", command] expected_error_code = 2 with pytest.raises(SystemExit) as excinfo: