Compare commits

..

No commits in common. "5b2a23d06af8943b5e17a325a671fc4058b5c8df" and "a5475a460bec45e3fe368a8c31ffc6d56d3e607b" have entirely different histories.

5 changed files with 89 additions and 248 deletions

View File

@ -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
```

25
run.py
View File

@ -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)

View File

@ -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)
}
}

View File

@ -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

View File

@ -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