Using React for parts of a Flask App

Background:

As a part of my work, I needed a console like viewer in a web application (like the one used in travis.ci). The frontend is simply Bootstrap 3 and some jQuery JavaScript. I have written a rudimentary one using Bootstrap’s Panel and List Groups and using the helper classes to style them. But the application has grown and it is time we got a really good log viewer.

Requirements:

  • The library should be easy to include in the project without requiring a complete overhaul of the frontend. (Things like Angular, Ember are out)
  • We might decouple the app into a REST API and frontend sometime in the future, so it needs to provide a upgrade path for the full frontend.
  • To me, a Python programmer, it should be easy to get started and start building, without enforcing specific new requirements.
    (e.g., Angular forces TypeScript, I am willing to learn, just not now, not for this one)

React with JSX syntax, the ability to just drop the the library and use it for only selective parts of the app seemed just right. After trying out the tic-tac-toe tutorial, I ventured to setup it for our project.

Setting up the development environment

JSX is not plain native Javascript. Even-though I could include the React and ReactDOM libraries using the script tags, I have to setup a node.js based environment to compile the JSX into JS.

Project file structure

The Flask app has a typical structure as show below

-- project/
    |-- flask_app/
    |   |-- static/
    |   |   |-- js/
    |   |   |-- css/
    |   |   |-- images/
    |   |-- tempaltes/
    |   |-- __init__.py
    |   |-- application.py
    |   |-- views.py
        ...
    |-- run.py
    |-- .gitgnore
    |-- README

Setting up React’s requirements

React’s Adding React to an Existing Application lists three requirements – a package manager, a bundler and a compiler. I used npm for package manager, Webpack for bundler and Babel for the compiler. Here are the steps for the setup:

  • Create the package.json file using npm init inside project directory.
  • Create a new directory named ui insdie the project to hold the React JSX files
  • Install the packages react, react-dom using npm install --save
  • Install the packages webpack, babel-core, babel-loader, babel-preset-env, babel-preset-react using npm install --save-dev
  • Add the line "build": "webpack --config webpack.config.js" to the scripts block of package.json
  • Create file .babelrc with a single line {"presets": ["react", "env"]}
  • Create file webpack.config.js with the contents
const path = require('path');

