{"record":{"id":"2bb63d31cfa9a852","repo":"pandas-dev/pandas","slug":"periodarray-does-not-allow-floating-point-in-const","errorCode":null,"errorMessage":"PeriodArray does not allow floating point in construction","messagePattern":"PeriodArray does not allow floating point in construction","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/period.py","lineNumber":306,"sourceCode":"                return scalars.copy()\n            return scalars\n\n        if not isinstance(\n            scalars, (np.ndarray, list, tuple, ABCSeries, ABCIndex, ExtensionArray)\n        ):\n            # test_constructor_empty_special has a case with an iter object\n            scalars = list(scalars)\n\n        if isinstance(scalars, ExtensionArray) and scalars.dtype.kind in \"iu\":\n            # e.g. masked or arrow-backed integer array; np.asarray would cast\n            #  integers-with-NA to float and raise a misleading \"floating point\"\n            #  error below, so route through object dtype to keep the integers.\n            scalars = scalars.to_numpy(dtype=object, na_value=NaT)\n\n        arrdata = np.asarray(scalars)\n        if arrdata.dtype.kind == \"f\" and len(arrdata) > 0:\n            if not lib.all_nans(arrdata):\n                raise TypeError(\n                    \"PeriodArray does not allow floating point in construction\"\n                )\n            ordinals = np.full(arrdata.shape, iNaT, dtype=np.int64)\n            return cls(ordinals, dtype=dtype)\n\n        elif arrdata.dtype.kind in \"iu\":\n            arr = arrdata.astype(np.int64, copy=False)\n            ordinals = libperiod.from_calendar_ordinals(arr, dtype)  # type: ignore[arg-type]\n            return cls(ordinals, dtype=dtype)\n        else:\n            periods = ensure_object(arrdata)\n\n            if dtype is None:\n                dtype_base = libperiod.extract_period_unit(periods)\n                dtype = PeriodDtype(dtype_base)\n            ordinals = libperiod.extract_ordinals(periods, dtype)  # type: ignore[arg-type]\n            return cls(ordinals, dtype=dtype)\n","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/arrays/period.py#L288-L324","documentation":"Raised by PeriodArray._from_sequence when the coerced input has float dtype and contains at least one non-NaN value. Period ordinals are integers by definition, so genuine floating-point data cannot be interpreted as periods; only all-NaN float arrays are tolerated (interpreted as all-NaT).","triggerScenarios":"pd.period_array([1.5, 2.0], dtype=...), pd.PeriodIndex([3.14]), or feeding a float Series into a period dtype. Numeric columns with NaN that get cast to float before being treated as periods but contain real fractional values.","commonSituations":"Reading a CSV column of years as float (2020.0) and trying to build a PeriodIndex. Mixing NaN with integer-like data producing float dtype. Off-by-one casts from nullable Int64 to Float64.","solutions":["Cast to integer first: np.asarray(data, dtype='int64') (only safe if no fractional part).","Drop or NaN-out fractional values, then construct from strings/Period objects.","Build from Period objects or ISO strings via pd.period_array(['2020-01-01', ...])."],"exampleFix":"# before\npd.period_array([2020.5, 2021.0], dtype=pd.PeriodDtype('Y'))\n# after\npd.period_array([2020, 2021], dtype=pd.PeriodDtype('Y'))\n# or from strings\npd.period_array(['2020','2021'], dtype=pd.PeriodDtype('Y'))","handlingStrategy":"validation","validationCode":"import numpy as np\nimport pandas as pd\n\ndef to_period_safe(data, freq):\n    arr = np.asarray(data)\n    if arr.dtype.kind == 'f':\n        if not pd.isna(arr).all() and not np.all(np.equal(np.mod(arr, 1), 0)):\n            raise ValueError('data has fractional floats; cannot be periods')\n        arr = arr.astype('int64', copy=False)\n    return pd.period_array(arr, dtype=pd.PeriodDtype(freq))","typeGuard":"import numpy as np\n\ndef is_integer_or_all_nan_float(arr) -> bool:\n    a = np.asarray(arr)\n    if a.dtype.kind == 'i':\n        return True\n    if a.dtype.kind == 'f':\n        return bool(np.all(np.isnan(a)) or np.all(np.equal(np.mod(a, 1), 0)))\n    return False","tryCatchPattern":"try:\n    pa = pd.period_array(data, dtype=pd.PeriodDtype(freq))\nexcept TypeError:\n    pa = pd.period_array(np.asarray(data, dtype='int64'), dtype=pd.PeriodDtype(freq))","preventionTips":["Coerce period-source columns to Int64 at load time, not Float64.","Reject fractional floats upstream rather than relying on the period constructor.","Prefer building periods from ISO strings or Period objects."],"tags":["period","dtype","float","constructor","pandas-arrays"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}