diff --git a/component_catalog/admin.py b/component_catalog/admin.py index 4dff4eb2..d88efaae 100644 --- a/component_catalog/admin.py +++ b/component_catalog/admin.py @@ -16,6 +16,7 @@ from django.urls import path from django.urls import reverse from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ @@ -504,7 +505,7 @@ def response_change(self, request, obj): "This license change impacts component usage in a Product or in another " "Component.
{}".format(", ".join(changelist_links)) ) - self.message_user(request, format_html(msg), messages.WARNING) + self.message_user(request, mark_safe(msg), messages.WARNING) return response @@ -554,15 +555,23 @@ def get_actions(self, request): del actions["set_policy"] return actions - def log_deletion(self, request, object, object_repr): + def delete_model(self, request, obj): """ + Handle single object deletion from the delete view. Add the option to delete associated `Package` instances. - We use this method rather than `self.delete_model()` since we want to support both - the delete_view and the `delete_selected` action. """ - super().log_deletion(request, object, object_repr) if request.POST.get("delete_packages"): - object.packages.all().delete() + obj.packages.all().delete() + super().delete_model(request, obj) + + def delete_queryset(self, request, queryset): + """ + Handle bulk deletion from the delete_selected action. + Add the option to delete associated `Package` instances. + """ + if request.POST.get("delete_packages"): + Package.objects.filter(component__in=queryset).delete() + super().delete_queryset(request, queryset) def changeform_view(self, request, object_id=None, form_url="", extra_context=None): """ @@ -1053,7 +1062,7 @@ def collect_data_action(self, request, queryset): if not_updated: msg += f"
{not_updated} package(s) NOT updated (data already set or URL unavailable)" - self.message_user(request, format_html(msg), messages.SUCCESS) + self.message_user(request, mark_safe(msg), messages.SUCCESS) @admin.display( ordering="component", @@ -1068,7 +1077,7 @@ def components_links(self, obj): assigned_package.component.get_admin_link(target="_blank") for assigned_package in obj.componentassignedpackage_set.all() ] - return format_html("
".join(component_links)) + return mark_safe("
".join(component_links)) @admin.display(description="Inferred URL") def inferred_url(self, obj): diff --git a/component_catalog/license_expression_dje.py b/component_catalog/license_expression_dje.py index b2f0e58e..b179b599 100644 --- a/component_catalog/license_expression_dje.py +++ b/component_catalog/license_expression_dje.py @@ -14,7 +14,7 @@ from django.forms import widgets from django.urls import reverse from django.utils.html import format_html -from django.utils.safestring import mark_safe +from django.utils.html import mark_safe from boolean.boolean import PARSE_ERRORS from license_expression import ExpressionError @@ -149,7 +149,7 @@ def normalize_and_validate_expression( msg = str(ee) if include_available: msg += available_licenses_message(licensing) - raise ValidationError(format_html(msg), code="invalid") + raise ValidationError(mark_safe(msg), code="invalid") except ParseError as pe: msg = PARSE_ERRORS[pe.error_code] @@ -157,15 +157,15 @@ def normalize_and_validate_expression( msg += ": " + pe.token_string if include_available: msg += available_licenses_message(licensing) - raise ValidationError(format_html(msg), code="invalid") + raise ValidationError(mark_safe(msg), code="invalid") except (ValueError, TypeError) as ve: msg = "Invalid reference licenses data.\n" + str(ve) - raise ValidationError(format_html(msg), code="invalid") + raise ValidationError(mark_safe(msg), code="invalid") except Exception as e: msg = "Invalid license expression.\n" + str(e) - raise ValidationError(format_html(msg), code="invalid") + raise ValidationError(mark_safe(msg), code="invalid") # NOTE: we test for None because an expression cannot be resolved to # a boolean and a plain "if parsed" would attempt to resolve the diff --git a/component_catalog/models.py b/component_catalog/models.py index 1c8719cc..99a00ec8 100644 --- a/component_catalog/models.py +++ b/component_catalog/models.py @@ -31,6 +31,7 @@ from django.template.defaultfilters import filesizeformat from django.utils.functional import cached_property from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.text import format_lazy from django.utils.text import get_valid_filename from django.utils.text import normalize_newlines @@ -190,7 +191,7 @@ def get_license_expression(self, template="{symbol.key}", as_link=False, show_po as_link=as_link, show_policy=show_policy, ) - return format_html(rendered) + return mark_safe(rendered) def get_license_expression_attribution(self): # note: the fields use in the template must be available as attributes or diff --git a/component_catalog/tests/test_admin.py b/component_catalog/tests/test_admin.py index 30b43a84..6627d43a 100644 --- a/component_catalog/tests/test_admin.py +++ b/component_catalog/tests/test_admin.py @@ -2204,18 +2204,20 @@ def test_component_admin_delete_confirmation_include_associated_packages(self): expected = "Would you also like to delete Packages associated with this Component" self.assertNotContains(response, expected) - package1 = Package.objects.create(filename="package1.zip", dataspace=self.dataspace1) + package1 = make_package(dataspace=self.dataspace1, filename="package1.zip") ComponentAssignedPackage.objects.create( component=self.component1, package=package1, dataspace=self.dataspace1 ) - package2 = Package.objects.create(filename="package2.zip", dataspace=self.dataspace1) + package2 = make_package(dataspace=self.dataspace1, filename="package2.zip") ComponentAssignedPackage.objects.create( component=self.component1, package=package2, dataspace=self.dataspace1 ) + self.assertEqual(2, self.component1.packages.count()) - self.assertTrue(self.component1.packages.exists()) response = self.client.get(delete_url) self.assertContains(response, expected) + field = '' + self.assertContains(response, field) data = { "post": "yes", @@ -2224,9 +2226,10 @@ def test_component_admin_delete_confirmation_include_associated_packages(self): response = self.client.post(delete_url, data=data, follow=True) self.assertContains(response, "was deleted successfully.") self.assertFalse(Component.objects.filter(pk=self.component1.pk).exists()) - self.assertFalse(Package.objects.filter(pk__in=[package1.pk, package2.pk]).exists()) + package_qs = Package.objects.filter(pk__in=[package1.pk, package2.pk]) + self.assertFalse(package_qs.exists()) - package3 = Package.objects.create(filename="package3.zip", dataspace=self.dataspace1) + package3 = make_package(dataspace=self.dataspace1, filename="package3.zip") ComponentAssignedPackage.objects.create( component=self.component2, package=package3, dataspace=self.dataspace1 ) diff --git a/component_catalog/tests/test_importers.py b/component_catalog/tests/test_importers.py index 02496bf9..eceb65d1 100644 --- a/component_catalog/tests/test_importers.py +++ b/component_catalog/tests/test_importers.py @@ -348,7 +348,7 @@ def test_component_import_url_without_scheme_validation(self): self.assertTrue(importer.formset.is_valid()) importer.save_all() added_component = importer.results["added"][0] - self.assertEqual("http://www.a.com", added_component.homepage_url) + self.assertEqual("https://www.a.com", added_component.homepage_url) def test_component_import_strip_input_values(self): file = os.path.join(TESTFILES_LOCATION, "valid_with_non_stripped_spaces.csv") diff --git a/component_catalog/views.py b/component_catalog/views.py index f24d1a05..775bf3b6 100644 --- a/component_catalog/views.py +++ b/component_catalog/views.py @@ -34,6 +34,7 @@ from django.utils.dateparse import parse_datetime from django.utils.html import escape from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.text import normalize_newlines from django.utils.translation import gettext from django.utils.translation import gettext_lazy as _ @@ -275,7 +276,7 @@ def tab_vulnerabilities(self): return { "fields": [(None, context, None, self.template)], - "label": format_html(label), + "label": mark_safe(label), } def get_fixed_packages_html(self, vulnerability, dataspace): @@ -311,7 +312,7 @@ def get_fixed_packages_html(self, vulnerability, dataspace): if is_vulnerable: display_value += package.get_html_link( href=f"{absolute_url}#vulnerabilities", - value=format_html(vulnerability_icon), + value=mark_safe(vulnerability_icon), ) else: display_value += no_vulnerabilities_icon @@ -336,7 +337,7 @@ def get_fixed_packages_html(self, vulnerability, dataspace): ) fixed_packages_values.append(display_value) - return format_html("
".join(fixed_packages_values)) + return mark_safe("
".join(fixed_packages_values)) class ComponentListView( @@ -703,7 +704,7 @@ def tab_subcomponents(self): if dataspace.show_usage_policy_in_user_views: usage_policy = subcomponent.get_usage_policy_display_with_icon() if not usage_policy: - usage_policy = format_html(" ") + usage_policy = mark_safe(" ") fields_data["usage_policy"] = usage_policy components.append(fields_data) @@ -1053,7 +1054,7 @@ def post_add_to_component(self, form_class): return redirect(request.path) error_msg = f"Error assigning packages to a component.\n{form.errors}" - messages.error(request, format_html(error_msg)) + messages.error(request, mark_safe(error_msg)) return redirect(request.path) def post(self, request, *args, **kwargs): @@ -1418,7 +1419,7 @@ def post_scan_to_package(self, form_class): messages.warning(request, "No new values to assign.") else: error_msg = f"Error assigning values to the package.\n{form.errors}" - messages.error(request, format_html(error_msg)) + messages.error(request, mark_safe(error_msg)) return redirect(f"{request.path}#essentials") @@ -1593,7 +1594,7 @@ def package_create_ajax_view(request): elif len_created > 1: packages = "\n".join([package.get_absolute_link() for package in created]) msg = f"The following Packages were successfully created{scan_msg}:\n{packages}" - messages.success(request, format_html(msg)) + messages.success(request, mark_safe(msg)) purls_wihtout_download_url = [package for package in created if not package.download_url] if purls_wihtout_download_url: @@ -1604,12 +1605,12 @@ def package_create_ajax_view(request): "\nAlternatively, you can directly provide a download URL instead of a " "package URL to create the packages.\n" ) - messages.warning(request, format_html(msg + "\n".join(packages))) + messages.warning(request, mark_safe(msg + "\n".join(packages))) if errors: - messages.error(request, format_html("\n".join(errors))) + messages.error(request, mark_safe("\n".join(errors))) if warnings: - messages.warning(request, format_html("\n".join(warnings))) + messages.warning(request, mark_safe("\n".join(warnings))) return JsonResponse({"redirect_url": redirect_url}) @@ -2187,7 +2188,7 @@ def license_clarity_fields(license_clarity_score): table.append( { "label": label, - "value": format_html(value), + "value": mark_safe(value), "help_text": help_text, "td_class": td_class, "th_class": th_class, @@ -2328,7 +2329,7 @@ def scan_detected_package_fields(self, key_files_packages): for label, scan_field in ScanCodeIO.SCAN_PACKAGE_FIELD: if value := self.detected_package_data.get(scan_field): if isinstance(value, list): - value = format_html("
".join([escape(entry) for entry in value])) + value = mark_safe("
".join([escape(entry) for entry in value])) else: value = escape(value) detected_package_fields.append((label, value)) @@ -2404,7 +2405,7 @@ def scan_summary_fields(self, scan_summary): if entry.get("value") ] - scan_summary_fields.append((label, format_html("\n".join(values)))) + scan_summary_fields.append((label, mark_safe("\n".join(values)))) scan_summary_fields.append(FieldSeparator) return scan_summary_fields diff --git a/dejacode/settings.py b/dejacode/settings.py index a4ff4d48..42abf429 100644 --- a/dejacode/settings.py +++ b/dejacode/settings.py @@ -635,6 +635,9 @@ def get_fake_redis_connection(config, use_strict_redis): # Although, this setting and registration views are needed for the user creation. ACCOUNT_ACTIVATION_DAYS = 10 +# django-altcha +ALTCHA_HMAC_KEY = env.str("DEJACODE_ALTCHA_HMAC_KEY", default="") + # https://github.com/zapier/django-rest-hooks HOOK_FINDER = "notification.models.find_and_fire_hook" HOOK_DELIVERER = "notification.tasks.deliver_hook_wrapper" @@ -683,11 +686,20 @@ def get_fake_redis_connection(config, use_strict_redis): MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware") INTERNAL_IPS = ["127.0.0.1"] +# drf-yasg DeprecationWarning +SWAGGER_USE_COMPAT_RENDERERS = False + +# The default protocol in urlize and urlizetrunc will change from HTTP to HTTPS +# in Django 7.0. +# Set the transitional setting URLIZE_ASSUME_HTTPS to True to opt into assuming HTTPS +# during the Django 6.x release cycle. +URLIZE_ASSUME_HTTPS = env.bool("DEJACODE_URLIZE_ASSUME_HTTPS", default=True) + if IS_TESTS: # Silent the django-axes logging during tests LOGGING["loggers"].update({"axes": {"handlers": ["null"]}}) # Do not pollute the MEDIA_ROOT location while running the tests. - MEDIA_ROOT = tempfile.TemporaryDirectory().name + MEDIA_ROOT = tempfile.mkdtemp() # Set a faster hashing algorithm for running the tests # https://docs.djangoproject.com/en/dev/topics/testing/overview/#password-hashing PASSWORD_HASHERS = [ diff --git a/dejacode_toolkit/spdx.py b/dejacode_toolkit/spdx.py index 63c8adea..f2059be7 100644 --- a/dejacode_toolkit/spdx.py +++ b/dejacode_toolkit/spdx.py @@ -10,6 +10,7 @@ import re from dataclasses import dataclass from dataclasses import field +from datetime import UTC from datetime import datetime from typing import List # Python 3.8 compatibility @@ -106,7 +107,7 @@ class CreationInfo: Format: YYYY-MM-DDThh:mm:ssZ """ created: str = field( - default_factory=lambda: datetime.utcnow().isoformat(timespec="seconds") + "Z", + default_factory=lambda: datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ"), ) def as_dict(self): diff --git a/dje/admin.py b/dje/admin.py index 6d20d8d1..6aa131b5 100644 --- a/dje/admin.py +++ b/dje/admin.py @@ -50,6 +50,7 @@ from django.utils.encoding import force_str from django.utils.html import format_html from django.utils.html import format_html_join +from django.utils.html import mark_safe from django.utils.http import urlencode from django.utils.translation import gettext as _ from django.views.generic import RedirectView @@ -252,10 +253,10 @@ class ProhibitDataspaceLookupMixin: Remove the possibility to look into other Dataspaces. """ - def lookup_allowed(self, lookup, value): + def lookup_allowed(self, lookup, value, request): if lookup.startswith("dataspace"): return False - return super().lookup_allowed(lookup, value) + return super().lookup_allowed(lookup, value, request) def check(self, **kwargs): errors = super().check(**kwargs) @@ -325,12 +326,13 @@ def log_change(self, request, object, message): return history_entry - def log_deletion(self, request, object, object_repr): + def log_deletions(self, request, queryset): """ - Log that an object will be deleted. + Log that objects will be deleted. Note that this method must be called before the deletion. """ - return History.log_deletion(request.user, object) + for object in queryset: + History.log_deletion(request.user, object) def history_view(self, request, object_id, extra_context=None): response = super().history_view(request, object_id, extra_context) @@ -413,7 +415,7 @@ def set_reference_link(self, request): do_set_link = all( [ DataspaceFilter in self.model_admin.list_filter, - self.model_admin.lookup_allowed(DataspaceFilter.parameter_name, None), + self.model_admin.lookup_allowed(DataspaceFilter.parameter_name, None, request), not self.is_popup, ] ) @@ -764,7 +766,7 @@ def save_formset(self, request, form, formset, change): super().save_formset(request, form, formset, change) def delete_model(self, request, obj): - # We are using this rather than self.log_deletion because it's not called + # We are using this rather than self.log_deletions because it's not called # Here, History.log_deletion is called for each object in the bulk. History.log_deletion(request.user, obj) super().delete_model(request, obj) @@ -987,10 +989,10 @@ def response_change(self, request, obj): return super().response_change(request, obj) - def lookup_allowed(self, lookup, value): + def lookup_allowed(self, lookup, value, request): if lookup in [EXTERNAL_SOURCE_LOOKUP]: return True - return super().lookup_allowed(lookup, value) + return super().lookup_allowed(lookup, value, request) @staticmethod def _limited_permission(request, obj, has_perm): @@ -1750,7 +1752,7 @@ def get_queryset(self, request): @admin.display(description=_("Permissions")) def get_permissions(self, obj): - return format_html("
".join(obj.permissions.values_list("name", flat=True))) + return mark_safe("
".join(obj.permissions.values_list("name", flat=True))) def formfield_for_manytomany(self, db_field, request=None, **kwargs): """Limit the available Permissions.""" diff --git a/dje/forms.py b/dje/forms.py index 4e7213e4..9606fe54 100644 --- a/dje/forms.py +++ b/dje/forms.py @@ -23,6 +23,7 @@ from django.forms.utils import ErrorList from django.utils.html import conditional_escape from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.translation import gettext_lazy as _ from crispy_forms.helper import FormHelper @@ -609,7 +610,7 @@ def __init__(self, *args, **kwargs): for model_class in models: model_name = str(model_class._meta.verbose_name) self.fields[model_name] = forms.MultipleChoiceField( - label=format_html("{}", model_name.title()), + label=mark_safe(model_name.title()), required=False, choices=model_class.get_exclude_choices(), widget=forms.CheckboxSelectMultiple(attrs={"class": "inline"}), @@ -652,7 +653,7 @@ def as_ul(self): if not self: return "" list_items = "".join(["
  • {}{}
  • ".format(k, str(v)) for k, v in self.items()]) - return format_html(f'') + return mark_safe(f'') class WarningList(ErrorList): @@ -665,7 +666,7 @@ def as_ul(self): if not self: return "" list_items = "".join(["
  • {}
  • ".format(conditional_escape(str(e))) for e in self]) - return format_html(f'') + return mark_safe(f'') class BoundFieldWithWarnings(BoundField): @@ -774,7 +775,7 @@ def __init__(self, *args, **kwargs): for model_name, tabset in get_all_tabsets().items(): check_all = '' - label = format_html(f"{model_name.title()} {check_all}") + label = mark_safe(f"{model_name.title()} {check_all}") self.fields[model_name] = forms.MultipleChoiceField( label=label, required=False, diff --git a/dje/list_display.py b/dje/list_display.py index 3d23a0ef..d4a90e5f 100644 --- a/dje/list_display.py +++ b/dje/list_display.py @@ -9,6 +9,7 @@ from django.contrib.humanize.templatetags.humanize import naturaltime from django.utils.formats import date_format from django.utils.html import format_html +from django.utils.html import mark_safe from dje.templatetags.dje_tags import urlize_target_blank from dje.utils import class_wrap @@ -89,7 +90,7 @@ def __init__(self, name, join_str, **kwargs): super().__init__(name, **kwargs) def to_representation(self, value): - return format_html(self.join_str.join(value)) + return mark_safe(self.join_str.join(value)) class AsNaturalTime(ListDisplayItem): diff --git a/dje/tasks.py b/dje/tasks.py index 08a68d3f..e73dbf72 100644 --- a/dje/tasks.py +++ b/dje/tasks.py @@ -36,8 +36,13 @@ def send_mail_task(subject, message, from_email, recipient_list, fail_silently=T The subject is cleaned from newlines and limited to 255 characters. """ - subject = "".join(subject.splitlines())[:255] - send_mail(subject, message, from_email, recipient_list, fail_silently) + send_mail( + subject="".join(subject.splitlines())[:255], + message=message, + from_email=from_email, + recipient_list=recipient_list, + fail_silently=fail_silently, + ) @job @@ -50,7 +55,13 @@ def send_mail_to_admins_task(subject, message, from_email=None, fail_silently=Tr if not recipient_list: return - send_mail_task(subject, message, from_email, recipient_list, fail_silently) + send_mail_task( + subject=subject, + message=message, + from_email=from_email, + recipient_list=recipient_list, + fail_silently=fail_silently, + ) @job("default", timeout=7200) diff --git a/dje/templatetags/dje_tags.py b/dje/templatetags/dje_tags.py index 007c6238..75cb933d 100644 --- a/dje/templatetags/dje_tags.py +++ b/dje/templatetags/dje_tags.py @@ -19,9 +19,9 @@ from django.urls import get_script_prefix from django.urls import resolve from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.html import urlize as _urlize from django.utils.http import urlencode -from django.utils.safestring import mark_safe register = Library() diff --git a/dje/tests/test_templatetags.py b/dje/tests/test_templatetags.py index 31f6dfe0..bc7457ff 100644 --- a/dje/tests/test_templatetags.py +++ b/dje/tests/test_templatetags.py @@ -20,7 +20,7 @@ def test_dje_templatetags_urlize_target_blank_template_tag(self): inputs = [ ( "domain.com", - 'domain.com', + 'domain.com', ), ( "http://domain.com", diff --git a/dje/tests/test_user.py b/dje/tests/test_user.py index cbba76d2..81450107 100644 --- a/dje/tests/test_user.py +++ b/dje/tests/test_user.py @@ -449,7 +449,7 @@ def test_user_admin_form_scope_homepage_layout_choices(self): card_layout_other = create("CardLayout", self.other_dataspace) response = self.client.get(url) - expected = '' + expected = 'Homepage layout:' self.assertContains(response, expected, html=True) self.assertContains(response, card_layout_nexb.name) self.assertNotContains(response, card_layout_other.name) diff --git a/dje/utils.py b/dje/utils.py index 08bbfdd9..aae13945 100644 --- a/dje/utils.py +++ b/dje/utils.py @@ -618,7 +618,7 @@ def get_cpe_vuln_link(cpe): base_url = "https://nvd.nist.gov/vuln/search/results" params = "?adv_search=true&isCpeNameSearch=true" vuln_url = f"{base_url}{params}&query={cpe}" - return format_html(f'{cpe}') + return mark_safe(f'{cpe}') def safe_filename(filename): diff --git a/dje/views.py b/dje/views.py index 5e2f2ab2..c722e2fd 100644 --- a/dje/views.py +++ b/dje/views.py @@ -54,7 +54,7 @@ from django.urls import reverse_lazy from django.utils import timezone from django.utils.decorators import method_decorator -from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.text import capfirst from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView @@ -982,7 +982,7 @@ def tab_activity(self, exclude_product_context=False): label = f'Activity {len(requests)}' return { "fields": activity_fields, - "label": format_html(label), + "label": mark_safe(label), } def tab_external_references(self): diff --git a/dje/widgets.py b/dje/widgets.py index f6358089..4eea5e14 100644 --- a/dje/widgets.py +++ b/dje/widgets.py @@ -11,6 +11,7 @@ from django.forms import widgets from django.forms.utils import flatatt from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.http import urlencode from django.utils.translation import gettext as _ @@ -55,14 +56,13 @@ def render(self, name, value, attrs=None, renderer=None, choices=()): if options: output.append(options) output.append("") - menu = format_html("\n".join(output)) return format_html( self.dropdown_template, - menu=menu, + menu=mark_safe("\n".join(output)), active="active" if value else "", label=self.label if self.label else name.title(), - link_content=format_html(self.link_content or ""), + link_content=mark_safe(self.link_content or ""), ) def render_option(self, name, selected_choices, option_value, option_label): diff --git a/license_library/tests/test_translation.py b/license_library/tests/test_translation.py index 8078f0a8..f4bc0a0e 100644 --- a/license_library/tests/test_translation.py +++ b/license_library/tests/test_translation.py @@ -44,13 +44,13 @@ def test_changeview_translation(self): translation.activate("en") response = self.client.get(url) - expected = '' + expected = 'License profile:' self.assertContains(response, expected) translation.activate("en_GB") # Activate the custom translation locale response = self.client.get(url) # The verbose part of the label is properly translated. - expected = '' + expected = 'Attribution type:' self.assertContains(response, expected) def test_admin_index_view_translation(self): diff --git a/policy/admin.py b/policy/admin.py index cfe54f31..645f3b9e 100755 --- a/policy/admin.py +++ b/policy/admin.py @@ -11,7 +11,7 @@ from django.http import HttpResponse from django.template.defaultfilters import linebreaksbr from django.urls import path -from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.html import urlize from django.utils.translation import gettext_lazy as _ @@ -81,25 +81,23 @@ class UsagePolicyAdmin(ColoredIconAdminMixin, DataspacedAdmin): "Subcomponent relationships, and Packages." ) - long_description = format_html( - urlize( - linebreaksbr( - "For each application object type, you can specify the Usage Policy " - "label text, icon, and icon color for each relevant policy position " - "that you need to communicate to your users. " - "Examples include Recommended, Approved, Restricted, and Prohibited.\n" - "You can also export your DejaCode License Usage Policy assignments as " - "a file to use in other applications by clicking the " - '"Download License Policies as YAML" button. ' - "For an example of how to use this file in an open source tool, see " - "https://github.com/nexB/scancode-toolkit/wiki/License-Policy-Plugin " - "for a detailed explanation." - ) + long_description = urlize( + linebreaksbr( + "For each application object type, you can specify the Usage Policy " + "label text, icon, and icon color for each relevant policy position " + "that you need to communicate to your users. " + "Examples include Recommended, Approved, Restricted, and Prohibited.\n" + "You can also export your DejaCode License Usage Policy assignments as " + "a file to use in other applications by clicking the " + '"Download License Policies as YAML" button. ' + "For an example of how to use this file in an open source tool, see " + "https://github.com/nexB/scancode-toolkit/wiki/License-Policy-Plugin " + "for a detailed explanation." ) ) def associated_policies(self, obj): - return format_html( + return mark_safe( "
    ".join( association.to_policy.str_with_content_type() for association in obj.to_policies.all() diff --git a/product_portfolio/admin.py b/product_portfolio/admin.py index cd5a6d22..c9624c07 100644 --- a/product_portfolio/admin.py +++ b/product_portfolio/admin.py @@ -17,7 +17,7 @@ from django.contrib.auth.models import Group from django.db import models from django.shortcuts import get_object_or_404 -from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.translation import gettext_lazy as _ from guardian.admin import GuardedModelAdminMixin @@ -398,7 +398,7 @@ class ProductAdmin( def get_feature_datalist(self, obj): if obj.pk: return obj.get_feature_datalist() - return format_html('') + return mark_safe('') def get_queryset(self, request, include_inactive=False): return ( @@ -473,7 +473,7 @@ def has_delete_permission(self, request, obj=None): def get_feature_datalist(self, obj): if obj.id and obj.product: return obj.product.get_feature_datalist() - return format_html('') + return mark_safe('') def get_actions(self, request): actions = super().get_actions(request) diff --git a/product_portfolio/tests/test_api.py b/product_portfolio/tests/test_api.py index c0ecbde5..508849ff 100644 --- a/product_portfolio/tests/test_api.py +++ b/product_portfolio/tests/test_api.py @@ -476,12 +476,13 @@ def test_api_product_endpoint_import_from_scan_action(self): self.assertEqual(expected, response.data) scan_input_location = self.testfiles_path / "import_from_scan.json" - data = { - "upload_file": scan_input_location.open(), - "create_codebase_resources": True, - "stop_on_error": False, - } - response = self.client.post(url, data) + with scan_input_location.open() as upload_file: + data = { + "upload_file": upload_file, + "create_codebase_resources": True, + "stop_on_error": False, + } + response = self.client.post(url, data) self.assertEqual(status.HTTP_200_OK, response.status_code) expected = { "status": "Imported from Scan: 1 Packages, 1 Product Packages, 3 Codebase Resources" diff --git a/product_portfolio/views.py b/product_portfolio/views.py index f20b8b56..3584bce1 100644 --- a/product_portfolio/views.py +++ b/product_portfolio/views.py @@ -43,6 +43,7 @@ from django.urls import reverse from django.utils.decorators import method_decorator from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.translation import gettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods @@ -515,7 +516,7 @@ def tab_inventory(self): } return { - "label": format_html(label), + "label": mark_safe(label), "fields": [(None, tab_context, None, template)], } @@ -538,7 +539,7 @@ def tab_dependencies(self): } return { - "label": format_html(label), + "label": mark_safe(label), "fields": [(None, tab_context, None, template)], } @@ -566,7 +567,7 @@ def tab_vulnerabilities(self): if not vulnerability_count and risk_threshold is None: label = 'Vulnerabilities 0' return { - "label": format_html(label), + "label": mark_safe(label), "fields": [], "disabled": True, "tooltip": "No vulnerabilities found in this Product", @@ -596,7 +597,7 @@ def tab_vulnerabilities(self): } return { - "label": format_html(label), + "label": mark_safe(label), "fields": [(None, tab_context, None, template)], } @@ -619,7 +620,7 @@ def tab_codebase(self): } return { - "label": format_html(label), + "label": mark_safe(label), "fields": [(None, tab_context, None, template)], } @@ -645,7 +646,7 @@ def tab_imports(self): } return { - "label": format_html(label), + "label": mark_safe(label), "fields": [(None, tab_context, None, template)], } @@ -2037,9 +2038,9 @@ def import_from_scan_view(request, dataspace, name, version=""): msg = "Imported from Scan:" for key, value in created_counts.items(): msg += f"
    • {value} {key}" - messages.success(request, format_html(msg)) + messages.success(request, mark_safe(msg)) if warnings: - messages.warning(request, format_html("
    ".join(warnings))) + messages.warning(request, mark_safe("
    ".join(warnings))) return redirect(f"{product.get_absolute_url()}#imports") else: form = form_class(request.user) diff --git a/purldb/views.py b/purldb/views.py index 1c4233d8..401fb43b 100644 --- a/purldb/views.py +++ b/purldb/views.py @@ -15,8 +15,8 @@ from django.http import Http404 from django.template.defaultfilters import filesizeformat from django.urls import reverse -from django.utils.html import format_html from django.utils.html import format_html_join +from django.utils.html import mark_safe from django.utils.text import capfirst from django.utils.translation import gettext_lazy as _ from django.views.generic import DetailView @@ -94,7 +94,7 @@ def get_purldb_tab_fields(purldb_entry, dataspace): if field_name == "declared_license_expression": show_policy = dataspace.show_usage_policy_in_user_views licensing = get_dataspace_licensing(dataspace) - value = format_html(get_formatted_expression(licensing, value, show_policy)) + value = mark_safe(get_formatted_expression(licensing, value, show_policy)) elif field_name == "dependencies": value = json.dumps(value, indent=2) elif field_name == "size": @@ -138,7 +138,7 @@ def inject_license_expression_formatted(dataspace, object_list): expression = obj.get("declared_license_expression") if expression: formatted_expression = get_formatted_expression(licensing, expression, show_policy) - obj["license_expression_formatted"] = format_html(formatted_expression) + obj["license_expression_formatted"] = mark_safe(formatted_expression) return object_list diff --git a/pyproject.toml b/pyproject.toml index 79713183..8e49b88a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ dependencies = [ "packaging==26.0", "pip==26.0.1", # Django - "Django==5.2.11", + "Django==6.0.2", "asgiref==3.11.1", "typing_extensions==4.15.0", "sqlparse==0.5.5", diff --git a/reporting/admin.py b/reporting/admin.py index f1fe3564..fa4c97dd 100644 --- a/reporting/admin.py +++ b/reporting/admin.py @@ -13,6 +13,7 @@ from django.db.models import PositiveSmallIntegerField from django.forms import HiddenInput from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ @@ -337,7 +338,7 @@ class ColumnTemplateAdmin(DataspacedAdmin): @admin.display(description=_("Assigned fields")) def get_field_names(self, instance): field_names = [assigned_field.field_name for assigned_field in instance.fields.all()] - return format_html("
    ".join(field_names)) + return mark_safe("
    ".join(field_names)) def get_queryset(self, request): qs = super().get_queryset(request) diff --git a/reporting/models.py b/reporting/models.py index f082656a..26418a0b 100644 --- a/reporting/models.py +++ b/reporting/models.py @@ -26,7 +26,7 @@ from django.forms import fields_for_model from django.urls import NoReverseMatch from django.urls import reverse -from django.utils.html import format_html +from django.utils.html import mark_safe from django.utils.http import urlencode from django.utils.translation import gettext_lazy as _ @@ -547,7 +547,7 @@ def as_headers(self, include_view_link=False): """Return a list of field name, usable as Report results headers.""" headers = [field.display_name or field.field_name for field in self.fields.all()] if include_view_link: - headers.insert(0, format_html(" ")) + headers.insert(0, mark_safe(" ")) return headers @@ -764,7 +764,7 @@ def get_output(self, queryset=None, user=None, include_view_link=False, multi_as if queryset is None: queryset = self.query.get_qs(user=user) - icon = format_html('') + icon = mark_safe('') rows = [] for instance in queryset: diff --git a/thirdparty/dist/asgiref-3.11.1-py3-none-any.whl.ABOUT b/thirdparty/dist/asgiref-3.11.1-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..2e911efc --- /dev/null +++ b/thirdparty/dist/asgiref-3.11.1-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: asgiref-3.11.1-py3-none-any.whl +name: asgiref +version: 3.11.1 +download_url: https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl +package_url: pkg:pypi/asgiref@3.11.1 +license_expression: bsd-new +copyright: Copyright asgiref project contributors +attribute: yes +checksum_md5: 45c208eee6ba3a4af25735a12bbeb363 +checksum_sha1: 9c6062b3b9eb39e14fafe0c07f329b6e4bf9dbee +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE diff --git a/thirdparty/dist/click-8.3.1-py3-none-any.whl.ABOUT b/thirdparty/dist/click-8.3.1-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..879c24bf --- /dev/null +++ b/thirdparty/dist/click-8.3.1-py3-none-any.whl.ABOUT @@ -0,0 +1,17 @@ +about_resource: click-8.3.1-py3-none-any.whl +name: click +version: 8.3.1 +download_url: https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl +package_url: pkg:pypi/click@8.3.1 +license_expression: bsd-new AND unknown-license-reference +copyright: Copyright click project contributors +attribute: yes +checksum_md5: f032502934a5979330da77e3f09d889c +checksum_sha1: 4645f956db291ad4bdb38a84f1e27ea87ca19a37 +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/cython-3.2.4-py3-none-any.whl.ABOUT b/thirdparty/dist/cython-3.2.4-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..a1ae1346 --- /dev/null +++ b/thirdparty/dist/cython-3.2.4-py3-none-any.whl.ABOUT @@ -0,0 +1,15 @@ +about_resource: cython-3.2.4-py3-none-any.whl +name: cython +version: 3.2.4 +download_url: https://files.pythonhosted.org/packages/ff/fa/d3c15189f7c52aaefbaea76fb012119b04b9013f4bf446cb4eb4c26c4e6b/cython-3.2.4-py3-none-any.whl +package_url: pkg:pypi/cython@3.2.4 +license_expression: apache-2.0 +copyright: Copyright cython project contributors +attribute: yes +track_changes: yes +checksum_md5: cb1da7746fd0fc2077f78f5ae89a4c3c +checksum_sha1: bbbedf37da4b846172f234097b1191e2d260e171 +licenses: + - key: apache-2.0 + name: Apache License 2.0 + file: apache-2.0.LICENSE diff --git a/thirdparty/dist/deprecated-1.3.1-py2.py3-none-any.whl.ABOUT b/thirdparty/dist/deprecated-1.3.1-py2.py3-none-any.whl.ABOUT new file mode 100644 index 00000000..037be334 --- /dev/null +++ b/thirdparty/dist/deprecated-1.3.1-py2.py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: deprecated-1.3.1-py2.py3-none-any.whl +name: deprecated +version: 1.3.1 +download_url: https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl +package_url: pkg:pypi/deprecated@1.3.1 +license_expression: mit +copyright: Copyright deprecated project contributors +attribute: yes +checksum_md5: f653365522f40405ec4059edab8618bd +checksum_sha1: cdf474353a5b98598f306d2cad18478e3bcaa4db +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/django-5.2.11-py3-none-any.whl b/thirdparty/dist/django-6.0.2-py3-none-any.whl similarity index 78% rename from thirdparty/dist/django-5.2.11-py3-none-any.whl rename to thirdparty/dist/django-6.0.2-py3-none-any.whl index 7db3e42c..a868e1d4 100644 Binary files a/thirdparty/dist/django-5.2.11-py3-none-any.whl and b/thirdparty/dist/django-6.0.2-py3-none-any.whl differ diff --git a/thirdparty/dist/django-6.0.2-py3-none-any.whl.ABOUT b/thirdparty/dist/django-6.0.2-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..d3b098b4 --- /dev/null +++ b/thirdparty/dist/django-6.0.2-py3-none-any.whl.ABOUT @@ -0,0 +1,21 @@ +about_resource: django-6.0.2-py3-none-any.whl +name: django +version: 6.0.2 +download_url: https://files.pythonhosted.org/packages/96/ba/a6e2992bc5b8c688249c00ea48cb1b7a9bc09839328c81dc603671460928/django-6.0.2-py3-none-any.whl +package_url: pkg:pypi/django@6.0.2 +license_expression: bsd-new AND python AND unknown-license-reference +copyright: Copyright django project contributors +attribute: yes +track_changes: yes +checksum_md5: 5e170a7a20b0edbb794228a20895cf17 +checksum_sha1: 70f23a750efce9d525a94dc2d4a15ce016a1e42b +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE + - key: python + name: Python Software Foundation License v2 + file: python.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/django_auth_ldap-5.3.0-py3-none-any.whl.ABOUT b/thirdparty/dist/django_auth_ldap-5.3.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..5b460d5f --- /dev/null +++ b/thirdparty/dist/django_auth_ldap-5.3.0-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: django_auth_ldap-5.3.0-py3-none-any.whl +name: django-auth-ldap +version: 5.3.0 +download_url: https://files.pythonhosted.org/packages/a9/91/38ba24b9d76925ce166b2eebe1b4ea460063b8ba8cf91d39d97ee3bad517/django_auth_ldap-5.3.0-py3-none-any.whl +package_url: pkg:pypi/django-auth-ldap@5.3.0 +license_expression: bsd-new +copyright: Copyright django-auth-ldap project contributors +attribute: yes +checksum_md5: 1cdf18b1be5d570d14813f1c41b90308 +checksum_sha1: b3cf94cf797280d009666f3f1fc7a668388331ea +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE diff --git a/thirdparty/dist/django_debug_toolbar-6.2.0-py3-none-any.whl.ABOUT b/thirdparty/dist/django_debug_toolbar-6.2.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..34fecba3 --- /dev/null +++ b/thirdparty/dist/django_debug_toolbar-6.2.0-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: django_debug_toolbar-6.2.0-py3-none-any.whl +name: django-debug-toolbar +version: 6.2.0 +download_url: https://files.pythonhosted.org/packages/88/04/e24611299a5ee0d4edfacf935b09cfb7d5d9cb653bd7b7883c3b43a6f90d/django_debug_toolbar-6.2.0-py3-none-any.whl +package_url: pkg:pypi/django-debug-toolbar@6.2.0 +license_expression: bsd-new +copyright: Copyright django-debug-toolbar project contributors +attribute: yes +checksum_md5: 5cb76c9000f250b297ee58875730c17d +checksum_sha1: 83f35096201654e73f19a8e5ed8bda9257a76ddc +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE diff --git a/thirdparty/dist/django_otp-1.7.0-py3-none-any.whl.ABOUT b/thirdparty/dist/django_otp-1.7.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..f3c482f7 --- /dev/null +++ b/thirdparty/dist/django_otp-1.7.0-py3-none-any.whl.ABOUT @@ -0,0 +1,13 @@ +about_resource: django_otp-1.7.0-py3-none-any.whl +name: django-otp +version: 1.7.0 +download_url: https://files.pythonhosted.org/packages/9c/f0/75ee6cdcf916b7c67dffa87aecdd173e4d68e456839dd53b9313e9cc9201/django_otp-1.7.0-py3-none-any.whl +package_url: pkg:pypi/django-otp@1.7.0 +license_expression: unlicense +copyright: Copyright django-otp project contributors +checksum_md5: dc77d137ff8501a161a02b3710f7b9c4 +checksum_sha1: dd03964929aaf7bc89a2b9f8a3410e96c66cd958 +licenses: + - key: unlicense + name: Unlicense + file: unlicense.LICENSE diff --git a/thirdparty/dist/django_rq-3.2.2-py3-none-any.whl.ABOUT b/thirdparty/dist/django_rq-3.2.2-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..80db80c3 --- /dev/null +++ b/thirdparty/dist/django_rq-3.2.2-py3-none-any.whl.ABOUT @@ -0,0 +1,17 @@ +about_resource: django_rq-3.2.2-py3-none-any.whl +name: django-rq +version: 3.2.2 +download_url: https://files.pythonhosted.org/packages/e8/dc/c6c9b193b8d66b252206e77d6cfdf93724e48ebe5e86e6d70542de9064d5/django_rq-3.2.2-py3-none-any.whl +package_url: pkg:pypi/django-rq@3.2.2 +license_expression: mit AND unknown-license-reference +copyright: Copyright django-rq project contributors +attribute: yes +checksum_md5: d7f95462e65e3d06d6434ef2601002be +checksum_sha1: 8444fa3da4151ed48765630b1f857948ae221b8a +licenses: + - key: mit + name: MIT License + file: mit.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/drf_yasg-1.21.14-py3-none-any.whl.ABOUT b/thirdparty/dist/drf_yasg-1.21.14-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..d7c03750 --- /dev/null +++ b/thirdparty/dist/drf_yasg-1.21.14-py3-none-any.whl.ABOUT @@ -0,0 +1,17 @@ +about_resource: drf_yasg-1.21.14-py3-none-any.whl +name: drf-yasg +version: 1.21.14 +download_url: https://files.pythonhosted.org/packages/bb/de/61880040534036044572225c485b0a4adc99b4c92e3eed3e5741b31674fd/drf_yasg-1.21.14-py3-none-any.whl +package_url: pkg:pypi/drf-yasg@1.21.14 +license_expression: bsd-new AND unknown-license-reference +copyright: Copyright drf-yasg project contributors +attribute: yes +checksum_md5: e04c18879948bfa1f278046d55ab273e +checksum_sha1: 8f20897ed76a47ba419560dd807f72dd15ee391d +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/gunicorn-25.0.3-py3-none-any.whl.ABOUT b/thirdparty/dist/gunicorn-25.0.3-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..3d5fe268 --- /dev/null +++ b/thirdparty/dist/gunicorn-25.0.3-py3-none-any.whl.ABOUT @@ -0,0 +1,17 @@ +about_resource: gunicorn-25.0.3-py3-none-any.whl +name: gunicorn +version: 25.0.3 +download_url: https://files.pythonhosted.org/packages/5e/84/117f39896ded517149be72d16c02252885690e9b0d1b84281944928f61aa/gunicorn-25.0.3-py3-none-any.whl +package_url: pkg:pypi/gunicorn@25.0.3 +license_expression: mit AND unknown-license-reference +copyright: Copyright gunicorn project contributors +attribute: yes +checksum_md5: 05f4b3c61cc31c26de7f4604e00b367c +checksum_sha1: 272e749a03817f7ecfee8fb7b1d6b86833229fcb +licenses: + - key: mit + name: MIT License + file: mit.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/jsonschema-4.26.0-py3-none-any.whl.ABOUT b/thirdparty/dist/jsonschema-4.26.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..03de1bb9 --- /dev/null +++ b/thirdparty/dist/jsonschema-4.26.0-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: jsonschema-4.26.0-py3-none-any.whl +name: jsonschema +version: 4.26.0 +download_url: https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl +package_url: pkg:pypi/jsonschema@4.26.0 +license_expression: mit +copyright: Copyright jsonschema project contributors +attribute: yes +checksum_md5: 2b7e04c1ca5e5c280087b9765d9f3970 +checksum_sha1: 6930315c45b54c0e68d7a3d039a533c8b8e7b3f1 +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/markdown-3.10.2-py3-none-any.whl.ABOUT b/thirdparty/dist/markdown-3.10.2-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..6c17f6a6 --- /dev/null +++ b/thirdparty/dist/markdown-3.10.2-py3-none-any.whl.ABOUT @@ -0,0 +1,17 @@ +about_resource: markdown-3.10.2-py3-none-any.whl +name: markdown +version: 3.10.2 +download_url: https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl +package_url: pkg:pypi/markdown@3.10.2 +license_expression: bsd-new AND unknown-license-reference +copyright: Copyright markdown project contributors +attribute: yes +checksum_md5: b8d54dbb01a69e80e57d72abdad42793 +checksum_sha1: 083b18be364835ca6be0be0e2a1263f219483f43 +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/maturin-1.11.5.tar.gz.ABOUT b/thirdparty/dist/maturin-1.11.5.tar.gz.ABOUT new file mode 100644 index 00000000..77d1de10 --- /dev/null +++ b/thirdparty/dist/maturin-1.11.5.tar.gz.ABOUT @@ -0,0 +1,301 @@ +about_resource: maturin-1.11.5.tar.gz +name: maturin +version: 1.11.5 +download_url: https://files.pythonhosted.org/packages/a4/84/bfed8cc10e2d8b6656cf0f0ca6609218e6fcb45a62929f5094e1063570f7/maturin-1.11.5.tar.gz +description: | + Build and publish crates with pyo3, cffi and uniffi bindings as well as rust binaries as python packages + # Maturin + + _formerly pyo3-pack_ + + [![Maturin User Guide](https://img.shields.io/badge/user-guide-brightgreen?logo=readthedocs&style=flat-square)](https://maturin.rs) + [![Crates.io](https://img.shields.io/crates/v/maturin.svg?logo=rust&style=flat-square)](https://crates.io/crates/maturin) + [![PyPI](https://img.shields.io/pypi/v/maturin.svg?logo=python&style=flat-square)](https://pypi.org/project/maturin) + [![discord server](https://img.shields.io/discord/1209263839632424990?logo=discord&style=flat-square)](https://discord.gg/33kcChzH7f) + + Build and publish crates with [pyo3, cffi and uniffi bindings](https://maturin.rs/bindings) as well as rust binaries as python packages with minimal configuration. + It supports building wheels for python 3.8+ on Windows, Linux, macOS and FreeBSD, can upload them to [pypi](https://pypi.org/) and has basic PyPy and GraalPy support. + + Check out the [User Guide](https://maturin.rs/)! + + ## Usage + + You can either download binaries from the [latest release](https://github.com/PyO3/maturin/releases/latest) or install it with [pipx](https://pypa.github.io/pipx/) or [uv](https://github.com/astral-sh/uv): + + ```shell + # pipx + pipx install maturin + # uv + uv tool install maturin + ``` + + > [!NOTE] + > + > `pip install maturin` should also work if you don't want to use pipx. + + There are three main commands: + + - `maturin new` creates a new cargo project with maturin configured. + - `maturin build` builds the wheels and stores them in a folder (`target/wheels` by default), but doesn't upload them. It's recommended to publish packages with [uv](https://github.com/astral-sh/uv) using `uv publish`. + - `maturin develop` builds the crate and installs it as a python module directly in the current virtualenv. Note that while `maturin develop` is faster, it doesn't support all the feature that running `pip install` after `maturin build` supports. + + maturin doesn't need extra configuration files and doesn't clash with an existing setuptools-rust configuration. + You can even integrate it with testing tools such as [tox](https://tox.readthedocs.io/en/latest/). + There are examples for the different bindings in the `test-crates` folder. + + The name of the package will be the name of the cargo project, i.e. the name field in the `[package]` section of `Cargo.toml`. + The name of the module, which you are using when importing, will be the `name` value in the `[lib]` section (which defaults to the name of the package). For binaries, it's simply the name of the binary generated by cargo. + + When using `maturin build` and `maturin develop` commands, you can compile a performance-optimized program by adding the `-r` or `--release` flag. + + ## Python packaging basics + + Python packages come in two formats: + A built form called wheel and source distributions (sdist), both of which are archives. + A wheel can be compatible with any python version, interpreter (cpython and pypy, mainly), operating system and hardware architecture (for pure python wheels), + can be limited to a specific platform and architecture (e.g. when using ctypes or cffi) or to a specific python interpreter and version on a specific architecture and operating system (e.g. with pyo3). + + When using `pip install` on a package, pip tries to find a matching wheel and install that. If it doesn't find one, it downloads the source distribution and builds a wheel for the current platform, + which requires the right compilers to be installed. Installing a wheel is much faster than installing a source distribution as building wheels is generally slow. + + When you publish a package to be installable with `pip install`, you upload it to [pypi](https://pypi.org/), the official package repository. + For testing, you can use [test pypi](https://test.pypi.org/) instead, which you can use with `pip install --index-url https://test.pypi.org/simple/`. + Note that for [publishing for linux](#manylinux-and-auditwheel), you need to use the manylinux docker container or zig, while for publishing from your repository you can use the [PyO3/maturin-action](https://github.com/PyO3/maturin-action) github action. + + ## Mixed rust/python projects + + To create a mixed rust/python project, create a folder with your module name (i.e. `lib.name` in Cargo.toml) next to your Cargo.toml and add your python sources there: + + ``` + my-project + ├── Cargo.toml + ├── my_project + │   ├── __init__.py + │   └── bar.py + ├── pyproject.toml + ├── README.md + └── src +    └── lib.rs + ``` + + You can specify a different python source directory in `pyproject.toml` by setting `tool.maturin.python-source`, for example + + **pyproject.toml** + + ```toml + [tool.maturin] + python-source = "python" + module-name = "my_project._lib_name" + ``` + + then the project structure would look like this: + + ``` + my-project + ├── Cargo.toml + ├── python + │ └── my_project + │ ├── __init__.py + │ └── bar.py + ├── pyproject.toml + ├── README.md + └── src +    └── lib.rs + ``` + + > [!NOTE] + > + > This structure is recommended to avoid [a common `ImportError` pitfall](https://github.com/PyO3/maturin/issues/490) + + maturin will add the native extension as a module in your python folder. When using develop, maturin will copy the native library and for cffi also the glue code to your python folder. You should add those files to your gitignore. + + With cffi you can do `from .my_project import lib` and then use `lib.my_native_function`, with pyo3 you can directly `from .my_project import my_native_function`. + + Example layout with pyo3 after `maturin develop`: + + ``` + my-project + ├── Cargo.toml + ├── my_project + │   ├── __init__.py + │   ├── bar.py + │   └── _lib_name.cpython-36m-x86_64-linux-gnu.so + ├── README.md + └── src +    └── lib.rs + ``` + + When doing this also be sure to set the module name in your code to match the last part of `module-name` (don't include the package path): + + ```rust + #[pymodule] + #[pyo3(name="_lib_name")] + fn my_lib_name(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add_class::()?; + Ok(()) + } + ``` + + ## Python metadata + + maturin supports [PEP 621](https://www.python.org/dev/peps/pep-0621/), you can specify python package metadata in `pyproject.toml`. + maturin merges metadata from `Cargo.toml` and `pyproject.toml`, `pyproject.toml` takes precedence over `Cargo.toml`. + + To specify python dependencies, add a list `dependencies` in a `[project]` section in the `pyproject.toml`. This list is equivalent to `install_requires` in setuptools: + + ```toml + [project] + name = "my-project" + dependencies = ["flask~=1.1.0", "toml>=0.10.2,<0.11.0"] + ``` + + You can add so called console scripts, which are shell commands that execute some function in your program in the `[project.scripts]` section. + The keys are the script names while the values are the path to the function in the format `some.module.path:class.function`, where the `class` part is optional. The function is called with no arguments. Example: + + ```toml + [project.scripts] + get_42 = "my_project:DummyClass.get_42" + ``` + + You can also specify [trove classifiers](https://pypi.org/classifiers/) in your `pyproject.toml` under `project.classifiers`: + + ```toml + [project] + name = "my-project" + classifiers = ["Programming Language :: Python"] + ``` + + ## Source distribution + + maturin supports building through `pyproject.toml`. To use it, create a `pyproject.toml` next to your `Cargo.toml` with the following content: + + ```toml + [build-system] + requires = ["maturin>=1.0,<2.0"] + build-backend = "maturin" + ``` + + If a `pyproject.toml` with a `[build-system]` entry is present, maturin can build a source distribution of your package when `--sdist` is specified. + The source distribution will contain the same files as `cargo package`. To only build a source distribution, pass `--interpreter` without any values. + + You can then e.g. install your package with `pip install .`. With `pip install . -v` you can see the output of cargo and maturin. + + You can use the options `compatibility`, `skip-auditwheel`, `bindings`, `strip` and common Cargo build options such as `features` under `[tool.maturin]` the same way you would when running maturin directly. + The `bindings` key is required for cffi and bin projects as those can't be automatically detected. Currently, all builds are in release mode (see [this thread](https://discuss.python.org/t/pep-517-debug-vs-release-builds/1924) for details). + + For a non-manylinux build with cffi bindings you could use the following: + + ```toml + [build-system] + requires = ["maturin>=1.0,<2.0"] + build-backend = "maturin" + + [tool.maturin] + bindings = "cffi" + compatibility = "linux" + ``` + + `manylinux` option is also accepted as an alias of `compatibility` for backward compatibility with old version of maturin. + + To include arbitrary files in the sdist for use during compilation specify `include` as an array of `path` globs with `format` set to `sdist`: + + ```toml + [tool.maturin] + include = [{ path = "path/**/*", format = "sdist" }] + ``` + + There's a `maturin sdist` command for only building a source distribution as workaround for [pypa/pip#6041](https://github.com/pypa/pip/issues/6041). + + ## Manylinux and auditwheel + + For portability reasons, native python modules on linux must only dynamically link a set of very few libraries which are installed basically everywhere, hence the name manylinux. + The pypa offers special docker images and a tool called [auditwheel](https://github.com/pypa/auditwheel/) to ensure compliance with the [manylinux rules](https://peps.python.org/pep-0599/#the-manylinux2014-policy). + If you want to publish widely usable wheels for linux pypi, **you need to use a manylinux docker image or build with zig**. + + The Rust compiler since version 1.64 [requires at least glibc 2.17](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html), so you need to use at least manylinux2014. + For publishing, we recommend enforcing the same manylinux version as the image with the manylinux flag, e.g. use `--manylinux 2014` if you are building in `quay.io/pypa/manylinux2014_x86_64`. + The [PyO3/maturin-action](https://github.com/PyO3/maturin-action) github action already takes care of this if you set e.g. `manylinux: 2014`. + + maturin contains a reimplementation of auditwheel automatically checks the generated library and gives the wheel the proper platform tag. + If your system's glibc is too new or you link other shared libraries, it will assign the `linux` tag. + You can also manually disable those checks and directly use native linux target with `--manylinux off`. + + For full manylinux compliance you need to compile in a CentOS docker container. The [pyo3/maturin](https://ghcr.io/pyo3/maturin) image is based on the manylinux2014 image, + and passes arguments to the `maturin` binary. You can use it like this: + + ``` + docker run --rm -v $(pwd):/io ghcr.io/pyo3/maturin build --release # or other maturin arguments + ``` + + Note that this image is very basic and only contains python, maturin and stable rust. If you need additional tools, you can run commands inside the manylinux container. + See [konstin/complex-manylinux-maturin-docker](https://github.com/konstin/complex-manylinux-maturin-docker) for a small educational example or [nanoporetech/fast-ctc-decode](https://github.com/nanoporetech/fast-ctc-decode/blob/b226ea0f2b2f4f474eff47349703d57d2ea4801b/.github/workflows/publish.yml) for a real world setup. + + maturin itself is manylinux compliant when compiled for the musl target. + + ## Examples + + - [agg-python-bindings](https://pypi.org/project/agg-python-bindings) - A Python Library that binds to Asciinema Agg terminal record renderer and Avt terminal emulator + - [ballista-python](https://github.com/apache/arrow-ballista-python) - A Python library that binds to Apache Arrow distributed query engine Ballista + - [bleuscore](https://github.com/shenxiangzhuang/bleuscore) - A BLEU score calculation library, written in pure Rust + - [chardetng-py](https://github.com/john-parton/chardetng-py) - Python binding for the chardetng character encoding detector. + - [connector-x](https://github.com/sfu-db/connector-x/tree/main/connectorx-python) - ConnectorX enables you to load data from databases into Python in the fastest and most memory efficient way + - [datafusion-python](https://github.com/apache/arrow-datafusion-python) - a Python library that binds to Apache Arrow in-memory query engine DataFusion + - [deltalake-python](https://github.com/delta-io/delta-rs/tree/main/python) - Native Delta Lake Python binding based on delta-rs with Pandas integration + - [opendal](https://github.com/apache/incubator-opendal/tree/main/bindings/python) - OpenDAL Python Binding to access data freely + - [orjson](https://github.com/ijl/orjson) - A fast, correct JSON library for Python + - [polars](https://github.com/pola-rs/polars/tree/master/py-polars) - Fast multi-threaded DataFrame library in Rust | Python | Node.js + - [pydantic-core](https://github.com/pydantic/pydantic-core) - Core validation logic for pydantic written in Rust + - [pyrus-cramjam](https://github.com/milesgranger/pyrus-cramjam) - Thin Python wrapper to de/compression algorithms in Rust + - [pyxel](https://github.com/kitao/pyxel) - A retro game engine for Python + - [roapi](https://github.com/roapi/roapi) - ROAPI automatically spins up read-only APIs for static datasets without requiring you to write a single line of code + - [robyn](https://github.com/sansyrox/robyn) - A fast and extensible async python web server with a Rust runtime + - [ruff](https://github.com/charliermarsh/ruff) - An extremely fast Python linter, written in Rust + - [rnet](https://github.com/0x676e67/rnet) - Asynchronous Python HTTP Client with Black Magic + - [rustpy-xlsxwriter](https://github.com/rahmadafandi/rustpy-xlsxwriter): A high-performance Python library for generating Excel files, utilizing the [rust_xlsxwriter](https://github.com/jmcnamara/rust_xlsxwriter) crate for efficient data handling. + - [tantivy-py](https://github.com/quickwit-oss/tantivy-py) - Python bindings for Tantivy + - [tpchgen-cli](https://github.com/clflushopt/tpchgen-rs/tree/main/tpchgen-cli) - Python CLI binding for `tpchgen`, a blazing fast TPC-H benchmark data generator built in pure Rust with zero dependencies. + - [watchfiles](https://github.com/samuelcolvin/watchfiles) - Simple, modern and high performance file watching and code reload in python + - [wonnx](https://github.com/webonnx/wonnx/tree/master/wonnx-py) - Wonnx is a GPU-accelerated ONNX inference run-time written 100% in Rust + + ## Contributing + + Everyone is welcomed to contribute to maturin! There are many ways to support the project, such as: + + - help maturin users with issues on GitHub and Gitter + - improve documentation + - write features and bugfixes + - publish blogs and examples of how to use maturin + + Our [contributing notes](https://github.com/PyO3/maturin/blob/main/guide/src/contributing.md) have more resources if you wish to volunteer time for maturin and are searching where to start. + + If you don't have time to contribute yourself but still wish to support the project's future success, some of our maintainers have GitHub sponsorship pages: + + - [messense](https://github.com/sponsors/messense) + + ## License + + Licensed under either of: + + - Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/PyO3/maturin/blob/main/license-apache) or http://www.apache.org/licenses/LICENSE-2.0) + - MIT license ([LICENSE-MIT](https://github.com/PyO3/maturin/blob/main/license-mit) or http://opensource.org/licenses/MIT) + + at your option. +homepage_url: https://github.com/pyo3/maturin +package_url: pkg:pypi/maturin@1.11.5 +license_expression: (unknown-license-reference AND mit AND apache-2.0 AND (mit OR apache-2.0)) + AND (apache-2.0 AND mit) +copyright: Copyright konstin +attribute: yes +track_changes: yes +checksum_md5: f335b690a812734f64b00336c865a290 +checksum_sha1: 920f79f993b3891d06a285d5297a542d3a638696 +licenses: + - key: apache-2.0 + name: Apache License 2.0 + file: apache-2.0.LICENSE + - key: mit + name: MIT License + file: mit.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/packaging-26.0-py3-none-any.whl.ABOUT b/thirdparty/dist/packaging-26.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..84cbadc5 --- /dev/null +++ b/thirdparty/dist/packaging-26.0-py3-none-any.whl.ABOUT @@ -0,0 +1,24 @@ +about_resource: packaging-26.0-py3-none-any.whl +name: packaging +version: '26.0' +download_url: https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl +package_url: pkg:pypi/packaging@26.0 +license_expression: apache-2.0 AND bsd-new AND bsd-simplified AND unknown-license-reference +copyright: Copyright packaging project contributors +attribute: yes +track_changes: yes +checksum_md5: 6612a2b4cddb48af24b6de0de620e353 +checksum_sha1: 4a6dc6fe247bea77685d5f010a10607105910fec +licenses: + - key: apache-2.0 + name: Apache License 2.0 + file: apache-2.0.LICENSE + - key: bsd-simplified + name: BSD-2-Clause + file: bsd-simplified.LICENSE + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/pip-26.0.1-py3-none-any.whl.ABOUT b/thirdparty/dist/pip-26.0.1-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..d772f7d0 --- /dev/null +++ b/thirdparty/dist/pip-26.0.1-py3-none-any.whl.ABOUT @@ -0,0 +1,21 @@ +about_resource: pip-26.0.1-py3-none-any.whl +name: pip +version: 26.0.1 +download_url: https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl +package_url: pkg:pypi/pip@26.0.1 +license_expression: apache-2.0 AND bsd-new AND unknown-license-reference +copyright: Copyright pip project contributors +attribute: yes +track_changes: yes +checksum_md5: 081fecbf1d611c25d80665627988f83f +checksum_sha1: 836c691bd92ebf1950cdf46c17e4afc90feb3f26 +licenses: + - key: apache-2.0 + name: Apache License 2.0 + file: apache-2.0.LICENSE + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/psycopg-3.3.2-py3-none-any.whl.ABOUT b/thirdparty/dist/psycopg-3.3.2-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..0ce6e54f --- /dev/null +++ b/thirdparty/dist/psycopg-3.3.2-py3-none-any.whl.ABOUT @@ -0,0 +1,19 @@ +about_resource: psycopg-3.3.2-py3-none-any.whl +name: psycopg +version: 3.3.2 +download_url: https://files.pythonhosted.org/packages/8c/51/2779ccdf9305981a06b21a6b27e8547c948d85c41c76ff434192784a4c93/psycopg-3.3.2-py3-none-any.whl +package_url: pkg:pypi/psycopg@3.3.2 +license_expression: lgpl-3.0 AND unknown-license-reference +copyright: Copyright The Psycopg Team +redistribute: yes +attribute: yes +track_changes: yes +checksum_md5: 4be01621ab709b77802453c528605dd3 +checksum_sha1: b06f35da894197c3218e3fee270b5023b64d3615 +licenses: + - key: lgpl-3.0 + name: GNU Lesser General Public License 3.0 + file: lgpl-3.0.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/pyasn1-0.6.2-py3-none-any.whl.ABOUT b/thirdparty/dist/pyasn1-0.6.2-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..decb7dc7 --- /dev/null +++ b/thirdparty/dist/pyasn1-0.6.2-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: pyasn1-0.6.2-py3-none-any.whl +name: pyasn1 +version: 0.6.2 +download_url: https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl +package_url: pkg:pypi/pyasn1@0.6.2 +license_expression: bsd-simplified +copyright: Copyright Ilya Etingof +attribute: yes +checksum_md5: cba2eaaeb038874e49a2b38564335ab1 +checksum_sha1: 0942be2a44f5db2de11d5311ee9d14aac6a4695f +licenses: + - key: bsd-simplified + name: BSD-2-Clause + file: bsd-simplified.LICENSE diff --git a/thirdparty/dist/pydantic-2.12.5-py3-none-any.whl.ABOUT b/thirdparty/dist/pydantic-2.12.5-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..9666fb8e --- /dev/null +++ b/thirdparty/dist/pydantic-2.12.5-py3-none-any.whl.ABOUT @@ -0,0 +1,17 @@ +about_resource: pydantic-2.12.5-py3-none-any.whl +name: pydantic +version: 2.12.5 +download_url: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl +package_url: pkg:pypi/pydantic@2.12.5 +license_expression: mit AND unknown-license-reference +copyright: Copyright pydantic project contributors +attribute: yes +checksum_md5: 0857f9b85480a4883a7ce20c8b07a025 +checksum_sha1: 1ae214c5e185c89b0ea88888b5b6d6f5badeef6d +licenses: + - key: mit + name: MIT License + file: mit.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/pyjwt-2.11.0-py3-none-any.whl.ABOUT b/thirdparty/dist/pyjwt-2.11.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..e6869e2f --- /dev/null +++ b/thirdparty/dist/pyjwt-2.11.0-py3-none-any.whl.ABOUT @@ -0,0 +1,13 @@ +about_resource: pyjwt-2.11.0-py3-none-any.whl +name: pyjwt +version: 2.11.0 +download_url: https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl +package_url: pkg:pypi/pyjwt@2.11.0 +license_expression: unknown-license-reference +copyright: Copyright pyjwt project contributors +checksum_md5: c1ffbbdb1d2dc33488b02e9ee916f59e +checksum_sha1: 7f86d797400444d37cbb5bc02df9022924ea3f5f +licenses: + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/pyparsing-3.3.2-py3-none-any.whl.ABOUT b/thirdparty/dist/pyparsing-3.3.2-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..1f47fb24 --- /dev/null +++ b/thirdparty/dist/pyparsing-3.3.2-py3-none-any.whl.ABOUT @@ -0,0 +1,21 @@ +about_resource: pyparsing-3.3.2-py3-none-any.whl +name: pyparsing +version: 3.3.2 +download_url: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl +package_url: pkg:pypi/pyparsing@3.3.2 +license_expression: mit AND python AND unknown-license-reference +copyright: Copyright pyparsing project contributors +attribute: yes +track_changes: yes +checksum_md5: 6c5959914bae3b31af7f20ef97c4d08a +checksum_sha1: 54dd06211446119d58e8b6b67ad7699cf5d8d8e2 +licenses: + - key: mit + name: MIT License + file: mit.LICENSE + - key: python + name: Python Software Foundation License v2 + file: python.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/redis-7.1.1-py3-none-any.whl.ABOUT b/thirdparty/dist/redis-7.1.1-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..bba9c0be --- /dev/null +++ b/thirdparty/dist/redis-7.1.1-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: redis-7.1.1-py3-none-any.whl +name: redis +version: 7.1.1 +download_url: https://files.pythonhosted.org/packages/29/55/1de1d812ba1481fa4b37fb03b4eec0fcb71b6a0d44c04ea3482eb017600f/redis-7.1.1-py3-none-any.whl +package_url: pkg:pypi/redis@7.1.1 +license_expression: mit +copyright: Copyright redis project contributors +attribute: yes +checksum_md5: 225d6350b6919bd164babde57c78cdcb +checksum_sha1: ec81feda2c893973ef1ea96ddc555e61699b9f30 +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/referencing-0.37.0-py3-none-any.whl.ABOUT b/thirdparty/dist/referencing-0.37.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..fbefef74 --- /dev/null +++ b/thirdparty/dist/referencing-0.37.0-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: referencing-0.37.0-py3-none-any.whl +name: referencing +version: 0.37.0 +download_url: https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl +package_url: pkg:pypi/referencing@0.37.0 +license_expression: mit +copyright: Copyright referencing project contributors +attribute: yes +checksum_md5: 0be0d0a9f3691df1a295018982a60ce9 +checksum_sha1: d38a45a8772a997bf4e14a52bc1745e6a8458f68 +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/rpds_py-0.30.0.tar.gz.ABOUT b/thirdparty/dist/rpds_py-0.30.0.tar.gz.ABOUT new file mode 100644 index 00000000..049387cb --- /dev/null +++ b/thirdparty/dist/rpds_py-0.30.0.tar.gz.ABOUT @@ -0,0 +1,85 @@ +about_resource: rpds_py-0.30.0.tar.gz +name: rpds-py +version: 0.30.0 +download_url: https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz +description: | + Python bindings to Rust's persistent data structures (rpds) + =========== + ``rpds.py`` + =========== + + |PyPI| |Pythons| |CI| + + .. |PyPI| image:: https://img.shields.io/pypi/v/rpds-py.svg + :alt: PyPI version + :target: https://pypi.org/project/rpds-py/ + + .. |Pythons| image:: https://img.shields.io/pypi/pyversions/rpds-py.svg + :alt: Supported Python versions + :target: https://pypi.org/project/rpds-py/ + + .. |CI| image:: https://github.com/crate-py/rpds/workflows/CI/badge.svg + :alt: Build status + :target: https://github.com/crate-py/rpds/actions?query=workflow%3ACI + + .. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat + :alt: ReadTheDocs status + :target: https://referencing.readthedocs.io/en/stable/ + + + Python bindings to the `Rust rpds crate `_ for persistent data structures. + + What's here is quite minimal (in transparency, it was written initially to support replacing ``pyrsistent`` in the `referencing library `_). + If you see something missing (which is very likely), a PR is definitely welcome to add it. + + Installation + ------------ + + The distribution on PyPI is named ``rpds.py`` (equivalently ``rpds-py``), and thus can be installed via e.g.: + + .. code:: sh + + $ pip install rpds-py + + Note that if you install ``rpds-py`` from source, you will need a Rust toolchain installed, as it is a build-time dependency. + An example of how to do so in a ``Dockerfile`` can be found `here `_. + + If you believe you are on a common platform which should have wheels built (i.e. and not need to compile from source), feel free to file an issue or pull request modifying the GitHub action used here to build wheels via ``maturin``. + + Usage + ----- + + Methods in general are named similarly to their ``rpds`` counterparts (rather than ``pyrsistent``\ 's conventions, though probably a full drop-in ``pyrsistent``\ -compatible wrapper module is a good addition at some point). + + .. code:: python + + >>> from rpds import HashTrieMap, HashTrieSet, List + + >>> m = HashTrieMap({"foo": "bar", "baz": "quux"}) + >>> m.insert("spam", 37) == HashTrieMap({"foo": "bar", "baz": "quux", "spam": 37}) + True + >>> m.remove("foo") == HashTrieMap({"baz": "quux"}) + True + + >>> s = HashTrieSet({"foo", "bar", "baz", "quux"}) + >>> s.insert("spam") == HashTrieSet({"foo", "bar", "baz", "quux", "spam"}) + True + >>> s.remove("foo") == HashTrieSet({"bar", "baz", "quux"}) + True + + >>> L = List([1, 3, 5]) + >>> L.push_front(-1) == List([-1, 1, 3, 5]) + True + >>> L.rest == List([3, 5]) + True +homepage_url: https://github.com/crate-py/rpds +package_url: pkg:pypi/rpds-py@0.30.0 +license_expression: mit +copyright: Copyright Julian Berman +attribute: yes +checksum_md5: 9a598f792d702fd0547a36ccc999ef91 +checksum_sha1: 5fdab25b519123e7e53e5f2629a597b9921f129c +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/ruff-0.15.0.tar.gz.ABOUT b/thirdparty/dist/ruff-0.15.0.tar.gz.ABOUT new file mode 100644 index 00000000..046c8ec9 --- /dev/null +++ b/thirdparty/dist/ruff-0.15.0.tar.gz.ABOUT @@ -0,0 +1,569 @@ +about_resource: ruff-0.15.0.tar.gz +name: ruff +version: 0.15.0 +download_url: https://files.pythonhosted.org/packages/c8/39/5cee96809fbca590abea6b46c6d1c586b49663d1d2830a751cc8fc42c666/ruff-0.15.0.tar.gz +description: | + + + # Ruff + + [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) + [![image](https://img.shields.io/pypi/v/ruff.svg)](https://pypi.python.org/pypi/ruff) + [![image](https://img.shields.io/pypi/l/ruff.svg)](https://github.com/astral-sh/ruff/blob/main/LICENSE) + [![image](https://img.shields.io/pypi/pyversions/ruff.svg)](https://pypi.python.org/pypi/ruff) + [![Actions status](https://github.com/astral-sh/ruff/workflows/CI/badge.svg)](https://github.com/astral-sh/ruff/actions) + [![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?logo=discord&logoColor=white)](https://discord.com/invite/astral-sh) + + [**Docs**](https://docs.astral.sh/ruff/) | [**Playground**](https://play.ruff.rs/) + + An extremely fast Python linter and code formatter, written in Rust. + +

    + Shows a bar chart with benchmark results. +

    + +

    + Linting the CPython codebase from scratch. +

    + + - ⚡️ 10-100x faster than existing linters (like Flake8) and formatters (like Black) + - 🐍 Installable via `pip` + - 🛠️ `pyproject.toml` support + - 🤝 Python 3.14 compatibility + - ⚖️ Drop-in parity with [Flake8](https://docs.astral.sh/ruff/faq/#how-does-ruffs-linter-compare-to-flake8), isort, and [Black](https://docs.astral.sh/ruff/faq/#how-does-ruffs-formatter-compare-to-black) + - 📦 Built-in caching, to avoid re-analyzing unchanged files + - 🔧 Fix support, for automatic error correction (e.g., automatically remove unused imports) + - 📏 Over [800 built-in rules](https://docs.astral.sh/ruff/rules/), with native re-implementations + of popular Flake8 plugins, like flake8-bugbear + - ⌨️ First-party [editor integrations](https://docs.astral.sh/ruff/editors) for [VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://docs.astral.sh/ruff/editors/setup) + - 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://docs.astral.sh/ruff/configuration/#config-file-discovery) + + Ruff aims to be orders of magnitude faster than alternative tools while integrating more + functionality behind a single, common interface. + + Ruff can be used to replace [Flake8](https://pypi.org/project/flake8/) (plus dozens of plugins), + [Black](https://github.com/psf/black), [isort](https://pypi.org/project/isort/), + [pydocstyle](https://pypi.org/project/pydocstyle/), [pyupgrade](https://pypi.org/project/pyupgrade/), + [autoflake](https://pypi.org/project/autoflake/), and more, all while executing tens or hundreds of + times faster than any individual tool. + + Ruff is extremely actively developed and used in major open-source projects like: + + - [Apache Airflow](https://github.com/apache/airflow) + - [Apache Superset](https://github.com/apache/superset) + - [FastAPI](https://github.com/tiangolo/fastapi) + - [Hugging Face](https://github.com/huggingface/transformers) + - [Pandas](https://github.com/pandas-dev/pandas) + - [SciPy](https://github.com/scipy/scipy) + + ...and [many more](#whos-using-ruff). + + Ruff is backed by [Astral](https://astral.sh), the creators of + [uv](https://github.com/astral-sh/uv) and [ty](https://github.com/astral-sh/ty). + + Read the [launch + post](https://astral.sh/blog/announcing-astral-the-company-behind-ruff), or the + original [project + announcement](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster). + + ## Testimonials + + [**Sebastián Ramírez**](https://twitter.com/tiangolo/status/1591912354882764802), creator + of [FastAPI](https://github.com/tiangolo/fastapi): + + > Ruff is so fast that sometimes I add an intentional bug in the code just to confirm it's actually + > running and checking the code. + + [**Nick Schrock**](https://twitter.com/schrockn/status/1612615862904827904), founder of [Elementl](https://www.elementl.com/), + co-creator of [GraphQL](https://graphql.org/): + + > Why is Ruff a gamechanger? Primarily because it is nearly 1000x faster. Literally. Not a typo. On + > our largest module (dagster itself, 250k LOC) pylint takes about 2.5 minutes, parallelized across 4 + > cores on my M1. Running ruff against our _entire_ codebase takes .4 seconds. + + [**Bryan Van de Ven**](https://github.com/bokeh/bokeh/pull/12605), co-creator + of [Bokeh](https://github.com/bokeh/bokeh/), original author + of [Conda](https://docs.conda.io/en/latest/): + + > Ruff is ~150-200x faster than flake8 on my machine, scanning the whole repo takes ~0.2s instead of + > ~20s. This is an enormous quality of life improvement for local dev. It's fast enough that I added + > it as an actual commit hook, which is terrific. + + [**Timothy Crosley**](https://twitter.com/timothycrosley/status/1606420868514877440), + creator of [isort](https://github.com/PyCQA/isort): + + > Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe + > it was working till I intentionally introduced some errors. + + [**Tim Abbott**](https://github.com/zulip/zulip/pull/23431#issuecomment-1302557034), lead developer of [Zulip](https://github.com/zulip/zulip) (also [here](https://github.com/astral-sh/ruff/issues/465#issuecomment-1317400028)): + + > This is just ridiculously fast... `ruff` is amazing. + + + + ## Table of Contents + + For more, see the [documentation](https://docs.astral.sh/ruff/). + + 1. [Getting Started](#getting-started) + 1. [Configuration](#configuration) + 1. [Rules](#rules) + 1. [Contributing](#contributing) + 1. [Support](#support) + 1. [Acknowledgements](#acknowledgements) + 1. [Who's Using Ruff?](#whos-using-ruff) + 1. [License](#license) + + ## Getting Started + + For more, see the [documentation](https://docs.astral.sh/ruff/). + + ### Installation + + Ruff is available as [`ruff`](https://pypi.org/project/ruff/) on PyPI. + + Invoke Ruff directly with [`uvx`](https://docs.astral.sh/uv/): + + ```shell + uvx ruff check # Lint all files in the current directory. + uvx ruff format # Format all files in the current directory. + ``` + + Or install Ruff with `uv` (recommended), `pip`, or `pipx`: + + ```shell + # With uv. + uv tool install ruff@latest # Install Ruff globally. + uv add --dev ruff # Or add Ruff to your project. + + # With pip. + pip install ruff + + # With pipx. + pipx install ruff + ``` + + Starting with version `0.5.0`, Ruff can be installed with our standalone installers: + + ```shell + # On macOS and Linux. + curl -LsSf https://astral.sh/ruff/install.sh | sh + + # On Windows. + powershell -c "irm https://astral.sh/ruff/install.ps1 | iex" + + # For a specific version. + curl -LsSf https://astral.sh/ruff/0.15.0/install.sh | sh + powershell -c "irm https://astral.sh/ruff/0.15.0/install.ps1 | iex" + ``` + + You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff), + and with [a variety of other package managers](https://docs.astral.sh/ruff/installation/). + + ### Usage + + To run Ruff as a linter, try any of the following: + + ```shell + ruff check # Lint all files in the current directory (and any subdirectories). + ruff check path/to/code/ # Lint all files in `/path/to/code` (and any subdirectories). + ruff check path/to/code/*.py # Lint all `.py` files in `/path/to/code`. + ruff check path/to/code/to/file.py # Lint `file.py`. + ruff check @arguments.txt # Lint using an input file, treating its contents as newline-delimited command-line arguments. + ``` + + Or, to run Ruff as a formatter: + + ```shell + ruff format # Format all files in the current directory (and any subdirectories). + ruff format path/to/code/ # Format all files in `/path/to/code` (and any subdirectories). + ruff format path/to/code/*.py # Format all `.py` files in `/path/to/code`. + ruff format path/to/code/to/file.py # Format `file.py`. + ruff format @arguments.txt # Format using an input file, treating its contents as newline-delimited command-line arguments. + ``` + + Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff-pre-commit`](https://github.com/astral-sh/ruff-pre-commit): + + ```yaml + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.15.0 + hooks: + # Run the linter. + - id: ruff-check + args: [ --fix ] + # Run the formatter. + - id: ruff-format + ``` + + Ruff can also be used as a [VS Code extension](https://github.com/astral-sh/ruff-vscode) or with [various other editors](https://docs.astral.sh/ruff/editors/setup). + + Ruff can also be used as a [GitHub Action](https://github.com/features/actions) via + [`ruff-action`](https://github.com/astral-sh/ruff-action): + + ```yaml + name: Ruff + on: [ push, pull_request ] + jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/ruff-action@v3 + ``` + + ### Configuration + + Ruff can be configured through a `pyproject.toml`, `ruff.toml`, or `.ruff.toml` file (see: + [_Configuration_](https://docs.astral.sh/ruff/configuration/), or [_Settings_](https://docs.astral.sh/ruff/settings/) + for a complete list of all configuration options). + + If left unspecified, Ruff's default configuration is equivalent to the following `ruff.toml` file: + + ```toml + # Exclude a variety of commonly ignored directories. + exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", + ] + + # Same as Black. + line-length = 88 + indent-width = 4 + + # Assume Python 3.9 + target-version = "py39" + + [lint] + # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. + select = ["E4", "E7", "E9", "F"] + ignore = [] + + # Allow fix for all enabled rules (when `--fix`) is provided. + fixable = ["ALL"] + unfixable = [] + + # Allow unused variables when underscore-prefixed. + dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + + [format] + # Like Black, use double quotes for strings. + quote-style = "double" + + # Like Black, indent with spaces, rather than tabs. + indent-style = "space" + + # Like Black, respect magic trailing commas. + skip-magic-trailing-comma = false + + # Like Black, automatically detect the appropriate line ending. + line-ending = "auto" + ``` + + Note that, in a `pyproject.toml`, each section header should be prefixed with `tool.ruff`. For + example, `[lint]` should be replaced with `[tool.ruff.lint]`. + + Some configuration options can be provided via dedicated command-line arguments, such as those + related to rule enablement and disablement, file discovery, and logging level: + + ```shell + ruff check --select F401 --select F403 --quiet + ``` + + The remaining configuration options can be provided through a catch-all `--config` argument: + + ```shell + ruff check --config "lint.per-file-ignores = {'some_file.py' = ['F841']}" + ``` + + To opt in to the latest lint rules, formatter style changes, interface updates, and more, enable + [preview mode](https://docs.astral.sh/ruff/rules/) by setting `preview = true` in your configuration + file or passing `--preview` on the command line. Preview mode enables a collection of unstable + features that may change prior to stabilization. + + See `ruff help` for more on Ruff's top-level commands, or `ruff help check` and `ruff help format` + for more on the linting and formatting commands, respectively. + + ## Rules + + + + **Ruff supports over 800 lint rules**, many of which are inspired by popular tools like Flake8, + isort, pyupgrade, and others. Regardless of the rule's origin, Ruff re-implements every rule in + Rust as a first-party feature. + + By default, Ruff enables Flake8's `F` rules, along with a subset of the `E` rules, omitting any + stylistic rules that overlap with the use of a formatter, like `ruff format` or + [Black](https://github.com/psf/black). + + If you're just getting started with Ruff, **the default rule set is a great place to start**: it + catches a wide variety of common errors (like unused imports) with zero configuration. + + + + Beyond the defaults, Ruff re-implements some of the most popular Flake8 plugins and related code + quality tools, including: + + - [autoflake](https://pypi.org/project/autoflake/) + - [eradicate](https://pypi.org/project/eradicate/) + - [flake8-2020](https://pypi.org/project/flake8-2020/) + - [flake8-annotations](https://pypi.org/project/flake8-annotations/) + - [flake8-async](https://pypi.org/project/flake8-async) + - [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/astral-sh/ruff/issues/1646)) + - [flake8-blind-except](https://pypi.org/project/flake8-blind-except/) + - [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/) + - [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) + - [flake8-builtins](https://pypi.org/project/flake8-builtins/) + - [flake8-commas](https://pypi.org/project/flake8-commas/) + - [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) + - [flake8-copyright](https://pypi.org/project/flake8-copyright/) + - [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) + - [flake8-debugger](https://pypi.org/project/flake8-debugger/) + - [flake8-django](https://pypi.org/project/flake8-django/) + - [flake8-docstrings](https://pypi.org/project/flake8-docstrings/) + - [flake8-eradicate](https://pypi.org/project/flake8-eradicate/) + - [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) + - [flake8-executable](https://pypi.org/project/flake8-executable/) + - [flake8-future-annotations](https://pypi.org/project/flake8-future-annotations/) + - [flake8-gettext](https://pypi.org/project/flake8-gettext/) + - [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) + - [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions) + - [flake8-logging](https://pypi.org/project/flake8-logging/) + - [flake8-logging-format](https://pypi.org/project/flake8-logging-format/) + - [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420) + - [flake8-pie](https://pypi.org/project/flake8-pie/) + - [flake8-print](https://pypi.org/project/flake8-print/) + - [flake8-pyi](https://pypi.org/project/flake8-pyi/) + - [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/) + - [flake8-quotes](https://pypi.org/project/flake8-quotes/) + - [flake8-raise](https://pypi.org/project/flake8-raise/) + - [flake8-return](https://pypi.org/project/flake8-return/) + - [flake8-self](https://pypi.org/project/flake8-self/) + - [flake8-simplify](https://pypi.org/project/flake8-simplify/) + - [flake8-slots](https://pypi.org/project/flake8-slots/) + - [flake8-super](https://pypi.org/project/flake8-super/) + - [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/) + - [flake8-todos](https://pypi.org/project/flake8-todos/) + - [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) + - [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) + - [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102)) + - [isort](https://pypi.org/project/isort/) + - [mccabe](https://pypi.org/project/mccabe/) + - [pandas-vet](https://pypi.org/project/pandas-vet/) + - [pep8-naming](https://pypi.org/project/pep8-naming/) + - [pydocstyle](https://pypi.org/project/pydocstyle/) + - [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) + - [pylint-airflow](https://pypi.org/project/pylint-airflow/) + - [pyupgrade](https://pypi.org/project/pyupgrade/) + - [tryceratops](https://pypi.org/project/tryceratops/) + - [yesqa](https://pypi.org/project/yesqa/) + + For a complete enumeration of the supported rules, see [_Rules_](https://docs.astral.sh/ruff/rules/). + + ## Contributing + + Contributions are welcome and highly appreciated. To get started, check out the + [**contributing guidelines**](https://docs.astral.sh/ruff/contributing/). + + You can also join us on [**Discord**](https://discord.com/invite/astral-sh). + + ## Support + + Having trouble? Check out the existing issues on [**GitHub**](https://github.com/astral-sh/ruff/issues), + or feel free to [**open a new one**](https://github.com/astral-sh/ruff/issues/new). + + You can also ask for help on [**Discord**](https://discord.com/invite/astral-sh). + + ## Acknowledgements + + Ruff's linter draws on both the APIs and implementation details of many other + tools in the Python ecosystem, especially [Flake8](https://github.com/PyCQA/flake8), [Pyflakes](https://github.com/PyCQA/pyflakes), + [pycodestyle](https://github.com/PyCQA/pycodestyle), [pydocstyle](https://github.com/PyCQA/pydocstyle), + [pyupgrade](https://github.com/asottile/pyupgrade), and [isort](https://github.com/PyCQA/isort). + + In some cases, Ruff includes a "direct" Rust port of the corresponding tool. + We're grateful to the maintainers of these tools for their work, and for all + the value they've provided to the Python community. + + Ruff's formatter is built on a fork of Rome's [`rome_formatter`](https://github.com/rome/tools/tree/main/crates/rome_formatter), + and again draws on both API and implementation details from [Rome](https://github.com/rome/tools), + [Prettier](https://github.com/prettier/prettier), and [Black](https://github.com/psf/black). + + Ruff's import resolver is based on the import resolution algorithm from [Pyright](https://github.com/microsoft/pyright). + + Ruff is also influenced by a number of tools outside the Python ecosystem, like + [Clippy](https://github.com/rust-lang/rust-clippy) and [ESLint](https://github.com/eslint/eslint). + + Ruff is the beneficiary of a large number of [contributors](https://github.com/astral-sh/ruff/graphs/contributors). + + Ruff is released under the MIT license. + + ## Who's Using Ruff? + + Ruff is used by a number of major open-source projects and companies, including: + + - [Albumentations](https://github.com/albumentations-team/AlbumentationsX) + - Amazon ([AWS SAM](https://github.com/aws/serverless-application-model)) + - [Anki](https://apps.ankiweb.net/) + - Anthropic ([Python SDK](https://github.com/anthropics/anthropic-sdk-python)) + - [Apache Airflow](https://github.com/apache/airflow) + - AstraZeneca ([Magnus](https://github.com/AstraZeneca/magnus-core)) + - [Babel](https://github.com/python-babel/babel) + - Benchling ([Refac](https://github.com/benchling/refac)) + - [Bokeh](https://github.com/bokeh/bokeh) + - Capital One ([datacompy](https://github.com/capitalone/datacompy)) + - CrowdCent ([NumerBlox](https://github.com/crowdcent/numerblox)) + - [Cryptography (PyCA)](https://github.com/pyca/cryptography) + - CERN ([Indico](https://getindico.io/)) + - [DVC](https://github.com/iterative/dvc) + - [Dagger](https://github.com/dagger/dagger) + - [Dagster](https://github.com/dagster-io/dagster) + - Databricks ([MLflow](https://github.com/mlflow/mlflow)) + - [Dify](https://github.com/langgenius/dify) + - [FastAPI](https://github.com/tiangolo/fastapi) + - [Godot](https://github.com/godotengine/godot) + - [Gradio](https://github.com/gradio-app/gradio) + - [Great Expectations](https://github.com/great-expectations/great_expectations) + - [HTTPX](https://github.com/encode/httpx) + - [Hatch](https://github.com/pypa/hatch) + - [Home Assistant](https://github.com/home-assistant/core) + - Hugging Face ([Transformers](https://github.com/huggingface/transformers), + [Datasets](https://github.com/huggingface/datasets), + [Diffusers](https://github.com/huggingface/diffusers)) + - IBM ([Qiskit](https://github.com/Qiskit/qiskit)) + - ING Bank ([popmon](https://github.com/ing-bank/popmon), [probatus](https://github.com/ing-bank/probatus)) + - [Ibis](https://github.com/ibis-project/ibis) + - [ivy](https://github.com/unifyai/ivy) + - [JAX](https://github.com/jax-ml/jax) + - [Jupyter](https://github.com/jupyter-server/jupyter_server) + - [Kraken Tech](https://kraken.tech/) + - [LangChain](https://github.com/hwchase17/langchain) + - [Litestar](https://litestar.dev/) + - [LlamaIndex](https://github.com/jerryjliu/llama_index) + - Matrix ([Synapse](https://github.com/matrix-org/synapse)) + - [MegaLinter](https://github.com/oxsecurity/megalinter) + - Meltano ([Meltano CLI](https://github.com/meltano/meltano), [Singer SDK](https://github.com/meltano/sdk)) + - Microsoft ([Semantic Kernel](https://github.com/microsoft/semantic-kernel), + [ONNX Runtime](https://github.com/microsoft/onnxruntime), + [LightGBM](https://github.com/microsoft/LightGBM)) + - Modern Treasury ([Python SDK](https://github.com/Modern-Treasury/modern-treasury-python)) + - Mozilla ([Firefox](https://github.com/mozilla/gecko-dev)) + - [Mypy](https://github.com/python/mypy) + - [Nautobot](https://github.com/nautobot/nautobot) + - Netflix ([Dispatch](https://github.com/Netflix/dispatch)) + - [Neon](https://github.com/neondatabase/neon) + - [Nokia](https://nokia.com/) + - [NoneBot](https://github.com/nonebot/nonebot2) + - [NumPyro](https://github.com/pyro-ppl/numpyro) + - [ONNX](https://github.com/onnx/onnx) + - [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal) + - [Open Wine Components](https://github.com/Open-Wine-Components/umu-launcher) + - [PDM](https://github.com/pdm-project/pdm) + - [PaddlePaddle](https://github.com/PaddlePaddle/Paddle) + - [Pandas](https://github.com/pandas-dev/pandas) + - [Pillow](https://github.com/python-pillow/Pillow) + - [Poetry](https://github.com/python-poetry/poetry) + - [Polars](https://github.com/pola-rs/polars) + - [PostHog](https://github.com/PostHog/posthog) + - Prefect ([Python SDK](https://github.com/PrefectHQ/prefect), [Marvin](https://github.com/PrefectHQ/marvin)) + - [PyInstaller](https://github.com/pyinstaller/pyinstaller) + - [PyMC](https://github.com/pymc-devs/pymc/) + - [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing) + - [pytest](https://github.com/pytest-dev/pytest) + - [PyTorch](https://github.com/pytorch/pytorch) + - [Pydantic](https://github.com/pydantic/pydantic) + - [Pylint](https://github.com/PyCQA/pylint) + - [PyScripter](https://github.com/pyscripter/pyscripter) + - [PyVista](https://github.com/pyvista/pyvista) + - [Reflex](https://github.com/reflex-dev/reflex) + - [River](https://github.com/online-ml/river) + - [Rippling](https://rippling.com) + - [Robyn](https://github.com/sansyrox/robyn) + - [Saleor](https://github.com/saleor/saleor) + - Scale AI ([Launch SDK](https://github.com/scaleapi/launch-python-client)) + - [SciPy](https://github.com/scipy/scipy) + - Snowflake ([SnowCLI](https://github.com/Snowflake-Labs/snowcli)) + - [Sphinx](https://github.com/sphinx-doc/sphinx) + - [Stable Baselines3](https://github.com/DLR-RM/stable-baselines3) + - [Starlette](https://github.com/encode/starlette) + - [Streamlit](https://github.com/streamlit/streamlit) + - [The Algorithms](https://github.com/TheAlgorithms/Python) + - [Vega-Altair](https://github.com/altair-viz/altair) + - [Weblate](https://weblate.org/) + - WordPress ([Openverse](https://github.com/WordPress/openverse)) + - [ZenML](https://github.com/zenml-io/zenml) + - [Zulip](https://github.com/zulip/zulip) + - [build (PyPA)](https://github.com/pypa/build) + - [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel) + - [delta-rs](https://github.com/delta-io/delta-rs) + - [featuretools](https://github.com/alteryx/featuretools) + - [meson-python](https://github.com/mesonbuild/meson-python) + - [nox](https://github.com/wntrblm/nox) + - [pip](https://github.com/pypa/pip) + + ### Show Your Support + + If you're using Ruff, consider adding the Ruff badge to your project's `README.md`: + + ```md + [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) + ``` + + ...or `README.rst`: + + ```rst + .. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json + :target: https://github.com/astral-sh/ruff + :alt: Ruff + ``` + + ...or, as HTML: + + ```html + Ruff + ``` + + ## License + + This repository is licensed under the [MIT License](https://github.com/astral-sh/ruff/blob/main/LICENSE) + +
    + + Made by Astral + +
    +homepage_url: https://docs.astral.sh/ruff +package_url: pkg:pypi/ruff@0.15.0 +license_expression: mit +copyright: Copyright Anthony Sottile, Florent Xicluna +attribute: yes +checksum_md5: bbef1102be85f3491f0e081879113991 +checksum_sha1: 4729a8b0983fa49d8e0afd50e0903c8a73f79c5d +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/setuptools-82.0.0-py3-none-any.whl.ABOUT b/thirdparty/dist/setuptools-82.0.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..4aac63e4 --- /dev/null +++ b/thirdparty/dist/setuptools-82.0.0-py3-none-any.whl.ABOUT @@ -0,0 +1,31 @@ +about_resource: setuptools-82.0.0-py3-none-any.whl +name: setuptools +version: 82.0.0 +download_url: https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl +package_url: pkg:pypi/setuptools@82.0.0 +license_expression: apache-2.0 AND bsd-new AND bsd-simplified AND lgpl-3.0 AND mit AND unknown-license-reference +copyright: Copyright setuptools project contributors +redistribute: yes +attribute: yes +track_changes: yes +checksum_md5: 46c24ad8ec6d79f6c341e76632afeb14 +checksum_sha1: 8125d8cfaf65276f0b73ed2906073f7f21b2077c +licenses: + - key: apache-2.0 + name: Apache License 2.0 + file: apache-2.0.LICENSE + - key: mit + name: MIT License + file: mit.LICENSE + - key: bsd-simplified + name: BSD-2-Clause + file: bsd-simplified.LICENSE + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE + - key: lgpl-3.0 + name: GNU Lesser General Public License 3.0 + file: lgpl-3.0.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/setuptools_rust-1.12.0-py3-none-any.whl.ABOUT b/thirdparty/dist/setuptools_rust-1.12.0-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..a4f0d099 --- /dev/null +++ b/thirdparty/dist/setuptools_rust-1.12.0-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: setuptools_rust-1.12.0-py3-none-any.whl +name: setuptools-rust +version: 1.12.0 +download_url: https://files.pythonhosted.org/packages/f9/7b/d05b1778f2d4e354d103e3421c6267d923032fefcc5ca5b7df0cb21cefd0/setuptools_rust-1.12.0-py3-none-any.whl +package_url: pkg:pypi/setuptools-rust@1.12.0 +license_expression: mit +copyright: Copyright setuptools-rust project contributors +attribute: yes +checksum_md5: 74f5c6c03aff2952130d373ae3ff0df6 +checksum_sha1: 82d6120bb40945248df563882726942ad2e2bd73 +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/setuptools_scm-9.2.2-py3-none-any.whl.ABOUT b/thirdparty/dist/setuptools_scm-9.2.2-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..76509c01 --- /dev/null +++ b/thirdparty/dist/setuptools_scm-9.2.2-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: setuptools_scm-9.2.2-py3-none-any.whl +name: setuptools-scm +version: 9.2.2 +download_url: https://files.pythonhosted.org/packages/3d/ea/ac2bf868899d0d2e82ef72d350d97a846110c709bacf2d968431576ca915/setuptools_scm-9.2.2-py3-none-any.whl +package_url: pkg:pypi/setuptools-scm@9.2.2 +license_expression: mit +copyright: Copyright setuptools-scm project contributors +attribute: yes +checksum_md5: 4627cbb7183ca139ee0e971c1387790e +checksum_sha1: 2097c943363e2772bc91a8f327ec18a0c5b0b1cd +licenses: + - key: mit + name: MIT License + file: mit.LICENSE diff --git a/thirdparty/dist/sqlparse-0.5.5-py3-none-any.whl.ABOUT b/thirdparty/dist/sqlparse-0.5.5-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..db85b421 --- /dev/null +++ b/thirdparty/dist/sqlparse-0.5.5-py3-none-any.whl.ABOUT @@ -0,0 +1,14 @@ +about_resource: sqlparse-0.5.5-py3-none-any.whl +name: sqlparse +version: 0.5.5 +download_url: https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl +package_url: pkg:pypi/sqlparse@0.5.5 +license_expression: bsd-new +copyright: Copyright sqlparse project contributors +attribute: yes +checksum_md5: d9fc99915bab1488672498cc1368e3cf +checksum_sha1: 1412101ac307a4db2bb7b06f0ce45612edcba7e6 +licenses: + - key: bsd-new + name: BSD-3-Clause + file: bsd-new.LICENSE diff --git a/thirdparty/dist/urllib3-2.6.3-py3-none-any.whl.ABOUT b/thirdparty/dist/urllib3-2.6.3-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..7266e4d7 --- /dev/null +++ b/thirdparty/dist/urllib3-2.6.3-py3-none-any.whl.ABOUT @@ -0,0 +1,17 @@ +about_resource: urllib3-2.6.3-py3-none-any.whl +name: urllib3 +version: 2.6.3 +download_url: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl +package_url: pkg:pypi/urllib3@2.6.3 +license_expression: mit AND unknown-license-reference +copyright: Copyright urllib3 project contributors +attribute: yes +checksum_md5: 574c8593fd05938d292a624ea3f96e89 +checksum_sha1: 29ab8033a22966e6880d05b194602b49508c78a8 +licenses: + - key: mit + name: MIT License + file: mit.LICENSE + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/thirdparty/dist/wheel-0.46.3-py3-none-any.whl.ABOUT b/thirdparty/dist/wheel-0.46.3-py3-none-any.whl.ABOUT new file mode 100644 index 00000000..214e84dd --- /dev/null +++ b/thirdparty/dist/wheel-0.46.3-py3-none-any.whl.ABOUT @@ -0,0 +1,13 @@ +about_resource: wheel-0.46.3-py3-none-any.whl +name: wheel +version: 0.46.3 +download_url: https://files.pythonhosted.org/packages/87/22/b76d483683216dde3d67cba61fb2444be8d5be289bf628c13fc0fd90e5f9/wheel-0.46.3-py3-none-any.whl +package_url: pkg:pypi/wheel@0.46.3 +license_expression: unknown-license-reference +copyright: Copyright wheel project contributors +checksum_md5: 268bf133a01ffa49c152e5e3a47296da +checksum_sha1: 8587c24d65be32a081b824d914dc31935159e2b7 +licenses: + - key: unknown-license-reference + name: Unknown License file reference + file: unknown-license-reference.LICENSE diff --git a/workflow/models.py b/workflow/models.py index 07c020f3..b861cba0 100644 --- a/workflow/models.py +++ b/workflow/models.py @@ -22,8 +22,7 @@ from django.utils import timezone from django.utils.functional import cached_property from django.utils.html import escape -from django.utils.html import format_html -from django.utils.safestring import mark_safe +from django.utils.html import mark_safe from django.utils.translation import gettext_lazy as _ import markdown @@ -529,7 +528,7 @@ def get_serialized_data_as_html(self, html_template="{label}: {value}", separato else: serialized_data.append(line) - return format_html(separator.join(serialized_data)) + return mark_safe(separator.join(serialized_data)) @property def serialized_data_html(self): diff --git a/workflow/views.py b/workflow/views.py index 1cc97ae3..bb12cff1 100644 --- a/workflow/views.py +++ b/workflow/views.py @@ -18,7 +18,7 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import redirect from django.shortcuts import render -from django.utils.html import format_html +from django.utils.html import mark_safe from dje.utils import get_preserved_filters from dje.utils import group_by @@ -123,7 +123,7 @@ def request_add_view(request, template_uuid): f"" ) - messages.success(request, format_html(msg)) + messages.success(request, mark_safe(msg)) return redirect(instance.get_absolute_url()) return render(request, "workflow/request_form.html", {"form": form}) @@ -187,7 +187,7 @@ def request_edit_view(request, request_uuid): f"" ) - messages.success(request, format_html(msg)) + messages.success(request, mark_safe(msg)) return redirect(request_instance) elif not form.has_changed():