Skip to main content

PyTags is a small XML/HTML construction templating library for Python, inspired by JavaTags.

Project description

Pytags

Pytags is a small XML/HTML construction templating library for Python, inspired by JavaTags.

It can renders fragments like:

from pytagsup.html import *

html5(attr({'lang': "en"}),
  head(
    meta(attr({'http-equiv': "Content-Type", 'content': "text/html; charset=UTF-8"})),
    title(text("title")),
    link(attr({'href': "xxx.css", 'rel': "stylesheet"}))
  )
).render()

in html:

<!DOCTYPE html>
<html lang='en'>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
    <title>title</title>
    <link href='xxx.css' rel='stylesheet'/>
 </head>
</html>

Installation

Add this line to your application's Gemfile:

pip install pytagsup

Online converter

To convert html to Pytags format try online converter.

Usage

Import module pytagsup.html in your class.

from pytagsup.html import *

class Layout:  
  #...

Attributes:

You have different ways to use attributes.

Declarative

Using Python#Dictionary definition, i.e. {'name': "value"} in attr method.

attr({'class': "navbar", 'style': "border: 0;"})

Dynamic

An attribute can be built fluently with add method, using key-value or Attribute overload

(
  attr()
  .add({'class': "fa fa-up", 'xxx': "show"})
  .add({'style': "border: 0;"})
)
(	
  attr()
    .add(attr({'class': "navbar"}))
    .add(attr({'style': "border: 0;"}))
)

add method appends values if already defined for an attribute

attr({'class': "navbar"})
  .add({'class': "fa fa-up"})
  .add({'style': "border: 0;"})

renders

 class='navbar fa fa-up' style='border: 0;'

An attribute can be modified with remove method, using key-value, Attribute overload or key

attr({'class': ".some fa fa-up", 'xxx': "fa fa-up"})
  .remove({'class': "fa-up"})
  .remove({'xxx': "fa"})
  .remove({'xxx': "fa-up"})

renders

class='.some fa' xxx=''
attr({'class': ".some fa fa-up", 'xxx': "fa fa-up"}).remove('class')

renders

xxx='fa fa-up'

see unit tests for other examples

Layouts:

An example of page layout:

from pytagsup.html import *

class Layout:

  def __init__(self, title, body):
    self._title = title
    self._body = body
  
  def render(self):
    return (
      html5(
        head(
          meta(attr({'charset': "utf-8"})),
          meta(attr({'http-equiv': "X-UA-Compatible", 'content': "IE=edge"})),
          meta(attr({'name': "viewport", 'content': "width=device-width, initial-scale=1"})),
          title(text(self._title)),
          link(attr({'rel': "stylesheet", 'href': "/css/bootstrap.min.css"})),
          link(attr({'rel': "stylesheet", 'href': "/css/app.css"}))
        ),
        body(
          self._body,
          script(attr({'src': "/js/jquery.min.js"})),
          script(attr({'src': "/js/bootstrap.min.js"}))
        )
      ).render()
    )

An example of table using reduce:

data = [{ 'th1': "value1", 'th2': "value2" }, { 'th1': "value3", 'th2': "value4" }]
header = data[0].keys()

table(attr({'class': "table"}),
  thead(
    reduce(
      lambda tr, h: tr.add(th(text(h))),
      header,
      tr()
    )
  ),
  reduce(
    lambda tbody, record: tbody.add(
      reduce(
        lambda row, x: row.add(td(text(record[x]))),
        header,
        tr()
      )
    ),
    data,
    tbody()
  )
)

Element

Ruby-Tags defines Text, Void, NonVoid and Group elements (see W3C Recommendation).

Every tag method (e.g. html5, body and so on) is defined as method using a Void or NonVoid element in accordance with W3C Recommendation.

To avoid built-in shadowing builtins module must be used, e.g.

import builtins

div(*builtins.map(lambda t: p(text(t)), ['x', 'y', 'z']))

To render text use text method.

text("aaa")

To render list of Elements you can use dummy group method or directly unpack argument lists

...
l = builtins.map(lambda t: li(text(t)), ['a', 'b', 'c'])
ul(
  group(*l)
)

...
ul(
  group(*builtins.map(lambda x: li(text(x)), ['a', 'b', 'c']))
)
...

You can also use add method to add children/sibling to a NonVoid/Void element respectively, for example:

...
g = group()
for x in ['a', 'b', 'c']:
  g.add(li(text(x)))
...
	
ul = ul()
for x in ['a', 'b', 'c']:
  ul.add(li(text(x)))

Or in a builder/fluent syntax way:

(
  ul()
    .add(li(text("item 1")))
    .add(li(text("item 2")))
    .add(li(text("item 3")))	
)  
(
  div(attr({'class': "xxx"}))
    .add(span(text("content")))
    .add(p(text("other content")))
)

Elements are equal ignoring attribute order definition, for example:

def test_equality(self):
  div1 = NonVoid("div", Attribute({'a': "b", 'c': "d"}))
  div2 = NonVoid("div", Attribute({'c': "d", 'a': "b"}))

  assert div1 == div2

see unit tests for other examples

Development

After checking out the repo, run pytest to run the tests.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/manlioGit/pytagsup.

License

The package is available as open source under the terms of the MIT License.

Project details


Release history Release notifications | RSS feed

This version

0.1

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytagsup-0.1.tar.gz (9.2 kB view hashes)

Uploaded Source

Built Distribution

pytagsup-0.1-py3-none-any.whl (7.3 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page