Robert Basic's blog

Install PyQt5 in Python 3 virtual environment

by Robert Basic on February 4th, 2015

It's been a while since I last made something with PyQt, so I decided to check out what's it like nowadays. I'm curious to see what's new in Qt5 and how does it differ from Qt4. Qt5 also can run under python 3 so I figured to give it a try.

Fedora 21 comes with both python 2.7 and python 3.4, but the default version is 2.7, which means if PyQt5 is installed through the package manager, it will be installed against 2.7. As I'm not currently in the mood of bricking my laptop by changing the default python version, I decided to install PyQt5 in a python virtual environment. Btw, Fedora 22 should have python 3 by default.

In the code samples below, assume the working directory is always ~/pyqt.

Create a virtual environment

First off, let's create a virtualenv with python 3.4:

virtualenv --python=python3.4 env

Activate the virtualenv and check the python version to verify:

source env/bin/activate
python --version

And that should print something like Python 3.4.1. Leave the virtualenv active, as that's where PyQt5 is going to be installed.

PyQt5 dependencies

Cool, now with that set up, let's get PyQt5 dependencies sorted out:

sudo yum install gcc gcc-c++ python3-devel qt5-base qt5-base-devel

As the documentation says, SIP must be installed before PyQt5. Lets grab the sources, configure and make and install them.

wget http://sourceforge.net/projects/pyqt/files/sip/sip-4.16.5/sip-4.16.5.tar.gz
tar xzf sip-4.16.5.tar.gz
cd sip-4.16.5
python configure.py
make
sudo make install
cd ..
rm -r sip-4.16.5*

Not sure why I had to do sudo make install. Verify sip is installed correctly by starting a python shell and typing in the following:

import sip
sip.SIP_VERSION_STR

That should show the sip version 4.16.5.

Installing PyQt5

All the dependencies should be met now, so let's install PyQt5.

wget http://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.4/PyQt-gpl-5.4.tar.gz
tar xzf PyQt-gpl-5.4.tar.gz
cd PyQt-gpl-5.4
python configure.py --qmake /usr/bin/qmake-qt5
make
make install
cd ..
rm -r PyQt-gpl-54*

This will install PyQt5 with the basic modules such as QtCore, QtWidgets and QtSql. Check the output of the python configure.py step to see what modules will be installed. If you need additional modules in your PyQt5 setup, you'll have to install additional Qt packages on your system. For example, to get the QtWebKit module, install the qt5-qtwebkit package through your package manager first.

Writing a basic PyQt5 app we can verify that it all works. Save the following as pyqt.py:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = QMainWindow()
    window.show()
    sys.exit(app.exec_())

Running it with python pyqt.py should start the application that's just one small window.

Happy hacking!

Tags: python, pyqt5, virtualenv.
Categories: Software, Development, Programming.

Configuring read-only and read-write access to bitbucket repos

by Robert Basic on January 30th, 2015

Trying to automate things on my server, I ended up needing read-only for one group of my bitbucket repos and read-write access to another group.

On bitbucket, if read-only access is required for a repository, a deployment key can be added for that repository.

Create one ssh key that will be a deployment, read-only key:

user@server$ ssh-keygen -f ~/.ssh/id_rsa_ro -t rsa -C "email@domain.com"

and add it to repositories needing read-only access.

Create a second ssh key that will be used for repositories needing read and write access:

user@server$ ssh-keygen -f ~/.ssh/id_rsa_rw -t rsa -C "email@domain.com"

and add it as an ssh key under your bitbucket account.

Next, configure ssh a bit, telling it what identity to use for what host by adding something like this to the ~/.ssh/config file:

Host bitbucket.org-ro
    HostName bitbucket.org
    IdentityFile ~/.ssh/id_rsa_ro

Host bitbucket.org-rw
    HostName bitbucket.org
    IdentityFile ~/.ssh/id_rsa_rw
Host 

With all that in place, for repositories where read-only access is needed, set the remote url for the origin like:

git remote set-url origin git@bitbucket.org-ro:user/repo_with_ro_access.git

and where read-write access is needed:

git remote set-url origin git@bitbucket.org-rw:user/repo_with_rw_access.git

Now for repositories with the bitbucket.org-ro hostname I have read-only access and for repositories with the bitbucket.org-rw hostname read and write access. Neat.

Tags: bitbucket, ssh, keys, setup.
Categories: Development.

Mocking hard dependencies with Mockery

by Robert Basic on December 23rd, 2014

One problem with unit testing legacy applications is that the code has new statements all over the place, instantiating new objects in a way that doesn't really makes it easier to test the code.

Of course, the easy answer to this is "Just refactor your application!", but that's almost always easier said than done.

If refactoring is an option, do it. If not, one option is to use Mockery to mock the hard dependencies.

One prerequisite to make this work is that the code we are trying to test uses autoloading.

Let's take the following code for an example:

<?php
namespace App;
class Service
{
    function callExternalService($param)
    {
        $externalService = new Service\External();
        $externalService->sendSomething($param);
        return $externalService->getSomething();
    }
}

The way we can test this without doing any changes to the code itself is by creating instance mocks by using the overload prefix.

<?php
namespace AppTest;
use Mockery as m;
class ServiceTest extends \PHPUnit_Framework_TestCase {
    public function testCallingExternalService()
    {
        $param = 'Testing';

        $externalMock = m::mock('overload:App\Service\External');
        $externalMock->shouldReceive('sendSomething')
            ->once()
            ->with($param);
        $externalMock->shouldReceive('getSomething')
            ->once()
            ->andReturn('Tested!');

        $service = new \App\Service();

        $result = $service->callExternalService($param);

        $this->assertSame('Tested!', $result);
    }
}

