diff --git a/src/omero_metadata/cli.py b/src/omero_metadata/cli.py index bc788371..db30ce41 100755 --- a/src/omero_metadata/cli.py +++ b/src/omero_metadata/cli.py @@ -242,6 +242,9 @@ def _configure(self, parser): populate.add_argument("--allow_nan", action="store_true", help=( "Allow empty values to become Nan in Long or Double columns")) + populate.add_argument("--force_cols", action="store_true", help=( + "Force creation of column names which are forbidden by default")) + populateroi.add_argument( "--measurement", type=int, default=None, help="Index of the measurement to populate. By default, all") @@ -533,7 +536,8 @@ def populate(self, args): cfg=args.cfg, cfgid=cfgid, attach=args.attach, options=localcfg, batch_size=args.batch, loops=loops, ms=ms, dry_run=args.dry_run, - allow_nan=args.allow_nan) + allow_nan=args.allow_nan, + force_cols=args.force_cols) ctx.parse() def rois(self, args): diff --git a/src/omero_metadata/populate.py b/src/omero_metadata/populate.py index a7a0c0c5..97c4c15d 100644 --- a/src/omero_metadata/populate.py +++ b/src/omero_metadata/populate.py @@ -36,6 +36,7 @@ import csv import re import json +import keyword from getpass import getpass from getopt import getopt, GetoptError @@ -178,11 +179,13 @@ class HeaderResolver(object): 'plate': PlateColumn, }, **plate_keys) - def __init__(self, target_object, headers, column_types=None): + def __init__(self, target_object, headers, column_types=None, + force_cols=False): self.target_object = target_object self.headers = headers self.headers_as_lower = [v.lower() for v in self.headers] self.types = column_types + self.force_cols = force_cols @staticmethod def is_row_column_types(row): @@ -225,6 +228,20 @@ def create_columns(self): def columns_sanity_check(self, columns): column_types = [column.__class__ for column in columns] column_names = [column.name for column in columns] + # Check for column names which are python keywords or contain spaces + if not self.force_cols: + lower_case_kws = [kw.lower() for kw in keyword.kwlist] + for col_name in column_names: + if col_name.lower() in lower_case_kws: + raise MetadataError( + ('Cannot use column name "' + col_name + + '" because it is a reserved python keyword')) + omero_reserved_col_names = ['Image Name', + 'Dataset Name'] + for col_name in column_names: + if ' ' in col_name and col_name not in omero_reserved_col_names: + log.warn('Column name "' + col_name + + '" contains a space and cannot be used for querying') if WellColumn in column_types and ImageColumn in column_types: log.debug(column_types) raise MetadataError( @@ -982,7 +999,7 @@ class ParsingContext(object): def __init__(self, client, target_object, file=None, fileid=None, cfg=None, cfgid=None, attach=False, column_types=None, options=None, batch_size=1000, loops=10, ms=500, - dry_run=False, allow_nan=False): + dry_run=False, allow_nan=False, force_cols=False): ''' This lines should be handled outside of the constructor: @@ -1006,6 +1023,7 @@ def __init__(self, client, target_object, file=None, fileid=None, target_object, self.value_resolver) self.dry_run = dry_run + self.force_cols = force_cols def create_annotation_link(self): self.target_class = self.target_object.__class__ @@ -1050,7 +1068,7 @@ def preprocess_from_handle(self, data): log.debug('Column types: %r' % self.column_types) self.header_resolver = HeaderResolver( self.target_object, header_row, - column_types=self.column_types) + column_types=self.column_types, force_cols=self.force_cols) self.columns = self.header_resolver.create_columns() log.debug('Columns: %r' % self.columns) if len(self.columns) > MAX_COLUMN_COUNT: