Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"babel >= 2.9.0",
"cattrs >= 23.2.0",
"chardet >= 5.2.0",
"defusedxml >= 0.7.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
DataSource,
Referenceable,
)
from allotropy.parsers.utils.pandas import read_csv, SeriesData
from allotropy.parsers.utils.pandas import read_csv, series_to_float_list, SeriesData
from allotropy.parsers.utils.uuids import random_uuid_str
from allotropy.parsers.utils.values import (
try_float,
Expand Down Expand Up @@ -1246,7 +1246,8 @@ def create_spectrum_results(
data = read_csv(StringIO("\n".join(wavelengths_sections)), sep="\t")

try:
wavelengths = data["Wavelength"].astype(float).tolist()
# Use series_to_float_list for locale support
wavelengths = series_to_float_list(data["Wavelength"], "wavelength")
except (ValueError, KeyError):
return [], []

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
NEGATIVE_ZERO,
NOT_APPLICABLE,
)
from allotropy.parsers.utils.pandas import map_rows, SeriesData
from allotropy.parsers.utils.pandas import map_rows, series_to_float_list, SeriesData
from allotropy.parsers.utils.uuids import random_uuid_str


Expand Down Expand Up @@ -233,7 +233,7 @@ def create_cube_well_items(well_data: pd.DataFrame) -> list[WellItem]:
cycle_count = DataCubeComponent(
FieldComponentDatatype.integer, "cycle count", "#"
)
index_column = well_data["Index"].astype(float).tolist()
index_column = series_to_float_list(well_data["Index"], "index")

data = SeriesData(well_data.iloc[0])
well_items: list[WellItem] = []
Expand Down Expand Up @@ -291,7 +291,9 @@ def create_cube_well_items(well_data: pd.DataFrame) -> list[WellItem]:
)
],
dimensions=[index_column],
measures=[well_data[dye_setting].astype(float).tolist()],
measures=[
series_to_float_list(well_data[dye_setting], "fluorescence")
],
),
passive_reference_dye_data_cube=DataCube(
label="passive reference dye",
Expand All @@ -305,7 +307,10 @@ def create_cube_well_items(well_data: pd.DataFrame) -> list[WellItem]:
],
dimensions=[index_column],
measures=[
well_data[passive_dye_settings[0]].astype(float).tolist()
series_to_float_list(
well_data[passive_dye_settings[0]],
"passive_fluorescence",
)
],
),
errors=errors,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from allotropy.parsers.utils.calculated_data_documents.definition import (
CalculatedDocument,
)
from allotropy.parsers.utils.pandas import series_to_float_list
from allotropy.parsers.utils.values import quantity_or_none, try_float_or_none
from allotropy.types import DictType

