This is just a little demonstration on how you can quickly change the basic cache provider provided by the PyOWM library. For this purpose we’ll use Memcached, which – simply put – is a key/value in-memory data store: this turns it into a perfect caching mechanism. I’ve never used Memcached before writing this post: this shall be a good moment for me to get to know it. This demo requires that you work on a Linux env, as Memcached originally is shipped for Unix-like systems via packet distribution systems (but can nevertheless be compiled from source).
I’ll use Ubuntu, with Memcached 1.4.6 and PyOWM 0.4.0. Let’s dive into it.
First we install Memcached and the relative Python bindings:
sudo apt-get install memcached python-memcache
Then we install PyOWM library and check the installation:
sudo pip install pyowm ls /usr/local/lib/python2.6/dist-packages # check installation
(in my distro, Python packages are installed by pip in the /usr/local/lib/python2.6/dist-packages folder: change accordingly to yours) In order to “plug” Memcached support into PyOWM we are going to leverage the installed Python bindings by creating an adapter class that can conform the SW interface that PyOWM expects into the Memcached API for getting/setting cache elements. Fortunately, the Memcached API is very close to the PyOWM expected interface (which is stated into the pyowm.abstractions.owmcache.OWMCache class), so we have chances that our adapter will be simple enough. Let’s name it “memcachedadapter.py“: you can put it anywhere, provided that this anywhere is “seen” by the Python intepreter: in example, you can put it into a folder listed into the PYTHONPATH variable or you can place it directly into the PyOWM install folder. I did the latter:
cd /usr/local/lib/python2.6/dist-packages/pyowm sudo vim memcachedadapter.py
The module will contain the MemcachedAdapter class:
#!/usr/bin/env python class MemcachedAdapter(): """ Realizes the pyowm.abstractions.owmcache.OWMCache interface adapting a memcache.Client object """ __ITEM_LIFETIME_MILLISECONDS = 1000*60*10 # Ten minutes def __init__(self, hostname="127.0.0.1", port="11211", item_lifetime=__ITEM_LIFETIME_MILLISECONDS): from memcache import Client self._memcached = Client([hostname+":"+port]) self._item_lifetime = item_lifetime def get(self, request_url): return self._memcached.get(request_url) def set(self, request_url, response_json): self._memcached.set(request_url, response_json, self._item_lifetime)
I wrote this adapter in 5 minutes, so please don’t blame me for errors 😉 It can surely be improved. Now what is left to do is to tell the PyOWM library how to use the adapter: this is done via configuration. The library uses OWMCache concrete instance which is created into a configuration file and injected into the code; a separate configuration file exist for the code supporting each Open Weather Map web API version. Currently only API version 2.5 is supported, so we’ll put our adapter into the pyowm.webapi25.configuration25.py file, commenting out the default cache object:
# Cache provider to be used # cache = NullCache() # <-- comment this line from memcachedadapter import MemcachedAdapter cache = MemcachedAdapter("127.0.0.1", "11211")
As you can see, we are adapting a local Memcached instance listening on the default 11211 port, but you can change this configuration as needed. Now let’s try it out – let’s start Memcached and use the PyOWM library:
memcached & python
>>> from pyowm import OWM >>> owm = OWM() >>> f = owm.daily_forecast("London,uk") # This first call to the API is not cached, obviously >>> g = owm.daily_forecast("London,uk") # This second call is cached
Time saving should be at a glance.
In a similar way it is possible to write adapters for plugging other cache/storage providers (Redis, MongoDB, etc..) into the PyOWM library.
EDIT: this post stimulated me to write more adapters, you can find them here.