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
4 changes: 2 additions & 2 deletions src/nemo_safe_synthesizer/cli/artifact_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@

from __future__ import annotations

import os
from dataclasses import dataclass, field
from datetime import datetime
from os import PathLike
Comment thread
mckornfield marked this conversation as resolved.
Dismissed
from pathlib import Path
from typing import TYPE_CHECKING, Generic, Self, TypeVar, overload

Expand Down Expand Up @@ -229,7 +229,7 @@ def __get__(self, obj: object | None, objtype: type | None = None) -> DirNode |
raise TypeError(f"DirNode can only be used with BoundDir or Workdir, got {type(obj)}")


class BoundDir(os.PathLike[str]):
class BoundDir(PathLike[str]):
"""Runtime class representing a bound directory path.

Provides access to child FileNode and DirNode descriptors as attributes.
Expand Down
4 changes: 2 additions & 2 deletions src/nemo_safe_synthesizer/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ def _build_validate_run_info(


def _run_validate_and_render(
nss: "SafeSynthesizer",
nss: SafeSynthesizer,
*,
settings: CLISettings,
workdir: "Workdir",
workdir: Workdir,
config: SafeSynthesizerParameters,
data: pd.DataFrame,
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion src/nemo_safe_synthesizer/config/autoconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def get_max_token_count(data: pd.DataFrame, group_by: str | None) -> int:
counts["num_rows"] = 1

counts["content_text"] = counts["content"].apply(lambda x: re.sub(r"\d.", "", x))
counts["content_text_char_count"] = counts["content_text"].apply(lambda x: len(x))
counts["content_text_char_count"] = counts["content_text"].apply(len)
counts["content_num_char_count"] = counts.apply(lambda x: len(x["content"]) - len(x["content_text"]), axis=1)

# Estimate the token count from the character count
Expand Down
3 changes: 0 additions & 3 deletions src/nemo_safe_synthesizer/config/replace_pii.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@
from ..configurator.parameters import (
Parameters,
)
from ..observability import get_logger
from .base import NSSBaseModel
from .types import OptionalListOrInt, OptionalListOrStr, OptionalStrList

logger = get_logger(__name__)

__all__ = [
"PiiReplacerConfig",
"Globals",
Expand Down
2 changes: 0 additions & 2 deletions src/nemo_safe_synthesizer/configurator/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
"DataT", bound=(int | float | str | bytes | bool | None | Sequence[int | float | str | bytes | bool | BaseModel])
)

ParameterT = TypeVar("ParameterT", bound="Parameter")


@dataclass(eq=False, order=False)
class Parameter(Generic[DataT]):
Expand Down
2 changes: 0 additions & 2 deletions src/nemo_safe_synthesizer/configurator/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,12 @@
from ..config.base import (
pydantic_model_config,
)
from ..observability import get_logger
from .parameter import (
DataT,
)

__all__ = ["Parameters"]

logger = get_logger(__name__)
PathT = str | Path


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ class State(BaseModel):
dt_format: Optional[str]

def _infer_col_dt_format(self, col: pd.Series) -> Optional[str]:
dt_formats = col.apply(lambda x: guess_datetime_format(x))
dt_formats = col.apply(guess_datetime_format)
if len(dt_formats.unique()) > 1:
logger.warning("Multiple time formats found: %s", dt_formats.unique())

Expand Down
5 changes: 3 additions & 2 deletions src/nemo_safe_synthesizer/data_processing/actions/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def maybe_d_str_to_fmt_multiple(input_date: str) -> Iterator[str]:
try:
yield from d_str_to_fmt_multiple(input_date)
except ValueError:
pass
return


def d_str_to_fmt(input_date: str) -> Optional[str]:
Expand All @@ -393,6 +393,7 @@ def infer_from_series(date_series: Iterable[str]) -> Optional[str]:
highest_occurrence = fmt_occurrences.most_common(1)
if highest_occurrence:
return highest_occurrence[0][0]
return None


def fit_and_transform_dates(
Expand Down Expand Up @@ -432,7 +433,7 @@ def fit_and_transform_dates(
"min": str(min_date),
}
except (ValueError, TypeError):
pass
continue
return date_min_dict, result_df


Expand Down
14 changes: 6 additions & 8 deletions src/nemo_safe_synthesizer/data_processing/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

from __future__ import annotations

from contextlib import suppress

import numpy as np
import pandas as pd

Expand Down Expand Up @@ -62,24 +64,20 @@ def _handle_enum_value(v: object) -> None | int | float | bool | str:
if isinstance(v, np.bool_):
return bool(v)

try:
with suppress(TypeError, ValueError, OverflowError):
# Convert to python int if possible, but np.float32 and other float
# types will be truncated by int(v), so check equality to make sure
# we haven't lost precision.
t = int(v) # ty: ignore[invalid-argument-type] -- third-party stub mismatch
if t == v:
return t
except Exception:
pass

try:
# Convert to python float if possible
return float(v) # ty: ignore[invalid-argument-type] -- third-party stub mismatch
except Exception:
pass

# Otherwise, ensure we're using a python str to avoid json encoding errors
return str(v)
except (TypeError, ValueError, OverflowError):
# Otherwise, ensure we're using a python str to avoid json encoding errors.
return str(v)


def check_enum_type(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ def __init__(self, original):
self.original = original
self.kv_pairs = []
self.fields = set()
self.unpack()

@abstractmethod
def unpack(self): # pragma: no cover
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,25 +106,36 @@ class JSONRecord(base.BaseRecord):
Provides lookup by JSONPath or ``ValuePath``.
"""

