From ab1238422a38314908cf460e7716b00dc1430dfb Mon Sep 17 00:00:00 2001 From: Noemi <45180344+unflxw@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:27:54 +0100 Subject: [PATCH] Define `appsignal.start()` initialization method This allows for a more ergonomic replacement to the previous: ```python from __appsignal__ import appsignal appsignal.start() ``` Into a simpler: ```python import appsignal appsignal.start() ``` But, more importantly, it allows users to keep the AppSignal configuration file at the project root (where commands such as `appsignal diagnose` expect to find it) and refer it from other parts of their application (such as `project_name/wsgi.py` in a Django project) without imposing the demand for the project root to itself be a Python package. --- src/appsignal/__init__.py | 58 ++++++++++++++++++++++++++++++++++++ src/appsignal/cli/command.py | 2 +- src/appsignal/cli/config.py | 41 ------------------------- 3 files changed, 59 insertions(+), 42 deletions(-) delete mode 100644 src/appsignal/cli/config.py diff --git a/src/appsignal/__init__.py b/src/appsignal/__init__.py index 0c82f91..b810e8b 100644 --- a/src/appsignal/__init__.py +++ b/src/appsignal/__init__.py @@ -1,3 +1,8 @@ +from __future__ import annotations + +import os +from runpy import run_path + from .client import Client as Appsignal from .metrics import add_distribution_value, increment_counter, set_gauge from .tracing import ( @@ -37,9 +42,62 @@ "increment_counter", "set_gauge", "add_distribution_value", + "start", ] +# Load the AppSignal client from the app specific `__appsignal__.py` client +# file. This loads the user config, rather than our default config. +# If no client file is found it return `None`. +# If there's a problem with the client file it will raise an +# `InvalidClientFileError` with a message containing more details. +def _client_from_config_file() -> Appsignal | None: + cwd = os.getcwd() + app_config_path = os.path.join(cwd, "__appsignal__.py") + if os.path.exists(app_config_path): + try: + client = run_path(app_config_path)["appsignal"] + if not isinstance(client, Appsignal): + raise InvalidClientFileError( + "The `appsignal` variable in `__appsignal__.py` does not contain an AppSignal client. " + "Please define the configuration file as described in " + "our documentation: " + "https://docs.appsignal.com/python/configuration.html" + ) + + return client + except KeyError as error: + raise InvalidClientFileError( + "No `appsignal` variable found in `__appsignal__.py`. " + "Please define the configuration file as described in " + "our documentation: " + "https://docs.appsignal.com/python/configuration.html" + ) from error + + return None + + +def _must_client_from_config_file() -> Appsignal: + client = _client_from_config_file() + if client is None: + raise InvalidClientFileError( + "No `__appsignal__.py` file found in the current directory. " + "Please define the configuration file as described in " + "our documentation: " + "https://docs.appsignal.com/python/configuration.html" + ) + + return client + + +def start() -> None: + _must_client_from_config_file().start() + + +class InvalidClientFileError(Exception): + pass + + # Try and load the appsignal-beta package. If it's present and imported, it # will print a message about switching to the `appsignal` package. try: diff --git a/src/appsignal/cli/command.py b/src/appsignal/cli/command.py index 32afdf4..6b05891 100644 --- a/src/appsignal/cli/command.py +++ b/src/appsignal/cli/command.py @@ -8,7 +8,7 @@ from ..client import Client from ..config import Config, Options from ..push_api_key_validator import PushApiKeyValidator -from .config import _client_from_config_file +from .. import _client_from_config_file from .exit_error import ExitError diff --git a/src/appsignal/cli/config.py b/src/appsignal/cli/config.py deleted file mode 100644 index 85473b2..0000000 --- a/src/appsignal/cli/config.py +++ /dev/null @@ -1,41 +0,0 @@ -from __future__ import annotations - -import os -from runpy import run_path - -from ..client import Client - - -# Load the AppSignal client from the app specific `__appsignal__.py` client -# file. This loads the user config, rather than our default config. -# If no client file is found it return `None`. -# If there's a problem with the client file it will raise an -# `InvalidClientFileError` with a message containing more details. -def _client_from_config_file() -> Client | None: - cwd = os.getcwd() - app_config_path = os.path.join(cwd, "__appsignal__.py") - if os.path.exists(app_config_path): - try: - client = run_path(app_config_path)["appsignal"] - if not isinstance(client, Client): - raise InvalidClientFileError( - "The `appsignal` variable does not contain an AppSignal client. " - "Please define the configuration file as described in " - "our documentation: " - "https://docs.appsignal.com/python/configuration.html" - ) - - return client - except KeyError as error: - raise InvalidClientFileError( - "No `appsignal` variable found. " - "Please define the configuration file as described in " - "our documentation: " - "https://docs.appsignal.com/python/configuration.html" - ) from error - - return None - - -class InvalidClientFileError(Exception): - pass