Expand All @@ -62,8 +63,10 @@ def _get_sensorgram_datacube(sensorgram_data: pd.DataFrame) -> DataCube:
structure_measures=[
DataCubeComponent(FieldComponentDatatype.double, "resonance", "RU")
],
dimensions=[sensorgram_data["Time (s)"].astype(float).to_list()],
measures=[sensorgram_data["Sensorgram (RU)"].astype(float).to_list()],
dimensions=[series_to_float_list(sensorgram_data["Time (s)"], "time")],
measures=[
series_to_float_list(sensorgram_data["Sensorgram (RU)"], "sensorgram")
],
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,13 @@ def build_section(

if metric_token == "COUNT": # noqa: S105
analyte_cols = analyte_labels
# Convert each analyte column to numeric, coercing errors to NaN then filling with 0.0
# Convert each analyte column to numeric, coercing errors to 0.0
# Use try_float_or_none for locale support, then fill None with 0.0
converted = cast(
pd.DataFrame,
out[analyte_cols].apply(pd.to_numeric, errors="coerce").fillna(0.0),
out[analyte_cols]
.apply(lambda col: col.apply(try_float_or_none))
.fillna(0.0),
)
out["Total Events"] = converted.sum(axis=1)
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,9 @@ def create(reader: CsvReader, header: PlateHeader) -> PlateRawData:
data = get_plate_dataframe(reader, header, columns=columns)

# get temperature and elapsed time (kinetic) from the first column of the first row with value
first_row_idx = int(pd.to_numeric(data.first_valid_index()))
first_row_idx = int(
try_float(str(data.first_valid_index()), "first_valid_index")
)
temperature = try_non_nan_float_or_none(str(data.iloc[first_row_idx, 1]))
elapsed_time = None
if pd.notna(elapsed := data.iloc[first_row_idx, 0]):
Expand Down Expand Up @@ -592,7 +594,9 @@ def create(reader: CsvReader, header: PlateHeader) -> SpectrumPlateRawData:
wavelength_data: list[PlateWavelengthData] = []
for wavelength in header.wavelengths:
data = get_plate_dataframe(reader, header, columns=columns)
first_row_idx = int(pd.to_numeric(data.first_valid_index()))
first_row_idx = int(
try_float(str(data.first_valid_index()), "first_valid_index")
)
temperature = try_non_nan_float_or_none(str(data.iloc[first_row_idx, 1]))
wavelength_data.append(
PlateWavelengthData.create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
SAMPLE_ROLE_TYPES,
)
from allotropy.parsers.utils.pandas import read_csv, SeriesData
from allotropy.parsers.utils.values import try_float_or_none
from allotropy.types import IOType


def to_num(data: pd.Series[Any]) -> pd.Series[Any]:
return pd.to_numeric(data, errors="coerce").replace(np.nan, None)
# try_float_or_none returns None for invalid values, but pandas converts None to np.nan
# So we need to explicitly replace np.nan with None, just like the original pd.to_numeric did
return data.apply(try_float_or_none).replace(np.nan, None)


class RocheCedexBiohtReader:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from allotropy.exceptions import AllotropeConversionError
from allotropy.parsers.constants import NOT_APPLICABLE
from allotropy.parsers.thermo_fisher_genesys30 import constants
from allotropy.parsers.utils.pandas import SeriesData
from allotropy.parsers.utils.pandas import series_to_float_list, SeriesData
from allotropy.parsers.utils.uuids import random_uuid_str


Expand Down Expand Up @@ -72,7 +72,7 @@ def create_measurement_groups(
)
],
dimensions=[data["wavelength(nm)"].tolist()],
measures=[data["ABS"].astype(float).tolist()],
measures=[series_to_float_list(data["ABS"], "absorbance")],
),
device_control_custom_info={
"operating minimum": {
Expand Down
11 changes: 8 additions & 3 deletions src/allotropy/parsers/thermo_skanit/thermo_skanit_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
)
from allotropy.parsers.utils.pandas import df_to_series_data, parse_header_row
from allotropy.parsers.utils.uuids import random_uuid_str
from allotropy.parsers.utils.values import try_float_or_none
from allotropy.parsers.utils.values import try_float, try_float_or_none

MEASUREMENT_TYPES = {
MeasurementType.ULTRAVIOLET_ABSORBANCE: "Absorbance",
Expand Down Expand Up @@ -402,7 +402,10 @@ def _set_headers(df: pd.DataFrame) -> pd.DataFrame:
)
df = df[df.columns[valid_columns]]
# Cast row numbers to int (float first to handle decimals, e.g. 1.0)
df.columns = df.columns.astype(float).astype(int)
# Use try_float for locale support
df.columns = pd.Index( # type: ignore[assignment]
[int(try_float(str(col), "column_name")) for col in df.columns]
)
return df

@staticmethod
Expand Down Expand Up @@ -442,7 +445,9 @@ def identify_data_and_sample_dfs(
]
wavelength_data[current_wavelength] = data_df

current_wavelength = float(wavelength_match.group(1))
current_wavelength = try_float(
wavelength_match.group(1), "wavelength"
)
current_data_section = []
reading_data = False
reading_samples = False
Expand Down
40 changes: 40 additions & 0 deletions src/allotropy/parsers/utils/locale_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Context management for locale-aware number parsing.

This module provides utilities to set and manage the current locale context
for number parsing throughout the parsing pipeline.
"""

from __future__ import annotations

from collections.abc import Iterator
from contextlib import contextmanager

from allotropy.parsers.utils.values import _current_locale


@contextmanager
def set_locale_context(locale: str | None) -> Iterator[None]:
"""Context manager to set the locale for number parsing.

Args:
locale: The locale string (e.g., "en_US", "de_DE", "fr_FR") or None for default

Example:
>>> with set_locale_context("de_DE"):
... # All try_float() calls within this context will use German locale
... value = try_float("1.234,56", "value") # Parses as 1234.56
"""
token = _current_locale.set(locale)
try:
yield
finally:
_current_locale.reset(token)


def get_current_locale() -> str | None:
"""Get the currently set locale for number parsing.

Returns:
The current locale string or None if not set
"""
return _current_locale.get()
Loading
Loading