DEV Community

Cover image for Programming while offline with Python
Jorge Alberto Díaz Orozco (Akiel)
Jorge Alberto Díaz Orozco (Akiel)

Posted on • Edited on

Programming while offline with Python

I live in Cuba. I've lived in Cuba since I was born and Cuba (believe me) is like kryptonite for software developers. Being one of the contries with less internet penetration (only 32.5% of the population has access to the internet) and having really high internet prices compared to average monthly income makes it really hard to be connected most of the time. Want more details? Check this OONI's report
Nevertheless, we have great universities, and thousands graduate every year on thechnology careers. I was one of those. And one of the things that hits me harder is having sometimes to work with online resources with so poor or and expensive internet access, and since I love to code with Python, here is what I did.
I was coding a project where I needed to get some data from a service online and it was annoying since I was doing something as ugly and unmaintainable as:

def doit():
    return 'false response'

    text_from_internet = get_data()
    return text_from_internet
Enter fullscreen mode Exit fullscreen mode

And when I finally was online and going to test my work I commented the false return:

def doit():
    # return 'false response'

    text_from_internet = get_data()
    return text_from_internet
Enter fullscreen mode Exit fullscreen mode

This is so ugly I'm totally embarrassed to show you what I was doing. But I didn't stop. After some time using this ugly fix and having problems of all sort because I off course forguet to comment/unccoment my lines of junk code I decided to find a better way to do this and wrote my own decorator to handle this kind of problem:

def offline_sandbox_value(value):
    def decorator(func):
        @wraps(func)
        def inner(*args, **kwargs):
            if SANDBOX:
                logging.debug('** Sandboxed ' + func.__name__ + '() with value: ' + value)
                return value
            else:
                return func(*args, **kwargs)

        return inner

    return decorator
Enter fullscreen mode Exit fullscreen mode

It might look a little bit simple but this piece of code saves me hours of work. This is a decorator to set a default value to my functions when I'm offline. So imagine the first function, If I'm going to try my project offline y can define SANDBOX = True and decorate my function with a fake response:

SANDBOX = True

@offline_sandbox_value('false response')
def doit():
    text_from_internet = get_data()
    return text_from_internet
Enter fullscreen mode Exit fullscreen mode

And then switch SANDBOX to False whenever I'm running my code online.
This is useful if I'm interested in sandboxing everything (even when I do have access), but what if I want to check for the availability of a resource and sandbox the method if I can't reach a given URL? Well, let's do that:

def offline_sandbox_value(value, url=None):
    def decorator(func):
        @wraps(func)
        def inner(*args, **kwargs):
            if url:
                if connect_to(url):
                    return func(*args, **kwargs)
                else:
                    logging.debug('** Sandboxed '+func.__name__+'() with value: '+value)
                    return value

            elif SANDBOX:
                logging.debug('** Sandboxed ' + func.__name__ + '() with value: ' + value)
                return value
            else:
                return func(*args, **kwargs)

        return inner

    return decorator
Enter fullscreen mode Exit fullscreen mode

And now I can pass a URL to my decorator and I don't have to define a value for SANDBOX if I do. So my code would be something like:

@offline_sandbox_value('false response', url='https://im-online.herokuapp.com/')
def doit():
    text_from_internet = get_data()
    return text_from_internet
Enter fullscreen mode Exit fullscreen mode

And since I was using this on various projects and it has being very useful to me I decided to package it and uploade it to PyPi with the name offline_sandbox so others can use it too. It's also on GitHub here Do you want to contribute? Open an Issue or Pull Request :-) Thanks for reading.

Top comments (1)

Collapse
 
rhymes profile image
rhymes

Very interesting solution!

Maybe there's also a way to integrate VCRpy with your workflow: github.com/kevin1024/vcrpy

This way you can return realistic responses while you're offline.

It's mainly used for offline testing but I don't think there's anything precluding you to use it in the actual code.

Maybe you can merge your "sandbox switch" with VCR and create a library of request / responses you can load while you're offline.

Hope this helps!