1
\$\begingroup\$

I have the following JSON:

{
  "items": [
    {
      "item": "abc",
      "status": "ready"
    },
    {
      "item": "def",
      "status": "ready"
    },
    {
      "item": "ghi",
      "status": "done",
      "items": [
        {
          "item": "ABC",
          "status": "ready"
        },
        {
          "item": "DEF",
          "status": "ready"
        },
        {
          "item": "GHI",
          "status": "done"
        }
      ]
    }
  ]
}

which I would like to convert to:

\begin{itemize}
    \item abc\hfill{}ready
    \item def\hfill{}ready
    \item ghi\hfill{}done
      \begin{itemize}
      \item ABC\hfill{}ready
      \item DEF\hfill{}ready
      \item GHI\hfill{}done
      \end{itemize}
\end{itemize}

The items can be nested arbitrarily deep. I have the following Python code:

import json
import os

TAB = '  '
BEGIN = '\\begin{itemize}'
ITEM = '\\item {0}\\hfill{{}}{1}'
END = '\\end{itemize}'

def main(path):
    with open(os.path.join(path, 'test.json')) as data_file:
        data = json.load(data_file)
    print('\n'.join(convert(data)))

def convert(data):
    stack = [data['items'].__iter__()]
    yield (TAB * (len(stack) - 1)) + BEGIN
    while len(stack) > 0:
        iterator = stack[len(stack) - 1]
        try:
            current = iterator.next()
            yield (TAB * (len(stack) - 1)) + ITEM.format(current['item'], current['status'])
            try:
                stack.append(current['items'].__iter__())
                yield (TAB * (len(stack) - 1)) + BEGIN
            except KeyError:
                pass
        except StopIteration:
            yield (TAB * (len(stack) - 1)) + END
            stack.pop()

I am new to Python and am looking for suggestions for the code to be more idiomatic Python.

\$\endgroup\$
3
\$\begingroup\$

Unless you specifically want a tab of 2 spaces in the resulting LaTeX, you can use '\t' to get the actual tab character.

TAB = '\t'

When working with strings with one or more backslashes, you can declare them as 'raw' strings by prefixing them with an r, which allows you to write backslash characters without having to escape them.

BEGIN = r'\begin{itemize}'
ITEM = r'\item {0}\hfill{{}}{1}'
END = r'\end{itemize}'

You can use the magic method iter() to get iterators, for example:

stack = [iter(data['items'])]

or

stack.append(iter(current['items']))

This is more idiomatic than calling the __iter__() method directly. In addition, there is a next() magic method as well which you can use to get the next item from an iterator.

current = next(iterator)

If you are using Python 3.4 or higher, I'd recommend checking out the pathlib module for manipulating file paths over os.path, but in this case using os.path does the job and is probably sufficient.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.