Skip to content

Commit

Permalink
refactor logging control (#243)
Browse files Browse the repository at this point in the history
* add dependency `rich`

* remove logging NullHandler from modules

* add function `setup_logging`

* use standard logging instead of `LogConfig`

* replace print with logger.info

* Delete logconfig.py

* remove dependency tqdm

use rich.progress instead

* replace tqdm with rich.progress for displaying progress bar

* update nplinker configs for logging

- update comments
- rename `to_stdout` to `use_console`

- Remove `cast=Path` for `log.file`, as the config variable is first cast, then examined on its type.

* update logging setup in NPLinker class

* print out configs when initializing NPLinker class

* change log message from debug to info

* Update __init__.py
  • Loading branch information
CunliangGeng authored May 21, 2024
1 parent 7d36688 commit e5e4ecb
Show file tree
Hide file tree
Showing 54 changed files with 205 additions and 266 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ dependencies = [
"numpy",
"pandas",
"pyteomics",
"rich",
"scipy",
"sortedcontainers",
"tqdm",
]

[project.optional-dependencies]
Expand Down
42 changes: 42 additions & 0 deletions src/nplinker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,45 @@
__author__ = "Cunliang Geng"
__email__ = "c.geng@esciencecenter.nl"
__version__ = "2.0.0-alpha.1"


def setup_logging(level: str = "INFO", file: str = "", use_console: bool = True) -> None:
"""Setup logging configuration for the ancestor logger "nplinker".
Args:
level: The log level, use the logging module's log level constants. Valid levels are:
"NOTSET", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL".
file: The file to write the log to. If the file does not exist, it will be created. The log
will be written to the file in append mode. If the file is an empty string (by default),
the log will not be written to a file.
use_console: Whether to log to the console.
"""
from rich.console import Console
from rich.logging import RichHandler

# Get the acncestor logger "nplinker"
logger = logging.getLogger(__name__)
logger.setLevel(level)

# File handler
if file:
logger.addHandler(
RichHandler(
console=Console(file=open(file, "a"), width=120), # force the line width to 120
omit_repeated_times=False,
rich_tracebacks=True,
tracebacks_show_locals=True,
log_time_format="[%Y-%m-%d %X]",
)
)

# Console handler
if use_console:
logger.addHandler(
RichHandler(
omit_repeated_times=False,
rich_tracebacks=True,
tracebacks_show_locals=True,
log_time_format="[%Y-%m-%d %X]",
)
)
7 changes: 3 additions & 4 deletions src/nplinker/class_info/chem_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,15 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import glob
import logging
import os
from collections import Counter
from canopus import Canopus
from canopus.classifications_to_gnps import analyse_canopus
from ..logconfig import LogConfig


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


# load Chem_class_predictions (canopus, molnetenhancer are loaded)
Expand Down Expand Up @@ -264,7 +263,7 @@ class prediction for a level. When no class is present, instead of Tuple it will

# use canopus_treemap to produce NPClassifier classes
# TODO: probably change when sirius v5 comes out
logger.debug("Using canopus_treemap to get NPC classes")
logger.info("Using canopus_treemap to get NPC classes")
canopus_workspace = Canopus(sirius=self._canopus_dir)
npc_file = os.path.join(self._canopus_dir, "npc_summary.tsv")
canopus_workspace.npcSummary().to_csv(npc_file, sep=sep)
Expand Down
5 changes: 2 additions & 3 deletions src/nplinker/class_info/class_matches.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os
from collections import Counter
from collections import defaultdict
import pandas as pd
from ..logconfig import LogConfig


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


class ClassMatches:
Expand Down
5 changes: 2 additions & 3 deletions src/nplinker/class_info/runcanopus.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
import os
import subprocess
import sys
from ..logconfig import LogConfig


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


def run_canopus(mgf_file, output_path, extra_params="--maxmz 600 formula zodiac structure canopus"):
Expand Down
6 changes: 3 additions & 3 deletions src/nplinker/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@
Validator("podp_id", required=True, when=Validator("mode", eq="podp")),
Validator("podp_id", required=False, when=Validator("mode", eq="local")),
# Log
## `loglevel` must be a string and must be one of the supported levels. It is transformed to
## `level` must be a string and must be one of the supported levels. It is transformed to
## uppercase to avoid case sensitivity.
Validator(
"log.level",
is_type_of=str,
cast=lambda v: v.upper(),
is_in=["NOTSET", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
),
Validator("log.file", is_type_of=str, cast=Path),
Validator("log.to_stdout", is_type_of=bool),
Validator("log.file", is_type_of=str),
Validator("log.use_console", is_type_of=bool),
# Mibig
Validator("mibig.to_use", required=True, is_type_of=bool),
Validator(
Expand Down
13 changes: 7 additions & 6 deletions src/nplinker/data/nplinker.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@ podp_id = ""

[log]
# Log level. The available levels are same as the levels in python package `logging`:
# "NOTSET", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL".
# "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL".
# The default value is "INFO".
level = "INFO"
# Redirect the log messages from stdout to a log file. If not set, the log messages will only be
# printed to stdout.
# The value is optional and must be a full path if set.
# The log file to append log messages.
# The value is optional.
# If not set or use empty string, log messages will not be written to a file.
# The file will be created if it does not exist. Log messages will be appended to the file if it exists.
file = "path/to/logfile"
# Whether to print log messages to stdout in addition to writing to the logfile.
# Whether to write log meesages to console.
# The default value is true.
to_stdout = true
use_console = true


[mibig]
Expand Down
3 changes: 0 additions & 3 deletions src/nplinker/genomics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import logging
from .bgc import BGC
from .gcf import GCF


logging.getLogger(__name__).addHandler(logging.NullHandler())

__all__ = [
"BGC",
"GCF",
Expand Down
3 changes: 0 additions & 3 deletions src/nplinker/genomics/antismash/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import logging
from .antismash_downloader import download_and_extract_antismash_data
from .antismash_loader import AntismashBGCLoader
from .antismash_loader import parse_bgc_genbank
Expand All @@ -7,8 +6,6 @@
from .podp_antismash_downloader import podp_download_and_extract_antismash_data


logging.getLogger(__name__).addHandler(logging.NullHandler())

__all__ = [
"download_and_extract_antismash_data",
"AntismashBGCLoader",
Expand Down
4 changes: 2 additions & 2 deletions src/nplinker/genomics/antismash/antismash_downloader.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from __future__ import annotations
import logging
import os
import shutil
from os import PathLike
from pathlib import Path
from nplinker.logconfig import LogConfig
from nplinker.utils import download_and_extract_archive
from nplinker.utils import list_dirs
from nplinker.utils import list_files


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)

# urls to be given to download antismash data
ANTISMASH_DB_DOWNLOAD_URL = "https://antismash-db.secondarymetabolites.org/output/{}/{}"
Expand Down
4 changes: 2 additions & 2 deletions src/nplinker/genomics/antismash/antismash_loader.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from __future__ import annotations
import fnmatch
import logging
import os
from Bio import SeqIO
from Bio import SeqRecord
from nplinker.genomics import BGC
from nplinker.logconfig import LogConfig
from nplinker.strain import Strain
from nplinker.utils import list_dirs
from nplinker.utils import list_files
from ..abc import BGCLoaderBase


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


class AntismashBGCLoader:
Expand Down
8 changes: 4 additions & 4 deletions src/nplinker/genomics/antismash/podp_antismash_downloader.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations
import json
import logging
import re
import time
from os import PathLike
Expand All @@ -11,11 +12,10 @@
from jsonschema import validate
from nplinker.defaults import GENOME_STATUS_FILENAME
from nplinker.genomics.antismash import download_and_extract_antismash_data
from nplinker.logconfig import LogConfig
from nplinker.schemas import GENOME_STATUS_SCHEMA


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)

NCBI_LOOKUP_URL = "https://www.ncbi.nlm.nih.gov/assembly/?term={}"
JGI_GENOME_LOOKUP_URL = (
Expand Down Expand Up @@ -248,7 +248,7 @@ def _ncbi_genbank_search(genbank_id: str, retry_times: int = 3) -> Tag | Navigab
url = NCBI_LOOKUP_URL.format(genbank_id)
retry = 1
while retry <= retry_times:
logger.debug(f"Looking up GenBank data for {genbank_id} at {url}")
logger.info(f"Looking up GenBank data for {genbank_id} at {url}")
resp = httpx.get(url, follow_redirects=True)
if resp.status_code == httpx.codes.OK:
# the page should contain a <dl> element with class "assembly_summary_new". retrieving
Expand Down Expand Up @@ -298,7 +298,7 @@ def _resolve_genbank_accession(genbank_id: str) -> str:

# get rid of any extraneous whitespace
genbank_id = genbank_id.strip()
logger.debug(f'Parsed GenBank ID to "{genbank_id}"')
logger.info(f'Parsed GenBank ID to "{genbank_id}"')

# run a search using the GenBank accession ID
try:
Expand Down
4 changes: 2 additions & 2 deletions src/nplinker/genomics/bgc.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from deprecated import deprecated
from nplinker.logconfig import LogConfig
from .aa_pred import predict_aa


if TYPE_CHECKING:
from ..strain import Strain
from .gcf import GCF

logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


class BGC:
Expand Down
3 changes: 0 additions & 3 deletions src/nplinker/genomics/bigscape/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import logging
from .bigscape_loader import BigscapeGCFLoader
from .bigscape_loader import BigscapeV2GCFLoader
from .runbigscape import run_bigscape


logging.getLogger(__name__).addHandler(logging.NullHandler())

__all__ = ["BigscapeGCFLoader", "BigscapeV2GCFLoader", "run_bigscape"]
4 changes: 2 additions & 2 deletions src/nplinker/genomics/bigscape/bigscape_loader.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from __future__ import annotations
import csv
import logging
import sqlite3
from os import PathLike
from nplinker.logconfig import LogConfig
from ..abc import GCFLoaderBase
from ..gcf import GCF


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


class BigscapeGCFLoader:
Expand Down
4 changes: 2 additions & 2 deletions src/nplinker/genomics/bigscape/runbigscape.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from __future__ import annotations
import logging
import os
import subprocess
import sys
from os import PathLike
from ...logconfig import LogConfig


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)

PFAM_PATH = os.path.join(sys.prefix, "nplinker_lib")

Expand Down
4 changes: 2 additions & 2 deletions src/nplinker/genomics/gcf.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING
from nplinker.logconfig import LogConfig
from nplinker.strain import StrainCollection


if TYPE_CHECKING:
from nplinker.strain import Strain
from .bgc import BGC

logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


class GCF:
Expand Down
3 changes: 0 additions & 3 deletions src/nplinker/genomics/mibig/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import logging
from .mibig_downloader import download_and_extract_mibig_metadata
from .mibig_loader import MibigLoader
from .mibig_loader import parse_bgc_metadata_json
from .mibig_metadata import MibigMetadata


logging.getLogger(__name__).addHandler(logging.NullHandler())

__all__ = [
"download_and_extract_mibig_metadata",
"MibigLoader",
Expand Down
4 changes: 2 additions & 2 deletions src/nplinker/genomics/mibig/mibig_downloader.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from __future__ import annotations
import logging
import os
import shutil
from pathlib import Path
from nplinker.logconfig import LogConfig
from nplinker.utils import download_and_extract_archive
from nplinker.utils import list_dirs
from nplinker.utils import list_files


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)

MIBIG_METADATA_URL = "https://dl.secondarymetabolites.org/mibig/mibig_json_{version}.tar.gz"

Expand Down
4 changes: 2 additions & 2 deletions src/nplinker/genomics/mibig/mibig_loader.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import logging
import os.path
from nplinker.logconfig import LogConfig
from nplinker.strain import Strain
from nplinker.utils import list_files
from ..abc import BGCLoaderBase
from ..bgc import BGC
from .mibig_metadata import MibigMetadata


logger = LogConfig.getLogger(__name__)
logger = logging.getLogger(__name__)


class MibigLoader:
Expand Down
Loading

0 comments on commit e5e4ecb

Please sign in to comment.