Tuesday, August 30, 2016

Python zipfiles with the cloud is technologic

Working with zip files in Python is straight forward.

Write it

s3connection = self.get_s3_connection()
bucket = s3connection.get_bucket(aws_bucket_name)
k = Key(bucket)
k.key = key.name


Cut it, Paste it, Save it

import shutil
shutil.copyfile(self.src_zipfile, self.temp_zipfile)

Load it

zf = zipfile.ZipFile(zip_file)   # turn file into a zipfile object
zf.extractall(path=unpack_path)  # extract all files to path
files = glob.glob(os.path.join(unpack_path, 'list_*.txt'))  #glob glob
for files in files:
    # to stuff to the files here

Check it

# In a test case
zf = zipfile.ZipFile(zip_file)
files = glob.glob(os.path.join(unpack_path, 'list_*.txt'))

Quick - rewrite it

with open(some_file, 'r+') as file:
    #do file rewrite here

Now here's daftfunk - technologic

Wednesday, August 3, 2016

Tidbits on Python's virtualenv

Python being a mess that it is - *cough* Python 2 vs 3 *cough* - has a thing for virtual dev environments.

Virtual dev enviroments or virtualenv solves the mess by creating isolated dev environments. Each environment then can have it's own Python and lib versions, dependencies and even permissions and settings. Virtualenv is complimented by virtualenvwrapper.

This is all well and good, unfortunately, virtualenv + wrapper are terminal (command line) driven and I often forget the basic commands. Hence, this blog post:

Basic assumption here is that you've setup and configured virtualenv with virtualenvwrapper.

1. Make a new virtual environment with a specific version of Python: use the -p flag

mkvirutalenv -p [path-to-python] [project name]

example: mkvirtualenv -p /usr/bin/python project1

2. List all existing virtual environments; workon command without arguments also works

lsvirtualenv -b

-b flag = brief mode, disables verbose output

3. Delete or remove an existing virtual environment; only deletes environments found in the WORKON_HOME path

rmvirtualenv [env_name]

Virtual environment must be deactivated before removing.

4. Deactivate current active virtual environment



- Command ref for virtualenvwrapper
- Ref for virtualenv

Monday, August 1, 2016

Facebook not playing nice with Twitter in an Ionic app

This bug I encountered when my Ionic was logged in via Facebook. It caused my Twitter routine not to retrieve user timelines. My Twitter routine depends on a Application only login to get an Oauth token.

The symptom of my problem was when doing a call to api.twitter.com/oauth2/token and api.twitter.com/1.1/statuses/user_timeline.json, Angular's $http wasn't sending the correct header values and I kept getting invalid request (code 99) error from twitter.

POST https://api.twitter.com/oauth2/token HTTP/1.1
Authorization: Basic [base64 code here]
Content-Type: application/x-www-form-urlencoded;charset=UTF-8

The thing to focus here is the Authorization value. Instead of a base64 encoded value for Twitter, Facebook overwrites it or I can't overwrite it via a $http config object.

With the bug understood, I found the solution was to use a $httpProvider interceptor to modify the header before sending it to the server.

function AuthHeaderInterceptor($rootScope, $q, $location, localStorageService) {
    // Function to handle a request
    var request = function (config) {

        var expression = /(https?:\/\/(.+?\.)?api.twitter.com\/1.1\/statuses\/user_timeline.json(\/[A-Za-z0-9\-\._~:\/\?#\[\]@!$&'\(\)\*\+,;\=]*)?)/g;
        var regex = new RegExp(expression);
        var test_url = config.url;

            var authToken = localStorageService.get('twitter_token'); // get token from local storage
            config.headers.Authorization = 'Bearer ' + authToken;     // Force overwrite the Authorization header

        // Return our config
        return config;

    // Function to handle errors
    var responseError = function (rejection) {
        // Return our rejected promise
        return $q.reject(rejection);

    return {
        request: request,
        responseError: responseError

All that's left is to set this to my app config and I was good to go.