Skip to content
Open
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
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed
- **`scitex-clew` is a FLOOR (`>=0.20.1`), not an exact pin.** All three
occurrences in `pyproject.toml` (core dependency, the `clew` extra, the
`dev` extra) read `scitex-clew==0.17.0` — a July 6 build. clew moved its
four stores off the retired embedded file engine onto the per-host
PostgreSQL, and because of the `==` that never reached this package:
running this suite still re-created a `.scitex/clew/runtime/clew.db`
database file. `>=0.20.1` sets the floor at the first clew release that
carries the migration with honest metadata, and lets subsequent fixes
through.
- **`scitex-dev` also becomes a FLOOR (`>=0.57.0`), not an exact pin —
required by the clew floor above.** clew's stores resolve through
`scitex_dev.store.host_store()`, and the previous exact `scitex-dev==0.28.0`
pin has no `scitex_dev.store` at all. Left at 0.28.0 the resolve still
SUCCEEDS and the failure lands at import instead: `failed to load plugin
'clew': ModuleNotFoundError: No module named 'scitex_dev.store'`, with
three clew integration tests failing on all three Python legs. clew 0.20.1
declares `scitex-dev>=0.49.2` — a floor measured by a real write-then-read,
since 0.43.1 imports every symbol clew uses and still raises `TypeError:
tuple indices must be integers or slices, not str` inside `Store.rows()`.
0.57.0 is PyPI's newest at time of writing; using `>=` rather than `==`
here avoids repeating the exact freeze bug this PR fixes for clew.
- **`scitex-scholar` 1.4.2 → 1.4.3 and `scitex-ssh` 1.0.1 → 1.1.0, required
by the scitex-dev floor above.** scitex-dev 0.57.0 itself declares
`scitex-scholar>=1.4.3` and `scitex-ssh>=1.1.0`; the previous exact pins
here (`==1.4.2`, `==1.0.1`) were below both floors and made the whole
dependency set unresolvable (`uv`: "your requirements are unsatisfiable"),
measured directly from a failed CI run on this branch before this commit.
Both stay exact pins (unlike clew/scitex-dev above) — this is a transitive
unblock, not the freeze-prone coupling this PR targets.

## [2.30.5] - 2026-06-30

