Compare commits

...

3 Commits

Author SHA1 Message Date
5b2a23d06a [2024-12-18] Update README and run.py to reflect new syntax
Also remove GitHub specific links and logo
2024-12-18 15:42:10 +00:00
2a3087ad35 [2024-12-18] Update Rust tests, add relevant derives to Results 2024-12-18 13:55:35 +00:00
bec55635f9 [2024-12-18] Adding tests for new syntax
- Moving old tests into `testInitSyntax.py`
- This syntax is still supported
- `testInitSyntax.py` also tests calling tic() before toc(), which is
not possible with the setup of `test.py`. This should be moved to its
own file soon.
2024-12-18 12:28:00 +00:00
5 changed files with 248 additions and 89 deletions

View File

@ -1,10 +1,5 @@
![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
@ -14,40 +9,76 @@ $ python -m pip install tictoc
```
## Usage
Import and initialise. **The module must be initialised to be used!**
Import.
```python
import tictoc
t = tictoc.init()
from tictoc import tic,toc
```
Begin timing with `tic()`, and stop with `toc()`.
If you only want to time one section of code then use `tic() and `toc()` directly. Begin timing with `tic()`, and stop with `toc()`.
```python
t.tic()
tic()
# some code
t.toc()
toc()
```
When `toc` is called, the results are saved. They can be accessed with the following syntax:
A call to `tic()` can be followed with multiple `toc()` calls. Each will print the time elapsed since the most recent `tic()` call.
```python
t.results.{unit}
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()
```
The available units are:
```python
t.results.nanos # u128
t.results.micros # u128
t.results.millis # u128
t.results.seconds # f64
results.nanos # u128
results.micros # u128
results.millis # u128
results.seconds # f64
```
## Full example
```python
import time
from tictoc import tic,toc
import tictoc
t = tictoc.init()
t.tic() # start timing
tic() # start timing
time.sleep(3) # sleep for 3 seconds
t.toc() # stop timing
toc() # stop timing
# >>> The elapsed time was 3.000132333 seconds.
print(t.results.seconds)
# >>> 3.000457715
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
```

25
run.py
View File

@ -1,11 +1,22 @@
import time
from tictoc import tic,toc
import tictoc
tic() # start timing
time.sleep(3) # sleep for 3 seconds
toc() # stop timing
# >>> The elapsed time was 3.000132333 seconds.
t = tictoc.init()
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.tic() # start timing
time.sleep(3) # sleep for 3 seconds
t.toc() # stop timing
print(t.results.seconds)
tic()
results = toc()
print(results.nanos)
# >>> 2825

View File

@ -7,7 +7,7 @@ mod tictoc {
use pyo3::exceptions::PyException;
#[pyclass]
#[derive(Clone)]
#[derive(Clone, Debug, PartialEq)]
struct Results {
#[pyo3(get)]
nanos: u128,
@ -74,6 +74,7 @@ mod tictoc {
}
}
}
#[test]
fn test_new() {
let init = Init::new();
@ -84,17 +85,48 @@ mod tictoc {
fn test_tic() {
let mut init = Init::new();
let time1 = init.time;
init.tic();
let _ = init.tic();
let time2 = init.time;
assert!(time2 > time1)
}
#[test]
fn test_toc() {
let mut init = Init::new();
init.tic();
let _ = init.tic();
println!("{}","test");
let _ = init.toc();
assert!(init.results.nanos > 0)
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()")
}
}

View File

@ -1,43 +1,41 @@
import pytest
import tictoc
from tictoc import tic,toc
import time
import math
@pytest.fixture
def t():
t = tictoc.init()
return t
class testFunctionality:
def testBasic(self, t):
t.tic()
def testBasic(self):
tic()
print("test")
t.toc()
assert t.results.seconds > 0
results = toc()
assert results.seconds > 0
def testOverwrite(self, t):
t.tic()
def testMultipleGlobalCalls(self):
tic()
print("test")
t.toc()
firstResult = t.results.seconds
results = toc()
print("test2")
t.toc()
secondResult = t.results.seconds
results2 = toc()
assert firstResult < secondResult
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
class testInvalid:
def testNoInit(self):
def testNonTicInputForToc(self):
with pytest.raises(Exception):
t.tic()
def testTocBeforeTic(self, t):
with pytest.raises(Exception):
t.toc()
tic()
print("test")
toc(1)
@pytest.mark.parametrize("sleepTime", [0.05, 0.5, 1])
class testAccuracy:
@ -45,42 +43,47 @@ class testAccuracy:
def tol(self):
return 0.0006
def testSingleCall(self, t, sleepTime, tol):
t.tic()
def testSingleCall(self, sleepTime, tol):
tic()
time.sleep(sleepTime)
t.toc()
assert (t.results.seconds > sleepTime) & (
t.results.seconds < (t.results.seconds + tol)
)
results = toc()
assert (results.seconds < sleepTime+tol)
def testMultipleCalls(self, t, sleepTime, tol):
t.tic()
def testMultipleGlobalCalls(self, sleepTime, tol):
tic()
time.sleep(sleepTime)
t.toc()
toc()
time.sleep(sleepTime)
t.toc()
assert (t.results.seconds > sleepTime * 2) & (
t.results.seconds < (t.results.seconds + tol)
)
results = toc()
assert (results.seconds < (sleepTime * 2)+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, t):
t.tic()
def testMicros(self):
tic()
print("test")
t.toc()
assert t.results.micros == (math.floor(t.results.nanos * pow(10, -3)))
results = toc()
assert results.micros == (math.floor(results.nanos * pow(10, -3)))
def testMillis(self, t):
t.tic()
def testMillis(self):
tic()
print("test")
t.toc()
assert t.results.millis == (math.floor(t.results.nanos * pow(10, -6)))
results = toc()
assert results.millis == (math.floor(results.nanos * pow(10, -6)))
def testSeconds(self, t):
t.tic()
def testSeconds(self):
tic()
print("test")
t.toc()
assert t.results.seconds == round(
(t.results.nanos * pow(10, -9)), 9
results = toc()
assert results.seconds == round(
(results.nanos * pow(10, -9)), 9
) # f64 vs u128, hence the round

82
tests/testInitSyntax.py Normal file
View File

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