Skip to content

Commit a902bd1

Browse files
Merge branch 'master' into feat/schema-namespace
2 parents 688ac4d + a00b89f commit a902bd1

15 files changed

Lines changed: 394 additions & 34 deletions

File tree

‎.github/workflows/draft_release.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@ jobs:
2626
with:
2727
config-name: release_drafter.yaml
2828
disable-autolabeler: true
29-
name: ${{ github.event.inputs.testpypi == 'true' && 'Test $RESOLVED_VERSION' || 'Release $RESOLVED_VERSION' }}
29+
name: ${{ github.event.inputs.testpypi == 'true' && 'Test DataJoint Library $RESOLVED_VERSION' || 'DataJoint Library $RESOLVED_VERSION' }}
3030
env:
3131
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# DataJoint for Python
1+
# DataJoint Library for Python
22

3-
DataJoint is a framework for scientific data pipelines based on the **Relational Workflow Model** — a paradigm where your database schema is an executable specification of your workflow.
3+
The **DataJoint Library** is a framework for scientific data pipelines based on the **Relational Workflow Model** — a paradigm where your database schema is an executable specification of your workflow.
44

55
- **Tables represent workflow steps** — Each table is a step in your pipeline
66
- **Foreign keys encode dependencies** — Parent tables must be populated before child tables

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ maintainers = [
3232
{name = "DataJoint Contributors", email = "support@datajoint.com"},
3333
]
3434
# manually sync here: https://docs.datajoint.com/core/datajoint-python/latest/#welcome-to-datajoint-for-python
35-
description = "DataJoint for Python is a framework for scientific workflow management based on relational principles. DataJoint is built on the foundation of the relational data model and prescribes a consistent method for organizing, populating, computing, and querying data."
35+
description = "The DataJoint Library for Python is a framework for scientific workflow management based on relational principles. It is built on the foundation of the relational data model and prescribes a consistent method for organizing, populating, computing, and querying data."
3636
readme = "README.md"
3737
license = {file = "LICENSE"}
3838
keywords = [

‎src/datajoint/builtin_codecs/filepath.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ def encode(
164164

165165
return {
166166
"path": path,
167-
"store": store_name,
167+
"store": config.resolve_store_name(store_name, use_filepath_default=True),
168168
"size": size,
169169
"is_dir": is_dir,
170170
"timestamp": datetime.now(timezone.utc).isoformat(),

‎src/datajoint/builtin_codecs/npy.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def encode(
356356
# Return metadata (includes numpy-specific shape/dtype)
357357
return {
358358
"path": path,
359-
"store": store_name,
359+
"store": config.resolve_store_name(store_name),
360360
"dtype": str(value.dtype),
361361
"shape": list(value.shape),
362362
}

‎src/datajoint/builtin_codecs/object.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def encode(
168168
timestamp = datetime.now(timezone.utc)
169169
metadata = {
170170
"path": path,
171-
"store": store_name,
171+
"store": config.resolve_store_name(store_name),
172172
"size": size,
173173
"ext": ext,
174174
"is_dir": is_dir,

‎src/datajoint/builtin_codecs/schema.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def encode(self, value, *, key=None, context=None, store_name=None):
6666
)
6767
backend = self._get_backend(store_name, config=config)
6868
backend.put_buffer(serialize(value), path)
69-
return {"path": path, "store": store_name, ...}
69+
return {"path": path, "store": config.resolve_store_name(store_name), ...}
7070
7171
def decode(self, stored, *, key=None, context=None):
7272
config = self._codec_config(key, context)

‎src/datajoint/declare.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ def compile_foreign_key(
203203
adapter,
204204
fk_attribute_map: dict[str, tuple[str, str]] | None = None,
205205
fk_index_candidates: list[list[str]] | None = None,
206+
column_comments: dict[str, str] | None = None,
206207
) -> None:
207208
"""
208209
Parse a foreign key line and update declaration components.
@@ -233,6 +234,11 @@ def compile_foreign_key(
233234
candidate supporting index; the redundancy/coverage decision is made
234235
post-parse (once the full primary key and index list are known).
235236
Updated in place.
237+
column_comments : dict, optional
238+
Mapping of ``column -> comment`` for backends that set column comments
239+
out of line (PostgreSQL's ``COMMENT ON COLUMN``). Each copied column's
240+
comment, with its core-type marker (e.g. ``:int32:``), is added so the
241+
child keeps the parent's declared type. Updated in place.
236242
237243
Raises
238244
------
@@ -288,14 +294,17 @@ def compile_foreign_key(
288294
# Enum type names start with "enum_" (generated hash-based names)
289295
if sql_type.startswith("enum_") and adapter.backend == "postgresql":
290296
sql_type = f"{adapter.quote_identifier(ref.database)}.{adapter.quote_identifier(sql_type)}"
297+
comment = parent_attr.sql_comment
291298
col_def = adapter.format_column_definition(
292299
name=attr,
293300
sql_type=sql_type,
294301
nullable=is_nullable,
295302
default=None,
296-
comment=parent_attr.sql_comment,
303+
comment=comment,
297304
)
298305
attr_sql.append(col_def)
306+
if comment and column_comments is not None:
307+
column_comments[attr] = comment
299308

300309
# Track FK attribute mapping for lineage: child_attr -> (parent_table, parent_attr)
301310
if fk_attribute_map is not None:
@@ -459,6 +468,7 @@ def add_attribute(line: str, in_key: bool) -> None:
459468
adapter,
460469
fk_attribute_map,
461470
fk_index_candidates,
471+
column_comments,
462472
)
463473
elif re.match(r"^(unique\s+)?index\s*\(.*\)\s*(#.*)?$", line, re.I): # index
464474
compile_index(re.sub(r"\s*#.*$", "", line), index_sql, adapter)

‎src/datajoint/gc.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,14 @@ def __init__(self, *schemas: "Schema", store: str | None = None, config=None) ->
113113
if not schemas:
114114
raise DataJointError("At least one schema must be provided")
115115
self.schemas = schemas
116-
self.store = store
116+
# An empty name (the bare ``@`` form) means the default store, as None
117+
# does. Kept as "", it would match no reference in _references, and every
118+
# stored file would look orphaned.
119+
self.store = store or None
117120
self.config = config if config is not None else schemas[0].connection._config
121+
# References record the resolved store name. Metadata written before
122+
# that may record an empty name or none; both mean the default store.
123+
self._default_store = self.config.stores.get("default")
118124
# Resolve the store eagerly: validates it exists and pins the backend
119125
# and section prefixes for this collector's lifetime (one store only).
120126
self.backend = get_store_backend(store, config=self.config)
@@ -174,7 +180,7 @@ def _references(self, heading_attr: str, verbose: bool) -> set[str]:
174180
try:
175181
for row in table.proj(attr_name).cursor(as_dict=True):
176182
for path, ref_store in attr.codec.referenced_paths(row[attr_name]):
177-
if self.store is None or ref_store == self.store:
183+
if self.store is None or (ref_store or self._default_store) == self.store:
178184
referenced.add(path)
179185
except Exception as e:
180186
logger.warning(f"Error scanning {table_name}.{attr_name}: {e}")

‎src/datajoint/hash_registry.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def put_hash(
250250
"hash": content_hash,
251251
"path": path, # Always stored for retrieval
252252
"schema": schema_name,
253-
"store": store_name,
253+
"store": config.resolve_store_name(store_name),
254254
"size": len(data),
255255
}
256256

0 commit comments

Comments
 (0)