[ { "id": "django_gen_01", "repo": "django", "question": "What is the full class hierarchy and architectural design behind how the Polygon geometry class supports list-like ring mutation through GEOS C bindings?", "category": "what", "sub_type": "architecture_exploration", "gold_answer": "The `Polygon` class in `django/contrib/gis/geos/polygon.py` is part of a multi-layered architecture that combines GEOS C library bindings with Python's list-like mutation capabilities.\n\n**Class Hierarchy:**\n`Polygon` \u2192 `GEOSGeometry` \u2192 `GEOSGeometryBase` (+ `ListMixin` via MRO) \u2192 `GEOSBase`\n\nSpecifically, `GEOSGeometry` is defined as `class GEOSGeometry(GEOSGeometryBase, ListMixin)` in geometry.py, giving Polygon all list mutation methods (append, extend, pop, sort, etc.) from `ListMixin`.\n\n**Key architectural details:**\n\n1. **_minlength = 1** on Polygon, meaning a Polygon must have at least 1 ring (the exterior ring). This is enforced by `ListMixin._rebuild()` which checks `newLen < self._minlength`.\n\n2. **_set_single and _assign_extended_slice** are explicitly set to the rebuild variants: `_set_single = GEOSGeometry._set_single_rebuild` and `_assign_extended_slice = GEOSGeometry._assign_extended_slice_rebuild`. This means any single-ring mutation triggers a full polygon rebuild via `_set_slice` \u2192 `_set_list`, which destroys the old GEOS geometry pointer and creates a new one.\n\n3. **_create_polygon** handles both empty polygons and populated ones. For empty polygons (length=0), it calls `capi.create_empty_polygon()` which maps to the GEOS C function `GEOSGeom_createEmptyPolygon`. For non-empty ones, it clones all ring pointers using `_clone()`, creates a ctypes array `(GEOM_PTR * n_holes)` for the holes, and calls `capi.create_polygon(shell, holes_param, n_holes)` which maps to `GEOSGeom_createPolygon`.\n\n4. **_clone method** handles two types of inputs: raw `GEOM_PTR` ctypes pointers (calling `capi.geom_clone(g)`) and Python GEOSGeometry wrapper objects (calling `capi.geom_clone(g.ptr)`).\n\n5. **_get_single_external** returns a full `GEOSGeometry` object constructed from a cloned pointer with the parent's SRID, while **_get_single_internal** returns a raw GEOM_PTR without cloning. The external ring uses `capi.get_extring` and interior rings use `capi.get_intring` with `index - 1` offset.\n\n6. **from_bbox** has a type-checking optimization: if any bbox value is not a float or int, it falls back to WKT string parsing via `GEOSGeometry(\"POLYGON(...)\")`. Otherwise it constructs directly from coordinate tuples.\n\n7. **LinearRing** (used as ring type) is a subclass of `LineString` with `_minlength = 4` and `_init_func = capi.create_linearring`. The `_construct_ring` method on Polygon returns an existing LinearRing directly if the input is already a LinearRing instance, otherwise tries to construct one, raising `TypeError` on failure.\n\n8. **_set_list** preserves the SRID during mutation: it saves the current SRID, replaces the pointer via `_create_polygon`, restores SRID if it was set, then destroys the old geometry pointer via `capi.destroy_geom`.\n\n9. The GEOS C function factories use **lazy loading** via `GEOSFuncFactory` (libgeos.py), which uses `@cached_property` on `func` to defer loading until first call. `GEOM_PTR` is `POINTER(GEOSGeom_t)` where `GEOSGeom_t` is an opaque ctypes `Structure`.\n\n10. The `__init__` logic detects `Polygon(shell, (hole1, hole2))` form: if there's exactly 1 hole argument that is a tuple/list, and its first element is a LinearRing, it unpacks that tuple as the hole list.", "rubric": [ "Identifies the class hierarchy: Polygon \u2192 GEOSGeometry \u2192 (GEOSGeometryBase + ListMixin) \u2192 GEOSBase/CPointerBase", "Explains that GEOSGeometry inherits from both GEOSGeometryBase and ListMixin, giving Polygon list mutation methods like append, extend, pop, sort", "Notes that Polygon sets _minlength = 1 (requiring at least one ring), enforced by ListMixin._rebuild", "Explains that _set_single and _assign_extended_slice are set to the rebuild variants, meaning any ring mutation triggers a full polygon rebuild via _set_list \u2192 _create_polygon", "Describes _create_polygon: handles empty polygons via capi.create_empty_polygon, and populated ones by cloning ring pointers and creating a ctypes array (GEOM_PTR * n_holes) for holes", "Describes _clone method: handles both raw GEOM_PTR (calls capi.geom_clone(g)) and GEOSGeometry wrapper objects (calls capi.geom_clone(g.ptr))", "Explains _get_single_external returns a GEOSGeometry from a cloned pointer with SRID, while _get_single_internal returns a raw GEOM_PTR; interior rings use index-1 offset", "Mentions _set_list preserves SRID during mutation: saves SRID, replaces pointer, restores SRID, then destroys old geometry", "Notes that LinearRing (used for rings) is a LineString subclass with _minlength=4 and _init_func=capi.create_linearring", "Mentions GEOSFuncFactory uses @cached_property for lazy loading of GEOS C functions, and GEOM_PTR is POINTER(GEOSGeom_t) where GEOSGeom_t is an opaque Structure" ], "key_files": [ "django/contrib/gis/geos/polygon.py", "django/contrib/gis/geos/geometry.py", "django/contrib/gis/geos/mutable_list.py", "django/contrib/gis/geos/linestring.py", "django/contrib/gis/geos/prototypes/geom.py", "django/contrib/gis/geos/libgeos.py" ], "source_doc": "[docstring: django/contrib/gis/geos/polygon.py] django.contrib.gis.geos.polygon.Polygon\ndjango.contrib.gis.geos.polygon.Polygon.__init__:\n Initialize on an exterior ring and a sequence of holes (both\n instances may be either LinearRing instances, or a tuple/list\n that may be constructed into a LinearRing).\n\n Examples of initialization, where shell, hole1, and hole2 are\n valid LinearRing geometries:\n >>> from django.contrib.gis.geos import LinearRing, Polygon\n >>> shell = hole1 = hole2 = LinearRing()\n >>> poly = Polygon(shell, hole1, hole2)\n >>> poly = Polygon(shell, (hole1, hole2))\n\n >>> # Example where a tuple parameters are used:\n >>> poly = Polygon(((0, 0), (0, 10), (10, 10), (10, 0), (0, 0)),\n ... ((4, 4), (4, 6), (6, 6), (6, 4), (4, 4)))\n\ndjango.contrib.gis.geos.polygon.Polygon.__iter__:\n Iterate over each ring in the polygon.\n\ndjango.contrib.gis.geos.polygon.Polygon.__len__:\n Return the number of rings in this Polygon.\n\ndjango.contrib.gis.geos.polygon.Polygon.from_bbox:\n Construct a Polygon from a bounding box (4-tuple).\n\ndjango.contrib.gis.geos.polygon.Polygon._construct_ring:\n Try to construct a ring from the given parameter.\n\ndjango.contrib.gis.geos.polygon.Polygon._get_single_internal:\n Return the ring at the specified index. The first index, 0, will\n always return the exterior ring. Indices > 0 will return the\n interior ring at the given index (e.g., poly[1] and poly[2] would\n return the first and second interior ring, respectively).\n\n CAREFUL: Internal/External are not the same as Interior/Exterior!\n Return a pointer from the existing geometries for use internally by the\n object's methods. _get_single_external() returns a clone of the same\n geometry for use by external code.\n\ndjango.contrib.gis.geos.polygon.Polygon.num_interior_rings:\n Return the number of interior rings.\n\ndjango.contrib.gis.geos.polygon.Polygon._get_ext_ring:\n Get the exterior ring of the Polygon.\n\ndjango.contrib.gis.geos.polygon.Polygon._set_ext_ring:\n Set the exterior ring of the Polygon.\n\ndjango.contrib.gis.geos.polygon.Polygon.tuple:\n Get the tuple for each ring in this Polygon.\n\ndjango.contrib.gis.geos.polygon.Polygon.kml:\n Return the KML representation of this Polygon.", "verification_verdict": "warn", "verification_issues": [ "The answer contains extensive implementation details (line numbers, internal method implementations, ctypes details, etc.) that go far beyond what the documentation provides. These cannot be verified from the documentation alone.", "Point 10 describes backward-compatibility logic for `Polygon(shell, (hole1, hole2))` form. The documentation shows this as a valid initialization example (`>>> poly = Polygon(shell, (hole1, hole2))`), so the claim about detecting this form is consistent with the docs, though the specific implementation details (lines 37-43, checking first element is LinearRing) cannot be verified.", "The class hierarchy claim (`Polygon \u2192 GEOSGeometry \u2192 GEOSGeometryBase (+ ListMixin via MRO) \u2192 GEOSBase \u2192 CPointerBase`) cannot be verified from the documentation but is plausible code-level detail.", "The documentation shows `poly = Polygon(shell, hole1, hole2)` and `poly = Polygon(shell, (hole1, hole2))` as both valid forms of initialization, which is consistent with the answer's point 10.", "The `_get_single_internal` description in the answer (returns raw GEOM_PTR without cloning, uses get_extring/get_intring with index-1 offset) is consistent with the doc's warning about Internal/External vs Interior/Exterior and the note about returning a pointer from existing geometries." ], "strip_verify_leakage": 0.05, "strip_verify_summary": "Nearly all claims are verifiable from stripped code; minor adjustments to remove 'CPointerBase' (not shown) and 'backward-compatibility' rationale characterization.", "generation_status": "completed", "generation_error": null }, { "id": "django_gen_04", "repo": "django", "question": "How does Django's SpatialReference class wrap the OGR C library, from pointer management and initialization through the ctypes prototype layer?", "category": "how", "sub_type": "system_design", "gold_answer": "The `SpatialReference` class in Django's GDAL wrapper is designed as a ctypes-based wrapper around the OGR/GDAL C library's `OGRSpatialReference` object. Here's how the system is designed:\n\n## Inheritance and Memory Management\n\n`SpatialReference` inherits from `GDALBase`, which inherits from `CPointerBase` (in `django/contrib/gis/ptr.py`). `CPointerBase` provides a `ptr` property that validates the underlying C pointer is not NULL before returning it (raising the class's `null_ptr_exception_class` if it is). `GDALBase` sets `null_ptr_exception_class = GDALException`. The `CPointerBase.__del__` method automatically calls the destructor when the object is garbage collected, with a try/except catching `(AttributeError, ImportError, TypeError)` in case parts are already garbage collected.\n\nThe `SpatialReference` destructor is `capi.release_srs`, which calls `OSRRelease` (not `OSRDestroySpatialReference`), meaning it uses reference counting.\n\n## Initialization Logic\n\nThe `__init__` method accepts an `axis_order` parameter (defaulting to `AxisOrder.TRADITIONAL = 0`). It validates this is either `None` or an `AxisOrder` instance. The method handles multiple input types:\n1. If `srs_type='wkt'`, it creates a new blank SRS pointer via `OSRNewSpatialReference(b\"\")`, imports the WKT, then sets the axis strategy.\n2. If the input is a string that can be parsed as an integer (e.g., '4326'), it prepends 'EPSG:' to make it valid user input.\n3. If the input is an integer, the srs_type is set to 'epsg'.\n4. If the input is already a `c_void_p` (the ptr_type), it's treated as a raw OGR pointer.\n\nAfter pointer creation, it calls `capi.set_axis_strategy` (wrapping `OSRSetAxisMappingStrategy`) with `AxisOrder.TRADITIONAL` to ensure traditional GIS longitude/latitude ordering.\n\n## ctypes Prototype Generation Layer\n\nThe prototypes in `django/contrib/gis/gdal/prototypes/srs.py` use generator functions from `prototypes/generation.py`:\n- `srs_output()` sets `restype=c_void_p` and errcheck to `check_srs` (which raises `SRSException` on NULL pointer)\n- `void_output()` sets `restype=c_int` and errcheck to `check_errcode` (which calls `check_err` to map OGR error codes to exceptions)\n- `string_output()` frees memory via `lgdal.VSIFree` after extracting the string value\n- `const_string_output()` does NOT free the pointer (used for `get_attr_value`, `get_auth_name`, `get_auth_code`)\n- `units_func()` uses `double_output` with `strarg=True`, triggering the `check_str_arg` errcheck that returns both the double value and the decoded string pointer value as a tuple\n\n## Export Format Specifics\n\nThe WKT export (`to_wkt`) decodes with 'utf-8', the PROJ export (`to_proj`) decodes with 'ascii', and the XML export (`to_xml`) decodes with 'utf-8'. The `to_pretty_wkt` and `to_xml` functions use `offset=-2` meaning the string pointer is the second-to-last argument.\n\n## Windows-Specific Design\n\nOn Windows (`os.name == 'nt'`), certain OSR functions use STDCALL convention, so the library is loaded both as `CDLL` (for `lgdal`) and `WinDLL` (for `lwingdal`). The `std_call()` function returns the appropriate version based on OS. Functions like `OSRClone`, `OSRNewSpatialReference`, `OSRExportToWkt`, `OSRImportFromEPSG`, `OSRSetFromUserInput`, and `OCTNewCoordinateTransformation` use `std_call`, while functions like `OSRRelease`, `OSRValidate`, `OSRGetSemiMajor`, and `OSRIsGeographic` use `lgdal` directly.\n\n## Error Handling\n\nOGR error code 7 specifically maps to `(SRSException, \"Unsupported SRS.\")` in the `OGRERR_DICT`. The `check_err` function raises the appropriate exception class based on the returned integer code.\n\n## CoordTransform\n\n`CoordTransform` also inherits from `GDALBase`, uses `capi.destroy_ct` (calling `OCTDestroyCoordinateTransformation`) as its destructor, stores source/target names as `_srs1_name` and `_srs2_name`, and passes `source._ptr`/`target._ptr` (the raw underlying pointer, not the property) to `capi.new_ct`. It's used in geometry transforms, the GeoJSON serializer (cached per SRID), and `LayerMapping`.\n\n## The `clone()` method preserves axis_order\n\nWhen cloning, `SpatialReference.clone()` passes `axis_order=self.axis_order` to the constructor, ensuring the clone maintains the same axis ordering strategy.", "rubric": [ "Explains the inheritance chain: SpatialReference \u2192 GDALBase \u2192 CPointerBase, where CPointerBase provides the ptr property that validates non-NULL pointers and GDALBase sets null_ptr_exception_class to GDALException", "Describes CPointerBase.__del__ calling the destructor with try/except catching (AttributeError, ImportError, TypeError) for garbage collection safety", "Notes that SpatialReference uses capi.release_srs (OSRRelease, reference counting) as its destructor, not OSRDestroySpatialReference", "Explains __init__ handles multiple input types: WKT (creates blank pointer then imports), string integers (prepend 'EPSG:'), plain integers (set srs_type='epsg'), and raw c_void_p pointers", "Mentions the AxisOrder enum (TRADITIONAL=0, AUTHORITY=1), the axis_order parameter validation, and capi.set_axis_strategy call to OSRSetAxisMappingStrategy", "Describes the ctypes prototype generation layer: srs_output sets restype=c_void_p with check_srs errcheck, void_output sets restype=c_int with check_errcode, string_output frees memory via VSIFree, const_string_output does NOT free the pointer", "Explains units_func uses double_output with strarg=True, triggering check_str_arg which returns both the double value and decoded string as a tuple", "Notes the Windows-specific design: CDLL (lgdal) vs WinDLL (lwingdal) for STDCALL convention, with std_call() selecting the appropriate one", "Explains CoordTransform: also inherits GDALBase, uses destroy_ct (OCTDestroyCoordinateTransformation), passes source._ptr/target._ptr (raw pointer, not property), stores _srs1_name/_srs2_name", "Notes that clone() preserves axis_order by passing axis_order=self.axis_order to the constructor" ], "key_files": [ "django/contrib/gis/gdal/srs.py", "django/contrib/gis/gdal/prototypes/srs.py", "django/contrib/gis/gdal/prototypes/generation.py", "django/contrib/gis/ptr.py", "django/contrib/gis/gdal/prototypes/errcheck.py", "django/contrib/gis/gdal/libgdal.py", "django/contrib/gis/gdal/error.py" ], "source_doc": "[docstring: django/contrib/gis/gdal/srs.py] django.contrib.gis.gdal.srs.SpatialReference\ndjango.contrib.gis.gdal.srs.SpatialReference:\n A wrapper for the OGRSpatialReference object. According to the GDAL web\n site, the SpatialReference object \"provide[s] services to represent\n coordinate systems (projections and datums) and to transform between them.\"\n\ndjango.contrib.gis.gdal.srs.SpatialReference.__init__:\n Create a GDAL OSR Spatial Reference object from the given input.\n The input may be string of OGC Well Known Text (WKT), an integer\n EPSG code, a PROJ string, and/or a projection \"well known\" shorthand\n string (one of 'WGS84', 'WGS72', 'NAD27', 'NAD83').\n\ndjango.contrib.gis.gdal.srs.SpatialReference.__getitem__:\n Return the value of the given string attribute node, None if the node\n doesn't exist. Can also take a tuple as a parameter, (target, child),\n where child is the index of the attribute in the WKT. For example:\n\n >>> wkt = (\n ... 'GEOGCS[\"WGS 84\",'\n ... ' DATUM[\"WGS_1984, ... AUTHORITY[\"EPSG\",\"4326\"]'\n ... ']'\n ... )\n >>> srs = SpatialReference(wkt) # could also use 'WGS84', or 4326\n >>> print(srs['GEOGCS'])\n WGS 84\n >>> print(srs['DATUM'])\n WGS_1984\n >>> print(srs['AUTHORITY'])\n EPSG\n >>> print(srs['AUTHORITY', 1]) # The authority value\n 4326\n >>> print(srs['TOWGS84', 4]) # the fourth value in this wkt\n 0\n >>> # For the units authority, have to use the pipe symbole.\n >>> print(srs['UNIT|AUTHORITY'])\n EPSG\n >>> print(srs['UNIT|AUTHORITY', 1]) # The authority value for the units\n 9122\n\ndjango.contrib.gis.gdal.srs.SpatialReference.__str__:\n Use 'pretty' WKT.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.attr_value:\n The attribute value for the given target node (e.g. 'PROJCS'). The\n index keyword specifies an index of the child node to return.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.auth_name:\n Return the authority name for the given string target node.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.auth_code:\n Return the authority code for the given string target node.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.clone:\n Return a clone of this SpatialReference object.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.from_esri:\n Morph this SpatialReference from ESRI's format to EPSG.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.identify_epsg:\n This method inspects the WKT of this SpatialReference, and will\n add EPSG authority nodes where an EPSG identifier is applicable.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.to_esri:\n Morph this SpatialReference to ESRI's format.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.validate:\n Check to see if the given spatial reference is valid.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.name:\n Return the name of this Spatial Reference.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.srid:\n Return the SRID of top-level authority, or None if undefined.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.linear_name:\n Return the name of the linear units.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.linear_units:\n Return the value of the linear units.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.angular_name:\n Return the name of the angular units.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.angular_units:\n Return the value of the angular units.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.units:\n Return a 2-tuple of the units value and the units name. Automatically\n determine whether to return the linear or angular units.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.ellipsoid:\n Return a tuple of the ellipsoid parameters:\n (semimajor axis, semiminor axis, and inverse flattening)\n\ndjango.contrib.gis.gdal.srs.SpatialReference.semi_major:\n Return the Semi Major Axis for this Spatial Reference.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.semi_minor:\n Return the Semi Minor Axis for this Spatial Reference.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.inverse_flattening:\n Return the Inverse Flattening for this Spatial Reference.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.geographic:\n Return True if this SpatialReference is geographic\n (root node is GEOGCS).\n\ndjango.contrib.gis.gdal.srs.SpatialReference.local:\n Return True if this SpatialReference is local (root node is LOCAL_CS).\n\ndjango.contrib.gis.gdal.srs.SpatialReference.projected:\n Return True if this SpatialReference is a projected coordinate system\n (root node is PROJCS).\n\ndjango.contrib.gis.gdal.srs.SpatialReference.import_epsg:\n Import the Spatial Reference from the EPSG code (an integer).\n\ndjango.contrib.gis.gdal.srs.SpatialReference.import_proj:\n Import the Spatial Reference from a PROJ string.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.import_user_input:\n Import the Spatial Reference from the given user input string.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.import_wkt:\n Import the Spatial Reference from OGC WKT (string)\n\ndjango.contrib.gis.gdal.srs.SpatialReference.import_xml:\n Import the Spatial Reference from an XML string.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.wkt:\n Return the WKT representation of this Spatial Reference.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.pretty_wkt:\n Return the 'pretty' representation of the WKT.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.proj:\n Return the PROJ representation for this Spatial Reference.\n\ndjango.contrib.gis.gdal.srs.SpatialReference.proj4:\n Alias for proj().\n\ndjango.contrib.gis.gdal.srs.SpatialReference.xml:\n Return the XML representation of this Spatial Reference.", "verification_verdict": "warn", "verification_issues": [ "The answer contains extensive implementation details (ctypes prototypes, Windows-specific design, memory management internals, CoordTransform details, error handling specifics) that are not present in the provided documentation. These appear to be extrapolations from actual source code knowledge rather than from the provided doc chunk.", "The documentation states that __init__ accepts 'string of OGC Well Known Text (WKT), an integer EPSG code, a PROJ string, and/or a projection well known shorthand string', while the answer adds details about axis_order parameter, c_void_p handling, and string-to-integer parsing that aren't in the doc.", "The answer's claim about clone() preserving axis_order is not mentioned in the documentation, which only says 'Return a clone of this SpatialReference object.'", "The documentation does not mention AxisOrder, CPointerBase, GDALBase, or any of the inheritance hierarchy described in the answer.", "The answer discusses CoordTransform extensively, but the provided documentation chunk only covers SpatialReference." ], "strip_verify_leakage": null, "strip_verify_summary": null, "generation_status": "completed", "generation_error": null }, { "id": "django_gen_03", "repo": "django", "question": "Where does OGRGeometry data flow when converting between GDAL and GEOS geometry systems, and how is memory managed?", "category": "where", "sub_type": "data_control_flow", "gold_answer": "The OGRGeometry data flows through a multi-layered architecture connecting GDAL C library calls to Python objects and bridging to the GEOS geometry system:\n\n**Data flow during construction (OGRGeometry.__init__):**\n1. Input is parsed using regex patterns imported from `django/contrib/gis/geometry.py`: `hex_regex`, `wkt_regex`, and `json_regex`.\n2. The geometry pointer is obtained via ctypes calls to GDAL C functions (`OGR_G_CreateFromWkt`, `OGR_G_CreateFromWkbEx`, `OGR_G_CreateGeometryFromJson`, `OGR_G_CreateGeometry`).\n3. The pointer is stored via `CPointerBase.ptr` setter (in `django/contrib/gis/ptr.py`), which validates it is `c_void_p` or None.\n4. The class is dynamically reassigned using the `GEO_CLASSES` dictionary lookup on `self.geom_type.num`, switching `self.__class__` to Point, LineString, Polygon, etc.\n\n**Data flow between OGR and GEOS (bidirectional WKB bridge):**\n- `OGRGeometry.geos` property: calls `self._geos_ptr()` which calls `GEOSGeometry._from_wkb(self.wkb)` \u2014 the WKB binary format is the interchange format.\n- `GEOSGeometry.ogr` property (in `django/contrib/gis/geos/geometry.py`): calls `gdal.OGRGeometry(self._ogr_ptr(), self.srs)` where `_ogr_ptr()` calls `gdal.OGRGeometry._from_wkb(self.wkb)` \u2014 again using WKB.\n\n**Data flow during transform:**\n- `OGRGeometry.transform()` accepts CoordTransform, SpatialReference, int, or str. For CoordTransform it calls `OGR_G_Transform`, for others it calls `OGR_G_TransformTo`.\n- `CoordTransform.__init__` (in srs.py) requires two SpatialReference objects and calls `capi.new_ct(source._ptr, target._ptr)`.\n\n**Memory management:**\n- `CPointerBase.__del__` calls `self.destructor(self.ptr)` \u2014 for OGRGeometry the destructor is `capi.destroy_geom` which wraps `OGR_G_DestroyGeometry`.\n- `GDALBase` (in base.py) inherits from `CPointerBase`.\n\n**The OGRGeomType._types mapping** covers types 0-12 (basic), 15-17, 100-102, 1008-1017 (Z variants), 2001-2017 (M variants), 3001-3017 (ZM variants), and types with wkb25bit offset (-2147483648 + type for 25D variants). The `GEO_CLASSES` dictionary maps these type numbers to corresponding Python geometry classes.", "rubric": [ "Explains that WKB (Well-Known Binary) is the interchange format between OGR and GEOS in both directions", "Describes OGRGeometry._geos_ptr() calling GEOSGeometry._from_wkb(self.wkb) for OGR-to-GEOS conversion", "Describes GEOSGeometry.ogr or transform using OGRGeometry._from_wkb for GEOS-to-OGR conversion", "Mentions that OGRGeometry.__init__ uses regex patterns (hex_regex, wkt_regex, json_regex) to parse input and calls appropriate GDAL C functions", "Explains the dynamic class reassignment via GEO_CLASSES dictionary lookup on geom_type.num, switching __class__ to Point, LineString, etc.", "Describes CPointerBase (in ptr.py) managing pointer storage with validation and __del__ calling self.destructor(self.ptr) for cleanup", "Mentions that GDALBase inherits from CPointerBase and OGRGeometry's destructor is capi.destroy_geom" ], "key_files": [ "django/contrib/gis/gdal/geometries.py", "django/contrib/gis/gdal/geomtype.py", "django/contrib/gis/ptr.py", "django/contrib/gis/gdal/prototypes/geom.py", "django/contrib/gis/gdal/srs.py", "django/contrib/gis/geos/geometry.py" ], "source_doc": "[docstring: django/contrib/gis/gdal/geometries.py] django.contrib.gis.gdal.geometries\nThe OGRGeometry is a wrapper for using the OGR Geometry class\n(see https://gdal.org/api/ogrgeometry_cpp.html#_CPPv411OGRGeometry).\nOGRGeometry may be instantiated when reading geometries from OGR Data Sources\n(e.g. SHP files), or when given OGC WKT (a string).\n\nWhile the 'full' API is not present yet, the API is \"pythonic\" unlike\nthe traditional and \"next-generation\" OGR Python bindings. One major\nadvantage OGR Geometries have over their GEOS counterparts is support\nfor spatial reference systems and their transformation.\n\nExample:\n >>> from django.contrib.gis.gdal import (\n ... OGRGeometry, OGRGeomType, SpatialReference\n ... )\n >>> wkt1, wkt2 = 'POINT(-90 30)', 'POLYGON((0 0, 5 0, 5 5, 0 5)'\n >>> pnt = OGRGeometry(wkt1)\n >>> print(pnt)\n POINT (-90 30)\n >>> mpnt = OGRGeometry(OGRGeomType('MultiPoint'), SpatialReference('WGS84'))\n >>> mpnt.add(wkt1)\n >>> mpnt.add(wkt1)\n >>> print(mpnt)\n MULTIPOINT (-90 30,-90 30)\n >>> print(mpnt.srs.name)\n WGS 84\n >>> print(mpnt.srs.proj)\n +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs\n >>> mpnt.transform(SpatialReference('NAD27'))\n >>> print(mpnt.proj)\n +proj=longlat +ellps=clrk66 +datum=NAD27 +no_defs\n >>> print(mpnt)\n MULTIPOINT (-89.99993037860248 29.99979788655764,-89.99993037860248\n 29.99979788655764)\n\n The OGRGeomType class is to make it easy to specify an OGR geometry type:\n >>> from django.contrib.gis.gdal import OGRGeomType\n >>> gt1 = OGRGeomType(3) # Using an integer for the type\n >>> gt2 = OGRGeomType('Polygon') # Using a string\n >>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive\n >>> # Equivalence works w/non-OGRGeomType objects:\n >>> print(gt1 == 3, gt1 == 'Polygon')\n True True", "verification_verdict": "warn", "verification_issues": [ "The vast majority of the answer's claims (about internal implementation details like regex patterns, ctypes calls, CPointerBase, GEO_CLASSES mapping, memory management, WKB bridge, etc.) go far beyond what the provided documentation contains. The documentation is a module-level docstring showing usage examples, not implementation details.", "These implementation claims cannot be verified against the provided documentation chunk, but they are plausible code-level details that could be derived from reading the actual source code.", "The answer does not contradict anything explicitly stated in the documentation.", "The documentation mentions transform() with SpatialReference('NAD27'), and the answer's description of transform() accepting SpatialReference/CoordTransform/int/str is consistent with the documented usage but extends beyond what is shown.", "The wkb25bit offset described as '-2147483648 + type' is a plausible implementation detail (0x80000000 is the wkb25DBit flag in OGR) but cannot be verified from the provided doc." ], "strip_verify_leakage": 0.1, "strip_verify_summary": "Most claims are verifiable from stripped code; minor adjustments needed for line numbers, unshown file contents, and regex pattern descriptions.", "generation_status": "completed", "generation_error": null }, { "id": "django_gen_05", "repo": "django", "question": "What is the full class hierarchy and architectural design of Django's GEOS Point class, including how it manages coordinates through the C API?", "category": "what", "sub_type": "concept_definition", "gold_answer": "The `Point` class in Django's GIS module (`django/contrib/gis/geos/point.py`) is a geometry class that represents a 2D or 3D point. It inherits from `GEOSGeometry`, which itself inherits from both `GEOSGeometryBase` and `ListMixin`. `GEOSGeometryBase` extends `GEOSBase`, which extends `CPointerBase` from `django/contrib/gis/ptr.py` \u2014 the lowest-level base that manages a C pointer (`_ptr`) with null-pointer checking and automatic destructor invocation via `__del__`.\n\n**Key architectural details:**\n\n1. **Class attributes**: `Point` sets `_minlength = 2`, `_maxlength = 3`, and `has_cs = True`. The `_minlength` and `_maxlength` come from the `ListMixin` protocol, constraining valid coordinate counts. `has_cs = True` overrides the default `False` in `GEOSGeometryBase`, signaling that this geometry type has a coordinate sequence.\n\n2. **Coordinate sequence (`_cs`)**: During `_post_init()` (defined in `GEOSGeometryBase`), when `has_cs` is `True`, a `GEOSCoordSeq` object is created by calling `capi.get_cs(self.ptr)` and wrapping the result with `GEOSCoordSeq(ptr, self.hasz)`. All coordinate access (x, y, z properties) delegates to this `GEOSCoordSeq` instance via `getOrdinate` and `setOrdinate` methods, which in turn call the GEOS C library functions `GEOSCoordSeq_getOrdinate` and `GEOSCoordSeq_setOrdinate`.\n\n3. **Point creation via C API**: `_create_point` is a `@classmethod` that creates a coordinate sequence using `capi.create_cs(c_uint(1), c_uint(ndim))` (calling GEOS's `GEOSCoordSeq_create` with size=1), sets coordinates using `capi.cs_setx`, `capi.cs_sety`, and optionally `capi.cs_setz`, then calls `capi.create_point(cs)` which wraps the GEOS C function `GEOSGeom_createPoint`. For empty points, `_create_point` passes `None` to `capi.create_point`.\n\n4. **Empty point handling**: The `__init__` supports creating empty points when `x=None`. The `__len__` method returns 0 for empty points (checked via `self.empty`). Pickling of empty points is special-cased: `_to_pickle_wkb` returns `None` instead of WKB bytes, and `_from_pickle_wkb` recreates via `_create_empty()` when it receives `None`.\n\n5. **ListMixin integration**: `Point` implements the `ListMixin` protocol by providing `_get_single_external` (dispatching to x/y/z by index 0/1/2), `_set_single` (using `self._cs.setOrdinate(index, 0, value)`), and `_set_list` (which creates a new point via `_create_point`, destroys the old geometry with `capi.destroy_geom`, sets the new pointer, restores the SRID, and calls `_post_init`). `_get_single_internal` is explicitly set equal to `_get_single_external`.\n\n6. **Z setter guard**: The `z` setter raises `GEOSException('Cannot set Z on 2D Point.')` if the point doesn't have a Z dimension (`self.hasz` is False).\n\n7. **`coords` is an alias**: At class level, `coords = tuple` makes `coords` an alias for the `tuple` property.\n\n8. **GEOS type ID mapping**: In `GEOSGeometryBase.__init__`, Point is mapped to GEOS type ID `0` in the `_GEOS_CLASSES` dictionary.\n\n9. **`tuple` property**: The `tuple` getter delegates to `self._cs.tuple`, which in `GEOSCoordSeq` returns a single tuple (not a tuple of tuples) when `size == 1` (which is always the case for a Point). The `tuple` setter assigns to `self._cs[0]`, which invokes `GEOSCoordSeq.__setitem__` with dimension-aware point setters (_set_point_2d, _set_point_3d, etc.).", "rubric": [ "Identifies the inheritance chain: Point \u2192 GEOSGeometry \u2192 GEOSGeometryBase (+ ListMixin) \u2192 GEOSBase \u2192 CPointerBase", "Explains CPointerBase manages a C pointer (_ptr) with null-pointer checking and destructor invocation in __del__", "Mentions Point sets _minlength=2, _maxlength=3, and has_cs=True as class attributes", "Explains that _post_init creates a GEOSCoordSeq from capi.get_cs(self.ptr) when has_cs is True", "Describes _create_point classmethod: creates coordinate sequence with capi.create_cs, sets x/y/z, and calls capi.create_point", "Explains empty point handling: x=None creates empty point, __len__ returns 0, pickling special-cases with _to_pickle_wkb returning None", "Describes ListMixin integration: _get_single_external dispatches by index to x/y/z, _set_single uses _cs.setOrdinate, _set_list recreates the point geometry", "Mentions z setter raises GEOSException if point is 2D", "Explains coordinate access delegates through GEOSCoordSeq's getOrdinate/setOrdinate which call capi.cs_getordinate/cs_setordinate", "Notes that the tuple property in GEOSCoordSeq returns a single tuple (not nested) when size==1, and coords is aliased to tuple at class level" ], "key_files": [ "django/contrib/gis/geos/point.py", "django/contrib/gis/geos/geometry.py", "django/contrib/gis/geos/coordseq.py", "django/contrib/gis/geos/prototypes/geom.py", "django/contrib/gis/geos/prototypes/coordseq.py", "django/contrib/gis/geos/mutable_list.py", "django/contrib/gis/ptr.py", "django/contrib/gis/geos/base.py" ], "source_doc": "[docstring: django/contrib/gis/geos/point.py] django.contrib.gis.geos.point.Point\ndjango.contrib.gis.geos.point.Point.__init__:\n The Point object may be initialized with either a tuple, or individual\n parameters.\n\n For example:\n >>> p = Point((5, 23)) # 2D point, passed in as a tuple\n >>> p = Point(5, 23, 8) # 3D point, passed as individual parameters\n\ndjango.contrib.gis.geos.point.Point._create_point:\n Create a coordinate sequence, set X, Y, [Z], and create point\n\ndjango.contrib.gis.geos.point.Point.__iter__:\n Iterate over coordinates of this Point.\n\ndjango.contrib.gis.geos.point.Point.__len__:\n Return the number of dimensions for this Point (either 0, 2 or 3).\n\ndjango.contrib.gis.geos.point.Point.x:\n Return the X component of the Point.\n\ndjango.contrib.gis.geos.point.Point.x:\n Set the X component of the Point.\n\ndjango.contrib.gis.geos.point.Point.y:\n Return the Y component of the Point.\n\ndjango.contrib.gis.geos.point.Point.y:\n Set the Y component of the Point.\n\ndjango.contrib.gis.geos.point.Point.z:\n Return the Z component of the Point.\n\ndjango.contrib.gis.geos.point.Point.z:\n Set the Z component of the Point.\n\ndjango.contrib.gis.geos.point.Point.tuple:\n Return a tuple of the point.\n\ndjango.contrib.gis.geos.point.Point.tuple:\n Set the coordinates of the point with the given tuple.", "verification_verdict": "pass", "verification_issues": [], "strip_verify_leakage": 0.0, "strip_verify_summary": "All claims in the gold answer are verifiable from the stripped source code; no documentation-only claims found.", "generation_status": "completed", "generation_error": null }, { "id": "django_gen_06", "repo": "django", "question": "Why is `ogrinspect` split into a public function and a private `_ogrinspect` generator, and how does the management command exploit that design?", "category": "why", "sub_type": "purpose_exploration", "gold_answer": "The `ogrinspect` function in `django/contrib/gis/utils/ogrinspect.py` exists as a convenience wrapper that joins the output of the internal `_ogrinspect()` generator into a single string with newlines. The separation of `ogrinspect` from `_ogrinspect` (prefixed with underscore) serves two distinct purposes:\n\n1. **Streaming vs. String output**: `_ogrinspect` is a generator (uses `yield` statements) that produces model definition lines one at a time. This allows the management command (`django/contrib/gis/management/commands/ogrinspect.py`) to collect lines into a list and append additional output (like the `--mapping` dictionary) before joining everything together. The public `ogrinspect()` function simply does `\"\\n\".join(_ogrinspect(*args, **kwargs))` for users who just want the complete string.\n\n2. **Management command integration**: The management command (`Command.handle()`) calls `_ogrinspect` directly rather than `ogrinspect` because it needs to extend the output with optional mapping dictionary generation. It uses `get_func_args(_ogrinspect)` to dynamically filter command-line options to only those parameters accepted by `_ogrinspect`, providing a flexible interface without hard-coding parameter names.\n\nThe `_ogrinspect` function appends `'field'` to OGR field names that end with an underscore (e.g., `mfield += \"field\"`). It uses a nested `process_kwarg()` helper to normalize the `null`, `blank`, and `decimal` parameters \u2014 when these are boolean `True`, they expand to all field names in the layer; when they are lists/tuples, they are lowercased for case-insensitive matching.\n\nFor geometry field generation, `_ogrinspect` delegates to `OGRGeomType.django` property which converts the OGR geometry type name to a Django field name by stripping '25D' suffix, mapping 'Unknown' to 'Geometry', mapping 'PointZ' to 'Point', and appending 'Field'. The `to_multi()` method on `OGRGeomType` simply adds 3 to the type number (since Multi variants are offset by 3 in OGR's type enumeration: Point=1\u2192MultiPoint=4, LineString=2\u2192MultiLineString=5, Polygon=3\u2192MultiPolygon=6).\n\nThe SRID handling logic shows that when SRID is 4326, the `srid_str` is set to an empty string (omitting the srid parameter from the generated field). When the layer's SRS is None or cannot determine an SRID, it defaults to `srid=-1`.", "rubric": [ "_ogrinspect is a generator (uses yield) that produces model definition lines one at a time, while ogrinspect joins them into a single string with newlines", "The management command calls _ogrinspect directly (not ogrinspect) so it can collect lines into a list and append additional output like the mapping dictionary before joining", "The command uses get_func_args(_ogrinspect) to dynamically filter command-line options to only those parameters accepted by _ogrinspect", "The process_kwarg nested helper normalizes null/blank/decimal: boolean True expands to all field names, lists/tuples are lowercased for case-insensitive matching", "OGR field names ending with underscore get 'field' appended to avoid trailing underscores in model field names", "SRID 4326 results in an empty srid_str since WGS84 is the default; None/unknown SRS defaults to srid=-1" ], "key_files": [ "django/contrib/gis/utils/ogrinspect.py", "django/contrib/gis/management/commands/ogrinspect.py", "django/contrib/gis/gdal/geomtype.py", "django/contrib/gis/gdal/field.py" ], "source_doc": "[docstring: django/contrib/gis/utils/ogrinspect.py] django.contrib.gis.utils.ogrinspect.ogrinspect\nGiven a data source (either a string or a DataSource object) and a string\n model name this function will generate a GeoDjango model.\n\n Usage:\n\n >>> from django.contrib.gis.utils import ogrinspect\n >>> ogrinspect('/path/to/shapefile.shp','NewModel')\n\n ...will print model definition to stout\n\n or put this in a Python script and use to redirect the output to a new\n model like:\n\n $ python generate_model.py > myapp/models.py\n\n # generate_model.py\n from django.contrib.gis.utils import ogrinspect\n shp_file = 'data/mapping_hacks/world_borders.shp'\n model_name = 'WorldBorders'\n\n print(ogrinspect(shp_file, model_name, multi_geom=True, srid=4326,\n geom_name='shapes', blank=True))\n\n Required Arguments\n `datasource` => string or DataSource object to file pointer\n\n `model name` => string of name of new model class to create\n\n Optional Keyword Arguments\n `geom_name` => For specifying the model name for the Geometry Field.\n Otherwise will default to `geom`\n\n `layer_key` => The key specifying which layer in the DataSource to use;\n defaults to 0 (the first layer). May be an integer index or a string\n identifier for the layer.\n\n `srid` => The SRID to use for the Geometry Field. If it can be determined,\n the SRID of the datasource is used.\n\n `multi_geom` => Boolean (default: False) - specify as multigeometry.\n\n `name_field` => String - specifies a field name to return for the\n __str__() method (which will be generated if specified).\n\n `imports` => Boolean (default: True) - set to False to omit the\n `from django.contrib.gis.db import models` code from the\n autogenerated models thus avoiding duplicated imports when building\n more than one model by batching ogrinspect()\n\n `decimal` => Boolean or sequence (default: False). When set to True\n all generated model fields corresponding to the `OFTReal` type will\n be `DecimalField` instead of `FloatField`. A sequence of specific\n field names to generate as `DecimalField` may also be used.\n\n `blank` => Boolean or sequence (default: False). When set to True all\n generated model fields will have `blank=True`. If the user wants to\n give specific fields to have blank, then a list/tuple of OGR field\n names may be used.\n\n `null` => Boolean (default: False) - When set to True all generated\n model fields will have `null=True`. If the user wants to specify\n give specific fields to have null, then a list/tuple of OGR field\n names may be used.\n\n Note: Call the _ogrinspect() helper to do the heavy lifting.", "verification_verdict": "warn", "verification_issues": [ "The answer contains many implementation details (e.g., field name collision avoidance by appending 'field', process_kwarg() helper, OGRGeomType.django property behavior, to_multi() method adding 3 to type number, SRID 4326 resulting in empty string) that are not present in the documentation. These appear to be plausible code-level extrapolations but cannot be verified from the provided documentation alone.", "The claim that ogrinspect does '\\n'.join(_ogrinspect(*args, **kwargs)) is plausible but not explicitly stated in the documentation - the doc only says 'Call the _ogrinspect() helper to do the heavy lifting'.", "The claim about get_func_args(_ogrinspect) being used in the management command is not in the documentation and cannot be verified.", "The claim about srid=-1 as default when SRS is None is not in the documentation - the doc says 'If it can be determined, the SRID of the datasource is used' but doesn't specify the fallback value." ], "strip_verify_leakage": 0.08, "strip_verify_summary": "Minor doc leakage in design rationale language and the explanation of why 4326 gets empty string; nearly all claims are verifiable from code.", "generation_status": "completed", "generation_error": null }, { "id": "django_gen_02", "repo": "django", "question": "Why does the ModelAdmin class use so many specific design patterns \u2014 like transaction wrapping only for non-safe methods, MRO-based formfield resolution, and unbound method fetching for actions?", "category": "why", "sub_type": "design_rationale", "gold_answer": "The `ModelAdmin` class in `django/contrib/admin/options.py` is designed with several key architectural and design rationale decisions:\n\n## Inheritance & Metaclass Architecture\n`ModelAdmin` inherits from `BaseModelAdmin`, which itself uses `forms.MediaDefiningClass` as its metaclass (line 130). This metaclass (defined in `django/forms/widgets.py:268`) automatically adds a `media` property to classes that don't define one explicitly. However, `ModelAdmin` explicitly defines its own `media` property (line 753) that includes jQuery, core.js, RelatedObjectLookups.js, actions.js, urlify.js, prepopulate.js, and xregexp, selecting `.min.js` versions when `settings.DEBUG` is False.\n\n## Transaction Wrapping Strategy\nBoth `changeform_view` and `delete_view` use a split-method pattern: the public method (e.g., `changeform_view` at line 1847) conditionally wraps calls in `transaction.atomic()` only for non-safe HTTP methods. GET/HEAD/OPTIONS/TRACE requests bypass the transaction wrapper and directly call the private `_changeform_view`/`_delete_view`. This is a deliberate performance optimization \u2014 read-only requests don't need transaction guarantees, while write operations (POST) are wrapped in `transaction.atomic(using=router.db_for_write(self.model))` to ensure database consistency across the correct database in multi-db setups.\n\n## Formfield Override Merging (Not Overwriting)\n`BaseModelAdmin.__init__` (line 154) uses `copy.deepcopy(FORMFIELD_FOR_DBFIELD_DEFAULTS)` and then merges subclass `formfield_overrides` using `setdefault().update()` rather than replacing. This design ensures that subclasses only need to specify the keys they want to change, while preserving defaults for other field types. The comment explicitly states: \"Merge FORMFIELD_FOR_DBFIELD_DEFAULTS with the formfield_overrides rather than simply overwriting.\"\n\n## MRO-Based Formfield Resolution\nIn `formfield_for_dbfield` (line 226), the method walks the field class's MRO (`db_field.__class__.mro()`) to find formfield overrides. This means overrides for parent field types (e.g., `CharField`) will also apply to subclass fields (e.g., `EmailField`) if no more specific override exists.\n\n## Permission System Design\n`has_view_permission` (line 601) deliberately checks BOTH the `view` AND `change` permission codenames \u2014 the rationale being that users with change permission should implicitly have view permission. The separate `has_view_or_change_permission` (line 619) exists for cases where subclasses override `has_view_permission` to no longer include the change permission check.\n\n## Action Resolution: Unbound Methods for Consistent Calling Conventions\n`get_action` (line 1073-1077) deliberately fetches methods from `self.__class__` rather than `self` to get an unbound method. The comment explains: \"this ensures that the calling conventions are the same for functions and methods.\" In `response_action` (line 1695), actions are always called as `func(self, request, queryset)`, so both standalone functions and methods receive the ModelAdmin as the first argument consistently.\n\n## Action Priority and Filtering\n`_get_base_actions` first collects site-wide actions, then extends with ModelAdmin-specific actions. Site-wide actions are skipped if their name conflicts with a ModelAdmin action (line 1015: `if name in base_action_names: continue`), giving ModelAdmin actions priority. Actions are further filtered by `_filter_actions_by_permissions`, which checks `callable.allowed_permissions` attribute (set by the `@admin.action(permissions=...)` decorator) and dynamically resolves `has_{permission}_permission` methods on the ModelAdmin.\n\n## Actions Disabled in Popups\n`get_actions` (line 1046) returns an empty dict if `IS_POPUP_VAR` is in `request.GET`, preventing actions from appearing in popup windows.\n\n## Logging: Single Object vs Bulk Create\n`log_addition` and `log_change` pass `single_object=True` to `LogEntry.objects.log_actions()`, which returns a single `LogEntry` instance. `log_deletions` does NOT pass `single_object=True` because deletions can be bulk operations. The `LogEntryManager.log_actions` method (in `models.py`) uses `save()` for single entries and `bulk_create()` for multiple, and `object_repr` is truncated to 200 characters (`str(obj)[:200]`).\n\n## View-Only Inline Form Validation Bypass\n`_create_formsets` (line 2380-2387) deliberately bypasses validation for view-only inline forms by setting `form._errors = {}` and `form.cleaned_data = form.initial`. This is because view-only form data won't be present in `request.POST`, so validation would fail. However, this bypass is skipped if the user has explicitly marked the form for deletion.\n\n## List Editable Security: Tampered PK Validation\n`_get_list_editable_queryset` (line 2015-2022) validates each PK from POST data using the model's pk field's `to_python()`. If any PK fails validation (indicating tampered POST data), it falls back to the full queryset rather than the optimized filtered queryset, disabling the optimization as a defensive measure.\n\n## Backward Compatibility URL Redirect\n`get_urls` (line 738-746) includes a catch-all `/` URL pattern that redirects to the change view. The comment says this \"was the change url before 1.9,\" using `RedirectView.as_view()` for backward compatibility.\n\n## Save As New: Hiding Save Buttons on Failure\nWhen `_saveasnew` is in POST and form validation fails (line 1979-1987), the context sets `show_save` and `show_save_and_continue` to False and forces `add = False` to use the change template, preventing confusing UI states.", "rubric": [ "Explain that changeform_view/delete_view only wrap non-safe HTTP methods (POST) in transaction.atomic() as a performance optimization, while GET/HEAD/OPTIONS/TRACE bypass the transaction wrapper", "Explain that formfield_for_dbfield walks the field class's MRO to find formfield overrides, allowing parent field type overrides to apply to subclass fields when no specific override exists", "Explain that get_action fetches methods from self.__class__ (not self) to get unbound methods, ensuring consistent calling conventions between standalone functions and methods \u2014 both receive ModelAdmin as first argument when called as func(self, request, queryset)", "Explain that BaseModelAdmin.__init__ merges formfield_overrides with FORMFIELD_FOR_DBFIELD_DEFAULTS using setdefault().update() rather than overwriting, so subclasses only need to specify keys they want to change", "Explain that has_view_permission checks both view AND change permission codenames because users with change permission should implicitly have view access", "Explain that _get_base_actions skips site-wide actions whose names conflict with ModelAdmin actions, giving ModelAdmin actions priority", "Explain that _create_formsets bypasses validation for view-only inline forms (setting form._errors={} and form.cleaned_data=form.initial) because their data won't be in request.POST, but this is skipped for forms marked for deletion" ], "key_files": [ "django/contrib/admin/options.py", "django/contrib/admin/models.py", "django/contrib/admin/decorators.py", "django/forms/widgets.py" ], "source_doc": "[docstring: django/contrib/admin/options.py] django.contrib.admin.options.ModelAdmin\ndjango.contrib.admin.options.ModelAdmin:\n Encapsulate all admin options and functionality for a given model.\n\ndjango.contrib.admin.options.ModelAdmin.get_model_perms:\n Return a dict of all perms for this model. This dict has the keys\n ``add``, ``change``, ``delete``, and ``view`` mapping to the True/False\n for each of those actions.\n\ndjango.contrib.admin.options.ModelAdmin.get_form:\n Return a Form class for use in the admin add view. This is used by\n add_view and change_view.\n\ndjango.contrib.admin.options.ModelAdmin.get_changelist:\n Return the ChangeList class for use on the changelist page.\n\ndjango.contrib.admin.options.ModelAdmin.get_changelist_instance:\n Return a `ChangeList` instance based on `request`. May raise\n `IncorrectLookupParameters`.\n\ndjango.contrib.admin.options.ModelAdmin.get_object:\n Return an instance matching the field and value provided, the primary\n key is used if no field is provided. Return ``None`` if no match is\n found or the object_id fails validation.\n\ndjango.contrib.admin.options.ModelAdmin.get_changelist_form:\n Return a Form class for use in the Formset on the changelist page.\n\ndjango.contrib.admin.options.ModelAdmin.get_changelist_formset:\n Return a FormSet class for use on the changelist page if list_editable\n is used.\n\ndjango.contrib.admin.options.ModelAdmin.get_formsets_with_inlines:\n Yield formsets and the corresponding inlines.\n\ndjango.contrib.admin.options.ModelAdmin.log_addition:\n Log that an object has been successfully added.\n\n The default implementation creates an admin LogEntry object.\n\ndjango.contrib.admin.options.ModelAdmin.log_change:\n Log that an object has been successfully changed.\n\n The default implementation creates an admin LogEntry object.\n\ndjango.contrib.admin.options.ModelAdmin.log_deletions:\n Log that objects will be deleted. Note that this method must be called\n before the deletion.\n\n The default implementation creates admin LogEntry objects.\n\ndjango.contrib.admin.options.ModelAdmin.action_checkbox:\n A list_display column containing a checkbox widget.\n\ndjango.contrib.admin.options.ModelAdmin._get_base_actions:\n Return the list of actions, prior to any request-based filtering.\n\ndjango.contrib.admin.options.ModelAdmin._filter_actions_by_permissions:\n Filter out any actions that the user doesn't have access to.\n\ndjango.contrib.admin.options.ModelAdmin.get_actions:\n Return a dictionary mapping the names of all actions for this\n ModelAdmin to a tuple of (callable, name, description) for each action.\n\ndjango.contrib.admin.options.ModelAdmin.get_action_choices:\n Return a list of choices for use in a form object. Each choice is a\n tuple (name, description).\n\ndjango.contrib.admin.options.ModelAdmin.get_action:\n Return a given action from a parameter, which can either be a callable,\n or the name of a method on the ModelAdmin. Return is a tuple of\n (callable, name, description).\n\ndjango.contrib.admin.options.ModelAdmin.get_list_display:\n Return a sequence containing the fields to be displayed on the\n changelist.\n\ndjango.contrib.admin.options.ModelAdmin.get_list_display_links:\n Return a sequence containing the fields to be displayed as links\n on the changelist. The list_display parameter is the list of fields\n returned by get_list_display().\n\ndjango.contrib.admin.options.ModelAdmin.get_list_filter:\n Return a sequence containing the fields to be displayed as filters in\n the right sidebar of the changelist page.\n\ndjango.contrib.admin.options.ModelAdmin.get_list_select_related:\n Return a list of fields to add to the select_related() part of the\n changelist items query.\n\ndjango.contrib.admin.options.ModelAdmin.get_search_fields:\n Return a sequence containing the fields to be searched whenever\n somebody submits a search query.\n\ndjango.contrib.admin.options.ModelAdmin.get_search_results:\n Return a tuple containing a queryset to implement the search\n and a boolean indicating if the results may contain duplicates.\n\ndjango.contrib.admin.options.ModelAdmin.get_preserved_filters:\n Return the preserved filters querystring.\n\ndjango.contrib.admin.options.ModelAdmin.construct_change_message:\n Construct a JSON structure describing changes from a changed object.\n\ndjango.contrib.admin.options.ModelAdmin.message_user:\n Send a message to the user. The default implementation\n posts a message using the django.contrib.messages backend.\n\n Exposes almost the same API as messages.add_message(), but accepts the\n positional arguments in a different order to maintain backwards\n compatibility. For convenience, it accepts the `level` argument as\n a string rather than the usual level number.\n\ndjango.contrib.admin.options.ModelAdmin.save_form:\n Given a ModelForm return an unsaved instance. ``change`` is True if\n the object is being changed, and False if it's being added.\n\ndjango.contrib.admin.options.ModelAdmin.save_model:\n Given a model instance save it to the database.\n\ndjango.contrib.admin.options.ModelAdmin.delete_model:\n Given a model instance delete it from the database.\n\ndjango.contrib.admin.options.ModelAdmin.delete_queryset:\n Given a queryset, delete it from the database.\n\ndjango.contrib.admin.options.ModelAdmin.save_formset:\n Given an inline formset save it to the database.\n\ndjango.contrib.admin.options.ModelAdmin.save_related:\n Given the ``HttpRequest``, the parent ``ModelForm`` instance, the\n list of inline formsets and a boolean value based on whether the\n parent is being added or changed, save the related objects to the\n database. Note that at this point save_form() and save_model() have\n already been called.\n\ndjango.contrib.admin.options.ModelAdmin.response_add:\n Determine the HttpResponse for the add_view stage.\n\ndjango.contrib.admin.options.ModelAdmin.response_change:\n Determine the HttpResponse for the change_view stage.\n\ndjango.contrib.admin.options.ModelAdmin.response_post_save_add:\n Figure out where to redirect after the 'Save' button has been pressed\n when adding a new object.\n\ndjango.contrib.admin.options.ModelAdmin.response_post_save_change:\n Figure out where to redirect after the 'Save' button has been pressed\n when editing an existing object.\n\ndjango.contrib.admin.options.ModelAdmin.response_action:\n Handle an admin action. This is called if a request is POSTed to the\n changelist; it returns an HttpResponse if the action was handled, and\n None otherwise.\n\ndjango.contrib.admin.options.ModelAdmin.response_delete:\n Determine the HttpResponse for the delete_view stage.\n\ndjango.contrib.admin.options.ModelAdmin.get_changeform_initial_data:\n Get the initial form data from the request's GET params.\n\ndjango.contrib.admin.options.ModelAdmin._get_obj_does_not_exist_redirect:\n Create a message informing the user that the object doesn't exist\n and return a redirect to the admin index page.\n\ndjango.contrib.admin.options.ModelAdmin._get_edited_object_pks:\n Return POST data values of list_editable primary keys.\n\ndjango.contrib.admin.options.ModelAdmin._get_list_editable_queryset:\n Based on POST data, return a queryset of the objects that were edited\n via list_editable.\n\ndjango.contrib.admin.options.ModelAdmin.changelist_view:\n The 'change list' admin view for this model.\n\ndjango.contrib.admin.options.ModelAdmin.get_deleted_objects:\n Hook for customizing the delete process for the delete view and the\n \"delete selected\" action.\n\ndjango.contrib.admin.options.ModelAdmin._delete_view:\n The 'delete' admin view for this model.\n\ndjango.contrib.admin.options.ModelAdmin.history_view:\n The 'history' admin view for this model.\n\ndjango.contrib.admin.options.ModelAdmin._create_formsets:\n Helper function to generate formsets for add/change_view.", "verification_verdict": "warn", "verification_issues": [ "The generated answer contains extensive implementation details (line numbers, specific code patterns, variable names, internal method logic) that go far beyond what the provided documentation describes. The documentation only contains docstrings/method descriptions, not source code details.", "Claims about specific line numbers (e.g., 'line 130', 'line 753', 'line 1847') cannot be verified from the documentation provided.", "Claims about transaction wrapping strategy, formfield override merging, MRO-based resolution, action priority filtering logic, etc. are plausible but entirely unsupported by the provided documentation which only contains method docstrings.", "The claim about `has_view_permission` checking both view AND change permissions is not mentioned in the documentation, which only describes `get_model_perms` returning a dict with add/change/delete/view keys.", "The documentation for `log_deletions` says 'Log that objects will be deleted. Note that this method must be called before the deletion.' - the answer's claim about `log_deletions` not passing `single_object=True` and using `bulk_create()` is an implementation detail not in the docs.", "The answer's claims about `_create_formsets` bypassing validation are implementation details beyond the doc's simple description of 'Helper function to generate formsets for add/change_view.'" ], "strip_verify_leakage": null, "strip_verify_summary": null, "generation_status": "completed", "generation_error": null }, { "id": "django_gen_07", "repo": "django", "question": "Where is `add_srs_entry` defined, how does it determine backend support, and what models does it interact with across different spatial backends?", "category": "where", "sub_type": "feature_location", "gold_answer": "The `add_srs_entry` function is located in `django/contrib/gis/utils/srs.py` and is re-exported through `django/contrib/gis/utils/__init__.py` (included in the `__all__` list alongside `mapping`, `ogrinfo`, `ogrinspect`, `LayerMapError`, and `LayerMapping`).\n\n**Where it lives and connects:**\n\n1. **Definition**: `django/contrib/gis/utils/srs.py` \u2014 the function takes a `srs` argument (either a GDAL `SpatialReference` or something that can be used to construct one, like an integer SRID).\n\n2. **Backend support check**: The function first checks `connection.ops.spatial_version` via `hasattr` to verify it's a spatial backend, then checks `connection.features.supports_add_srs_entry`. This feature flag is:\n - **`True` by default** in `BaseSpatialFeatures` (`base/features.py`)\n - **Explicitly `False`** in `MySQL` (`mysql/features.py`) and `Oracle` (`oracle/features.py`)\n - **Inherited as `True`** in PostGIS (`postgis/features.py`) and SpatiaLite (`spatialite/features.py`), since neither overrides it\n\n3. **SpatialRefSys model retrieval**: The function calls `connection.ops.spatial_ref_sys()` which is an abstract method on `BaseSpatialOperations` (raises `NotImplementedError`). Concrete implementations return:\n - `PostGISSpatialRefSys` (from `postgis/models.py`) \u2014 has fields: `srid`, `auth_name`, `auth_srid`, `srtext`, `proj4text`\n - `SpatialiteSpatialRefSys` (from `spatialite/models.py`) \u2014 has fields: `srid`, `auth_name`, `auth_srid`, `ref_sys_name`, `proj4text`, `srtext`\n Both models inherit from `SpatialRefSysMixin` (in `base/models.py`) and both map to the `spatial_ref_sys` database table with `managed = False`.\n\n4. **Backend-specific field handling**: The function dynamically inspects the model's field names via `SpatialRefSys._meta.get_fields()`. If `\"srtext\"` is present (both PostGIS and SpatiaLite have it), it adds `srs.wkt` to kwargs. If `\"ref_sys_name\"` is present (only SpatiaLite has this field), it adds the `ref_sys_name` value.\n\n5. **Idempotency**: The function uses a try/except pattern \u2014 it first tries `SpatialRefSys.objects.using(database).get(srid=srs.srid)`. Only if `DoesNotExist` is raised does it call `create(**kwargs)`.\n\n6. **SpatialRefSysMixin**: Located in `django/contrib/gis/db/backends/base/models.py`, this mixin provides a `srs` cached_property that first tries to construct a GDAL `SpatialReference` from `self.wkt`, and if that fails, falls back to `self.proj4text`. It also provides properties like `ellipsoid`, `name`, `spheroid`, `datum`, `projected`, `local`, `geographic`, `linear_name`, `linear_units`, `angular_name`, `angular_units`, and `units`, plus class methods `get_units` and `get_spheroid`.\n\n7. **Testing**: In `tests/gis_tests/test_spatialrefsys.py`, the `test_add_entry` method is decorated with `@skipUnlessDBFeature(\"supports_add_srs_entry\")` and tests adding SRID 3857, then verifies the entry exists and that `get_spheroid(srs.wkt)` starts with `\"SPHEROID[\"`.", "rubric": [ "Defined in django/contrib/gis/utils/srs.py and re-exported through django/contrib/gis/utils/__init__.py", "Checks connection.ops.spatial_version (via hasattr) and connection.features.supports_add_srs_entry to verify backend support", "supports_add_srs_entry is True by default in BaseSpatialFeatures but explicitly False in MySQL and Oracle backends", "PostGIS and SpatiaLite inherit the True default (neither overrides it)", "Calls connection.ops.spatial_ref_sys() to get the SpatialRefSys model (abstract/NotImplementedError in base, concrete in PostGIS and SpatiaLite)", "PostGISSpatialRefSys has fields srid, auth_name, auth_srid, srtext, proj4text; SpatialiteSpatialRefSys adds ref_sys_name", "Both models inherit from SpatialRefSysMixin in base/models.py and both use the spatial_ref_sys table with managed=False", "Dynamically inspects model fields: adds srs.wkt if 'srtext' is present, adds ref_sys_name if that field is present (SpatiaLite only)", "Uses try/except with get(srid=srs.srid) for idempotency \u2014 only creates if DoesNotExist is raised" ], "key_files": [ "django/contrib/gis/utils/srs.py", "django/contrib/gis/db/backends/base/features.py", "django/contrib/gis/db/backends/base/models.py", "django/contrib/gis/db/backends/postgis/models.py", "django/contrib/gis/db/backends/spatialite/models.py", "django/contrib/gis/db/backends/base/operations.py" ], "source_doc": "[docstring: django/contrib/gis/utils/srs.py] django.contrib.gis.utils.srs.add_srs_entry\nTake a GDAL SpatialReference system and add its information to the\n `spatial_ref_sys` table of the spatial backend. Doing this enables\n database-level spatial transformations for the backend. Thus, this utility\n is useful for adding spatial reference systems not included by default with\n the backend:\n\n >>> from django.contrib.gis.utils import add_srs_entry\n >>> add_srs_entry(3857)\n\n Keyword Arguments:\n auth_name:\n This keyword may be customized with the value of the `auth_name` field.\n Defaults to 'EPSG'.\n\n auth_srid:\n This keyword may be customized with the value of the `auth_srid` field.\n Defaults to the SRID determined by GDAL.\n\n ref_sys_name:\n For SpatiaLite users only, sets the value of the `ref_sys_name` field.\n Defaults to the name determined by GDAL.\n\n database:\n The name of the database connection to use; the default is the value\n of `django.db.DEFAULT_DB_ALIAS` (at the time of this writing, its value\n is 'default').", "verification_verdict": "pass", "verification_issues": [], "strip_verify_leakage": 0.05, "strip_verify_summary": "Only one claim about a code comment was removed; nearly all claims are verifiable from stripped source code.", "generation_status": "completed", "generation_error": null }, { "id": "django_gen_08", "repo": "django", "question": "How does Django implement portable file locking across different platforms, and what happens when no locking mechanism is available?", "category": "how", "sub_type": "algorithm_implementation", "gold_answer": "The `django/core/files/locks.py` module implements portable file locking through platform-specific branching using `os.name == 'nt'`.\n\n**Platform detection and three code paths:**\n\n1. **Windows (`os.name == 'nt'`):** Uses `ctypes` to call Windows kernel32 `LockFileEx`/`UnlockFileEx` functions directly. The lock constants are: `LOCK_SH = 0`, `LOCK_NB = 0x1`, `LOCK_EX = 0x2`. The implementation defines a custom ctypes `OVERLAPPED` structure (containing `_OFFSET` and `_OFFSET_UNION` inner structures). The `ULONG_PTR` type is dynamically determined by comparing `sizeof(c_ulong)` with `sizeof(c_void_p)` \u2014 if they differ, `c_int64` is used instead of `c_ulong`. The `lock()` function obtains a Windows file handle via `msvcrt.get_osfhandle(_fd(f))`, creates a zeroed `OVERLAPPED` struct, and calls `LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped))`. The `0xFFFF0000` is passed as an argument to `LockFileEx`. Both `lock()` and `unlock()` return `bool(ret)` where ret is the Windows API return value.\n\n2. **Non-Windows with `fcntl` available:** Uses `fcntl.flock()`. Lock constants are taken directly from the `fcntl` module (`fcntl.LOCK_SH`, `fcntl.LOCK_NB`, `fcntl.LOCK_EX`). The `lock()` function calls `fcntl.flock(_fd(f), flags)` and returns `True` on success; it catches `BlockingIOError` and returns `False`. The `unlock()` function calls `fcntl.flock(_fd(f), fcntl.LOCK_UN)` and always returns `True`.\n\n3. **Fallback (no `fcntl` available):** If `fcntl` import raises `ImportError` or `AttributeError`, all lock constants are set to 0, `lock()` always returns `False`, and `unlock()` always returns `True` \u2014 effectively making locking a no-op.\n\n**The `_fd()` helper:** Accepts either a file object or a raw file descriptor integer. It checks `hasattr(f, 'fileno')` and calls `f.fileno()` if available, otherwise returns `f` directly. This allows the lock functions to work with both file objects and raw integer file descriptors.\n\n**Usage in Django:**\n- `django/core/files/move.py`: `file_move_safe()` acquires `LOCK_EX` on a raw fd (from `os.open()`) when `os.rename()` fails and it falls back to manual copying, unlocking in a `finally` block.\n- `django/core/files/storage/filesystem.py`: `FileSystemStorage._save()` acquires `LOCK_EX` on a raw fd, with handling to use `os.fdopen()` only after the first chunk determines the write mode ('wb' vs 'wt').\n- `django/core/cache/backends/filebased.py`: `FileBasedCache.touch()` acquires `LOCK_EX` on a file object to read and rewrite cache entries.\n- `django/test/testcases.py`: `SerializeMixin.setUpClass()` acquires `LOCK_EX` on a lockfile to serialize test case execution; the lockfile is closed via `addClassCleanup()`.\n\nThe module exports exactly five names via `__all__`: `('LOCK_EX', 'LOCK_SH', 'LOCK_NB', 'lock', 'unlock')`.", "rubric": [ "Explains platform detection uses `os.name == 'nt'` to branch between Windows and non-Windows paths", "Describes the Windows path: uses ctypes to call kernel32 LockFileEx/UnlockFileEx with a custom OVERLAPPED structure, and msvcrt.get_osfhandle to get the Windows file handle", "Mentions Windows lock constants: LOCK_SH=0, LOCK_NB=0x1, LOCK_EX=0x2", "Describes ULONG_PTR dynamic sizing by comparing sizeof(c_ulong) vs sizeof(c_void_p), using c_int64 if they differ", "Describes the non-Windows path with fcntl: uses fcntl.flock(), catches BlockingIOError to return False, lock constants come from the fcntl module", "Describes the fallback no-op path when fcntl import fails (ImportError or AttributeError): all constants set to 0, lock() returns False, unlock() returns True", "Explains the _fd() helper: checks hasattr(f, 'fileno') to support both file objects and raw integer file descriptors", "Mentions at least two places in Django that use the locks module (e.g., file_move_safe, FileSystemStorage._save, FileBasedCache, SerializeMixin)", "Notes __all__ exports five names: LOCK_EX, LOCK_SH, LOCK_NB, lock, unlock" ], "key_files": [ "django/core/files/locks.py", "django/core/files/move.py", "django/core/files/storage/filesystem.py", "django/core/cache/backends/filebased.py", "django/test/testcases.py" ], "source_doc": "[docstring: django/core/files/locks.py] django.core.files.locks\nPortable file locking utilities.\n\nBased partially on an example by Jonathan Feignberg in the Python\nCookbook [1] (licensed under the Python Software License) and a ctypes port by\nAnatoly Techtonik for Roundup [2] (license [3]).\n\n[1] https://code.activestate.com/recipes/65203/\n[2] https://sourceforge.net/p/roundup/code/ci/default/tree/roundup/backends/portalocker.py # NOQA\n[3] https://sourceforge.net/p/roundup/code/ci/default/tree/COPYING.txt\n\nExample Usage::\n\n >>> from django.core.files import locks\n >>> with open('./file', 'wb') as f:\n ... locks.lock(f, locks.LOCK_EX)\n ... f.write('Django')", "verification_verdict": "pass", "verification_issues": [], "strip_verify_leakage": 0.1, "strip_verify_summary": "Minor doc leakage in Windows API constant names and purpose descriptions; most claims are directly verifiable from stripped code.", "generation_status": "completed", "generation_error": null }, { "id": "django_gen_11", "repo": "django", "question": "Where is FileDescriptor defined and how does it integrate with DeferredAttribute to handle file field access on model instances?", "category": "where", "sub_type": "identifier_location", "gold_answer": "`FileDescriptor` is located in `django/db/models/fields/files.py`. It inherits from `DeferredAttribute` which is defined in `django/db/models/query_utils.py`. The `FileDescriptor` is installed on model classes via `FileField.contribute_to_class()`, which calls `setattr(cls, self.attname, self.descriptor_class(self))`. The `ImageFileDescriptor` subclass of `FileDescriptor` is defined in the same file and is used by `ImageField`.\n\nKey architectural details:\n\n1. `FileDescriptor` inherits from `DeferredAttribute` (defined in `django/db/models/query_utils.py`). The parent class `DeferredAttribute` does NOT define a `__set__` method; it only defines `__init__`, `__get__`, `_check_parent_chain`, `fetch_one`, and `fetch_many`. `FileDescriptor` adds its own `__set__` method which simply does `instance.__dict__[self.field.attname] = value`.\n\n2. In `FileDescriptor.__get__`, when the value retrieved from `super().__get__()` (which calls `DeferredAttribute.__get__`) is a `File` instance but NOT a `FieldFile`, the descriptor wraps it in `self.field.attr_class` (which is `FieldFile` for `FileField` or `ImageFieldFile` for `ImageField`), sets `file_copy._committed = False`, and stores the wrapped file in `instance.__dict__`.\n\n3. `FileDescriptor.__get__` handles five distinct cases: (a) string or None \u2192 wraps in attr_class, (b) `DatabaseDefault` instance \u2192 uses `self.field.db_default`, (c) `File` but not `FieldFile` \u2192 wraps and marks as uncommitted, (d) `FieldFile` without `field` attr \u2192 restores instance/field/storage, (e) `FieldFile` with mismatched instance \u2192 corrects the instance reference.\n\n4. The `DeferredAttribute.__get__` parent method handles deferred field loading: if the field name is not in `instance.__dict__`, it either checks the parent chain or calls `instance._state.fetch_mode.fetch(self, instance)` to load the value.\n\n5. `ImageFileDescriptor.__set__` extends `FileDescriptor.__set__` by additionally calling `self.field.update_dimension_fields(instance, force=True)` when `previous_file is not None`.", "rubric": [ "FileDescriptor is located in django/db/models/fields/files.py and inherits from DeferredAttribute (defined in django/db/models/query_utils.py)", "FileDescriptor is installed on model classes via FileField.contribute_to_class() using setattr(cls, self.attname, self.descriptor_class(self))", "DeferredAttribute does NOT define __set__; FileDescriptor adds its own __set__ that stores the value in instance.__dict__[self.field.attname]", "FileDescriptor.__get__ calls super().__get__() (DeferredAttribute.__get__) and then handles multiple cases: string/None wrapping, File-but-not-FieldFile wrapping with _committed=False, and FieldFile instance/field restoration", "DeferredAttribute.__get__ handles deferred field loading by checking instance.__dict__ and fetching values if not present", "ImageFileDescriptor subclasses FileDescriptor and extends __set__ to call update_dimension_fields when previous_file is not None" ], "key_files": [ "django/db/models/fields/files.py", "django/db/models/query_utils.py", "django/core/files/base.py" ], "source_doc": "[docstring: django/db/models/fields/files.py] django.db.models.fields.files.FileDescriptor\ndjango.db.models.fields.files.FileDescriptor:\n The descriptor for the file attribute on the model instance. Return a\n FieldFile when accessed so you can write code like::\n\n >>> from myapp.models import MyModel\n >>> instance = MyModel.objects.get(pk=1)\n >>> instance.file.size\n\n Assign a file object on assignment so you can do::\n\n >>> with open('/path/to/hello.world') as f:\n ... instance.file = File(f)", "verification_verdict": "pass", "verification_issues": [], "strip_verify_leakage": 0.1, "strip_verify_summary": "Minor doc leakage: line numbers, 'pickle recovery' annotation, and 'not during Model.__init__()' rationale are not verifiable from stripped code; all structural and logic claims are verifiable.", "generation_status": "completed", "generation_error": null }, { "id": "django_gen_10", "repo": "django", "question": "Why does Django's model Field class use so many cached_property decorators and custom copy/pickle methods instead of simpler implementations?", "category": "why", "sub_type": "performance", "gold_answer": "The Django `Field` class (in `django/db/models/fields/__init__.py`) employs several deliberate performance optimizations:\n\n**1. `cached_col` and `get_col()` \u2014 Avoiding repeated Col object creation during query compilation**\nThe `get_col()` method checks if the requested alias matches `self.model._meta.db_table` and the output_field is self or None; if so, it returns `self.cached_col`, a `@cached_property` that creates a single `Col(self.model._meta.db_table, self)` expression object and reuses it. Since `get_col()` is called during SQL compilation, the caching avoids repeatedly constructing identical `Col` objects for the most common case.\n\n**2. `_get_default` as `@cached_property` \u2014 Caching callable resolution once**\nThe `get_default()` method delegates to `self._get_default()`, but `_get_default` is a `@cached_property` that returns a *callable* (not the default value itself). This means the decision logic about what kind of default to use (callable default, static default wrapped in a lambda, `DatabaseDefault`, `return_None`, or `str`) is computed only once. The module-level `return_None` function exists so that fields returning `None` as their default can reference a shared function.\n\n**3. `__deepcopy__` uses shallow copy**\nThe `__deepcopy__` method uses `copy.copy(self)` (shallow copy) rather than true deep copy. Only `self.remote_field` gets shallow-copied if present.\n\n**4. `__copy__` uses `Empty()` to bypass `__reduce__`**\nThe `__copy__` method creates an `Empty()` instance and then reassigns its `__class__`, rather than using normal copy mechanics, which avoids triggering `__reduce__`. The `_empty()` function uses the same pattern for pickling unattached fields.\n\n**5. `__reduce__` \u2014 Pickling returns the canonical instance, not a copy**\nFor model-attached fields, `__reduce__` returns `_load_field` with `(app_label, model_name, field_name)`, which on unpickling fetches the field from `model._meta.get_field()`. It also pops `_get_default` from the pickle state.\n\n**6. `validators` and `error_messages` as `@cached_property` \u2014 Lazy computation**\nBoth `validators` and `error_messages` are `@cached_property`, meaning their values are computed once on first access and cached. The raw user-provided values are stored in `_validators` and `_error_messages` for deconstruction.\n\n**7. `unique` as `@cached_property` \u2014 Avoiding repeated boolean computation**\nThe `unique` property is a `@cached_property` that returns `self._unique or self.primary_key`, so the short-circuit boolean is evaluated once.\n\n**8. `creation_counter` and `__hash__` \u2014 O(1) hashing and O(log n) field insertion via bisect**\nThe `__hash__` returns `hash(self.creation_counter)`, an integer, which is O(1). The `__lt__` method (from `@total_ordering`) enables comparison. In `Options.add_field()` (options.py), `bisect.insort()` is used to insert fields into `local_fields` and `local_many_to_many` in sorted order, leveraging the `creation_counter` for O(log n) insertion.\n\n**9. `get_db_converters` uses `hasattr` check for `from_db_value`**\nThe `get_db_converters` method uses `hasattr(self, 'from_db_value')` rather than a default no-op method, so that the base Field class (which has no `from_db_value`) returns an empty list.\n\n**10. `get_class_lookups` uses `functools.cache` in RegisterLookupMixin**\nThe parent class `RegisterLookupMixin` (query_utils.py) uses `@functools.cache` on `get_class_lookups`, caching the merged MRO lookup dictionary per class. Cache is explicitly invalidated via `_clear_cached_class_lookups` only when new lookups are registered.", "rubric": [ "Mentions cached_col/get_col() caching Col objects to avoid repeated creation during SQL compilation", "Explains _get_default as a cached_property that caches the callable resolution logic (not the default value itself) so decision logic runs only once", "Describes __deepcopy__ using shallow copy instead of true deep copy for performance", "Explains __copy__ using Empty() class trick to bypass __reduce__ overhead", "Mentions __reduce__ returning _load_field for model-attached fields to fetch canonical instance rather than copying, and popping _get_default from state", "Notes validators and/or error_messages as @cached_property for lazy one-time computation", "Mentions unique as @cached_property to avoid repeated boolean evaluation", "Explains creation_counter enabling O(1) hashing and O(log n) sorted insertion via bisect", "Notes get_db_converters using hasattr check for from_db_value rather than a no-op method to avoid unnecessary converter overhead", "Mentions get_class_lookups using functools.cache in RegisterLookupMixin to cache merged MRO lookup dictionaries" ], "key_files": [ "django/db/models/fields/__init__.py", "django/db/models/query_utils.py", "django/db/models/options.py", "django/db/models/expressions.py" ], "source_doc": "[docstring: django/db/models/fields/__init__.py] django.db.models.fields.Field\ndjango.db.models.fields.Field:\n Base class for all field types\n\ndjango.db.models.fields.Field.__str__:\n Return \"app_label.model_label.field_name\" for fields attached to\n models.\n\ndjango.db.models.fields.Field.__repr__:\n Display the module, class, and name of the field.\n\ndjango.db.models.fields.Field._check_field_name:\n Check if field name is valid, i.e. 1) does not end with an\n underscore, 2) does not contain \"__\" and 3) is not \"pk\".\n\ndjango.db.models.fields.Field.select_format:\n Custom format for select clauses. For example, GIS columns need to be\n selected as AsText(table.col) on MySQL as the table.col data can't be\n used by Django.\n\ndjango.db.models.fields.Field.deconstruct:\n Return enough information to recreate the field as a 4-tuple:\n\n * The name of the field on the model, if contribute_to_class() has\n been run.\n * The import path of the field, including the class, e.g.\n django.db.models.IntegerField. This should be the most portable\n version, so less specific may be better.\n * A list of positional arguments.\n * A dict of keyword arguments.\n\n Note that the positional or keyword arguments must contain values of\n the following types (including inner values of collection types):\n\n * None, bool, str, int, float, complex, set, frozenset, list, tuple,\n dict\n * UUID\n * datetime.datetime (naive), datetime.date\n * top-level classes, top-level functions - will be referenced by their\n full import path\n * Storage instances - these have their own deconstruct() method\n\n This is because the values here must be serialized into a text format\n (possibly new Python code, possibly JSON) and these are the only types\n with encoding handlers defined.\n\n There's no need to return the exact way the field was instantiated this\n time, just ensure that the resulting field is the same - prefer keyword\n arguments over positional ones, and omit parameters with their default\n values.\n\ndjango.db.models.fields.Field.clone:\n Uses deconstruct() to clone a new copy of this Field.\n Will not preserve any class attachments/attribute names.\n\ndjango.db.models.fields.Field.__reduce__:\n Pickling should return the model._meta.fields instance of the field,\n not a new copy of that field. So, use the app registry to load the\n model and then the field back.\n\ndjango.db.models.fields.Field.get_pk_value_on_save:\n Hook to generate new PK values on save. This method is called when\n saving instances with no primary key value set. If this method returns\n something else than None, then the returned value is used when saving\n the new instance.\n\ndjango.db.models.fields.Field.to_python:\n Convert the input value into the expected Python data type, raising\n django.core.exceptions.ValidationError if the data can't be converted.\n Return the converted value. Subclasses should override this.\n\ndjango.db.models.fields.Field.validators:\n Some validators can't be created at field initialization time.\n This method provides a way to delay their creation until required.\n\ndjango.db.models.fields.Field.validate:\n Validate value and raise ValidationError if necessary. Subclasses\n should override this to provide validation logic.\n\ndjango.db.models.fields.Field.clean:\n Convert the value's type and run validation. Validation errors\n from to_python() and validate() are propagated. Return the correct\n value if no error is raised.\n\ndjango.db.models.fields.Field.db_check:\n Return the database column check constraint for this field, for the\n provided connection. Works the same way as db_type() for the case that\n get_internal_type() does not map to a preexisting model field.\n\ndjango.db.models.fields.Field.db_type:\n Return the database column data type for this field, for the provided\n connection.\n\ndjango.db.models.fields.Field.rel_db_type:\n Return the data type that a related field pointing to this field should\n use. For example, this method is called by ForeignKey and OneToOneField\n to determine its data type.\n\ndjango.db.models.fields.Field.cast_db_type:\n Return the data type to use in the Cast() function.\n\ndjango.db.models.fields.Field.db_parameters:\n Extension of db_type(), providing a range of different return values\n (type, checks). This will look at db_type(), allowing custom model\n fields to override it.\n\ndjango.db.models.fields.Field.db_returning:\n Private API intended only to be used by Django itself.\n\ndjango.db.models.fields.Field.contribute_to_class:\n Register the field with the model class it belongs to.\n\n If private_only is True, create a separate instance of this field\n for every subclass of cls, even if cls is not an abstract model.\n\ndjango.db.models.fields.Field.get_filter_kwargs_for_object:\n Return a dict that when passed as kwargs to self.model.filter(), would\n yield all instances having the same value for this field as obj has.\n\ndjango.db.models.fields.Field.pre_save:\n Return field's value just before saving.\n\ndjango.db.models.fields.Field.get_prep_value:\n Perform preliminary non-db specific value checks and conversions.\n\ndjango.db.models.fields.Field.get_db_prep_value:\n Return field's value prepared for interacting with the database\n backend.\n\n Used by the default implementations of get_db_prep_save().\n\ndjango.db.models.fields.Field.get_db_prep_save:\n Return field's value prepared for saving into a database.\n\ndjango.db.models.fields.Field.has_default:\n Return a boolean of whether this field has a default value.\n\ndjango.db.models.fields.Field.has_db_default:\n Return a boolean of whether this field has a db_default value.\n\ndjango.db.models.fields.Field.get_default:\n Return the default value for this field.\n\ndjango.db.models.fields.Field.get_choices:\n Return choices with a default blank choices included, for use\n as