File indexing completed on 2026-09-28 09:36:47
0001 """
0002 Type of a spec column whose unset value reads back as the "NULL" sentinel.
0003
0004 JobSpec, FileSpec and DatasetSpec install their columns as None and override
0005 __getattribute__ to substitute the string "NULL" for a column that is still None. A read
0006 therefore yields the column type or that sentinel, while a write takes the column type or
0007 None -- two types for one attribute, which only a descriptor can express.
0008
0009 Declaring a column as SpecColumn[int] instead of `int | str` gives a type checker both
0010 halves:
0011
0012 job.PandaID # int | str
0013 job.PandaID = 5 # ok
0014 job.PandaID = None # ok, and reads back as "NULL"
0015 job.PandaID = "5" # error, which `int | str` could not catch
0016
0017 The declarations carry no value, so nothing here runs beyond building the generic alias
0018 when the spec module is imported; the columns are still installed by __init__.
0019
0020 The "NULL" sentinel is legacy debt. When it goes, every SpecColumn[T] becomes T | None and
0021 this module is deleted.
0022 """
0023
0024 from typing import Generic, Literal, TypeVar
0025
0026 _T = TypeVar("_T")
0027
0028
0029 Null = Literal["NULL"]
0030
0031
0032 class SpecColumn(Generic[_T]):
0033 """A spec column: read as _T or the "NULL" sentinel, written as _T, None or that
0034 sentinel -- writing it back is how a column is copied from one spec to another, and
0035 valuesMap() turns it into a NULL bind value just as it does for None."""
0036
0037 def __get__(self, obj: object, objtype: "type | None" = None) -> "_T | Null":
0038
0039
0040 raise NotImplementedError
0041
0042 def __set__(self, obj: object, value: "_T | Null | None") -> None:
0043 raise NotImplementedError