Best JavaScript code snippet using ng-mocks
test_contentmanager.py
Source:test_contentmanager.py
...21 cm.add_get_handler(key, foo_getter)22 m = self._make_message()23 m['Content-Type'] = 'text/plain'24 m['X-Bar-Header'] = 'foo'25 self.assertEqual(cm.get_content(m, foo='bar'), ('bar', 'foo'))26 def get_key_as_get_content_key_order(self, order, key):27 def bar_getter(msg):28 return msg['X-Bar-Header']29 def foo_getter(msg):30 return msg['X-Foo-Header']31 cm = ContentManager()32 cm.add_get_handler(key, foo_getter)33 for precedence, key in self.get_key_params.values():34 if precedence > order:35 cm.add_get_handler(key, bar_getter)36 m = self._make_message()37 m['Content-Type'] = 'text/plain'38 m['X-Bar-Header'] = 'bar'39 m['X-Foo-Header'] = 'foo'40 self.assertEqual(cm.get_content(m), ('foo'))41 def test_get_content_raises_if_unknown_mimetype_and_no_default(self):42 cm = ContentManager()43 m = self._make_message()44 m['Content-Type'] = 'text/plain'45 with self.assertRaisesRegex(KeyError, 'text/plain'):46 cm.get_content(m)47 class BaseThing(str):48 pass49 baseobject_full_path = __name__ + '.' + 'TestContentManager.BaseThing'50 class Thing(BaseThing):51 pass52 testobject_full_path = __name__ + '.' + 'TestContentManager.Thing'53 set_key_params = {54 'type': (0, Thing,),55 'full_path': (1, testobject_full_path,),56 'qualname': (2, 'TestContentManager.Thing',),57 'name': (3, 'Thing',),58 'base_type': (4, BaseThing,),59 'base_full_path': (5, baseobject_full_path,),60 'base_qualname': (6, 'TestContentManager.BaseThing',),61 'base_name': (7, 'BaseThing',),62 'str_type': (8, str,),63 'str_full_path': (9, 'builtins.str',),64 'str_name': (10, 'str',), # str name and qualname are the same65 'null_key': (11, None,),66 }67 def set_key_as_set_content_key(self, order, key):68 def foo_setter(msg, obj, foo=None):69 msg['X-Foo-Header'] = foo70 msg.set_payload(obj)71 cm = ContentManager()72 cm.add_set_handler(key, foo_setter)73 m = self._make_message()74 msg_obj = self.Thing()75 cm.set_content(m, msg_obj, foo='bar')76 self.assertEqual(m['X-Foo-Header'], 'bar')77 self.assertEqual(m.get_payload(), msg_obj)78 def set_key_as_set_content_key_order(self, order, key):79 def foo_setter(msg, obj):80 msg['X-FooBar-Header'] = 'foo'81 msg.set_payload(obj)82 def bar_setter(msg, obj):83 msg['X-FooBar-Header'] = 'bar'84 cm = ContentManager()85 cm.add_set_handler(key, foo_setter)86 for precedence, key in self.get_key_params.values():87 if precedence > order:88 cm.add_set_handler(key, bar_setter)89 m = self._make_message()90 msg_obj = self.Thing()91 cm.set_content(m, msg_obj)92 self.assertEqual(m['X-FooBar-Header'], 'foo')93 self.assertEqual(m.get_payload(), msg_obj)94 def test_set_content_raises_if_unknown_type_and_no_default(self):95 cm = ContentManager()96 m = self._make_message()97 msg_obj = self.Thing()98 with self.assertRaisesRegex(KeyError, self.testobject_full_path):99 cm.set_content(m, msg_obj)100 def test_set_content_raises_if_called_on_multipart(self):101 cm = ContentManager()102 m = self._make_message()103 m['Content-Type'] = 'multipart/foo'104 with self.assertRaises(TypeError):105 cm.set_content(m, 'test')106 def test_set_content_calls_clear_content(self):107 m = self._make_message()108 m['Content-Foo'] = 'bar'109 m['Content-Type'] = 'text/html'110 m['To'] = 'test'111 m.set_payload('abc')112 cm = ContentManager()113 cm.add_set_handler(str, lambda *args, **kw: None)114 m.set_content('xyz', content_manager=cm)115 self.assertIsNone(m['Content-Foo'])116 self.assertIsNone(m['Content-Type'])117 self.assertEqual(m['To'], 'test')118 self.assertIsNone(m.get_payload())119@parameterize120class TestRawDataManager(TestEmailBase):121 # Note: these tests are dependent on the order in which headers are added122 # to the message objects by the code. There's no defined ordering in123 # RFC5322/MIME, so this makes the tests more fragile than the standards124 # require. However, if the header order changes it is best to understand125 # *why*, and make sure it isn't a subtle bug in whatever change was126 # applied.127 policy = policy.default.clone(max_line_length=60,128 content_manager=raw_data_manager)129 message = EmailMessage130 def test_get_text_plain(self):131 m = self._str_msg(textwrap.dedent("""\132 Content-Type: text/plain133 Basic text.134 """))135 self.assertEqual(raw_data_manager.get_content(m), "Basic text.\n")136 def test_get_text_html(self):137 m = self._str_msg(textwrap.dedent("""\138 Content-Type: text/html139 <p>Basic text.</p>140 """))141 self.assertEqual(raw_data_manager.get_content(m),142 "<p>Basic text.</p>\n")143 def test_get_text_plain_latin1(self):144 m = self._bytes_msg(textwrap.dedent("""\145 Content-Type: text/plain; charset=latin1146 Basìc tëxt.147 """).encode('latin1'))148 self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt.\n")149 def test_get_text_plain_latin1_quoted_printable(self):150 m = self._str_msg(textwrap.dedent("""\151 Content-Type: text/plain; charset="latin-1"152 Content-Transfer-Encoding: quoted-printable153 Bas=ECc t=EBxt.154 """))155 self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt.\n")156 def test_get_text_plain_utf8_base64(self):157 m = self._str_msg(textwrap.dedent("""\158 Content-Type: text/plain; charset="utf8"159 Content-Transfer-Encoding: base64160 QmFzw6xjIHTDq3h0Lgo=161 """))162 self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt.\n")163 def test_get_text_plain_bad_utf8_quoted_printable(self):164 m = self._str_msg(textwrap.dedent("""\165 Content-Type: text/plain; charset="utf8"166 Content-Transfer-Encoding: quoted-printable167 Bas=c3=acc t=c3=abxt=fd.168 """))169 self.assertEqual(raw_data_manager.get_content(m), "Basìc tëxt�.\n")170 def test_get_text_plain_bad_utf8_quoted_printable_ignore_errors(self):171 m = self._str_msg(textwrap.dedent("""\172 Content-Type: text/plain; charset="utf8"173 Content-Transfer-Encoding: quoted-printable174 Bas=c3=acc t=c3=abxt=fd.175 """))176 self.assertEqual(raw_data_manager.get_content(m, errors='ignore'),177 "Basìc tëxt.\n")178 def test_get_text_plain_utf8_base64_recoverable_bad_CTE_data(self):179 m = self._str_msg(textwrap.dedent("""\180 Content-Type: text/plain; charset="utf8"181 Content-Transfer-Encoding: base64182 QmFzw6xjIHTDq3h0Lgo\xFF=183 """))184 self.assertEqual(raw_data_manager.get_content(m, errors='ignore'),185 "Basìc tëxt.\n")186 def test_get_text_invalid_keyword(self):187 m = self._str_msg(textwrap.dedent("""\188 Content-Type: text/plain189 Basic text.190 """))191 with self.assertRaises(TypeError):192 raw_data_manager.get_content(m, foo='ignore')193 def test_get_non_text(self):194 template = textwrap.dedent("""\195 Content-Type: {}196 Content-Transfer-Encoding: base64197 Ym9ndXMgZGF0YQ==198 """)199 for maintype in 'audio image video application'.split():200 with self.subTest(maintype=maintype):201 m = self._str_msg(template.format(maintype+'/foo'))202 self.assertEqual(raw_data_manager.get_content(m), b"bogus data")203 def test_get_non_text_invalid_keyword(self):204 m = self._str_msg(textwrap.dedent("""\205 Content-Type: image/jpg206 Content-Transfer-Encoding: base64207 Ym9ndXMgZGF0YQ==208 """))209 with self.assertRaises(TypeError):210 raw_data_manager.get_content(m, errors='ignore')211 def test_get_raises_on_multipart(self):212 m = self._str_msg(textwrap.dedent("""\213 Content-Type: multipart/mixed; boundary="==="214 --===215 --===--216 """))217 with self.assertRaises(KeyError):218 raw_data_manager.get_content(m)219 def test_get_message_rfc822_and_external_body(self):220 template = textwrap.dedent("""\221 Content-Type: message/{}222 To: foo@example.com223 From: bar@example.com224 Subject: example225 an example message226 """)227 for subtype in 'rfc822 external-body'.split():228 with self.subTest(subtype=subtype):229 m = self._str_msg(template.format(subtype))230 sub_msg = raw_data_manager.get_content(m)231 self.assertIsInstance(sub_msg, self.message)232 self.assertEqual(raw_data_manager.get_content(sub_msg),233 "an example message\n")234 self.assertEqual(sub_msg['to'], 'foo@example.com')235 self.assertEqual(sub_msg['from'].addresses[0].username, 'bar')236 def test_get_message_non_rfc822_or_external_body_yields_bytes(self):237 m = self._str_msg(textwrap.dedent("""\238 Content-Type: message/partial239 To: foo@example.com240 From: bar@example.com241 Subject: example242 The real body is in another message.243 """))244 self.assertEqual(raw_data_manager.get_content(m)[:10], b'To: foo@ex')245 def test_set_text_plain(self):246 m = self._make_message()247 content = "Simple message.\n"248 raw_data_manager.set_content(m, content)249 self.assertEqual(str(m), textwrap.dedent("""\250 Content-Type: text/plain; charset="utf-8"251 Content-Transfer-Encoding: 7bit252 Simple message.253 """))254 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)255 self.assertEqual(m.get_content(), content)256 def test_set_text_html(self):257 m = self._make_message()258 content = "<p>Simple message.</p>\n"259 raw_data_manager.set_content(m, content, subtype='html')260 self.assertEqual(str(m), textwrap.dedent("""\261 Content-Type: text/html; charset="utf-8"262 Content-Transfer-Encoding: 7bit263 <p>Simple message.</p>264 """))265 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)266 self.assertEqual(m.get_content(), content)267 def test_set_text_charset_latin_1(self):268 m = self._make_message()269 content = "Simple message.\n"270 raw_data_manager.set_content(m, content, charset='latin-1')271 self.assertEqual(str(m), textwrap.dedent("""\272 Content-Type: text/plain; charset="iso-8859-1"273 Content-Transfer-Encoding: 7bit274 Simple message.275 """))276 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)277 self.assertEqual(m.get_content(), content)278 def test_set_text_short_line_minimal_non_ascii_heuristics(self):279 m = self._make_message()280 content = "et là il est monté sur moi et il commence à m'éto.\n"281 raw_data_manager.set_content(m, content)282 self.assertEqual(bytes(m), textwrap.dedent("""\283 Content-Type: text/plain; charset="utf-8"284 Content-Transfer-Encoding: 8bit285 et là il est monté sur moi et il commence à m'éto.286 """).encode('utf-8'))287 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)288 self.assertEqual(m.get_content(), content)289 def test_set_text_long_line_minimal_non_ascii_heuristics(self):290 m = self._make_message()291 content = ("j'ai un problème de python. il est sorti de son"292 " vivarium. et là il est monté sur moi et il commence"293 " à m'éto.\n")294 raw_data_manager.set_content(m, content)295 self.assertEqual(bytes(m), textwrap.dedent("""\296 Content-Type: text/plain; charset="utf-8"297 Content-Transfer-Encoding: quoted-printable298 j'ai un probl=C3=A8me de python. il est sorti de son vivari=299 um. et l=C3=A0 il est mont=C3=A9 sur moi et il commence =300 =C3=A0 m'=C3=A9to.301 """).encode('utf-8'))302 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)303 self.assertEqual(m.get_content(), content)304 def test_set_text_11_lines_long_line_minimal_non_ascii_heuristics(self):305 m = self._make_message()306 content = '\n'*10 + (307 "j'ai un problème de python. il est sorti de son"308 " vivarium. et là il est monté sur moi et il commence"309 " à m'éto.\n")310 raw_data_manager.set_content(m, content)311 self.assertEqual(bytes(m), textwrap.dedent("""\312 Content-Type: text/plain; charset="utf-8"313 Content-Transfer-Encoding: quoted-printable314 """ + '\n'*10 + """315 j'ai un probl=C3=A8me de python. il est sorti de son vivari=316 um. et l=C3=A0 il est mont=C3=A9 sur moi et il commence =317 =C3=A0 m'=C3=A9to.318 """).encode('utf-8'))319 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)320 self.assertEqual(m.get_content(), content)321 def test_set_text_maximal_non_ascii_heuristics(self):322 m = self._make_message()323 content = "áà äéèÄöÅ.\n"324 raw_data_manager.set_content(m, content)325 self.assertEqual(bytes(m), textwrap.dedent("""\326 Content-Type: text/plain; charset="utf-8"327 Content-Transfer-Encoding: 8bit328 áà äéèÄöÅ.329 """).encode('utf-8'))330 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)331 self.assertEqual(m.get_content(), content)332 def test_set_text_11_lines_maximal_non_ascii_heuristics(self):333 m = self._make_message()334 content = '\n'*10 + "áà äéèÄöÅ.\n"335 raw_data_manager.set_content(m, content)336 self.assertEqual(bytes(m), textwrap.dedent("""\337 Content-Type: text/plain; charset="utf-8"338 Content-Transfer-Encoding: 8bit339 """ + '\n'*10 + """340 áà äéèÄöÅ.341 """).encode('utf-8'))342 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)343 self.assertEqual(m.get_content(), content)344 def test_set_text_long_line_maximal_non_ascii_heuristics(self):345 m = self._make_message()346 content = ("áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ"347 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ"348 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ.\n")349 raw_data_manager.set_content(m, content)350 self.assertEqual(bytes(m), textwrap.dedent("""\351 Content-Type: text/plain; charset="utf-8"352 Content-Transfer-Encoding: base64353 w6HDoMOkw6nDqMSZw7bFkcOhw6DDpMOpw6jEmcO2xZHDocOgw6TDqcOoxJnD354 tsWRw6HDoMOkw6nDqMSZw7bFkcOhw6DDpMOpw6jEmcO2xZHDocOgw6TDqcOo355 xJnDtsWRw6HDoMOkw6nDqMSZw7bFkcOhw6DDpMOpw6jEmcO2xZHDocOgw6TD356 qcOoxJnDtsWRw6HDoMOkw6nDqMSZw7bFkcOhw6DDpMOpw6jEmcO2xZHDocOg357 w6TDqcOoxJnDtsWRLgo=358 """).encode('utf-8'))359 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)360 self.assertEqual(m.get_content(), content)361 def test_set_text_11_lines_long_line_maximal_non_ascii_heuristics(self):362 # Yes, it chooses "wrong" here. It's a heuristic. So this result363 # could change if we come up with a better heuristic.364 m = self._make_message()365 content = ('\n'*10 +366 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ"367 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ"368 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ.\n")369 raw_data_manager.set_content(m, "\n"*10 +370 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ"371 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ"372 "áà äéèÄöÅáà äéèÄöÅáà äéèÄöÅáà äéèÄöÅ.\n")373 self.assertEqual(bytes(m), textwrap.dedent("""\374 Content-Type: text/plain; charset="utf-8"375 Content-Transfer-Encoding: quoted-printable376 """ + '\n'*10 + """377 =C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4=99=C3=B6=C5=91=C3=A1=C3=378 =A0=C3=A4=C3=A9=C3=A8=C4=99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=379 =C3=A9=C3=A8=C4=99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=C3=380 =A8=C4=99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4=99=381 =C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4=99=C3=B6=C5=382 =91=C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4=99=C3=B6=C5=91=C3=A1=383 =C3=A0=C3=A4=C3=A9=C3=A8=C4=99=C3=B6=C5=91=C3=A1=C3=A0=C3=384 =A4=C3=A9=C3=A8=C4=99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=385 =C3=A8=C4=99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4=386 =99=C3=B6=C5=91=C3=A1=C3=A0=C3=A4=C3=A9=C3=A8=C4=99=C3=B6=387 =C5=91.388 """).encode('utf-8'))389 self.assertEqual(m.get_payload(decode=True).decode('utf-8'), content)390 self.assertEqual(m.get_content(), content)391 def test_set_text_non_ascii_with_cte_7bit_raises(self):392 m = self._make_message()393 with self.assertRaises(UnicodeError):394 raw_data_manager.set_content(m,"áà äéèÄöÅ.\n", cte='7bit')395 def test_set_text_non_ascii_with_charset_ascii_raises(self):396 m = self._make_message()397 with self.assertRaises(UnicodeError):398 raw_data_manager.set_content(m,"áà äéèÄöÅ.\n", charset='ascii')399 def test_set_text_non_ascii_with_cte_7bit_and_charset_ascii_raises(self):400 m = self._make_message()401 with self.assertRaises(UnicodeError):402 raw_data_manager.set_content(m,"áà äéèÄöÅ.\n", cte='7bit', charset='ascii')403 def test_set_message(self):404 m = self._make_message()405 m['Subject'] = "Forwarded message"406 content = self._make_message()407 content['To'] = 'python@vivarium.org'408 content['From'] = 'police@monty.org'409 content['Subject'] = "get back in your box"410 content.set_content("Or face the comfy chair.")411 raw_data_manager.set_content(m, content)412 self.assertEqual(str(m), textwrap.dedent("""\413 Subject: Forwarded message414 Content-Type: message/rfc822415 Content-Transfer-Encoding: 8bit416 To: python@vivarium.org417 From: police@monty.org418 Subject: get back in your box419 Content-Type: text/plain; charset="utf-8"420 Content-Transfer-Encoding: 7bit421 MIME-Version: 1.0422 Or face the comfy chair.423 """))424 payload = m.get_payload(0)425 self.assertIsInstance(payload, self.message)426 self.assertEqual(str(payload), str(content))427 self.assertIsInstance(m.get_content(), self.message)428 self.assertEqual(str(m.get_content()), str(content))429 def test_set_message_with_non_ascii_and_coercion_to_7bit(self):430 m = self._make_message()431 m['Subject'] = "Escape report"432 content = self._make_message()433 content['To'] = 'police@monty.org'434 content['From'] = 'victim@monty.org'435 content['Subject'] = "Help"436 content.set_content("j'ai un problème de python. il est sorti de son"437 " vivarium.")438 raw_data_manager.set_content(m, content)439 self.assertEqual(bytes(m), textwrap.dedent("""\440 Subject: Escape report441 Content-Type: message/rfc822442 Content-Transfer-Encoding: 8bit443 To: police@monty.org444 From: victim@monty.org445 Subject: Help446 Content-Type: text/plain; charset="utf-8"447 Content-Transfer-Encoding: 8bit448 MIME-Version: 1.0449 j'ai un problème de python. il est sorti de son vivarium.450 """).encode('utf-8'))451 # The choice of base64 for the body encoding is because generator452 # doesn't bother with heuristics and uses it unconditionally for utf-8453 # text.454 # XXX: the first cte should be 7bit, too...that's a generator bug.455 # XXX: the line length in the body also looks like a generator bug.456 self.assertEqual(m.as_string(maxheaderlen=self.policy.max_line_length),457 textwrap.dedent("""\458 Subject: Escape report459 Content-Type: message/rfc822460 Content-Transfer-Encoding: 8bit461 To: police@monty.org462 From: victim@monty.org463 Subject: Help464 Content-Type: text/plain; charset="utf-8"465 Content-Transfer-Encoding: base64466 MIME-Version: 1.0467 aidhaSB1biBwcm9ibMOobWUgZGUgcHl0aG9uLiBpbCBlc3Qgc29ydGkgZGUgc29uIHZpdmFyaXVt468 Lgo=469 """))470 self.assertIsInstance(m.get_content(), self.message)471 self.assertEqual(str(m.get_content()), str(content))472 def test_set_message_invalid_cte_raises(self):473 m = self._make_message()474 content = self._make_message()475 for cte in 'quoted-printable base64'.split():476 for subtype in 'rfc822 external-body'.split():477 with self.subTest(cte=cte, subtype=subtype):478 with self.assertRaises(ValueError) as ar:479 m.set_content(content, subtype, cte=cte)480 exc = str(ar.exception)481 self.assertIn(cte, exc)482 self.assertIn(subtype, exc)483 subtype = 'external-body'484 for cte in '8bit binary'.split():485 with self.subTest(cte=cte, subtype=subtype):486 with self.assertRaises(ValueError) as ar:487 m.set_content(content, subtype, cte=cte)488 exc = str(ar.exception)489 self.assertIn(cte, exc)490 self.assertIn(subtype, exc)491 def test_set_image_jpg(self):492 for content in (b"bogus content",493 bytearray(b"bogus content"),494 memoryview(b"bogus content")):495 with self.subTest(content=content):496 m = self._make_message()497 raw_data_manager.set_content(m, content, 'image', 'jpeg')498 self.assertEqual(str(m), textwrap.dedent("""\499 Content-Type: image/jpeg500 Content-Transfer-Encoding: base64501 Ym9ndXMgY29udGVudA==502 """))503 self.assertEqual(m.get_payload(decode=True), content)504 self.assertEqual(m.get_content(), content)505 def test_set_audio_aif_with_quoted_printable_cte(self):506 # Why you would use qp, I don't know, but it is technically supported.507 # XXX: the incorrect line length is because binascii.b2a_qp doesn't508 # support a line length parameter, but we must use it to get newline509 # encoding.510 # XXX: what about that lack of tailing newline? Do we actually handle511 # that correctly in all cases? That is, if the *source* has an512 # unencoded newline, do we add an extra newline to the returned payload513 # or not? And can that actually be disambiguated based on the RFC?514 m = self._make_message()515 content = b'b\xFFgus\tcon\nt\rent ' + b'z'*100516 m.set_content(content, 'audio', 'aif', cte='quoted-printable')517 self.assertEqual(bytes(m), textwrap.dedent("""\518 Content-Type: audio/aif519 Content-Transfer-Encoding: quoted-printable520 MIME-Version: 1.0521 b=FFgus=09con=0At=0Dent=20zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=522 zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz""").encode('latin-1'))523 self.assertEqual(m.get_payload(decode=True), content)524 self.assertEqual(m.get_content(), content)525 def test_set_video_mpeg_with_binary_cte(self):526 m = self._make_message()527 content = b'b\xFFgus\tcon\nt\rent ' + b'z'*100528 m.set_content(content, 'video', 'mpeg', cte='binary')529 self.assertEqual(bytes(m), textwrap.dedent("""\530 Content-Type: video/mpeg531 Content-Transfer-Encoding: binary532 MIME-Version: 1.0533 """).encode('ascii') +534 # XXX: the second \n ought to be a \r, but generator gets it wrong.535 # THIS MEANS WE DON'T ACTUALLY SUPPORT THE 'binary' CTE.536 b'b\xFFgus\tcon\nt\nent zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' +537 b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz')538 self.assertEqual(m.get_payload(decode=True), content)539 self.assertEqual(m.get_content(), content)540 def test_set_application_octet_stream_with_8bit_cte(self):541 # In 8bit mode, univeral line end logic applies. It is up to the542 # application to make sure the lines are short enough; we don't check.543 m = self._make_message()544 content = b'b\xFFgus\tcon\nt\rent\n' + b'z'*60 + b'\n'545 m.set_content(content, 'application', 'octet-stream', cte='8bit')546 self.assertEqual(bytes(m), textwrap.dedent("""\547 Content-Type: application/octet-stream548 Content-Transfer-Encoding: 8bit549 MIME-Version: 1.0550 """).encode('ascii') +551 b'b\xFFgus\tcon\nt\nent\n' +552 b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\n')553 self.assertEqual(m.get_payload(decode=True), content)554 self.assertEqual(m.get_content(), content)555 def test_set_headers_from_header_objects(self):556 m = self._make_message()557 content = "Simple message.\n"558 header_factory = self.policy.header_factory559 raw_data_manager.set_content(m, content, headers=(560 header_factory("To", "foo@example.com"),561 header_factory("From", "foo@example.com"),562 header_factory("Subject", "I'm talking to myself.")))563 self.assertEqual(str(m), textwrap.dedent("""\564 Content-Type: text/plain; charset="utf-8"565 To: foo@example.com566 From: foo@example.com567 Subject: I'm talking to myself.568 Content-Transfer-Encoding: 7bit569 Simple message.570 """))571 def test_set_headers_from_strings(self):572 m = self._make_message()573 content = "Simple message.\n"574 raw_data_manager.set_content(m, content, headers=(575 "X-Foo-Header: foo",576 "X-Bar-Header: bar",))577 self.assertEqual(str(m), textwrap.dedent("""\578 Content-Type: text/plain; charset="utf-8"579 X-Foo-Header: foo580 X-Bar-Header: bar581 Content-Transfer-Encoding: 7bit582 Simple message.583 """))584 def test_set_headers_with_invalid_duplicate_string_header_raises(self):585 m = self._make_message()586 content = "Simple message.\n"587 with self.assertRaisesRegex(ValueError, 'Content-Type'):588 raw_data_manager.set_content(m, content, headers=(589 "Content-Type: foo/bar",)590 )591 def test_set_headers_with_invalid_duplicate_header_header_raises(self):592 m = self._make_message()593 content = "Simple message.\n"594 header_factory = self.policy.header_factory595 with self.assertRaisesRegex(ValueError, 'Content-Type'):596 raw_data_manager.set_content(m, content, headers=(597 header_factory("Content-Type", " foo/bar"),)598 )599 def test_set_headers_with_defective_string_header_raises(self):600 m = self._make_message()601 content = "Simple message.\n"602 with self.assertRaisesRegex(ValueError, 'a@fairly@@invalid@address'):603 raw_data_manager.set_content(m, content, headers=(604 'To: a@fairly@@invalid@address',)605 )606 print(m['To'].defects)607 def test_set_headers_with_defective_header_header_raises(self):608 m = self._make_message()609 content = "Simple message.\n"610 header_factory = self.policy.header_factory611 with self.assertRaisesRegex(ValueError, 'a@fairly@@invalid@address'):612 raw_data_manager.set_content(m, content, headers=(613 header_factory('To', 'a@fairly@@invalid@address'),)614 )615 print(m['To'].defects)616 def test_set_disposition_inline(self):617 m = self._make_message()618 m.set_content('foo', disposition='inline')619 self.assertEqual(m['Content-Disposition'], 'inline')620 def test_set_disposition_attachment(self):621 m = self._make_message()622 m.set_content('foo', disposition='attachment')623 self.assertEqual(m['Content-Disposition'], 'attachment')624 def test_set_disposition_foo(self):625 m = self._make_message()626 m.set_content('foo', disposition='foo')627 self.assertEqual(m['Content-Disposition'], 'foo')628 # XXX: we should have a 'strict' policy mode (beyond raise_on_defect) that629 # would cause 'foo' above to raise.630 def test_set_filename(self):631 m = self._make_message()632 m.set_content('foo', filename='bar.txt')633 self.assertEqual(m['Content-Disposition'],634 'attachment; filename="bar.txt"')635 def test_set_filename_and_disposition_inline(self):636 m = self._make_message()637 m.set_content('foo', disposition='inline', filename='bar.txt')638 self.assertEqual(m['Content-Disposition'], 'inline; filename="bar.txt"')639 def test_set_non_ascii_filename(self):640 m = self._make_message()641 m.set_content('foo', filename='ábárî.txt')642 self.assertEqual(bytes(m), textwrap.dedent("""\643 Content-Type: text/plain; charset="utf-8"644 Content-Transfer-Encoding: 7bit645 Content-Disposition: attachment;646 filename*=utf-8''%C3%A1b%C3%A1r%C3%AE.txt647 MIME-Version: 1.0648 foo649 """).encode('ascii'))650 content_object_params = {651 'text_plain': ('content', ()),652 'text_html': ('content', ('html',)),653 'application_octet_stream': (b'content',654 ('application', 'octet_stream')),655 'image_jpeg': (b'content', ('image', 'jpeg')),656 'message_rfc822': (message(), ()),657 'message_external_body': (message(), ('external-body',)),658 }659 def content_object_as_header_receiver(self, obj, mimetype):660 m = self._make_message()661 m.set_content(obj, *mimetype, headers=(662 'To: foo@example.com',663 'From: bar@simple.net'))664 self.assertEqual(m['to'], 'foo@example.com')665 self.assertEqual(m['from'], 'bar@simple.net')666 def content_object_as_disposition_inline_receiver(self, obj, mimetype):667 m = self._make_message()668 m.set_content(obj, *mimetype, disposition='inline')669 self.assertEqual(m['Content-Disposition'], 'inline')670 def content_object_as_non_ascii_filename_receiver(self, obj, mimetype):671 m = self._make_message()672 m.set_content(obj, *mimetype, disposition='inline', filename='bár.txt')673 self.assertEqual(m['Content-Disposition'], 'inline; filename="bár.txt"')674 self.assertEqual(m.get_filename(), "bár.txt")675 self.assertEqual(m['Content-Disposition'].params['filename'], "bár.txt")676 def content_object_as_cid_receiver(self, obj, mimetype):677 m = self._make_message()678 m.set_content(obj, *mimetype, cid='some_random_stuff')679 self.assertEqual(m['Content-ID'], 'some_random_stuff')680 def content_object_as_params_receiver(self, obj, mimetype):681 m = self._make_message()682 params = {'foo': 'bár', 'abc': 'xyz'}683 m.set_content(obj, *mimetype, params=params)684 if isinstance(obj, str):685 params['charset'] = 'utf-8'686 self.assertEqual(m['Content-Type'].params, params)687if __name__ == '__main__':...
default.py
Source:default.py
1#!/usr/bin/python2# -*- coding: utf-8 -*-3import xbmc, xbmcgui, xbmcaddon, urllib, urllib2, socket, cookielib, re, os, shutil, base64, xbmcvfs4addon = xbmcaddon.Addon()5socket.setdefaulttimeout(60)6addonID = addon.getAddonInfo('id')7translation = addon.getLocalizedString8addonUserDataFolder=xbmc.translatePath("special://profile/addon_data/"+addonID)9subTempDir=xbmc.translatePath("special://profile/addon_data/"+addonID+"/srtTemp/")10icon = xbmc.translatePath('special://home/addons/'+addonID+'/icon.png')11rarFile=xbmc.translatePath(addonUserDataFolder+"/sub.")12subFile=xbmc.translatePath(addonUserDataFolder+"/sub.srt")13favFile=xbmc.translatePath(addonUserDataFolder+"/favourites")14apiKeyFile=xbmc.translatePath(addonUserDataFolder+"/api.key")15if not os.path.isdir(addonUserDataFolder):16 os.mkdir(addonUserDataFolder)17if not os.path.isdir(subTempDir):18 os.mkdir(subTempDir)19if os.path.exists(apiKeyFile):20 fh = open(apiKeyFile, 'r')21 ownKey = fh.read()22 fh.close()23else:24 ownKey=""25user=""26pw=""27backNav=""28pause=""29saveSub=""30language=""31def getSettings():32 global user33 user=addon.getSetting("user")34 global pw35 pw=addon.getSetting("pw")36 global backNav37 backNav=addon.getSetting("backNav")38 global pause39 pause=addon.getSetting("pause")40 global saveSub41 saveSub=addon.getSetting("saveSub")42 global language43 language=addon.getSetting("language")44getSettings()45if pause=="true" and xbmc.Player().isPlayingVideo():46 xbmc.Player().pause()47playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)48if playlist.getposition()>=0:49 currentTitle = playlist[playlist.getposition()].getdescription()50 51currentFile = xbmc.Player().getPlayingFile()52cj = cookielib.CookieJar()53mainUrl = "http://www.subcentral.de"54opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))55userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0"56opener.addheaders = [('User-Agent', userAgent)]57opener.open(mainUrl+"/index.php?form=UserLogin", data="loginUsername="+urllib.quote_plus(user)+"&loginPassword="+urllib.quote_plus(pw))58while (user=="" or pw==""):59 addon.openSettings()60 getSettings()61currentEpisode=""62currentSeason=""63currentEpisode=xbmc.getInfoLabel('VideoPlayer.Episode')64currentSeason=xbmc.getInfoLabel('VideoPlayer.Season')65dirName = ""66try:67 dirName=(currentFile.split(os.sep)[-2]).lower()68except:69 pass70fileName=os.path.basename(currentFile).lower()71if currentEpisode=="":72 matchDir=re.compile('\\.s(.+?)e(.+?)\\.', re.DOTALL).findall(dirName)73 matchFile=re.compile('\\.s(.+?)e(.+?)\\.', re.DOTALL).findall(fileName)74 if len(matchDir)>0:75 currentSeason=matchDir[0][0]76 currentEpisode=matchDir[0][1]77 elif len(matchFile)>0:78 currentSeason=matchFile[0][0]79 currentEpisode=matchFile[0][1]80if currentEpisode=="":81 match=re.compile('(.+?)- s(.+?)e(.+?) ', re.DOTALL).findall(xbmc.getInfoLabel('VideoPlayer.Title').lower())82 if len(match)>0:83 currentSeason=match[0][1]84 currentEpisode=match[0][2]85if len(currentEpisode)==1:86 currentEpisode="0"+currentEpisode87if len(currentSeason)==1:88 currentSeason="0"+currentSeason89currentRelease=""90if "-" in fileName:91 currentRelease=(fileName.split("-")[-1]).lower()92 if "." in currentRelease:93 currentRelease=currentRelease[:currentRelease.find(".")]94elif "-" in dirName:95 currentRelease=(dirName.split("-")[-1]).lower()96def main():97 global mainType98 mainType = ""99 dialog = xbmcgui.Dialog()100 nr=dialog.select("SubCentral.de", [translation(30013),translation(30001),translation(30002),translation(30011)])101 if nr==0:102 search()103 elif nr==1:104 mainType="fav"105 showFavourites()106 elif nr==2:107 mainType="all"108 showAllSeries()109 elif nr==3:110 addon.openSettings()111 getSettings()112 main()113 else:114 if pause=="true" and xbmc.Player().isPlayingVideo():115 xbmc.Player().pause()116def search():117 title=xbmc.getInfoLabel('VideoPlayer.TVShowTitle')118 season=currentSeason119 episode=currentEpisode120 release=currentRelease121 122 if title=="" or season=="":123 matchDir=re.compile('(.+?)\\.s(.+?)e(.+?)\\.', re.DOTALL).findall(dirName)124 matchFile=re.compile('(.+?)\\.s(.+?)e(.+?)\\.', re.DOTALL).findall(fileName)125 matchTitle=re.compile('(.+?)- s(.+?)e(.+?) ', re.DOTALL).findall(xbmc.getInfoLabel('VideoPlayer.Title').lower())126 if len(matchDir)>0:127 title=matchDir[0][0]128 elif len(matchFile)>0:129 title=matchFile[0][0]130 elif len(matchTitle)>0:131 title=matchTitle[0][0].strip()132 133 title=title.replace("."," ")134 if "(" in title:135 title=title[:title.find("(")].strip()136 137 if title=="" or season=="" or episode=="":138 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+translation(30014)+'!,3000,'+icon+')')139 main()140 else:141 if season[0:1]=="0":142 season=season[1:]143 general=base64.b64decode("QUl6YVN5RGJtNzRTNlZia1VjWmNQeC1HTTFtU1B5N2ZYU0R2Vy1J")144 global ownKey145 if ownKey=="":146 ownKey=general147 searchString='intitle:"[subs] '+title+' - staffel '+season+'|0'+season+'"'148 fullUrl="https://www.googleapis.com/customsearch/v1?key="+ownKey+"&cx=016144106520845837387:lj4yjfpwyna&q="+urllib.quote_plus(searchString)+"&alt=json"149 xbmc.log("SCDE Addon Log - Search: "+title+"#"+season)150 content = getUrl(fullUrl)151 if '"items"' in content:152 content = content[content.find('"items"'):]153 spl=content.split('"kind"')154 finalUrl=""155 for i in range(1,len(spl),1):156 entry=spl[i]157 match=re.compile('"title": "(.+?)"', re.DOTALL).findall(entry)158 title=match[0]159 match=re.compile('"link": "(.+?)"', re.DOTALL).findall(entry)160 url=match[0]161 if "staffel" in title.lower() and "subs:" in title.lower() and "postID=" not in url and "boardID=" not in url:162 finalUrl=url163 break164 if finalUrl=="":165 for i in range(1,len(spl),1):166 entry=spl[i]167 match=re.compile('"title": "(.+?)"', re.DOTALL).findall(entry)168 title=match[0]169 match=re.compile('"link": "(.+?)"', re.DOTALL).findall(entry)170 url=match[0]171 if "staffel" in title.lower() and "postID=" not in url and "boardID=" not in url:172 finalUrl=url173 break174 175 if len(season)==1:176 season="0"+season177 178 if finalUrl!="":179 threadID = finalUrl[finalUrl.find("&threadID=")+10:]180 if "&" in threadID:181 threadID = threadID[:threadID.find("&")]182 content = opener.open("http://www.subcentral.de/index.php?page=Thread&threadID="+threadID).read()183 if 'class="bedankhinweisSC' in content:184 contentThanks=content185 contentThanks=contentThanks[contentThanks.find('class="bedankhinweisSC'):]186 match=re.compile('href="index.php\\?action=Thank(.+?)"', re.DOTALL).findall(contentThanks)187 matchID=re.compile('name="threadID" value="(.+?)"', re.DOTALL).findall(contentThanks)188 dialog = xbmcgui.Dialog()189 nr=dialog.select(title, [translation(30005)+"..."])190 if nr>=0:191 opener.open(mainUrl+"/index.php?action=Thank"+match[0].replace("&","&"))192 content = opener.open(mainUrl+"/index.php?page=Thread&threadID="+matchID[0]).read()193 194 attachments = []195 titles = []196 197 match=re.compile('<title>(.+?)-', re.DOTALL).findall(content)198 tvShowTitle=match[0].replace("[Subs]","").strip()199 200 content = content[content.find("quoteData.set('post-")+1:]201 content = content[:content.find("quoteData.set('post-")]202 contentDE=content203 contentEN=""204 if '<img src="creative/bilder/flags/usa.png"' in content:205 contentDE=content[:content.find('<img src="creative/bilder/flags/usa.png"')]206 contentEN=content[content.find('<img src="creative/bilder/flags/usa.png"'):]207 elif '<img src="creative/bilder/flags/uk.png"' in content:208 contentDE=content[:content.find('<img src="creative/bilder/flags/uk.png"')]209 contentEN=content[content.find('<img src="creative/bilder/flags/uk.png"'):]210 elif 'Englische Untertitel:' in content:211 contentDE=content[:content.find('Englische Untertitel:')]212 contentEN=content[content.find('Englische Untertitel:'):]213 if "page=Attachment&attachmentID=" not in contentDE:214 contentDE=content215 216 if language=="0":217 tempDE=appendSubInfo(tvShowTitle,season,episode,release,contentDE,"DE")218 attachments += tempDE[0]219 titles += tempDE[1]220 if contentEN!="":221 tempEN=appendSubInfo(tvShowTitle,season,episode,release,contentEN,"EN")222 attachments += tempEN[0]223 titles += tempEN[1]224 elif language=="1":225 tempDE=appendSubInfo(tvShowTitle,season,episode,release,contentDE,"DE")226 attachments += tempDE[0]227 titles += tempDE[1]228 elif language=="2" and contentEN!="":229 tempEN=appendSubInfo(tvShowTitle,season,episode,release,contentEN,"EN")230 attachments += tempEN[0]231 titles += tempEN[1]232 233 if len(titles)>0:234 titles, attachments = (list(x) for x in zip(*sorted(zip(titles, attachments))))235 dialog = xbmcgui.Dialog()236 nr=dialog.select(os.path.basename(currentFile), titles)237 if nr>=0:238 subUrl=mainUrl+"/index.php?page=Attachment&attachmentID="+attachments[nr]239 setSubtitle(subUrl)240 elif backNav=="true":241 main()242 else:243 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+translation(30015)+'!,3000,'+icon+')')244 main()245 elif '"totalResults": "0"' in content:246 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+translation(30015)+'!,3000,'+icon+')')247 main()248 else:249 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+translation(30016)+'!,10000,'+icon+')')250 main()251def getEpisodes(entry):252 ep=ep2=""253 match=re.compile('>E(.+?) -', re.DOTALL).findall(entry,0,10)254 match2=re.compile('>(.+?)x(.+?) -', re.DOTALL).findall(entry,0,10)255 match3=re.compile('>(.+?)\\. ', re.DOTALL).findall(entry,0,10)256 match4=re.compile('>(.+?) -', re.DOTALL).findall(entry,0,10)257 match5=re.compile('>(.+?)<', re.DOTALL).findall(entry,0,10)258 if "- komplett<" in entry.lower():259 ep=ep2=" - Komplett"260 else:261 if len(match)>0:262 ep=match[0]263 elif len(match2):264 ep=match2[0][1]265 elif len(match3):266 ep=match3[0]267 elif len(match4):268 ep=match4[0]269 elif len(match5):270 ep=match5[0]271 else:272 ep="00"273 ep2="E"+ep274 return [ep,ep2]275def appendSubInfo(tvShowTitle,season,episode,release,content,lang):276 attachments1 = []277 titles1 = []278 content2=content.replace('<span class=" Stil36 Stil31">','').replace('<span class="Stil37">','')279 match=re.compile('<div align="center"><a href="http://www.subcentral.de/index.php\\?page=Attachment&attachmentID=(.+?)">⪠E(.+?) \\((.+?)\\)</a>', re.DOTALL).findall(content2)280 for attach, ep, rel in match:281 ep2="E"+ep282 if episode==ep:283 check = release==""284 if release!="":285 check = release==rel.lower()286 if check:287 if attach not in attachments1:288 attachments1.append(attach)289 titles1.append(lang+" - "+tvShowTitle+" - S"+season+ep2+" - "+rel.replace("</span>",""))290 if len(attachments1)==0:291 match=re.compile('<div align="center"><a href="http://www.subcentral.de/index.php\\?page=Attachment&attachmentID=(.+?)">⪠E(.+?) \\((.+?)\\)</a>', re.DOTALL).findall(content2)292 for attach, ep, rel in match:293 ep2="E"+ep294 if episode==ep:295 if attach not in attachments1:296 attachments1.append(attach)297 titles1.append(lang+" - "+tvShowTitle+" - S"+season+ep2+" - "+rel.replace("</span>",""))298 if len(attachments1)==0:299 match=re.compile('<div align="center"><a href="http://www.subcentral.de/index.php\\?page=Attachment&attachmentID=(.+?)">⪠E(.+?) \\((.+?)\\)</a>', re.DOTALL).findall(content2)300 for attach, ep, rel in match:301 ep2="E"+ep302 if attach not in attachments1:303 attachments1.append(attach)304 titles1.append(lang+" - "+tvShowTitle+" - S"+season+ep2+" - "+rel.replace("</span>",""))305 attachments2 = []306 titles2 = []307 splitStr = ""308 if 'class="release"' in content:309 splitStr = 'class="release"'310 elif 'class="Stil9"' in content:311 splitStr = 'class="Stil9"'312 if splitStr:313 spl=content.split(splitStr)314 for i in range(1,len(spl),1):315 entry=spl[i].replace("<strong>","").replace("</strong>","").replace('<span style="font-size: 8pt">','')316 temp = getEpisodes(entry)317 ep = temp[0]318 ep2 = temp[1]319 match=re.compile('index.php\\?page=Attachment&attachmentID=(.+?)">(.+?)</a>', re.DOTALL).findall(entry)320 for attach, rel in match:321 if episode==ep:322 check = release==""323 if release!="":324 check = release==rel.lower()325 if check:326 if attach not in attachments2:327 attachments2.append(attach)328 titles2.append(lang+" - "+tvShowTitle+" - S"+season+ep2+" - "+rel.replace("</span>",""))329 if len(attachments2)==0:330 spl=content.split(splitStr)331 for i in range(1,len(spl),1):332 entry=spl[i].replace("<strong>","").replace("</strong>","").replace('<span style="font-size: 8pt">','')333 temp = getEpisodes(entry)334 ep = temp[0]335 ep2 = temp[1]336 match=re.compile('index.php\\?page=Attachment&attachmentID=(.+?)">(.+?)</a>', re.DOTALL).findall(entry)337 for attach, rel in match:338 if episode==ep:339 if attach not in attachments2:340 attachments2.append(attach)341 titles2.append(lang+" - "+tvShowTitle+" - S"+season+ep2+" - "+rel.replace("</span>",""))342 if len(attachments2)==0:343 spl=content.split(splitStr)344 for i in range(1,len(spl),1):345 entry=spl[i].replace("<strong>","").replace("</strong>","").replace('<span style="font-size: 8pt">','')346 temp = getEpisodes(entry)347 ep = temp[0]348 ep2 = temp[1]349 match=re.compile('index.php\\?page=Attachment&attachmentID=(.+?)">(.+?)</a>', re.DOTALL).findall(entry)350 for attach, rel in match:351 if attach not in attachments2:352 attachments2.append(attach)353 titles2.append(lang+" - "+tvShowTitle+" - S"+season+ep2+" - "+rel.replace("</span>",""))354 return [attachments1+attachments2,titles1+titles2]355def showFavourites():356 ids = []357 titles = []358 if os.path.exists(favFile):359 fh = open(favFile, 'r')360 for line in fh:361 id = line[:line.find("#")]362 title = line[line.find("#")+1:]363 title = title[:title.find("#END")]364 ids.append(id)365 titles.append(title)366 fh.close()367 titles, ids = (list(x) for x in zip(*sorted(zip(titles, ids))))368 dialog = xbmcgui.Dialog()369 nr=dialog.select(translation(30001), titles)370 if nr>=0:371 id=ids[nr]372 title=titles[nr]373 showSeries(id)374 elif backNav=="true":375 main()376def showAllSeries():377 content = opener.open(mainUrl+"/index.php").read()378 content = content[content.find('<option value=""> Serien QuickJump </option>')+1:]379 content = content[:content.find('</form>')]380 match=re.compile('<option value="(.+?)">(.+?)</option>', re.DOTALL).findall(content)381 threadIDs = []382 threadNames = []383 for id, title in match:384 threadIDs.append(id)385 threadNames.append(title)386 dialog = xbmcgui.Dialog()387 nr=dialog.select(translation(30002), threadNames)388 if nr>=0:389 id=threadIDs[nr]390 title=threadNames[nr]391 showSeries(id)392 elif backNav=="true":393 main()394def showSeries(seriesID):395 content = opener.open(mainUrl+"/index.php?page=Board&boardID="+seriesID).read()396 match=re.compile('<title>(.+?) -', re.DOTALL).findall(content)397 SeriesTitle=match[0]398 content = content[content.find("<h3>Wichtige Themen</h3>"):]399 content = content[:content.find('</table>')]400 spl=content.split('<p id="threadTitle')401 threadIDs = []402 threadNames = []403 season=currentSeason404 if season[0:1]=="0":405 season=season[1:]406 for i in range(1,len(spl),1):407 entry=spl[i]408 match=re.compile('<a href="index.php\\?page=Thread&threadID=(.+?)">(.+?)</a>', re.DOTALL).findall(entry)409 if ("staffel "+season in match[0][1].lower() or "staffel 0"+season in match[0][1].lower()) and "subs" in match[0][1].lower():410 threadIDs.append(match[0][0])411 threadNames.append(cleanTitle(match[0][1]))412 if len(threadIDs)==0:413 for i in range(1,len(spl),1):414 entry=spl[i]415 match=re.compile('<a href="index.php\\?page=Thread&threadID=(.+?)">(.+?)</a>', re.DOTALL).findall(entry)416 if "subs" in match[0][1].lower():417 threadIDs.append(match[0][0])418 threadNames.append(cleanTitle(match[0][1]))419 threadNames, threadIDs = (list(x) for x in zip(*sorted(zip(threadNames, threadIDs))))420 content=""421 if os.path.exists(favFile):422 fh = open(favFile, 'r')423 content=fh.read()424 fh.close()425 if seriesID+"#" not in content:426 threadNames.append(translation(30003))427 else:428 threadNames.append(translation(30004))429 dialog = xbmcgui.Dialog()430 nr=dialog.select(os.path.basename(currentFile), threadNames)431 if nr>=0:432 if nr==len(threadNames)-1:433 if threadNames[nr]==translation(30003):434 addToFavourites(seriesID,SeriesTitle)435 elif threadNames[nr]==translation(30004):436 removeFromFavourites(seriesID,SeriesTitle)437 showSeries(seriesID)438 else:439 id=threadIDs[nr]440 showSubtitles(seriesID,id)441 elif backNav=="true":442 if mainType=="all":443 showAllSeries()444 elif mainType=="fav":445 showFavourites()446def showSubtitles(seriesID,id):447 content = opener.open(mainUrl+"/index.php?page=Thread&threadID="+id).read()448 match=re.compile('<title>(.+?)</title>', re.DOTALL).findall(content)449 title=match[0]450 if 'class="bedankhinweisSC' in content:451 contentThanks=content452 contentThanks=contentThanks[contentThanks.find('class="bedankhinweisSC'):]453 match=re.compile('href="index.php\\?action=Thank(.+?)"', re.DOTALL).findall(contentThanks)454 matchID=re.compile('name="threadID" value="(.+?)"', re.DOTALL).findall(contentThanks)455 dialog = xbmcgui.Dialog()456 nr=dialog.select(title, [translation(30005)+"..."])457 if nr>=0:458 opener.open(mainUrl+"/index.php?action=Thank"+match[0].replace("&","&"))459 content = opener.open(mainUrl+"/index.php?page=Thread&threadID="+id).read()460 elif backNav=="true":461 showSeries(seriesID)462 attachments = []463 titles = []464 465 match=re.compile('<title>(.+?)-', re.DOTALL).findall(content)466 tvShowTitle=match[0].replace("[Subs]","").strip()467 match=re.compile('Staffel (.+?) ', re.DOTALL).findall(content)468 season=match[0]469 if len(season)==1:470 season="0"+season471 472 content = content[content.find("quoteData.set('post-")+1:]473 content = content[:content.find("quoteData.set('post-")]474 contentDE=content475 contentEN=""476 if '<img src="creative/bilder/flags/usa.png"' in content:477 contentDE=content[:content.find('<img src="creative/bilder/flags/usa.png"')]478 contentEN=content[content.find('<img src="creative/bilder/flags/usa.png"'):]479 elif '<img src="creative/bilder/flags/uk.png"' in content:480 contentDE=content[:content.find('<img src="creative/bilder/flags/uk.png"')]481 contentEN=content[content.find('<img src="creative/bilder/flags/uk.png"'):]482 elif 'Englische Untertitel:' in content:483 contentDE=content[:content.find('Englische Untertitel:')]484 contentEN=content[content.find('Englische Untertitel:'):]485 if "page=Attachment&attachmentID=" not in contentDE:486 contentDE=content487 488 if language=="0":489 tempDE=appendSubInfo(tvShowTitle,season,currentEpisode,currentRelease,contentDE,"DE")490 attachments += tempDE[0]491 titles += tempDE[1]492 if contentEN!="":493 tempEN=appendSubInfo(tvShowTitle,season,currentEpisode,currentRelease,contentEN,"EN")494 attachments += tempEN[0]495 titles += tempEN[1]496 elif language=="1":497 tempDE=appendSubInfo(tvShowTitle,season,currentEpisode,currentRelease,contentDE,"DE")498 attachments += tempDE[0]499 titles += tempDE[1]500 elif language=="2" and contentEN!="":501 tempEN=appendSubInfo(tvShowTitle,season,currentEpisode,currentRelease,contentEN,"EN")502 attachments += tempEN[0]503 titles += tempEN[1]504 505 if len(titles)>0:506 titles, attachments = (list(x) for x in zip(*sorted(zip(titles, attachments))))507 dialog = xbmcgui.Dialog()508 nr=dialog.select(os.path.basename(currentFile), titles)509 if nr>=0:510 subUrl=mainUrl+"/index.php?page=Attachment&attachmentID="+attachments[nr]511 setSubtitle(subUrl)512 elif backNav=="true":513 showSeries(seriesID)514def setSubtitle(subUrl):515 clearSubTempDir()516 rarContent = opener.open(subUrl).read()517 if rarContent.startswith("Rar"):518 ext="rar"519 else:520 ext="zip"521 global rarFile522 rarFile=rarFile+ext523 fh = open(rarFile, 'wb')524 fh.write(rarContent)525 fh.close()526 xbmc.executebuiltin("XBMC.Extract("+rarFile+", "+subTempDir+")")527 xbmc.sleep(1000)528 files = os.listdir(subTempDir)529 tempFile=""530 if len(files)>1:531 dialog = xbmcgui.Dialog()532 nr=dialog.select(currentTitle, files)533 if nr>=0:534 tempFile = xbmc.translatePath(subTempDir+"/"+files[nr])535 else:536 clearSubTempDir()537 if backNav=="true":538 main()539 elif len(files)!=0:540 tempFile = xbmc.translatePath(subTempDir+"/"+files[0])541 else:542 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+translation(30017)+'!,3000,'+icon+')')543 if pause=="true" and xbmc.Player().isPlayingVideo():544 xbmc.Player().pause()545 if tempFile!="":546 shutil.copy2(tempFile, subFile)547 if saveSub=="true" and "http://" not in currentFile and "plugin://" not in currentFile:548 try:549 extLength = len(currentFile.split(".")[-1])550 archiveFile = currentFile[:-extLength]+"srt"551 xbmcvfs.copy(tempFile, archiveFile)552 global subFile553 subFile = archiveFile554 except:555 pass556 clearSubTempDir()557 xbmc.Player().setSubtitles(subFile)558 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+translation(30012)+'!,2000,'+icon+')')559 if pause=="true" and xbmc.Player().isPlayingVideo():560 xbmc.Player().pause()561def clearSubTempDir():562 files = os.listdir(subTempDir)563 for file in files:564 try:565 os.remove(xbmc.translatePath(subTempDir+"/"+file))566 except:567 pass568def addToFavourites(seriesID,title):569 entry=seriesID+"#"+title+"#END"570 if os.path.exists(favFile):571 fh = open(favFile, 'r')572 content=fh.read()573 fh.close()574 if entry not in content:575 fh=open(favFile, 'a')576 fh.write(entry+"\n")577 fh.close()578 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+title+': '+translation(30008)+',3000,'+icon+')')579 else:580 fh=open(favFile, 'a')581 fh.write(entry+"\n")582 fh.close()583def removeFromFavourites(seriesID,title):584 newContent=""585 fh = open(favFile, 'r')586 for line in fh:587 if seriesID+"#" not in line:588 newContent+=line589 fh.close()590 fh=open(favFile, 'w')591 fh.write(newContent)592 fh.close()593 xbmc.executebuiltin('XBMC.Notification(SubCentral.de:,'+title+': '+translation(30009)+',3000,'+icon+')')594def getUrl(url):595 req = urllib2.Request(url)596 req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; rv:23.0) Gecko/20100101 Firefox/23.0')597 response = urllib2.urlopen(req)598 content=response.read()599 response.close()600 return content601def cleanTitle(title):602 title=title.replace("<","<").replace(">",">").replace("&","&").replace("'","'").replace(""","\"").replace("ß","Ã").replace("–","-")603 title=title.replace("Ä","Ã").replace("Ü","Ã").replace("Ö","Ã").replace("ä","ä").replace("ü","ü").replace("ö","ö")604 title=title.strip()605 return title...
test_message.py
Source:test_message.py
...367 allparts = list(m.walk())368 parts = [allparts[n] for n in parts]369 self.assertEqual(list(m.iter_parts()), parts)370 class _TestContentManager:371 def get_content(self, msg, *args, **kw):372 return msg, args, kw373 def set_content(self, msg, *args, **kw):374 self.msg = msg375 self.args = args376 self.kw = kw377 def test_get_content_with_cm(self):378 m = self._str_msg('')379 cm = self._TestContentManager()380 self.assertEqual(m.get_content(content_manager=cm), (m, (), {}))381 msg, args, kw = m.get_content('foo', content_manager=cm, bar=1, k=2)382 self.assertEqual(msg, m)383 self.assertEqual(args, ('foo',))384 self.assertEqual(kw, dict(bar=1, k=2))385 def test_get_content_default_cm_comes_from_policy(self):386 p = policy.default.clone(content_manager=self._TestContentManager())387 m = self._str_msg('', policy=p)388 self.assertEqual(m.get_content(), (m, (), {}))389 msg, args, kw = m.get_content('foo', bar=1, k=2)390 self.assertEqual(msg, m)391 self.assertEqual(args, ('foo',))392 self.assertEqual(kw, dict(bar=1, k=2))393 def test_set_content_with_cm(self):394 m = self._str_msg('')395 cm = self._TestContentManager()396 m.set_content(content_manager=cm)397 self.assertEqual(cm.msg, m)398 self.assertEqual(cm.args, ())399 self.assertEqual(cm.kw, {})400 m.set_content('foo', content_manager=cm, bar=1, k=2)401 self.assertEqual(cm.msg, m)402 self.assertEqual(cm.args, ('foo',))403 self.assertEqual(cm.kw, dict(bar=1, k=2))404 def test_set_content_default_cm_comes_from_policy(self):405 cm = self._TestContentManager()406 p = policy.default.clone(content_manager=cm)407 m = self._str_msg('', policy=p)408 m.set_content()409 self.assertEqual(cm.msg, m)410 self.assertEqual(cm.args, ())411 self.assertEqual(cm.kw, {})412 m.set_content('foo', bar=1, k=2)413 self.assertEqual(cm.msg, m)414 self.assertEqual(cm.args, ('foo',))415 self.assertEqual(cm.kw, dict(bar=1, k=2))416 # outcome is whether xxx_method should raise ValueError error when called417 # on multipart/subtype. Blank outcome means it depends on xxx (add418 # succeeds, make raises). Note: 'none' means there are content-type419 # headers but payload is None...this happening in practice would be very420 # unusual, so treating it as if there were content seems reasonable.421 # method subtype outcome422 subtype_params = (423 ('related', 'no_content', 'succeeds'),424 ('related', 'none', 'succeeds'),425 ('related', 'plain', 'succeeds'),426 ('related', 'related', ''),427 ('related', 'alternative', 'raises'),428 ('related', 'mixed', 'raises'),429 ('alternative', 'no_content', 'succeeds'),430 ('alternative', 'none', 'succeeds'),431 ('alternative', 'plain', 'succeeds'),432 ('alternative', 'related', 'succeeds'),433 ('alternative', 'alternative', ''),434 ('alternative', 'mixed', 'raises'),435 ('mixed', 'no_content', 'succeeds'),436 ('mixed', 'none', 'succeeds'),437 ('mixed', 'plain', 'succeeds'),438 ('mixed', 'related', 'succeeds'),439 ('mixed', 'alternative', 'succeeds'),440 ('mixed', 'mixed', ''),441 )442 def _make_subtype_test_message(self, subtype):443 m = self.message()444 payload = None445 msg_headers = [446 ('To', 'foo@bar.com'),447 ('From', 'bar@foo.com'),448 ]449 if subtype != 'no_content':450 ('content-shadow', 'Logrus'),451 msg_headers.append(('X-Random-Header', 'Corwin'))452 if subtype == 'text':453 payload = ''454 msg_headers.append(('Content-Type', 'text/plain'))455 m.set_payload('')456 elif subtype != 'no_content':457 payload = []458 msg_headers.append(('Content-Type', 'multipart/' + subtype))459 msg_headers.append(('X-Trump', 'Random'))460 m.set_payload(payload)461 for name, value in msg_headers:462 m[name] = value463 return m, msg_headers, payload464 def _check_disallowed_subtype_raises(self, m, method_name, subtype, method):465 with self.assertRaises(ValueError) as ar:466 getattr(m, method)()467 exc_text = str(ar.exception)468 self.assertIn(subtype, exc_text)469 self.assertIn(method_name, exc_text)470 def _check_make_multipart(self, m, msg_headers, payload):471 count = 0472 for name, value in msg_headers:473 if not name.lower().startswith('content-'):474 self.assertEqual(m[name], value)475 count += 1476 self.assertEqual(len(m), count+1) # +1 for new Content-Type477 part = next(m.iter_parts())478 count = 0479 for name, value in msg_headers:480 if name.lower().startswith('content-'):481 self.assertEqual(part[name], value)482 count += 1483 self.assertEqual(len(part), count)484 self.assertEqual(part.get_payload(), payload)485 def subtype_as_make(self, method, subtype, outcome):486 m, msg_headers, payload = self._make_subtype_test_message(subtype)487 make_method = 'make_' + method488 if outcome in ('', 'raises'):489 self._check_disallowed_subtype_raises(m, method, subtype, make_method)490 return491 getattr(m, make_method)()492 self.assertEqual(m.get_content_maintype(), 'multipart')493 self.assertEqual(m.get_content_subtype(), method)494 if subtype == 'no_content':495 self.assertEqual(len(m.get_payload()), 0)496 self.assertEqual(m.items(),497 msg_headers + [('Content-Type',498 'multipart/'+method)])499 else:500 self.assertEqual(len(m.get_payload()), 1)501 self._check_make_multipart(m, msg_headers, payload)502 def subtype_as_make_with_boundary(self, method, subtype, outcome):503 # Doing all variation is a bit of overkill...504 m = self.message()505 if outcome in ('', 'raises'):506 m['Content-Type'] = 'multipart/' + subtype507 with self.assertRaises(ValueError) as cm:508 getattr(m, 'make_' + method)()509 return510 if subtype == 'plain':511 m['Content-Type'] = 'text/plain'512 elif subtype != 'no_content':513 m['Content-Type'] = 'multipart/' + subtype514 getattr(m, 'make_' + method)(boundary="abc")515 self.assertTrue(m.is_multipart())516 self.assertEqual(m.get_boundary(), 'abc')517 def test_policy_on_part_made_by_make_comes_from_message(self):518 for method in ('make_related', 'make_alternative', 'make_mixed'):519 m = self.message(policy=self.policy.clone(content_manager='foo'))520 m['Content-Type'] = 'text/plain'521 getattr(m, method)()522 self.assertEqual(m.get_payload(0).policy.content_manager, 'foo')523 class _TestSetContentManager:524 def set_content(self, msg, content, *args, **kw):525 msg['Content-Type'] = 'text/plain'526 msg.set_payload(content)527 def subtype_as_add(self, method, subtype, outcome):528 m, msg_headers, payload = self._make_subtype_test_message(subtype)529 cm = self._TestSetContentManager()530 add_method = 'add_attachment' if method=='mixed' else 'add_' + method531 if outcome == 'raises':532 self._check_disallowed_subtype_raises(m, method, subtype, add_method)533 return534 getattr(m, add_method)('test', content_manager=cm)535 self.assertEqual(m.get_content_maintype(), 'multipart')536 self.assertEqual(m.get_content_subtype(), method)537 if method == subtype or subtype == 'no_content':538 self.assertEqual(len(m.get_payload()), 1)539 for name, value in msg_headers:540 self.assertEqual(m[name], value)541 part = m.get_payload()[0]542 else:543 self.assertEqual(len(m.get_payload()), 2)544 self._check_make_multipart(m, msg_headers, payload)545 part = m.get_payload()[1]546 self.assertEqual(part.get_content_type(), 'text/plain')547 self.assertEqual(part.get_payload(), 'test')548 if method=='mixed':549 self.assertEqual(part['Content-Disposition'], 'attachment')550 elif method=='related':551 self.assertEqual(part['Content-Disposition'], 'inline')552 else:553 # Otherwise we don't guess.554 self.assertIsNone(part['Content-Disposition'])555 class _TestSetRaisingContentManager:556 def set_content(self, msg, content, *args, **kw):557 raise Exception('test')558 def test_default_content_manager_for_add_comes_from_policy(self):559 cm = self._TestSetRaisingContentManager()560 m = self.message(policy=self.policy.clone(content_manager=cm))561 for method in ('add_related', 'add_alternative', 'add_attachment'):562 with self.assertRaises(Exception) as ar:563 getattr(m, method)('')564 self.assertEqual(str(ar.exception), 'test')565 def message_as_clear(self, body_parts, attachments, parts, msg):566 m = self._str_msg(msg)567 m.clear()568 self.assertEqual(len(m), 0)569 self.assertEqual(list(m.items()), [])570 self.assertIsNone(m.get_payload())571 self.assertEqual(list(m.iter_parts()), [])572 def message_as_clear_content(self, body_parts, attachments, parts, msg):573 m = self._str_msg(msg)574 expected_headers = [h for h in m.keys()575 if not h.lower().startswith('content-')]576 m.clear_content()577 self.assertEqual(list(m.keys()), expected_headers)578 self.assertIsNone(m.get_payload())579 self.assertEqual(list(m.iter_parts()), [])580 def test_is_attachment(self):581 m = self._make_message()582 self.assertFalse(m.is_attachment)583 m['Content-Disposition'] = 'inline'584 self.assertFalse(m.is_attachment)585 m.replace_header('Content-Disposition', 'attachment')586 self.assertTrue(m.is_attachment)587 m.replace_header('Content-Disposition', 'AtTachMent')588 self.assertTrue(m.is_attachment)589class TestEmailMessage(TestEmailMessageBase, TestEmailBase):590 message = EmailMessage591 def test_set_content_adds_MIME_Version(self):592 m = self._str_msg('')593 cm = self._TestContentManager()594 self.assertNotIn('MIME-Version', m)595 m.set_content(content_manager=cm)596 self.assertEqual(m['MIME-Version'], '1.0')597 class _MIME_Version_adding_CM:598 def set_content(self, msg, *args, **kw):599 msg['MIME-Version'] = '1.0'600 def test_set_content_does_not_duplicate_MIME_Version(self):601 m = self._str_msg('')602 cm = self._MIME_Version_adding_CM()603 self.assertNotIn('MIME-Version', m)604 m.set_content(content_manager=cm)605 self.assertEqual(m['MIME-Version'], '1.0')606class TestMIMEPart(TestEmailMessageBase, TestEmailBase):607 # Doing the full test run here may seem a bit redundant, since the two608 # classes are almost identical. But what if they drift apart? So we do609 # the full tests so that any future drift doesn't introduce bugs.610 message = MIMEPart611 def test_set_content_does_not_add_MIME_Version(self):612 m = self._str_msg('')613 cm = self._TestContentManager()614 self.assertNotIn('MIME-Version', m)615 m.set_content(content_manager=cm)616 self.assertNotIn('MIME-Version', m)617if __name__ == '__main__':...
basecontenteditor.py
Source:basecontenteditor.py
1from zoundry.appframework.global_services import getLoggerService2from zoundry.appframework.ui.events.editcontrolevents import IZEditControlEvents3from zoundry.appframework.ui.events.toolbarevents import ZEVT_TOOLBAR_RESIZE4from zoundry.appframework.ui.util.colorutil import getDefaultDialogBackgroundColor5from zoundry.appframework.ui.widgets.controls.advanced.editcontrol import IZRichTextEditControl6from zoundry.appframework.ui.widgets.controls.common.acceleratortable import ZAcceleratorEntry7from zoundry.appframework.ui.widgets.controls.common.acceleratortable import ZAcceleratorTable8from zoundry.appframework.ui.widgets.controls.common.menu.menu import ZMenu9from zoundry.appframework.ui.widgets.controls.common.menu.menumodel import ZModelBasedMenuContentProvider10from zoundry.appframework.ui.widgets.controls.common.menu.menumodel import ZModelBasedMenuEventHandler11from zoundry.appframework.ui.widgets.controls.common.toolbar.toolbar import ZToolBar12from zoundry.appframework.ui.widgets.controls.common.toolbar.toolbarmodel import ZModelBasedToolBarContentProvider13from zoundry.appframework.ui.widgets.controls.common.toolbar.toolbarmodel import ZModelBasedToolBarEventHandler14from zoundry.appframework.ui.widgets.dialogs.standarddialogs import ZShowNotYetImplementedMessage15from zoundry.base.exceptions import ZAbstractMethodCalledException16from zoundry.blogapp.constants import IZBlogAppAcceleratorIds17from zoundry.blogapp.services.datastore.documentimpl import ZXhtmlContent18from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZBlogPostEditorToolBarActionContext19from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZBlogPostInsertImageAction20from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZBlogPostInsertImgTagAction21from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZBlogPostInsertLinkAction22from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZBlogPostSpellCheckAction23from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZBlogRichTextFormatAction24from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZFocusOnTagwordsAction25from zoundry.blogapp.ui.actions.blogeditor.blogeditoractions import ZFocusOnTitleAction26from zoundry.blogapp.ui.editors.blogeditorctrls.blogposteditcontrol import IZBlogPostEditControl27from zoundry.blogapp.ui.editors.blogeditorctrls.metadata import ZBlogPostMetaDataWidget28from zoundry.blogapp.ui.menus.blogeditor.blogcontenteditorcontextmenumodel import ZBlogContentEditorContextMenuModel29from zoundry.blogapp.ui.menus.blogeditor.blogeditortoolbarmodel import ZBlogContentEditorToolbarModel30import wx3132# ------------------------------------------------------------------------------33# Interface that blog content editor controls must implement.34# ------------------------------------------------------------------------------35class IZBlogContentEditorControl:3637 def refreshUI(self):38 u"""refreshUI() -> void39 Updates the UI as well editor content based on the model data40 """ #$NON-NLS-1$41 # end refreshUI()4243 def updateModel(self):44 u"""updateModel() -> void45 Updates the model data (title, xhtml document etc) from the UI controls.46 """ #$NON-NLS-1$47 # end updateModel()4849 def modelSaved(self):50 u"""modelSaved() -> void51 Invoked by the editor framework when the model data has been persisted.52 """ #$NON-NLS-1$53 # end modelSaved()5455# end IZBlogContentEditorControl565758# ------------------------------------------------------------------------------59# Implements the accelerator table for the blog post content editor.60# ------------------------------------------------------------------------------61class ZBlogPostContentEditorAcceleratorTable(ZAcceleratorTable):6263 def __init__(self, context):64 self.context = context65 ZAcceleratorTable.__init__(self, IZBlogAppAcceleratorIds.ZID_BLOG_POST_EDITOR_CONTENT_ACCEL)66 # end __init__()6768 def _createActionContext(self):69 return self.context70 # end _createActionContext()7172 def _loadAdditionalEntries(self):73 return [74 # Bold, Italic, Underline, Strike75 ZAcceleratorEntry(wx.ACCEL_CTRL, ord(u'B'), ZBlogRichTextFormatAction(IZRichTextEditControl.ZCAPABILITY_BOLD)), #$NON-NLS-1$76 ZAcceleratorEntry(wx.ACCEL_CTRL, ord(u'I'), ZBlogRichTextFormatAction(IZRichTextEditControl.ZCAPABILITY_ITALIC)), #$NON-NLS-1$77 ZAcceleratorEntry(wx.ACCEL_CTRL, ord(u'U'), ZBlogRichTextFormatAction(IZRichTextEditControl.ZCAPABILITY_UNDERLINE)), #$NON-NLS-1$78 # create link79 ZAcceleratorEntry(wx.ACCEL_CTRL, ord(u'L'), ZBlogPostInsertLinkAction()), #$NON-NLS-1$80 ZAcceleratorEntry(wx.ACCEL_CTRL, ord(u'K'), ZBlogPostInsertLinkAction()), #$NON-NLS-1$81 # insert image82 ZAcceleratorEntry(wx.ACCEL_CTRL, ord(u'M'), ZBlogPostInsertImageAction()), #$NON-NLS-1$,83 ZAcceleratorEntry(wx.ACCEL_CTRL + wx.ACCEL_SHIFT, ord(u'M'), ZBlogPostInsertImgTagAction()), #$NON-NLS-1$,84 # spell check85 ZAcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_F7, ZBlogPostSpellCheckAction()),86 # Go to Title87 ZAcceleratorEntry(wx.ACCEL_ALT, ord(u'T'), ZFocusOnTitleAction()), #$NON-NLS-1$88 # Go to Tagwords89 ZAcceleratorEntry(wx.ACCEL_SHIFT, wx.WXK_TAB, ZFocusOnTagwordsAction()), #$NON-NLS-1$90 ]91 # end _loadAdditionalEntries()9293# end ZBlogPostContentEditorAcceleratorTable949596# ------------------------------------------------------------------------------97# This is the base class of the blog post content area editor.98# Concrete implementations are WsyiWyg and XhtmlText content editors99# ------------------------------------------------------------------------------100class ZBlogPostContentEditorBase(wx.Panel, IZBlogContentEditorControl):101102 def __init__(self, parentWindow, zblogPostEditor, zblogPostEditorModel):103 self.zblogPostEditor = zblogPostEditor104 self.zblogPostEditorModel = zblogPostEditorModel105 self.editor = None106 self.metaDataWidget = None107 self.contentEditCtrl = None108 # dirty: internally keep track if the editor (mshtml/scintilla) content has been modified.109 self.contentModified = False110 wx.Panel.__init__(self, parentWindow, wx.ID_ANY)111 self._createWidgets()112 self._layoutWidgets()113 self._bindWidgetEvents()114 if self._getContentEditControl():115 self._bindContentEditCtrlEvents()116 # end __init__()117118 def focusOnContent(self):119 self.contentEditCtrl.SetFocus()120 # end focusOnContent()121122 def getMetaDataWidget(self):123 return self.metaDataWidget124 # end getMetaDataWidget()125126 def _getModel(self):127 return self.zblogPostEditorModel128 # end _getModel129130 def _getContentEditControl(self):131 return self.contentEditCtrl132 # end _getContentEditControl133134 def _createWidgets(self):135 self.SetBackgroundColour(wx.Colour(255, 255, 255))136 self.metaDataWidget = ZBlogPostMetaDataWidget(self, self._getModel().getMetaDataModel() )137 self.metaDataWidget.SetBackgroundColour(getDefaultDialogBackgroundColor())138 self.contentEditCtrl = self._createContentEditCtrl(self)139 # Note: toolbar must be created only after the contentEditCtrl has been created (so that edit control capabilities can be determined)140 self.toolBar = self._createToolBar()141 self.tbStaticLine = wx.StaticLine(self, wx.ID_ANY)142143 self.acceleratorTable = ZBlogPostContentEditorAcceleratorTable(ZBlogPostEditorToolBarActionContext(self))144 self.contentEditCtrl.SetAcceleratorTable(self.acceleratorTable)145 # end _createWidgets()146147 def _createContentEditCtrl(self, parent):148 # sublcasses must create concrete IZBlogPostEditControl impl.149 raise ZAbstractMethodCalledException(self.__class__.__name__, u"_createContentEditCtrl") #$NON-NLS-1$150 # end _createContentEditCtrl()151152 def _layoutWidgets(self):153 self.sizer = wx.BoxSizer(wx.VERTICAL)154 self.sizer.Add(self.metaDataWidget, 0, wx.EXPAND)155 self.sizer.Add(self.toolBar, 0, wx.EXPAND)156 self.sizer.Add(self.tbStaticLine, 0, wx.EXPAND)157 self.sizer.Add(self.contentEditCtrl, 1, wx.EXPAND)158 self.SetSizer(self.sizer)159 self.SetAutoLayout(True)160 self.Layout()161 # end _layoutWidgets()162163 def _bindWidgetEvents(self):164 self.Bind(ZEVT_TOOLBAR_RESIZE, self.onToolBarResize, self.toolBar)165 wx.EVT_NAVIGATION_KEY(self.metaDataWidget, self.onMetaDataKeyboardNavigation)166 self.acceleratorTable.bindTo(self)167 # end _bindWidgetEvents()168169 def _bindContentEditCtrlEvents(self):170 self.Bind(IZEditControlEvents.ZEVT_UPDATE_UI, self.onUpdateUI, self._getContentEditControl())171 self.Bind(IZEditControlEvents.ZEVT_SELECTION_CHANGE, self.onSelectionChange, self._getContentEditControl())172 self.Bind(IZEditControlEvents.ZEVT_CONTEXT_MENU, self.onContextMenu, self._getContentEditControl())173 self.Bind(IZEditControlEvents.ZEVT_CONTENT_MODIFIED, self.onContentModified, self._getContentEditControl())174 # end _bindContentEditCtrlEvents()175176 def _createToolBar(self):177 self.toolBarModel = self._createToolBarModel()178 self.toolBarContext = ZBlogPostEditorToolBarActionContext(self)179 contentProvider = ZModelBasedToolBarContentProvider(self.toolBarModel, self.toolBarContext)180 eventHandler = ZModelBasedToolBarEventHandler(self.toolBarModel, self.toolBarContext)181 return ZToolBar(contentProvider, eventHandler, self)182 # end _createToolBar()183184 def _createToolBarModel(self):185 toolbarModel = ZBlogContentEditorToolbarModel()186 return toolbarModel187 # end _createToolBarModel()188189 def _isContentModified(self):190 return self.contentModified191 #end _isContentModified()192193 def _setContentModified(self, modified):194 self.contentModified = modified195196 def onUpdateUI(self, event): #@UnusedVariable197 self.zblogPostEditor._fireUpdateMenu() 198 self.toolBar.refresh()199 self._updateCaretPostionUI()200 # end onUIUpdate()201 202 def _updateCaretPostionUI(self):203 (row, col) = self._getContentEditControl().getCaretPosition()204 text = u"" #$NON-NLS-1$205 if row != -1 and col != -1:206 text = u"%d : %d" % (row, col) #$NON-NLS-1$207 self.zblogPostEditor.statusBarModel.setPaneText(u"rowcol", text) #$NON-NLS-1$208 self.zblogPostEditor._fireStatusBarChangedEvent()209 # end _updateCaretPostionUI()210211 def onContentModified(self, event): #@UnusedVariable212 # This is the event handler for mshtml/stc content modified/dirty indicator.213 # Notify the blog post editor just one time214 if not self._isContentModified():215 self.zblogPostEditor.setDirty(True)216 self._setContentModified(True)217 # end onContentModified()218219 def onSelectionChange(self, event): #@UnusedVariable220 pass221 # end onSelectionChange()222223 def onContextMenu(self, event):224 linkCtx = self.getLinkContext()225 imageCtx = self.getImageContext()226 tableCtx = self.getTableContext()227 removeExtMarker = False228 if self.hasCapability(IZBlogPostEditControl.ZCAPABILITY_EXTENDED_ENTRY_MARKER) \229 and self._getContentEditControl().canRemoveExtendedEntryMarker():230 removeExtMarker = True231232 menuModel = ZBlogContentEditorContextMenuModel()233 menuModel.initialize(linkCtx, imageCtx, tableCtx, removeExtMarker)234235 menuContext = self.zblogPostEditor.getMenuActionContext()236 contentProvider = ZModelBasedMenuContentProvider(menuModel, menuContext)237 eventHandler = ZModelBasedMenuEventHandler(menuModel, menuContext)238 menu = ZMenu(event.getParentWindow(), menuModel.getRootNode(), contentProvider, eventHandler)239 try:240 event.getParentWindow().PopupMenu(menu, event.getXYPoint())241 except Exception, e:242 getLoggerService().exception(e)243 menu.Destroy()244 # end onContextMenu()245246 def refreshUI(self):247 document = self.zblogPostEditorModel.getDocument()248 # refresh title, tags, blog data etc.249 self.metaDataWidget.refreshUI()250 # get xhtml content and set it in the edit control.251 if document.getContent() is not None:252 xhtmlDoc = document.getContent().getXhtmlDocument()253 self._getContentEditControl().setXhtmlDocument(xhtmlDoc)254 # end refreshUI()255256 def modelSaved(self):257 # model was saved to data store.258 # Clear dirty flag so that onContentModified() handler can set the flag in the model259 self._setContentModified(False)260 # Clear flags (such as 'content modified') in the content editor (eg. ZMSHTMLBlogPostEditControl via ZBlogPostWysiwygContentEditor)261 self._getContentEditControl().clearState()262 # Refresh widget UI.263 self.metaDataWidget.refreshUI()264 # end modelSaved()265266 def updateModel(self):267 document = self.zblogPostEditorModel.getDocument()268 # Flush title, tags, blog meta data etc. from UI controls to zmetadata model.269 self.metaDataWidget.updateModel()270 # Next copy title, tags etc. from meta data model to the document.271 self.zblogPostEditorModel.getMetaDataModel().updateDocument(document)272273 # Finally, get the Xhtml content from the editor and set it in the document274 xhtmlDoc = self._getContentEditControl().getXhtmlDocument()275 xhtmlContent = ZXhtmlContent()276 xhtmlContent.setXhtmlDocument(xhtmlDoc)277 document.setContent(xhtmlContent)278 # end updateModel()279280 def onTool(self, ctx): #@UnusedVariable281 ZShowNotYetImplementedMessage(self)282 # end onTool()283284 def onToolBarResize(self, event):285 self.Layout()286 event.Skip()287 # end onToolBarResize()288289 # This is a bit hack-y - when tabbing from the tagwords text control, in290 # the forward direction, the focus does not get properly set to the291 # content editor. I'm not really sure where it goes, actually. This292 # method will listen for keyboard nav events in the meta data widget and293 # re-route a forward direction Tab event so that it sets the focus294 # explicitly on the content editor.295 def onMetaDataKeyboardNavigation(self, event):296 focusWidget = self.metaDataWidget.FindFocus()297 if event.GetDirection() and event.IsFromTab() and focusWidget == self.metaDataWidget.tagwordsText:298 self.focusOnContent()299 else:300 event.Skip()301 # end onMetaDataKeyboardNavigation()302303 def hasCapability(self, capabilityId):304 return self._getContentEditControl().getCapabilities().hasCapability(capabilityId)305 # end hasCapability()306307 def canCut(self):308 return self._getContentEditControl().canCut()309 # end canCut()310311 def cut(self):312 self._getContentEditControl().cut()313 # end cut()314315 def canCopy(self):316 return self._getContentEditControl().canCopy()317 # end canCopy()318319 def copy(self):320 self._getContentEditControl().copy()321 # end copy()322323 def canPaste(self, xhtmlFormat):324 if xhtmlFormat:325 return self._getContentEditControl().canPasteXhtml()326 else:327 return self._getContentEditControl().canPaste()328 # end canPaste()329330 def paste(self, xhtmlFormat):331 if xhtmlFormat:332 self._getContentEditControl().pasteXhtml()333 else:334 self._getContentEditControl().paste()335 # end paste()336337 def canInsertXhtml(self):338 return self._getContentEditControl().canInsertXhtml()339 # end canInsertXhtml340341 def insertXhtml(self, xhtmlString): #@UnusedVariable342 self._getContentEditControl().insertXhtml(xhtmlString)343 # end insertXhtml344345 def canSelectAll(self):346 return self._getContentEditControl().canSelectAll()347 # end canSelectAll()348349 def selectAll(self):350 self._getContentEditControl().selectAll()351 # end selectAll()352353 def canUndo(self):354 return self._getContentEditControl().canUndo()355 # end canUndo()356357 def undo(self):358 self._getContentEditControl().undo()359 # end undo()360361 def canRedo(self):362 return self._getContentEditControl().canRedo()363 # end canRedo()364365 def redo(self):366 self._getContentEditControl().redo()367 # end redo()368369 # ---------------------------------------------370 # RichTextEdit formatting commands. Eg. Bold, Italic.371 # ---------------------------------------------372373 def isFormattingEnabled(self, capabilityId):374 return self._getContentEditControl().isFormattingEnabled(capabilityId)375 # end isFormattingEnabled()376377 def getFormattingState(self, capabilityId):378 return self._getContentEditControl().getFormattingState(capabilityId)379 # end getFormattingState()380381 def applyFormatting(self, capabilityId, customData):382 self._getContentEditControl().applyFormatting(capabilityId, customData)383 # end applyFormatting()384385 def getLinkContext(self):386 u"""getLinkContext() -> IZXHTMLEditControlLinkContext387 Returns link creation and edit context if available or None otherwise.""" #$NON-NLS-1$388 return self._getContentEditControl().getLinkContext()389 # end getLinkContext390391 def getImageContext(self):392 u"""getImageContext() -> IZXHTMLEditControlImageContext393 Returns image creation and edit context if available or None otherwise.""" #$NON-NLS-1$394 return self._getContentEditControl().getImageContext()395 # end getImageContext396397 def getTableContext(self):398 u"""getTableContext() -> IZXHTMLEditControlTableContext399 Returns table insertion and edit context if available or None otherwise.""" #$NON-NLS-1$400 return self._getContentEditControl().getTableContext()401 # end getTableContext402403 def getCurrentSelection(self):404 u"""getCurrentSelection() -> IZXHTMLEditControlSelection405 """ #$NON-NLS-1$406 return self._getContentEditControl().getCurrentSelection()407 # end getCurrentSelection()408409 # ---------------------------------------------410 # Extended entry411 # ---------------------------------------------412413 def insertExtendedEntryMarker(self):414 self._getContentEditControl().insertExtendedEntryMarker()415 # end insertExtendedEntryMarker()416417 def removeExtendedEntryMarker(self):418 self._getContentEditControl().removeExtendedEntryMarker()419 # removeExtendedEntryMarker()420421 # ---------------------------------------------422 # Spellcheck423 # ---------------------------------------------424 def createSpellCheckContext(self):425 u"""createSpellCheckContext() -> IZEditControlSpellCheckContext426 Returns IZEditControlSpellCheckContext if spellcheck is supported or None otherwise.427 """ #$NON-NLS-1$428 return self._getContentEditControl().createSpellCheckContext()429 # end createSpellCheckContext()430431 # ---------------------------------------------432 # Find and Find/Replace433 # ---------------------------------------------434 def createFindReplaceContext(self):435 u"""createFindReplaceContext() -> IZEditControlFindReplaceTextContext436 Returns IZEditControlFindReplaceTextContext if find/replace is supported or None otherwise.437 """ #$NON-NLS-1$438 return self._getContentEditControl().createFindReplaceContext()439 # end createFindReplaceContext()440 441 # ---------------------------------------------442 # Validate and Tidy443 # ---------------------------------------------444 def schemaValidate(self):445 self._getContentEditControl().schemaValidate()446 # end schemaValidate447 448 def clearValidation(self):449 self._getContentEditControl().clearValidation()450 # end clearValidation 451 452 def runTidy(self):453 self._getContentEditControl().runTidy()454 # end runTidy 455 456
...
dev_appserver_blobstore.py
Source:dev_appserver_blobstore.py
1#!/usr/bin/env python2#3# Copyright 2007 Google Inc.4#5# Licensed under the Apache License, Version 2.0 (the "License");6# you may not use this file except in compliance with the License.7# You may obtain a copy of the License at8#9# http://www.apache.org/licenses/LICENSE-2.010#11# Unless required by applicable law or agreed to in writing, software12# distributed under the License is distributed on an "AS IS" BASIS,13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14# See the License for the specific language governing permissions and15# limitations under the License.16#17"""Blobstore support classes.18Classes:19 DownloadRewriter:20 Rewriter responsible for transforming an application response to one21 that serves a blob to the user.22 CreateUploadDispatcher:23 Creates a dispatcher that is added to dispatcher chain. Handles uploads24 by storing blobs rewriting requests and returning a redirect.25"""26import cgi27import cStringIO28import logging29import mimetools30import re31import sys32from google.appengine.api import apiproxy_stub_map33from google.appengine.api import blobstore34from google.appengine.api import datastore35from google.appengine.api import datastore_errors36from google.appengine.tools import dev_appserver_upload37from webob import byterange38UPLOAD_URL_PATH = '_ah/upload/'39UPLOAD_URL_PATTERN = '/%s(.*)' % UPLOAD_URL_PATH40AUTO_MIME_TYPE = 'application/vnd.google.appengine.auto'41ERROR_RESPONSE_TEMPLATE = """42<html>43 <head>44 <title>%(response_code)d %(response_string)s</title>45 </head>46 <body text=#000000 bgcolor=#ffffff>47 <h1>Error: %(response_string)s</h1>48 <h2>%(response_text)s</h2>49 </body>50</html>51"""52def GetBlobStorage():53 """Get blob-storage from api-proxy stub map.54 Returns:55 BlobStorage instance as registered with blobstore API in stub map.56 """57 return apiproxy_stub_map.apiproxy.GetStub('blobstore').storage58_BYTESRANGE_IS_EXCLUSIVE = not hasattr(byterange.Range, 'serialize_bytes')59if _BYTESRANGE_IS_EXCLUSIVE:60 ParseRange = byterange.Range.parse_bytes61 MakeContentRange = byterange.ContentRange62 def GetContentRangeStop(content_range):63 return content_range.stop64 _orig_is_content_range_valid = byterange._is_content_range_valid65 def _new_is_content_range_valid(start, stop, length, response=False):66 return _orig_is_content_range_valid(start, stop, length, False)67 def ParseContentRange(content_range_header):68 try:69 byterange._is_content_range_valid = _new_is_content_range_valid70 return byterange.ContentRange.parse(content_range_header)71 finally:72 byterange._is_content_range_valid = _orig_is_content_range_valid73else:74 def ParseRange(range_header):75 original_stdout = sys.stdout76 sys.stdout = cStringIO.StringIO()77 try:78 parse_result = byterange.Range.parse_bytes(range_header)79 finally:80 sys.stdout = original_stdout81 if parse_result is None:82 return None83 else:84 ranges = []85 for start, end in parse_result[1]:86 if end is not None:87 end += 188 ranges.append((start, end))89 return parse_result[0], ranges90 class _FixedContentRange(byterange.ContentRange):91 def __init__(self, start, stop, length):92 self.start = start93 self.stop = stop94 self.length = length95 def MakeContentRange(start, stop, length):96 if stop is not None:97 stop -= 298 content_range = _FixedContentRange(start, stop, length)99 return content_range100 def GetContentRangeStop(content_range):101 stop = content_range.stop102 if stop is not None:103 stop += 2104 return stop105 def ParseContentRange(content_range_header):106 return _FixedContentRange.parse(content_range_header)107def ParseRangeHeader(range_header):108 """Parse HTTP Range header.109 Args:110 range_header: Range header as retrived from Range or X-AppEngine-BlobRange.111 Returns:112 Tuple (start, end):113 start: Start index of blob to retrieve. May be negative index.114 end: None or end index. End index is exclusive.115 (None, None) if there is a parse error.116 """117 if not range_header:118 return None, None119 parsed_range = ParseRange(range_header)120 if parsed_range:121 range_tuple = parsed_range[1]122 if len(range_tuple) == 1:123 return range_tuple[0]124 return None, None125def DownloadRewriter(response, request_headers):126 """Intercepts blob download key and rewrites response with large download.127 Checks for the X-AppEngine-BlobKey header in the response. If found, it will128 discard the body of the request and replace it with the blob content129 indicated.130 If a valid blob is not found, it will send a 404 to the client.131 If the application itself provides a content-type header, it will override132 the content-type stored in the action blob.133 If Content-Range header is provided, blob will be partially served. The134 application can set blobstore.BLOB_RANGE_HEADER if the size of the blob is135 not known. If Range is present, and not blobstore.BLOB_RANGE_HEADER, will136 use Range instead.137 Args:138 response: Response object to be rewritten.139 request_headers: Original request headers. Looks for 'Range' header to copy140 to response.141 """142 blob_key = response.headers.getheader(blobstore.BLOB_KEY_HEADER)143 if blob_key:144 del response.headers[blobstore.BLOB_KEY_HEADER]145 try:146 blob_info = datastore.Get(147 datastore.Key.from_path(blobstore.BLOB_INFO_KIND,148 blob_key,149 namespace=''))150 content_range_header = response.headers.getheader('Content-Range')151 blob_size = blob_info['size']152 range_header = response.headers.getheader(blobstore.BLOB_RANGE_HEADER)153 if range_header is not None:154 del response.headers[blobstore.BLOB_RANGE_HEADER]155 else:156 range_header = request_headers.getheader('Range')157 def not_satisfiable():158 """Short circuit response and return 416 error."""159 response.status_code = 416160 response.status_message = 'Requested Range Not Satisfiable'161 response.body = cStringIO.StringIO('')162 response.headers['Content-Length'] = '0'163 del response.headers['Content-Type']164 del response.headers['Content-Range']165 if range_header:166 start, end = ParseRangeHeader(range_header)167 if start is not None:168 if end is None:169 if start >= 0:170 content_range_start = start171 else:172 content_range_start = blob_size + start173 content_range = MakeContentRange(174 content_range_start, blob_size, blob_size)175 content_range_header = str(content_range)176 else:177 content_range = MakeContentRange(start, min(end, blob_size),178 blob_size)179 content_range_header = str(content_range)180 response.headers['Content-Range'] = content_range_header181 else:182 not_satisfiable()183 return184 content_range_header = response.headers.getheader('Content-Range')185 content_length = blob_size186 start = 0187 end = content_length188 if content_range_header is not None:189 content_range = ParseContentRange(content_range_header)190 if content_range:191 start = content_range.start192 stop = GetContentRangeStop(content_range)193 content_length = min(stop, blob_size) - start194 stop = start + content_length195 content_range = MakeContentRange(start, stop, blob_size)196 response.headers['Content-Range'] = str(content_range)197 else:198 not_satisfiable()199 return200 blob_stream = GetBlobStorage().OpenBlob(blob_key)201 blob_stream.seek(start)202 response.body = cStringIO.StringIO(blob_stream.read(content_length))203 response.headers['Content-Length'] = str(content_length)204 content_type = response.headers.getheader('Content-Type')205 if not content_type or content_type == AUTO_MIME_TYPE:206 response.headers['Content-Type'] = blob_info['content_type']207 response.large_response = True208 except datastore_errors.EntityNotFoundError:209 response.status_code = 500210 response.status_message = 'Internal Error'211 response.body = cStringIO.StringIO()212 if response.headers.getheader('status'):213 del response.headers['status']214 if response.headers.getheader('location'):215 del response.headers['location']216 if response.headers.getheader('content-type'):217 del response.headers['content-type']218 logging.error('Could not find blob with key %s.', blob_key)219def CreateUploadDispatcher(get_blob_storage=GetBlobStorage):220 """Function to create upload dispatcher.221 Returns:222 New dispatcher capable of handling large blob uploads.223 """224 from google.appengine.tools import dev_appserver225 class UploadDispatcher(dev_appserver.URLDispatcher):226 """Dispatcher that handles uploads."""227 def __init__(self):228 """Constructor.229 Args:230 blob_storage: A BlobStorage instance.231 """232 self.__cgi_handler = dev_appserver_upload.UploadCGIHandler(233 get_blob_storage())234 def Dispatch(self,235 request,236 outfile,237 base_env_dict=None):238 """Handle post dispatch.239 This dispatcher will handle all uploaded files in the POST request, store240 the results in the blob-storage, close the upload session and transform241 the original request in to one where the uploaded files have external242 bodies.243 Returns:244 New AppServerRequest indicating request forward to upload success245 handler.246 """247 if base_env_dict['REQUEST_METHOD'] != 'POST':248 outfile.write('Status: 400\n\n')249 return250 upload_key = re.match(UPLOAD_URL_PATTERN, request.relative_url).group(1)251 try:252 upload_session = datastore.Get(upload_key)253 except datastore_errors.EntityNotFoundError:254 upload_session = None255 if upload_session:256 success_path = upload_session['success_path']257 max_bytes_per_blob = upload_session['max_bytes_per_blob']258 max_bytes_total = upload_session['max_bytes_total']259 upload_form = cgi.FieldStorage(fp=request.infile,260 headers=request.headers,261 environ=base_env_dict)262 try:263 mime_message_string = self.__cgi_handler.GenerateMIMEMessageString(264 upload_form,265 max_bytes_per_blob=max_bytes_per_blob,266 max_bytes_total=max_bytes_total)267 datastore.Delete(upload_session)268 self.current_session = upload_session269 header_end = mime_message_string.find('\n\n') + 1270 content_start = header_end + 1271 header_text = mime_message_string[:header_end].replace('\n', '\r\n')272 content_text = mime_message_string[content_start:].replace('\n',273 '\r\n')274 complete_headers = ('%s'275 'Content-Length: %d\r\n'276 '\r\n') % (header_text, len(content_text))277 return dev_appserver.AppServerRequest(278 success_path,279 None,280 mimetools.Message(cStringIO.StringIO(complete_headers)),281 cStringIO.StringIO(content_text),282 force_admin=True)283 except dev_appserver_upload.InvalidMIMETypeFormatError:284 outfile.write('Status: 400\n\n')285 except dev_appserver_upload.UploadEntityTooLargeError:286 outfile.write('Status: 413\n\n')287 response = ERROR_RESPONSE_TEMPLATE % {288 'response_code': 413,289 'response_string': 'Request Entity Too Large',290 'response_text': 'Your client issued a request that was too '291 'large.'}292 outfile.write(response)293 else:294 logging.error('Could not find session for %s', upload_key)295 outfile.write('Status: 404\n\n')296 def EndRedirect(self, dispatched_output, original_output):297 """Handle the end of upload complete notification.298 Makes sure the application upload handler returned an appropriate status299 code.300 """301 response = dev_appserver.RewriteResponse(dispatched_output)302 logging.info('Upload handler returned %d', response.status_code)303 outfile = cStringIO.StringIO()304 outfile.write('Status: %s\n' % response.status_code)305 if response.body and len(response.body.read()) > 0:306 response.body.seek(0)307 outfile.write(response.body.read())308 else:309 outfile.write(''.join(response.headers.headers))310 outfile.seek(0)311 dev_appserver.URLDispatcher.EndRedirect(self,312 outfile,313 original_output)...
connresp.py
Source:connresp.py
1from zoundry.appframework.exceptions import ZAppFrameworkException2from zoundry.appframework.messages import _extstr3from zoundry.base.util.fileutil import getFileMetaData4import os56# ------------------------------------------------------------------------------7# The interface for connection response information. This object contains the8# meta information about the connection response (code, message, headers).9# ------------------------------------------------------------------------------10class IZHttpConnectionRespInfo:11 12 def getURL(self):13 u"""getURL() -> string14 Returns the URL that this response represents.""" #$NON-NLS-1$15 # end getURL()16 17 def getCode(self):18 u"""getCode() -> int19 Returns the HTTP response code.""" #$NON-NLS-1$20 # end getCode()21 22 def getMessage(self):23 u"""getMessage() -> string24 Returns the HTTP response message.""" #$NON-NLS-1$25 # end getMessage()26 27 def getHeaders(self):28 u"""getHeaders() -> map<string, string>29 Returns a map of HTTP response header (map of header30 key to header value).""" #$NON-NLS-1$31 # end getHeaders()32 33 def getHeader(self, name):34 u"""getHeader(string) -> string35 Returns the value of the header with the given name.""" #$NON-NLS-1$36 # end getHeader()37 38 def getContentType(self):39 u"""getContentType() -> string40 Returns the content type of the response.""" #$NON-NLS-1$41 # end getContentType()42 43 def getContentLength(self):44 u"""getContentLength() -> int45 Returns the content length of the response.""" #$NON-NLS-1$46 # end getContentLength()4748# end IZHttpConnectionRespInfo495051# ------------------------------------------------------------------------------52# Extends the IZHttpConnectionRespInfo by adding accessors to get at the actual53# response content.54# ------------------------------------------------------------------------------55class IZHttpConnectionResp(IZHttpConnectionRespInfo):56 57 def getContentStream(self):58 u"""getContentStream() -> stream59 Returns a file-like object for the content for this60 response.""" #$NON-NLS-1$61 # end getContentStream62 63 def getContent(self):64 u"""getContent() -> data[]65 Returns the content data for this response.""" #$NON-NLS-1$66 # end getContent()67 68 def getContentFilename(self):69 u"""getContentFilename() -> string70 Returns the filename where the content for this response71 is stored.""" #$NON-NLS-1$72 # end getContentFilename()7374# end IZHttpConnectionResp757677# ------------------------------------------------------------------------------78# A simple implementation of a connection response info.79# ------------------------------------------------------------------------------80class ZHttpConnectionRespInfo(IZHttpConnectionRespInfo):8182 def __init__(self, url, code, message, headers):83 self.url = url84 self.code = code85 self.message = message86 self.headers = headers87 # end __init__()88 89 def getURL(self):90 return self.url91 # end getURL()9293 def getCode(self):94 return self.code95 # end getCode()96 97 def getMessage(self):98 return self.message99 # end getMessage()100 101 def getHeaders(self):102 return self.headers103 # end getHeaders()104 105 def getHeader(self, name):106 if name in self.headers:107 return self.headers[name]108 return None109 # end getHeader()110 111 def getContentType(self):112 return self.getHeader(u"content-type") #$NON-NLS-1$113 # end getContentType()114 115 def getContentLength(self):116 cl = self.getHeader(u"content-length") #$NON-NLS-1$117 if cl is not None:118 return long(cl)119 return None120 # end getContentLength()121122# end ZHttpConnectionRespInfo123124125# ------------------------------------------------------------------------------126# A simple implementation of a connection response.127# ------------------------------------------------------------------------------128class ZHttpConnectionResp(ZHttpConnectionRespInfo, IZHttpConnectionResp):129130 def __init__(self, url, code, message, headers, contentFilename):131 ZHttpConnectionRespInfo.__init__(self, url, code, message, headers)132133 self.contentFilename = contentFilename134 # end __init__()135136 def getContentLength(self):137 if os.path.isfile(self.contentFilename):138 return getFileMetaData(self.contentFilename)[2]139140 return ZHttpConnectionRespInfo.getContentLength(self)141 # end getContentLength()142143 def getContentStream(self):144 if not os.path.isfile(self.contentFilename):145 raise ZAppFrameworkException(u"%s: '%s'." % (_extstr(u"connresp.NoContentFoundError"), self.contentFilename)) #$NON-NLS-1$ #$NON-NLS-2$146 return open(self.contentFilename)147 # end getContentStream148 149 def getContent(self):150 file = self.getContentStream()151 try:152 return file.read()153 finally:154 file.close()155 # end getContent()156 157 def getContentFilename(self):158 return self.contentFilename159 # end getContentFilename()160
...
test_forms.py
Source:test_forms.py
1# -*- coding: utf-8 -*-2# Copyright: 2011 Prashant Kumar <contactprashantat AT gmail DOT com>3# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.4"""5MoinMoin - MoinMoin.util.forms Tests6"""7from MoinMoin.util import forms8class Bind(object):9 """ class for self defined test_bind attributes """10 def __init__(self):11 self.label = 'test_content'12 self.default_value = 'test_bind_default'13 self.optional = True14 self.properties = {'autofocus': False, 'placeholder': None}15 self.errors = None16test_bind = Bind()17test_attributes = {'type': 'submit', u'required': 'test_required', 'autofocus': None, 'placeholder': None}18def test_label_filter():19 # when content is None20 result1 = forms.label_filter('test_tagname', test_attributes, None, 'test_context', test_bind)21 expected = 'test_content'22 assert result1 == expected23 # when content is not None24 result2 = forms.label_filter('test_tagname', test_attributes, 'new_content', 'test_context', test_bind)25 expected = 'new_content'26 assert result2 == expected27def test_button_filter():28 result = forms.button_filter('test_tagname', test_attributes, 'new_content', 'test_context', None)29 expected = 'new_content'30 assert result == expected31 # attributes.get('type') in ['submit', 'reset', ])32 content_result = forms.button_filter('input', test_attributes, 'new_content', 'test_context', test_bind)33 expected = 'new_content'34 assert content_result == expected35 attributes_result = test_attributes['value']36 expected = 'test_bind_default'37 assert attributes_result == expected38 # tagname == 'button'39 content_result = forms.button_filter('button', test_attributes, None, 'test_context', test_bind)40 expected = 'test_bind_default'41 assert content_result == expected42def test_required_filter():43 test_bind.optional = False44 test_attributes[u'class'] = 'test_class'45 content_result = forms.required_filter('test_tagname', test_attributes, 'new_content', 'test_context', test_bind)46 expected = 'new_content'47 assert content_result == expected48 # fixing a class for the form element, restricts the HTML we can generate49 # attribute_result = test_attributes[u'class']50 # expected = u'required'51 # assert attribute_result == expected52 # tagname == 'input'53 content_result = forms.required_filter('input', test_attributes, 'new_content', 'test_context', test_bind)54 expected = 'new_content'55 assert content_result == expected56 attribute_result = test_attributes[u'required']57 expected = u'required'58 assert attribute_result == expected59def test_autofocus_filter():60 test_bind.properties = {'autofocus': True}61 content_result = forms.autofocus_filter('test_tagname', test_attributes, 'new_content', 'test_context', test_bind)62 assert content_result == 'new_content'63 attribute_result = test_attributes[u'autofocus']64 assert attribute_result == u'autofocus'65def test_placeholder_filter():66 test_bind.properties['placeholder'] = 'test_placeholder'67 content_result = forms.placeholder_filter('test_tagname', test_attributes, 'new_content', 'test_context', test_bind)68 assert content_result == 'new_content'69 attribute_result = test_attributes['placeholder']70 assert attribute_result == 'test_placeholder'71def test_error_filter_factory():72 # when 'class' not in test_attributes73 test_bind.errors = 'test_errors'74 test_attributes.pop(u'class')75 test_fun_returned = forms.error_filter_factory('test_moin_error')76 content_result = test_fun_returned('test_tagname', test_attributes, 'new_content', 'test_context', test_bind)77 assert content_result == 'new_content'78 attribute_result = test_attributes['class']79 assert attribute_result == 'test_moin_error'80 # class in test_attributes81 test_attributes['class'] = 'test_attribute_class'82 content_result = test_fun_returned('test_tagname', test_attributes, 'new_content', 'test_context', test_bind)83 assert content_result == 'new_content'84 attribute_result = test_attributes['class']85 expected = 'test_attribute_class test_moin_error'...
generator_compiler.py
Source:generator_compiler.py
1#!/usr/bin/env python2# This file is part of VoltDB.3# Copyright (C) 2008-2011 VoltDB Inc.4#5# VoltDB is free software: you can redistribute it and/or modify6# it under the terms of the GNU General Public License as published by7# the Free Software Foundation, either version 3 of the License, or8# (at your option) any later version.9#10# VoltDB is distributed in the hope that it will be useful,11# but WITHOUT ANY WARRANTY; without even the implied warranty of12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13# GNU General Public License for more details.14#15# You should have received a copy of the GNU General Public License16# along with VoltDB. If not, see <http://www.gnu.org/licenses/>.17# read a file into a string18def readfile(filename):19 FH=open(filename, 'r')20 fileString = FH.read()21 FH.close()22 return fileString23# take a string and make a file from it24def writefile(filename, content):25 FH=open(filename, 'w')26 FH.write(content)27 FH.close()28# these are the documents to embed and the29# variable names to assign them to30names = [("buildFileContent", "build.xml"),31 ("clientFileContent", "Client.java"),32 ("ddlFileContent", "ddl.sql"),33 ("deleteFileContent", "Delete.java"),34 ("deploymentFileContent", "deployment.xml"),35 ("insertFileContent", "Insert.java"),36 ("projectFileContent", "project.xml"),37 ("selectFileContent", "Select.java")]38# load the template39scriptContent = readfile("generate_input.py")40# load the content before the stub code41startContent = scriptContent.split("### REPLACED BY SCRIPT ###")[0]42# load the content after the stub code43endContent = scriptContent.rsplit("### END REPLACE ###")[-1]44# start with the first half of the template45outContent = startContent46# embed all the documents47for namepair in names:48 content = readfile(namepair[1])49 outContent += namepair[0] + " = \"\"\""50 outContent += content + "\"\"\"\n\n"51# wrap up with the second half of the template52outContent += endContent...
Using AI Code Generation
1import { MockBuilder, MockRender } from 'ng-mocks';2import { AppModule } from './app.module';3import { AppComponent } from './app.component';4beforeAll(() => MockBuilder(AppComponent, AppModule));5beforeEach(() => MockRender(AppComponent));6it('renders a title', () => {7 expect(MockRender(AppComponent).content('h1')).toContain('Welcome to app!');8});9import { Component } from '@angular/core';10@Component({11 Welcome to {{ title }}!12 <img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjMwMCIgdmlld0JveD0iMCAwIDMwMCAzMDAiPgo8c3R5bGU+LmNscy0xe2ZpbGw6I2ZmZjt9PC9zdHlsZT4KPHRpdGxlPmFwc
Using AI Code Generation
1import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';2import { AppComponent } from './app.component';3describe('AppComponent', () => {4 beforeEach(() => MockBuilder(AppComponent));5 it('should create the app', () => {6 const fixture = MockRender(AppComponent);7 const app = ngMocks.find('app-root');8 expect(app).toBeDefined();9 });10});11import { Component, OnInit } from '@angular/core';12@Component({13})14export class AppComponent implements OnInit {15 title = 'ng-mocks';16 constructor() { }17 ngOnInit() {18 }19}20 {{title}}21h1 {22 color: blue;23}24import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';25import { AppComponent } from './app.component';26describe('AppComponent', () => {27 beforeEach(() => MockBuilder(AppComponent));28 it('should create the app', () => {29 const fixture = MockRender(AppComponent);30 const app = ngMocks.find('app-root');31 expect(app).toBeDefined();32 });33});34import { Component, OnInit } from '@angular/core';35@Component({36})37export class AppComponent implements OnInit {38 title = 'ng-mocks';39 constructor() { }40 ngOnInit() {41 }42}43 {{title}}44h1 {45 color: blue;46}47import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';48import { AppComponent } from './app.component';49describe('AppComponent', () => {50 beforeEach(() => MockBuilder(AppComponent));51 it('should create the app', () => {52 const fixture = MockRender(AppComponent);53 const app = ngMocks.find('app-root');
Using AI Code Generation
1describe('MyComponent', () => {2 beforeEach(() => {3 TestBed.configureTestingModule({4 });5 });6 it('should render content', () => {7 const fixture = TestBed.createComponent(MyComponent);8 fixture.detectChanges();9 const element = fixture.debugElement.query(By.css('div'));10 expect(element.nativeElement.textContent).toEqual('Hello World');11 });12});13@Component({14 <div> {{ text }} </div>15})16export class MyComponent {17 text = 'Hello World';18}19describe('MyComponent', () => {20 beforeEach(() => {21 TestBed.configureTestingModule({22 });23 ngMocks.faster();24 });25 it('should render content', () => {26 const fixture = TestBed.createComponent(MyComponent);27 fixture.detectChanges();28 const element = fixture.debugElement.query(By.css('div'));29 expect(element.nativeElement.textContent).toEqual('Hello World');30 });31});32@Component({33 <div> {{ text }} </div>34})35export class MyComponent {36 text = 'Hello World';37}38describe('MyComponent', () => {39 beforeEach(() => {40 TestBed.configureTestingModule({41 });42 ngMocks.faster();43 });44 it('should render content', () => {45 const fixture = TestBed.createComponent(MyComponent);46 fixture.detectChanges();47 const element = fixture.debugElement.query(By.css('div'));48 expect(element.nativeElement.textContent).toEqual('Hello World');49 });50});51@Component({52})53export class MyComponent {54 text = 'Hello World';55}
Using AI Code Generation
1const ngMocks = require('ng-mocks');2const { MockBuilder, MockRender, MockInstance } = ngMocks;3const { AppModule } = require('./app.module');4describe('AppComponent', () => {5 beforeEach(() => MockBuilder(AppComponent, AppModule));6 it('should create the app', () => {7 const fixture = MockRender(AppComponent);8 const app = ngMocks.content(fixture.debugElement, 'app-root');9 expect(app).not.toBeNull();10 });11});12import { NgModule } from '@angular/core';13import { BrowserModule } from '@angular/platform-browser';14import { AppComponent } from './app.component';15@NgModule({16 imports: [BrowserModule],17})18export class AppModule {}19import { Component } from '@angular/core';20@Component({21})22export class AppComponent {}23import { MockBuilder, MockRender } from 'ng-mocks';24import { AppComponent } from './app.component';25import { AppModule } from './app.module';26describe('AppComponent', () => {27 beforeEach(() => MockBuilder(AppComponent, AppModule));28 it('should create the app', () => {29 const fixture = MockRender(AppComponent);30 const app = fixture.debugElement.nativeElement;31 expect(app).not.toBeNull();32 });33});
Using AI Code Generation
1var content = ngMocks.content;2var fixture = ngMocks.find('my-component');3var data = content(fixture, 'my-component');4expect(data).toEqual('test');5@Component({6})7export class MyComponent {8}9import { MyComponent } from './my-component.component';10import { ngMocks } from 'ng-mocks';11describe('MyComponent', () => {12 ngMocks.universe.add(MyComponent);13 ngMocks.faster();14 it('should render the component', () => {15 const fixture = ngMocks.find('my-component');16 expect(fixture).toBeDefined();17 const data = ngMocks.content(fixture, 'my-component');18 expect(data).toEqual('test');19 });20});21ngMocks.content(fixture, 'my-component')22ngMocks.content(fixture, MyComponent)23ngMocks.content(fixture, MyComponent, { inputs: { ... } })24ngMocks.content(fixture, MyComponent, { outputs: { ... } })25ngMocks.content(fixture, MyComponent, { providers: { ... } })26ngMocks.content(fixture, MyComponent, { declarations: { ... } })27ngMocks.content(fixture, MyComponent, { imports: { ... } })28ngMocks.content(fixture, MyComponent, { schemas: { ... } })29ngMocks.content(fixture, MyComponent, { queries: { ... } })30ngMocks.content(fixture, MyComponent, { entryComponents: { ... } })31ngMocks.content(fixture, MyComponent, { exports: { ... } })32ngMocks.content(fixture, MyComponent, { bootstrap: { ... } })33ngMocks.content(fixture, MyComponent, { providers: { ... }, declarations: { ... } })34ngMocks.content(fixture, MyComponent, { providers: { ... }, declarations: { ... }, imports: { ... } })35ngMocks.content(fixture, MyComponent, { providers: { ... }, declarations: { ... }, imports: { ... }, schemas: { ... } })36ngMocks.content(fixture, MyComponent, { providers: { ... }, declarations: { ... }, imports: { ... }, schemas: { ... }, queries: { ... } })37ngMocks.content(fixture, MyComponent, { providers: { ... }, declarations: { ... }, imports: { ... }, schemas: { ... }, queries: { ... }, entryComponents: { ... } })
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!