diff --git a/README.md b/README.md index 348d3b9..2a88882 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ +![A logo with the word tictoc followed by a stopwatch emoji](./.docs/logoLightMode.png#gh-light-mode-only) +![A logo with the word tictoc followed by a stopwatch emoji](./.docs/logoDarkMode.png#gh-dark-mode-only) + # Fast, simple and accurate Python timing. Written in Rust. +![badge](https://github.com/andrwcnln/tictoc-py/actions/workflows/python.yml/badge.svg) +![badge](https://github.com/andrwcnln/tictoc-py/actions/workflows/rust.yml/badge.svg) ![badge](https://img.shields.io/pypi/dm/tictoc) ## Installation @@ -9,76 +14,40 @@ $ python -m pip install tictoc ``` ## Usage -Import. +Import and initialise. **The module must be initialised to be used!** ```python -from tictoc import tic,toc +import tictoc +t = tictoc.init() ``` -If you only want to time one section of code then use `tic() and `toc()` directly. Begin timing with `tic()`, and stop with `toc()`. +Begin timing with `tic()`, and stop with `toc()`. ```python -tic() +t.tic() # some code -toc() +t.toc() ``` -A call to `tic()` can be followed with multiple `toc()` calls. Each will print the time elapsed since the most recent `tic()` call. +When `toc` is called, the results are saved. They can be accessed with the following syntax: ```python -tic() -time.sleep(3) -toc() -# >>> The elapsed time was 3.000132333 seconds. -time.sleep(3) -toc() -# >>> The elapsed time was 6.000383124 seconds. -``` -For more complex timing operations, you can assign the output of `tic()` and pass it as an input to `toc()`. -> [!NOTE] -> This syntax cannot be used interchangeably with the default syntax above. Any call to `tic()` resets the global timer. -```python -firstTic = tic() -time.sleep(3) -secondTic = tic() -time.sleep(1) -toc(firstTic) -# >>> The elapsed time was 4.000317251 seconds. -time.sleep(3) -toc(secondTic) -# >>> The elapsed time was 4.000312568 seconds. -``` -Any call to `toc()` will print the elapsed time in seconds. You can save the results with full precision by assigning the output of `toc()`. -```python -tic() -# some code -results = toc() +t.results.{unit} ``` The available units are: ```python -results.nanos # u128 -results.micros # u128 -results.millis # u128 -results.seconds # f64 +t.results.nanos # u128 +t.results.micros # u128 +t.results.millis # u128 +t.results.seconds # f64 ``` ## Full example ```python import time -from tictoc import tic,toc -tic() # start timing +import tictoc +t = tictoc.init() + +t.tic() # start timing time.sleep(3) # sleep for 3 seconds -toc() # stop timing -# >>> The elapsed time was 3.000132333 seconds. +t.toc() # stop timing -firstTic = tic() -time.sleep(3) -secondTic = tic() -time.sleep(1) -toc(firstTic) -# >>> The elapsed time was 4.000317251 seconds. -time.sleep(3) -toc(secondTic) -# >>> The elapsed time was 4.000312568 seconds. - -tic() -results = toc() -print(results.nanos) -# >>> 2825 +print(t.results.seconds) +# >>> 3.000457715 ``` diff --git a/run.py b/run.py index 62ee3df..64b2978 100644 --- a/run.py +++ b/run.py @@ -1,22 +1,11 @@ import time -from tictoc import tic,toc -tic() # start timing -time.sleep(3) # sleep for 3 seconds -toc() # stop timing -# >>> The elapsed time was 3.000132333 seconds. +import tictoc -firstTic = tic() -time.sleep(3) -secondTic = tic() -time.sleep(1) -toc(firstTic) -# >>> The elapsed time was 4.000317251 seconds. -time.sleep(3) -toc(secondTic) -# >>> The elapsed time was 4.000312568 seconds. +t = tictoc.init() -tic() -results = toc() -print(results.nanos) -# >>> 2825 +t.tic() # start timing +time.sleep(3) # sleep for 3 seconds +t.toc() # stop timing + +print(t.results.seconds) diff --git a/src/lib.rs b/src/lib.rs index 66a1b23..00bbdf3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ mod tictoc { use pyo3::exceptions::PyException; #[pyclass] - #[derive(Clone, Debug, PartialEq)] + #[derive(Clone)] struct Results { #[pyo3(get)] nanos: u128, @@ -74,7 +74,6 @@ mod tictoc { } } } - #[test] fn test_new() { let init = Init::new(); @@ -85,48 +84,17 @@ mod tictoc { fn test_tic() { let mut init = Init::new(); let time1 = init.time; - let _ = init.tic(); + init.tic(); let time2 = init.time; assert!(time2 > time1) } - + #[test] fn test_toc() { let mut init = Init::new(); - let _ = init.tic(); + init.tic(); println!("{}","test"); - let _ = init.toc(None).unwrap(); - assert!(init.results.nanos > 0); - } - - #[test] - fn test_passing_tic_to_toc() { - let mut init = Init::new(); - let tic_obj = init.tic().unwrap(); - println!("{}","test"); - let results = init.toc(Some(tic_obj)).unwrap(); - assert!(init.results.nanos > 0); - assert_eq!(init.results,results) - } - - #[test] - fn test_multiple_calls() { - let mut init = Init::new(); - let first_tic = init.tic().unwrap(); - println!("{}","test"); - let second_tic = init.tic().unwrap(); - println!("{}","test"); - let results2 = init.toc(Some(second_tic)).unwrap(); - let results = init.toc(Some(first_tic)).unwrap(); - assert!(results.nanos > results2.nanos); - } - - #[test] - fn test_toc_before_tic() { - let mut init = Init::new(); - //assert!(init.toc(None).is_err()) - pyo3::prepare_freethreaded_python(); - let e = init.toc(None).unwrap_err(); - assert_eq!(e.to_string(),"Exception: tic() must be called before toc()") + let _ = init.toc(); + assert!(init.results.nanos > 0) } } diff --git a/tests/test.py b/tests/test.py index 7fbfdd4..b019fd2 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1,41 +1,43 @@ import pytest -from tictoc import tic,toc +import tictoc import time import math + +@pytest.fixture +def t(): + t = tictoc.init() + return t + + class testFunctionality: - def testBasic(self): - tic() + def testBasic(self, t): + t.tic() print("test") - results = toc() - assert results.seconds > 0 + t.toc() + assert t.results.seconds > 0 - def testMultipleGlobalCalls(self): - tic() + def testOverwrite(self, t): + t.tic() print("test") - results = toc() + t.toc() + firstResult = t.results.seconds print("test2") - results2 = toc() + t.toc() + secondResult = t.results.seconds - assert results.seconds < results2.seconds - - def testMultipleCalls(self): - first = tic() - print("test") - second = tic() - print("test2") - secondResult = toc(second).seconds - firstResult = toc(first).seconds - - assert firstResult > secondResult + assert firstResult < secondResult class testInvalid: - def testNonTicInputForToc(self): + def testNoInit(self): with pytest.raises(Exception): - tic() - print("test") - toc(1) + t.tic() + + def testTocBeforeTic(self, t): + with pytest.raises(Exception): + t.toc() + @pytest.mark.parametrize("sleepTime", [0.05, 0.5, 1]) class testAccuracy: @@ -43,47 +45,42 @@ class testAccuracy: def tol(self): return 0.0006 - def testSingleCall(self, sleepTime, tol): - tic() + def testSingleCall(self, t, sleepTime, tol): + t.tic() time.sleep(sleepTime) - results = toc() - assert (results.seconds < sleepTime+tol) + t.toc() + assert (t.results.seconds > sleepTime) & ( + t.results.seconds < (t.results.seconds + tol) + ) - def testMultipleGlobalCalls(self, sleepTime, tol): - tic() + def testMultipleCalls(self, t, sleepTime, tol): + t.tic() time.sleep(sleepTime) - toc() + t.toc() time.sleep(sleepTime) - results = toc() - assert (results.seconds < (sleepTime * 2)+tol) + t.toc() + assert (t.results.seconds > sleepTime * 2) & ( + t.results.seconds < (t.results.seconds + tol) + ) - def testMultipleCalls(self, sleepTime, tol): - first = tic() - time.sleep(sleepTime) - second = tic() - time.sleep(sleepTime) - results2 = toc(second) - results = toc(first) - assert (results.seconds < (sleepTime * 2)+tol) - assert (results2.seconds < sleepTime+tol) class testConsistency: - def testMicros(self): - tic() + def testMicros(self, t): + t.tic() print("test") - results = toc() - assert results.micros == (math.floor(results.nanos * pow(10, -3))) + t.toc() + assert t.results.micros == (math.floor(t.results.nanos * pow(10, -3))) - def testMillis(self): - tic() + def testMillis(self, t): + t.tic() print("test") - results = toc() - assert results.millis == (math.floor(results.nanos * pow(10, -6))) + t.toc() + assert t.results.millis == (math.floor(t.results.nanos * pow(10, -6))) - def testSeconds(self): - tic() + def testSeconds(self, t): + t.tic() print("test") - results = toc() - assert results.seconds == round( - (results.nanos * pow(10, -9)), 9 + t.toc() + assert t.results.seconds == round( + (t.results.nanos * pow(10, -9)), 9 ) # f64 vs u128, hence the round diff --git a/tests/testInitSyntax.py b/tests/testInitSyntax.py deleted file mode 100644 index 97b7557..0000000 --- a/tests/testInitSyntax.py +++ /dev/null @@ -1,82 +0,0 @@ -import pytest -import tictoc -import time -import math - - -@pytest.fixture -def t(): - t = tictoc.init() - return t - - -class testFunctionality: - def testBasic(self, t): - t.tic() - print("test") - t.toc() - assert t.results.seconds > 0 - - def testOverwrite(self, t): - t.tic() - print("test") - t.toc() - firstResult = t.results.seconds - print("test2") - t.toc() - secondResult = t.results.seconds - - assert firstResult < secondResult - - -class testInvalid: - def testNoInit(self): - with pytest.raises(Exception): - t.tic() - - def testTocBeforeTic(self, t): - with pytest.raises(Exception): - t.toc() - - -@pytest.mark.parametrize("sleepTime", [0.05, 0.5, 1]) -class testAccuracy: - @pytest.fixture(scope="class") - def tol(self): - return 0.0006 - - def testSingleCall(self, t, sleepTime, tol): - t.tic() - time.sleep(sleepTime) - t.toc() - assert (t.results.seconds < sleepTime+tol) - - def testMultipleCalls(self, t, sleepTime, tol): - t.tic() - time.sleep(sleepTime) - t.toc() - time.sleep(sleepTime) - t.toc() - assert (t.results.seconds < (sleepTime * 2)+tol) - - -class testConsistency: - def testMicros(self, t): - t.tic() - print("test") - t.toc() - assert t.results.micros == (math.floor(t.results.nanos * pow(10, -3))) - - def testMillis(self, t): - t.tic() - print("test") - t.toc() - assert t.results.millis == (math.floor(t.results.nanos * pow(10, -6))) - - def testSeconds(self, t): - t.tic() - print("test") - t.toc() - assert t.results.seconds == round( - (t.results.nanos * pow(10, -9)), 9 - ) # f64 vs u128, hence the round