mirror of
https://github.com/clearml/clearml-server
synced 2025-01-31 10:56:48 +00:00
64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
|
import copy
|
||
|
import re
|
||
|
|
||
|
from mongoengine import Q
|
||
|
from mongoengine.queryset.visitor import QueryCompilerVisitor, SimplificationVisitor, QCombination
|
||
|
|
||
|
|
||
|
class RegexWrapper(object):
|
||
|
def __init__(self, pattern, flags=None):
|
||
|
super(RegexWrapper, self).__init__()
|
||
|
self.pattern = pattern
|
||
|
self.flags = flags
|
||
|
|
||
|
@property
|
||
|
def regex(self):
|
||
|
return re.compile(self.pattern, self.flags if self.flags is not None else 0)
|
||
|
|
||
|
|
||
|
class RegexMixin(object):
|
||
|
|
||
|
def to_query(self, document):
|
||
|
query = self.accept(SimplificationVisitor())
|
||
|
query = query.accept(RegexQueryCompilerVisitor(document))
|
||
|
return query
|
||
|
|
||
|
def _combine(self, other, operation):
|
||
|
"""Combine this node with another node into a QCombination
|
||
|
object.
|
||
|
"""
|
||
|
if getattr(other, 'empty', True):
|
||
|
return self
|
||
|
|
||
|
if self.empty:
|
||
|
return other
|
||
|
|
||
|
return RegexQCombination(operation, [self, other])
|
||
|
|
||
|
|
||
|
class RegexQCombination(RegexMixin, QCombination):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class RegexQ(RegexMixin, Q):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class RegexQueryCompilerVisitor(QueryCompilerVisitor):
|
||
|
"""
|
||
|
Improved mongoengine complied queries visitor class that supports compiled regex expressions as part of the query.
|
||
|
|
||
|
We need this class since mongoengine's Q (QNode) class uses copy.deepcopy() as part of the tree simplification
|
||
|
stage, which does not support re.compiled objects (since Python 2.5).
|
||
|
This class allows users to provide regex strings wrapped in QueryRegex instances, which are lazily evaluated to
|
||
|
to re.compile instances just before being visited for compilation (this is done after the simplification stage)
|
||
|
"""
|
||
|
|
||
|
def visit_query(self, query):
|
||
|
query = copy.deepcopy(query)
|
||
|
query.query = self._transform_query(query.query)
|
||
|
return super(RegexQueryCompilerVisitor, self).visit_query(query)
|
||
|
|
||
|
def _transform_query(self, query):
|
||
|
return {k: v.regex if isinstance(v, RegexWrapper) else v for k, v in query.items()}
|