working logger in python with stub

was a mess until it wasnt anymore, yay
This commit is contained in:
Christoph J. Scherr 2023-07-08 00:37:07 +02:00
parent 7da4e18456
commit 4fc6ac7e0a
Signed by: PlexSheep
GPG Key ID: 25B4ACF7D88186CC
12 changed files with 152 additions and 9 deletions

View File

@ -0,0 +1 @@
from ._libpt import *

12
python/libpt/__init__.pyi Normal file
View File

@ -0,0 +1,12 @@
"""
# libpt python bindings
`libpt` is originally implemented in rust, but offers a python module too.
"""
from . import logger
def is_loaded() -> bool:
"""
returns true if `libpt` has been loaded
"""
...

View File

@ -0,0 +1,12 @@
"""
# libpt python bindings
`libpt` is originally implemented in rust, but offers a python module too.
"""
from . import logger
def is_loaded() -> bool:
"""
returns true if `libpt` has been loaded
"""
...

65
python/libpt/logger.pyi Normal file
View File

@ -0,0 +1,65 @@
"""
# A specialized Logger for `libpt`
"""
""" the default log level """
DEFAULT_LOG_LEVEL = "INFO"
""" Set the value of this key as envar to set a loglevel """
LOGGER_ENV_KEY = "LIBPT_LOGLEVEL"
class Logger:
"""
`libpt` logger
Call `init` once before usage, else all logging attempts will be ignored.
"""
def __init__(self):
"""
get a new logger
"""
...
@staticmethod
def init():
"""
initialize the logger before the first usage
"""
...
@staticmethod
def init_specialized(color: bool):
"""
initialize the logger before the first usage, but with the ability to tweak things a bit
"""
...
def error(self, printable: str):
"""
log at level `error`
"""
...
def warn(self, printable: str):
"""
log at level `error`
"""
...
def info(self, printable: str):
"""
log at level `error`
"""
...
def debug(self, printable: str):
"""
log at level `error`
"""
...
def trace(self, printable: str):
"""
log at level `error`
"""
...

1
scripts/pytests.sh Executable file
View File

@ -0,0 +1 @@
python -m unittest discover -fs tests/python

View File

@ -35,7 +35,7 @@ use pyo3::prelude::*;
///
/// Always returns `true` if you can execute it.
#[pyfunction]
pub fn libpt_loaded() -> bool {
pub fn is_loaded() -> bool {
true
}
@ -50,12 +50,13 @@ fn py_logger(py: Python, m: &PyModule) -> PyResult<()> {
Ok(())
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Python module: root
///
/// This function is the entry point of [`PyO3`](pyo3). This is where the main module is built.
#[pymodule]
fn libpt(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(libpt_loaded, m)?)?;
fn _libpt(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(is_loaded, m)?)?;
// load logger module
py_logger(py, m)?;

View File

@ -15,12 +15,10 @@
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
use std::{
fmt,
io::Write,
sync::atomic::{AtomicBool, Ordering},
};
use env_logger::{
fmt::{Formatter, Style},
Env, Target, WriteStyle,
};
use log::{debug, error, info, trace, warn, Level};
@ -29,7 +27,7 @@ use pyo3::prelude::*;
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
/// The log level used when none is specified
pub const DEFAULT_LOG_LEVEL: Level = Level::Info;
/// Register your level to this ENVAR to override the used level
/// Register your level to this environment variable to override the used level
pub const LOGGER_ENV_KEY: &'static str = "LIBPT_LOGLEVEL";
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
@ -43,7 +41,8 @@ static INITIALIZED: AtomicBool = AtomicBool::new(false);
///
/// ### Setting a [`Level`](log::Level)
///
/// To set a [`Level`](log::Level), you need to set the ENVAR `LIBPT_LOGLEVEL` to either of
/// To set a [`Level`](log::Level), you need to set the environment variable `LIBPT_LOGLEVEL`
/// to either of:
///
/// - `Trace`
/// - `Debug`
@ -54,6 +53,7 @@ static INITIALIZED: AtomicBool = AtomicBool::new(false);
pub struct Logger {}
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
/// ## Main implementation
impl Logger {
/// ## create a `Logger`
///
@ -138,6 +138,7 @@ impl Logger {
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Implementation of the python interface
#[pymethods]
impl Logger {
/// ## Python version of [`new()`](Logger::new)
@ -151,6 +152,12 @@ impl Logger {
pub fn py_init() {
Self::init()
}
/// ## Python version of [`init_specialized()`](Logger::init_specialized)
#[pyo3(name = "init_specialized")]
#[staticmethod]
pub fn py_init_specialized(color: bool) {
Self::init_specialized(false, color, Target::Stdout)
}
/// ## Python version of [`error()`](Logger::error)
#[pyo3(name = "error")]
pub fn py_error(&self, printable: String) {

View File

@ -5,7 +5,8 @@
// IMPORTS /////////////////////////////////////////////////////////////////////////////////////////
use libpt;
/// ## check if libpt is loaded
#[test]
fn loaded_libpt() {
assert!(libpt::libpt_loaded())
fn test_libpt_is_loaded() {
assert!(libpt::is_loaded())
}

15
tests/python/lib.py Normal file
View File

@ -0,0 +1,15 @@
"""
tests for the general behaviour of the libraries availability
"""
import unittest
import libpt
class TestLibptGeneral(unittest.TestCase):
def test_loaded(self):
assert libpt.is_loaded()
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,21 @@
"""
test the logger
"""
import unittest
from libpt import logger
class TestLogger(unittest.TestCase):
def test_basic_logging(self):
logger.Logger.init()
l = logger.Logger()
l.trace("MSG")
l.debug("MSG")
l.info("MSG")
l.warn("MSG")
l.error("MSG")
if __name__ == '__main__':
unittest.main()

View File

@ -30,6 +30,7 @@ mod test_logger_struct {
use regex::Regex;
/// ## setup that's needed before testing the logger struct
fn setup() {
// we don't want to log messages during our tests!
Logger::init_specialized(false, false, env_logger::Target::Stdout);
@ -45,6 +46,9 @@ mod test_logger_struct {
/// - [`Logger::info`]
/// - [`Logger::warn`]
/// - [`Logger::error`]
///
/// After those methods have Successfully been executed, their outputs gets stored in a single
/// [`String`] and a [`Regex`] checks if we have five correctly formatted messages.
#[test]
fn test_log_basic() {
std::env::set_var(LOGGER_ENV_KEY, "Trace");
@ -62,12 +66,15 @@ mod test_logger_struct {
print!("{}", combined);
// too long, so i split into two lines.
// this matches the format of the env_logger perfectly, but make sure that color is off,
// else the ANSI escape sequences break this test
let regex = Regex::new(concat!(
r"(?m)\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z ",
r"(TRACE|DEBUG|INFO|WARN|ERROR) +libpt::logger\] MSG"
))
.unwrap();
// we have 5 log levels, therefore we should have 5 captures
assert_eq!(regex.captures_iter(&combined).count(), 5);
}