Repository: pola-rs/polars
File: py-polars/polars/io/spreadsheet/functions.py (Python)

Code before:
            return _identify_from_magic_bytes(magic_bytes)


def _read_spreadsheet(
    sheet_id: int | Sequence[int] | None,
    sheet_name: str | list[str] | tuple[str] | None,
    source: str | Path | IO[bytes] | bytes,
    engine: ExcelSpreadsheetEngine | Literal["ods"] | None,
    engine_options: dict[str, Any] | None = None,
    read_options: dict[str, Any] | None = None,
    schema_overrides: SchemaDict | None = None,
    infer_schema_length: int | None = N_INFER_DEFAULT,
    *,
    raise_if_empty: bool = True,
) -> pl.DataFrame | dict[str, pl.DataFrame]:
    if is_file := isinstance(source, (str, Path)):
        source = normalize_filepath(source)
        if looks_like_url(source):
            source = process_file_url(source)

    if engine is None:
        if is_file and str(source).lower().endswith(".ods"):
            # note: if called from "read_ods" the engine cannot be 'None', hence
            # this check is only triggered when called from "read_excel"
            msg = "OpenDocumentSpreadsheet files require use of `read_ods`, not `read_excel`"
            raise ValueError(msg)

        # note: eventually want 'calamine' to be the default for all extensions
        file_type = _identify_workbook(source)
        engine = "calamine" if file_type in ("xlsb", "xls") else "xlsx2csv"

    read_options = (read_options or {}).copy()
    engine_options = (engine_options or {}).copy()

    # normalise some top-level parameters to 'read_options' entries
    if engine == "calamine":
        if ("schema_sample_rows" in read_options) and (
            infer_schema_length != N_INFER_DEFAULT
        ):
            msg = 'cannot specify both `infer_schema_length` and `read_options["schema_sample_rows"]`'
            raise ParameterCollisionError(msg)
        read_options["schema_sample_rows"] = infer_schema_length

    elif engine == "xlsx2csv":
        if ("infer_schema_length" in read_options) and (
            infer_schema_length != N_INFER_DEFAULT
        ):
            msg = 'cannot specify both `infer_schema_length` and `read_options["infer_schema_length"]`'
            raise ParameterCollisionError(msg)
        read_options["infer_schema_length"] = infer_schema_length
    else:

Review comment (suggestion):
This part of the logic wasn't being hit anymore since `engine` cannot be None. Not sure if we still need this.

Code after:
            return "xlsx"
    except UnicodeDecodeError:
        pass
    finally:
        data.seek(initial_position)
    return None


def _identify_workbook(wb: str | Path | IO[bytes] | bytes) -> str | None:
    """Use file extension (and magic bytes) to identify Workbook type."""
    if not isinstance(wb, (str, Path)):
        # raw binary data (bytesio, etc)
        return _identify_from_magic_bytes(wb)
    else:
        p = Path(wb)
        ext = p.suffix[1:].lower()

        # unambiguous file extensions
        if ext in ("xlsx", "xlsm", "xlsb"):
            return ext
        elif ext[:2] == "od":
            return "ods"

        # check magic bytes to resolve ambiguity (eg: xls/xlsx, or no extension)
        with p.open("rb") as f:
            magic_bytes = BytesIO(f.read(8))
            return _identify_from_magic_bytes(magic_bytes)


def _read_spreadsheet(
    sheet_id: int | Sequence[int] | None,
    sheet_name: str | list[str] | tuple[str] | None,
    source: str | Path | IO[bytes] | bytes,
    engine: ExcelSpreadsheetEngine,
    engine_options: dict[str, Any] | None = None,
    read_options: dict[str, Any] | None = None,
    schema_overrides: SchemaDict | None = None,
    infer_schema_length: int | None = N_INFER_DEFAULT,
    columns: Sequence[int] | Sequence[str] | None = None,
    *,
    raise_if_empty: bool = True,
) -> pl.DataFrame | dict[str, pl.DataFrame]:
    if isinstance(source, (str, Path)):
        source = normalize_filepath(source)
        if looks_like_url(source):
            source = process_file_url(source)

    read_options = (read_options or {}).copy()
    engine_options = (engine_options or {}).copy()

    # normalise some top-level parameters to 'read_options' entries