From c7c6541af0b0d1afc30ddfea35227c5b407151e3 Mon Sep 17 00:00:00 2001 From: Fabro Date: Mon, 16 Mar 2026 01:36:30 -0400 Subject: [PATCH] checkpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚒️ Generated with [Fabro](https://fabro.sh) --- checkpoint.json | 34 +- nodes/extract_patch/script_invocation.json | 5 + nodes/extract_patch/script_timing.json | 5 + nodes/extract_patch/status.json | 6 + nodes/solve/diff.patch | 3204 ++++++++++++++++++++ 5 files changed, 3244 insertions(+), 10 deletions(-) create mode 100644 nodes/extract_patch/script_invocation.json create mode 100644 nodes/extract_patch/script_timing.json create mode 100644 nodes/extract_patch/status.json create mode 100644 nodes/solve/diff.patch diff --git a/checkpoint.json b/checkpoint.json index 6fc71593b..568892a2f 100644 --- a/checkpoint.json +++ b/checkpoint.json @@ -1,34 +1,38 @@ { - "timestamp": "2026-03-16T05:36:26.336376Z", - "current_node": "solve", + "timestamp": "2026-03-16T05:36:30.351384Z", + "current_node": "extract_patch", "completed_nodes": [ "start", "setup", - "solve" + "solve", + "extract_patch" ], "node_retries": { "start": 1, + "extract_patch": 1, "setup": 1, "solve": 1 }, "context_values": { "last_stage": "solve", "internal.node_visit_count": 1, - "command.output": "fatal: destination path '.' already exists and is not an empty directory.\n", - "internal.thread_id": "setup", + "command.output": "", + "internal.thread_id": "solve", "command.stderr": "", "response.solve": "All tests pass. Here's a summary of the changes made:\n\n## Changes\n\n### `django/db/models/fields/__init__.py`\n\n1. **Added `_check_max_length_choices` call to `CharField.check()`** — Includes the new check in the CharField system checks pipeline.\n\n2. **Added `CharField._check_max_length_choices()` method** — A new system check that:\n - Only runs when both `max_length` and `choices` are set\n - Uses `self.flatchoices` to handle both flat choices and grouped choices\n - Filters to only string values (non-string choice values like integers don't have a length constraint)\n - Gracefully handles invalid choices (TypeError/ValueError) since those are already caught by `_check_choices()`\n - Returns `fields.E122` error when the longest choice value exceeds `max_length`\n\n### `tests/invalid_models_tests/test_ordinary_fields.py`\n\nAdded two test cases:\n- **`test_choices_longer_than_max_length`** — Verifies the error is raised for flat choices that exceed max_length\n- **`test_choices_in_groups_longer_than_max_length`** — Verifies the error is raised for grouped choices that exceed max_length", - "current.preamble": "Goal: Add check to ensure max_length fits longest choice.\nDescription\n\t\nThere is currently no check to ensure that Field.max_length is large enough to fit the longest value in Field.choices.\nThis would be very helpful as often this mistake is not noticed until an attempt is made to save a record with those values that are too long.\n\n\n## Completed stages\n- **setup**: fail\n - Script: `git clone https://github.com/django/django.git . && git checkout fee75d2aed4e58ada6567c464cfd22e89dc65f4a && python -m pip install -e .`\n - Stdout:\n ```\n fatal: destination path '.' already exists and is not an empty directory.\n ```\n - Stderr: (empty)\n\n## Context\n- failure_class: deterministic\n- failure_signature: setup|deterministic|script failed with exit code: ## stdout fatal: destination path '.' already exists and is not an empty directory.\n", + "current.preamble": "Goal: Add check to ensure max_length fits longest choice.\nDescription\n\t\nThere is currently no check to ensure that Field.max_length is large enough to fit the longest value in Field.choices.\nThis would be very helpful as often this mistake is not noticed until an attempt is made to save a record with those values that are too long.\n\n\n## Completed stages\n- **setup**: fail\n - Script: `git clone https://github.com/django/django.git . && git checkout fee75d2aed4e58ada6567c464cfd22e89dc65f4a && python -m pip install -e .`\n - Stdout:\n ```\n fatal: destination path '.' already exists and is not an empty directory.\n ```\n - Stderr: (empty)\n- **solve**: success\n - Model: claude-opus-4-6, 19.9k tokens in / 7.9k out\n - Files: /tmp/django_repo/django/db/models/fields/__init__.py, /tmp/django_repo/tests/invalid_models_tests/test_ordinary_fields.py\n", "graph.rankdir": "LR", "outcome": "success", "internal.retry_count.solve": 1, - "current_node": "solve", + "current_node": "extract_patch", "internal.run_id": "01KKTJ3AF4KC3M7YGJ5CRBC17X", "last_response": "All tests pass. Here's a summary of the changes made:\n\n## Changes\n\n### `django/db/models/fields/__init__.py`\n\n1. **Added `_check_max_length_choices` call to `CharField.check()`** — Includes the new ", "failure_signature": "", "internal.retry_count.setup": 1, "internal.retry_count.start": 1, "internal.fidelity": "compact", + "internal.retry_count.extract_patch": 1, + "thread.solve.current_node": "extract_patch", "thread.setup.current_node": "solve", "failure_class": "", "thread.start.current_node": "setup", @@ -74,15 +78,25 @@ "start": { "status": "success", "duration_ms": 0 + }, + "extract_patch": { + "status": "success", + "context_updates": { + "command.output": "", + "command.stderr": "" + }, + "notes": "Script completed: git diff", + "duration_ms": 220 } }, - "next_node_id": "extract_patch", + "next_node_id": "exit", "loop_failure_signatures": { "setup|deterministic|script failed with exit code: ## stdout fatal: destination path '.' already exists and is not an empty directory.": 1 }, "node_visits": { "start": 1, - "setup": 1, - "solve": 1 + "solve": 1, + "extract_patch": 1, + "setup": 1 } } \ No newline at end of file diff --git a/nodes/extract_patch/script_invocation.json b/nodes/extract_patch/script_invocation.json new file mode 100644 index 000000000..6d29afc80 --- /dev/null +++ b/nodes/extract_patch/script_invocation.json @@ -0,0 +1,5 @@ +{ + "command": "git diff", + "language": "shell", + "timeout_ms": null +} \ No newline at end of file diff --git a/nodes/extract_patch/script_timing.json b/nodes/extract_patch/script_timing.json new file mode 100644 index 000000000..7fb9dd37f --- /dev/null +++ b/nodes/extract_patch/script_timing.json @@ -0,0 +1,5 @@ +{ + "duration_ms": 219, + "exit_code": 0, + "timed_out": false +} \ No newline at end of file diff --git a/nodes/extract_patch/status.json b/nodes/extract_patch/status.json new file mode 100644 index 000000000..10f25fa22 --- /dev/null +++ b/nodes/extract_patch/status.json @@ -0,0 +1,6 @@ +{ + "status": "success", + "notes": "Script completed: git diff", + "failure_reason": null, + "timestamp": "2026-03-16T05:36:30.350315+00:00" +} \ No newline at end of file diff --git a/nodes/solve/diff.patch b/nodes/solve/diff.patch new file mode 100644 index 000000000..9c3f2e43c --- /dev/null +++ b/nodes/solve/diff.patch @@ -0,0 +1,3204 @@ +diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py +new file mode 100644 +index 0000000..4c62f36 +--- /dev/null ++++ b/django/db/models/fields/__init__.py +@@ -0,0 +1,2418 @@ ++import collections.abc ++import copy ++import datetime ++import decimal ++import operator ++import uuid ++import warnings ++from base64 import b64decode, b64encode ++from functools import partialmethod, total_ordering ++ ++from django import forms ++from django.apps import apps ++from django.conf import settings ++from django.core import checks, exceptions, validators ++# When the _meta object was formalized, this exception was moved to ++# django.core.exceptions. It is retained here for backwards compatibility ++# purposes. ++from django.core.exceptions import FieldDoesNotExist # NOQA ++from django.db import connection, connections, router ++from django.db.models.constants import LOOKUP_SEP ++from django.db.models.query_utils import DeferredAttribute, RegisterLookupMixin ++from django.utils import timezone ++from django.utils.datastructures import DictWrapper ++from django.utils.dateparse import ( ++ parse_date, parse_datetime, parse_duration, parse_time, ++) ++from django.utils.duration import duration_microseconds, duration_string ++from django.utils.functional import Promise, cached_property ++from django.utils.ipv6 import clean_ipv6_address ++from django.utils.itercompat import is_iterable ++from django.utils.text import capfirst ++from django.utils.translation import gettext_lazy as _ ++ ++__all__ = [ ++ 'AutoField', 'BLANK_CHOICE_DASH', 'BigAutoField', 'BigIntegerField', ++ 'BinaryField', 'BooleanField', 'CharField', 'CommaSeparatedIntegerField', ++ 'DateField', 'DateTimeField', 'DecimalField', 'DurationField', ++ 'EmailField', 'Empty', 'Field', 'FieldDoesNotExist', 'FilePathField', ++ 'FloatField', 'GenericIPAddressField', 'IPAddressField', 'IntegerField', ++ 'NOT_PROVIDED', 'NullBooleanField', 'PositiveIntegerField', ++ 'PositiveSmallIntegerField', 'SlugField', 'SmallAutoField', ++ 'SmallIntegerField', 'TextField', 'TimeField', 'URLField', 'UUIDField', ++] ++ ++ ++class Empty: ++ pass ++ ++ ++class NOT_PROVIDED: ++ pass ++ ++ ++# The values to use for "blank" in SelectFields. Will be appended to the start ++# of most "choices" lists. ++BLANK_CHOICE_DASH = [("", "---------")] ++ ++ ++def _load_field(app_label, model_name, field_name): ++ return apps.get_model(app_label, model_name)._meta.get_field(field_name) ++ ++ ++# A guide to Field parameters: ++# ++# * name: The name of the field specified in the model. ++# * attname: The attribute to use on the model object. This is the same as ++# "name", except in the case of ForeignKeys, where "_id" is ++# appended. ++# * db_column: The db_column specified in the model (or None). ++# * column: The database column for this field. This is the same as ++# "attname", except if db_column is specified. ++# ++# Code that introspects values, or does other dynamic things, should use ++# attname. For example, this gets the primary key value of object "obj": ++# ++# getattr(obj, opts.pk.attname) ++ ++def _empty(of_cls): ++ new = Empty() ++ new.__class__ = of_cls ++ return new ++ ++ ++def return_None(): ++ return None ++ ++ ++@total_ordering ++class Field(RegisterLookupMixin): ++ """Base class for all field types""" ++ ++ # Designates whether empty strings fundamentally are allowed at the ++ # database level. ++ empty_strings_allowed = True ++ empty_values = list(validators.EMPTY_VALUES) ++ ++ # These track each time a Field instance is created. Used to retain order. ++ # The auto_creation_counter is used for fields that Django implicitly ++ # creates, creation_counter is used for all user-specified fields. ++ creation_counter = 0 ++ auto_creation_counter = -1 ++ default_validators = [] # Default set of validators ++ default_error_messages = { ++ 'invalid_choice': _('Value %(value)r is not a valid choice.'), ++ 'null': _('This field cannot be null.'), ++ 'blank': _('This field cannot be blank.'), ++ 'unique': _('%(model_name)s with this %(field_label)s ' ++ 'already exists.'), ++ # Translators: The 'lookup_type' is one of 'date', 'year' or 'month'. ++ # Eg: "Title must be unique for pub_date year" ++ 'unique_for_date': _("%(field_label)s must be unique for " ++ "%(date_field_label)s %(lookup_type)s."), ++ } ++ system_check_deprecated_details = None ++ system_check_removed_details = None ++ ++ # Field flags ++ hidden = False ++ ++ many_to_many = None ++ many_to_one = None ++ one_to_many = None ++ one_to_one = None ++ related_model = None ++ ++ descriptor_class = DeferredAttribute ++ ++ # Generic field type description, usually overridden by subclasses ++ def _description(self): ++ return _('Field of type: %(field_type)s') % { ++ 'field_type': self.__class__.__name__ ++ } ++ description = property(_description) ++ ++ def __init__(self, verbose_name=None, name=None, primary_key=False, ++ max_length=None, unique=False, blank=False, null=False, ++ db_index=False, rel=None, default=NOT_PROVIDED, editable=True, ++ serialize=True, unique_for_date=None, unique_for_month=None, ++ unique_for_year=None, choices=None, help_text='', db_column=None, ++ db_tablespace=None, auto_created=False, validators=(), ++ error_messages=None): ++ self.name = name ++ self.verbose_name = verbose_name # May be set by set_attributes_from_name ++ self._verbose_name = verbose_name # Store original for deconstruction ++ self.primary_key = primary_key ++ self.max_length, self._unique = max_length, unique ++ self.blank, self.null = blank, null ++ self.remote_field = rel ++ self.is_relation = self.remote_field is not None ++ self.default = default ++ self.editable = editable ++ self.serialize = serialize ++ self.unique_for_date = unique_for_date ++ self.unique_for_month = unique_for_month ++ self.unique_for_year = unique_for_year ++ if isinstance(choices, collections.abc.Iterator): ++ choices = list(choices) ++ self.choices = choices ++ self.help_text = help_text ++ self.db_index = db_index ++ self.db_column = db_column ++ self._db_tablespace = db_tablespace ++ self.auto_created = auto_created ++ ++ # Adjust the appropriate creation counter, and save our local copy. ++ if auto_created: ++ self.creation_counter = Field.auto_creation_counter ++ Field.auto_creation_counter -= 1 ++ else: ++ self.creation_counter = Field.creation_counter ++ Field.creation_counter += 1 ++ ++ self._validators = list(validators) # Store for deconstruction later ++ ++ messages = {} ++ for c in reversed(self.__class__.__mro__): ++ messages.update(getattr(c, 'default_error_messages', {})) ++ messages.update(error_messages or {}) ++ self._error_messages = error_messages # Store for deconstruction later ++ self.error_messages = messages ++ ++ def __str__(self): ++ """ ++ Return "app_label.model_label.field_name" for fields attached to ++ models. ++ """ ++ if not hasattr(self, 'model'): ++ return super().__str__() ++ model = self.model ++ app = model._meta.app_label ++ return '%s.%s.%s' % (app, model._meta.object_name, self.name) ++ ++ def __repr__(self): ++ """Display the module, class, and name of the field.""" ++ path = '%s.%s' % (self.__class__.__module__, self.__class__.__qualname__) ++ name = getattr(self, 'name', None) ++ if name is not None: ++ return '<%s: %s>' % (path, name) ++ return '<%s>' % path ++ ++ def check(self, **kwargs): ++ return [ ++ *self._check_field_name(), ++ *self._check_choices(), ++ *self._check_db_index(), ++ *self._check_null_allowed_for_primary_keys(), ++ *self._check_backend_specific_checks(**kwargs), ++ *self._check_validators(), ++ *self._check_deprecation_details(), ++ ] ++ ++ def _check_field_name(self): ++ """ ++ Check if field name is valid, i.e. 1) does not end with an ++ underscore, 2) does not contain "__" and 3) is not "pk". ++ """ ++ if self.name.endswith('_'): ++ return [ ++ checks.Error( ++ 'Field names must not end with an underscore.', ++ obj=self, ++ id='fields.E001', ++ ) ++ ] ++ elif LOOKUP_SEP in self.name: ++ return [ ++ checks.Error( ++ 'Field names must not contain "%s".' % (LOOKUP_SEP,), ++ obj=self, ++ id='fields.E002', ++ ) ++ ] ++ elif self.name == 'pk': ++ return [ ++ checks.Error( ++ "'pk' is a reserved word that cannot be used as a field name.", ++ obj=self, ++ id='fields.E003', ++ ) ++ ] ++ else: ++ return [] ++ ++ def _check_choices(self): ++ if not self.choices: ++ return [] ++ ++ def is_value(value, accept_promise=True): ++ return isinstance(value, (str, Promise) if accept_promise else str) or not is_iterable(value) ++ ++ if is_value(self.choices, accept_promise=False): ++ return [ ++ checks.Error( ++ "'choices' must be an iterable (e.g., a list or tuple).", ++ obj=self, ++ id='fields.E004', ++ ) ++ ] ++ ++ # Expect [group_name, [value, display]] ++ for choices_group in self.choices: ++ try: ++ group_name, group_choices = choices_group ++ except (TypeError, ValueError): ++ # Containing non-pairs ++ break ++ try: ++ if not all( ++ is_value(value) and is_value(human_name) ++ for value, human_name in group_choices ++ ): ++ break ++ except (TypeError, ValueError): ++ # No groups, choices in the form [value, display] ++ value, human_name = group_name, group_choices ++ if not is_value(value) or not is_value(human_name): ++ break ++ ++ # Special case: choices=['ab'] ++ if isinstance(choices_group, str): ++ break ++ else: ++ return [] ++ ++ return [ ++ checks.Error( ++ "'choices' must be an iterable containing " ++ "(actual value, human readable name) tuples.", ++ obj=self, ++ id='fields.E005', ++ ) ++ ] ++ ++ def _check_db_index(self): ++ if self.db_index not in (None, True, False): ++ return [ ++ checks.Error( ++ "'db_index' must be None, True or False.", ++ obj=self, ++ id='fields.E006', ++ ) ++ ] ++ else: ++ return [] ++ ++ def _check_null_allowed_for_primary_keys(self): ++ if (self.primary_key and self.null and ++ not connection.features.interprets_empty_strings_as_nulls): ++ # We cannot reliably check this for backends like Oracle which ++ # consider NULL and '' to be equal (and thus set up ++ # character-based fields a little differently). ++ return [ ++ checks.Error( ++ 'Primary keys must not have null=True.', ++ hint=('Set null=False on the field, or ' ++ 'remove primary_key=True argument.'), ++ obj=self, ++ id='fields.E007', ++ ) ++ ] ++ else: ++ return [] ++ ++ def _check_backend_specific_checks(self, **kwargs): ++ app_label = self.model._meta.app_label ++ for db in connections: ++ if router.allow_migrate(db, app_label, model_name=self.model._meta.model_name): ++ return connections[db].validation.check_field(self, **kwargs) ++ return [] ++ ++ def _check_validators(self): ++ errors = [] ++ for i, validator in enumerate(self.validators): ++ if not callable(validator): ++ errors.append( ++ checks.Error( ++ "All 'validators' must be callable.", ++ hint=( ++ "validators[{i}] ({repr}) isn't a function or " ++ "instance of a validator class.".format( ++ i=i, repr=repr(validator), ++ ) ++ ), ++ obj=self, ++ id='fields.E008', ++ ) ++ ) ++ return errors ++ ++ def _check_deprecation_details(self): ++ if self.system_check_removed_details is not None: ++ return [ ++ checks.Error( ++ self.system_check_removed_details.get( ++ 'msg', ++ '%s has been removed except for support in historical ' ++ 'migrations.' % self.__class__.__name__ ++ ), ++ hint=self.system_check_removed_details.get('hint'), ++ obj=self, ++ id=self.system_check_removed_details.get('id', 'fields.EXXX'), ++ ) ++ ] ++ elif self.system_check_deprecated_details is not None: ++ return [ ++ checks.Warning( ++ self.system_check_deprecated_details.get( ++ 'msg', ++ '%s has been deprecated.' % self.__class__.__name__ ++ ), ++ hint=self.system_check_deprecated_details.get('hint'), ++ obj=self, ++ id=self.system_check_deprecated_details.get('id', 'fields.WXXX'), ++ ) ++ ] ++ return [] ++ ++ def get_col(self, alias, output_field=None): ++ if output_field is None: ++ output_field = self ++ if alias != self.model._meta.db_table or output_field != self: ++ from django.db.models.expressions import Col ++ return Col(alias, self, output_field) ++ else: ++ return self.cached_col ++ ++ @cached_property ++ def cached_col(self): ++ from django.db.models.expressions import Col ++ return Col(self.model._meta.db_table, self) ++ ++ def select_format(self, compiler, sql, params): ++ """ ++ Custom format for select clauses. For example, GIS columns need to be ++ selected as AsText(table.col) on MySQL as the table.col data can't be ++ used by Django. ++ """ ++ return sql, params ++ ++ def deconstruct(self): ++ """ ++ Return enough information to recreate the field as a 4-tuple: ++ ++ * The name of the field on the model, if contribute_to_class() has ++ been run. ++ * The import path of the field, including the class:e.g. ++ django.db.models.IntegerField This should be the most portable ++ version, so less specific may be better. ++ * A list of positional arguments. ++ * A dict of keyword arguments. ++ ++ Note that the positional or keyword arguments must contain values of ++ the following types (including inner values of collection types): ++ ++ * None, bool, str, int, float, complex, set, frozenset, list, tuple, ++ dict ++ * UUID ++ * datetime.datetime (naive), datetime.date ++ * top-level classes, top-level functions - will be referenced by their ++ full import path ++ * Storage instances - these have their own deconstruct() method ++ ++ This is because the values here must be serialized into a text format ++ (possibly new Python code, possibly JSON) and these are the only types ++ with encoding handlers defined. ++ ++ There's no need to return the exact way the field was instantiated this ++ time, just ensure that the resulting field is the same - prefer keyword ++ arguments over positional ones, and omit parameters with their default ++ values. ++ """ ++ # Short-form way of fetching all the default parameters ++ keywords = {} ++ possibles = { ++ "verbose_name": None, ++ "primary_key": False, ++ "max_length": None, ++ "unique": False, ++ "blank": False, ++ "null": False, ++ "db_index": False, ++ "default": NOT_PROVIDED, ++ "editable": True, ++ "serialize": True, ++ "unique_for_date": None, ++ "unique_for_month": None, ++ "unique_for_year": None, ++ "choices": None, ++ "help_text": '', ++ "db_column": None, ++ "db_tablespace": None, ++ "auto_created": False, ++ "validators": [], ++ "error_messages": None, ++ } ++ attr_overrides = { ++ "unique": "_unique", ++ "error_messages": "_error_messages", ++ "validators": "_validators", ++ "verbose_name": "_verbose_name", ++ "db_tablespace": "_db_tablespace", ++ } ++ equals_comparison = {"choices", "validators"} ++ for name, default in possibles.items(): ++ value = getattr(self, attr_overrides.get(name, name)) ++ # Unroll anything iterable for choices into a concrete list ++ if name == "choices" and isinstance(value, collections.abc.Iterable): ++ value = list(value) ++ # Do correct kind of comparison ++ if name in equals_comparison: ++ if value != default: ++ keywords[name] = value ++ else: ++ if value is not default: ++ keywords[name] = value ++ # Work out path - we shorten it for known Django core fields ++ path = "%s.%s" % (self.__class__.__module__, self.__class__.__qualname__) ++ if path.startswith("django.db.models.fields.related"): ++ path = path.replace("django.db.models.fields.related", "django.db.models") ++ elif path.startswith("django.db.models.fields.files"): ++ path = path.replace("django.db.models.fields.files", "django.db.models") ++ elif path.startswith("django.db.models.fields.proxy"): ++ path = path.replace("django.db.models.fields.proxy", "django.db.models") ++ elif path.startswith("django.db.models.fields"): ++ path = path.replace("django.db.models.fields", "django.db.models") ++ # Return basic info - other fields should override this. ++ return (self.name, path, [], keywords) ++ ++ def clone(self): ++ """ ++ Uses deconstruct() to clone a new copy of this Field. ++ Will not preserve any class attachments/attribute names. ++ """ ++ name, path, args, kwargs = self.deconstruct() ++ return self.__class__(*args, **kwargs) ++ ++ def __eq__(self, other): ++ # Needed for @total_ordering ++ if isinstance(other, Field): ++ return self.creation_counter == other.creation_counter ++ return NotImplemented ++ ++ def __lt__(self, other): ++ # This is needed because bisect does not take a comparison function. ++ if isinstance(other, Field): ++ return self.creation_counter < other.creation_counter ++ return NotImplemented ++ ++ def __hash__(self): ++ return hash(self.creation_counter) ++ ++ def __deepcopy__(self, memodict): ++ # We don't have to deepcopy very much here, since most things are not ++ # intended to be altered after initial creation. ++ obj = copy.copy(self) ++ if self.remote_field: ++ obj.remote_field = copy.copy(self.remote_field) ++ if hasattr(self.remote_field, 'field') and self.remote_field.field is self: ++ obj.remote_field.field = obj ++ memodict[id(self)] = obj ++ return obj ++ ++ def __copy__(self): ++ # We need to avoid hitting __reduce__, so define this ++ # slightly weird copy construct. ++ obj = Empty() ++ obj.__class__ = self.__class__ ++ obj.__dict__ = self.__dict__.copy() ++ return obj ++ ++ def __reduce__(self): ++ """ ++ Pickling should return the model._meta.fields instance of the field, ++ not a new copy of that field. So, use the app registry to load the ++ model and then the field back. ++ """ ++ if not hasattr(self, 'model'): ++ # Fields are sometimes used without attaching them to models (for ++ # example in aggregation). In this case give back a plain field ++ # instance. The code below will create a new empty instance of ++ # class self.__class__, then update its dict with self.__dict__ ++ # values - so, this is very close to normal pickle. ++ state = self.__dict__.copy() ++ # The _get_default cached_property can't be pickled due to lambda ++ # usage. ++ state.pop('_get_default', None) ++ return _empty, (self.__class__,), state ++ return _load_field, (self.model._meta.app_label, self.model._meta.object_name, ++ self.name) ++ ++ def get_pk_value_on_save(self, instance): ++ """ ++ Hook to generate new PK values on save. This method is called when ++ saving instances with no primary key value set. If this method returns ++ something else than None, then the returned value is used when saving ++ the new instance. ++ """ ++ if self.default: ++ return self.get_default() ++ return None ++ ++ def to_python(self, value): ++ """ ++ Convert the input value into the expected Python data type, raising ++ django.core.exceptions.ValidationError if the data can't be converted. ++ Return the converted value. Subclasses should override this. ++ """ ++ return value ++ ++ @cached_property ++ def validators(self): ++ """ ++ Some validators can't be created at field initialization time. ++ This method provides a way to delay their creation until required. ++ """ ++ return [*self.default_validators, *self._validators] ++ ++ def run_validators(self, value): ++ if value in self.empty_values: ++ return ++ ++ errors = [] ++ for v in self.validators: ++ try: ++ v(value) ++ except exceptions.ValidationError as e: ++ if hasattr(e, 'code') and e.code in self.error_messages: ++ e.message = self.error_messages[e.code] ++ errors.extend(e.error_list) ++ ++ if errors: ++ raise exceptions.ValidationError(errors) ++ ++ def validate(self, value, model_instance): ++ """ ++ Validate value and raise ValidationError if necessary. Subclasses ++ should override this to provide validation logic. ++ """ ++ if not self.editable: ++ # Skip validation for non-editable fields. ++ return ++ ++ if self.choices is not None and value not in self.empty_values: ++ for option_key, option_value in self.choices: ++ if isinstance(option_value, (list, tuple)): ++ # This is an optgroup, so look inside the group for ++ # options. ++ for optgroup_key, optgroup_value in option_value: ++ if value == optgroup_key: ++ return ++ elif value == option_key: ++ return ++ raise exceptions.ValidationError( ++ self.error_messages['invalid_choice'], ++ code='invalid_choice', ++ params={'value': value}, ++ ) ++ ++ if value is None and not self.null: ++ raise exceptions.ValidationError(self.error_messages['null'], code='null') ++ ++ if not self.blank and value in self.empty_values: ++ raise exceptions.ValidationError(self.error_messages['blank'], code='blank') ++ ++ def clean(self, value, model_instance): ++ """ ++ Convert the value's type and run validation. Validation errors ++ from to_python() and validate() are propagated. Return the correct ++ value if no error is raised. ++ """ ++ value = self.to_python(value) ++ self.validate(value, model_instance) ++ self.run_validators(value) ++ return value ++ ++ def db_type_parameters(self, connection): ++ return DictWrapper(self.__dict__, connection.ops.quote_name, 'qn_') ++ ++ def db_check(self, connection): ++ """ ++ Return the database column check constraint for this field, for the ++ provided connection. Works the same way as db_type() for the case that ++ get_internal_type() does not map to a preexisting model field. ++ """ ++ data = self.db_type_parameters(connection) ++ try: ++ return connection.data_type_check_constraints[self.get_internal_type()] % data ++ except KeyError: ++ return None ++ ++ def db_type(self, connection): ++ """ ++ Return the database column data type for this field, for the provided ++ connection. ++ """ ++ # The default implementation of this method looks at the ++ # backend-specific data_types dictionary, looking up the field by its ++ # "internal type". ++ # ++ # A Field class can implement the get_internal_type() method to specify ++ # which *preexisting* Django Field class it's most similar to -- i.e., ++ # a custom field might be represented by a TEXT column type, which is ++ # the same as the TextField Django field type, which means the custom ++ # field's get_internal_type() returns 'TextField'. ++ # ++ # But the limitation of the get_internal_type() / data_types approach ++ # is that it cannot handle database column types that aren't already ++ # mapped to one of the built-in Django field types. In this case, you ++ # can implement db_type() instead of get_internal_type() to specify ++ # exactly which wacky database column type you want to use. ++ data = self.db_type_parameters(connection) ++ try: ++ return connection.data_types[self.get_internal_type()] % data ++ except KeyError: ++ return None ++ ++ def rel_db_type(self, connection): ++ """ ++ Return the data type that a related field pointing to this field should ++ use. For example, this method is called by ForeignKey and OneToOneField ++ to determine its data type. ++ """ ++ return self.db_type(connection) ++ ++ def cast_db_type(self, connection): ++ """Return the data type to use in the Cast() function.""" ++ db_type = connection.ops.cast_data_types.get(self.get_internal_type()) ++ if db_type: ++ return db_type % self.db_type_parameters(connection) ++ return self.db_type(connection) ++ ++ def db_parameters(self, connection): ++ """ ++ Extension of db_type(), providing a range of different return values ++ (type, checks). This will look at db_type(), allowing custom model ++ fields to override it. ++ """ ++ type_string = self.db_type(connection) ++ check_string = self.db_check(connection) ++ return { ++ "type": type_string, ++ "check": check_string, ++ } ++ ++ def db_type_suffix(self, connection): ++ return connection.data_types_suffix.get(self.get_internal_type()) ++ ++ def get_db_converters(self, connection): ++ if hasattr(self, 'from_db_value'): ++ return [self.from_db_value] ++ return [] ++ ++ @property ++ def unique(self): ++ return self._unique or self.primary_key ++ ++ @property ++ def db_tablespace(self): ++ return self._db_tablespace or settings.DEFAULT_INDEX_TABLESPACE ++ ++ def set_attributes_from_name(self, name): ++ self.name = self.name or name ++ self.attname, self.column = self.get_attname_column() ++ self.concrete = self.column is not None ++ if self.verbose_name is None and self.name: ++ self.verbose_name = self.name.replace('_', ' ') ++ ++ def contribute_to_class(self, cls, name, private_only=False): ++ """ ++ Register the field with the model class it belongs to. ++ ++ If private_only is True, create a separate instance of this field ++ for every subclass of cls, even if cls is not an abstract model. ++ """ ++ self.set_attributes_from_name(name) ++ self.model = cls ++ cls._meta.add_field(self, private=private_only) ++ if self.column: ++ # Don't override classmethods with the descriptor. This means that ++ # if you have a classmethod and a field with the same name, then ++ # such fields can't be deferred (we don't have a check for this). ++ if not getattr(cls, self.attname, None): ++ setattr(cls, self.attname, self.descriptor_class(self)) ++ if self.choices is not None: ++ setattr(cls, 'get_%s_display' % self.name, ++ partialmethod(cls._get_FIELD_display, field=self)) ++ ++ def get_filter_kwargs_for_object(self, obj): ++ """ ++ Return a dict that when passed as kwargs to self.model.filter(), would ++ yield all instances having the same value for this field as obj has. ++ """ ++ return {self.name: getattr(obj, self.attname)} ++ ++ def get_attname(self): ++ return self.name ++ ++ def get_attname_column(self): ++ attname = self.get_attname() ++ column = self.db_column or attname ++ return attname, column ++ ++ def get_internal_type(self): ++ return self.__class__.__name__ ++ ++ def pre_save(self, model_instance, add): ++ """Return field's value just before saving.""" ++ return getattr(model_instance, self.attname) ++ ++ def get_prep_value(self, value): ++ """Perform preliminary non-db specific value checks and conversions.""" ++ if isinstance(value, Promise): ++ value = value._proxy____cast() ++ return value ++ ++ def get_db_prep_value(self, value, connection, prepared=False): ++ """ ++ Return field's value prepared for interacting with the database backend. ++ ++ Used by the default implementations of get_db_prep_save(). ++ """ ++ if not prepared: ++ value = self.get_prep_value(value) ++ return value ++ ++ def get_db_prep_save(self, value, connection): ++ """Return field's value prepared for saving into a database.""" ++ return self.get_db_prep_value(value, connection=connection, prepared=False) ++ ++ def has_default(self): ++ """Return a boolean of whether this field has a default value.""" ++ return self.default is not NOT_PROVIDED ++ ++ def get_default(self): ++ """Return the default value for this field.""" ++ return self._get_default() ++ ++ @cached_property ++ def _get_default(self): ++ if self.has_default(): ++ if callable(self.default): ++ return self.default ++ return lambda: self.default ++ ++ if not self.empty_strings_allowed or self.null and not connection.features.interprets_empty_strings_as_nulls: ++ return return_None ++ return str # return empty string ++ ++ def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_choices_to=None, ordering=()): ++ """ ++ Return choices with a default blank choices included, for use ++ as