<commit_before>from os.path import join

from django.core.files.storage import DefaultStorage
from django.db import models

from candidates.models import PersonRedirect
from ynr_refactoring.settings import PersonIdentifierFields


class PersonImageManager(models.Manager):
    def create_from_file(self, image_filename, ideal_relative_name, defaults):
        # Import the file to media root and create the ORM
        # objects.
        storage = DefaultStorage()
        desired_storage_path = join("images", ideal_relative_name)
        with open(image_filename, "rb") as f:
            storage_filename = storage.save(desired_storage_path, f)
        return self.create(image=storage_filename, **defaults)

    def update_or_create_from_file(
        self, image_filename, ideal_relative_name, person, defaults
    ):
        try:
            image = self.get(person=person, md5sum=defaults["md5sum"])
            for k, v in defaults.items():
                setattr(image, k, v)
            image.save()
            return image, False

        except self.model.DoesNotExist:
            # Prepare args for the base object first:
            defaults["person"] = person

            # And now the extra object:
            image = self.create_from_file(
                image_filename, ideal_relative_name, defaults
            )
        return image


class PersonIdentifierQuerySet(models.query.QuerySet):
    def select_choices(self):
        default_option = [(None, "")]
        options = [(f.name, f.value) for f in PersonIdentifierFields]
        return default_option + options

    def editable_value_types(self):
        """
        Until we have a way to truly manage any key/value pair there are some
        IDs that we don't want to be user editable just yet.

        In that case, we need a way to exclude non-editable models from
        the edit form and the versions diff.
        """
        return self.filter(
            value_type__in=[vt[0] for vt in self.select_choices()]
        )


class PersonQuerySet(models.query.QuerySet):
    def alive_now(self):
        return self.filter(death_date="")

    def joins_for_csv_output(self):
        from popolo.models import Membership

        return self.prefetch_related(
            models.Prefetch(
                "memberships",
                Membership.objects.select_related(
                    "ballot", "ballot__election", "party", "post"
                ),
            ),
            "images__uploading_user",
            "tmp_person_identifiers",
        )

    def get_by_id_with_redirects(self, person_id):
        try:
            person = self.get(id=person_id)
        except self.model.DoesNotExist:
            try:
                person_id = PersonRedirect.objects.get(
                    old_person_id=person_id
                ).new_person_id
                self.get_by_id_with_redirects(person_id)
            except PersonRedirect.DoesNotExist:
                person = None
        return person<commit_msg>Raise Person.DoesNotExist to make interface easier to use<commit_after>from os.path import join

from django.core.files.storage import DefaultStorage
from django.db import models

from candidates.models import PersonRedirect
from ynr_refactoring.settings import PersonIdentifierFields


class PersonImageManager(models.Manager):
    def create_from_file(self, image_filename, ideal_relative_name, defaults):
        # Import the file to media root and create the ORM
        # objects.
        storage = DefaultStorage()
        desired_storage_path = join("images", ideal_relative_name)
        with open(image_filename, "rb") as f:
            storage_filename = storage.save(desired_storage_path, f)
        return self.create(image=storage_filename, **defaults)

    def update_or_create_from_file(
        self, image_filename, ideal_relative_name, person, defaults
    ):
        try:
            image = self.get(person=person, md5sum=defaults["md5sum"])
            for k, v in defaults.items():
                setattr(image, k, v)
            image.save()
            return image, False

        except self.model.DoesNotExist:
            # Prepare args for the base object first:
            defaults["person"] = person

            # And now the extra object:
            image = self.create_from_file(
                image_filename, ideal_relative_name, defaults
            )
        return image


class PersonIdentifierQuerySet(models.query.QuerySet):
    def select_choices(self):
        default_option = [(None, "")]
        options = [(f.name, f.value) for f in PersonIdentifierFields]
        return default_option + options

    def editable_value_types(self):
        """
        Until we have a way to truly manage any key/value pair there are some
        IDs that we don't want to be user editable just yet.

        In that case, we need a way to exclude non-editable models from
        the edit form and the versions diff.
        """
        return self.filter(
            value_type__in=[vt[0] for vt in self.select_choices()]
        )


class PersonQuerySet(models.query.QuerySet):
    def alive_now(self):
        return self.filter(death_date="")

    def joins_for_csv_output(self):
        from popolo.models import Membership

        return self.prefetch_related(
            models.Prefetch(
                "memberships",
                Membership.objects.select_related(
                    "ballot", "ballot__election", "party", "post"
                ),
            ),
            "images__uploading_user",
            "tmp_person_identifiers",
        )

    def get_by_id_with_redirects(self, person_id):
        try:
            person = self.get(id=person_id)
        except self.model.DoesNotExist:
            try:
                person_id = PersonRedirect.objects.get(
                    old_person_id=person_id
                ).new_person_id
                self.get_by_id_with_redirects(person_id)
            except PersonRedirect.DoesNotExist:
                raise self.model.DoesNotExist
        return person
{'fraction_non_alphanumeric': 0.0752299605781866, 'fraction_numerical': 0.0009855453350854138, 'mean_word_length': 2.184623430962343, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3073799', 'n_tokens_mistral': 1662, 'n_tokens_neox': 1607, 'n_words': 430}