@@ -541,7 +541,8 @@ def compute_smaller_slice(larger_shape, smaller_shape, larger_slice):
541541
542542# Define the patterns for validation
543543validation_patterns = [
544- r"[\;\[\:]" , # Flow control characters
544+ # r"[\;\[\:]", # Flow control characters
545+ r"[\;]" , # Flow control characters
545546 r"(^|[^\w])__[\w]+__($|[^\w])" , # Dunder methods
546547 r"\.\b(?!real|imag|(\d*[eE]?[+-]?\d+)|(\d*[eE]?[+-]?\d+j)|\d*j\b|(sum|prod|min|max|std|mean|var|any|all|where)"
547548 r"\s*\([^)]*\)|[a-zA-Z_]\w*\s*\([^)]*\))" , # Attribute patterns
@@ -592,7 +593,7 @@ def validate_expr(expr: str) -> None:
592593 raise ValueError (f"'{ expr } ' is not a valid expression." )
593594
594595 # Check for invalid characters not covered by the tokenizer
595- invalid_chars = re .compile (r"[^\w\s+\-*/%().,=<>!&|~^]" )
596+ invalid_chars = re .compile (r"[^\w\s+\-*/%()[] .,=<>!&|~^]" )
596597 if invalid_chars .search (skip_quotes ) is not None :
597598 invalid_chars = invalid_chars .findall (skip_quotes )
598599 raise ValueError (f"Expression { expr } contains invalid characters: { invalid_chars } " )
@@ -744,6 +745,38 @@ def visit_Call(self, node):
744745 return newexpression , newoperands
745746
746747
748+ def convert_to_slice (expression ):
749+ """
750+ Assumes all operands are of the form o...
751+ Parameters
752+ ----------
753+ expression: str
754+
755+ Returns
756+ -------
757+ new_expr : str
758+ """
759+
760+ new_expr = ""
761+ skip_to_char = 0
762+ for i , expr_i in enumerate (expression ):
763+ if i < skip_to_char :
764+ continue
765+ if expr_i == "[" :
766+ k = expression [i :].find ("]" ) # start checking from after [
767+ slice_convert = expression [i : i + k + 1 ] # include [ and ]
768+ slicer = eval (f"np.s_{ slice_convert } " )
769+ slicer = (slicer ,) if isinstance (slicer , slice ) else slicer # standardise to tuple
770+ if any (isinstance (el , str ) for el in slicer ): # handle fields
771+ raise ValueError ("Cannot handle fields for slicing lazy expressions." )
772+ slicer = str (slicer )
773+ new_expr += ".slice(" + slicer + ")"
774+ skip_to_char = i + k + 1
775+ else :
776+ new_expr += expr_i
777+ return new_expr
778+
779+
747780class TransformNumpyCalls (ast .NodeTransformer ):
748781 def __init__ (self ):
749782 self .replacements = {}
@@ -2780,6 +2813,7 @@ def save(self, urlpath=None, **kwargs):
27802813 def _new_expr (cls , expression , operands , guess , out = None , where = None , ne_args = None ):
27812814 # Validate the expression
27822815 validate_expr (expression )
2816+ expression = convert_to_slice (expression )
27832817 if guess :
27842818 # The expression has been validated, so we can evaluate it
27852819 # in guessing mode to avoid computing reductions
0 commit comments