zombie-squirrel 0.8.4__py3-none-any.whl → 0.8.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  Provides functions to fetch and cache project names, subject IDs, and asset
4
4
  metadata from the AIND metadata database with support for multiple backends."""
5
5
 
6
- __version__ = "0.8.4"
6
+ __version__ = "0.8.6"
7
7
 
8
8
  from zombie_squirrel.acorn_contents.asset_basics import asset_basics # noqa: F401
9
9
  from zombie_squirrel.acorn_contents.raw_to_derived import raw_to_derived # noqa: F401
@@ -6,7 +6,7 @@ import pandas as pd
6
6
  from aind_data_access_api.document_db import MetadataDbClient
7
7
 
8
8
  import zombie_squirrel.acorns as acorns
9
- from zombie_squirrel.utils import setup_logging
9
+ from zombie_squirrel.utils import setup_logging, SquirrelMessage
10
10
 
11
11
 
12
12
  @acorns.register_acorn(acorns.NAMES["basics"])
@@ -45,7 +45,11 @@ def asset_basics(force_update: bool = False) -> pd.DataFrame:
45
45
 
46
46
  if df.empty or force_update:
47
47
  setup_logging()
48
- logging.info("Updating cache for asset basics")
48
+ logging.info(SquirrelMessage(
49
+ tree=acorns.TREE.__class__.__name__,
50
+ acorn=acorns.NAMES["basics"],
51
+ message="Updating cache"
52
+ ).to_json())
49
53
  df = pd.DataFrame(
50
54
  columns=[
51
55
  "_id",
@@ -85,7 +89,11 @@ def asset_basics(force_update: bool = False) -> pd.DataFrame:
85
89
  BATCH_SIZE = 100
86
90
  asset_records = []
87
91
  for i in range(0, len(keep_ids), BATCH_SIZE):
88
- logging.info(f"Fetching asset basics batch {i // BATCH_SIZE + 1}...")
92
+ logging.info(SquirrelMessage(
93
+ tree=acorns.TREE.__class__.__name__,
94
+ acorn=acorns.NAMES["basics"],
95
+ message=f"Fetching batch {i // BATCH_SIZE + 1}"
96
+ ).to_json())
89
97
  batch_ids = keep_ids[i: i + BATCH_SIZE]
90
98
  batch_records = client.retrieve_docdb_records(
91
99
  filter_query={"_id": {"$in": batch_ids}},
@@ -6,7 +6,7 @@ import pandas as pd
6
6
  from aind_data_access_api.document_db import MetadataDbClient
7
7
 
8
8
  import zombie_squirrel.acorns as acorns
9
- from zombie_squirrel.utils import setup_logging
9
+ from zombie_squirrel.utils import setup_logging, SquirrelMessage
10
10
 
11
11
 
12
12
  @acorns.register_acorn(acorns.NAMES["r2d"])
@@ -30,7 +30,11 @@ def raw_to_derived(force_update: bool = False) -> pd.DataFrame:
30
30
 
31
31
  if df.empty or force_update:
32
32
  setup_logging()
33
- logging.info("Updating cache for raw to derived mapping")
33
+ logging.info(SquirrelMessage(
34
+ tree=acorns.TREE.__class__.__name__,
35
+ acorn=acorns.NAMES["r2d"],
36
+ message="Updating cache"
37
+ ).to_json())
34
38
  client = MetadataDbClient(
35
39
  host=acorns.API_GATEWAY_HOST,
36
40
  version="v2",
@@ -6,7 +6,7 @@ import pandas as pd
6
6
  from aind_data_access_api.document_db import MetadataDbClient
7
7
 
8
8
  import zombie_squirrel.acorns as acorns
9
- from zombie_squirrel.utils import setup_logging
9
+ from zombie_squirrel.utils import setup_logging, SquirrelMessage
10
10
 
11
11
 
12
12
  @acorns.register_acorn(acorns.NAMES["d2r"])
@@ -30,7 +30,11 @@ def source_data(force_update: bool = False) -> pd.DataFrame:
30
30
 
31
31
  if df.empty or force_update:
32
32
  setup_logging()
33
- logging.info("Updating cache for source data")
33
+ logging.info(SquirrelMessage(
34
+ tree=acorns.TREE.__class__.__name__,
35
+ acorn=acorns.NAMES["d2r"],
36
+ message="Updating cache"
37
+ ).to_json())
34
38
  client = MetadataDbClient(
35
39
  host=acorns.API_GATEWAY_HOST,
36
40
  version="v2",
@@ -6,7 +6,7 @@ import pandas as pd
6
6
  from aind_data_access_api.document_db import MetadataDbClient
7
7
 
8
8
  import zombie_squirrel.acorns as acorns
9
- from zombie_squirrel.utils import setup_logging
9
+ from zombie_squirrel.utils import setup_logging, SquirrelMessage
10
10
 
11
11
 
12
12
  @acorns.register_acorn(acorns.NAMES["upn"])
@@ -30,7 +30,11 @@ def unique_project_names(force_update: bool = False) -> list[str]:
30
30
 
31
31
  if df.empty or force_update:
32
32
  setup_logging()
33
- logging.info("Updating cache for unique project names")
33
+ logging.info(SquirrelMessage(
34
+ tree=acorns.TREE.__class__.__name__,
35
+ acorn=acorns.NAMES["upn"],
36
+ message="Updating cache"
37
+ ).to_json())
34
38
  client = MetadataDbClient(
35
39
  host=acorns.API_GATEWAY_HOST,
36
40
  version="v2",
@@ -6,7 +6,7 @@ import pandas as pd
6
6
  from aind_data_access_api.document_db import MetadataDbClient
7
7
 
8
8
  import zombie_squirrel.acorns as acorns
9
- from zombie_squirrel.utils import setup_logging
9
+ from zombie_squirrel.utils import setup_logging, SquirrelMessage
10
10
 
11
11
 
12
12
  @acorns.register_acorn(acorns.NAMES["usi"])
@@ -30,7 +30,11 @@ def unique_subject_ids(force_update: bool = False) -> list[str]:
30
30
 
31
31
  if df.empty or force_update:
32
32
  setup_logging()
33
- logging.info("Updating cache for unique subject IDs")
33
+ logging.info(SquirrelMessage(
34
+ tree=acorns.TREE.__class__.__name__,
35
+ acorn=acorns.NAMES["usi"],
36
+ message="Updating cache"
37
+ ).to_json())
34
38
  client = MetadataDbClient(
35
39
  host=acorns.API_GATEWAY_HOST,
36
40
  version="v2",
zombie_squirrel/acorns.py CHANGED
@@ -9,6 +9,7 @@ from zombie_squirrel.forest import (
9
9
  MemoryTree,
10
10
  S3Tree,
11
11
  )
12
+ from zombie_squirrel.utils import SquirrelMessage
12
13
 
13
14
  # --- Backend setup ---------------------------------------------------
14
15
 
@@ -16,12 +17,22 @@ API_GATEWAY_HOST = "api.allenneuraldynamics.org"
16
17
 
17
18
  forest_type = os.getenv("FOREST_TYPE", "memory").lower()
18
19
 
19
- if forest_type == "S3": # pragma: no cover
20
- logging.info("Using S3 forest for caching")
20
+ if forest_type == "s3": # pragma: no cover
21
+ logging.info(SquirrelMessage(
22
+ tree="S3Tree",
23
+ acorn="system",
24
+ message="Initializing S3 forest for caching"
25
+ ).to_json())
21
26
  TREE = S3Tree()
22
- else:
23
- logging.info("Using in-memory forest for caching")
27
+ elif forest_type == "memory":
28
+ logging.info(SquirrelMessage(
29
+ tree="MemoryTree",
30
+ acorn="system",
31
+ message="Initializing in-memory forest for caching"
32
+ ).to_json())
24
33
  TREE = MemoryTree()
34
+ else:
35
+ raise ValueError(f"Unknown FOREST_TYPE: {forest_type}")
25
36
 
26
37
  # --- Acorn registry and names -----------------------------------------------------
27
38
 
@@ -45,14 +56,3 @@ def register_acorn(name: str):
45
56
  return func
46
57
 
47
58
  return decorator
48
-
49
-
50
- # Import acorn_contents modules to trigger registration
51
- # This must be done after the registry and decorator are defined
52
- from zombie_squirrel.acorn_contents import ( # noqa: E402, F401
53
- asset_basics,
54
- raw_to_derived,
55
- source_data,
56
- unique_project_names,
57
- unique_subject_ids,
58
- )
zombie_squirrel/forest.py CHANGED
@@ -8,7 +8,7 @@ import boto3
8
8
  import duckdb
9
9
  import pandas as pd
10
10
 
11
- from zombie_squirrel.utils import get_s3_cache_path, prefix_table_name
11
+ from zombie_squirrel.utils import get_s3_cache_path, prefix_table_name, SquirrelMessage
12
12
 
13
13
 
14
14
  class Tree(ABC):
@@ -53,7 +53,11 @@ class S3Tree(Tree):
53
53
  Key=s3_key,
54
54
  Body=parquet_buffer.getvalue(),
55
55
  )
56
- logging.info(f"Stored cache to S3: s3://{self.bucket}/{s3_key}")
56
+ logging.info(SquirrelMessage(
57
+ tree="S3Tree",
58
+ acorn=table_name,
59
+ message=f"Stored cache to s3://{self.bucket}/{s3_key}"
60
+ ).to_json())
57
61
 
58
62
  def scurry(self, table_name: str) -> pd.DataFrame:
59
63
  """Fetch DataFrame from S3 parquet file."""
@@ -68,14 +72,18 @@ class S3Tree(Tree):
68
72
  )
69
73
  """
70
74
  result = duckdb.query(query).to_df()
71
- logging.info(
72
- f"Retrieved cache from S3: s3://{self.bucket}/{s3_key}"
73
- )
75
+ logging.info(SquirrelMessage(
76
+ tree="S3Tree",
77
+ acorn=table_name,
78
+ message=f"Retrieved cache from s3://{self.bucket}/{s3_key}"
79
+ ).to_json())
74
80
  return result
75
81
  except Exception as e:
76
- logging.warning(
77
- f"Error fetching from cache {s3_key}: {e}"
78
- )
82
+ logging.warning(SquirrelMessage(
83
+ tree="S3Tree",
84
+ acorn=table_name,
85
+ message=f"Error fetching from cache {s3_key}: {e}"
86
+ ).to_json())
79
87
  return pd.DataFrame()
80
88
 
81
89
 
zombie_squirrel/utils.py CHANGED
@@ -1,6 +1,18 @@
1
1
  """Utility functions for zombie-squirrel package."""
2
2
 
3
3
  import logging
4
+ from pydantic import BaseModel
5
+
6
+
7
+ class SquirrelMessage(BaseModel):
8
+ """Structured logging message for zombie-squirrel operations."""
9
+ tree: str
10
+ acorn: str
11
+ message: str
12
+
13
+ def to_json(self) -> str:
14
+ """Convert message to JSON string."""
15
+ return self.model_dump_json()
4
16
 
