Added loguru

This commit is contained in:
Jacob Hinkle 2022-09-27 11:25:25 -04:00
parent 6c62d0568d
commit cb53db3bcd
8 changed files with 67 additions and 53 deletions

36
poetry.lock generated
View File

@ -94,6 +94,21 @@ category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
[[package]]
name = "loguru"
version = "0.6.0"
description = "Python logging made (stupidly) simple"
category = "main"
optional = false
python-versions = ">=3.5"
[package.dependencies]
colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
[package.extras]
dev = ["sphinx-rtd-theme (>=0.4.3)", "sphinx-autobuild (>=0.7.1)", "Sphinx (>=4.1.1)", "isort (>=5.1.1)", "black (>=19.10b0)", "pytest-cov (>=2.7.1)", "pytest (>=4.6.2)", "tox (>=3.9.0)", "flake8 (>=3.7.7)", "docutils (==0.16)", "colorama (>=0.3.4)"]
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "0.4.3" version = "0.4.3"
@ -248,6 +263,17 @@ category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
[[package]]
name = "win32-setctime"
version = "1.1.0"
description = "A small Python utility to set file creation time on Windows"
category = "main"
optional = false
python-versions = ">=3.5"
[package.extras]
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
[[package]] [[package]]
name = "zipp" name = "zipp"
version = "3.8.1" version = "3.8.1"
@ -263,7 +289,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "c44b5e718866e498815a184650d98fd5e637b07246375d1e9fc4298a0125f0d6" content-hash = "6ca131347c47d90f6093f09ad7a6025b55535855e382770019f20e60c07b6c15"
[metadata.files] [metadata.files]
attrs = [ attrs = [
@ -363,6 +389,10 @@ iniconfig = [
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
] ]
loguru = [
{file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"},
{file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"},
]
mypy-extensions = [ mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
@ -440,6 +470,10 @@ typing-extensions = [
{file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"},
{file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"},
] ]
win32-setctime = [
{file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"},
{file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"},
]
zipp = [ zipp = [
{file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"},
{file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"},

View File

@ -8,6 +8,7 @@ authors = ["Jacob Hinkle <jacob.hinkle@jhink.org>"]
python = "^3.7" python = "^3.7"
click = "^8.1.3" click = "^8.1.3"
colorama = "^0.4.5" colorama = "^0.4.5"
loguru = "^0.6.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = "^22.8.0" black = "^22.8.0"

View File

@ -1,50 +1,4 @@
import sqlite3 import sys
from . import store from . import store
from .version import __version__ from .version import __version__
def save_data(
destination_mapping,
desc=f"Provenance-tracking with nancy v{__version__}",
):
"""
A command-line interface to compute and save a set of outputs.
Ex:
.. code:
save_data({
"scores.csv": scores,
"checkpoints": checkpoint_dir,
"plots/learning_curve.pdf": learning_curve_plot,
"plots/test_roc.pdf": test_auc_plot,
"
},
"""
import argparse
import os
import sys
parser = argparse.ArgumentParser(description=desc)
parser.add_argument(
"--out_dir",
"-o",
required=True,
help="Directory (will be created) in which to save all outputs",
)
args = parser.parse_args()
if os.path.exists(args.out_dir):
print(
f"Output directory {args.out_dir} exists. Refusing to overwrite.",
file=sys.stderr,
)
sys.exit(1)
# Create the output directory, back up the in-memory db to this location, an
# switch to it.
os.makedirs(args.out_dir, exist_ok=True)
persist_db(os.path.join(args.out_dir, "nancy.db"))
# Now we save the provided roots, and record their locations in _conn.data

View File

@ -1,4 +1,5 @@
import click import click
from loguru import logger
from ..version import __version__ from ..version import __version__
@ -30,8 +31,17 @@ def version():
@click.group( @click.group(
cls=AliasedGroup, cls=AliasedGroup,
help=f"Composable provenance tracking for scientific data") help=f"Composable provenance tracking for scientific data")
def main(): @click.option(
pass "-L", "--log_level",
# https://loguru.readthedocs.io/en/stable/api/logger.html#levels
type=click.Choice(['CRITICAL', 'ERROR', 'WARNING', 'SUCCESS', 'INFO', 'DEBUG', 'TRACE']),
default='SUCCESS',
help='If given, print all output including debugging info.',
)
def main(log_level):
import sys
logger.remove()
logger.add(sys.stderr, level=log_level)
#main.add_command(freeze) #main.add_command(freeze)
#main.add_command(thaw) #main.add_command(thaw)
main.add_command(diff.diff_cli, name='diff') main.add_command(diff.diff_cli, name='diff')

View File

@ -1,4 +1,5 @@
import click import click
from loguru import logger
from .. import db, fs, store from .. import db, fs, store
@ -91,6 +92,7 @@ def diff(store, filedir_path, show_hashes=False, use_color=True):
help='If given, do not print any color output.', help='If given, do not print any color output.',
) )
def diff_cli(path, show_hashes, no_color): def diff_cli(path, show_hashes, no_color):
@logger.catch
"""Detect and describe changes to PATH """Detect and describe changes to PATH
PATH is a path to a file or directory inside an existing nancy store PATH is a path to a file or directory inside an existing nancy store
@ -116,4 +118,5 @@ def diff_cli(path, show_hashes, no_color):
except FileNotFoundError as e: except FileNotFoundError as e:
print(str(e), file=sys.stderr) print(str(e), file=sys.stderr)
sys.exit(1) sys.exit(1)
logger.success("Computed diff")

View File

@ -1,4 +1,5 @@
import click import click
from loguru import logger
from .. import store from .. import store
@ -10,6 +11,7 @@ import sys
def record(directory, message, show_diff=True, show_hashes=False, use_color=True, def record(directory, message, show_diff=True, show_hashes=False, use_color=True,
@logger.catch
skip_confirm=False): skip_confirm=False):
"""Unwrapped record command""" """Unwrapped record command"""
if not os.path.isdir(directory): if not os.path.isdir(directory):
@ -26,12 +28,12 @@ def record(directory, message, show_diff=True, show_hashes=False, use_color=True
if show_diff: if show_diff:
print_diff(fsdiff, show_hashes=show_hashes, use_color=use_color) print_diff(fsdiff, show_hashes=show_hashes, use_color=use_color)
print('Message:', message) logger.info('Recording with message:', message)
if skip_confirm or confirm("Record the values above into the database?"): if skip_confirm or confirm("Record the values above into the database?"):
s.record(fsdiff, message=message) s.record(fsdiff, message=message)
else: else:
print("Cancelled!") logger.info("Cancelled!")
sys.exit(1) sys.exit(1)

View File

@ -1,6 +1,7 @@
"""Interaction with the filesystem and with file database entries""" """Interaction with the filesystem and with file database entries"""
from dataclasses import dataclass from dataclasses import dataclass
from loguru import logger
import hashlib import hashlib
import operator import operator
import os import os
@ -201,6 +202,7 @@ class FSEntry:
@classmethod @classmethod
def from_db_index(cls, cursor, root_id=None, root_row=None): def from_db_index(cls, cursor, root_id=None, root_row=None):
@logger.catch
"""Given id of an entry in filedir, recursively fill this object""" """Given id of an entry in filedir, recursively fill this object"""
fields = 'id, filename, filetype, frozen, deleted' fields = 'id, filename, filetype, frozen, deleted'
if root_row is None: if root_row is None:

View File

@ -1,5 +1,7 @@
"""Utilities for creating new stores and linking between them.""" """Utilities for creating new stores and linking between them."""
from loguru import logger
from . import db, environment, fs, machine from . import db, environment, fs, machine
import datetime import datetime
@ -22,6 +24,7 @@ class Program:
def set_start_time(self, t): def set_start_time(self, t):
self.start_time = t self.start_time = t
@logger.catch
def __enter__(self): def __enter__(self):
if self._evaluated: if self._evaluated:
raise RuntimeError("Cannot re-enter a Program context") raise RuntimeError("Cannot re-enter a Program context")
@ -68,7 +71,7 @@ class Program:
cur.connection.commit() cur.connection.commit()
self._evaluated = True # prevent re-running self._evaluated = True # prevent re-running
elapsed = end_time - self.start_time elapsed = end_time - self.start_time
print(f"Program [{self.id}] {self.name} (message:{self.message}) ran in {elapsed} seconds.") logger.success(f"Program [{self.id}] {self.name} (message:{self.message}) ran in {elapsed} seconds.")
class Store: class Store:
@ -178,7 +181,9 @@ class Store:
def fs_entries(self, shallow=False): def fs_entries(self, shallow=False):
"""Return recursive structure containing FSEntry objects from db""" """Return recursive structure containing FSEntry objects from db"""
root_id = self.filedir_root_index() root_id = self.filedir_root_index()
logger.debug('root_id={}', root_id)
if root_id is None: if root_id is None:
logger.trace("Empty root")
return fs.FSEntry.empty_root() return fs.FSEntry.empty_root()
else: else:
return fs.FSEntry.from_db_index(cur, root_id=root_id) return fs.FSEntry.from_db_index(cur, root_id=root_id)
@ -197,9 +202,12 @@ class Store:
# provided # provided
os.path.relpath(os.path.realpath(filepath), os.path.realpath(self.path)), os.path.relpath(os.path.realpath(filepath), os.path.realpath(self.path)),
) )
logger.trace("DIFF")
recorded = self.path_to_fsentry(filepath) recorded = self.path_to_fsentry(filepath)
logger.debug("CURRENT: \n{}", str(current))
logger.debug("RECORDED: \n{}", str(recorded))
return fs.FSDiff.compute(recorded, current) return fs.FSDiff.compute(recorded, current)
def record(self, diff, message=None): def record(self, diff, message=None):