get_provenance

get_provenance(random_state=None, data=None)[source]

Obtain a provenance record describing how a run can be reproduced.

Opt-in and side-effect free: nothing in AAanalysis attaches this record to its output, and no return type changes. Call it next to a run and keep the record with the results.

The one field external code cannot easily recover is the effective resolved seed: random_state is resolved here through the very same check the tools use, so the record reports the seed that actually takes effect, including when options['random_state'] overrides the value passed in.

Added in version 1.1.0.

Parameters:
  • random_state (int, optional) – Seed as it would be passed to a tool (its constructor random_state or a per-call seed). Resolved through the global options['random_state'] override, so the recorded value is the one that takes effect. None means no seed is in effect (stochastic steps vary between runs).

  • data (array-like, pd.DataFrame, or pd.Series, optional) – Input to fingerprint (e.g. df_seq, X, or labels). When given, a stable sha256 digest is recorded so a later run can confirm it used the same input. When None, input_hash is None.

Returns:

dict_provenance – JSON-serializable record with the following keys:

  • aaanalysis_version: the installed package version.

  • python_version: the running interpreter version.

  • dependencies: {name: version} for the dependencies whose version can change a computed result (None for any not installed).

  • git_commit: commit of the package checkout, or None for a regular (non-source) install.

  • random_state: the effective resolved seed, or None.

  • deterministic: True when an effective seed is in force, so every stochastic step is reproducible; False when no seed is in effect. A tool that uses no randomness is reproducible either way.

  • input_hash: sha256:<hex> over data, or None.

Return type:

dict

Notes

The record deliberately carries no timestamp or hostname: every field is something that can change a result, which is what makes two records comparable for equality as a reproducibility key.

Examples

The get_provenance function returns a plain, JSON-serializable dict recording how a run can be reproduced. It is opt-in: no AAanalysis function attaches it to its output and no return type changes, so results stay plain numpy and pandas. You call it next to a run and keep the record with the results.

The one field external code cannot easily recover is the effective resolved seed — the seed that actually takes effect after the options['random_state'] → constructor → per-call resolution.

import json
import aaanalysis as aa
aa.options["verbose"] = False

# 'random_state' is resolved through the same check the tools use, so the record
# reports the seed that actually takes effect.
provenance = aa.get_provenance(random_state=42)
print(json.dumps(provenance, indent=2))
{
  "aaanalysis_version": "1.0.3",
  "python_version": "3.14.0",
  "dependencies": {
    "numpy": "2.4.6",
    "pandas": "3.0.3",
    "scikit-learn": "1.8.0",
    "scipy": "1.17.1"
  },
  "git_commit": "c58533da287242645e419ee9c3679e71051e1f05",
  "random_state": 42,
  "deterministic": true,
  "input_hash": null
}

Every value is JSON-native, so the record round-trips through json.dumps and can be written to disk next to the results it describes. deterministic says whether a seed is in force: with one, every stochastic step is reproducible; without one (random_state=None), stochastic steps vary between runs.

print("round-trips through JSON:", json.loads(json.dumps(provenance)) == provenance)

# Without a seed the run is stochastic, and the record says so.
unseeded = aa.get_provenance()
print("random_state:", unseeded["random_state"], "| deterministic:", unseeded["deterministic"])
round-trips through JSON: True
random_state: None | deterministic: False

Pass the run’s input to data to fingerprint it. A stable sha256 digest is recorded, so a later run can confirm it started from the same input. data accepts a DataFrame, Series, array, or list — e.g. df_seq, the feature matrix X, or labels.

df_seq = aa.load_dataset(name="DOM_GSEC", n=5)
aa.display_df(df=df_seq, n_rows=10, show_shape=True)
DataFrame shape: (10, 9)
  entry gene sequence label tmd_start tmd_stop jmd_n tmd jmd_c
1 Q14802 FXYD3 MQKVTLGLLVFLAGF...PGETPPLITPGSAQS 0 37 59 NSPFYYDWHS LQVGGLICAGVLCAMGIIIVMSA KCKCKFGQKS
2 Q86UE4 MTDH MAARSWQDELAQQAE...SPKQIKKKKKARRET 0 50 72 LGLEPKRYPG WVILVGTGALGLLLLFLLGYGWA AACAGARKKR
3 Q969W9 PMEPA1 MHRLMGVNSTAAAAA...AIWSKEKDKQKGHPL 0 41 63 FQSMEITELE FVQIIIIVVVMMVMVVVITCLLS HYKLSARSFI
4 P53801 PTTG1IP MAPGVARGPTPYWRL...GLFKEENPYARFENN 0 97 119 RWGVCWVNFE ALIITMSVVGGTLLLGIAICCCC CCRRKRSRKP
5 Q8IUW5 RELL1 MAPRALPGSAVLAAA...EVPATPVKRERSGTE 0 59 81 NDTGNGHPEY IAYALVPVFFIMGLFGVLICHLL KKKGYRCTTE
6 P05067 APP MLPGLALLLLAAWTA...GYENPTYKFFEQMQN 1 701 723 FAEDVGSNKG AIIGLMVGGVVIATVIVITLVML KKKQYTSIHH
7 P14925 Pam MAGRARSGLLLLLLG...EEEYSAPLPKPAPSS 1 868 890 KLSTEPGSGV SVVLITTLLVIPVLVLLAIVMFI RWKKSRAFGD
8 P70180 Npr3 MRSLLLFTFSACVLL...RELREDSIRSHFSVA 1 477 499 PCKSSGGLEE SAVTGIVVGALLGAGLLMAFYFF RKKYRITIER
9 Q03157 Aplp1 MGPTSPAARGQGRRW...HGYENPTYRFLEERP 1 585 607 APSGTGVSRE ALSGLLIMGAGGGSLIVLSLLLL RKKKPYGTIS
10 Q06481 APLP2 MAATGTAAAAATGRL...GYENPTYKYLEQMQI 1 694 716 LREDFSLSSS ALIGLLVIAVAIATVIVISLVML RKRQYGTISH
provenance = aa.get_provenance(random_state=42, data=df_seq)
print("input_hash:", provenance["input_hash"])

# The digest tracks the input: a changed value gives a different hash.
df_changed = df_seq.copy()
df_changed.loc[0, "sequence"] = "MKV"
print("changed   :", aa.get_provenance(data=df_changed)["input_hash"])
input_hash: sha256:e9c8bdb622b17284b97cc352362556f4866e6b50d6042ac79a38dcf70e46f034
changed   : sha256:f620d7700c551e06f05907c1f56cbb329845a487c517e3200abae8119a729f08

This is why the record is worth keeping. options['random_state'] overrides everything, including a seed passed explicitly at the call site. The record reports the seed that actually took effect, which the call site alone does not tell you.

aa.options["random_state"] = 7
print("passed random_state=42, but options wins ->", aa.get_provenance(random_state=42)["random_state"])

aa.options["random_state"] = "off"
print("options back off, argument applies   ->", aa.get_provenance(random_state=42)["random_state"])
passed random_state=42, but options wins -> 7
options back off, argument applies   -> 42

Record it next to any seeded run — pass the tool the same random_state and its input to data — and store the dict with your results (e.g. json.dump). Two runs that agree on the record reproduce the same output. The record deliberately carries no timestamp or hostname: every field is something that can change a result, which is what makes two records comparable.