django-seal


Namedjango-seal JSON
Version 1.6.1 PyPI version JSON
download
home_pagehttps://github.com/charettes/django-seal
SummaryAllows ORM constructs to be sealed to prevent them from executing queries on attribute accesses.
upload_time2023-09-21 22:15:28
maintainer
docs_urlNone
authorSimon Charette
requires_python
licenseMIT License
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            django-seal
===========

.. image:: https://publicdomainvectors.org/photos/Seal2.png
    :target: https://publicdomainvectors.org
    :alt: Seal

------------

.. image:: https://github.com/charettes/django-seal/workflows/Test/badge.svg
    :target: https://github.com/charettes/django-seal/actions
    :alt: Build Status

.. image:: https://coveralls.io/repos/github/charettes/django-seal/badge.svg?branch=master
    :target: https://coveralls.io/github/charettes/django-seal?branch=master
    :alt: Coverage status


Django application providing queryset sealing capability to force appropriate usage of ``only()``/``defer()`` and
``select_related()``/``prefetch_related()``.

Installation
------------

.. code:: sh

    pip install django-seal

Usage
-----

.. code:: python

    # models.py
    from django.db import models
    from seal.models import SealableModel

    class Location(SealableModel):
        latitude = models.FloatField()
        longitude = models.FloatField()

    class SeaLion(SealableModel):
        height = models.PositiveIntegerField()
        weight = models.PositiveIntegerField()
        location = models.ForeignKey(Location, models.CASCADE, null=True)
        previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')

By default ``UnsealedAttributeAccess`` warnings will be raised on sealed objects attributes accesses

.. code:: python

    >>> location = Location.objects.create(latitude=51.585474, longitude=156.634331)
    >>> sealion = SeaLion.objects.create(height=1, weight=100, location=location)
    >>> sealion.previous_locations.add(location)
    >>> SeaLion.objects.only('height').seal().get().weight
    UnsealedAttributeAccess:: Attempt to fetch deferred field "weight" on sealed <SeaLion instance>.
    >>> SeaLion.objects.seal().get().location
    UnsealedAttributeAccess: Attempt to fetch related field "location" on sealed <SeaLion instance>.
    >>> SeaLion.objects.seal().get().previous_locations.all()
    UnsealedAttributeAccess: Attempt to fetch many-to-many field "previous_locations" on sealed <SeaLion instance>.

You can `elevate the warnings to exceptions by filtering them`_. This is useful to assert no unsealed attribute accesses are
performed when running your test suite for example.

.. code:: python

    >>> import warnings
    >>> from seal.exceptions import UnsealedAttributeAccess
    >>> warnings.filterwarnings('error', category=UnsealedAttributeAccess)
    >>> SeaLion.objects.only('height').seal().get().weight
    Traceback (most recent call last)
    ...
    UnsealedAttributeAccess:: Attempt to fetch deferred field "weight" on sealed <SeaLion instance>.
    >>> SeaLion.objects.seal().get().location
    Traceback (most recent call last)
    ...
    UnsealedAttributeAccess: Attempt to fetch related field "location" on sealed <SeaLion instance>.
    >>> SeaLion.objects.seal().get().previous_locations.all()
    Traceback (most recent call last)
    ...
    UnsealedAttributeAccess: Attempt to fetch many-to-many field "previous_locations" on sealed <SeaLion instance>.

Or you can `configure logging to capture warnings`_ to log unsealed attribute accesses to the ``py.warnings`` logger which is a
nice way to identify and address unsealed attributes accesses from production logs without taking your application down if some
instances happen to slip through your battery of tests.

.. code:: python

    >>> import logging
    >>> logging.captureWarnings(True)

.. _elevate the warnings to exceptions by filtering them: https://docs.python.org/3/library/warnings.html#warnings.filterwarnings
.. _configure logging to capture warnings: https://docs.python.org/3/library/logging.html#logging.captureWarnings

Sealable managers can also be automatically sealed at model definition time to avoid having to call ``seal()`` systematically
by passing ``seal=True`` to ``SealableModel`` subclasses, ``SealableManager`` and ``SealableQuerySet.as_manager``.

