pynt: a lightweight build tool, written in Python

Problem
I mainly work under Linux and when I write a Python program, I don’t care if it runs on other platforms or not. Does it work for me? Good :) So far I haven’t really used any build tools. If I needed something, I solved it with a Bash script.

However, a few weeks ago I started to work on a larger side project (JiVE Image Viewer) and I wanted to make it portable from the beginning. Beside Linux, it must also work on Windows (on Mac I couldn’t try it).

Now, if I want to automate some build task (e.g. creating a standalone executable from the project), a Bash script is not enough as it doesn’t run under Windows. Should I write the same thing in a .bat file? Hell, no! Should I install Cygwin on all my Windows machines? No way! It’s time to start using a build tool. The time has finally come.

Solution
There are tons of build tools. I wanted something very simple with which I can do some basic tasks: run an external command, create a directory, delete a directory, move a file, move a directory, etc. As I am most productive in Python, I wanted a build tool that I can program in pure Python. And I wanted something simple that I can start using right away without reading tons of docs.

And this is how I found pynt. Some of its features:

  • easy to learn
  • build tasks are just python funtions
  • manages dependencies between tasks
  • automatically generates a command line interface
  • supports python 2.7 and python 3.x” (source)

Just create a file called build.py in your project’s root folder and invoke the build tool with the command “pynt“.

My project is in a virtual environment. First I installed pynt in the virt. env.:

$ pip install pynt

Here you can find an example that I wrote for JiVE.

Advertisements
Categories: python Tags: , , ,

Convert a nested OrderedDict to normal dict

Problem
You have a nested OrderedDict object and you want to convert it to a normal dict.

Today I was playing with the configparser module. It reads an .ini file and builds a dict-like object. However, I prefer normal dict objects. With a configparser object’s “._sections” you can access the underlying dictionary object, but it’s a nested OrderedDict object.

Example:

; preferences.ini

[GENERAL]
onekey = "value in some words"

[SETTINGS]
resolution = '1024 x 768'
import configparser
from pprint import pprint

config = configparser.ConfigParser()
config.read("preferences.ini")
pprint(config._sections)

Sample output:

OrderedDict([('GENERAL', OrderedDict([('onekey', '"value in some words"')])),
             ('SETTINGS', OrderedDict([('resolution', "'1024 x 768'")]))])

Solution
JSON to the rescue! Convert the nested OrderedDict to json, thus you lose the order. Then, convert the json back to a dictionary. Voilá, you have a plain dict object.

    def to_dict(self, config):
        """
        Nested OrderedDict to normal dict.
        """
        return json.loads(json.dumps(config))

Output:

{'GENERAL': {'onekey': '"value in some words"'},
 'SETTINGS': {'resolution': "'1024 x 768'"}}

As you can see, quotes around string values are kept by configparser. If you want to remove them, see my previous post.

I found this solution here @ SO.

Using ConfigParser, read an .ini file to a dict and remove quotes around string values

Problem
In Python you can read .ini files easily with the configparser module.

An .ini file looks like this:

[OPTIONS]
name = Jabba

As you can see, string values are not quoted. However, for me it looks lame. IMO a string must be between quotes or apostrophes. With quotes you can also add whitespace characters to the beginning or the end of a string. So I prefer writing this:

[OPTIONS]
name = "Jabba"

But now quotes become part of the string. If you read it with configparser, the value of name is '"Jabba"' instead of 'Jabba'.

Solution
When using configparser, it builds a dict-like object. I prefer to work with normal dictionaries. So first I read the .ini file, then convert the configparser object to dict, and finally I remove quotes (or apostrophes) from string values. Here is my solution:

preferences.ini

[GENERAL]
onekey = "value in some words"

[SETTINGS]
resolution = '1024 x 768'

example.py

#!/usr/bin/env python3

from pprint import pprint
import preferences

prefs = preferences.Preferences("preferences.ini")
d = prefs.as_dict()
pprint(d)

preferences.py

import sys
import configparser
import json
from pprint import pprint

def remove_quotes(original):
    d = original.copy()
    for key, value in d.items():
        if isinstance(value, str):
            s = d[key]
            if s.startswith(('"', "'")):
                s = s[1:]
            if s.endswith(('"', "'")):
                s = s[:-1]
            d[key] = s
            # print(f"string found: {s}")
        if isinstance(value, dict):
            d[key] = remove_quotes(value)
    #
    return d

class Preferences:
    def __init__(self, preferences_ini):
        self.preferences_ini = preferences_ini

        self.config = configparser.ConfigParser()
        self.config.read(preferences_ini)

        self.d = self.to_dict(self.config._sections)

    def as_dict(self):
        return self.d

    def to_dict(self, config):
        """
        Nested OrderedDict to normal dict.
        Also, remove the annoying quotes (apostrophes) from around string values.
        """
        d = json.loads(json.dumps(config))
        d = remove_quotes(d)
        return d

The line d = remove_quotes(d) is responsible for removing the quotes. Comment / uncomment this line to see the difference.

Output:

$ ./example.py

{'GENERAL': {'onekey': 'value in some words'},
 'SETTINGS': {'resolution': '1024 x 768'}}

I also posted this to SO (link here).

JiVE: A general purpose, cross-platform image viewer with some built-in NSFW support, written in Python 3.6 using PyQt5

In the past 2-3 weeks I’ve been working on a general purpose, cross-platform image viewer that has some built-in NSFW support. It’s called JiVE and it’s in Python 3.6 using PyQt5. A unique feature of JiVE is that it allows you to browse online images just as if they were local images.

You can find it on GitHub: https://github.com/jabbalaci/JiVE-Image-Viewer. I also wrote a detailed documentation.

Screenshots

In action:

jive.png

Selecting an NSFW subreddit:

nsfw.png

Read the docs for more info.

install PyQt5

The following is based on this YouTube video.

$ sudo apt install python3-pyqt5
...
$ python3
>>> import PyQt5
>>>
=======================================================================
$ sudo apt install python3-pyqt5.qtsql
...
$ python3
>>> from PyQt5 import QtSql
>>>
=======================================================================
$ sudo apt install qttools5-dev-tools
...
$ ls -al /usr/lib/x86_64-linux-gnu/qt5/bin/designer
lrwxrwxrwx 1 root root 25 ápr   14 09:38 /usr/lib/x86_64-linux-gnu/qt5/bin/designer -> ../../../qt5/bin/designer

I put a symbolic link on designer to launch it easily.

Categories: PyQt5, python

word cloud generator

March 12, 2018 Leave a comment
Categories: python Tags:

unzip: perform the opposite of zip

March 8, 2018 Leave a comment

zip

>>> a = [1, 2, 3]
>>> b = ["one", "two", "three"]
>>> zip(a, b)
<zip object at 0x7fd30310b508>
>>> list(zip(a, b))
[(1, 'one'), (2, 'two'), (3, 'three')]

unzip
How to perform the opposite of zip? That is, we have [(1, 'one'), (2, 'two'), (3, 'three')], and we want to get back [1, 2, 3] and ["one", "two", "three"].

>>> li
[(1, 'one'), (2, 'two'), (3, 'three')]
>>> a, b = zip(*li)
>>> a
(1, 2, 3)
>>> b
('one', 'two', 'three')

Notice that the results are tuples.

More info here.

Categories: python Tags: ,