diff --git a/cellarium/cas/__init__.py b/cellarium/cas/__init__.py index 9740146..6ce9f1d 100644 --- a/cellarium/cas/__init__.py +++ b/cellarium/cas/__init__.py @@ -1,6 +1,6 @@ from cellarium.cas.client import CASClient -from . import constants, exceptions, postprocessing, preprocessing, service, settings, version, visualization +from . import constants, exceptions, logging, postprocessing, preprocessing, service, settings, version, visualization __version__ = version.get_version() @@ -15,4 +15,5 @@ "service", "settings", "version", + "logging", ] diff --git a/cellarium/cas/client.py b/cellarium/cas/client.py index a0e6265..6c3c9e2 100644 --- a/cellarium/cas/client.py +++ b/cellarium/cas/client.py @@ -1,7 +1,6 @@ import asyncio import datetime import functools -import logging import math import operator import pkgutil @@ -15,6 +14,7 @@ from anndata import ImplicitModificationWarning from deprecated import deprecated +from cellarium.cas.logging import logger from cellarium.cas.service import action_context_manager from . import _io, constants, exceptions, models, preprocessing, service, settings, version @@ -71,7 +71,7 @@ def __init__( api_token=api_token, api_url=api_url, client_session_id=self.client_session_id ) - logging.info(f"Connecting to the Cellarium Cloud backend with session {self.client_session_id}...") + logger.info(f"Connecting to the Cellarium Cloud backend with session {self.client_session_id}...") self.user_info = self.cas_api_service.validate_token() username = self.user_info["username"] self.__print(f"User is {username}") diff --git a/cellarium/cas/logging.py b/cellarium/cas/logging.py new file mode 100644 index 0000000..c1ad726 --- /dev/null +++ b/cellarium/cas/logging.py @@ -0,0 +1,17 @@ +import logging + +from cellarium.cas import settings + +# Create a custom logger for the package +logger = logging.getLogger("cellarium.cas") +logger.setLevel(settings.LOGGING_LEVEL) + +# Create a handler +handler = logging.StreamHandler() + +# Create a formatter and set it for the handler +formatter = logging.Formatter(fmt=settings.LOGGING_FORMAT, datefmt=settings.LOGGING_DATE_FORMAT) +handler.setFormatter(formatter) + +# Add the handler to the logger +logger.addHandler(handler) diff --git a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py index 30b8fa6..e6723e7 100644 --- a/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py +++ b/cellarium/cas/postprocessing/cell_ontology/cell_ontology_cache.py @@ -1,4 +1,3 @@ -import logging import typing as t from functools import lru_cache @@ -8,6 +7,7 @@ from cellarium.cas import settings # noqa from cellarium.cas._io import suppress_stderr +from cellarium.cas.logging import logger # Used in CZ CELLxGENE schema v5: # https://github.com/chanzuckerberg/single-cell-curation/blob/main/schema/5.0.0/schema.md @@ -56,7 +56,7 @@ def __init__(self, cl_owl_path: str = DEFAULT_CL_OWL_PATH): """ with suppress_stderr(): - logging.info(f"Loading cell ontology OWL from: {cl_owl_path}") + logger.info(f"Loading cell ontology OWL from: {cl_owl_path}") cl = owlready2.get_ontology(cl_owl_path).load() # only keep CL classes with a singleton label diff --git a/cellarium/cas/service.py b/cellarium/cas/service.py index 73966fa..fcd16df 100644 --- a/cellarium/cas/service.py +++ b/cellarium/cas/service.py @@ -1,6 +1,5 @@ import asyncio import json -import logging import ssl import typing as t from contextlib import ContextDecorator @@ -14,9 +13,10 @@ from aiohttp import client_exceptions from cellarium.cas import constants, endpoints, exceptions, settings +from cellarium.cas.logging import logger if settings.is_interactive_environment(): - logging.debug("Running in an interactive environment, applying nest_asyncio") + logger.debug("Running in an interactive environment, applying nest_asyncio") nest_asyncio.apply() # Context variable to track the action id for the current context @@ -211,7 +211,7 @@ async def _aiohttp_async_post( except (json.decoder.JSONDecodeError, client_exceptions.ClientResponseError): response_detail = await response.text() except KeyError: - logging.warning("Response body doesn't have a 'detail' key, returning full response body") + logger.warning("Response body doesn't have a 'detail' key, returning full response body") response_detail = str(await response.json()) self.raise_response_exception(status_code=status_code, detail=response_detail) diff --git a/cellarium/cas/settings.py b/cellarium/cas/settings.py index 86f5c6d..c87443d 100644 --- a/cellarium/cas/settings.py +++ b/cellarium/cas/settings.py @@ -8,8 +8,9 @@ AIOHTTP_READ_TIMEOUT_SECONDS = 730 MAX_CHUNK_SIZE_SEARCH_METHOD = 500 CELLARIUM_CLOUD_BACKEND_URL = "https://cellarium-cloud-api.cellarium.ai" - -logging.basicConfig(level=logging.INFO, format="* [%(asctime)s.%(msecs)03d] %(message)s", datefmt="%H:%M:%S") +LOGGING_LEVEL = logging.INFO +LOGGING_FORMAT = "* [%(asctime)s.%(msecs)03d] %(message)s" +LOGGING_DATE_FORMAT = "%H:%M:%S" def is_interactive_environment() -> bool: diff --git a/cellarium/cas/visualization/__init__.py b/cellarium/cas/visualization/__init__.py index 361380a..eb9cc5c 100644 --- a/cellarium/cas/visualization/__init__.py +++ b/cellarium/cas/visualization/__init__.py @@ -1,4 +1,4 @@ -import logging +from cellarium.cas.logging import logger try: from .circular_tree_plot_umap_dash_app.app import CASCircularTreePlotUMAPDashApp # noqa @@ -6,7 +6,7 @@ __all__ = ["CASCircularTreePlotUMAPDashApp", "find_and_kill_process"] except ImportError: - logging.warn( + logger.warning( """ Visualization dependencies not installed. To install the Cellarium CAS Client with visualation dependencies, please run: diff --git a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py index c257d8a..dd21820 100644 --- a/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py +++ b/cellarium/cas/visualization/circular_tree_plot_umap_dash_app/app.py @@ -14,7 +14,7 @@ from dash.development.base_component import Component from plotly.express.colors import sample_colorscale -from cellarium.cas import settings # noqa +from cellarium.cas.logging import logger from cellarium.cas.postprocessing import ( CAS_CL_SCORES_ANNDATA_OBSM_KEY, CAS_METADATA_ANNDATA_UNS_KEY, @@ -264,7 +264,7 @@ def run(self, port: int = 8050, jupyter_mode: str = "inline", **kwargs): :param port: The port on which to run the Dash application. |br| `Default:` ``8050`` """ - logging.info(f"Starting Dash application on port {port}...") + logger.info(f"Starting Dash application on port {port}...") try: self.app.run_server(port=port, jupyter_mode=jupyter_mode, jupyter_height=self.height + 100, **kwargs) except OSError: # Dash raises OSError if the port is already in use