diff --git a/edxsearch/__init__.py b/edxsearch/__init__.py index 0f5cc993..2432599e 100644 --- a/edxsearch/__init__.py +++ b/edxsearch/__init__.py @@ -1,3 +1,3 @@ """ Container module for testing / demoing search """ -__version__ = '3.3.0' +__version__ = '3.4.0' diff --git a/search/result_processor.py b/search/result_processor.py index cc5961ed..6674cca1 100644 --- a/search/result_processor.py +++ b/search/result_processor.py @@ -131,7 +131,12 @@ def excerpt(self): return None match_phrases = [self._match_phrase] - separate_phrases = list(shlex.split(self._match_phrase)) + try: + separate_phrases = list(shlex.split(self._match_phrase)) + # This can happen when the phrase contains an apostrophe - the POSIX mode does not allow unclosed quotations. + except ValueError: + separate_phrases = list(shlex.split(self._match_phrase, posix=False)) + if len(separate_phrases) > 1: match_phrases.extend(separate_phrases) else: diff --git a/search/tests/test_search_result_processor.py b/search/tests/test_search_result_processor.py index 3dbcce65..a144a3dc 100644 --- a/search/tests/test_search_result_processor.py +++ b/search/tests/test_search_result_processor.py @@ -267,6 +267,30 @@ def test_excerpt_ellipsis_undecorated(self): srp = SearchResultProcessor(test_result, 'Just a line') self.assertIn(ELLIPSIS, srp.excerpt) + @ddt.data( + ("shouldn't", "This shouldn't have failed."), + ("shouldn\'t", " This shouldn't have failed."), + ('"shouldn\'t have"', "This shouldn't have failed."), + ("shouldn\\'t\\'ve", "shouldn't've failed."), # An even number of apostrophes needs to be escaped. + ('"shouldn\'t\'ve failed"', "shouldn't've failed."), + ("shou\'dn\'t\'ve", "This shou'dn't've failed."), + ('"shou\'dn\'t\'ve failed"', "This shou'dn't've failed."), + ) + @ddt.unpack + def test_excerpt_apostrophe(self, search_phrase, expected_excerpt): + test_result = { + "content": { + "notes": ( + "This should not have failed. " + "This shouldn't have failed. " + "This shouldn't've failed. " + "This shou'dn't've failed." + ) + } + } + srp = SearchResultProcessor(test_result, search_phrase) + self.assertIn(expected_excerpt, srp.excerpt) + class TestSearchResultProcessor(SearchResultProcessor): """