Skip to content

Advanced Usage

StefanGreve edited this page Oct 18, 2023 · 6 revisions

Frontend Configuration

The CLI interface of anonpy creates a INI file on launch at the location of get_resource_path("anonpy"):

[client]
download_directory = C:\Users\stefan.greve\downloads
token = None
user_agent = None
proxies = None
enable_logging = False
log_level = 20
verbose = True
force = False

[security]
hash = sha256

[server]
api = https://pixeldrain.com/api/
upload = /file
download = /file/{}
preview = /file/{}/info

Note that the $home variable will be expanded in the configuration file itself by the time of writing. Use the ConfigHandler class to programmatically interact with this configuration, or to create your own.

import json
from anonpy.internals import ConfigHandler, get_resource_path

folder = get_resource_path("my_module")
path = folder.joinpath("config.ini")

with ConfigHandler(path) as config_handler:
    config_handler.add_section("test", settings={
        "hello": "world",
        "number": 2,
        "switch": True
    })

    # pretty-print output
    print(json.dumps(config_handler.json, indent=2))

The context manager will save the content of the config_handler object on exit to path. This class can also be used without a context manager. Passing no path to the constructor is also possible, but will raise an error when the save method is invoked.

resource_folder = get_resource_path("anonpy")

# read existing configuration file
config = ConfigHandler(resource_folder / "anonpy.ini")
config.read()

# prints 'True' with default settings
print(config.get_optioen("client", "verbose"))

Registering Providers

The AnonPy class inherits from RequestHandler for establishing communication through session objects. Since the registration process requires an preview (aka info) endpoint for the progress bars, you may want to use RequestHandler as a base class and implement the methods for download and upload yourself.

By Inheritance

The providers namespace implements custom-tailored solutions to specific REST APIs and serve as a reference implementation for hooking up your backend of choice, but you can also implement your own classes by using inheritance:

from anonpy import AnonPy
from anonpy.internals import Authorization
from typing import Final, Self

class PixelDrain(AnonPy):
    def __init__(self: Self, token: Optional[str]=None) -> None:
        self.api: Final = "https://pixeldrain.com/api/"
        self.endpoint = Endpoint(upload="/file", download="file/{}", preview="/file/{}/info")
        
        # there are more optional parameters to configure the bahvior of the base class
        super().__init__(api=self.api, endpoint=self.endpoint)

        # configure basic authorization
        if token: self.set_credentials(Authorization.Basic)

The code above is used to showcase the mechanics of inheriting from AnonPy, the PixelDrain class can be imported from the anonpy.providers namespace directly

By Duck-Typing

Alternatively, you can also use the Endpoint data class directly:

from anonpy import AnonPy, Endpoint

api = "https://pixeldrain.com/api/"

# preview/info endpoint is required for the progress bar to estimate the time for completion
endpoint = Endpoint(upload="/file", download="file/{}", preview="/file/{}/info")

# declare a new pseudo type for your backend (optional)
type PixelDrain = AnonPy

# register the provider to AnonPy
pixel = PixelDrain(api, endpoint)

Configuring Logging

The internals namespace supplies the facilities that are necessary for structured logging and currently supports the following targets:

  • None (print logs to terminal)
  • *.csv
  • *.json
  • *.log | *.txt | *.dat

The LogHandler class implements a wrapper around Python's built-in logging module. The LogLevel Enum mirrors the native log levels, to further reinforce this point.

Example 1

from anonpy.internals import LogHandler, LogLevel
from pathlib import Path

target = "test_anonpy.csv"

# create a new logger object
logger = LogHandler(level=LogLevel.DEBUG)

# use the builder pattern for setting up targets
logger \
    .set_base_path(path=Path.home()) \
    .add_handler(target) \
    .add_handler(None)

logger.debug("Hello, %s", "World")

# read the entire log history into memory
log_book = logger.get_log_history(target)
print(log_book)

# call on application exit
logger.shutdown()

Note that the built-in logging library is optimized to use the %s formatting style. Using string interpolation ("f-strings") here might have an extract cost because the formatting would apply even if the message is not logged.

Example 2

The AnonPy or PixelDrain contructors take a enable_logging parameter (disabled by default) for toggling the logging behavior. The default implementation of download, preview and upload will log their calls if enable_logging is set to True, but will raise a TypeError exception if no handler was attached prior to these function invocations.

from anonpy.providers import PixelDrain

pixel = PixelDrain(enable_logging=True)

# log to console
pixel.logger.add_handler("console")

upload = pixel.preview("Aozkv26f", progressbar=True)

It's also possible to use the log handler from the rich library by passing rich_console instead of console to the add_handler method

Encryption and Decryption

TODO