5
17
 
6
18
  def setup_logging():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zombie-squirrel
3
- Version: 0.8.4
3
+ Version: 0.8.6
4
4
  Summary: Generated from aind-library-template
5
5
  Author: Allen Institute for Neural Dynamics
6
6
  License: MIT
@@ -21,7 +21,7 @@ Dynamic: license-file
21
21
  ![Code Style](https://img.shields.io/badge/code%20style-black-black)
22
22
  [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)
23
23
  ![Interrogate](https://img.shields.io/badge/interrogate-100.0%25-brightgreen)
24
- ![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)
24
+ ![Coverage](https://img.shields.io/badge/coverage-99%25-brightgreen)
25
25
  ![Python](https://img.shields.io/badge/python->=3.10-blue?logo=python)
26
26
 
27
27
  <img src="zombie-squirrel_logo.png" width="400" alt="Logo (image from ChatGPT)">
@@ -0,0 +1,16 @@
1
+ zombie_squirrel/__init__.py,sha256=xHHJ6bd_QrBfJVqejcucILL05-9V1SHbB3EFC4ebf70,693
2
+ zombie_squirrel/acorns.py,sha256=Sb5bYUGhvTvtWpRn7IuymBbFQ5-WhO6DOJf0hRZ-azI,1484
3
+ zombie_squirrel/forest.py,sha256=hsXBJrtAs4LnAabpIBp88ByDeDXfrK0AePqdkVMz-e8,3262
4
+ zombie_squirrel/sync.py,sha256=51ufe4n_3CvYrfTKW4KHngY4k-E9k0I_HGdWOIHY-bA,366
5
+ zombie_squirrel/utils.py,sha256=hyXoWstJ7rUYZVmazEtt5hXJ4SAMbfmlQMDUmBlfFZw,1280
6
+ zombie_squirrel/acorn_contents/__init__.py,sha256=N4Wun9kn44_nCwV4g6naEVzf76ozOgEoupAHLYpiGsI,224
7
+ zombie_squirrel/acorn_contents/asset_basics.py,sha256=PYN1NQsTVVCdLVd7JgTMTf5uepABOKVtSe4Sx_wrA1g,6037
8
+ zombie_squirrel/acorn_contents/raw_to_derived.py,sha256=7y2xA7GLC2hMj_Z7gz-uBOKiVdzGjBtQ2lsgHzASnOg,2853
9
+ zombie_squirrel/acorn_contents/source_data.py,sha256=I7A3mHqVO4C4880w82LNlBHZZ72uSHw3eCwrKtVCnSI,1901
10
+ zombie_squirrel/acorn_contents/unique_project_names.py,sha256=VAS0CZzsC9ObPM39KfrIjYPDIVcqu9H9wyZz8styznQ,1612
11
+ zombie_squirrel/acorn_contents/unique_subject_ids.py,sha256=H_eb3ucayNOdt4GtW26qckqvX6qGcRU59Q_D9NlnSbg,1585
12
+ zombie_squirrel-0.8.6.dist-info/licenses/LICENSE,sha256=U0Y7B3gZJHXpjJVLgTQjM8e_c8w4JJpLgGhIdsoFR1Y,1092
13
+ zombie_squirrel-0.8.6.dist-info/METADATA,sha256=dNdtuz95_8ZWfhRivvf8cUH4gtXGLO0d_6eaGfsHnt8,1897
14
+ zombie_squirrel-0.8.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
+ zombie_squirrel-0.8.6.dist-info/top_level.txt,sha256=FmM0coe4AangURZLjM4JwwRv2B8H6oINYCoZLKLDCKA,16
16
+ zombie_squirrel-0.8.6.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- zombie_squirrel/__init__.py,sha256=V1ZXhNO1h3PxKP-k5yb8YtU1sgw0ie8JduMXfR3C7Zo,693
2
- zombie_squirrel/acorns.py,sha256=oFrRkE3P6Mf9ZUCM8JmzDPBdc4gnoc-gVau7kWt0EJY,1429
3
- zombie_squirrel/forest.py,sha256=v0K1u0EA0OptzxocFC-fPEi6xYcnJ9SoWJ6aiPF4jLg,2939
4
- zombie_squirrel/sync.py,sha256=51ufe4n_3CvYrfTKW4KHngY4k-E9k0I_HGdWOIHY-bA,366
5
- zombie_squirrel/utils.py,sha256=v9IsbICSflk5TjSFSgcEoL0FSyU-M8_fn3OYdkjBu8Y,983
6
- zombie_squirrel/acorn_contents/__init__.py,sha256=N4Wun9kn44_nCwV4g6naEVzf76ozOgEoupAHLYpiGsI,224
7
- zombie_squirrel/acorn_contents/asset_basics.py,sha256=_vbZS7fa_u-2J592aKWzFd3jFFBZMU7PnrVeF4WWrkw,5741
8
- zombie_squirrel/acorn_contents/raw_to_derived.py,sha256=iQ5L12VJm2GVUU9J9HjLcr_YhMcHYFGLtXzfqmLrgNM,2718
9
- zombie_squirrel/acorn_contents/source_data.py,sha256=boO6kd8ksdYzg_LBhmvTFfI1vjJuIFRUKWSC40TVwnA,1755
10
- zombie_squirrel/acorn_contents/unique_project_names.py,sha256=inHOXd1_XeUVFGv9HT9m4GXE3vN9qbPR0H6aEtzVAZo,1475
11
- zombie_squirrel/acorn_contents/unique_subject_ids.py,sha256=J9F_I0iR5HU6D2gme6vdC-kMGPxb6F6TfoW1zX1x-PM,1446
12
- zombie_squirrel-0.8.4.dist-info/licenses/LICENSE,sha256=U0Y7B3gZJHXpjJVLgTQjM8e_c8w4JJpLgGhIdsoFR1Y,1092
13
- zombie_squirrel-0.8.4.dist-info/METADATA,sha256=FDGupBmCDrMY4maTCb-U2xJeZ0mSp02dWyWI4K2iplA,1898
14
- zombie_squirrel-0.8.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
- zombie_squirrel-0.8.4.dist-info/top_level.txt,sha256=FmM0coe4AangURZLjM4JwwRv2B8H6oINYCoZLKLDCKA,16
16
- zombie_squirrel-0.8.4.dist-info/RECORD,,