.. code-block:: python

    from django.db import models
    from seal.models import SealableManager, SealableModel, SealableQuerySet

    class Location(SealableModel, seal=True):
        latitude = models.FloatField()
        longitude = models.FloatField()

    class SeaLion(SealableModel):
        height = models.PositiveIntegerField()
        weight = models.PositiveIntegerField()
        location = models.ForeignKey(Location, models.CASCADE, null=True)
        previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')

        objects = SealableManager(seal=True)
        others = SealableQuerySet.as_manager(seal=True)

Development
-----------

Make your changes, and then run tests via tox:

.. code:: sh

    tox

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/charettes/django-seal",
    "name": "django-seal",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "",
    "author": "Simon Charette",
    "author_email": "simon.charette@zapier.com",
    "download_url": "https://files.pythonhosted.org/packages/67/13/dc72299b4438231447c839497d76ece5cd1e8f794a92d4c773c6e1befaf1/django-seal-1.6.1.tar.gz",
    "platform": null,
    "description": "django-seal\n===========\n\n.. image:: https://publicdomainvectors.org/photos/Seal2.png\n    :target: https://publicdomainvectors.org\n    :alt: Seal\n\n------------\n\n.. image:: https://github.com/charettes/django-seal/workflows/Test/badge.svg\n    :target: https://github.com/charettes/django-seal/actions\n    :alt: Build Status\n\n.. image:: https://coveralls.io/repos/github/charettes/django-seal/badge.svg?branch=master\n    :target: https://coveralls.io/github/charettes/django-seal?branch=master\n    :alt: Coverage status\n\n\nDjango application providing queryset sealing capability to force appropriate usage of ``only()``/``defer()`` and\n``select_related()``/``prefetch_related()``.\n\nInstallation\n------------\n\n.. code:: sh\n\n    pip install django-seal\n\nUsage\n-----\n\n.. code:: python\n\n    # models.py\n    from django.db import models\n    from seal.models import SealableModel\n\n    class Location(SealableModel):\n        latitude = models.FloatField()\n        longitude = models.FloatField()\n\n    class SeaLion(SealableModel):\n        height = models.PositiveIntegerField()\n        weight = models.PositiveIntegerField()\n        location = models.ForeignKey(Location, models.CASCADE, null=True)\n        previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')\n\nBy default ``UnsealedAttributeAccess`` warnings will be raised on sealed objects attributes accesses\n\n.. code:: python\n\n    >>> location = Location.objects.create(latitude=51.585474, longitude=156.634331)\n    >>> sealion = SeaLion.objects.create(height=1, weight=100, location=location)\n    >>> sealion.previous_locations.add(location)\n    >>> SeaLion.objects.only('height').seal().get().weight\n    UnsealedAttributeAccess:: Attempt to fetch deferred field \"weight\" on sealed <SeaLion instance>.\n    >>> SeaLion.objects.seal().get().location\n    UnsealedAttributeAccess: Attempt to fetch related field \"location\" on sealed <SeaLion instance>.\n    >>> SeaLion.objects.seal().get().previous_locations.all()\n    UnsealedAttributeAccess: Attempt to fetch many-to-many field \"previous_locations\" on sealed <SeaLion instance>.\n\nYou can `elevate the warnings to exceptions by filtering them`_. This is useful to assert no unsealed attribute accesses are\nperformed when running your test suite for example.\n\n.. code:: python\n\n    >>> import warnings\n    >>> from seal.exceptions import UnsealedAttributeAccess\n    >>> warnings.filterwarnings('error', category=UnsealedAttributeAccess)\n    >>> SeaLion.objects.only('height').seal().get().weight\n    Traceback (most recent call last)\n    ...\n    UnsealedAttributeAccess:: Attempt to fetch deferred field \"weight\" on sealed <SeaLion instance>.\n    >>> SeaLion.objects.seal().get().location\n    Traceback (most recent call last)\n    ...\n    UnsealedAttributeAccess: Attempt to fetch related field \"location\" on sealed <SeaLion instance>.\n    >>> SeaLion.objects.seal().get().previous_locations.all()\n    Traceback (most recent call last)\n    ...\n    UnsealedAttributeAccess: Attempt to fetch many-to-many field \"previous_locations\" on sealed <SeaLion instance>.\n\nOr you can `configure logging to capture warnings`_ to log unsealed attribute accesses to the ``py.warnings`` logger which is a\nnice way to identify and address unsealed attributes accesses from production logs without taking your application down if some\ninstances happen to slip through your battery of tests.\n\n.. code:: python\n\n    >>> import logging\n    >>> logging.captureWarnings(True)\n\n.. _elevate the warnings to exceptions by filtering them: https://docs.python.org/3/library/warnings.html#warnings.filterwarnings\n.. _configure logging to capture warnings: https://docs.python.org/3/library/logging.html#logging.captureWarnings\n\nSealable managers can also be automatically sealed at model definition time to avoid having to call ``seal()`` systematically\nby passing ``seal=True`` to ``SealableModel`` subclasses, ``SealableManager`` and ``SealableQuerySet.as_manager``.\n\n.. code-block:: python\n\n    from django.db import models\n    from seal.models import SealableManager, SealableModel, SealableQuerySet\n\n    class Location(SealableModel, seal=True):\n        latitude = models.FloatField()\n        longitude = models.FloatField()\n\n    class SeaLion(SealableModel):\n        height = models.PositiveIntegerField()\n        weight = models.PositiveIntegerField()\n        location = models.ForeignKey(Location, models.CASCADE, null=True)\n        previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')\n\n        objects = SealableManager(seal=True)\n        others = SealableQuerySet.as_manager(seal=True)\n\nDevelopment\n-----------\n\nMake your changes, and then run tests via tox:\n\n.. code:: sh\n\n    tox\n",
    "bugtrack_url": null,
    "license": "MIT License",
    "summary": "Allows ORM constructs to be sealed to prevent them from executing queries on attribute accesses.",
    "version": "1.6.1",
    "project_urls": {
        "Homepage": "https://github.com/charettes/django-seal"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4ca7c7bfe50e3bb2fe105cf46af20db229e16826ddb9b1c8a10f6d02bcfbee0f",
                "md5": "b75b9ad1fa1a0d149074f1bc12d346cf",
                "sha256": "75b0236f0dd12a1aa92dcf50fa00c8ac855f21148837bc8d6d242fd6233ada9a"
            },
            "downloads": -1,
            "filename": "django_seal-1.6.1-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b75b9ad1fa1a0d149074f1bc12d346cf",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": null,
            "size": 9100,
            "upload_time": "2023-09-21T22:15:26",
            "upload_time_iso_8601": "2023-09-21T22:15:26.881396Z",
            "url": "https://files.pythonhosted.org/packages/4c/a7/c7bfe50e3bb2fe105cf46af20db229e16826ddb9b1c8a10f6d02bcfbee0f/django_seal-1.6.1-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6713dc72299b4438231447c839497d76ece5cd1e8f794a92d4c773c6e1befaf1",
                "md5": "2c447e97a23701416f46041d17a20448",
                "sha256": "21af9495127dbf51e8ab567ac5a96fff76e43a5df4e46356ded7df8ca4fe6324"
            },
            "downloads": -1,
            "filename": "django-seal-1.6.1.tar.gz",
            "has_sig": false,
            "md5_digest": "2c447e97a23701416f46041d17a20448",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 12230,
            "upload_time": "2023-09-21T22:15:28",
            "upload_time_iso_8601": "2023-09-21T22:15:28.092607Z",
            "url": "https://files.pythonhosted.org/packages/67/13/dc72299b4438231447c839497d76ece5cd1e8f794a92d4c773c6e1befaf1/django-seal-1.6.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-09-21 22:15:28",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "charettes",
    "github_project": "django-seal",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "django-seal"
}
        
Elapsed time: 0.10903s