def test_template_parsing2(mock_find_files, mock_read, mock_push_strings): mock_find_files.return_value = [ TranslatableFile('dir1/dir2', '1.html', 'locdir1'), ] mock_read.side_effect = [ # 1.html HTML_TEMPLATE.replace( '{content}', u'<p>{% t "<b>Strong</b> {a}" a="A" _context="c1,c2" ' u'_tags="t1,t2" _comment="comment1" _charlimit=22 ' u'_key="first_key" %}</p>\n' u'<p>{% ut "παράδειγμα {b}" b="B" _context="c1,c2" ' u'_tags="t1,t2" _comment="comment2" _charlimit=33 ' u'_key="second_key" %}</p>' ), ] expected = [ # 1.html SourceString( u'<b>Strong</b> {a}', 'c1,c2', _tags='t1,t2', _comment='comment1', _charlimit=22, _occurrences=['r1/dir2/1.html:4'], _key='first_key', ), SourceString( u'παράδειγμα {b}', 'c1,c2', _tags='t1,t2', _comment="comment2", _charlimit=33, _occurrences=['r1/dir2/1.html:5'], _key='second_key', ), ] run_and_compare(expected)
def test_push_strings_reaches_cds_handler(self, mock_push_strings): response = MagicMock() response.status_code = 200 response.content = '{}' mock_push_strings.return_value = response strings = [SourceString('a'), SourceString('b')] mytx = self._get_tx() mytx.push_source_strings(strings, False) mock_push_strings.assert_called_once_with(strings, False)
def test_basic(self): src = TEMPLATE.replace( u'{{string1}}', u'{% t "A very important sentence" %}' ).replace( u'{{string2}}', u'{% t "I will look for {total} items" total=bucket.items|length %}' ) strings = extract_transifex_template_strings(src) assert strings == [ SourceString(u"A very important sentence"), SourceString(u"I will look for {total} items"), ]
def test_template_parsing(mock_find_files, mock_read, mock_push_strings): mock_find_files.return_value = [ TranslatableFile('dir1/dir2', '1.html', 'locdir1'), TranslatableFile('dir4/dir5', '1.txt', 'locdir1'), ] mock_read.side_effect = [ # 1.html HTML_TEMPLATE.replace( '{content}', u'<p>{% t "<b>Strong</b> {a}" a="A" _context="c1,c2" ' u'_tags="t1,t2" _comment="comment1" _charlimit=22 %}</p>\n' u'<p>{% ut "παράδειγμα {b}" b="B" _context="c1,c2" ' u'_tags="t1,t2" _comment="comment2" _charlimit=33 %}</p>' ), # 1.txt HTML_TEMPLATE.replace( '{content}', u'{% t _context="c1,c2" _tags="t1,t2" _comment="co1" _charlimit=22 %}\n' u'This is a short string\n' u'{% endt %}\n' u'{% t _context="c1,c2" _tags="t1,t2" _comment="co2" _charlimit=33 %}\n' u'This is not a shorter string\n' u'{% endt %}' ), ] expected = [ # 1.html SourceString( u'<b>Strong</b> {a}', 'c1,c2', _tags='t1,t2', _comment="comment1", _charlimit=22, _occurrences=['r1/dir2/1.html:4'], ), SourceString( u'παράδειγμα {b}', 'c1,c2', _tags='t1,t2', _comment="comment2", _charlimit=33, _occurrences=['r1/dir2/1.html:5'], ), # 1.txt SourceString( u'\nThis is a short string\n', 'c1,c2', _tags='t1,t2', _comment="co1", _charlimit=22, _occurrences=['r4/dir5/1.txt:4'], ), SourceString( u'\nThis is not a shorter string\n', 'c1,c2', _tags='t1,t2', _comment="co2", _charlimit=33, _occurrences=['r4/dir5/1.txt:7'], ), ] run_and_compare(expected)
def test_registered_imports(self): # Test all combinations in multi-level imports # with a custom registered function ex = Extractor() ex.register_functions('module1.module2.module3.myfunc') src = TEMPLATE.format( _import=('from module1.module2 import module3 as m3\n' 'import module1.module2.module3 as _m3\n'), call1='m3.myfunc', call2='_m3.myfunc', ) results = ex.extract_strings(src, 'myfile.py') assert results == self._strings() src = TEMPLATE.format( _import=('from module1 import module2 as m2\n' 'import module1.module2 as _m2\n'), call1='m2.module3.myfunc', call2='_m2.module3.myfunc', ) results = ex.extract_strings(src, 'myfile.py') assert results == self._strings() src = TEMPLATE.format( _import='import module1 as _m1', call1='_m1.module2.module3.myfunc', call2='_m1.module2.module3.myfunc', ) # mocking gets a little bit different here shifting occurrences expected = [ SourceString(u'Le canapé', u'désign', param1='1', param2=2, param3=True, _occurrences=['myfile.py:6']), SourceString(u'Les données', u'opération', _comment='comment', _tags=['t1', 't2'], _charlimit=33, _occurrences=['myfile.py:7']), ] results = ex.extract_strings(src, 'myfile.py') assert results == expected
def test_push_strings_reaches_cds_handler( self, mock_push_strings, mock_get_status ): response = MagicMock() response.status_code = 202 response.content = '{"data":{"links":{"job":"/job"}}}' mock_push_strings.return_value = response response = MagicMock() response.status_code = 200 response.content = '{"data":{"status":"completed","details":{}}}' mock_get_status.return_value = response strings = [SourceString('a'), SourceString('b')] mytx = self._get_tx() mytx.push_source_strings(strings, False) mock_push_strings.assert_called_once_with(strings, False)
def test_default_values(self): string = SourceString('something') assert string.string == 'something' assert string.context is None assert string.meta == {} assert string.developer_comment is None assert string.character_limit is None assert string.tags == []
def test_push_source_strings(self, patched_logger): cds_host = 'https://some.host' cds_handler = CDSHandler(['el', 'en'], 'some_token', secret='some_secret', host=cds_host) # test push no content responses.add(responses.POST, cds_host + '/content/', status=200, json={'data': []}) cds_handler.push_source_strings([], False) assert patched_logger.error.call_count == 0 # test push with content responses.add(responses.POST, cds_host + '/content/', status=200, json={'data': []}) source_string = SourceString('some_string') cds_handler.push_source_strings([source_string], False) assert patched_logger.error.call_count == 0 responses.reset() # test wrong data format responses.add(responses.POST, cds_host + '/content/', status=422, json={ "status": 422, "message": "Invalid Payload", "details": [{ "message": "\"string\" is required", "path": ["some_key1", "string"], "type": "any.required", "context": { "key": "string", "label": "string" } }] }) # we don't care about the payload this time, just want to # see how the service handles the errors cds_handler.push_source_strings([], False) # The actual error message differs between Python 2 and Python 3 messages = [ 'Error pushing source strings to CDS: UnknownError ' '(`422 Client Error: {err} for url: ' 'https://some.host/content/`)'.format(err=x) for x in ('Unprocessable Entity', 'None') ] assert patched_logger.error.call_args[0][0] in messages
def _strings(self): return [ SourceString( u'Le canapé', u'désign', param1='1', param2=2, param3=True, _occurrences=['myfile.py:8'], ), SourceString( u'Les données', u'opération', _comment='comment', _tags=['t1', 't2'], _charlimit=33, _occurrences=['myfile.py:9'], ), ]
def test_all_string_params(self): src = TEMPLATE.replace( u'{{string1}}', u'{%t "Le canapé" ' u'_context="furniture" _comment="_comment" _charlimit=10 ' u'_tags="t1,t2" %}') strings = extract_transifex_template_strings(src) assert strings == [ SourceString(u"Le canapé", _context=u'furniture', _comment=u'_comment', _charlimit=10, _tags=['t1', 't2']), ]
def test_custom_meta(self): string = SourceString( 'something', _context='one,two,three', _comment='A crucial comment', _charlimit=33, _tags=' t1,t2 , t3', custom='custom', ) assert string.string == 'something' assert string.context == ['one', 'two', 'three'] assert string.developer_comment == 'A crucial comment' assert string.character_limit == 33 assert string.tags == ['t1', 't2', 't3'] assert string.meta.get('custom') is None
def tnode_to_source_string(tnode): """ Convert a parsed TNode to a SourceString instance. TNode is what the template tag implementation will return having processed the contents from the template. A SourceString is a data object which exposes information in a useful way for pushing to transifex. """ if not isinstance(tnode.source_string.var, string_types): return None meta = {} for key, value in tnode.params.items(): if len(value.filters) != 0: continue if isinstance(value.var, string_types): meta[key] = value.var elif getattr(value.var, 'literal', None) is not None: meta[key] = value.var.literal _context = meta.pop('_context', None) return SourceString(tnode.source_string.var, _context, **meta)
def test_multiline(self): src = TEMPLATE.replace( u'{{string1}}', u""" {% t visit_type='first' username=user.name _context="stuff" _charlimit=10 %} {visit_type, select, first {Welcome, {username}} returning {Welcome back, {username}} } {% endt %}""") strings = extract_transifex_template_strings(src) assert strings[0] == SourceString( u""" {visit_type, select, first {Welcome, {username}} returning {Welcome back, {username}} } """, _context='stuff', _charlimit=10, )
def clone_string(source_string, new_tags=None): """Create a new SourceString instance, identical to the one given, by optionally replacing its tags with the ones given. :param SourceString source_string: the string to clone :param list new_tags: a list of strings to use as the tags for the new string :rtype: SourceString :return: a new SourceString instance """ cloned_string = SourceString( source_string.string, _context=( ','.join(source_string.context) if source_string.context else '' ), **source_string.meta ) if new_tags is not None: cloned_string.meta[consts.KEY_TAGS] = new_tags return cloned_string
def test_tag_list(self): string = SourceString( 'something', _tags=['t1', 't2', 't3'], ) assert string.tags == ['t1', 't2', 't3']
def test_python_parsing_push_exception(mock_find_files, mock_read, mock_push_strings): mock_push_strings.return_value = 500, "content_to_trigger_exception" mock_find_files.return_value = [ TranslatableFile('dir1', '1.py', 'locdir1'), TranslatableFile('dir1/dir2', '2.py', 'locdir1'), TranslatableFile('dir1/dir3', '3.py', 'locdir1'), ] mock_read.side_effect = [ # 1.py PYTHON_TEMPLATE.format( _import='import transifex.native', call1='native.translate', call2='native.translate', string1=u'Le canapé', string2=u'Les données', ), # 2.py PYTHON_TEMPLATE.format( _import='import transifex.native as _n', call1='_n.translate', call2='_n.translate', string1=u'Le canapé 2', string2=u'Les données 2', ), # 3.py PYTHON_TEMPLATE.format( _import='from transifex.native import translate', call1='translate', call2='translate', string1=u'Le canapé 3', string2=u'Les données 3', ), ] expected = [ # 1.py SourceString( u'Le canapé', u'désign1,désign2', _occurrences=['r1/1.py:6'], ), SourceString( u'Les données', u'opération', _comment='comment', _tags='t1,t2', _charlimit=33, _occurrences=['r1/1.py:7'], ), # 2.py SourceString( u'Le canapé 2', u'désign1,désign2', _occurrences=['r1/dir2/2.py:6'], ), SourceString( u'Les données 2', u'opération', _comment='comment', _tags='t1,t2', _charlimit=33, _occurrences=['r1/dir2/2.py:7'], ), # 3.py SourceString( u'Le canapé 3', u'désign1,désign2', _occurrences=['r1/dir3/3.py:6'], ), SourceString( u'Les données 3', u'opération', _comment='comment', _tags='t1,t2', _charlimit=33, _occurrences=['r1/dir3/3.py:7'], ), ] compare(expected)
string1=u'Le canapé 2', string2=u'Les données 2', ), # 3.py PYTHON_TEMPLATE.format( _import='from transifex.native import translate', call1='translate', call2='translate', string1=u'Le canapé 3', string2=u'Les données 3', ), ] SOURCE_STRINGS = [ # 1.py SourceString(u'Le canapé', u'désign1,désign2', _occurrences=['r1/1.py:6'],), SourceString( u'Les données', u'opération', _comment='comment', _tags='t1,t2', _charlimit=33, _occurrences=['r1/1.py:7'], ), # 2.py SourceString(u'Le canapé 2', u'désign1,désign2', _occurrences=['r1/dir2/2.py:6'],), SourceString( u'Les données 2', u'opération', _comment='comment', _tags='t1,t2', _charlimit=33, _occurrences=['r1/dir2/2.py:7'], ), # 3.py SourceString(u'Le canapé 3', u'désign1,désign2', _occurrences=['r1/dir3/3.py:6'],), SourceString(