⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Merged
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
17 changes: 13 additions & 4 deletions src/datajoint/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,20 @@ def declare(self, context=None):
"""
if self.connection.in_transaction:
raise DataJointError("Cannot declare new tables inside a transaction, e.g. from inside a populate/make call")
# Enforce strict CamelCase #1150
if not is_camel_case(self.class_name):
# Validate class name #1150
class_name = self.class_name
if "_" in class_name:
warnings.warn(
f"Table class name `{class_name}` contains underscores. "
"CamelCase names without underscores are recommended.",
UserWarning,
stacklevel=2,
)
class_name = class_name.replace("_", "")
if not is_camel_case(class_name):
raise DataJointError(
"Table class name `{name}` is invalid. Please use CamelCase. ".format(name=self.class_name)
+ "Classes defining tables should be formatted in strict CamelCase."
f"Table class name `{self.class_name}` is invalid. "
"Class names must be in CamelCase, starting with a capital letter."
)
sql, _external_stores, primary_key, fk_attribute_map = declare(self.full_table_name, self.definition, context)

Expand Down
1 change: 1 addition & 0 deletions src/datajoint/user_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"to_arrow",
"to_arrays",
"keys",
"fetch",
"fetch1",
"head",
"tail",
Expand Down
9 changes: 9 additions & 0 deletions src/datajoint/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import re
import shutil
import warnings
from pathlib import Path

from .errors import DataJointError
Expand Down Expand Up @@ -86,6 +87,14 @@ def from_camel_case(s):
def convert(match):
return ("_" if match.groups()[0] else "") + match.group(0).lower()

# Handle underscores: warn and remove them
if "_" in s:
warnings.warn(
f"Table class name `{s}` contains underscores. " "CamelCase names without underscores are recommended.",
UserWarning,
stacklevel=3,
)
s = s.replace("_", "")
if not is_camel_case(s):
raise DataJointError("ClassName must be alphanumeric in CamelCase, begin with a capital letter")
return re.sub(r"(\B[A-Z])|(\b[A-Z])", convert, s)
Expand Down
9 changes: 6 additions & 3 deletions tests/integration/test_declare.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,8 @@ class IndexAttribute(dj.Manual):

def test_table_name_with_underscores(schema_any):
"""
Test issue #1150 -- Reject table names containing underscores. Tables should be in strict
CamelCase.
Test issue #1150 -- Table names with underscores should produce a warning but still work.
Strict CamelCase is recommended.
"""

class TableNoUnderscores(dj.Manual):
Expand All @@ -363,5 +363,8 @@ class Table_With_Underscores(dj.Manual):
"""

schema_any(TableNoUnderscores)
with pytest.raises(dj.DataJointError, match="must be alphanumeric in CamelCase"):
# Underscores now produce a warning instead of an error (legacy support)
with pytest.warns(UserWarning, match="contains underscores"):
schema_any(Table_With_Underscores)
# Verify the table was created successfully
assert Table_With_Underscores.is_declared
10 changes: 6 additions & 4 deletions tests/integration/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ def test_from_camel_case():
assert from_camel_case("AllGroups") == "all_groups"
with pytest.raises(DataJointError):
from_camel_case("repNames")
with pytest.raises(DataJointError):
from_camel_case("10_all")
with pytest.warns(UserWarning, match="contains underscores"):
with pytest.raises(DataJointError):
from_camel_case("10_all")
with pytest.raises(DataJointError):
from_camel_case("hello world")
with pytest.raises(DataJointError):
from_camel_case("#baisc_names")
with pytest.warns(UserWarning, match="contains underscores"):
with pytest.raises(DataJointError):
from_camel_case("#baisc_names")


def test_to_camel_case():
Expand Down
Loading