def test_fromURL(self): """Test 'fromURL' constructor""" url = 'http://media.tannern.com/pynliner/test.html' p = Pynliner() with mock.patch.object(Pynliner, '_get_url') as mocked: mocked.return_value = u"""<?xml version='1.0' encoding='utf-8'?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>test</title> <link rel="stylesheet" type="text/css" href="test.css"/> <style type="text/css">h1 {color: #fc0;}</style> </head> <body> <h1>Hello World!</h1> <p>:)</p> </body> </html>""" p.from_url(url) self.assertEqual(p.root_url, 'http://media.tannern.com') self.assertEqual(p.relative_url, 'http://media.tannern.com/pynliner/') p._get_soup() with mock.patch.object(Pynliner, '_get_url') as mocked: mocked.return_value = 'p {color: #999}' p._get_external_styles() self.assertEqual(p.style_string, "p {color: #999}") p._get_internal_styles() self.assertEqual(p.style_string, "p {color: #999}\nh1 {color: #fc0;}\n") p._get_styles() output = p.run() desired = u"""<?xml version='1.0' encoding='utf-8'?> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>test</title> </head> <body> <h1 style="color: #fc0">Hello World!</h1> <p style="color: #999">:)</p> </body> </html>""" self.assertEqual(output, desired)
def test_custom_log(self): self.log = logging.getLogger('testlog') self.log.setLevel(logging.DEBUG) self.logstream = StringIO.StringIO() handler = logging.StreamHandler(self.logstream) formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s") handler.setFormatter(formatter) self.log.addHandler(handler) self.p = Pynliner(self.log).from_string(self.html) self.p.run() log_contents = self.logstream.getvalue() self.assertIn("DEBUG", log_contents)
def _render(self, context): """ Renders the plain and html versions of a template. Return both in a tuple, where the first element is the plain text version and the second element is the html version :return: (str, str,) """ if not context: context = Context({}) plain = self.template_plain.render(context) html = self.template_html.render(context) css = get_template(self.template_style).render(Context({})) p = Pynliner() html = p.from_string(html).with_cssString(css).run() return plain, html
def test_newline_multiple_styles(self): """Test that multiple CSS styles get separated with spaces instead of newlines""" html = '<style>h1 { font-weight:bold; color: red}</style><h1>Bold Red</h1>' desired_output = '<h1 style="font-weight: bold; color: red">Bold Red</h1>' output = Pynliner().from_string(html).run() self.assertEqual(output, desired_output)
def setUp(self): self.html = "<style>h1 { color:#ffcc00; }</style><h1>Hello World!</h1>" self.p = Pynliner().from_string(self.html)
def test_08_comma_whitespace(self): """Test excess whitespace in CSS""" html = '<style>h1, h2 ,h3,\nh4{ color: #000} </style><h1>1</h1><h2>2</h2><h3>3</h3><h4>4</h4>' desired_output = '<h1 style="color: #000">1</h1><h2 style="color: #000">2</h2><h3 style="color: #000">3</h3><h4 style="color: #000">4</h4>' output = Pynliner().from_string(html).run() self.assertEqual(output, desired_output)
def test_attribute_selector(self): html = """<h1 title="foo">Hello World!</h1>""" css = """h1[title="foo"] { color: red; }""" expected = u"""<h1 title="foo" style="color: red">Hello World!</h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_child_selector(self): html = """<h1><span>Hello World!</span></h1>""" css = """h1 > span { color: red; }""" expected = u"""<h1><span style="color: red">Hello World!</span></h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_multiple_class_selector(self): html = """<h1 class="a b">Hello World!</h1>""" css = """h1.a.b { color: red; }""" expected = u"""<h1 class="a b" style="color: red">Hello World!</h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_no_log(self): self.p = Pynliner() self.assertEqual(self.p.log, None) self.assertEqual(cssutils.log.enabled, False)
def test_unicode_content(self): html = u"""<h1>Hello World!</h1><p>\u2022 point</p>""" css = """h1 { color: red; }""" expected = u"""<h1 style="color: red">Hello World!</h1><p>\u2022 point</p>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_conditional_comments(self): html = "<!-- <normal> --><!--[if condition]><p>special</p><![endif]-->" expected = "<!-- <normal> --><!--[if condition]><p>special</p><![endif]-->" output = Pynliner( allow_conditional_comments=True).from_string(html).run() self.assertEqual(output, expected)
def initial_email(self, custom_msg=None, send=True): """ Generates the body for an initial saved search notification and returns it or sends it in an email based on the opt in status of the user. Inputs: :custom_msg: Custom message to be added when manually resending an initial email :send: Denotes if we should send the generated email (True) or return the body (False). If False, the body will be used in an invitation. Default: True Outputs: :message: Generated email body (if :send: is False) or None """ default_reason = 'Jobs are not sent in initial saved search emails' log_kwargs = { 'reason': default_reason, 'was_sent': False, 'was_received': False, 'recipient': self.user, 'recipient_email': self.email, 'new_jobs': 0, 'backfill_jobs': 0, 'uuid': uuid.uuid4().hex } message = None if self.user.opt_in_myjobs: # Even if send=False, this will still get sent; send=False currently # means the generated email body will be used in an invitation. log_kwargs['was_sent'] = True context_dict = { 'saved_searches': [(self, )], 'custom_msg': custom_msg, 'contains_pss': hasattr(self, 'partnersavedsearch') } message = render_to_string("mysearches/email_initial.html", context_dict) message = Pynliner().from_string(message).run() if send: category = ('{"category": "My.jobs Saved Search Created ' '(%s:%s|%s)"}') % (self.content_type, self.pk, log_kwargs['uuid']) headers = {'X-SMTPAPI': category} try: send_email(message, email_type=settings.SAVED_SEARCH_INITIAL, recipients=[self.email], label=self.label.strip(), headers=headers) except Exception as e: log_kwargs['was_sent'] = False log_kwargs['reason'] = getattr(e, 'smtp_error', e.message) if context_dict['contains_pss']: reason = log_kwargs['reason'] if reason == default_reason: # Most other instances of SavedSearchLog have nothing # in the reason field when successful. This one is a # little different, serving as a reminder of why this # particular email contains no jobs. reason = None self.partnersavedsearch.create_record( "Automatic sending of initial partner saved search", failure_message=reason) else: log_kwargs['reason'] = "User can't receive MyJobs email" SavedSearchLog.objects.create(**log_kwargs) if not send: return message
def compose(request): cwd = get_working_dir() config = get_user_config(request.user) file_folder = "templates" template_folder = "templates" params = request.POST if len(params) == 0: params = request.GET # nav_form = ComposeNavForm() # nav_form.fields["template_subfolder"].initial="/" template_subfolder = "/" compose_form = ComposeTemplateForm() compose_form.fields["template_subfolder"].initial = "/" # test_form = ComposeTestForm() try: action = params["action"] except: action = "none" template_path = clean_subfolder(getParamDefault(params, "file_path", "")) if template_path.find("/templates\\") == 0: subfolder_default = template_path[11:] else: subfolder_default = "" template_subfolder = clean_subfolder( getParamDefault(params, "template_subfolder", subfolder_default)) file_name = getParamDefault(params, "file_name", "") file_content = getParamDefault(params, "file_content", "") template_test_case = getParamDefault(params, "template_test_case", "") test_case_xform = getParamDefault(params, "test_case_xform", "") template_stylesheet = getParamDefault(params, "template_stylesheet", "") stylesheet_content = getParamDefault(params, "template_stylesheet_content", "") template_sample = getParamDefault(params, "template_sample", "") rendered = "" render_type = "txt" if template_path == "": template_path = file_folder + template_subfolder else: if template_path[0] == "/": template_path = template_path[1:] if not (file_name == "") and (file_content == ""): file_content = get_local_txt_content(cwd, config, template_path, file_name) file_content = file_content.replace("\n\n", "\n") if action == "save": file_content = params["file_content"] if file_name.find(".") < 0: file_name = file_name + ".txt" template_path = file_folder + template_subfolder push_local_txt(cwd, config, template_path, file_name, file_content) #print(compose_form) elif action == "nav": template_subfolder = clean_subfolder( getParamDefault(params, "template_subfolder", "")) compose_form.fields["template_subfolder"].initial = template_subfolder elif action == "preview": try: subs = getData(config, data_file=template_test_case, local_data_folder="test_data") except: subs = {} try: subs = subs["docroot"] except: pass rendered = substituteVariablesPlainString(config, file_content, subs) render_type = "txt" if (file_name.find(".md")): #fix needed rendered = convert_markdown_string(rendered) rendered = '<div class="echo-publish">' + rendered + "</div>" rendered = Pynliner().from_string(rendered).with_cssString( stylesheet_content).run() render_type = "md" ### if not (template_stylesheet == ""): stylesheet_content = get_local_txt_content( cwd, config, template_folder + template_subfolder, template_stylesheet) if not (template_test_case == ""): subs = getData(config, data_file=template_test_case, local_data_folder="test_data") try: subs = subs["docroot"] except: pass fields, groups, tree = fields_from_subs(subs) field_string = "Fields" for field in fields: field_string += "\n" field_string += "{{" + field + "}}" logic_string = "Logic" for field in fields: logic_string += "\n" logic_string += "{% if " + field + " == \"\" %}{% endif %}" group_string = "Groups" for field in fields: group_string += "\n" group_string += "{% for item in " + field + " %}{% endfor %}" template_sample = { "fields": field_string, "logic": logic_string, "groups": group_string } items = folder_files(config, "templates" + template_subfolder) folders, files = get_folders_and_files(template_subfolder, items) style_files = [(file["name"], file["name"]) for file in files if file["name"].find(".css") > 0] template_files = [(file["name"], file["name"]) for file in files if file["name"].find(".css") < 0] compose_form.fields['template_files'].choices = [("", "---") ] + template_files compose_form.fields["file_name"].initial = file_name compose_form.fields["file_name"].label = "File name" compose_form.fields["file_content"].initial = file_content compose_form.fields["file_content"].label = "File content" compose_form.fields["template_subfolder"].initial = template_subfolder compose_form.fields['template_subfolder'].choices = [ (folder["name"], folder["name"]) for folder in folders ] compose_form.fields["template_subfolder"].initial = template_subfolder compose_form.fields['template_test_case'].initial = template_test_case compose_form.fields['template_stylesheet'].choices = [("", "---") ] + style_files compose_form.fields[ 'template_stylesheet_content'].initial = stylesheet_content #compose_form.fields['template_sample'].initial = template_sample data_files = folder_files(config, "test_data") data_files = sorted(data_files, key=lambda k: k['ext'] + k['name']) compose_form.fields['template_test_case'].choices = [("", "---")] + [ (file["name"], file["name"]) for file in data_files ] data_files = folder_files(config, "transforms") data_files = sorted(data_files, key=lambda k: k['ext'] + k['name']) compose_form.fields['test_case_xform'].choices = [("", "---")] + [ (file["name"], file["name"]) for file in data_files ] return render( request, compose_page, { "title": "Compose Template", "glyph": "glyphicon glyphicon-cog", "form": compose_form, "sub_title": template_subfolder, "sample": template_sample, #"stylesheet_content": stylesheet_content, "rendered": rendered, "render": render_type, "install_display": install_display })
def email_to_html_text(msgBody): BODY_TEXT = html2text.html2text(msgBody) # The HTML body of the email. BODY_HTML = (Pynliner().from_string(msgBody).run() ) # bleach.linkify(bleach.clean(msgBody)) return BODY_TEXT, BODY_HTML
def test_child_with_first_child_and_class_selector_complex_dom(self): html = """<h1><span class="hello">Hello World!</span><p>foo</p><div class="barclass"><span>baz</span>bar</div></h1>""" css = """h1 > .hello:first-child { color: green; }""" expected = u"""<h1><span class="hello" style="color: green">Hello World!</span><p>foo</p><div class="barclass"><span>baz</span>bar</div></h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_first_child_descendant_selector_complex_dom(self): html = """<h1><div><span>Hello World!</span></div><p>foo</p><div class="barclass"><span>baz</span>bar</div></h1>""" css = """h1 :first-child { color: red; }""" expected = u"""<h1><div style="color: red"><span style="color: red">Hello World!</span></div><p>foo</p><div class="barclass"><span style="color: red">baz</span>bar</div></h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_comma_separated_nested_styles(self): html = """<style>.orange-wrapper p, .super-orange-wrapper p { color:orange; }</style><div class="orange-wrapper"><p>Orange</p></div><div><p>Black</p></div>""" desired_output = """<div class="orange-wrapper"><p style="color: orange">Orange</p></div><div><p>Black</p></div>""" output = Pynliner().from_string(html).run() self.assertEqual(output, desired_output)
def test_comma_specificity(self): html = '<i>howdy</i>' css = 'i, i { color: red; } i { color: blue; }' expected = '<i style="color: blue">howdy</i>' output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_missing_link_descendant_selector(self): html = '<div id="a"><i>x</i></div>' css = '#a b i { color: red }' expected = html output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_combination_selector(self): html = """<h1 id="a" class="b">Hello World!</h1>""" css = """h1#a.b { color: red; }""" expected = u"""<h1 id="a" class="b" style="color: red">Hello World!</h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_unknown_pseudo_selector(self): html = """<h1><span>Hello World!</span><p>foo</p><div class="barclass"><span>baz</span>bar</div></h1>""" css = """h1 > span:css4-selector { color: red; }""" expected = u"""<h1><span>Hello World!</span><p>foo</p><div class="barclass"><span>baz</span>bar</div></h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_adjacent_selector(self): html = """<h1>Hello World!</h1><h2>How are you?</h2>""" css = """h1 + h2 { color: red; }""" expected = u"""<h1>Hello World!</h1><h2 style="color: red">How are you?</h2>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_child_follow_by_first_child_selector_with_comments(self): html = """<h1> <!-- enough said --><span>Hello World!</span><p>foo</p><div class="barclass"><span>baz</span>bar</div></h1>""" css = """h1 > :first-child { color: red; }""" expected = u"""<h1> <!-- enough said --><span style="color: red">Hello World!</span><p>foo</p><div class="barclass"><span>baz</span>bar</div></h1>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_09_overloadedStyles(self): html = '<style>h1 { color: red; } #test { color: blue; }</style><h1 id="test">Hello world!</h1>' expected = '<h1 id="test" style="color: blue">Hello world!</h1>' output = Pynliner().from_string(html).run() self.assertEqual(expected, output)
def test_id_el_child_with_first_child_override_selector_complex_dom(self): html = """<div id="abc"><span class="cde">Hello World!</span><p>foo</p><div class="barclass"><span>baz</span>bar</div></div>""" css = """#abc > * { color: green; } #abc > :first-child { color: red; }""" expected = u"""<div id="abc"><span class="cde" style="color: red">Hello World!</span><p style="color: green">foo</p><div class="barclass" style="color: green"><span>baz</span>bar</div></div>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def test_overwrite_comma(self): """Test overwrite inline styles""" html = '<style>h1,h2,h3 {color: #000;}</style><h1 style="color: #fff">Foo</h1><h3 style="color: #fff">Foo</h3>' desired_output = '<h1 style="color: #000; color: #fff">Foo</h1><h3 style="color: #000; color: #fff">Foo</h3>' output = Pynliner().from_string(html).run() self.assertEqual(output, desired_output)
def test_child_with_first_and_last_child_override_selector(self): html = """<p><span>Hello World!</span></p>""" css = """p > * { color: green; } p > :first-child:last-child { color: red; }""" expected = u"""<p><span style="color: red">Hello World!</span></p>""" output = Pynliner().from_string(html).with_cssString(css).run() self.assertEqual(output, expected)
def setUp(self): self.html = """<style>.b1,.b2 { font-weight:bold; } .c {color: red}</style><span class="b1">Bold</span><span class="b2 c">Bold Red</span>""" self.p = Pynliner().from_string(self.html)
def setUp(self): self.pyn = Pynliner(case_sensitive=False)