
Ring Documentation Release 0.9.0 Jeong YunWon Jul 31, 2021 Guidelines: 1 Quickstart 3 2 Why Ring? 5 3 Documents 7 3.1 Quickstart................................................7 3.2 Why Ring?................................................ 12 3.3 Factory functions............................................. 17 3.4 Attributes of Ring object......................................... 20 3.5 Save and load rich data.......................................... 24 3.6 Extend Ring to meet your own needs.................................. 26 3.7 The future of Ring............................................ 27 3.8 Contribution............................................... 28 3.9 ring ................................................... 29 4 Indices and tables 49 Python Module Index 51 Index 53 i ii Ring Documentation, Release 0.9.0 Ring provides function-oriented cache interface for various backends. Repository: https://github.com/youknowone/ring/ Guidelines: 1 Ring Documentation, Release 0.9.0 2 Guidelines: CHAPTER 1 Quickstart See Quickstart to learn the basic concept of Ring with examples. Using it in your code can be done in a single minute. 3 Ring Documentation, Release 0.9.0 4 Chapter 1. Quickstart CHAPTER 2 Why Ring? Caching is a popular concept widely spread on the broad range of computer science but its interface is not well developed yet. In these days, we still experience common inconvenience. Ring is one of the solutions for humans. Its approach is close integration with the programming language. See Why Ring? for details. 5 Ring Documentation, Release 0.9.0 6 Chapter 2. Why Ring? CHAPTER 3 Documents 3.1 Quickstart To start, remember the philosophy of Ring is a human-friendly high-level interface with transparent and concrete low-level access. You probably be able to access most of the levels of Ring you want. 3.1.1 Installation PyPI is the recommended way. $ pip install ring To browse versions and tarballs, visit: https://pypi.python.org/pypi/ring/ Though Ring includes support for many backends, their packages are not included in ring installation due to the following issues: 1. Ring supports many backends but users don’t use all of them. 2. Backends packages not only cost storages and time but also require some non-Python packages to be installed, which cannot be automated by pip. 3. Installing some of them is not easy on some platforms. Check each backend you use and manually add related packages to setup.py or requirements.txt. If you are new to Ring and cache, let’s start with ring.lru(). It doesn’t require any dependency. Changing lru to another backend is simple for later. Note: If you are new to LRU cache, check https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_ recently_used_(LRU) for details. 7 Ring Documentation, Release 0.9.0 3.1.2 First example Let’s start with a simple example: function cache with bytes data. import ring import requests # save in a new lru storage @ring.lru() def get_url(url): return requests.get(url).content # default access - it is cached data= get_url('http://example.com') This flow is what you see in common smart cache decorators. Actually, this is very similar to functools. lru_cache() in Python standard library. The differences start here. The core feature of Ring is explicit controllers. # delete the cache get_url.delete('http://example.com') # get cached data or None data_or_none= get_url.get('http://example.com') # get internal cache key key= get_url.key('http://example.com') # and access directly to the backend encoded_data= get_url.storage.backend.get(key) cached_data= get_url.decode(encoded_data) Ring will have full control for any layer of caching. Which doesn’t exist in functools.lru_cache() see Attributes of Ring object for sub-functions details. see Why Ring? if this document doesn’t explain what Ring does. 3.1.3 method, classmethod, staticmethod, property Ring is adaptable for any kind of methods for Python class. import ring import requests class Page(object): base_content='<html></html>' def __init__(self, url): self.url= url def __ring_key__(self): return 'page='+ self.url @ring.lru() def content(self): return requests.get(self.url).content (continues on next page) 8 Chapter 3. Documents Ring Documentation, Release 0.9.0 (continued from previous page) @ring.lru() @classmethod def class_content(cls): return cls.base_content @ring.lru() @staticmethod def example_dot_com(): return requests.get('http://example.com').content @ring.lru() @property def url_property(self): return self.url_property Page.example_dot_com() # as expected assert Page.example_dot_com.key().endswith('Page.example_dot_com') # key with ,!function-name Page.class_content() # as expected # key with function-name + class name assert Page.class_content.key().endswith('Page.class_content:Page') p= Page('http://example.com') p.content() # as expected # key with class name + function name + __ring_key__ assert p.content.key().endswith('Page.content:page=http://example.com') assert p.url_property ==p.url see Factory functions for details. 3.1.4 Choosing backend Let’s consider using external cache storage instead of lru. Ring includes common cache storage supports. Memcached is one of the popular cache storage. Memcached is not a Python Project. You must install and run it to let your python code connects there. Fortunately, because Memcached is very popular, it is well-packaged on most of the platforms. Check how to install it on your platform. note For example, apt install memcached for Debian/Ubuntu. yum install memcached for CentOS/RHEL. brew install memcache for macOS with Homebrew. Once you installed it, do not forget to start it. In Ring, you can choose any compatible Memcached package. If you are new to Memcached, let’s try pymemcache to install it easily. $ pip install pymemcache Now you are ready to edit the get_url to use Memcached. import ring import requests (continues on next page) 3.1. Quickstart 9 Ring Documentation, Release 0.9.0 (continued from previous page) import pymemcache.client #1 import pymemcache client= pymemcache.client.Client(('127.0.0.1', 11211)) #2 create a client # save to memcache client, expire in 60 seconds. @ring.memcache(client, expire=60) #3 lru -> memcache def get_url(url): return requests.get(url).content # default access - it is cached data= get_url('http://example.com') Try and compare what’s changed from ring.lru() version. There are many more included factories for various backends. see Factory functions about more factories and backends. see Extend Ring to meet your own needs to create your own factory. asyncio support Ring supports asyncio with a few factories which also are included. They follow similar convention but requiring await for IO jobs. import ring @ring.lru(force_asyncio=True) # non-asyncio backends require `force_asyncio` async def f(): ... result= await f() # using `await` for __call__ cached_result= await f.get() # using `await` for get() key=f.key() # NOT using `await` for key() note Non-IO sub-functions doesn’t require await. note the sync version factories are not compatible with asyncio. see Factory functions and search for asyncio to find fit factories. 3.1.5 Structured or complex data The modern software handles structured data rather than chunks of bytes. Because the popular cache storages only support raw bytes or string, data needs to be encoded and decoded. The coder parameter in Ring factories decides the kind of coding. import ring import json import pymemcache.client client= pymemcache.client.Client(('127.0.0.1', 11211)) @ring.memcache(client, expire=60, coder='json') def f(): return {'key':'data','number': 42} (continues on next page) 10 Chapter 3. Documents Ring Documentation, Release 0.9.0 (continued from previous page) f() # create cache data loaded=f.get() assert isinstance(loaded, dict) assert loaded =={'key':'data','number': 42} raw_data=f.storage.backend.get(f.key()) assert isinstance(raw_data, bytes) # `str` for py2 assert raw_data == json.dumps({'key':'data','number': 42}).encode('utf-8') see Save and load rich data about more backends. see Extend Ring to meet your own needs to create and register your own coders. 3.1.6 Factory parameters Ring factories share common parameters to control Ring objects’ behavior. • key_prefix • coder • ignorable_keys • user_inferface • storage_interface see Factory functions for details. 3.1.7 Low-level access Do you wonder how your data is encoded? Which keys are mapped to the functions? You don’t need to be suffered by looking inside of Ring. At this time, let’s use ring.dict() to look into the storage. import ring dict_storage={} @ring.dict(dict_storage) def f(): ... key=f.key() # retrieving the key raw_data=f.storage.backend.get(key) # getting raw data from storage # look into `dict_storage` by yourself to check how it works. see Attributes of Ring object for more attributes. 3.1.8 Bulk access Bulk access API is optionally supported. 3.1. Quickstart 11 Ring Documentation, Release 0.9.0 @ring.memcache(...) def f(a, b): ... # getting data for f(1, 2), f(1, 3), f(a=2, b=2) data=f.get_many((1,2), (1,3), {'a':2,'b':2}) see Attributes of Ring object for more attributes. 3.1.9 Further documents see Why Ring? see Attributes of Ring object see ring — the full reference of Ring 3.2 Why Ring? Caching is a popular concept widely spread on the broad range of computer science. But cache interface is not well-developed yet. Ring is one of the solutions for humans. Its approach is close integration with a programming language. 3.2.1 Common problems of cache note Skip this section if you are familiar with cache and decorator patterns for cache in Python world. The straightforward approach to storage Traditionally we considered cache as a storage. In that sense, calling useful actual_function() with an argument for the cached result of cached_function() looks like next series of works: # psuedo code for rough flow key= create_key() if storage.has(key): result= storage.get(key) else: result= cached_function() storage.set(key, result) actual_function(result) What’s the problem? We are interested in cached_function() and actual_function() instead of storage.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages60 Page
-
File Size-