diff --git a/CHANGELOG.md b/CHANGELOG.md index a3df26065..ba664996f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/pyproject.toml b/pyproject.toml index 265512614..52892f0e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,12 +78,30 @@ 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", @@ -91,7 +109,7 @@ dependencies = [ "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", @@ -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 @@ -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 @@ -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] @@ -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", @@ -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"] diff --git a/tests/integration/test_integration.py b/tests/integration/test_integration.py index 29ae13d21..491849efb 100755 --- a/tests/integration/test_integration.py +++ b/tests/integration/test_integration.py @@ -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 # --------------------------------------------------------------------------- @@ -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 # --------------------------------------------------------------------------- @@ -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."""