Source code for example.boilerplate

import json
from datetime import datetime
from logging import Logger, StreamHandler
from os import environ as env
from pathlib import Path
from typing import Any, Optional

from aiohttp import ClientSession
from msgpackr.constants import UNDEFINED

from novelai_api import NovelAIAPI
from novelai_api.utils import get_encryption_key


[docs]class API: """ Boilerplate for the redundant parts. Using the object as a context manager will automatically login using the environment variables ``NAI_USERNAME`` and ``NAI_PASSWORD``. Usage: .. code-block:: python async with API() as api: api = api.api encryption_key = api.encryption_key logger = api.logger ... # Do stuff A custom base address can be passed to the constructor to replace the default (:attr:`BASE_ADDRESS <novelai_api.NovelAI_API.NovelAIAPI.BASE_ADDRESS>`) """ _username: str _password: str _session: ClientSession logger: Logger api: Optional[NovelAIAPI]
[docs] def __init__(self, base_address: Optional[str] = None): dotenv = Path(".env") if dotenv.exists(): with dotenv.open("r") as f: for line in f: if "=" in line: key, value = line.strip().split("=", 1) env[key] = value.strip() if "NAI_USERNAME" not in env or "NAI_PASSWORD" not in env: raise RuntimeError("Please ensure that NAI_USERNAME and NAI_PASSWORD are set in your environment") self._username = env["NAI_USERNAME"] self._password = env["NAI_PASSWORD"] self.logger = Logger("NovelAI") self.logger.addHandler(StreamHandler()) self.api = NovelAIAPI(logger=self.logger) if base_address is not None: self.api.BASE_ADDRESS = base_address
@property def encryption_key(self): return get_encryption_key(self._username, self._password) async def __aenter__(self): self._session = ClientSession() await self._session.__aenter__() self.api.attach_session(self._session) await self.api.high_level.login(self._username, self._password) return self async def __aexit__(self, exc_type, exc_val, exc_tb): await self._session.__aexit__(exc_type, exc_val, exc_tb)
[docs]class JSONEncoder(json.JSONEncoder): """ Extended JSON encoder to support bytes """
[docs] def default(self, o: Any) -> Any: if isinstance(o, bytes): return o.hex() if o is UNDEFINED: return "<UNDEFINED>" if isinstance(o, datetime): return o.isoformat() return super().default(o)
[docs]def dumps(e: Any) -> str: """ Shortcut to a configuration of json.dumps for consistency """ return json.dumps(e, indent=4, ensure_ascii=False, cls=JSONEncoder)