Best JavaScript code snippet using playwright-internal
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
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({headless: false});4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.setContent('<html><body><h1>Hello World!</h1></body></html>');7 await page.screenshot({path: 'example.png'});8 await browser.close();9})();10- [Playwright Github](
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 for (const browserType of BROWSER) {4 const browser = await playwright[browserType].launch({5 });6 const context = await browser.newContext();7 const page = await context.newPage();8 await page.setContent('<h1>Playwright</h1>');9 await page.screenshot({ path: `example-${browserType}.png` });10 await browser.close();11 }12})();
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.click('text=Playwright - Node.js library to automate Chromium, Firefox and WebKit with a single API');7 await page.click('text=API Documentation');8 await page.click('text=Page');
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!