def unpack(self):
def __init__(self, original):
super().__init__(original)
self._unpack_json()

def _unpack_json(self) -> None:
flattened_dict = flatten({"": self.original} if isinstance(self.original, str) else self.original)

kv_pairs = convert_flat_dict_to_kv_pairs(flattened_dict)
for pair in kv_pairs:
self.fields.add(pair.field)
self.kv_pairs.append(pair)

def unpack(self):
self.kv_pairs = []
self.fields = set()
self._unpack_json()

def value_for_json_path(self, json_path: str) -> Optional[str]:
"""Return the string value at ``json_path``, or None if not found."""
for pair in self.kv_pairs:
if pair.json_path == json_path:
return str(pair.value)
return None

def value_for_value_path(self, path: base.ValuePath) -> Optional[str]:
"""Return the string value at ``path``, or None if not found."""
for pair in self.kv_pairs:
if pair.value_path == path:
return str(pair.value)
return None

def flattened(self) -> dict[base.ValuePath, object]:
"""Return a dict mapping each ``ValuePath`` to its scalar value."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def _parse_dates(value: str | int | float, scalar_type: str | None = None) -> li
try:
value = float(value)
except (ValueError, TypeError):
pass
value = str(value)

if isinstance(value, float) and math.isnan(value):
# don't try to match something that is NaN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def _init_sentence_transformer_model() -> SentenceTransformer | None:
return SentenceTransformer("distiluse-base-multilingual-cased-v2")
except RetryError:
return None
return None

@staticmethod
def _get_embedding_vectors(
Expand Down Expand Up @@ -438,15 +439,11 @@ def _get_text_semantic_similarity(
)
text_semantic_similarity_overfitting_factor.notes = warning_message

try:
return (
text_semantic_similarity,
text_semantic_similarity_underfitting_factor,
text_semantic_similarity_overfitting_factor,
)
except Exception:
logger.exception("Failed to scale and finalize text semantic similarity.")
return EvaluationScore(), EvaluationScore(), EvaluationScore()
return (
text_semantic_similarity,
text_semantic_similarity_underfitting_factor,
text_semantic_similarity_overfitting_factor,
)

##
## PCA
Expand Down
12 changes: 6 additions & 6 deletions src/nemo_safe_synthesizer/evaluation/statistics/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ def _uptype_object_to_float(
try:
l = l.astype({col: "float"}) # noqa: E741
r = r.astype({col: "float"}) # noqa: E741
except Exception:
# In particular ValueErrors if the non-numeric is not convertible, but catch everything.
except (TypeError, ValueError, OverflowError):
# Keep non-convertible mixed columns in their original dtype.
pass
return l, r

Expand Down Expand Up @@ -144,14 +144,14 @@ def get_numeric_distribution_bins(training: pd.Series, synthetic: pd.Series) ->
# We also bin across the training and synthetic Series combined since we are binning across the combined range, otherwise we can see OOM's or sigkill's.
try:
bins = np.histogram_bin_edges(pd.concat([training, synthetic]), bins="doane", range=(min_value, max_value))
except Exception:
pass
except (TypeError, ValueError):
bins = np.array([], dtype=np.float64)
# If 'doane' still doesn't do the trick just force 500 bins.
if len(bins) == 0 or len(bins) > 500:
try:
bins = np.histogram_bin_edges(pd.concat([training, synthetic]), bins=500, range=(min_value, max_value))
except Exception:
pass
except (TypeError, ValueError):
bins = np.array([], dtype=np.float64)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return bins


Expand Down
6 changes: 4 additions & 2 deletions src/nemo_safe_synthesizer/generation/vllm_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _install_noop_remote_cache_backends() -> None:
RemoteAutotuneCache.backend_override_cls = _NoopRemoteCacheBackend # ty: ignore[invalid-assignment]
logger.debug("Installed no-op backend for RemoteAutotuneCache (redis unavailable)")
except ImportError:
pass
logger.debug("RemoteAutotuneCache is unavailable; skipping no-op backend patch", exc_info=True)


_install_noop_remote_cache_backends()
Expand Down Expand Up @@ -185,7 +185,7 @@ def __del__(self) -> None:
try:
self.teardown()
except Exception:
pass
logger.debug("VllmBackend teardown failed during garbage collection", exc_info=True)

def initialize(self, **kwargs) -> None:
"""Initialize and load the model into memory.
Expand Down Expand Up @@ -447,6 +447,8 @@ def _generate(
case _:
raise ValueError("input_ids are not a tensor, list, or None!")

if result is None:
raise ValueError("input_ids are not a tensor, list, or None!")
return result
case _:
raise ValueError("input ids are not a tensor or list!")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ def _try_extract_entities(
except ValidationError:
logger.exception("Error decoding classification JSON returned by llm")
on_validation_error()
return {}


class ColumnClassifier(ABC):
Expand Down Expand Up @@ -651,7 +652,6 @@ def _detect_entities_chunked(
"ctx": {"nchunks": nchunks, "misses": n_cache_miss},
},
)
last_log = monotonic()
entities_to_delete = []
for idx, ent in enumerate(entities):
has_superset = any(
Expand Down
10 changes: 4 additions & 6 deletions src/nemo_safe_synthesizer/pii_replacer/data_editor/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,10 @@ def _render_cell(
try:
foreach_itr = ast.literal_eval(foreach_str)
except (ValueError, TypeError, SyntaxError):
pass

try:
foreach_itr = json.loads(foreach_str)
except (json.JSONDecodeError, TypeError):
pass
try:
foreach_itr = json.loads(foreach_str)
except (json.JSONDecodeError, TypeError):
foreach_itr = None

try:
iter(foreach_itr)
Expand Down
11 changes: 5 additions & 6 deletions src/nemo_safe_synthesizer/pii_replacer/ner/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import re
from dataclasses import dataclass, field
from pathlib import Path
from re import Pattern
from typing import Optional

import yaml
Expand Down Expand Up @@ -82,7 +81,7 @@ def __post_init__(self):
raise CustomPredictorError("score must be one of low, med, high")

self.regex_compiled = self.regex
if not isinstance(self.regex, Pattern):
if not isinstance(self.regex, re.Pattern):
self.regex_compiled = re.compile(str(self.regex))

self._load_header_patterns()
Expand Down Expand Up @@ -141,13 +140,13 @@ def _namespace_from_config(config: dict) -> str:
#####################


def get_regex_predictors_from_config(config: dict) -> Optional[list[RegexPredictor]]:
def get_regex_predictors_from_config(config: dict) -> list[RegexPredictor]:
out_predictors = []
namespace = _namespace_from_config(config)

predictor_dicts = config.get("regex", None)
if predictor_dicts is None:
return
return []

for name, patterns in predictor_dicts.items():
predictor_name = name.lower()
Expand Down Expand Up @@ -179,13 +178,13 @@ def _process_phrase_list_file(config: dict, builder: PhraseMatcherBuilder) -> Ph
return builder


def get_phrase_predictors_from_config(config: dict) -> Optional[list[RegexPredictor]]:
def get_phrase_predictors_from_config(config: dict) -> list[RegexPredictor]:
out_predictors = []
namespace = _namespace_from_config(config)

phrase_predictors = config.get("phrase", None)
if phrase_predictors is None:
return
return []

for predictor_name, phrase_config in phrase_predictors.items():
predictor_name = predictor_name.lower()
Expand Down
4 changes: 2 additions & 2 deletions src/nemo_safe_synthesizer/pii_replacer/ner/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ def _parse_dates(value: str | int | float, scalar_type: Optional[str] = None) ->
# original value was a number.
try:
value = float(value)
except Exception:
pass
except (ValueError, TypeError):
value = str(value)

if isinstance(value, float) and math.isnan(value):
# don't try to match something that is NaN
Expand Down
Loading
Loading