Running a specific test in nose2

Today I needed to run a specific nose2 test case to fix an error. This can be achieved the following ways.

My test cases are located in project/tests.

To run all the test cases in a test.

nose2 project.tests.test_file

To run a specific test case in a test.

nose2 project.tests.test_file.TestCase.test_method

That’s it. Happy coding.

Advertisements

Flask error loading config file in instance directory

I have been dealing with a really frustrating problem today. Yesterday my code was working and today it was failed without any code changes.

This is the piece of code causing the problem.

app = Flask(__name__, instance_relative_config=True)
app.config.from_object('config')
app.config.from_pyfile('config.cfg')

And this is the error.

Traceback (most recent call last):
  File "run.py", line 1, in 
    from project import app
  File "C:\Python27\env\vod_test\src\project\__init__.py", line 37, in 
    load_config()
  File "C:\Python27\env\vod_test\src\project\__init__.py", line 33, in load_config
    app.config.from_pyfile('config.cfg')
  File "C:\Python27\env\vod_test\lib\site-packages\flask\config.py", line 129, in from_pyfile
    with open(filename) as config_file:
IOError: [Errno 2] Unable to load configuration file (No such file or directory): 'C:\\Python27\\env\\vod_test\\var\\project-instance\\config.cfg'

Flask is trying to load the config file from C:\\Python27\\env\\vod_test\\var\\project-instance\\config.cfg instead of from C:\\Python27\\env\\vod_test\\project\\instance\\config.cfg. Where is the var coming from? And why is there a hyphen between project and instance?

The strange thing was that the problem only occurred when I was running my test cases from the command line. In PyCharm the code was working. How frustrating. It turned out that PyCharm was using a different virtualenv than the command line. After comparing the output of ‘pip freeze’ I discovered that some libraries had different versions.

To solve the problem I added the following code.

import os
from flask import Flask


def load_instance_config_fix(filename):
    config = {}
    with app.open_instance_resource(filename) as f:
        for line in f:
            if line[0] == "#":
                continue
            name, value = line.partition("=")[::2]
            config[name.strip()] = value.strip()
    return config


def handle_incorrect_instance_path(f):
    def handle_load_instance_config():
        try:
            f()
        except IOError:
            app.instance_path = os.path.join(os.path.abspath(os.curdir), 'instance')
            config = load_instance_config_fix('config.cfg')
            app.config.update(config)

    return handle_load_instance_config


@handle_incorrect_instance_path
def load_config():
    app.config.from_object('config')
    app.config.from_pyfile('config.cfg')


app = Flask(__name__, instance_relative_config=True)

load_config()


@app.route('/')
def hello_world():
    return 'Hello, World!'

Just some nice syntactic sugar with a decorator to keep the code nice and concise.

Another way to solve the problem is by setting the instance_path when initializing Flask. What fun would that be 🙂

import os
from flask import Flask


app = Flask(__name__, instance_path=os.path.join(os.path.abspath(os.curdir), 'instance'), instance_relative_config=True)
app.config.from_object('config')
app.config.from_pyfile('config.cfg')


@app.route('/')
def hello_world():
    return 'Hello, World!'

Back to real coding 🙂

Test API webhooks from localhost

To test the Mollie payment API on my localhost I needed a way to receive the webhook callback on my localhost. To be able to do this I needed a service to tunnel a public URL to localhost (my local machine, as opposed to a publicly accessible URL). Here are few examples of services that provide this service:

ngrok (free plan)

localtunnel (free)

pagekite

forwardhq

These types of tools give you a publicly accessible URL that forwards the request to the localhost port, which can be used for the API callback URL while testing.

Create a new project in PyCharm based on an existing virtualenv

Today I cloned a project from Github and needed to setup a project in PyCharm for it. These are some quick notes how to setup a new project in PyCharm based on an existing virutalenv.

  1. Clone the project with: git clone <URI>.
  2. Open PyCharm.
  3. Create a new project: File -> New project…
  4. Select project type: python
  5. Click create.
  6. Select the root directory of the virtualenv.
  7. Select local type by clicking the button behind the source field.
  8. From the Scripts directory of the virtualenv select python.exe.
  9. Clicke create.
  10. PyCharm will display a message that the directory is not empty (“The directory <…> is not empty. Would you like to create a project from the existing source instead?”).
  11. Click Yes.
  12. Select File -> Settings…
  13. Select Project […] -> Project Structure.
  14. Delete current source directory.
  15. Add the source directory in the virtualenv.
  16. Click OK.

You’re ready to rock. Have fun!

 

Marshmallow not respecting ordered=True

I had a little fight with Marshmallow and the ordered=True in class Meta. When ordered=True is set the fields should be outputed in the order specified in the property fields of the class Meta.

Example:

class AuthorSchema(ma.Schema):
    id = base_fields.Int(dump_only=True)

    absolute_url = ma.AbsoluteURLFor('api.author', id='<id>')

    links = ma.Hyperlinks({
        'self': ma.URLFor('api.author', id='<id>'),
        'collection': ma.URLFor('api.authors')
    })

    @post_dump(pass_many=True)
    def wrap(self, data, many):
        key = 'authors' if many else 'author'
        return {
            key: data
        }

    class Meta:
        fields = (
            'id',
            'name',
            'links',
            'absolute_url',
        )
        ordered = True

This was the output.

{
  "author": {
    "absolute_url": "http://localhost:8080/api/v4/authors/123",
    "id": 123,
    "links": {
      "collection": "/api/v4/authors/",
      "self": "/api/v4/authors/123"
    },
    "name": "Fred Douglass"
  }
}

After some Googeling I found out that the culprit was Flask.jsonify. It orders output alphabetically by default. The following setting switches this off.

app.config['JSON_SORT_KEYS'] = False

After this the output was in the specified order.

{
  "author": {
    "id": 123,
    "name": "Fred Douglass",
    "links": {
      "self": "/api/v4/authors/123",
      "collection": "/api/v4/authors/"
    },
    "absolute_url": "http://localhost:8080/api/v4/authors/123"
  }
}

Hope this saves someone else time.

Changing location of virtual environments breaks virtualenvwrapper-win

Today I wanted to move the location of my virtual environments to Dropbox. Makes life easier if I ever have to change computers. I moved the directory that contains the virtual environments and set the system variable WORKON_HOME to the new location. Then I tried it out. Activating the virtual environment with command workon worked just fine. Then I wanted to switch to the virtual environment with the command cdvirtualenv and it failed with an error saying that the location did not exist.

Puzzled I checked the system variables with the command set (I’m running Windows 10) and I noticed the system variable VIRTUAL_ENV that was pointing to the old location. I checked my variable settings under “System” → “Advanced system settings” → “Environment Variables” and could not find it there. Which meant it was being set somewhere when activating the virtual environment. After searching all the virtualenvwrapper-win scripts I could not find “SET VIRTUAL ENV=”. Then I noticed that the “workon.bat” file called “activate.bat” located in the script directory of the virtual environment. Here I found the “SET VIRTUAL ENV=” which contained a hard coded location, which was the old WORKON_HOME location as the virtual environment already existed.

To fix the problem I had to change this line of each “activate.bat” file manually. After that it worked like a dream. Problem solved!

By the way this isn’t a virtualenvwrapper-win problem, but a virtualenv problem.

UPDATE 4-1-2017

During a little break laying in the bath I came up with a much quicker and easier approach to solving the problem… Creating a symbolic link from the old location to the new location.

Just fire up a console with administrator rights and execute the following command.

mklink /d <old directory location> <new directory location>

Hmmmmm, that was quick 🙂