Compare commits

...

18 commits

Author SHA1 Message Date
1bdef8c493 make things hopefully ready for v0.1.7 2023-09-29 17:50:47 +02:00
2fb3fc298c python shenanigans 2023-09-29 13:42:37 +02:00
8cd7dcd77d fix warnings 2023-09-29 12:32:06 +02:00
0e9da09102 link docu files 2023-09-29 12:31:26 +02:00
9d1a242060 docu things i guess 2023-09-20 20:35:07 +02:00
cbd0717cc6 fix log and math docu 2023-09-20 20:14:10 +02:00
Christoph J. Scherr
341a64a0f5 renaming things back to libpt, its kinda responsible 2023-09-20 18:37:06 +02:00
Christoph J. Scherr
3334920d18 bintols work with generic hmnsize 2023-09-20 18:16:21 +02:00
Christoph J. Scherr
12ac4ebb38 structure stuff 2023-09-20 18:15:53 +02:00
Christoph J. Scherr
ebac3201cd bintols 2023-09-20 15:37:50 +02:00
Christoph J. Scherr
3c8a2d9661 everything compiles 2023-09-20 14:52:22 +02:00
Christoph J. Scherr
fa6eb387ce Merge branch 'devel' of https://git.cscherr.de/PlexSheep/pt into devel 2023-09-20 14:32:36 +02:00
f2bab05909 intermediate 2023-09-20 14:32:25 +02:00
Christoph J. Scherr
482e246bc8 add bintols 2023-09-20 14:28:40 +02:00
9fb726b5df compile pt-core 2023-09-15 20:14:50 +02:00
Christoph J. Scherr
999c753d3e move more stuff 2023-09-15 17:28:57 +02:00
Christoph J. Scherr
8113e5ac65 make pt-log compile 2023-09-15 17:15:09 +02:00
Christoph J. Scherr
7803195c24 restructure to workspace oriented design 2023-09-15 17:00:22 +02:00
56 changed files with 975 additions and 501 deletions

View file

@ -1,9 +1,30 @@
[package]
name = "libpt"
version = "0.1.6"
[workspace]
resolver = "2"
members = [
".",
"members/pt-core",
"members/pt-bintols",
"members/pt-math",
"members/pt-bin",
"members/pt-log",
"members/pt-net",
"members/pt-py",
"members/pt-hedu",
]
default-members = [
".",
"members/pt-bin",
"members/pt-core",
"members/pt-py",
"members/pt-log",
"members/pt-math",
]
[workspace.package]
publish = false
version = "0.1.7"
edition = "2021"
authors = ["Christoph J. Scherr <software@cscherr.de>"]
license = "GPL-3.0-or-later"
license = "MIT"
description = "Personal multitool"
readme = "README.md"
homepage = "https://git.cscherr.de/PlexSheep/pt"
@ -11,39 +32,47 @@ repository = "https://git.cscherr.de/PlexSheep/pt"
keywords = ["cli", "python", "scriptable", "pyo3", "library"]
categories = ["command-line-utilities", "development-tools", "development-tools::ffi"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace.dependencies]
pyo3 = "0.19"
[package]
name = "libpt"
publish = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
[features]
default = ["core", "log"]
core = []
math = []
log = []
bintols = []
net = []
ccc = ["math"]
hedu = ["bintols"]
[lib]
name = "pt"
crate-type = ["cdylib", "rlib"]
name = "libpt"
crate-type = [
"dylib", # .dll, .so, .dynlib
"staticlib" # .lib, .a
]
[[bin]]
name = "pt"
path = "src/bin/main/mod.rs"
[[bin]]
name = "ccc"
path = "src/bin/ccc/mod.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.3.11", features = ["derive"] }
clap-num = "1.0.2"
clap-verbosity-flag = "2.0.1"
env_logger = "0.10.0"
humantime = "2.1.0"
num = "0.4.0"
num-traits = "0.2.16"
openssl = "0.10.55"
openssl-sys = "0.9.90"
pyo3 = "0.18.1"
regex = "1.9.1"
reqwest = { version = "0.11.18", features = ["blocking"] }
serde = { version = "1.0.171", features = ["derive"] }
serde_json = "1.0.102"
signal-hook = "0.3.15"
tracing = "0.1.37"
tracing-appender = "0.2.2"
tracing-subscriber = "0.3.17"
[dev-dependencies]
gag = "1.0.0"
pt-bintols = { version = "0.1.0", path = "members/pt-bintols" }
pt-core = { version = "0.1.0", path = "members/pt-core" }
pt-hedu = { version = "0.1.0", path = "members/pt-hedu" }
pt-log = { version = "0.1.0", path = "members/pt-log" }
pt-math = { version = "0.1.0", path = "members/pt-math" }
pt-net = { version = "0.1.0", path = "members/pt-net" }
pt-ccc = { version = "0.1.0", path = "members/pt-ccc" }

View file

@ -9,10 +9,6 @@ crate, python module or executable.
Let's see if I make it a bloated mess or stop committing after 30 hello worlds.
#### But the name `pt` / `libpt` already exists!
So what? I don't care. Besides, there is not enough names to name everything unique.
## Dependencies
- See `cargo.toml`

30
members/pt-bin/Cargo.toml Normal file
View file

@ -0,0 +1,30 @@
[package]
autobins = true
name = "pt-bin"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "ccc"
path = "src/ccc/mod.rs"
[[bin]]
name = "pt"
path = "src/main/mod.rs"
[dependencies]
clap = { version = "4.4.4", features = ["derive"] }
clap-num = "1.0.2"
clap-verbosity-flag = "2.0.1"
libpt = { version = "0.1.7", path = "../..", features = ["ccc", "math", "hedu", "net"] }

View file