If we run this test now, it should pass. Mockery does it's job and our App\Service will use the mocked external service instead of the real one.

The problem whit this is when we want to, for example, test the App\Service\External itself, or if we use that class somewhere else in our tests.

When Mockery overloads a class, because of how PHP works with files, that overloaded class file must not be included otherwise Mockery will throw a "class already exists" exception. This is where autoloading kicks in and makes our job a lot easier.

To make this possible, we'll tell PHPUnit to run the tests that have overloaded classes in separate processes and to not preserve global state. That way we'll avoid having the overloaded class included more than once. Of course this has it's downsides as these tests will run slower.

Our test example from above now becomes:

<?php
namespace AppTest;
use Mockery as m;
/**
 * @runTestsInSeparateProcesses
 * @preserveGlobalState disabled
 */
class ServiceTest extends \PHPUnit_Framework_TestCase {
    public function testCallingExternalService()
    {
        $param = 'Testing';

        $externalMock = m::mock('overload:App\Service\External');
        $externalMock->shouldReceive('sendSomething')
            ->once()
            ->with($param);
        $externalMock->shouldReceive('getSomething')
            ->once()
            ->andReturn('Tested!');

        $service = new \App\Service();

        $result = $service->callExternalService($param);

        $this->assertSame('Tested!', $result);
    }
}

And that should be pretty much it. If nothing else, it should make parts of old code easier to test.

For anyone interested, I put the example code up on Github.

Tags: mockery, php, testing, unit tests.
Categories: Development, Programming.

Configuring the trackpad and touchpad behaviour for Thinkpad T540p on Fedora 21

by Robert Basic on December 22nd, 2014

This is the last post about the Thinkpad and Fedora. At least for a while. Promise.

With the new generation of Thinkpads, Lenovo decided to change the touchpad. They removed the 5 physical buttons from the touchpad area and left us with one bigger touchpad. To click anything it's now either touch click (two-finger click for right clicks) or one can push the entire touchpad down, the clickpad. The touchpad has different regions for getting left/middle/right clicks. Sort of.

And for the first time I completely agree with reviews on the internet. This thing is horrible.

If you want both the touch and push clicks, forget it. It just won't be usable how inaccurate this thing is. If the touch click is turned on, it will get in the way of your typing. You forget yourself and do a push click with the touch click enabled? Here's some double/triple click for you. Just don't even bother with the touch click, turn it off.

You're left now with the trackpad and touchpad for movement, and the clickpad for clicks. Again, pain. You push down the touchpad to click aaand... Good luck and I hope you clicked the thing you wanted. Your finger will move, just a little bit and so will the cursor. And here's the kicker. Touchpad movements can't be turned off. At least not in a easy and intuitive way.

After quite some time searching the internet for a fix, I found a forum post explaining how to get this thing usable (sadly, I can't find that post again to link to it):

Section "InputClass"
    Identifier "TrackPad with buttons only"
    MatchDriver "synaptics"
    Option "SoftButtonAreas" "65% 0 0 0 50% 65% 0 0" # emulate right and middle buttons
    Option "AreaBottomEdge" "1" # disable moving but not buttons
EndSection

Save this as 99-thinkpad-clickpad.conf in /etc/X11/xorg.conf.d/. The touch parts of the touchpad are disabled so we have the trackpad for movements and the clickpad for buttons. I just need to tweak the left/middle/right button clicks a bit more, because there are times when I accidentally do a middle click.

Oh, and now there's no mouse scroll because that's touchpad only.

Tags: t540p, thinkpad, laptop, fedora, touchpad, clickpad, trackpad.
Categories: Blablabla, Software.

Battery charge thresholds for Thinkpad T540p on Fedora 21

by Robert Basic on December 19th, 2014

This week I got myself a new laptop, a Thinkpad T540p. One of the features it has is that the battery's life can be prolonged by setting custom charging thresholds.

The start charge threshold tells the battery to start charging only when the charge drops bellow that limit, and the stop charge threshold tells the battery to stop the charging when the upper limit is reached. I set the start threshold to 40% and the stop threshold to 70%. I think this should be good enough for me as I mainly use my laptop at home where it's always plugged in.

After a bit of a digging around, I managed to get it working under Fedora 21.

The main thing to know is that there is tp_smapi for older Thinkpad's, and tpacpi-bat for the newer ones. I have a T540p so it's the latter for me.

There is also tlp, but at the moment I couldn't get it to work completely because it has no packages for Fedora 21 yet. Fedora 20/19 should be OK though, and for those I would probably go with tlp.

After git cloning the repository, run the install perl script, and if all went OK, set the start threshold like:

./tpacpi-bat -s ST 1 40

and the stop threshold:

./tpacpi-bat -s SP 1 70

Where 1 is the battery number, starting from 1, and 40 and 70 are the start and the stop thresholds in percentage.

These settings should remain after a reboot, but what I noticed is that they are gone after taking out and putting the battery back in. When I tried to set the threshold parameters again, I couldn't do it as the system was complaining about the missing acpi_call kernel module. I re-run the perl install script from tpacpi-bat and got it working again.

I'll be on the lookout for the tlp packages for Fedora 21, that looks like it would work nicer than this.

Now the only last bit I'm missing is the battery cycle count, but seems current kernels don't support it yet.

Tags: fedora, laptop, thinkpad, t540p, tpacpi-bat, battery.
Categories: Software, Development.