def test_uuid(self): assert isinstance(FilePattern.get_uuid(), uuid.UUID), "type uuid.UUID expected" assert FilePattern.get_uuid().hex[12] == "4", "UUID version 4 expected" assert (FixedUUIDFilePattern(filename_pattern="{uuid:x}{ext}")( instance=DefaultModel(title="best model"), filename="some_file.txt") == "522d6f3519204b0fb82ae8f558af2749.txt" )
def test_destruct(self): assert FilePattern().deconstruct() == ("dynamic_filenames.FilePattern", [], {}) assert FilePattern(filename_pattern="{name}{ext}").deconstruct() == ( "dynamic_filenames.FilePattern", [], { "filename_pattern": "{name}{ext}" }, ) assert FilePattern(name="sth").deconstruct() == ( "dynamic_filenames.FilePattern", [], { "name": "sth" }, )
# -*- coding: utf-8 -*- from __future__ import unicode_literals, absolute_import from django.db import models from django.utils import timezone from six import python_2_unicode_compatible from stdimage.models import StdImageField from dynamic_filenames import FilePattern image_variations = {"home": {"width": 530, "height": 220, "crop": True}} upload_to_pattern = FilePattern( filename_pattern="{model_name}/{instance.title:slug}{ext}") @python_2_unicode_compatible class Feed(models.Model): home_url = models.URLField(verbose_name="Site Home Page") feed_url = models.URLField(verbose_name="RSS Feed URL") title = models.CharField(max_length=255) author = models.CharField(max_length=255) tags = models.CharField(max_length=255, blank=True) image = StdImageField( upload_to=upload_to_pattern, blank=True, null=True, variations=image_variations, ) enabled = models.BooleanField(default=True) def __str__(self): return self.title
def test_call__name_override(self): assert FilePattern(name='special_name')( instance=DefaultModel(), filename='some_file.txt' ) == 'special_name.txt'
def test_call__app_label(self): assert FilePattern(filename_pattern='{app_label}/{name}{ext}')( instance=DefaultModel(), filename='some_file.txt' ) == 'testapp/some_file.txt'
def test_call__full_path(self): assert FilePattern()( instance=DefaultModel(), filename='/var/www/index.html' ) == 'index.html'
def test_call__only_extension(self): assert FilePattern()(instance=DefaultModel(), filename='.htaccess') == '.htaccess'
def test_call__default(self): assert FilePattern()(instance=DefaultModel(), filename='test_file.txt') == 'test_file.txt'
FileExtensionValidator, MinValueValidator, MaxValueValidator, ) from django.utils.translation import gettext_lazy as _ from dynamic_filenames import FilePattern from io import BytesIO from PIL import Image from stdimage.models import StdImageField __all__ = [ "StaticMapImage", ] static_map_image_path = FilePattern( filename_pattern="{app_label}/{model_name}/{uuid:base32}{ext}") DEFAULT_MAP_WIDTH = 992 DEFAULT_MAP_HEIGHT = 300 DEFAULT_MAP_ZOOM = 11 DEFAULT_MAP_SCALE = 1 def download_static_map_image_from_jawg( center=None, zoom=DEFAULT_MAP_ZOOM, scale=DEFAULT_MAP_SCALE, width=DEFAULT_MAP_WIDTH, height=DEFAULT_MAP_HEIGHT, ): if not center: raise exceptions.ValidationError("Missing required property 'center'")
class Talk(models.Model): title = models.CharField(max_length=300, null=False) description = HTMLField(null=True) audio_original = models.FileField( null=True, blank=True, upload_to=FilePattern( filename_pattern='audio/original/tmi-archive-{uuid:.12base32}.mp3' ), validators=[FileExtensionValidator(['mp3'])]) audio_cleaned = models.FileField( null=True, blank=True, upload_to=FilePattern( filename_pattern='audio/cleaned/tmi-archive-{uuid:.12base32}.mp3'), validators=[FileExtensionValidator(['mp3'])]) audio_filename = models.CharField(max_length=300, blank=True, null=True) original_file_name = models.CharField(max_length=300, blank=True, null=True) created_by = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='created_by') updated_by = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='updated_by') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) auto_add_user_data = True transcription = models.TextField( null=True, help_text= 'The transcription of the audio is formatted in a specific way:' '"[timestamp @speaker_name] all text of paragraph (new line)". For example: <br>' '[0:00:00.0 @student] Some question.<br>' '[0:00:10.4 @culadasa] Answer to question.') transcription_deepgram = models.TextField(null=True) def __str__(self): return self.title def save(self, *args, **kwargs): if self.auto_add_user_data: if self.pk is None: self.created_by = get_current_user() self.updated_by = get_current_user() res = super(Talk, self).save(*args, **kwargs) return res def get_absolute_url(self): return reverse('talk_view', kwargs={'pk': self.id}) @property def mp3_url_clean(self): if self.audio_cleaned is None: return None try: file_name = str(self.audio_cleaned) except ValueError: return None file_name = file_name.split('/')[-1] return f'https://mp3.tmi-archive.com/{file_name}' @property def transcription_text(self): if self.transcription is None: return '(no transcription available)' sentences = self.transcription.split('\r\n') sentences = [s.split(']')[1] if ']' in s else s for s in sentences] paragraphs = [] paragraph = '' for sentence in sentences: if len(paragraph) > 500: paragraphs.append(copy.copy(paragraph)) paragraph = '' paragraph += str(sentence) paragraphs.append(paragraph) return "<br><br>".join(paragraphs) @property def transcription_for_audio(self): transcription = self.transcription for i in range(10): transcription = transcription.replace(f'@speaker_{i}', '') transcription = transcription.replace(' ]', ' -]') # the player needs very specific lines: # [00:00:03.6-] So anybody has on? sentences = transcription.split('\r\n') paragraphs = [] paragraph = '' for sentence in sentences: if len(paragraph) > 500: paragraphs.append(paragraph) paragraph = '' if len(paragraph) > 0: sentence = sentence.split(']')[1] paragraph += str(sentence) paragraphs.append(paragraph) return "\r\n".join(paragraphs)
from .model_fields import MandatesField, ValidatedPhoneNumberField from .person_forms.models import * from ..elus.models import StatutMandat from ..lib.display import genrer from ..lib.model_fields import ChoiceArrayField __all__ = [ "Person", "PersonEmail", "PersonTag", "PersonForm", "PersonFormSubmission", "PersonValidationSMS", ] person_image_path = FilePattern( filename_pattern="{app_label}/{model_name}/{instance.id}/{uuid:s}{ext}") class PersonQueryset(models.QuerySet): def with_contact_phone(self): return self.exclude(contact_phone="") def verified(self): return self.filter(contact_phone_status=Person.CONTACT_PHONE_VERIFIED) def search(self, query, *or_query): q = reduce( lambda a, b: a | Q(search=PrefixSearchQuery( b, config="simple_unaccented")), or_query, Q(search=PrefixSearchQuery(query, config="simple_unaccented")),
def test_call__name_override(self): assert (FilePattern(name="special_name")( instance=DefaultModel(), filename="some_file.txt") == "special_name.txt")
def test_call__model_name(self): assert (FilePattern(filename_pattern="{model_name}/{name}{ext}")( instance=DefaultModel(), filename="some_file.txt") == "defaultmodel/some_file.txt")
def test_call__app_label(self): assert (FilePattern(filename_pattern="{app_label}/{name}{ext}")( instance=DefaultModel(), filename="some_file.txt") == "testapp/some_file.txt")
def test_call__override_pattern(self): assert (FilePattern(filename_pattern="my_file{ext}")( instance=DefaultModel(), filename="other_file.txt") == "my_file.txt")
def test_destruct(self): assert FilePattern().deconstruct() == ('dynamic_filenames.FilePattern', [], {}) assert FilePattern(filename_pattern='{name}{ext}').deconstruct() == ( 'dynamic_filenames.FilePattern', [], {'filename_pattern': '{name}{ext}'}) assert FilePattern(name='sth').deconstruct() == ( 'dynamic_filenames.FilePattern', [], {'name': 'sth'})
def test_init(self): assert FilePattern().kwargs == {} assert FilePattern().override_values == {} assert FilePattern(path='sth').kwargs == {'path': 'sth'} assert FilePattern(path='sth').override_values == {'path': 'sth'}
# cas spécifique : si on revient à "attente d'informations supplémentaires suite à une modification par un non admin # c'est forcément une modification if (new_status == cls.STATUS_AWAITING_SUPPLEMENTARY_INFORMATION and person is not None): res["title"] = "Modification de la demande" # some couples (old_status, new_status) elif (old_status, new_status) in cls.HISTORY_MESSAGES: res["title"] = cls.HISTORY_MESSAGES[(old_status, new_status)] else: res["title"] = cls.HISTORY_MESSAGES.get( new_status, "[Modification non identifiée]") return res document_path = FilePattern( filename_pattern="financement/request/{instance.request_id}/{uuid:s}{ext}") @reversion.register() class Document(models.Model): TYPE_INVOICE = "I" TYPE_PICTURE = "P" TYPE_OTHER = "O" TYPE_CHOICES = ( (TYPE_INVOICE, _("Facture")), ( TYPE_PICTURE, _("Photo ou illustration de l'événement, de la salle, du matériel" ), ), (TYPE_OTHER, _("Autre type de justificatif")),
def test_call__no_extension(self): assert FilePattern()(instance=DefaultModel(), filename='test_file') == 'test_file'
"form_class": CustomDateTimeFormField, } defaults.update(kwargs) return super().formfield(**defaults) def get_default_subtype(): subtype = (EventSubtype.objects.filter( type=EventSubtype.TYPE_PUBLIC_ACTION).order_by("created").values( "id").first()) return subtype and subtype["id"] report_image_path = FilePattern( filename_pattern="{app_label}/{model_name}/{instance.id}/report_banner{ext}" ) class EventManager(models.Manager.from_queryset(EventQuerySet)): def create(self, *args, **kwargs): subtype = kwargs.get("subtype", None) if subtype: kwargs["description"] = kwargs.get("description", subtype.default_description) kwargs["image"] = kwargs.get("image", subtype.default_image) return self.create_event(*args, **kwargs) def create_event(self, organizer_person=None, organizer_group=None,
def test_call__dot_file(self): assert FilePattern()( instance=DefaultModel(), filename='.hidden-truth.txt' ) == '.hidden-truth.txt'
class Calendar(ImageMixin): objects = CalendarManager() name = models.CharField(_("titre"), max_length=255) slug = models.SlugField(_("slug"), unique=True) archived = models.BooleanField("Calendrier archivé", default=False) parent = models.ForeignKey( "Calendar", on_delete=models.SET_NULL, related_name="children", related_query_name="child", null=True, blank=True, ) events = models.ManyToManyField("Event", related_name="calendars", through="CalendarItem") user_contributed = models.BooleanField( _("Les utilisateurs peuvent ajouter des événements"), default=False) description = models.TextField( _("description"), blank=True, help_text=_("Saisissez une description (HTML accepté)"), ) image = StdImageField( _("bannière"), upload_to=FilePattern( filename_pattern= "{app_label}/{model_name}/{instance.name:slug}{ext}"), variations={ "thumbnail": (400, 250), "banner": (1200, 400) }, blank=True, ) class Meta: verbose_name = _("Agenda") def __str__(self): return self.name def clean_fields(self, exclude=None): super().clean_fields() if exclude is None: exclude = [] if "parent" not in exclude: calendar = self for i in range(settings.CALENDAR_MAXIMAL_DEPTH): calendar = calendar.parent if calendar is None: break else: raise ValidationError({ "parent": ValidationError( _("Impossible d'utiliser ce calendrier comme parent :" " cela excéderait la profondeur maximale autorisée.") ) })
def test_call__override_pattern(self): assert FilePattern(filename_pattern='my_file{ext}')( instance=DefaultModel(), filename='other_file.txt' ) == 'my_file.txt'
""" objects = AbstractLabelManager() label = models.CharField(_("nom"), max_length=50, unique=True, blank=False) description = models.TextField(_("description"), blank=True) class Meta: abstract = True def __str__(self): return self.label icon_path = FilePattern( filename_pattern="{app_label}/{model_name}/{instance.id}/icon{ext}" ) class BaseSubtype(TimeStampedModel, AbstractLabel): """ Abstract class for event and group labels which should have special appearance on map """ VISIBILITY_NONE = "N" VISIBILITY_ADMIN = "D" VISIBILITY_ALL = "A" VISIBILITY_CHOICES = ( (VISIBILITY_NONE, _("Personne (plus utilisé)")), (VISIBILITY_ADMIN, _("Seulement depuis l'administration")), (VISIBILITY_ALL, _("N'importe qui")),
def test_call__model_name(self): assert FilePattern(filename_pattern='{model_name}/{name}{ext}')( instance=DefaultModel(), filename='some_file.txt' ) == 'defaultmodel/some_file.txt'
from unicodedata import normalize from io import BytesIO from django.db import models from django.shortcuts import resolve_url from django.conf import settings from django.utils.safestring import SafeText from stdimage.models import StdImageField from dynamic_filenames import FilePattern from django.core.files.base import ContentFile from stdimage.utils import render_variations from PIL import Image from .enums import MAKES, COUNTRIES, FUEL_TYPES, BODY_STYLES upload_to_pattern = FilePattern( filename_pattern='{model_name}/{uuid:.16base32}{ext}') def slug(text): clean_text = text.strip().replace(' ', '-').replace(',', '-') while '--' in clean_text: clean_text = clean_text.replace('--', '-') ascii_text = normalize('NFKD', clean_text).encode('ascii', 'ignore') return ascii_text.lower().decode() def resize_and_autorotate(file_name, variations, storage): with storage.open(file_name) as f: with Image.open(f) as image: file_format = image.format exif = image._getexif()
from django.db import models from dynamic_filenames import FilePattern upload_to_pattern = FilePattern( filename_pattern="{instance.title:slug}{ext}", ) class DefaultModel(models.Model): title = models.CharField(max_length=100, default="hello goodby") file_field = models.FileField(upload_to=upload_to_pattern)
def test_call__slug(self): assert FilePattern(filename_pattern='{instance.title:slug}{ext}')( instance=DefaultModel(title='best model with ünicode'), filename='some_file.txt' ) == 'best-model-with-unicode.txt'
from dynamic_filenames import FilePattern upload_to_pattern = FilePattern( filename_pattern='{app_label:.25}/{model_name:.30}/{uuid:base32}{ext}' )
def test_call__slug_precision(self): assert FilePattern(filename_pattern='{instance.title:.4slug}{ext}')( instance=DefaultModel(title='best model'), filename='some_file.txt' ) == 'best.txt'