From 8db01dea0d1fa13c9b5137fcf6292c60c4ba7638 Mon Sep 17 00:00:00 2001 From: Danielle Callan Date: Wed, 3 Dec 2025 22:33:44 -0500 Subject: [PATCH 1/7] set sep for has_n_columns assertions to comma for ftype csv --- lib/galaxy/tool_util/verify/__init__.py | 4 +++- lib/galaxy/tool_util/verify/asserts/__init__.py | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/galaxy/tool_util/verify/__init__.py b/lib/galaxy/tool_util/verify/__init__.py index cac554dd0b71..fa72cfa56e6c 100644 --- a/lib/galaxy/tool_util/verify/__init__.py +++ b/lib/galaxy/tool_util/verify/__init__.py @@ -99,7 +99,9 @@ def get_filename(filename: str) -> str: assertions = attributes.get("assert_list", None) if assertions is not None: try: - verify_assertions(output_content, attributes["assert_list"], attributes.get("decompress", False)) + # Auto-detect separator based on file type + sep = "," if attributes.get("ftype") == "csv" else "\t" + verify_assertions(output_content, attributes["assert_list"], attributes.get("decompress", False), sep=sep) except AssertionError as err: errmsg = f"{item_label} different than expected\n" errmsg += unicodify(err) diff --git a/lib/galaxy/tool_util/verify/asserts/__init__.py b/lib/galaxy/tool_util/verify/asserts/__init__.py index 532692c6198a..f2066a34747b 100644 --- a/lib/galaxy/tool_util/verify/asserts/__init__.py +++ b/lib/galaxy/tool_util/verify/asserts/__init__.py @@ -41,7 +41,7 @@ assertion_functions: Dict[str, Callable] = {k: v[1] for (k, v) in assertion_module_and_functions.items()} -def verify_assertions(data: bytes, assertion_description_list: list, decompress: bool = False): +def verify_assertions(data: bytes, assertion_description_list: list, decompress: bool = False, sep: str = None): """This function takes a list of assertions and a string to check these assertions against.""" if decompress: @@ -51,10 +51,10 @@ def verify_assertions(data: bytes, assertion_description_list: list, decompress: with get_fileobj(tmpfh.name, mode="rb", compressed_formats=None) as fh: data = fh.read() for assertion_description in assertion_description_list: - verify_assertion(data, assertion_description) + verify_assertion(data, assertion_description, sep=sep) -def verify_assertion(data: bytes, assertion_description): +def verify_assertion(data: bytes, assertion_description, sep: str = None): tag = assertion_description["tag"] assert_function_name = "assert_" + tag assert_function = assertion_functions.get(assert_function_name) @@ -103,5 +103,9 @@ def verify_assertion(data: bytes, assertion_description): if "children" in assert_function_args: args["children"] = assertion_description["children"] + # Only set sep if the assertion accepts it and it's not already specified in XML + if "sep" in assert_function_args and sep is not None and "sep" not in assertion_description["attributes"]: + args["sep"] = sep + # TODO: Verify all needed function arguments are specified. assert_function(**args) From 0e2f38d21ce033e8a74d986d35e41602010eb7c1 Mon Sep 17 00:00:00 2001 From: Danielle Callan Date: Wed, 3 Dec 2025 22:34:55 -0500 Subject: [PATCH 2/7] add some tests for assertions sep detection based on ftype --- test/unit/tool_util/test_verify_function.py | 76 +++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/test/unit/tool_util/test_verify_function.py b/test/unit/tool_util/test_verify_function.py index 1b6ace05f78b..1f5cce112095 100644 --- a/test/unit/tool_util/test_verify_function.py +++ b/test/unit/tool_util/test_verify_function.py @@ -93,3 +93,79 @@ def test_sim_size_failure_still_updates(tmp_path): assert assertion_error assert (tmp_path / filename).exists() assert (tmp_path / filename).open("rb").read() == b"expected" + + +def test_csv_ftype_auto_sep(): + """test that ftype='csv' automatically sets separator for has_n_columns assertion""" + item_label = "csv test" + output_content = b"col1,col2,col3\n" + attributes = { + "ftype": "csv", + "assert_list": [ + { + "tag": "has_n_columns", + "attributes": {"n": "3"}, + "children": [], + } + ], + } + + # This should pass because ftype="csv" triggers sep="," auto-detection + verify( + item_label, + output_content, + attributes=attributes, + filename=None, + get_filecontent=t_data_downloader_for(output_content), + ) + + +def test_tabular_ftype_auto_sep(): + """test that ftype='tabular' uses tab separator for has_n_columns assertion""" + item_label = "tabular test" + output_content = b"col1\tcol2\tcol3\n" + attributes = { + "ftype": "tabular", + "assert_list": [ + { + "tag": "has_n_columns", + "attributes": {"n": "3"}, + "children": [], + } + ], + } + + # This should pass because ftype="tabular" triggers sep="\t" (default) + verify( + item_label, + output_content, + attributes=attributes, + filename=None, + get_filecontent=t_data_downloader_for(output_content), + ) + + +def test_csv_ftype_explicit_sep_override(): + """test that explicit sep in assertion overrides ftype='csv' auto-detection""" + item_label = "csv with explicit sep test" + # Tab-separated data (not comma-separated!) + output_content = b"col1\tcol2\tcol3\n" + attributes = { + "ftype": "csv", # ftype is csv but data is actually tab-separated + "assert_list": [ + { + "tag": "has_n_columns", + "attributes": {"n": "3", "sep": "\t"}, # Explicit sep overrides + "children": [], + } + ], + } + + # This should pass because explicit sep="\t" overrides the ftype="csv" auto-detection + verify( + item_label, + output_content, + attributes=attributes, + filename=None, + get_filecontent=t_data_downloader_for(output_content), + ) From 3e81c696ec46938f485c19962dc1f78c4840b1a9 Mon Sep 17 00:00:00 2001 From: Danielle Callan Date: Thu, 4 Dec 2025 09:31:26 -0500 Subject: [PATCH 3/7] remove trailing whitespace --- test/unit/tool_util/test_verify_function.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/tool_util/test_verify_function.py b/test/unit/tool_util/test_verify_function.py index 1f5cce112095..bea7efb55fd0 100644 --- a/test/unit/tool_util/test_verify_function.py +++ b/test/unit/tool_util/test_verify_function.py @@ -109,7 +109,7 @@ def test_csv_ftype_auto_sep(): } ], } - + # This should pass because ftype="csv" triggers sep="," auto-detection verify( item_label, @@ -134,7 +134,7 @@ def test_tabular_ftype_auto_sep(): } ], } - + # This should pass because ftype="tabular" triggers sep="\t" (default) verify( item_label, @@ -160,7 +160,7 @@ def test_csv_ftype_explicit_sep_override(): } ], } - + # This should pass because explicit sep="\t" overrides the ftype="csv" auto-detection verify( item_label, From 43bb246a8d185190f89bd106d3a7a622d8aa0e7c Mon Sep 17 00:00:00 2001 From: Danielle Callan Date: Thu, 4 Dec 2025 09:39:35 -0500 Subject: [PATCH 4/7] explicit optional for sep in assertions --- lib/galaxy/tool_util/verify/asserts/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/galaxy/tool_util/verify/asserts/__init__.py b/lib/galaxy/tool_util/verify/asserts/__init__.py index f2066a34747b..7f4561113b5f 100644 --- a/lib/galaxy/tool_util/verify/asserts/__init__.py +++ b/lib/galaxy/tool_util/verify/asserts/__init__.py @@ -8,6 +8,7 @@ from typing import ( Callable, Dict, + Optional, Tuple, ) @@ -41,7 +42,7 @@ assertion_functions: Dict[str, Callable] = {k: v[1] for (k, v) in assertion_module_and_functions.items()} -def verify_assertions(data: bytes, assertion_description_list: list, decompress: bool = False, sep: str = None): +def verify_assertions(data: bytes, assertion_description_list: list, decompress: bool = False, sep: Optional[str] = None): """This function takes a list of assertions and a string to check these assertions against.""" if decompress: @@ -54,7 +55,7 @@ def verify_assertions(data: bytes, assertion_description_list: list, decompress: verify_assertion(data, assertion_description, sep=sep) -def verify_assertion(data: bytes, assertion_description, sep: str = None): +def verify_assertion(data: bytes, assertion_description, sep: Optional[str] = None): tag = assertion_description["tag"] assert_function_name = "assert_" + tag assert_function = assertion_functions.get(assert_function_name) From 99d66964e31ecdee971528abad11fcabf357178b Mon Sep 17 00:00:00 2001 From: Danielle Callan Date: Thu, 4 Dec 2025 09:53:47 -0500 Subject: [PATCH 5/7] fix asserts formatting --- lib/galaxy/tool_util/verify/asserts/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/galaxy/tool_util/verify/asserts/__init__.py b/lib/galaxy/tool_util/verify/asserts/__init__.py index 7f4561113b5f..6556f89f6f0e 100644 --- a/lib/galaxy/tool_util/verify/asserts/__init__.py +++ b/lib/galaxy/tool_util/verify/asserts/__init__.py @@ -42,7 +42,9 @@ assertion_functions: Dict[str, Callable] = {k: v[1] for (k, v) in assertion_module_and_functions.items()} -def verify_assertions(data: bytes, assertion_description_list: list, decompress: bool = False, sep: Optional[str] = None): +def verify_assertions( + data: bytes, assertion_description_list: list, decompress: bool = False, sep: Optional[str] = None +): """This function takes a list of assertions and a string to check these assertions against.""" if decompress: From 1c987b0ec10812db7e8888beba83428ed99a3d2a Mon Sep 17 00:00:00 2001 From: Danielle Callan Date: Thu, 4 Dec 2025 20:08:26 -0500 Subject: [PATCH 6/7] update docs for changing default sep value for csv --- lib/galaxy/tool_util/verify/asserts/tabular.py | 7 ++++--- lib/galaxy/tool_util/xsd/galaxy.xsd | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/galaxy/tool_util/verify/asserts/tabular.py b/lib/galaxy/tool_util/verify/asserts/tabular.py index 9fc8e9f71c05..e98569e625ba 100644 --- a/lib/galaxy/tool_util/verify/asserts/tabular.py +++ b/lib/galaxy/tool_util/verify/asserts/tabular.py @@ -13,7 +13,7 @@ ) from ._util import _assert_number -Sep = Annotated[str, AssertionParameter("Separator defining columns, default: tab")] +Sep = Annotated[str, AssertionParameter("Separator defining columns, default: tab (or comma for csv)")] Comment = Annotated[ str, AssertionParameter( @@ -53,9 +53,10 @@ def assert_has_n_columns( Number of columns can optionally also be specified with ``delta``. Alternatively the range of expected occurences can be specified by ``min`` and/or ``max``. - Optionally a column separator (``sep``, default is ``\t``) `and comment character(s) + Optionally a column separator (``sep``) and comment character(s) can be specified (``comment``, default is empty string). The first non-comment - line is used for determining the number of columns. + line is used for determining the number of columns. The default separator is + tab for most tabular data types, but comma for csv files. """ first_line = get_first_line(output, comment) n_columns = len(first_line.split(sep)) diff --git a/lib/galaxy/tool_util/xsd/galaxy.xsd b/lib/galaxy/tool_util/xsd/galaxy.xsd index cdae18ce6541..35e9e75a1968 100644 --- a/lib/galaxy/tool_util/xsd/galaxy.xsd +++ b/lib/galaxy/tool_util/xsd/galaxy.xsd @@ -2606,9 +2606,10 @@ For instance, ````. The assertion tests only the first lin Number of columns can optionally also be specified with ``delta``. Alternatively the range of expected occurences can be specified by ``min`` and/or ``max``. -Optionally a column separator (``sep``, default is `` ``) `and comment character(s) +Optionally a column separator (``sep``) and comment character(s) can be specified (``comment``, default is empty string). The first non-comment -line is used for determining the number of columns. +line is used for determining the number of columns. The default separator is +tab for most tabular data types, but comma for csv files. $attribute_list::5]]> @@ -2635,7 +2636,7 @@ $attribute_list::5]]> - + From c123c355661690ca7d5b9fe19f77ab0b7cf99060 Mon Sep 17 00:00:00 2001 From: Danielle Callan Date: Mon, 8 Dec 2025 23:43:16 -0500 Subject: [PATCH 7/7] thread tool profile into verify and gate csv sep default --- lib/galaxy/tool_util/verify/__init__.py | 9 +++- lib/galaxy/tool_util/verify/_types.py | 1 + .../tool_util/verify/asserts/tabular.py | 8 ++-- lib/galaxy/tool_util/verify/interactor.py | 42 +++++++++++++++++-- lib/galaxy/tool_util/verify/parse.py | 4 ++ lib/galaxy/tool_util/xsd/galaxy.xsd | 6 +-- test/unit/tool_util/test_verify_function.py | 42 +++++++++++++++++-- 7 files changed, 96 insertions(+), 16 deletions(-) diff --git a/lib/galaxy/tool_util/verify/__init__.py b/lib/galaxy/tool_util/verify/__init__.py index fa72cfa56e6c..d24643387e65 100644 --- a/lib/galaxy/tool_util/verify/__init__.py +++ b/lib/galaxy/tool_util/verify/__init__.py @@ -38,6 +38,8 @@ tifffile = None # type: ignore[assignment, unused-ignore] +from packaging.version import Version + from galaxy.tool_util.parser.util import ( DEFAULT_DELTA, DEFAULT_DELTA_FRAC, @@ -75,6 +77,7 @@ def verify( keep_outputs_dir: Optional[str] = None, verify_extra_files: Optional[Callable] = None, mode="file", + profile: Optional[str] = None, ): """Verify the content of a test output using test definitions described by attributes. @@ -99,8 +102,10 @@ def get_filename(filename: str) -> str: assertions = attributes.get("assert_list", None) if assertions is not None: try: - # Auto-detect separator based on file type - sep = "," if attributes.get("ftype") == "csv" else "\t" + # Auto-detect separator based on file type for profile >= 26.0 + sep: Optional[str] = None + if profile and Version(profile) >= Version("26.0"): + sep = "," if attributes.get("ftype") == "csv" else "\t" verify_assertions(output_content, attributes["assert_list"], attributes.get("decompress", False), sep=sep) except AssertionError as err: errmsg = f"{item_label} different than expected\n" diff --git a/lib/galaxy/tool_util/verify/_types.py b/lib/galaxy/tool_util/verify/_types.py index c532dab9aa69..5015ca453f28 100644 --- a/lib/galaxy/tool_util/verify/_types.py +++ b/lib/galaxy/tool_util/verify/_types.py @@ -38,6 +38,7 @@ class ToolTestDescriptionDict(TypedDict): tool_id: str tool_version: Optional[str] + profile: NotRequired[Optional[str]] name: str test_index: int inputs: ExpandedToolInputsJsonified diff --git a/lib/galaxy/tool_util/verify/asserts/tabular.py b/lib/galaxy/tool_util/verify/asserts/tabular.py index e98569e625ba..2dcdec337f05 100644 --- a/lib/galaxy/tool_util/verify/asserts/tabular.py +++ b/lib/galaxy/tool_util/verify/asserts/tabular.py @@ -13,7 +13,9 @@ ) from ._util import _assert_number -Sep = Annotated[str, AssertionParameter("Separator defining columns, default: tab (or comma for csv)")] +Sep = Annotated[ + str, AssertionParameter("Separator defining columns, default: tab (or comma for csv with profile >= 26.0)") +] Comment = Annotated[ str, AssertionParameter( @@ -55,8 +57,8 @@ def assert_has_n_columns( Optionally a column separator (``sep``) and comment character(s) can be specified (``comment``, default is empty string). The first non-comment - line is used for determining the number of columns. The default separator is - tab for most tabular data types, but comma for csv files. + line is used for determining the number of columns. For tools with profile >= 26.0, + the default separator is tab for most tabular data types, but comma for csv files. """ first_line = get_first_line(output, comment) n_columns = len(first_line.split(sep)) diff --git a/lib/galaxy/tool_util/verify/interactor.py b/lib/galaxy/tool_util/verify/interactor.py index 57bfc4af3168..daa4baa22d25 100644 --- a/lib/galaxy/tool_util/verify/interactor.py +++ b/lib/galaxy/tool_util/verify/interactor.py @@ -140,6 +140,7 @@ class ValidToolTestDict(TypedDict): error: Literal[False] tool_id: str tool_version: str + profile: NotRequired[Optional[str]] test_index: int @@ -147,6 +148,7 @@ class InvalidToolTestDict(TypedDict): error: Literal[True] tool_id: str tool_version: str + profile: NotRequired[Optional[str]] test_index: int inputs: Any exception: str @@ -303,7 +305,13 @@ def get_tool_tests(self, tool_id: str, tool_version: Optional[str] = None) -> Li return response.json() def verify_output_collection( - self, output_collection_def, output_collection_id, history, tool_id, tool_version=None + self, + output_collection_def, + output_collection_id, + history, + tool_id, + tool_version=None, + profile: Optional[str] = None, ): data_collection = self._get( f"dataset_collections/{output_collection_id}", data={"instance_type": "history"} @@ -319,6 +327,7 @@ def verify_dataset(element, element_attrib, element_outfile): attributes=element_attrib, tool_id=tool_id, tool_version=tool_version, + profile=profile, ) except AssertionError as e: raise AssertionError( @@ -327,7 +336,17 @@ def verify_dataset(element, element_attrib, element_outfile): verify_collection(output_collection_def, data_collection, verify_dataset) - def verify_output(self, history_id, jobs, output_data, output_testdef, tool_id, maxseconds, tool_version=None): + def verify_output( + self, + history_id, + jobs, + output_data, + output_testdef, + tool_id, + maxseconds, + tool_version=None, + profile: Optional[str] = None, + ): outfile = output_testdef.outfile attributes = output_testdef.attributes name = output_testdef.name @@ -342,6 +361,7 @@ def verify_output(self, history_id, jobs, output_data, output_testdef, tool_id, attributes=attributes, tool_id=tool_id, tool_version=tool_version, + profile=profile, ) except AssertionError as e: raise AssertionError(f"Output {name}: {str(e)}") @@ -378,6 +398,7 @@ def verify_output(self, history_id, jobs, output_data, output_testdef, tool_id, primary_attributes, tool_id=tool_id, tool_version=tool_version, + profile=profile, ) except AssertionError as e: raise AssertionError(f"Primary output {name}: {str(e)}") @@ -386,7 +407,9 @@ def wait_for_jobs(self, history_id, jobs, maxseconds): for job in jobs: self.wait_for_job(job["id"], history_id, maxseconds) - def verify_output_dataset(self, history_id, hda_id, outfile, attributes, tool_id, tool_version=None): + def verify_output_dataset( + self, history_id, hda_id, outfile, attributes, tool_id, tool_version=None, profile: Optional[str] = None + ): fetcher = self.__dataset_fetcher(history_id) test_data_downloader = self.__test_data_downloader(tool_id, tool_version, attributes) verify_hid( @@ -396,6 +419,7 @@ def verify_output_dataset(self, history_id, hda_id, outfile, attributes, tool_id dataset_fetcher=fetcher, test_data_downloader=test_data_downloader, keep_outputs_dir=self.keep_outputs_dir, + profile=profile, ) self._verify_metadata(history_id, hda_id, attributes) @@ -1300,6 +1324,7 @@ def verify_hid( test_data_downloader, dataset_fetcher=None, keep_outputs_dir: Optional[str] = None, + profile: Optional[str] = None, ): assert dataset_fetcher is not None @@ -1322,6 +1347,7 @@ def verify_extra_files(extra_files): get_filecontent=test_data_downloader, keep_outputs_dir=keep_outputs_dir, verify_extra_files=verify_extra_files, + profile=profile, ) @@ -1757,6 +1783,7 @@ def register_exception(e: Exception): tool_id=job["tool_id"], maxseconds=maxseconds, tool_version=testdef.tool_version, + profile=testdef.profile, ) except Exception as e: register_exception(e) @@ -1816,7 +1843,11 @@ def register_exception(e: Exception): # the job completed so re-hit the API for more information. data_collection_id = data_collection_list[name]["id"] galaxy_interactor.verify_output_collection( - output_collection_def, data_collection_id, history, job["tool_id"] + output_collection_def, + data_collection_id, + history, + job["tool_id"], + profile=testdef.profile, ) except Exception as e: register_exception(e) @@ -1993,6 +2024,7 @@ class ToolTestDescription: name: str tool_id: str tool_version: Optional[str] + profile: Optional[str] test_index: int num_outputs: Optional[int] stdout: Optional[AssertionList] @@ -2041,6 +2073,7 @@ def __init__(self, json_dict: ToolTestDescriptionDict): self.request_schema = json_dict.get("request_schema", None) self.tool_id = json_dict["tool_id"] self.tool_version = json_dict.get("tool_version") + self.profile = json_dict.get("profile") self.maxseconds = json_dict.get("maxseconds") def test_data(self): @@ -2067,6 +2100,7 @@ def to_dict(self) -> ToolTestDescriptionDict: "test_index": self.test_index, "tool_id": self.tool_id, "tool_version": self.tool_version, + "profile": self.profile, "required_files": self.required_files, "required_data_tables": self.required_data_tables, "required_loc_files": self.required_loc_files, diff --git a/lib/galaxy/tool_util/verify/parse.py b/lib/galaxy/tool_util/verify/parse.py index c272cf6c44a2..dfecd0af855e 100644 --- a/lib/galaxy/tool_util/verify/parse.py +++ b/lib/galaxy/tool_util/verify/parse.py @@ -144,6 +144,7 @@ def _description_from_tool_source( required_data_tables, required_loc_files, ) + profile = tool_source.parse_profile() processed_test_dict = ValidToolTestDict( { "inputs": processed_inputs, @@ -164,16 +165,19 @@ def _description_from_tool_source( "required_loc_files": required_loc_files, "tool_id": tool_id, "tool_version": tool_version, + "profile": profile, "test_index": test_index, "maxseconds": maxseconds, "error": False, } ) except Exception: + profile = tool_source.parse_profile() processed_test_dict = InvalidToolTestDict( { "tool_id": tool_id, "tool_version": tool_version, + "profile": profile, "test_index": test_index, "inputs": {}, "error": True, diff --git a/lib/galaxy/tool_util/xsd/galaxy.xsd b/lib/galaxy/tool_util/xsd/galaxy.xsd index 35e9e75a1968..258d04e46d57 100644 --- a/lib/galaxy/tool_util/xsd/galaxy.xsd +++ b/lib/galaxy/tool_util/xsd/galaxy.xsd @@ -2608,8 +2608,8 @@ range of expected occurences can be specified by ``min`` and/or ``max``. Optionally a column separator (``sep``) and comment character(s) can be specified (``comment``, default is empty string). The first non-comment -line is used for determining the number of columns. The default separator is -tab for most tabular data types, but comma for csv files. +line is used for determining the number of columns. For tools with profile >= 26.0, +the default separator is tab for most tabular data types, but comma for csv files. $attribute_list::5]]> @@ -2636,7 +2636,7 @@ $attribute_list::5]]> - + = 26.0)]]> diff --git a/test/unit/tool_util/test_verify_function.py b/test/unit/tool_util/test_verify_function.py index bea7efb55fd0..d8273bac12f1 100644 --- a/test/unit/tool_util/test_verify_function.py +++ b/test/unit/tool_util/test_verify_function.py @@ -95,9 +95,9 @@ def test_sim_size_failure_still_updates(tmp_path): assert (tmp_path / filename).open("rb").read() == b"expected" -def test_csv_ftype_auto_sep(): - """test that ftype='csv' automatically sets separator for has_n_columns assertion""" - item_label = "csv test" +def test_csv_ftype_auto_sep_profile_26(): + """For profile >= 26.0, ftype='csv' automatically sets separator for has_n_columns.""" + item_label = "csv test profile 26.0" output_content = b"col1,col2,col3\n" attributes = { "ftype": "csv", @@ -110,16 +110,50 @@ def test_csv_ftype_auto_sep(): ], } - # This should pass because ftype="csv" triggers sep="," auto-detection + # With profile >= 26.0, ftype="csv" triggers sep="," auto-detection verify( item_label, output_content, attributes=attributes, filename=None, get_filecontent=t_data_downloader_for(output_content), + profile="26.0", ) +def test_csv_ftype_auto_sep_legacy_profile(): + """Without profile, default behavior still uses tab separator for has_n_columns.""" + item_label = "csv test legacy profile" + output_content = b"col1,col2,col3\n" + attributes = { + "ftype": "csv", + "assert_list": [ + { + "tag": "has_n_columns", + "attributes": {"n": "3"}, + "children": [], + } + ], + } + + # Without a profile, sep auto-detection is not applied, so the default + # separator remains a tab character. Splitting a comma-separated line on + # tabs yields 1 column instead of 3, so this should raise an AssertionError. + raised = False + try: + verify( + item_label, + output_content, + attributes=attributes, + filename=None, + get_filecontent=t_data_downloader_for(output_content), + ) + except AssertionError: + raised = True + + assert raised + + def test_tabular_ftype_auto_sep(): """test that ftype='tabular' uses tab separator for has_n_columns assertion""" item_label = "tabular test"