Zpretty - pt/html/xml prettifier

Hello everybody, I released zpretty, a tool for making xml-ish files look like if they were "PEP8-ified".

Given that many of you like PEP8, maybe you will also like zpretty :wink:

The main reason I developed this package is that I hate checking the diffs of this kind of files.

I am thinking to customized templates when you upgrade an add on (or Plone itself), generic setup files customized TTW that should me merged back in your package, merging refactored page templates, and so on.

If you "zprettify" the files you are diffing, the job is much easier.

The goal is achieved formatting the XML with properly 2space nested elements, with sorted attributes, one per line and with a reasonable logic (e.g. class comes first, then id, data-attributes are grouped, tal attributes are sorted by they order of execution, i.e. define, condition, ...)
Bonus for Plonistas: tal:defines definitions are formatted one per line and a trailing semicolumn is always added (so the next time you add a definition you will have a one line diff).

The tool is highly opinionated and for sure there are alternatives (tidy, xmllint) that produce prettier output, but they will not sort work on attributes as well as zpretty is doing.

Source code/issue tracker available here:

2 Likes

Yes, highly opinionated. The tool does not really improve the readability, it makes things worse. You can also argue
about the sorting of attributes. Personally I prefer a sorting where the tal:* attributes come first...it's also questionable if you want all attributes on a dedicated line...not my coding styles...but as (you) said: highly opinionated.

-aj

I still haven't tried, but I do really want something like that, specially for what you say: keep diff's easy to read.

Extra bonus would be to integrate it with plone.recipe.codeanalysis, so once you clean up all your files you are warned every time you change a template or xml and leave the file with an improper style (again so that diff's later on are easy to read).

Many thanks for sharing it!!

Thanks @zopyx for jumping in this thread.

The tool does not really improve the readability, it makes things worse.

The obtained readability looks good to me, at least in daily usage.
For sure it is far better than the one I sometimes find around.
Not everybody is using linters/prettifier for html, xml or pts and many times I find mixed indentation styles.

So I usually have better code when I use zpretty.

Before I was using an alias for:

tidy -xml -asxml -indent --indent-spaces 2 --indent-attributes y --wrap-attributes y --literal-attributes y --wrap 0

and it worked fine but was messing up the tal:defines attributes.

Do you have a source file example that is rendered in a poorly readable way?
Can you pass it to me so I can use it to improve the code.

Also: do you have some other tools that does a better job?

Personally I prefer a sorting where the tal:* attributes come first.

I read somewhere that designers like class to be the first one (do not ask me why).
Anyway sorting attributes in a different way can be easily controlled tweaking the parameters here:

it's also questionable if you want all attributes on a dedicated line

Attributes can be rendered in one line changing '\n' with ' ' here:

Adding a couple of command line switches and some code could easily adjust the behavior as you want.

Fact is that (I think you will easily agree with me) you do not want to have always attributes in one line.

TAL templates can have lots of attributes (it is called Template Attribute Language for some reason ;)).
Also regular HTML elements (e.g. "input") may have lots of attributes.

In order to produce a tool that works for everybody and in every case, some rules had to be decided.

I think the rules I decided were the best from my point of view.
Luckily, now the package is open sourced on github and published on PyPI (I added collective as a maintainer).

I am really open to listen for everybody opinion.

Thanks @gforcada!

Personally I would not enforce this kind of style.
There are many editors out there that pretend to justify XML code in different ways.
People will easily get annoyed.

Thanks @alert for sharing this.

I have to try it to integrate it in my vim setup - together with https://github.com/Chiel92/vim-autoformat

Regarding the indentation - as I understand it, you indent everythin by just 2 spaces.
Could you change it to fit the Plone style guide?

http://docs.plone.org/develop/styleguide/python.html#indentation

Quoting it:

Indentation of 2 characters to show nesting, 4 characters to list attributes on separate lines.
This distinction makes it easier to see the difference between attributes and nested elements.

See the attached example how such tools can affect readability. The one-line LINK statement now broken into six lines...single lines containing a quote char or closing brackets....no thanks.

Andreas

That's indeed an option worthy to add, I will open an issue on github.
Do you think the ZCML style guide should apply also to pt?

Ok, I see you do not like it.

