Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.0.10 #12

Merged
merged 5 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/tests_and_coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
run: pip list

- name: Run tests and show coverage on the command line
run: coverage run --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m
run: coverage run --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m --fail-under=100

- name: Upload reports to codecov
env:
Expand All @@ -45,4 +45,4 @@ jobs:
./codecov -t ${CODECOV_TOKEN}

- name: Run tests and show the branch coverage on the command line
run: coverage run --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m
run: coverage run --branch --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m --fail-under=100
4 changes: 2 additions & 2 deletions .github/workflows/tests_and_coverage_old.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
run: pip list

- name: Run tests and show coverage on the command line
run: coverage run --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m
run: coverage run --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m --fail-under=100

- name: Upload reports to codecov
env:
Expand All @@ -45,4 +45,4 @@ jobs:
./codecov -t ${CODECOV_TOKEN}

- name: Run tests and show the branch coverage on the command line
run: coverage run --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m
run: coverage run --branch --source=metronomes --omit="*tests*" -m pytest --cache-clear --assert=plain && coverage report -m --fail-under=100
27 changes: 20 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This library offers the easiest way to run regular tasks. Just give it a functio
- [**Logging**](#logging)
- [**Error escaping**](#error-escaping)
- [**Working with Cancellation Tokens**](#working-with-cancellation-tokens)
- [**Limitations**](#limitations)
- [**How to set a time limit**](#how-to-set-a-time-limit)


## Quick start
Expand Down Expand Up @@ -247,19 +247,32 @@ metronome.start(token=TimeoutToken(1))
If you pass cancellation tokens both during metronome initialization and in the `start()` method, their limitations will be summed up.


## Limitations
## How to set a time limit

You can limit the total running time of the metronome by setting the `duration` value (in seconds):
You can specify a time limit (in seconds) for which the metronome will tick. When the specified time is over, it will simply stop. There are 2 ways to do this: when creating a metronome object or when calling the `start()` method.

```python
from time import sleep
from metronomes import Metronome
In the first way, the time will start counting from the moment the metronome object is created:

metronome = Metronome(0.2, lambda: print('go!'), duration=0.6)
```python
metronome = Metronome(0.2, lambda: print('go!'), duration=0.6)

metronome.start()
sleep(1)
#> go!
#> go!
#> go!
```

In the second way, the countdown will start by calling the `start()` method:

```python
metronome = Metronome(0.2, lambda: print('go!'))

metronome.start(duration=0.6)
sleep(1)
#> go!
#> go!
#> go!
```

Choose the right way to limit time. When using the metronome in the [context manager mode](#use-it-as-a-context-manager), only the first way is available to you, in almost all other situations - the second one is preferable.
19 changes: 13 additions & 6 deletions metronomes/metronome.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ def __init__(self, iteration: Union[int, float], callback: Callable[[], Any], su
self.logger: LoggerProtocol = logger
self.token: AbstractToken = SimpleToken(token)
if duration is not None:
if duration < 0:
raise ValueError('The total duration of the metronome operation cannot be less than zero.')
elif iteration > duration:
raise ValueError('The time of one iteration cannot exceed the running time of the metronome as a whole.')
self.token = self.token + TimeoutToken(duration)
self.token += self.create_duration_token(duration)
self.thread: Optional[Thread] = None
self.started: bool = False
self.stopped: bool = False
Expand All @@ -52,13 +48,16 @@ def __exit__(self, exception_type: Optional[Type[BaseException]], exception_valu
self.stop()
return False

def start(self, token: AbstractToken = DefaultToken()) -> 'Metronome':
def start(self, token: AbstractToken = DefaultToken(), duration: Optional[Union[int, float]] = None) -> 'Metronome':
with self.lock:
if self.stopped:
raise RunStoppedMetronomeError('Metronomes are disposable, you cannot restart a stopped metronome.')
if self.started:
raise RunAlreadyStartedMetronomeError('The metronome has already been launched.')

if duration is not None:
token += self.create_duration_token(duration)

self.thread = Thread(target=self.run_loop, args=(self.token + token,))
self.thread.daemon = True

Expand Down Expand Up @@ -102,3 +101,11 @@ def run_loop(self, token: AbstractToken) -> None:
self.sleeping_callback(sleep_time)

self.stopped = True

def create_duration_token(self, duration: Union[int, float]) -> TimeoutToken:
if duration < 0:
raise ValueError('The total duration of the metronome operation cannot be less than zero.')
elif self.iteration > duration:
raise ValueError('The time of one iteration cannot exceed the running time of the metronome as a whole.')

return TimeoutToken(duration)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = 'setuptools.build_meta'

[project]
name = 'metronomes'
version = '0.0.9'
version = '0.0.10'
authors = [
{ name='Evgeniy Blinov', email='[email protected]' },
]
Expand Down
21 changes: 21 additions & 0 deletions tests/units/test_metronome.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,21 @@ def test_iteration_more_than_duration():
Metronome(5, lambda: None, duration=1)


def test_iteration_more_than_duration_in_start_method():
with pytest.raises(ValueError, match=full_match('The time of one iteration cannot exceed the running time of the metronome as a whole.')):
Metronome(5, lambda: None).start(duration=1)


def test_duration_less_than_zero():
with pytest.raises(ValueError, match=full_match('The total duration of the metronome operation cannot be less than zero.')):
Metronome(0.5, lambda: None, duration=-1)


def test_duration_less_than_zero_in_start_method():
with pytest.raises(ValueError, match=full_match('The total duration of the metronome operation cannot be less than zero.')):
Metronome(0.5, lambda: None).start(duration=-1)


def test_set_duration_time():
metronome = Metronome(0.00001, lambda: None, duration=0.001)

Expand All @@ -258,6 +268,17 @@ def test_set_duration_time():
assert metronome.stopped


def test_set_duration_in_start_method():
metronome = Metronome(0.00001, lambda: None)

assert not metronome.stopped

metronome.start(duration=0.001)
sleep(0.1)

assert metronome.stopped


def test_context_manager_basics():
actions = []
metronome = Metronome(0.00001, lambda: actions.append(1))
Expand Down
Loading