semvec/pypi-packages huggingface dataset:
ptb-menu-pagination 0.2.2
Creates google-like navigation menu using python-telegram-bot wrapper
License: MIT
Requires Python: >=3.9,<4.0
Keywords: python-telegram-bot,pagination,menu,telegram-bot,telegram-bot-pagination

# python telegram bot menu pagination
![Actions Status](https://github.com/SergSm/ptb-menu-pagination/workflows/ci/badge.svg)
[![Maintainability](https://api.codeclimate.com/v1/badges/9eade003d09d837c852e/maintainability)](https://codeclimate.com/github/SergSm/ptb-menu-pagination/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/9eade003d09d837c852e/test_coverage)](https://codeclimate.com/github/SergSm/ptb-menu-pagination/test_coverage)

# Description

Makes a google style pagination line for a list of items.

![](https://github.com/SergSm/ptb-menu-pagination/raw/main/example/media/example2.png)

In other words it builds a menu for navigation if you have 
a lot of search results or whatever list of anything 

![](https://github.com/SergSm/ptb-menu-pagination/raw/main/example/media/example3.png)


### Installation

```
pip install ptb-menu-navigation
```


or if you are working with source code and use Poetry tool:

```
make install
```

### Usage
```python
from paginator import get_menu
```


Use ```get_menu``` function to create a line of pages

#### Example:
```python
from paginator import get_menu 
from dataclasses import dataclass

# Define initial menu settings in the dataclass.
@dataclass
class Menu:
    items_per_page: int = 10
    pages_per_line: int = 3
    navigation_signature: str = '±'
    page_label: str = ' p. '

# Add the initial call of get_menu
def handling_input(update, context):
    # ...
    # On first invocation
    navigation = get_menu(total_items=len(search_results),
                          current_page=1,
                          menu_settings=Menu)
    # ...

# Add a callback to handle a page switching  
def navigate(update, context):
    # ...
    navigation = get_menu(total_items=len(search_results),
                          current_page=int(current_page),
                          menu_settings=Menu)     
    # ...            
```
where ```search_results``` is a list of strings and ```current_page```
is a number extracted from a ```callback_data```.

See ```examples/search_bot.py```

### Demo bot launch
Create a ```.env``` file with a ```TOKEN``` variable
inside of an ```/examples``` for launching 
the
[demo](https://github.com/SergSm/ptb-menu-pagination/blob/main/example/search_bot.py) bot.\
eg:\
```TOKEN=<YOUR_TELEGRAM_BOT_TOKEN_FROM_BOT_FATHER>```

You may also provide some additional menu values in the same ```.env``` file:
```
ITEMS_PER_PAGE=1
PAGES_PER_LINE=1
NAVIGATION_SIGNATURE="±"
PAGE_LABEL=" p. "
```
asyncio-contextmanager-pool 0.1.2
A library providing a pool-like object for holding `AsyncContextManager` instances.
License: MIT
Requires Python: >=3.8,<4.0

# asyncio-contextmanager-pool

A library providing a pool-like object for holding `AsyncContextManager` instances.

## Why?

Some objects, like MongoDB connections to a Replica Set, are expensive to create, time-wise. As a result, they are usually created once and then used across the entire application. This mitigates, or eliminates, the costs associated with creating and setting up such objects.

However, there are situations where one may need to dynamically create such objects. One such example would be a multi-tenant API that can talk to multiple instances.

One could use `cachetools` to hold the references, perhaps in a `TTLCache`, so that not "too many" instances are kept (especially when not used), but then they must also make sure that instances are cleaned up properly, sometimes with some leniency (TTL).

## Features

- Async Context Manager (`async with`) support to manage objects
- Memoizes instances based on the arguments used to create them, which prevents duplicates and saves init time
- Provides TTL support, so that objects are kept for a set period of time after not being used, which again helps preventing duplication

## Usage

```python
import asyncio
from asyncio_contextmanager_pool import Pool


class Example:
    """
    A dummy implementation of an AsyncContextManager
    that "knows" when it was used.
    """
    def __init__(self, message: str) -> None:
        self.message = message

        self.enter_called = 0
        self.exit_called = 0

    async def __aenter__(self):
        self.enter_called += 1
        return self

    async def __aexit__(self, *args, **kwargs):
        self.exit_called += 1


async with Pool(Example, ttl=5) as p:
    # Get an instance of Example
    async with p.get("hello, world") as inst_1:
        # Use it
        assert inst_1.message == "hello, world"

    # Here, under normal circumstances, `inst_1` is still alive
    assert inst_1.exit_called == 0

    # So, if I `get` it again...
    async with p.get("hello, world") as inst_2:
        # And use it...
        assert inst_2.message == "hello, world"
    
    # I will get the exact same object
    assert inst_1 is inst_2

    # Now, let's assume some time passes...
    await asyncio.sleep(10)

    # Here, inst_1 already expired, so inst_3
    # will be a new object...
    async with p.get("hello, world") as inst_3:
        assert inst_3.message == "hello, world"

    assert inst_1 is not inst_3
    assert inst_1.exit_called == 1

# And after the `async with` block, everything is cleaned:
assert inst_3.exit_called == 1
```

## Notes

### Pickle support

If a `Pool` instance is copied via Pickle (e.g., through `multiprocessing.Process` or a `concurrent.futures.ProcessPoolExecutor`), the instances are not copied.

This is by design, because:

- Some objects should not be copied between processes (e.g., `pymongo.MongoClient`)
- Object expiration uses `asyncio`'s Timer functions, which are attached to the Event Loop. Event Loops cannot be shared between processes.