utility package

core4.util provides various support and helper methods used by various core4 packages and modules.

cryptography

data management

node meta information

pagination

Pagination support

class core4.util.pager.PageResult(code, message, page_count, total_count, page, body, count, per_page)

Bases: tuple

body

Alias for field number 5

code

Alias for field number 0

count

Alias for field number 6

message

Alias for field number 1

page

Alias for field number 4

page_count

Alias for field number 2

per_page

Alias for field number 7

total_count

Alias for field number 3

class core4.util.pager.CorePager(length=None, query=None, *args, **kwargs)[source]

Bases: object

The paginator features paging with CoreRequestHandler. A request handler with pagination must specify two methods:

  1. the query method to collect data for the requested page
  2. the length (total count) of the total data set.

The CorePager method page() will then return a PageResult which can be handled properly by CoreRequestHandler method .reply.

Example:

The following example is based on core4.api.v1.request.queue.JobHandler HTTP method GET with no parameter. This request returns the active jobs from sys.queue with pagination:

class JobHandler(CoreRequestHandler):

    def initialize(self):
        self._collection = {}

    def collection(self, name):
        if name not in self._collection:
            self._collection[name] = self.config.sys[name].connect_async()
        return self._collection[name]

    async def get(self, _id=None):
        ret = await self.get_listing()
        self.reply(ret)

    async def get_listing(self):

        async def _length(filter):
            return await self.collection("queue").count_documents(filter)

        async def _query(skip, limit, filter, sort_by):
            return self.collection("queue").find(
                filter).skip(skip).sort(sort_by).limit(limit)

        per_page = int(self.get_argument("per_page", 10))
        current_page = int(self.get_argument("page", 0))
        query_filter = self.get_argument("filter", {})
        sort_by = self.get_argument("sort", [])

        pager = CorePager(
                    per_page=per_page,
                    current_page=current_page,
                    length=_length,
                    query=_query,
                    sort_by=sort_by,
                    filter=query_filter
                )
        return await pager.page()

This request handler example has two helper methods. .initialize creates a dict ._collection to store asynchronous MongoDB connections using motor. The .collection method instantiated each connection to a collection with the special .connect_async methods. All handlers which follow tornado’s async paradigm have to use .connect_async. By default, the access via .config.sys[name] implicitely uses the .connect method using synchronous pymongo.

The request handlers .get method forwards the request to async .get_listing. This method defines two inline methods _length and _query.

These methods have to process a filter and a skip, limit, and sort_by attribute respectively.

After passing the request arguments these methods are specified in the CorePager instance. This object’s .page method returns a PageResult named tuple. This object type is automatically handled by CoreRequestHandler standard .reply method.

PAGE_ATTR = ('per_page', 'current_page', 'filter', 'sort_by')
initialise(**kwargs)[source]

Initialises the following pagination attributes:

Parameters:
  • per_page – number of records per page
  • current_page – of the pager
  • filter – dict with motor query filter
  • sort_by – tuple of sort attribute and sort order
page(page=None)[source]
Returns:PageResult
page_count

total number of pages

Type:return
filtered_count

total number of filtered documents

Type:return
length(filter)[source]

Needs to be implemented with every pager. The passed filter is to be applied.

Parameters:filter – variant, depends on the pager implementation
Returns:total number (int) of filtered records
query(skip, limit, filter, sort_by)[source]

Needs to be implemented with every pager. The passed skip attribute is the number of records to skip. The limit attribute is the number of records to retrieve. The passed filter and sort_by attributes are to be applied in the search.

Parameters:
  • skip – number (int) of records to skip
  • limit – number (int) of records to retrieve
  • filter – variant, depends on the pager implementation
  • sort_by – variant, depends on the pager implementation
Returns:

list of dict

total_count

total number of documents without filter

Type:return

general purpose utilities

General helper tools.

class core4.util.tool.Singleton[source]

Bases: type

Singleton metaclass, see https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python.

class core4.util.tool.lazyproperty(func)[source]

Bases: object

core4.util.tool.dict_merge(dct, merge_dct, add_keys=True)[source]

Recursive dict merge. Inspired by :meth:dict.update(), instead of updating only top-level keys, dict_merge recurses down into dicts nested to an arbitrary depth, updating keys. The merge_dct is merged into dct.

This version will return a copy of the dictionary and leave the original arguments untouched.

The optional argument add_keys, determines whether keys which are present in merge_dict but not dct should be included in the new dict.

Parameters:
  • dct – onto which the merge is executed
  • merge_dct – dict to be merged into dct
  • add_keys – whether to add new keys, defaults to True
Returns:

updated dict

core4.util.tool.has_next(iterable_data)[source]

Pass through all values from the given iterable, augmented by the information if there are more values to come after the current one (True), or if it is the last value (False).

Parameters:iterable_data – iterable type data
Returns:boolean