<commit_before>#!/usr/bin/env python
"""
_views_

Utilities for handling design docs and the resulting views they create

"""
import contextlib
import posixpath

from .document import Document
from .result import Result, python_to_couch


class Code(str):
    """
    _Code_

    string derived object that allows us to wrap/manipulate javascript blobs

    """
    def __init__(self, s):
        super(Code, self).__init__(s)


def _codify(code_or_str):
    """
    helper to rationalise None, str or Code objects
    """
    if code_or_str is None:
        return None
    if not isinstance(code_or_str, Code):
        return Code(code_or_str)
    return code_or_str


class View(dict):
    """
    Dictionary based object representing a view, exposing the map, reduce
    functions as attributes and supporting query/data access via the view

    Provides a sliceable and iterable default result collection that can 
    be used to query the view data via the result attribute.

    Eg:

    Using integers to skip/limit:
    view.result[100:200]
    view.result[:200]
    view.result[100:]

    Using strings or lists as startkey/endkey:

    view.result[ ["2013","10"]:["2013","11"] ]
    view.result[["2013","10"]]
    view.result[["2013","10"]:]

    For large views, iteration is supported via result:

    for doc in view.result:
        print doc

    The default result collection provides basic functionality, 
    which can be customised with other arguments to the view URL 
    using the custom_result context.

    For example:

    #including documents
    with view.custom_result(include_docs=True) as rslt:
        rslt[100:200] # slice by result
        rslt[["2013","10"]:["2013","11"]] # slice by startkey/endkey

        #iteration
        for doc in rslt:
            print doc

    Iteration over a view within startkey/endkey range:

    with view.custom_result(startkey="2013", endkey="2014") as rslt:
        for doc in rslt:
            print doc

    """
    def __init__(self, ddoc, view_name, map_func=None, reduce_func=None):
        super(View, self).__init__()
        self.design_doc = ddoc
        self._r_session = self.design_doc._r_session
        self.view_name = view_name
        if map_func is not None:
            self['map'] = _codify(map_func)
        if reduce_func is not None:
            self['reduce'] = _codify(reduce_func)
        self.result = Result(self)

    @property
    def map(self):
        """map property getter"""
        return self.get('map')

    @map.setter
    def map(self, js_func):
        """map property setter, accepts str or Code obj"""
        self['map'] = _codify(js_func)

    @property
    def reduce(self):
        """reduce property getter"""
        return self.get('reduce')

    @reduce.setter
    def reduce(self, js_func):
        """reduce property setter, accepts str or Code obj"""
        self['reduce'] = _codify(js_func)

    @property
    def url(self):
        """property that builds the view URL"""
        return posixpath.join(
            self.design_doc._document_url,
            '_view',
            self.view_name
        )

    def __call__(self, **kwargs):
        """
        retrieve data from the view, using the kwargs provided
        as query parameters

        descending bool
        endkey string or array
        endkey_docid  string
        group bool
        group_level ??
        include_docs bool
        inclusive_end  bool
        key string
        limit   int
        reduce  boolean
        skip    int
        stale   enum(ok, update_after)
        startkey  string or array
        startkey_docid  string

        """
        params = python_to_couch(kwargs)
        resp = self._r_session.get(self.url, params=params)
        resp.raise_for_status()
        return resp.json()

    @contextlib.contextmanager
    def custom_result(self, **options):
        """
        _custom_result_

        If you want to customise the result behaviour,
        you can build your own with extra options to the result
        call using this context manager.

        Example:

        with view.custom_result(include_docs=True, reduce=False) as rslt:
            data = rslt[100:200]

        """
        rslt = Result(self, **options)
        yield rslt
        del rslt<commit_msg>Add make_result method to View class<commit_after>#!/usr/bin/env python
"""
_views_

Utilities for handling design docs and the resulting views they create

"""
import contextlib
import posixpath

from .document import Document
from .result import Result, python_to_couch