Maybe the tal:attributes, when you are defining only one attribute can be in one line.
Maybe the ">" can be on the same line of the last attribute (I decided to put it there because it marks the indentation level of the element).

But indeed the output as it is now matches more my tastes, has shorter lines and reminds this coding style:

attributes = {
    'href': '...',
    'title': '...',
}

I like closing the dicts/tuples/lists on a new line and leaving a comma in the last element.
Again it allows you better diffs and looks more balanced to my eyes.

So it seems a matter of taste.
Personally I do not think I will change it, unless I see advantages in some other better option :slight_smile:

IMO yes - when indenting I personally stick with 4 lines indentation for attributes, 2 lines for nesting elements also for *.pt and *.html files.

Although @zopyx argument has also a point - I usually also try to write one-liners per element in pt/html files.

You should accept pull requests to make the result configurable...

Overall I agree with @thet - but that's not the point. Choice is important. That's the point.

I am working on this topic and today I released a version that gives an initial support for zcml files (0.9.1.1).

This is an example of zpretty (with the --zcml option) formatting a real life zcml (one of the longest I found):

Of course they are welcome!

Infact it is planned to make the program understand some flags.

Personally I do not see a widespread adoption of the ZCML style guide in templates (it is rarely used in zcml files also).
One liners make sense if you have "few" attributes.

Should we start splitting attributes on separate lines when the line gets longer than N characters?

Just give me rules and I will try to implement them!
For the moment thanks for you comments!

btw. even ZCML has a style guide https://zopetoolkit.readthedocs.io/en/latest/codingstyle/zcml-style.html

This is what I use to format zcml in sublime https://gist.github.com/jensens/4fc631616f5ef9ac4c6b (using xmlpp)

That is exactly the feature I added in the last release: being able to follow exactly the ZCML style guide :slight_smile:

Am I wrong or this is not fully compliant with the ZCML style guide: the tag will be closed aligned to the beginning of the start tag:

ale@emily:~/tmp/zope.formlib$ xml_pp -s indented_a src/zope/formlib/configure.zcml|tail
  <!-- TODO We need a widget for tuples (and sets, for that matter). -->
  <adapter
      factory=".source.SourceListInputWidget"
      for="zope.schema.interfaces.IList
  zope.schema.interfaces.ISource
           zope.publisher.interfaces.browser.IBrowserRequest"
      permission="zope.Public"
      provides="zope.formlib.interfaces.ISimpleInputWidget"
  />
</configure>

Compare this with:

 ale@emily:~/tmp/zope.formlib$ zpretty --zcml src/zope/formlib/configure.zcml|tail
  <!-- TODO We need a widget for tuples (and sets, for that matter). -->
  <adapter
      provides="zope.formlib.interfaces.ISimpleInputWidget"
      for="zope.schema.interfaces.IList
           zope.schema.interfaces.ISource
           zope.publisher.interfaces.browser.IBrowserRequest"
      factory=".source.SourceListInputWidget"
      permission="zope.Public"
      />

Note that the spaces in the for attribute are fixed correctly by zpretty and not by xml_pp.

Edit: as far as I can see xmpl_pp sorts the attribute alphabetically, zpretty can order it better (and this can be modified/improved as we want).

1 Like

The second variant is clearly more readable.

When it comes to sorting of attributes: again very personal and also depending and specific on the tag name.
E.g. for a browser:page 'name' and 'for' are most important, for an *adapter' I need to know about 'provides' and 'for first. When it comes to ZPT: TAL attributes are most important for me - in fact TAL attribute have an existing execution order. Attributes on one line or per-line....this all depends: never one-liner for ZCML, in ZPT I want at least one attribute per line for TAL and I18n attribute but no necessarily for standard HTML attributes...I am not even consistent my self in my own template. My personal guideline here is: must look good to me.

-aj

@zopyx it would be kind of you to upload files that currently are not covered in a branch or link them as gyst for example.
This folder contains some examples used in the tests:

About the attributes sorting, tal:attributes are sorted by precedence since the very beginning: it was one of the feature I did wanted absolutely.

and zcml attributes are sorted according to this (incomplete) list:

About the "must look good to me", well... this is hard :slight_smile:
In order to make code consistent among developers some compromise has to be found.