Welcome to canvas-core’s documentation!

canvas-core

Quickstart

First, install canvas-core.

#> pip install canvas-core

Then, add canvas_core to INSTALLED_APPS in your project settings.

# settings.py

INSTALLED_APPS = [
    # ...
    "canvas_core",
    "canvas_core.plugins",
    "canvas_core.caching",
    "canvas_core.calendars",
    "canvas_core.commands",
    "canvas_core.config",
    "canvas_core.events",
    "canvas_core.metrics",
    "canvas_core.storage",
    "canvas_core.templating",
    # ...
]

Finally, add canvas_core’s URL patterns to your project’s urls.py.

# urls.py
from django.urls import include, path

urlpatterns = [
    # ...
    path("canvas_core/", include("canvas_core.urls")),
    # ...
]

Contributing

If you want to contribute to the canvas-core project, you can open a pull request to our repository.

Getting Started

Ready to contribute? Here’s how to set up canvas-core for local development:

  1. Fork the canvas-core repo on GitHub.

  2. Clone your fork locally: git clone git@github.com:your-github-username/canvas-core.git

  3. Navigate to your clone: cd canvas-core

  4. Activate the virtualenv: poetry shell

  5. Install the dependencies: poetry install

  6. Install the pre-commit hooks: pre-commit install --install-hooks

  7. Create a branch for your change: git checkout -b name-of-your-bugfix-or-feature

  8. Start the example project, if needed for testing: ./manage.py runserver_plus

  9. Make your changes in the editor of your choice.

  10. Run the test suite: pytest

  11. Commit your changes and fix any issues reported by pre-commit.

  12. Push your changes: git push --set-upstream origin name-of-your-bugfix-or-feature

  13. Submit a pull request in GitHub.

Pull Request Guidelines

Before you submit a pull request, make sure that it meets our guidelines:

  1. Pull requests must have tests.

  2. Pull requests must be narrow in their scope, and ideally small in size.

  3. If the pull request adds or changes functionality, it should include updates to the documentation in docs/.

Adding an SDK resource

  1. Create a new directory at canvas_core/api_name

  2. Run ./manage.py startapp api_name canvas_core/api_name

  3. git add canvas_core/api_name && git commit -nm "Generated boilerplate for api_name"

  4. pre-commit run --files canvas_core/api_name/**/*

  5. git add canvas_core/api_name && git commit -nm "Boilerplate pre-commit fixes"

  6. Update the name attribute of the newly-generated AppConfig class in canvas_core/api_name/apps.py to be a subapp of canvas_core (canvas_core.api_name).

  7. Add canvas_core.api_name to the INSTALLED_APPS in example/settings.py

  8. Add canvas_core.api_name to the INSTALLED_APPS example in README.md

  9. git add canvas_core/api_name README.md example/settings.py && git commit -m "Install canvas_core.api_name into the example app"

  10. Documentation

    • Short description of the purpose and responsibilities of the API

    • Basic interface

    • Auto-generated module documentation

    • What events does it emit?

    • What errors does your API emit, and when?

    • What state does it hold? (usually models, but possibly also cache keys, etc)

    • Does it provide any HTTP API endpoints/urls?

    • Does it provide middleware or other Django-y things?

Conventions

  • Define your interface in __init__.py first

  • Write tests against your interface (in tests.py for small APIs, or tests/**/test_*.py files for larger ones)

  • Define your data model, if any

    • Only top-level models should be exposed (i.e. models that you’d expect to be referenced by other models in the system)

    • Models should be exposed via get_modelname_model() functions, and use the app registry to resolve them (apps.get_model("api_name.ModelName", require_ready=False)) to avoid load order dependencies

  • Provide admin classes for your data model!

    • Usually you’ll only want admin classes for the top-level models

  • Use the django.utils.translation.gettext_lazy (aliased to _) when writing static strings (like help_text for model and form fields)

  • Add types to everything

  • If a type is not used directly (i.e. it’s only used for a type annotation) put it in an if TYPE_CHECKING: block to prevent unnecessary imports

  • Error handling

    • Modules should define their own exception classes, extending from CanvasCoreException.

    • Module-level exceptions should be appropriately descriptive, and generic enough to avoid leaky abstractions

      • Exceptions should not reveal the implementation

    • All module exceptions should be caught and re-raised as their own exceptions

      • For example, an ObjectDoesNotExist error from the Django ORM should be caught and re-raised as MoreSpecificModuleLookupError.

    • All raised exceptions must chain the original exception.

  • Logging

  • Metrics

    • Use python indetifier conventions for metric names

    • Perfer using the metrics decorators and context managers over custom metrics

Indices and tables