Best JavaScript code snippet using puppeteer
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 puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch();4  const page = await browser.newPage();5  await page.screenshot({path: 'example.png'});6  await browser.close();7})();Using AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch();4  const page = await browser.newPage();5  await page.screenshot({path: 'example.png'});6  await browser.close();7})();8const puppeteer = require('puppeteer');9(async () => {10  const browser = await puppeteer.launch();11  const page = await browser.newPage();12  await page.screenshot({path: 'example.png'});13  await browser.close();14})();15const fs = require('fs');16const puppeteer = require('puppeteer');17(async () => {18    const browser = await puppeteer.launch();19    const page = await browser.newPage();20    await page.screenshot({path: 'example.png'});21    await browser.close();22})();Using AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch({headless: false});4  const page = await browser.newPage();5  await page.type('#lst-ib', 'puppeteer');6  await page.keyboard.press('Enter');7  await page.waitForNavigation();8  await page.screenshot({path: 'example.png'});9  await browser.close();10})();11const puppeteer = require('puppeteer');12(async () => {13  const browser = await puppeteer.launch({headless: false});14  const page = await browser.newPage();15  await page.type('#lst-ib', 'puppeteer');16  await page.keyboard.press('Enter');17  await page.waitForNavigation();18  await page.screenshot({path: 'example.png'});19  await browser.close();20})();21const puppeteer = require('puppeteer');22(async () => {23  const browser = await puppeteer.launch({headless: false});24  const page = await browser.newPage();25  await page.type('#lst-ib', 'puppeteer');26  await page.keyboard.press('Enter');27  await page.waitForNavigation();28  await page.screenshot({path: 'example.png'});29  await browser.close();30})();31const puppeteer = require('puppeteer');32(async () => {33  const browser = await puppeteer.launch({headless: false});34  const page = await browser.newPage();35  await page.type('#lst-ib', 'puppeteer');36  await page.keyboard.press('Enter');37  await page.waitForNavigation();38  await page.screenshot({path: 'example.png'});39  await browser.close();40})();41const puppeteer = require('puppeteer');42(async () => {43  const browser = await puppeteer.launch({headless: false});44  const page = await browser.newPage();45  await page.type('#lst-ib', 'pUsing AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch();4  const page = await browser.newPage();5  const content = await page.content();6  console.log(content);7  await browser.close();8})();Using AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch();4  const page = await browser.newPage();5  const content = await page.content();6  console.log(content);7  await browser.close();8})();9const puppeteer = require('puppeteer');10(async () => {11  const browser = await puppeteer.launch();12  const page = await browser.newPage();13  await page.pdf({ path: 'page.pdf' });14  await browser.close();15})();16const puppeteer = require('puppeteer');17(async () => {18  const browser = await puppeteer.launch();19  const page = await browser.newPage();20  await page.screenshot({ path: 'page.png' });21  await browser.close();22})();23const puppeteer = require('puppeteer');24(async () => {25  const browser = await puppeteer.launch();26  const page = await browser.newPage();27  await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64Using AI Code Generation
1const puppeteer = require('puppeteer');2(async () => {3  const browser = await puppeteer.launch();4  const page = await browser.newPage();5  const text = await page.content();6  console.log(text);7  await browser.close();8})();9const puppeteer = require('puppeteer');10(async () => {11  const browser = await puppeteer.launch();12  const page = await browser.newPage();13  const text = await page.evaluate(() => document.body.innerText);14  console.log(text);15  await browser.close();16})();Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
