BlackSheep Documentation

repository·main·Indexed 25 days ago

https://github.com/neoteroi/blacksheep

An asynchronous web framework for building event-based web applications with Python, inspired by Flask and ASP.NET Core. It features high performance, automatic dependency injection, automatic request binding, and native HTTP/2 client support. The framework is ASGI-compatible and provides a comprehensive set of routing decorators, response helpers, and security tools for authentication and authorization, including OIDC, JWT Bearer, Basic, and API Key authentication.

Tokens
10.6K
Snippets
22
Records
76
Agent score
81%

What's inside BlackSheep

  1. Automatic binding of request data

    main

    BlackSheep can automatically bind request data to handler parameters using type annotations and specialized classes like FromJSON and FromQuery.

    JSON Body Binding

    Use FromJSON[T] to automatically parse the JSON payload into a dataclass or Pydantic model.

    Route Parameter Binding

    Parameters in the handler function that match names in the route path (e.g., /:name) are automatically extracted.

    Query Parameter Binding

    • Implicit: If a parameter name does not match a route parameter, it is automatically treated as a query string parameter.
    • Explicit: Use FromQuery[T] to explicitly define how query parameters should be read and provide default values.
    from dataclasses import dataclass
    from blacksheep import Application, FromJSON, FromQuery, get, post
    
    app = Application()
    
    @dataclass
    class CreateCatInput:
        name: str
    
    @post("/api/cats")
    async def example(data: FromJSON[CreateCatInput]):
        # data is bound from JSON payload
        ...
    
    @get("/:culture_code/:area")
    async def home(culture_code, area):
        # parameters obtained from route matching names
        return f"Request for: {culture_code} {area}"
    
    @get("/api/products")
    def get_products(
        page: int = 1,
        size: int = 30,
        search: str = "",
    ):
        # implicit query parameters with default values
        ...
    
    @get("/api/products2")
    def get_products2(
        page: FromQuery[int] = FromQuery(1),
        size: FromQuery[int] = FromQuery(30),
        search: FromQuery[str] = FromQuery(""),
    ):
        # explicit query parameters with default values
        ...
  2. Configure Visual Studio Code for benchmark debugging

    main

    To debug specific benchmark files in VS Code, use the following launch.json configuration. This ensures the ${workspaceFolder} is added to PYTHONPATH so imports work correctly.

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Python Debugger: Current File",
                "type": "debugpy",
                "request": "launch",
                "program": "${file}",
                "console": "integratedTerminal",
                "env": {
                    "PYTHONPATH": "${workspaceFolder}"
                }
            }
        ]
    }
  3. Reset and rerun benchmarks after modifications

    main

    If you modify the benchmark code, it is recommended to clear previous results before running the suite and generating a new report.

    export PYTHONPATH="."
    rm -rf benchmark_results && python perf/main.py && python perf/genreport.py
  4. Run the BlackSheep benchmark suite

    main

    To measure the performance (execution time and memory utilization) of the library, install the required dependencies and run the benchmark suite from the repository root. You can specify the number of times to run the suite using the --times flag.

    # Install dependencies
    pip install -r req.txt
    
    # Run the benchmark suite
    export PYTHONPATH="."
    python perf/main.py
    
    # Run the suite multiple times (e.g., 3 times)
    python perf/main.py --times 3
  5. Bootstrap a project with blacksheep-cli

    main

    BlackSheep provides a CLI to rapidly bootstrap new projects using templates. First, install the CLI package, then use the create command.

    1. Install the CLI:
    pip install blacksheep-cli
    1. Bootstrap a project:
    blacksheep create

    The CLI supports custom templates compatible with Cookiecutter.

    pip install blacksheep-cli
    blacksheep create
  6. Run individual benchmarks with iPython or cProfile

    main

    Benchmarks are organized so that individual files can be run interactively. Benchmark functions must start with the prefix benchmark_ to be automatically discovered by main.py. To run a single benchmark file, set the PYTHONPATH to the root directory.

    export PYTHONPATH="."
    
    # Run a single benchmark file using iPython's timeit magic
    ipython perf/benchmarks/writeresponse.py timeit
    
    # Run a single benchmark file using cProfile
    python -m cProfile -s tottime perf/benchmarks/writeresponse.py | head -n 50
  7. Run a BlackSheep application with an ASGI server

    main

    BlackSheep is an ASGI-compatible framework and requires an ASGI HTTP server to run (e.g., uvicorn, hypercorn, or granian).

    To run an application defined in server.py using uvicorn:

    1. Install uvicorn:
    pip install uvicorn
    1. Run the server:
    uvicorn server:app
    pip install uvicorn
    uvicorn server:app
  8. The Message class and its header management

    main

    The Message class is the base class for Request and Response. It provides methods to manage HTTP headers. Headers are stored as a list of RawHeader (tuples of bytes).

    Key header operations:

    • add_header(key, value): Adds a new header.
    • set_header(key, value): Removes existing headers with the same key and adds a new one.
    • get_first_header(key): Returns the first value found for a key.
    • get_headers(key): Returns all values associated with a key.
    • get_single_header(key): Returns the single value for a key, raising ValueError if zero or multiple headers are found.
    • remove_header(key): Removes all headers matching the key.
    • has_header(key): Checks if a header exists.
  9. Stream large content with StreamedContent

    main
    Use StreamedContent to handle large data efficiently without loading it all into memory. It requires an async generator (the data_provider) that yields chunks of bytes. You can either read the entire content into memory using .read() or stream it chunk-by-chunk using .stream() or .get_parts().