A purl aka. Package URL parser and builder
—
Database model mixins and query utilities for Django and SQLAlchemy frameworks, enabling seamless integration of PackageURL fields into web applications and ORM models. These integrations provide ready-to-use mixins that add PURL fields and related functionality to your models.
Django model mixins and query utilities for working with PackageURLs in Django applications.
from packageurl.contrib.django.models import PackageURLMixin, PackageURLQuerySetMixin
from packageurl.contrib.django.utils import purl_to_lookups
class PackageURLMixin:
"""
Django model mixin providing PackageURL fields and methods.
Fields:
type (CharField): Package type field
namespace (CharField): Package namespace field
name (CharField): Package name field
version (CharField): Package version field
qualifiers (CharField): Package qualifiers field
subpath (CharField): Package subpath field
"""
def set_package_url(self, package_url):
"""
Set model fields from a PackageURL object or string.
Args:
package_url (PackageURL | str): PackageURL object or string to extract fields from
"""
def get_package_url(self):
"""
Get PackageURL object from model fields.
Returns:
PackageURL: PackageURL object constructed from model fields
"""
@property
def package_url(self):
"""
Get PackageURL as string property.
Returns:
str: PackageURL string representation
"""
class PackageURLQuerySetMixin:
"""
Django QuerySet mixin providing PackageURL filtering methods.
"""
def for_package_url(self, purl_str, encode=True, exact_match=False):
"""
Filter QuerySet based on a Package URL string.
Args:
purl_str (str): Package URL string to filter by
encode (bool): Whether to encode PURL components (default: True)
exact_match (bool): Whether to require exact match (default: False)
Returns:
QuerySet: Filtered queryset matching the PURL criteria
"""
def with_package_url(self):
"""
Return objects with Package URL defined.
Returns:
QuerySet: Objects that have both type and name fields populated
"""
def without_package_url(self):
"""
Return objects with empty Package URL.
Returns:
QuerySet: Objects with empty type or name fields
"""
def empty_package_url(self):
"""
Return objects with empty Package URL. Alias of without_package_url.
Returns:
QuerySet: Objects with empty Package URL
"""
def order_by_package_url(self):
"""
Order by Package URL fields.
Returns:
QuerySet: QuerySet ordered by type, namespace, name, version, qualifiers, subpath
"""
class PackageURLQuerySet(PackageURLQuerySetMixin, models.QuerySet):
"""
Django QuerySet that combines PackageURLQuerySetMixin with standard QuerySet.
Provides all PackageURL filtering methods on QuerySet objects.
"""
def purl_to_lookups(purl_str, encode=True, include_empty_fields=False):
"""
Convert PackageURL string to Django field lookups.
Args:
purl_str (str): PackageURL string to convert
encode (bool): Whether to encode components (default: True)
include_empty_fields (bool): Whether to include empty fields (default: False)
Returns:
dict: Dictionary of field lookups for Django queries
"""
def without_empty_values(input_dict):
"""
Return a new dict not including empty value entries from input_dict.
Args:
input_dict (dict): Dictionary to filter
Returns:
dict: Dictionary with empty values removed
Note:
None, empty string, empty list, and empty dict/set are cleaned.
0 and False values are kept.
"""SQLAlchemy declarative mixin providing PackageURL fields and methods for SQLAlchemy models.
from packageurl.contrib.sqlalchemy.mixin import PackageURLMixin
class PackageURLMixin:
"""
SQLAlchemy declarative mixin providing PackageURL fields and methods.
Fields:
type (Mapped[str]): Package type column
namespace (Mapped[str]): Package namespace column
name (Mapped[str]): Package name column
version (Mapped[str]): Package version column
qualifiers (Mapped[str]): Package qualifiers column
subpath (Mapped[str]): Package subpath column
"""
def set_package_url(self, package_url):
"""
Set model fields from a PackageURL object or string.
Args:
package_url (PackageURL): PackageURL object to extract fields from
"""
def get_package_url(self):
"""
Get PackageURL object from model fields.
Returns:
PackageURL: PackageURL object constructed from model fields
"""
@property
def package_url(self):
"""
Get PackageURL as string property.
Returns:
str: PackageURL string representation
"""Django filter classes for PackageURL filtering in Django REST framework and similar applications.
from packageurl.contrib.django.filters import PackageURLFilter
class PackageURLFilter(django_filters.CharFilter):
"""
Django filter for PackageURL fields.
Provides filtering capabilities for web APIs and admin interfaces.
Supports exact matching and empty Package URL filtering with special "EMPTY" value.
Attributes:
is_empty (str): Special value "EMPTY" to filter for empty Package URLs
exact_match_only (bool): Whether to require exact Package URL matching
help_text (str): Help text for the filter
"""
def __init__(self, exact_match_only=False, **kwargs):
"""
Initialize PackageURL filter.
Args:
exact_match_only (bool): Whether to match only exact Package URL strings
**kwargs: Additional filter arguments
"""
def filter(self, qs, value):
"""
Apply PackageURL filtering to QuerySet.
Args:
qs (QuerySet): QuerySet to filter
value (str): Filter value, or "EMPTY" for empty Package URLs
Returns:
QuerySet: Filtered QuerySet
"""PACKAGE_URL_FIELDS = ("type", "namespace", "name", "version", "qualifiers", "subpath")
# Tuple of PackageURL field names used in Django modelsfrom django.db import models
from packageurl.contrib.django.models import PackageURLMixin, PackageURLQuerySetMixin
from packageurl import PackageURL
class PackageQuerySet(models.QuerySet, PackageURLQuerySetMixin):
pass
class Package(models.Model, PackageURLMixin):
# Additional model fields
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
objects = PackageQuerySet.as_manager()
def __str__(self):
return str(self.get_package_url())
# Usage
package = Package()
purl = PackageURL.from_string("pkg:pypi/django@3.2.0")
package.set_package_url(purl)
package.save()
# Query by PURL
packages = Package.objects.for_package_url("pkg:pypi/django@3.2.0")
django_packages = Package.objects.for_package_url("pkg:pypi/django", exact_match=False)from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from packageurl.contrib.sqlalchemy.mixin import PackageURLMixin
from packageurl import PackageURL
Base = declarative_base()
class Package(Base, PackageURLMixin):
__tablename__ = 'packages'
id = Column(Integer, primary_key=True)
description = Column(String)
# Usage
engine = create_engine('sqlite:///packages.db')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
package = Package()
purl = PackageURL.from_string("pkg:maven/org.springframework/spring-core@5.3.21")
package.set_package_url(purl)
session.add(package)
session.commit()
# Query
retrieved_purl = package.get_package_url()
print(retrieved_purl.to_string())from packageurl.contrib.django.utils import purl_to_lookups
from packageurl import PackageURL
# Convert PURL to Django lookups
purl = PackageURL.from_string("pkg:npm/%40angular/core@12.0.0")
lookups = purl_to_lookups(purl)
# Use in manual queries
packages = Package.objects.filter(**lookups)
# Complex queries
maven_packages = Package.objects.filter(type='maven')
spring_packages = Package.objects.filter(
type='maven',
namespace__startswith='org.springframework'
)Install with Tessl CLI
npx tessl i tessl/pypi-packageurl-python