Added a proper README and the peek() method to TTLStack. Also some fixes to docs

This commit is contained in:
nocturn9x 2020-05-31 16:40:03 +02:00
parent 1943defbdc
commit 369f9cd44e
2 changed files with 192 additions and 21 deletions

185
README.md
View File

@ -2,19 +2,188 @@
`ttlcollections` is a pure Python implementation of a various data structures with built-in TTL (time to live) functionality, using nothing but the standard library.
## Usage
Coming soon
## Installation
Coming soon
To install the library from source simply clone this repository and run the command `python3 setup.py install`
## Usage
As of now `ttlcollections` implements 2 data structures: a queue and a stack.
The difference between a stack and a queue is that the former follows the LIFO (Last-in First-out) scheme, while the latter follows the FIFO (First-in First out) scheme.
These 2 collections are implemented using `collections.deque` for fast `O(1)` complexity when accessing elements trough `pop`/`get` and `push`/`put`
For both queues and stacks you can pass
### Example - TTLQueue
```python
from ttlcollections import TTLQueue
import time
q = TTLQueue(ttl=60) # Elements that are older than 60 seconds will be deleted
q.put(1)
time.sleep(60)
q.get() # Will raise ttlcollections.errors.QueueEmpty because the TTL for 1 has expired
```
#### Methods
This is the methods documentation for TTLStack in Sphinx format
##### `TTLQueue` - `__init__()`
A FIFO data structure with per-item time to live (TTL)
All items will have a default time to live, after that has
expired (on the next mutating operation a.k.a put or get)
expired elements will be popped out automatically.
It is also possible to set a different TTL for every item and to
define the maximum queue size.
__Note__: This queue is __NOT__ thread safe and must be properly locked
when used with multiple threads
```
:param qsize: The max size of the queue, defaults to 0 (no limit)
:type qsize: int, optional
:param ttl: The TTL for every item in the queue, defaults to 0 (no TTL)
:type ttl: int, optional
:param timer: The timer function that the queue will use to
keep track of elapsed time. Defaults to time.monotonic(), but can
be customized. Any function that yields an incremental value
on each subsequent call is acceptable, but its return values
should not be repeated during runtime to avoid nonsense results
:type timer: class: FunctionType, optional
```
##### `TTLQueue` - `put()`
Pops expired element out of the queue if their TTL has expired by when units of time (usually seconds)
```
:param when: The expiry date to check items against. Items' whose
insertion date, according to self.timer, is less or equal
than this number will be automatically deleted
:type when: int
```
##### `TTLQueue` - `get()`
Puts an item onto the queue
```
:param element: The element to put in the queue
:type element: object
:param ttl: If you want to override the default ttl
of the class for a specific element, you can specify
that, defaults to 0 (use the default TTL)
:param ttl: int, optional
:raises QueueFull: If the queue is full
```
##### `TTLQueue` - `expire()`
Pops expired element out of the queue if their TTL has expired by `when` units of time (usually seconds)
```
:param when: The expiry date to check items against. Items' whose
insertion date, according to self.timer, is less or equal
than this number will be automatically deleted
:type when: int
```
### Example - TTLStack
```python
from ttlcollections import TTLStack
import time
q = TTLStack(ttl=60) # Elements that are older than 60 seconds will be deleted
q.push(1)
time.sleep(60)
q.pop() # Will raise ttlcollections.errors.StackEmpty because the TTL for 1 has expired
```
#### Methods
This is the methods documentation for TTLStack in Sphinx format
##### `TTLStack` - `__init__()`
A stack-like (LIFO) data structure with per-item time to live (TTL).
All items will have a default time to live, after that has
expired (on the next mutating operation a.k.a push or pop)
elements will be popped out automatically.
It is also possible to set a different TTL for every item and to define the maximum stack size
**Note**: This stack is __NOT__ thread safe and must be properly locked when used with multiple threads
```
:param size: The max size of the stack, defaults to 0 (no limit)
:type size: int, optional
:param ttl: The TTL for every item in the stack, defaults to 0 (no TTL)
:type ttl: int, optional
:param timer: The timer function that the stack will use to
keep track of elapsed time. Defaults to time.monotonic(), but can
be customized. Any function that yields an incremental value
on each subsequent call is acceptable, but its return values
should not be repeated during runtime to avoid nonsense results
:type timer: class: FunctionType, optional
```
##### `TTLStack` - `push()`
Pushes an item onto the stack
```
:param element: The element to push
:type element: object
:param ttl: If you want to override the default ttl
of the class for a specific element, you can specify
that, defaults to 0 (use the default TTL)
:param ttl: int, optional
:raises StackFull: If the stack is full
```
##### `TTLStack` - `pop()`
Pops an item from the stack, raising StackEmpty if the stack is empty
```
:raises StackEmpty: If the stack is empty
```
##### `TTLStack` - `expire()`
Pops expired element out of the stack if their TTL has expired by `when` units of time (usually seconds)
```
:param when: The expiry date to check items against.
Items' whose insertion date, according to self.timer, is less or equal than this number
will be automatically deleted
:type when: int
```
#### Notes
Please consider that the TTL expiration check is done at every mutating operation (e.g. `put` or `pop`) and that already expired elements may take space in memory until one of these methods is called.
You can force the TTL expiration check by calling the `expire` method. This method takes a single parameter and will delete all items in the collection that have expired the by the current time (according to the timer function) plus the specified amount of time units (usually seconds). For the current time you can use the collection's internal timer function (e.g. `TTLQueue.timer()`)
## Credits
Coming soon
Nocturn9x - Main developer
### Contacts for Nocturn9x
[Telegram](https://telegram.me/processare)
[Email](mailto:nocturn9x@intellivoid.net)
## FAQs
Coming soon

View File

@ -4,6 +4,7 @@ from types import FunctionType
import math
from .errors import QueueEmpty, QueueFull, StackEmpty, StackFull
class TTLQueue:
"""A FIFO data structure with per-item time to live (TTL)
@ -22,8 +23,7 @@ class TTLQueue:
:type ttl: int, optional
:param timer: The timer function that the queue will use to
keep track of elapsed time. Defaults to time.monotonic(), but can
be customized (another monotonic clock is timeit.default_timer, for
instance). Any function that yields an incremental value
be customized. Any function that yields an incremental value
on each subsequent call is acceptable, but its return values
should not be repeated during runtime to avoid nonsense results
:type timer: class: FunctionType, optional
@ -101,7 +101,7 @@ class TTLQueue:
yield element
class TTLStack(TTLQueue):
class TTLStack:
"""A stack-like (LIFO) data structure with per-item time to live (TTL)
All items will have a default time to live, after that has
expired (on the next mutating operation a.k.a push or pop)
@ -112,23 +112,24 @@ class TTLStack(TTLQueue):
Note: This stack is NOT thread safe and must be properly locked
when used with multiple threads
:param qsize: The max size of the stack, defaults to 0 (no limit)
:type qsize: int, optional
:param size: The max size of the stack, defaults to 0 (no limit)
:type size: int, optional
:param ttl: The TTL for every item in the stack, defaults to 0 (no TTL)
:type ttl: int, optional
:param timer: The timer function that the stack will use to
keep track of elapsed time. Defaults to time.monotonic(), but can
be customized (another monotonic clock is timeit.default_timer, for
instance). Any function that yields an incremental value
be customized. Any function that yields an incremental value
on each subsequent call is acceptable, but its return values
should not be repeated during runtime to avoid nonsense results
:type timer: class: FunctionType, optional
"""
def __init__(self, qsize: int = 0, ttl: int = 0, timer: FunctionType = monotonic):
def __init__(self, size: int = 0, ttl: int = 0, timer: FunctionType = monotonic):
"""Object constructor"""
super().__init__(qsize, ttl, timer)
self.timer = timer
self.ttl = ttl
self.size = size
self._stack = deque()
def push(self, element, ttl: int = 0):
@ -145,7 +146,7 @@ class TTLStack(TTLQueue):
ttl = ttl if ttl else self.ttl
self.expire(self.timer())
if len(self._stack) < self.qsize:
if len(self._stack) < self.size:
self._stack.appendleft((self.timer() + ttl, element))
else:
raise StackFull("The stack is full!")
@ -153,6 +154,8 @@ class TTLStack(TTLQueue):
def pop(self):
"""Pops an item from the stack, raising StackEmpty if the
stack is empty
:raises StackEmpty: If the stack is empty
"""
self.expire(self.timer())
@ -163,9 +166,9 @@ class TTLStack(TTLQueue):
def __repr__(self):
"""Implements repr(self)"""
string = "TTLStack({list}, qsize={qsize}, ttl={ttl}, timer={timer})"
string = "TTLStack({list}, size={qsize}, ttl={ttl}, timer={timer})"
values = [t[1] for t in self._stack]
return string.format(list=values, qsize=self.qsize, ttl=self.ttl, timer=self.timer)
return string.format(list=values, qsize=self.size, ttl=self.ttl, timer=self.timer)
def expire(self, when: int):
"""Pops expired element out of the stack if their TTL has
@ -187,4 +190,3 @@ class TTLStack(TTLQueue):
if date <= when:
del self._stack[i]
i += 1