module.exports = {
    entry: './ui/logger.js',  // logger.js is where I plan to write the JSX code
    output: {
        path: path.resolve(__dirname, 'flask_app/static/js/'),
        filename: "logger.js"
    },
    module: {
        rules: [
            { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
        ]
    }
}

Here is what I have done so far:

  • I have initiaed the project with package.json to manage things like requirements for the JS files, run npm commands, …etc. I guess this is like the setup.py of Python world.
  • Added the required packages
  • Configured Babel compiler to use the presets required for React to compile
  • Configured Webpack to read the ui/logger.js file and compile it using Babel and put it the Flask app’s static/js/ folder so that it can be used in the Jinja templates using url_for('static', filename='logger.js')
  • Configured NPM so that npm run build would run webpack to compile and put the file in static folder.

New Project structure

After adding everything, this is how the project looks

-- project/
    |-- flask_app/
    |   |-- static/
    |   |   |-- js/
        ...
    |-- run.py
    |-- .gitgnore
    |-- README
    |-- node_modules/
    |-- ui/
    |   |-- logger.js
    |-- .babelrc
    |-- webpack.config.js
    |-- package.json

With the above setup, I am good to go. All I need to do is add a script tag with src pointed to the logger.js. With everything setup,

  • I added a small JSX snippet to ui/logger.js
  • ran npm run build (the file compiled and was put in the static/js/ folder)
  • started the Flask development server python run.py
  • loaded the app in the browser.

Everything worked as expected.

..except it didn’t the second time

Now I changed the code in ui/logger.js > ran npm run build > reloaded the page in browser. Nothing changed. Now we have a problem. It’s the browser caching the output static/js/logger.js file.

Solving Caching issue

While Caching is good from a client’s point of view, it is a little tricky in a development environment. If we were building a full blown React app using the react-cli, we won’t have this issue as the react-scripts would watch the file changes and reload the browser for us. In the current setup using Flask’s development server, however, we need to take care of it ourselves. Webpack to the rescue.

Webpack optimizations

I followed Webpack’s Caching guide and applied everything suggested. Now the webpack.config.js looks like this:

const webpack = require('webpack');
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');


module.exports = {
    entry: {
        main: './ui/logger.js',
        vendor: [
            'react', 'react-dom'
        ]
    },
    output: {
        path: path.resolve(__dirname, 'flask_app/static/build'),
        filename: "[name].[chunkhash].js"
    },
    module: {
        rules: [
            { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(['flask_app/static/build']),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor'
        }),
        new webpack.optimize.CommonsChunkPlugin({
            name: 'runtime'
        }),
    ]
}

This is what the updated webpack config does:
– instead of saving the generated Javascript as a single file called logger.js it splits the output into three files named
* main.[chunkhash].js which contains the compiled ui/logger.js
* vendor.[chunkhash].js which contains the libraries listed in entry.vendor
* runtime.[chunkhash].js which contains the Webpack’s runtime logic to load the files generated

Note: the chuckhash is a value that webpack substitutes when generating the files. This changes with the changes in entry files. So we have a different filename in the output with every build, thus avoiding the caching issue.

  • the CleanWebpackPlugin removes all the files in the output directory before generating new files so we don’t have outdated files like main.hash1.js, main.hash2.js.. etc.,
  • since static/js folder has other files like bootstrap, jquery ..etc., So the output.path is set to a new directory static/build, to prevent the Clean Webpack plugin from deleting them.

With the above config, we will have a different filename everytime we build using npm run build. Now the file cached by the web browser is not used as the new filename is different from the old one.

But how do we use the latest filenames in the “ tag in the Jinja templates?

There is a plugin to solve this issue called Flask-Webpack, but I felt it too be an overkill.

Flask Context Processor to get the hashed filename

Add the following context processor to the Flask app:

@app.context_processor
def hash_processor():
    def hashed_url(filepath):
        directory, filename = filepath.rsplit('/')
        name, extension = filename.rsplit(".")
        folder = os.path.join(app.root_path, 'static', directory)
        files = os.listdir(folder)
        for f in files:
            regex = name+"\.[a-z0-9]+\."+extension
            if re.match(regex, f):
                return os.path.join('/static', directory, f)
        return os.path.join('/static', filepath)
    return dict(hashed_url=hashed_url)

This provides a function called hashed_url which looks for the file and returns its hashed form. Now we can add the files using script tags as below:

<scrip.t src="{{ hashed_url('build/runtime.js')></script>
<scrip.t src="{{ hashed_url('build/vendor.js')></script>
<scrip.t src="{{ hashed_url('build/main.js')></script>

The hashed_url would match the filename passed to it with the the files in the directory and returns the hashed form. For e.g., hashed_url("build/main.js") returns /static/build/main.16f45d183a4c0f0b1b37.jss

Conclusion

The whole process of setting this up took multiple hours of research and testing. I could have used one of the available boilerplates to set this up, but I now have it in the form I want it and I understand what the different parts mean and do. It lets me use React for small components as required and grow as the project grows. It also creates no disruption in the workflow of other developers. Happy coding time ahead 🙂

Python mock – Handling namespaces

Unit testing a big python application comes with its own set of worries which includes mocking calls to parts of code which we will test somewhere else.

Let us say I have a **utils.py** (every project has one anyways)

# utils.py
def word_length(name):
    # here it is a trivial function
    # assume that this is a costly network/DB call
    return len(name)

 
And I have another module which uses word_length using the from module import function syntax.

# user.py
from project.utils import word_length

def calculate(name):
    length = word_length(name)
    return length

Now I want to unit test all the functions in **user.py** and since I am going to test just the user module and want to avoid costly calls made by my utils module I am going to mock out calls to `word_length` using Python mock library.

# test_user.py
from project.user import calculate

from mock import patch

@patch('project.utils.word_length')
def test_calculate(mock_length):
    mock_length.return_value = 10
    assert calculate('hello') == 5

One would expect this assertion to fail because we have mocked out the word_length to return 10. But this passes and our mock is not working. Why? Because **NAMESPACE**. Here we have patched the function in the namespace utils. But we have imported the function to the user.py namespace by using `from module import function`. So we need to patch the function in the user namespace where it is used and not in the utils where it is defined. So change the line


@patch('project.utils.word_length')

# to

@patch('project.user.word_length')

But what if we have used simply like

# user.py
import utils

def calculate(name):
    length = utils.word_length(name)
    return length

This time we can straight away use the @patch('project.utils.word_length') as we are importing the entire module and namespace remains as such.

Python Pitfalls

I was woken up today with the following question:
[python]
def foo(x=[]):
x.append(1)
return x

>>> foo()
>>> foo()
[/python]

What could be the output? The answer is

[1]
[1, 1]

I was stupefied for a minute before I started DuckDuckGo-ing Python default arguments, Python garbage collection, Python pitfalls..etc.,

These links helped me understand mutable objects’ memory management.
Deadly Bloody Serious – Default Argument Blunders
Udacity Wiki – Common Python Pitfalls
Digi Wiki – Python Garbage Collection

Travis CI config for Python + NodeJS

I currently work with the Gluu Federation – an open source company. My present job is to build a Web UI for the cluster management using the available API.

We use Python Flask for the Backend and AngularJS+Bootstrap for the Frontend. Pretty much a standard affair these days. Testing is crucial and we have the backend tests in Python Nose and the Frontend Unit tests using Karma and Jasmine running on NodeJS.

Now the question is how does one configure the Travis CI .yml file to perform tests in a both Python and Javascript. I initially set up using language: node_js and ran only the frontend tests. Then I went around searching and stumbled on travis-ci – issue#4090 – Support multiple languages. Thanks to the tip from @BanzaiMan I now have both frontend and backend tests running with a simple yml file.

Getting ready for planet CODE

With the end of TeachForIndia Fellowship around the corner, I am contemplating on jumping into the programming world. So here is a checklist of things that I am going to put up in place and document it along the way.

Get a decent mail ID

Though not strictly related to planet code, I wanted to have a decent email id. The one I used ~~aruntheguy at gmail~~ was created when I was 15 and not so professional. Hence I have moved the mail to arunmozhi.in.

Creating a online presence

These days online presence is mostly Social Media. I deleted my Facebook account and have only Twitter, but that alone isn’t sufficient.

So,
Moved blog from static-site Pelican back to wordpress for easy theming and maintanence
Created a home page where I can showcase stuff

Customer Research

Making use of a skillset is all about selling it. So what do the buyers look for? Being a follower of Coding Horror I started of with his post on How to hire a programmer.

Here are the things I learnt:
1. Know to really write a program – I pass
2. Should have a portfolio – Need to create a portfolio page
3. Be culturally fit for the role – Depends on the company
4. Answer computer science theoritical/tricky/nerdy qustions – Well you can’t really prepare for them, can you? May be the theory part, but again when was the last time I thought about hash tables, 3rd year of my college?
5. Expect an audition project or a real world problem to solve.
6. Pitch in front of small group – have mixed feelings about this. But good to know this might be coming.

1 is done, 2 requires some work, 3 can’t really be worked on, 4 is subjective on how we look at it, solving puzzles and learning nerdy jokes is not the point, it shows the recruiter how we approach a problem and how much passionate about programming is a person. I will leave them at that. Finally, the points 5 and 6 are subjective to personal preference and circumstances as outlined in the comments by various people. I am sort of going to forget them for now.

Product preparation

I am the product, in case you are wondering. The article cited above and others linked in that article give a general idea about the product.
With that in mind, and my long time personal goals, here is the list of things I have in mind to do:

  1. Learn touch-typing!! Yeah, I am a pecker – albeit a fast one. – Done
  2. Learn Vim to the extent I am not going into v mode everytime to delete a set of words. – Ever learning
  3. Get core commit rights for QGIS – its time to work on itCouldn’t fit in time.
  4. Create a Portfolio/Resume/HireMe page
  5. Learn some tools of trade:
    • Plain text manipulations – Regex
    • Shell scripting
    • Code Editor – Vim
    • Version Control – Git + Github
    • Debugging Tools
    • Unit Testing Frameworks
  6. …….

I guess I will add more to the list as I set the goals. For now this should keep me focused.

Apparix – Bookmarking in terminal

When working in a large code base like Quantum GIS or when dealing with a lot of repositories in the machine, it is always tedious to cd all the way to the folder we require to move to. Enter apparix, an excellent linux tool I found by googling “bookmarking in the terminal”. This blog post has the complete details of how to use it.

Yay, no longer cd goto/project/src/core/of/module1 and again cd ../../../test/number/three. I can simply do

$ bm projectsrc
$ bm test3
$ bm fancypants4

to bookmark my locations and simply

$ to projectsrc
$ to test3
$ to fancypants4

One more tool added in the arsenal to improve productivity.

Unit Testing with CasperJS

Today I sat down to create a JavaScript library. I wanted to do it the way I have long dreamed of – TDD (Test Driven Development). There is no dearth of Unit testing libraries and frameworks for JavaScript, so after some reading on the internet settled on CasperJS and PhantomJS combination. CasperJS is just awesome for functional testing, but Unit testing? Even though it supports Unit Testing, it as such is not a dedicated unit testing framework like Karma or Protractor. Read this for more information on TTD frameworks for JS libraries.

Loading plain JavaScript files in CasperJS for unit testing seems to be completely undocumented. I tend to think it is because it wasn’t meant to be webpage-less. But the note on docs of tester module says:

The best way to learn how to use the Tester API and see it in action is probably to have a look at CasperJS’ own test suites.

Thanks for this quote, I found that using the fs module one can load local filesystem files as modules to be used. Using that now I could write unit tests while developing the library and later on write functional tests while using the library.

Here is the file structure

library
--test
  |--unit
  |--test.js
  |--index.html
--src
  |--livetransit.js

And here is are the two tests – i) uses a webpage based approach; ii) uses module approach
https://gist.github.com/tecoholic/937f51b6889448836db8