class Code(str):
    """
    _Code_

    string derived object that allows us to wrap/manipulate javascript blobs

    """
    def __init__(self, s):
        super(Code, self).__init__(s)


def _codify(code_or_str):
    """
    helper to rationalise None, str or Code objects
    """
    if code_or_str is None:
        return None
    if not isinstance(code_or_str, Code):
        return Code(code_or_str)
    return code_or_str


class View(dict):
    """
    Dictionary based object representing a view, exposing the map, reduce
    functions as attributes and supporting query/data access via the view

    Provides a sliceable and iterable default result collection that can 
    be used to query the view data via the result attribute.

    Eg:

    Using integers to skip/limit:
    view.result[100:200]
    view.result[:200]
    view.result[100:]

    Using strings or lists as startkey/endkey:

    view.result[ ["2013","10"]:["2013","11"] ]
    view.result[["2013","10"]]
    view.result[["2013","10"]:]

    For large views, iteration is supported via result:

    for doc in view.result:
        print doc

    The default result collection provides basic functionality, 
    which can be customised with other arguments to the view URL 
    using the custom_result context.

    For example:

    #including documents
    with view.custom_result(include_docs=True) as rslt:
        rslt[100:200] # slice by result
        rslt[["2013","10"]:["2013","11"]] # slice by startkey/endkey

        #iteration
        for doc in rslt:
            print doc

    Iteration over a view within startkey/endkey range:

    with view.custom_result(startkey="2013", endkey="2014") as rslt:
        for doc in rslt:
            print doc

    """
    def __init__(self, ddoc, view_name, map_func=None, reduce_func=None):
        super(View, self).__init__()
        self.design_doc = ddoc
        self._r_session = self.design_doc._r_session
        self.view_name = view_name
        if map_func is not None:
            self['map'] = _codify(map_func)
        if reduce_func is not None:
            self['reduce'] = _codify(reduce_func)
        self.result = Result(self)

    @property
    def map(self):
        """map property getter"""
        return self.get('map')

    @map.setter
    def map(self, js_func):
        """map property setter, accepts str or Code obj"""
        self['map'] = _codify(js_func)

    @property
    def reduce(self):
        """reduce property getter"""
        return self.get('reduce')

    @reduce.setter
    def reduce(self, js_func):
        """reduce property setter, accepts str or Code obj"""
        self['reduce'] = _codify(js_func)

    @property
    def url(self):
        """property that builds the view URL"""
        return posixpath.join(
            self.design_doc._document_url,
            '_view',
            self.view_name
        )

    def __call__(self, **kwargs):
        """
        retrieve data from the view, using the kwargs provided
        as query parameters

        descending bool
        endkey string or array
        endkey_docid  string
        group bool
        group_level ??
        include_docs bool
        inclusive_end  bool
        key string
        limit   int
        reduce  boolean
        skip    int
        stale   enum(ok, update_after)
        startkey  string or array
        startkey_docid  string

        """
        params = python_to_couch(kwargs)
        resp = self._r_session.get(self.url, params=params)
        resp.raise_for_status()
        return resp.json()

    def make_result(self, **options):
        """
        Wrap the call to get result data in a Result object.
        
        """
        return Result(self, **options)

    @contextlib.contextmanager
    def custom_result(self, **options):
        """
        _custom_result_

        If you want to customise the result behaviour,
        you can build your own with extra options to the result
        call using this context manager.

        Example:

        with view.custom_result(include_docs=True, reduce=False) as rslt:
            data = rslt[100:200]

        """
        rslt = self.make_result(**options)
        yield rslt
        del rslt
{'fraction_non_alphanumeric': 0.0876376433193325, 'fraction_numerical': 0.015438755817913498, 'mean_word_length': 2.304576144036009, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5750663', 'n_tokens_mistral': 2670, 'n_tokens_neox': 2494, 'n_words': 808}