From a00354bd1c88c293f64bc2504674a53f1b5d383e Mon Sep 17 00:00:00 2001 From: AlbertEngstfeld Date: Fri, 28 Feb 2025 11:47:23 +0100 Subject: [PATCH 1/3] Fix converting and saving files with upper case characetrs. --- unitpackage/entry.py | 66 ++++++++++++++++++++++++++++++++++++++++---- unitpackage/local.py | 2 +- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/unitpackage/entry.py b/unitpackage/entry.py index 0afdd60e..542e295e 100644 --- a/unitpackage/entry.py +++ b/unitpackage/entry.py @@ -627,6 +627,25 @@ def from_csv(cls, csvname, metadata=None, fields=None): >>> entry.user 'Max Doe' + .. important:: + Upper case filenames are converted to lower case entry identifiers! + + A filename containing upper case characters:: + + >>> import os + >>> fields = [{'name':'E', 'unit': 'mV'}, {'name':'I', 'unit': 'A'}] + >>> entry = Entry.from_csv(csvname='examples/from_csv/UpperCase.csv', fields=fields) + >>> entry + Entry('uppercase') + + Casing in the filename is preserved in the metadata:: + + >>> entry.resource # doctest: +NORMALIZE_WHITESPACE + {'name': 'uppercase', + 'type': 'table', + 'path': 'UpperCase.csv', + ... + """ from unitpackage.local import create_unitpackage @@ -788,11 +807,23 @@ def from_df(cls, df, metadata=None, fields=None, outdir=None, *, basename): >>> entry.save(outdir='./test/generated/from_df') - TESTS + .. important:: + Basenames with upper case characters are stored with lower case characters! + To separate words use underscores. + + The basename will always be converted to lowercase entry identifiers:: + + >>> import pandas as pd + >>> from unitpackage.entry import Entry + >>> df = pd.DataFrame({'x':[1,2,3], 'y':[2,3,4]}) + >>> entry = Entry.from_df(df=df, basename='TEST_DF') + >>> entry + Entry('test_df') + + TESTS: Verify that all fields are properly created even when they are not specified as fields:: - >>> import os >>> fields = [{'name':'x', 'unit': 'm'}, {'name':'P', 'unit': 'um'}, {'name':'E', 'unit': 'V'}] >>> metadata = {'user':'Max Doe'} >>> entry = Entry.from_df(df=df, basename='test_df', metadata=metadata, fields=fields) @@ -832,9 +863,13 @@ def save(self, *, outdir, basename=None): True When a ``basename`` is set, the files are named ``basename.csv`` and ``basename.json``. - Note that for a valid frictionless Data Package this base name - MUST be lower-case and contain only alphanumeric - characters along with ".", "_" or "-" characters':: + + .. note:: + For a valid frictionless Data Package the basename + MUST be lower-case and contain only alphanumeric + characters along with ``.``, ``_`` or ``-`` characters' + + A valid basename:: >>> import os >>> entry = Entry.create_examples()[0] @@ -843,10 +878,29 @@ def save(self, *, outdir, basename=None): >>> os.path.exists(f'test/generated/{basename}.json') and os.path.exists(f'test/generated/{basename}.csv') True + Upper case characters are saved lower case:: + + >>> import os + >>> import pandas as pd + >>> from unitpackage.entry import Entry + >>> df = pd.DataFrame({'x':[1,2,3], 'y':[2,3,4]}) + >>> basename = 'Upper_Case_Save' + >>> entry = Entry.from_df(df=df, basename=basename) + >>> entry.save(outdir='./test/generated') + >>> os.path.exists(f'test/generated/{basename}.json') and os.path.exists(f'test/generated/{basename}.csv') + True + + >>> new_entry = Entry.from_local(f'test/generated/{basename.lower()}.json') + >>> new_entry.resource # doctest: +NORMALIZE_WHITESPACE + {'name': 'upper_case_save', + 'type': 'table', + 'path': 'upper_case_save.csv', + ... + TESTS: Save the entry as Data Package with metadata containing datetime format, - which is not natively supported by JSON. + which is not natively supported by JSON.:: >>> import os >>> from datetime import datetime diff --git a/unitpackage/local.py b/unitpackage/local.py index 5309900c..96dfff3d 100644 --- a/unitpackage/local.py +++ b/unitpackage/local.py @@ -176,7 +176,7 @@ def create_unitpackage(csvname, metadata=None, fields=None): ) package.infer() - resource = package.get_resource(Path(csv_basename).stem) + resource = package.get_resource(Path(csv_basename).stem.lower()) resource.custom.setdefault("metadata", {}) resource.custom["metadata"].setdefault("echemdb", metadata) From aa8203ad16d34a31e73cf1e5a93274d1e407c835 Mon Sep 17 00:00:00 2001 From: AlbertEngstfeld Date: Fri, 28 Feb 2025 11:48:03 +0100 Subject: [PATCH 2/3] Add news and test files --- doc/news/save_entry_case.rst | 3 +++ examples/from_csv/UpperCase.csv | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 doc/news/save_entry_case.rst create mode 100644 examples/from_csv/UpperCase.csv diff --git a/doc/news/save_entry_case.rst b/doc/news/save_entry_case.rst new file mode 100644 index 00000000..e0aa8d46 --- /dev/null +++ b/doc/news/save_entry_case.rst @@ -0,0 +1,3 @@ +**Fixed:** + +* Fixed creating and saving entries containing upper case characters, which are converted to lowercase, to match the frictionless specifications. diff --git a/examples/from_csv/UpperCase.csv b/examples/from_csv/UpperCase.csv new file mode 100644 index 00000000..3d44148b --- /dev/null +++ b/examples/from_csv/UpperCase.csv @@ -0,0 +1,3 @@ +E,I +1,2 +3,4 From 557c7f90e6fb6c794da6ed63fc4207e461d3d283 Mon Sep 17 00:00:00 2001 From: AlbertEngstfeld Date: Fri, 28 Feb 2025 14:03:21 +0100 Subject: [PATCH 3/3] Fix doctest --- unitpackage/entry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unitpackage/entry.py b/unitpackage/entry.py index 542e295e..55a288c2 100644 --- a/unitpackage/entry.py +++ b/unitpackage/entry.py @@ -887,7 +887,7 @@ def save(self, *, outdir, basename=None): >>> basename = 'Upper_Case_Save' >>> entry = Entry.from_df(df=df, basename=basename) >>> entry.save(outdir='./test/generated') - >>> os.path.exists(f'test/generated/{basename}.json') and os.path.exists(f'test/generated/{basename}.csv') + >>> os.path.exists(f'test/generated/{basename.lower()}.json') and os.path.exists(f'test/generated/{basename.lower()}.csv') True >>> new_entry = Entry.from_local(f'test/generated/{basename.lower()}.json')