@ -15,11 +15,10 @@
#![warn(clippy::pedantic)]
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
use pt::math::calculator::{*, self};
use pt::logger::*;
use libpt::ccc::*;
use libpt::log::*;
use clap::{Parser, Subcommand};
use clap_num::number_range;
use clap::Parser;
use clap_verbosity_flag::{Verbosity, InfoLevel};
use std::path::PathBuf;
@ -42,6 +41,7 @@ static LONG_ABOUT_ROOT: &'static str = r##"
"##;
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
/// defines CLI interface
#[derive(Debug, Clone, Parser)]
#[command(
author,
@ -81,12 +81,12 @@ pub struct Cli {
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
fn main() {
let cli = Cli::parse();
let ll: tracing::Level = match cli.verbose.log_level().unwrap().as_str() {
"TRACE" => tracing::Level::TRACE,
"DEBUG" => tracing::Level::DEBUG,
"INFO" => tracing::Level::INFO,
"WARN" => tracing::Level::WARN,
"ERROR" => tracing::Level::ERROR,
let ll: Level = match cli.verbose.log_level().unwrap().as_str() {
"TRACE" => Level::TRACE,
"DEBUG" => Level::DEBUG,
"INFO" => Level::INFO,
"WARN" => Level::WARN,
"ERROR" => Level::ERROR,
_ => {
eprintln!("'{}' is not a valid loglevel", cli.verbose.to_string());
std::process::exit(1);

View file

@ -15,11 +15,7 @@
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
use pt::{logger, networking::monitoring::uptime, common::*};
// we want the log macros in any case
#[allow(unused_imports)]
use tracing::{debug, error, info, trace, warn};
use libpt::{log::*, net::monitoring::uptime};
use clap::Parser;
@ -45,19 +41,19 @@ use std::path::PathBuf;
/// ## Main function of the [`pt`](crate) binary
pub fn main() {
let cli = Cli::parse();
let ll: tracing::Level = match cli.verbose.log_level().unwrap().as_str() {
"TRACE" => tracing::Level::TRACE,
"DEBUG" => tracing::Level::DEBUG,
"INFO" => tracing::Level::INFO,
"WARN" => tracing::Level::WARN,
"ERROR" => tracing::Level::ERROR,
let ll: Level = match cli.verbose.log_level().unwrap().as_str() {
"TRACE" => Level::TRACE,
"DEBUG" => Level::DEBUG,
"INFO" => Level::INFO,
"WARN" => Level::WARN,
"ERROR" => Level::ERROR,
_ => {
eprintln!("'{}' is not a valid loglevel", cli.verbose.to_string());
std::process::exit(EXIT_FAILURE_USAGE);
std::process::exit(1);
}
};
if cli.log_meta {
logger::Logger::init_customized(
Logger::init_customized(
false,
PathBuf::from("/dev/null"),
true,
@ -72,7 +68,7 @@ pub fn main() {
.expect("could not initialize Logger");
} else {
// less verbose version
logger::Logger::init_customized(
Logger::init_customized(
false,
PathBuf::from("/dev/null"),
true,

View file

@ -0,0 +1,20 @@
[package]
name = "pt-bintols"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
num-traits = "0.2.16"
pt-core = { version = "0.1.0", path = "../pt-core" }
pt-log = { version = "0.1.0", path = "../pt-log" }

View file

@ -0,0 +1,41 @@
//* # See what's behind the datatypes of Rust
//*
//* This Crate shows off how datatypes of rust are stored in memory.
// reexport macros
pub use crate::investigate_memory_layout;
/// ## Investigate the internal representation of variables
///
/// Takes 1. the Type and 2. a [`Vec`] of items (of that datatype).
#[macro_export]
macro_rules! investigate_memory_layout {
($t:ty, $v:tt) => {
println!("Type:\t{}", std::any::type_name::<$t>());
println!("\talign:\t{:?} B", std::mem::align_of::<$t>());
println!("\tID:\t{:?}\n", std::any::TypeId::of::<$t>());
println!("\tItems:");
unsafe {
for (index, item) in $v.iter().enumerate() {
let pointer = item as *const $t;
let mut memory: [u8; std::mem::size_of::<$t>()] = std::mem::transmute(item.clone());
memory.reverse();
println!("\
\t{index:02x}\titem:\t\t{item:?}\n\
\t\tpointer: \t{:X?}\n\
\t\talign: \t{}\n\
\t\tsize: \t{}\n\
\t\tmemory: \t{:X?}\n\
\t\tbin mem: \t{}\n\
\t\tnote: \tmemory order reversed\n\
",
pointer,
display::byte_bit_display(std::mem::align_of_val(item)),
display::byte_bit_display(memory.len()),
memory,
display::bytes_to_bin(&memory)
);
}
}
};
}

View file

@ -0,0 +1,67 @@
//* # Tools that help display binary values, data sizes, etc
use super::*;
pub use num_traits::{PrimInt, ToPrimitive};
/// ## Get the binary representation for a Byte array [`&[u8]`]
///
/// ### Arguments
/// * `data` - The data you are trying to dump
pub fn bytes_to_bin(data: &[u8]) -> String {
let mut s = format!("0b{:08b}", data.first().unwrap());
for i in 1..data.len() {
s.push_str(&format!("_{:08b}", data[i]));
if i % 8 == 0 {
s.push_str("\n")
}
}
return s;
}
/// Quickly format a number of Bytes [`usize`] with the corresponding
/// number of bits
pub fn byte_bit_display(data: usize) -> String {
format!("{} B = {} bit", data.clone(), data * 8)
}
/// ## Format total byte sizes to human readable sizes
pub fn humanbytes<T>(total: T) -> String
where
T: PrimInt,
T: ToPrimitive,
T: Ord,
T: std::fmt::Display,
T: std::fmt::Debug,
{
if total < T::from(KIBI).unwrap() {
return format!("{total} B");
} else if T::from(KIBI).unwrap() <= total && total < T::from(MEBI).unwrap() {
return format!("{:.2} K", total.to_f64().unwrap() / KIBI as f64);
} else if T::from(MEBI).unwrap() <= total && total < T::from(GIBI).unwrap() {
return format!("{:.2} M", total.to_f64().unwrap() / MEBI as f64);
} else if T::from(GIBI).unwrap() <= total && total < T::from(TEBI).unwrap() {
return format!("{:.2} G", total.to_f64().unwrap() / GIBI as f64);
} else if T::from(TEBI).unwrap() <= total && total < T::from(PEBI).unwrap() {
return format!("{:.2} T", total.to_f64().unwrap() / TEBI as f64);
} else if T::from(PEBI).unwrap() <= total && total < T::from(EXBI).unwrap() {
return format!("{:.2} P", total.to_f64().unwrap() / PEBI as f64);
}
// now we are starting to reach the sizes that are pretty unrealistic
// (as of 2023 that is, hello future)
//
// the later ones overflow `usize` on 64 Bit computers, so we have
// to work with a fixed, larger sized datatype
else {
let total: u128 = total.to_u128().unwrap();
if EXBI <= total && total < ZEBI {
return format!("{:.2} E", total.to_f64().unwrap() / EXBI as f64);
} else if ZEBI <= total && total < YOBI {
return format!("{:.2} Z", total.to_f64().unwrap() / ZEBI as f64);
} else if YOBI <= total {
return format!("{:.2} Y", total.to_f64().unwrap() / YOBI as f64);
}
else {
unreachable!()
}
}
}

View file

@ -0,0 +1,27 @@
//* # Tools to work with binary values, memory, storage
//!
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
//! module.
// official binary prefixes, see [https://en.wikipedia.org/wiki/Binary_prefix]
/// 2^10
pub const KIBI: usize = 2usize.pow(10);
/// 2^20
pub const MEBI: usize = 2usize.pow(20);
/// 2^30
pub const GIBI: usize = 2usize.pow(30);
/// 2^40
pub const TEBI: usize = 2usize.pow(40);
/// 2^50
pub const PEBI: usize = 2usize.pow(50);
/// 2^60
pub const EXBI: u128 = 2u128.pow(60);
// at this point, `usize` would overflow, so we have to switch to a bigger datatype.
/// 2^70
pub const ZEBI: u128 = 2u128.pow(70);
/// 2^80
pub const YOBI: u128 = 2u128.pow(80);
// use pt_core;
pub mod datalayout;
pub mod display;

View file

@ -0,0 +1,7 @@
use pt_bintols::*;
#[test]
fn mkdmp() {
let v = vec![true, true, false];
investigate_memory_layout!(bool, v);
}

View file

@ -0,0 +1,63 @@
use pt_bintols::*;
use pt_bintols::display::*;
#[test]
fn btobin() {
let data = [19, 19];
let r = bytes_to_bin(&data);
assert_eq!(r, format!("0b00010011_00010011"));
}
#[test]
fn big_btobin() {
let data = [12,31,82,32,123,32,92,23,12,32,12,1,1,1];
let r = bytes_to_bin(&data);
assert_eq!(r, format!("0b00001100_00011111_01010010_\
00100000_01111011_00100000_01011100_00010111_00001100\n\
_00100000_00001100_00000001_00000001_00000001"));
}
#[test]
fn bybit() {
assert_eq!(byte_bit_display(120), format!("120 B = 960 bit"));
assert_eq!(byte_bit_display(12), format!("12 B = 96 bit"));
assert_eq!(byte_bit_display(8), format!("8 B = 64 bit"));
}
#[test]
fn hmnbytes() {
assert_eq!(humanbytes(0), format!("0 B"));
assert_eq!(humanbytes(1), format!("1 B"));
assert_eq!(humanbytes(KIBI-1), format!("1023 B"));
assert_eq!(humanbytes(KIBI), format!("1.00 K"));
assert_eq!(humanbytes(KIBI+1), format!("1.00 K"));
assert_eq!(humanbytes(MEBI-1), format!("1024.00 K"));
assert_eq!(humanbytes(MEBI), format!("1.00 M"));
assert_eq!(humanbytes(MEBI+1), format!("1.00 M"));
assert_eq!(humanbytes(GIBI-1), format!("1024.00 M"));
assert_eq!(humanbytes(GIBI), format!("1.00 G"));
assert_eq!(humanbytes(GIBI+1), format!("1.00 G"));
assert_eq!(humanbytes(TEBI-1), format!("1024.00 G"));
assert_eq!(humanbytes(TEBI), format!("1.00 T"));
assert_eq!(humanbytes(TEBI+1), format!("1.00 T"));
assert_eq!(humanbytes(PEBI-1), format!("1024.00 T"));
assert_eq!(humanbytes(PEBI), format!("1.00 P"));
assert_eq!(humanbytes(PEBI+1), format!("1.00 P"));
assert_eq!(humanbytes(EXBI-1), format!("1024.00 P"));
assert_eq!(humanbytes(EXBI), format!("1.00 E"));
assert_eq!(humanbytes(EXBI+1), format!("1.00 E"));
assert_eq!(humanbytes(ZEBI-1), format!("1024.00 E"));
assert_eq!(humanbytes(ZEBI), format!("1.00 Z"));
assert_eq!(humanbytes(ZEBI+1), format!("1.00 Z"));
assert_eq!(humanbytes(YOBI-1), format!("1024.00 Z"));
assert_eq!(humanbytes(YOBI), format!("1.00 Y"));
assert_eq!(humanbytes(YOBI+1), format!("1.00 Y"));
}

22
members/pt-ccc/Cargo.toml Normal file
View file

@ -0,0 +1,22 @@
[package]
name = "pt-ccc"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
num = "0.4.1"
num-traits = "0.2.16"
pt-core = { version = "0.1.7", path = "../pt-core" }
pt-log = { version = "0.1.7", path = "../pt-log" }
pt-math = { version = "0.1.7", path = "../pt-math" }

View file

@ -15,7 +15,13 @@
use std::fmt::Display;
pub use num_traits::PrimInt;
#[allow(unused_imports)] // we possibly want to use all log levels
use pt_log::*;
#[allow(unused_imports)] // import more complex math stuff from there
use pt_math;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
/// Quick Result with a ccc error
pub type Result<T> = std::result::Result<T, Error>;
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
@ -69,38 +75,54 @@ pub enum Function {
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Top Level Error Type
///
/// Contains many variants of other errors, that can occur when using the crate.
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
/// The term has bad syntax
SyntaxError(String)
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Represents some kind of computed value
#[derive(Debug)]
pub enum Value {
/// Variable value
Variable(VarVal),
/// Numerical value
Numerical(NumVal),
/// Complex number value
Complex(ComplVal),
}
/// Represents some kind of numeric value
#[non_exhaustive]
#[derive(Debug)]
pub enum NumVal {
/// Value > 0
Signed(i128),
/// Value can be negative
Unsigned(u128),
/// Value is not an integer
Float(f64)
}
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
/// Represents a Value with at least one variable,
///
/// currently not implemented
#[derive(Debug)]
pub struct VarVal {
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Represents a Value with a complex number,
///
/// currently not implemented
#[derive(Debug)]
pub struct ComplVal {
}
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////

View file

@ -1,5 +1,8 @@
//! # Calculate expressions
//!
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
//! module.
//!
//! Calculate Calculations with your Calculator (`ccc`)
//!
//! This modules aim is to take a term of any kind ([String]) and calculate it's value, be it
@ -22,7 +25,9 @@ pub mod term;
pub use term::*;
#[allow(unused_imports)] // we possibly want to use all log levels
use crate::logger::{trace, debug, info, warn, error};
use pt_log::*;
#[allow(unused_imports)] // import more complex math stuff from there
use pt_math;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////

View file

@ -21,7 +21,10 @@ use std::collections::VecDeque;
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub use super::{Error, Result, Value, base::{self, *}};
use crate::logger::*;
#[allow(unused_imports)] // we possibly want to use all log levels
use pt_log::*;
#[allow(unused_imports)] // import more complex math stuff from there
use pt_math;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
@ -41,11 +44,14 @@ use crate::logger::*;
#[derive(Debug)]
enum Token {
/// Some kind of operator
#[allow(unused)] // tmp
Operator(Operator),
/// A concrete value that we can calculate something with. May be a constant, integer, float,
/// etc.
/// The Token has a value that can be used in calculation
Value(super::base::Value),
/// A variable of some kind that will be present in the result
#[allow(unused)] // tmp
Variable(char),
}
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
@ -65,6 +71,7 @@ pub struct Term {
/////////////////////////////////////
///// internal values following /////
/////////////////////////////////////
#[allow(unused)] // tmp
operator_stack: Vec<Operator>,
output_queue: VecDeque<Token>
}
@ -92,9 +99,9 @@ impl Term {
self.text = Self::filter(&self.original)?;
// Storage for unfinished tokens
let mut unfinished_chars: Vec<char> = Vec::new();
let _unfinished_chars: Vec<char> = Vec::new();
for (index, c) in self.original.chars().enumerate() {
for (_index, c) in self.original.chars().enumerate() {
// this will be a mess, but it has to be before i can sort the mess.
match c {
// TODO: make function to check if character is an operator, use it
@ -121,7 +128,8 @@ impl Term {
///
/// Returns: A tuple with a [`Token`] and a [`bool`]. If the bool is false, the [`Token`] is
/// marked as "incomplete", meaning that the character cannot be used yet.
fn to_tok(s: Vec<char>) -> Result<Token> {
#[allow(unused)] // tmp
fn to_tok(_s: Vec<char>) -> Result<Token> {
Ok(19.into())
}

View file

@ -0,0 +1,15 @@
[package]
name = "pt-core"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
[dependencies]

View file

@ -1,7 +1,10 @@
//! # common functionalities
//!
//! This module implements common functionality useful for many use cases, such as macros,
//! Formatting functions and more.
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
//! module.
//!
//! This crate implements core functionality useful for many use cases, such as macros,
//! formatting functions and more.
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
// we want docs
@ -23,8 +26,6 @@ pub mod macros;
pub mod printing;
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
pub const EXIT_SUCCESS: i32 = 0;
pub const EXIT_FAILURE_USAGE: i32 = 1;
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////

View file

@ -14,8 +14,6 @@
pub use crate::divider;
pub use crate::print_divider;
use pyo3::prelude::*;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
@ -47,17 +45,5 @@ macro_rules! print_divider {
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
/// python interface for [`divider!`], can also be used with rust
#[pyfunction]
pub fn divider() -> String {
divider!()
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// python interface for [`print_divider!`], can also be used with rust
#[pyfunction]
pub fn print_divider() {
print_divider!()
}
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,17 @@
[package]
name = "pt-hedu"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -0,0 +1,6 @@
//! # Dump data
//!
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
//! module.
//!
//! This crate is currently empty.

22
members/pt-log/Cargo.toml Normal file
View file

@ -0,0 +1,22 @@
[package]
name = "pt-log"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
[dependencies]
tracing = "0.1.37"
tracing-appender = "0.2.2"
tracing-subscriber = "0.3.17"
pyo3 = {workspace = true}
[dev-dependencies]
gag = "1.0.0"

View file

@ -1,12 +1,6 @@
//! # very short description
//! # Error module for [`pt-log`](crate)
//!
//! Short description
//!
//! Details
//!
//! ## Section 1
//!
//! ## Section 2
//! This module handles errors in logging contexts.
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
// we want docs
@ -22,7 +16,7 @@ use pyo3::{exceptions::PyException, PyErr};
use tracing::subscriber::SetGlobalDefaultError;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
/// a quick alias for a result with a [`LoggerError`]
/// a quick alias for a result with a [`Error`]
pub type Result<T> = std::result::Result<T, Error>;
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
@ -32,7 +26,7 @@ pub type Result<T> = std::result::Result<T, Error>;
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
/// ## Errors for the [logger](crate::logger)
/// ## Errors for the [Logger](super::Logger)
pub enum Error {
/// Bad IO operation
IO(std::io::Error),
@ -96,3 +90,4 @@ impl std::fmt::Display for Error {
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////

View file

@ -1,14 +1,18 @@
//! # A specialized Logger for [`pt`](crate)
//! # A specialized Logger for [`pt`](../libpt/index.html)
//!
//! For the library version, only the basic [`log`] is used, so that it is possible for
//! the end user to use the [`log`] frontend they desire.
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
//! module.
//!
//! For the library version, only the basic [`tracing`] is used, so that it is possible for
//! the end user to use the [`tracing`] frontend they desire.
//!
//! I did however decide to create a [`Logger`] struct. This struct is mainly intended to be used
//! with the python module of [`pt`](crate), but is still just as usable in other contexts.
//! with the python module of [`pt`](../libpt/index.html), but is still just as usable in other contexts.
//!
//! ## Technologies used for logging:
//! - [`log`]: base logging crate
//! - [`env_logger`]: used for the executable
//! - [`tracing`]: base logging crate
//! - [`tracing_appender`]: Used to log to files
//! - [`tracing_subscriber`]: Used to do actual logging, formatting, to stdout
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
@ -39,21 +43,10 @@ pub const DEFAULT_LOG_DIR: &'static str = "/dev/null";
static INITIALIZED: AtomicBool = AtomicBool::new(false);
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
/// ## Logger for [`pt`](crate)
/// ## Logger for [`pt`](../libpt/index.html)
///
/// This struct exists mainly for the python module, so that we can use the same logger with both
/// python and rust.
///
/// ### Setting a [`Level`](log::Level)
///
/// To set a [`Level`](log::Level), you need to set the environment variable `LIBPT_LOGLEVEL`
/// to either of:
///
/// - `Trace`
/// - `Debug`
/// - `Info`
/// - `Warn`
/// - `Error`
#[pyclass]
pub struct Logger {}
@ -71,7 +64,7 @@ impl Logger {
///
/// Will enable the logger to be used.
///
/// Assumes some defaults, use [`init_customized`](init_customized) for more control
/// Assumes some defaults, use [`init_customized`](Self::init_customized) for more control
pub fn init(log_dir: Option<PathBuf>, max_level: Option<Level>) -> Result<()> {
Self::init_customized(
log_dir.is_some(),
@ -107,7 +100,7 @@ impl Logger {
warn!("trying to reinitialize the logger, ignoring");
return Err(Error::Usage(format!("logging is already initialized")));
} else {
let filter = tracing_subscriber::filter::FilterFn::new(|metadata| {
let filter = tracing_subscriber::filter::FilterFn::new(|_metadata| {
// let mut filter = false;
//
// // if it's this lib, continue
@ -154,35 +147,35 @@ impl Logger {
}
}
/// ## logging at [`Level::Error`]
/// ## logging at [`Level::ERROR`]
pub fn error<T>(&self, printable: T)
where
T: fmt::Display,
{
error!("{}", printable)
}
/// ## logging at [`Level::Warn`]
/// ## logging at [`Level::WARN`]
pub fn warn<T>(&self, printable: T)
where
T: fmt::Display,
{
warn!("{}", printable)
}
/// ## logging at [`Level::Info`]
/// ## logging at [`Level::INFO`]
pub fn info<T>(&self, printable: T)
where
T: fmt::Display,
{
info!("{}", printable)
}
/// ## logging at [`Level::Debug`]
/// ## logging at [`Level::DEBUG`]
pub fn debug<T>(&self, printable: T)
where
T: fmt::Display,
{
debug!("{}", printable)
}
/// ## logging at [`Level::Trace`]
/// ## logging at [`Level::TRACE`]
pub fn trace<T>(&self, printable: T)
where
T: fmt::Display,
@ -248,7 +241,7 @@ impl Logger {
////////////////////////////////////////////////////////////////////////////////////////////////////
impl fmt::Debug for Logger {
/// ## Debug representation for [`Logger`]
/// ## DEBUG representation for [`Logger`]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
@ -261,3 +254,4 @@ impl fmt::Debug for Logger {
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////

View file

@ -0,0 +1,17 @@
[package]
name = "pt-math"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -1,12 +1,9 @@
//! # very short description
//! # General Mathmatics functionalities
//!
//! Short description
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
//! module.
//!
//! Details
//!
//! ## Section 1
//!
//! ## Section 2
//! This module is currently empty, but will contain many math functionalities in a future version.
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
// we want docs

24
members/pt-net/Cargo.toml Normal file
View file

@ -0,0 +1,24 @@
[package]
name = "pt-net"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
humantime = "2.1.0"
pt-core = { version = "0.1.0", path = "../pt-core" }
pt-log = { version = "0.1.0", path = "../pt-log" }
pt-math = { version = "0.1.0", path = "../pt-math" }
reqwest = { version = "0.11.20", features = ["blocking"] }
serde = { version = "1.0.188", features = ["serde_derive"] }
serde_json = "1.0.107"

View file

@ -1,5 +1,8 @@
//! # various networking tools
//!
//! This crate is part of [`pt`](../libpt/index.html), but can also be used as a standalone
//! module.
//!
//! The networking module contains various tools related to connections. For example, it contains a
//! tool that has the purpose to check if your connection is consistently available.

View file

@ -19,19 +19,17 @@
use std::{fmt, time::Duration};
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
use crate::logger::*;
use pt_log::*;
use reqwest;
use humantime::{format_duration, format_rfc3339};
use std::time::SystemTime;
use pyo3::prelude::*;
use serde::{Deserialize, Serialize};
use serde_json;
use crate::divider;
use pt_core::divider;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
@ -50,27 +48,20 @@ pub const DEFAULT_CHECK_URLS: &'static [&'static str] =
/// ## Describes an uptime status
///
/// [`UptimeStatus`] describes the result of an uptime check.
#[pyclass]
#[derive(Serialize, Deserialize)]
pub struct UptimeStatus {
/// true if the [`UptimeStatus`] is considered successful
#[pyo3(get, set)]
pub success: bool,
/// the percentage of reachable urls out of the total urls
#[pyo3(get, set)]
pub success_ratio: u8,
/// the percentage of reachable urls out of the total urls that need to be reachable in order
/// for this [`UptimeStatus`] to be considered a success.
#[pyo3(get, set)]
pub success_ratio_target: u8,
/// the number of reachable [`urls`](UptimeStatus::urls)
#[pyo3(get, set)]
pub reachable: usize,
/// which urls to check in [`check()`](UptimeStatus::check)
#[pyo3(get, set)]
pub urls: Vec<String>,
/// timeout length for requests (in ms)
#[pyo3(get, set)]
pub timeout: u64,
}
@ -146,38 +137,6 @@ impl UptimeStatus {
trace!("calculated success as: {}", self.success)
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Implementation of the Python interface
#[pymethods]
impl UptimeStatus {
/// calls [`new()`](UptimeStatus::new) with python compatible arguments
#[new]
pub fn py_new(success_ratio_target: u8, urls: Vec<String>, timeout: u64) -> Self {
Self::new(success_ratio_target, urls, timeout)
}
/// Same as [`check()`](UptimeStatus::check)
#[pyo3(name = "check")]
pub fn py_check(&mut self) {
self.check();
}
/// Same as [`calc_success()`](UptimeStatus::calc_success)
#[pyo3(name = "calc_success")]
pub fn py_calc_success(&mut self) {
self.calc_success();
}
/// we want to display the [`UptimeStatus`] in python too, so we need `__str__`
pub fn __str__(&self) -> String {
format!("{}", self)
}
/// we want to debug display the [`UptimeStatus`] in python too, so we need `__str__`
pub fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
impl fmt::Debug for UptimeStatus {
@ -261,30 +220,6 @@ pub fn continuous_uptime_monitor(
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Python interface for [`continuous_uptime_monitor`]
///
/// Runs the function in a different thread and checks from time to time for things like Pythons
/// `KeyboardInterrupt` exception.
#[pyfunction]
#[pyo3(name = "continuous_uptime_monitor")]
pub fn py_continuous_uptime_monitor(
py: Python,
success_ratio_target: u8,
urls: Vec<String>,
interval: u64,
timeout: u64,
) -> PyResult<()> {
// execute the function in a different thread
let _th = std::thread::spawn(move || {
continuous_uptime_monitor(success_ratio_target, urls, interval, timeout);
});
loop {
Python::check_signals(py)?;
std::thread::sleep(std::time::Duration::from_millis(100))
}
}
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
/// Displays the current status for the [continuous uptime monitor](continuous_uptime_monitor)
fn display_uptime_status(

120
members/pt-py/.github/workflows/CI.yml vendored Normal file
View file

@ -0,0 +1,120 @@
# This file is autogenerated by maturin v1.1.0
# To update, run
#
# maturin generate-ci github
#
name: CI
on:
push:
branches:
- main
- master
tags:
- '*'
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
linux:
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64, x86, aarch64, armv7, s390x, ppc64le]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
windows:
runs-on: windows-latest
strategy:
matrix:
target: [x64, x86]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
architecture: ${{ matrix.target }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
macos:
runs-on: macos-latest
strategy:
matrix:
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- name: Upload sdist
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
release:
name: Release
runs-on: ubuntu-latest
if: "startsWith(github.ref, 'refs/tags/')"
needs: [linux, windows, macos, sdist]
steps:
- uses: actions/download-artifact@v3
with:
name: wheels
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --skip-existing *

72
members/pt-py/.gitignore vendored Normal file
View file

@ -0,0 +1,72 @@
/target
# Byte-compiled / optimized / DLL files
__pycache__/
.pytest_cache/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
.venv/
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
include/
man/
venv/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
pip-selfcheck.json
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
.DS_Store
# Sphinx documentation
docs/_build/
# PyCharm
.idea/
# VSCode
.vscode/
# Pyenv
.python-version

22
members/pt-py/Cargo.toml Normal file
View file

@ -0,0 +1,22 @@
[package]
name = "pt-py"
publish.workspace = true
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "pt_py"
crate-type = ["cdylib"]
[dependencies]
pyo3 = { workspace = true }
libpt = { version = "0.1.7", path = "../../" }

21
members/pt-py/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Christoph Johannes Scherr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

76
members/pt-py/README.md Normal file
View file

@ -0,0 +1,76 @@
# pt / libpt
![pt-logo](data/media/pt-logo.svg)
`pt` stands for either one of "personal tool", "plex tool", "pete" or something among those lines.
It is a collection of tools that i might or might not use. The intended purpose of this repo is that
I program whatever i feel is worth having in a personal thing into it, then use it as either a lib,
crate, python module or executable.
Let's see if I make it a bloated mess or stop committing after 30 hello worlds.
#### But the name `pt` / `libpt` already exists!
So what? I don't care. Besides, there is not enough names to name everything unique.
## Dependencies
- See `cargo.toml`
- [openssl bindings for rust](https://docs.rs/openssl/latest/openssl/)
- [Python](https://www.python.org/)
- [`maturin`](https://maturin.rs) - `pip install maturin`
## Compiling & Installing from source
If you only want the rust library, you can simply build it with `cargo build`. Add it to your
project like any other local dependency.
If you want to use the python variant too, you need to compile with maturing.
- Install in `venv`: `maturin develop --release`
- Install in system: `maturin build --release && pip install target/wheels/libpt-x.x.x-*`
## Installing from [pypi](https://pypi.org)
`libpt` has been packaged for [pypi.org](https://pypi.org/project/libpt/).
You can install it with `pip install libpt`
## Installing from [crates.io](https://crates.io)
`libpt` has been packaged for [crates.io](https://crates.io/crates/libpt).
You can add the library to your project with `cargo add libpt`.
## Installing from my personal package registry
`libpt` has been packaged for [git.cscherr.de](https://git.cscherr.de).
You can add the registry to your `config.toml` and then `cargo add libpt`
[Package](https://git.cscherr.de/PlexSheep/-/packages/cargo/libpt/)
## Testing
Testing needs to be done separately for the rust and python parts:
- Rust testing with `cargo test`
- Python testing with `./scripts/pytests.sh` or `python -m unittest discover -fs tests/python`
## Documentation
The documentation can be automatically generated with `cargo doc --open`.
An up to date version of the Documentation can be found [here](https://docs.rs/libpt/)
## Mirrored
The origin of this repository is [git.cscherr.de](https://git.cscherr.de/PlexSheep/pt)
It is mirrored to:
- [Codeberg](https://codeberg.org/PlexSheep/pt)
## License
**Pt is MIT Licensed**

View file

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

101
members/pt-py/src/lib.rs Normal file
View file

@ -0,0 +1,101 @@
// FIXME: Using a local dependency does not work with maturin as it seems?
use libpt::{
log::*,
};
use pyo3::prelude::*;
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
/// ## Check if [`libpt`](crate) has been loaded
///
/// Always returns `true` if you can execute it.
#[pyfunction]
pub fn is_loaded() -> bool {
true
}
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
/// ## Python module: logger
#[pymodule]
fn py_logger(py: Python, parent: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "logger")?;
module.add_class::<Logger>()?;
parent.add_submodule(module)?;
Ok(())
}
//
// ////////////////////////////////////////////////////////////////////////////////////////////////////
// /// ## Python module: common
// #[pymodule]
// fn py_common(py: Python, parent: &PyModule) -> PyResult<()> {
// let module = PyModule::new(py, "common")?;
// py_common_printing(py, module)?;
//
// parent.add_submodule(module)?;
// Ok(())
// }
//
// ////////////////////////////////////////////////////////////////////////////////////////////////////
// /// ## Python module: common.printing
// #[pymodule]
// fn py_common_printing(py: Python, parent: &PyModule) -> PyResult<()> {
// let module = PyModule::new(py, "printing")?;
// module.add_function(wrap_pyfunction!(common::printing::divider, module)?)?;
// module.add_function(wrap_pyfunction!(common::printing::print_divider, module)?)?;
//
// parent.add_submodule(module)?;
// Ok(())
// }
//
// ////////////////////////////////////////////////////////////////////////////////////////////////////
// /// ## Python module: networking
// #[pymodule]
// fn py_networking(py: Python, parent: &PyModule) -> PyResult<()> {
// let module = PyModule::new(py, "networking")?;
// py_networking_monitoring(py, module)?;
//
// parent.add_submodule(module)?;
// Ok(())
// }
//
// ////////////////////////////////////////////////////////////////////////////////////////////////////
// /// ## Python module: networking.monitoring
// #[pymodule]
// fn py_networking_monitoring(py: Python, parent: &PyModule) -> PyResult<()> {
// let module = PyModule::new(py, "monitoring")?;
// py_networking_monitoring_uptime(py, module)?;
//
// parent.add_submodule(module)?;
// Ok(())
// }
//
// ////////////////////////////////////////////////////////////////////////////////////////////////////
// /// ## Python module: networking.monitoring.uptime
// #[pymodule]
// fn py_networking_monitoring_uptime(py: Python, parent: &PyModule) -> PyResult<()> {
// let module = PyModule::new(py, "uptime")?;
// module.add_class::<networking::monitoring::uptime::UptimeStatus>()?;
// module.add_function(wrap_pyfunction!(
// networking::monitoring::uptime::py_continuous_uptime_monitor,
// module
// )?)?;
//
// parent.add_submodule(module)?;
// 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!(is_loaded, m)?)?;
// load sub modules
// py_common(py, m)?;
py_logger(py, m)?;
// py_networking(py, m)?;
Ok(())
}

View file

@ -1,129 +1,22 @@
//! # `libpt`
//! # A library for common needs
//!
//! [`libpt`](crate) contains my personal code. It is compiled as all of the following:
//! `pt` aims to implement a number of functionalities that might me useful to develop
//! programs in Rust. It aims to be a collection of generally, possibly useful things.
//!
//! - dynamic library (`cdylib`, `.so` file on Linux)
//! - rust library crate (`rlib`, usable as )
//! - python module (with [`PyO3`](pyo3))
//! - executable (as `pt`)
//!
//! For more info on the linkage types, please refer to the
//! [rust reference](https://doc.rust-lang.org/reference/linkage.html).
//! `pt` is a project consisting of multiple smaller crates, all bundled together in this
//! "main crate". Most crates will only show up if you activate their feature.
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
// we want docs
#![warn(missing_docs)]
#![warn(rustdoc::missing_crate_level_docs)]
// we want Debug everywhere. This is a library and there will be many bugs.
#![warn(missing_debug_implementations)]
// enable clippy's extra lints, the pedantic version
#![warn(clippy::pedantic)]
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
/// contains useful code, such as macros, for general use
pub mod common;
/// logger used by libpt
pub mod logger;
/// networking tools
pub mod networking;
/// math tools
pub mod math;
use crate::logger::Logger;
use pyo3::prelude::*;
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
/// ## Check if [`libpt`](crate) has been loaded
///
/// Always returns `true` if you can execute it.
#[pyfunction]
pub fn is_loaded() -> bool {
true
}
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
/// ## Python module: logger
#[pymodule]
fn py_logger(py: Python, parent: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "logger")?;
module.add_class::<Logger>()?;
parent.add_submodule(module)?;
Ok(())
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Python module: common
#[pymodule]
fn py_common(py: Python, parent: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "common")?;
py_common_printing(py, module)?;
parent.add_submodule(module)?;
Ok(())
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Python module: common.printing
#[pymodule]
fn py_common_printing(py: Python, parent: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "printing")?;
module.add_function(wrap_pyfunction!(common::printing::divider, module)?)?;
module.add_function(wrap_pyfunction!(common::printing::print_divider, module)?)?;
parent.add_submodule(module)?;
Ok(())
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Python module: networking
#[pymodule]
fn py_networking(py: Python, parent: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "networking")?;
py_networking_monitoring(py, module)?;
parent.add_submodule(module)?;
Ok(())
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Python module: networking.monitoring
#[pymodule]
fn py_networking_monitoring(py: Python, parent: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "monitoring")?;
py_networking_monitoring_uptime(py, module)?;
parent.add_submodule(module)?;
Ok(())
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Python module: networking.monitoring.uptime
#[pymodule]
fn py_networking_monitoring_uptime(py: Python, parent: &PyModule) -> PyResult<()> {
let module = PyModule::new(py, "uptime")?;
module.add_class::<networking::monitoring::uptime::UptimeStatus>()?;
module.add_function(wrap_pyfunction!(
networking::monitoring::uptime::py_continuous_uptime_monitor,
module
)?)?;
parent.add_submodule(module)?;
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!(is_loaded, m)?)?;
// load sub modules
py_common(py, m)?;
py_logger(py, m)?;
py_networking(py, m)?;
Ok(())
}
#[cfg(feature = "core")]
pub use pt_core as core;
#[cfg(feature = "bintols")]
pub use pt_bintols as bintols;
#[cfg(feature = "hedu")]
pub use pt_hedu as hedu;
#[cfg(feature = "log")]
pub use pt_log as log;
#[cfg(feature = "math")]
pub use pt_math as math;
#[cfg(feature = "net")]
pub use pt_net as net;
#[cfg(feature = "ccc")]
pub use pt_ccc as ccc;

View file

@ -1,41 +0,0 @@
//! # very short description
//!
//! Short description
//!
//! Details
//!
//! ## Section 1
//!
//! ## Section 2
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
// we want docs
#![warn(missing_docs)]
#![warn(rustdoc::missing_crate_level_docs)]
// we want Debug everywhere.
#![warn(missing_debug_implementations)]
// enable clippy's extra lints, the pedantic version
#![warn(clippy::pedantic)]
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub mod calculator;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

View file

View file

@ -1,12 +0,0 @@
/// # tests for the general behaviour of the libraries availability
///
/// These tests will not go very in depth
// IMPORTS /////////////////////////////////////////////////////////////////////////////////////////
use pt;
/// ## check if pt is loaded
#[test]
fn test_pt_is_loaded() {
assert!(pt::is_loaded())
}

View file

@ -1,15 +0,0 @@
"""
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

@ -1,21 +0,0 @@
"""
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

@ -1,88 +0,0 @@
//! # Tests for pt::logger::Logger
//!
//! Note: the module uses a global variable to store if the thread has
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
use pt::common::macros::get_stdout_for;
/// ## Tests for basic logging functionality
use pt::logger::*;
use regex::Regex;
use std::sync::Once;
//// HELPERS ///////////////////////////////////////////////////////////////////////////////////////
static SETUP: Once = Once::new();
// only initialize once
/// ## setup that's needed before testing the logger struct
fn setup() {
SETUP.call_once(|| {
// we don't want to log messages during our tests!
Logger::init_customized(
false,
std::path::PathBuf::from("/dev/null"),
false,
false,
true,
false,
tracing::Level::TRACE,
false,
false,
false,
)
.expect("could not initialize Logger");
println!()
});
}
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
/// ## Tests for basic logging
///
/// This test tests if the loggers basic logging functionality works, that is it's methods:
///
/// - [`Logger::trace`]
/// - [`Logger::debug`]
/// - [`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() {
setup();
let l = Logger::new();
let trace_out = get_stdout_for!(l.trace("MSG"));
let debug_out = get_stdout_for!(l.debug("MSG"));
let info_out = get_stdout_for!(l.info("MSG"));
let warn_out = get_stdout_for!(l.warn("MSG"));
let error_out = get_stdout_for!(l.error("MSG"));
let combined = format!(
"{}{}{}{}{}",
trace_out, debug_out, info_out, warn_out, error_out
);
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"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z\s+(TRACE|DEBUG|INFO|WARN|ERROR)\sMSG"
))
.unwrap();
// we have 5 log levels, therefore we should have 5 captures
assert_eq!(regex.captures_iter(&combined).count(), 5);
}
#[test]
fn test_multi_initialize() {
setup();
let l = Logger::new();
// these should be ignored due to the global flag
Logger::init(None, None).unwrap_err();
Logger::init(None, None).unwrap_err();
Logger::init(None, None).unwrap_err();
Logger::init(None, None).unwrap_err();
l.info("Successfully ignored extra init");
}