semvec/pypi-packages huggingface dataset:
eodo2 0.1.21
EdgeOneDynamicOrigin
Requires Python: >=3.12

EdgeOne 是腾讯云的边缘安全加速平台。该脚本为其提供动态更新源站组 IP 的功能。
此功能特别适用于那些 IP 地址可能会变化的源站，确保 CDN 始终能够正确地获取最新的内容。比如仅有动态 IPV6 地址的服务器，
也能够长期稳定部署WEB服务，而不必使用 frp / ngork 等内网端口转发工具。

注意，若要使用该脚本，在 EdgeOne 中的加速域名必须使用源站组配置源站。

### 使用方法

#### windows
1. 安装 `pip install eodo2`
2. 运行 `eodo2 -p 54321`以启动。 -p 54321 表示 web 管理界面监听端口为 54321。
3. 在 `http://localhost:54321` 中配置必要的配置项。

#### ubuntu
1. 安装 `pip3 install eodo2 -U --break-system-packages`
2. 运行 `export PATH="$HOME/.local/bin:$PATH" && source ~/.bashrc` 将 ~/.local/bin 加入 PATH
3. 运行 `eodo2 -p 54321`以启动。  -p 54321 表示 web 管理界面监听端口为 54321。
4. 在 `http://localhost:54321` 中配置必要的配置项。
classic-scenarios 0.1.1
Primitives for writing scenarios
Requires Python: >=3.10

# Classic Scenarios

Предоставляет примитивы для написания простых сценариев с бизнес-логикой.

## Установка

```shell
pip install classic-scenarios
```

## Использование

```python
from classic.components import component, no_init
from classic.scenarios import scenario, Return

import pydantic


class SomeEntity(pydantic.BaseModel):
    """Это как будто очень полезный класс,
    представляющий собой какое-то понятие из предметной области
    """
    id: int
    

class SomeParams(pydantic.BaseModel):
    """Модель для проверки ввода"""
    some_obj_id: int
    some_prop: str

    
class Database:
    """Интерфейс для объекта, работающего с БД"""
    
    def get(self, id):
        raise NotImplemented
    
    def save(self, obj):
        raise NotImplemented

    
# Использование component не обязательно, 
# но с ним выглядит более идиоматично
@component
class SomeUseCase:
    db: Database
    
    params: SomeParams = no_init(None)
    some_obj: SomeEntity = no_init(None)
    
    @scenario
    def run(self):
        """
        Это сценарий транзакции,
        в котором последовательно,
        шаг за шагом прописаны шаги.
        """
        self._do_something()
        self._do_anything()
        self._and_something_yet()
    
    def _do_something(self):
        """Здесь можно сделать что-то полезное, например, взять объект из БД"""
        self.some_obj = self.db.get(self.params.some_obj_id)
    
    def _do_anything(self):
        if self.some_obj is None:
            # Это приведет к остановке сценария, 
            # но сценарий не упадет, а вернет 'No obj'
            raise Return('No obj')
        
        self.some_prop = 'Some value'

    def _and_something_yet(self):
        self.db.save(self.some_obj)


use_case = SomeUseCase(Database())
use_case.run(params=SomeParams(123))
```

При вызове run декоратор scenario сделает 2 вещи:
- скопирует полученный в self инстанс SomeUseCase, чтобы продолжить исполнение
  уже с копией. Это нужно для потокобезопасности.
- разложит все полученные kwargs в self. В примере выше объект SomeParams,
  переданный в ключе params, будет доступен в сценарии в атрибуте self.params.

Копирование объекта имеет один побочный эффект. Из-за того, что при вызове run 
снимается поверхностная копия объекта, копия получит ссылки на те же объекты.
Если в свойствах класса-сценария будут инстансы изменяемых типов, то при 
повторном вызове сценария мы увидим состояние из предыдущего!

Это похоже на эффект, получаемый при использовании инстансов сложных типов 
в качестве аргументов функции по умолчанию:
```python
def func(arg=[]):
    arg.append('1')
```
Здесь так же между вызовами будет сохраняться состояние arg. В целом, если 
такое свойство исползьуется только для чтения, в этом нет проблем. Кроме того,
сложно представить себе такое свойство, которое имело бы свойство по умолчанию,
то есть инициализировалось бы конструктором, и при этом было бы изменяемо, 
потому такое поведение не кажется проблемой.