### Changed
Expand Down
46 changes: 33 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,38 @@ dependencies = [
"beautifulsoup4>=4.12.0", # HTML parsing - used by web/cli modules
# Config + env loading (scitex.helpers.load_scitex_env delegates here)
"scitex-config==0.3.6",
# Reproducibility Verification
"scitex-clew==0.17.0",
# Reproducibility Verification.
# A FLOOR, not a pin: an exact `==` froze this at 0.17.0 (2026-07-06) for
# two months, so the storage-backend migration shipped in clew 0.20.0 never
# reached anyone here and the retired embedded file engine kept being used.
# 0.20.0 is the first release where clew's stores resolve through
# scitex_dev.store.host_store() instead of a database file; 0.20.1 is the
# first that declares an honest scitex-dev floor for it.
"scitex-clew>=0.20.1",
# App SDK — unified file storage for local + cloud
"scitex-app==0.2.11",
# Delegated core modules (thin re-exports)
"scitex-dev==0.28.0",
#
# scitex-dev 0.28.0 -> a FLOOR at 0.57.0, not a pin — same reasoning as the
# clew floor above, and REQUIRED BY it: clew's stores resolve through
# `scitex_dev.store.host_store()`, and 0.28.0 has no `scitex_dev.store` at
# all. Left at an exact 0.28.0 pin the resolve still SUCCEEDS and the
# failure lands at import instead — measured here as "failed to load
# plugin 'clew': ModuleNotFoundError: No module named 'scitex_dev.store'"
# plus three failing clew integration tests on all three Python legs.
# The floor clew declares is 0.49.2, measured by a real write-then-read
# (0.43.1 imports every symbol and still TypeErrors inside `Store.rows()`);
# 0.57.0 is PyPI's newest at time of writing. An exact `==` here would
# repeat the exact bug this PR fixes for clew, so this is `>=`, not `==`.
"scitex-dev>=0.57.0",
"scitex-io==0.3.3",
"scitex-stats==0.2.24",
"scitex-audio==0.3.0",
"scitex-notification==0.2.9",
"scitex-notebook==0.1.2",
# Delegated modules from #51 standalonization
"scitex-db==0.1.12",
"scitex-scholar==1.4.2",
"scitex-scholar==1.4.3",
"scitex-parallel==0.1.8",
"scitex-types==0.1.6",
"scitex-path==0.1.7",
Expand Down Expand Up @@ -658,7 +676,7 @@ scholar = [
"connectedpapers-py",
# # Heavy dependencies handled by _AVAILABLE flags
# "torch",
"scitex-scholar==1.4.2"
"scitex-scholar==1.4.3"
]

# Schema Module - Data schema validation
Expand Down Expand Up @@ -730,7 +748,7 @@ tex = [
# Tunnel Module - SSH reverse tunnel for NAT traversal
# Use: pip install scitex[tunnel]
tunnel = [
"scitex-ssh==1.0.1",
"scitex-ssh==1.1.0",
]

# Torch Module - PyTorch support
Expand Down Expand Up @@ -792,8 +810,10 @@ web = [

# Clew Module - Hash-based verification for reproducible science (Ariadne's thread)
# Use: pip install scitex[clew]
# Note: No extra dependencies - uses only the standard library
clew = ["scitex-clew==0.17.0"]
# Note: clew's own dependencies come with it. Since 0.20.0 its stores resolve
# through scitex_dev.store.host_store() (the per-host PostgreSQL), not a
# database file, so this is no longer a standard-library-only extra.
clew = ["scitex-clew>=0.20.1"]

# Writer Module - Academic paper writing
# Use: pip install scitex[writer]
Expand Down Expand Up @@ -948,20 +968,20 @@ dev = [
"scitex-audio==0.3.0",
"scitex-audit==0.2.0",
"scitex-browser==0.1.15",
"scitex-clew==0.17.0",
"scitex-clew>=0.20.1",
# NOTE: scitex-hub (optional peer powering cloud/module/project; formerly
# scitex-cloud) is intentionally NOT in [dev] — it is unreleased, so listing
# it here would break CI's `.[all,dev]` resolve. Install explicitly via
# `pip install scitex[cloud]` when scitex-hub is available.
"scitex-container==0.2.1",
"scitex-dataset==0.5.0",
"scitex-dev==0.28.0",
"scitex-dev>=0.57.0",
"scitex-etc==0.2.1",
"scitex-genai==0.1.1",
"scitex-io==0.3.3",
"scitex-notification==0.2.9",
"scitex-scholar==1.4.2",
"scitex-ssh==1.0.1",
"scitex-scholar==1.4.3",
"scitex-ssh==1.1.0",
"scitex-stats==0.2.24",
"scitex-ui==0.6.0",
"scitex-writer==2.24.1",
Expand Down Expand Up @@ -1091,7 +1111,7 @@ all = [
# ============================================
# Tool Configurations
# ============================================
linter = ["scitex-dev==0.28.0"]
linter = ["scitex-dev>=0.57.0"]
orochi = ["scitex-orochi==0.17.0"]
agent-container = ["scitex-agent-container==0.21.11"]

Expand Down
45 changes: 40 additions & 5 deletions tests/integration/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,37 @@ def tmp_dir():
shutil.rmtree(d, ignore_errors=True)


@pytest.fixture(scope="module")
def _clew_store_dsn():
"""A throwaway local PostgreSQL cluster for clew's store-backed tests.

As of scitex-clew>=0.20.1, clew's four stores resolve through
`scitex_dev.store.host_store()`, which defaults to the fleet's central
Postgres (unreachable from this off-fleet CI runner, and not something a
test must ever write to regardless). Point `SCITEX_STORE_DSN` at a
private, throwaway cluster instead, using the exact affordance
scitex-dev shipped for this: scitex-scholar, scitex-writer and
scitex-dev's own CI independently hit the same "off-fleet CI cannot
exercise a store-backed path" wall on 2026-08-29, and
`scitex_dev.store.testing.ephemeral_cluster_dsn()` is the shared fix.

Module-scoped: one throwaway cluster serves every clew test in this
file rather than paying `initdb`+`pg_ctl start` per test.
"""
testing = pytest.importorskip("scitex_dev.store.testing")
try:
with testing.ephemeral_cluster_dsn() as dsn:
yield dsn
except RuntimeError as exc:
pytest.skip(f"no throwaway PostgreSQL available for clew's store: {exc}")


@pytest.fixture
def _clew_store(_clew_store_dsn, monkeypatch):
"""Point SCITEX_STORE_DSN at the throwaway cluster for one test."""
monkeypatch.setenv("SCITEX_STORE_DSN", _clew_store_dsn)


# ---------------------------------------------------------------------------
# 1. Lazy loading and namespace
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -208,17 +239,21 @@ def test_ecosystem_registry(self):
class TestClewIntegration:
"""Verify stx.clew is accessible through unified namespace."""

def test_status(self):
def test_status(self, _clew_store):
result = stx.clew.status()
assert isinstance(result, dict)

def test_hash_file(self, tmp_dir):
def test_hash_file(self, tmp_dir, _clew_store):
path = os.path.join(tmp_dir, "test.txt")
with open(path, "w") as f:
f.write("hello")
h = stx.clew.hash_file(path)
assert isinstance(h, str)
assert len(h) == 32 # SHA-256 prefix
# Full SHA-256 hex digest (64 chars). Prior to scitex-clew's
# clew-fix-truncated-hash-comparison fix, hash_file() returned the
# first 32 hex chars only, which silently broke external hash
# comparisons; clew now returns the full digest.
assert len(h) == 64


# ---------------------------------------------------------------------------
Expand All @@ -229,13 +264,13 @@ def test_hash_file(self, tmp_dir):
class TestCrossModuleWorkflow:
"""Verify modules work together in realistic workflows."""

def test_io_save_then_clew_hash(self, tmp_dir):
def test_io_save_then_clew_hash(self, tmp_dir, _clew_store):
"""Save a file via stx.io, verify clew can hash it."""
path = os.path.join(tmp_dir, "data.csv")
df = pd.DataFrame({"a": [1, 2, 3]})
stx.io.save(df, path)
h = stx.clew.hash_file(path)
assert len(h) == 32
assert len(h) == 64 # full SHA-256 hex digest, see test_hash_file

def test_stats_then_io_save(self, tmp_dir):
"""Run a stat test, save results via stx.io."""
Expand Down
Loading