def twilio_view(f):
    """This decorator provides several helpful shortcuts for writing Twilio
    views.

        - It ensures that only requests from Twilio are passed through. This
          helps protect you from forged requests.

        - It ensures your view is exempt from CSRF checks via Django's
          @csrf_exempt decorator. This is necessary for any view that accepts
          POST requests from outside the local domain (eg: Twilio's servers).

        - It allows your view to (optionally) return TwiML to pass back to
          Twilio's servers instead of building a ``HttpResponse`` object
          manually.

        - It allows your view to (optionally) return any ``twilio.Verb`` object
          instead of building a ``HttpResponse`` object manually.

    Usage::

        from twilio.twiml import Response

        @twilio_view
        def my_view(request):
            r = Response()
            r.sms("Thanks for the SMS message!")
            return r
    """
    @csrf_exempt
    @wraps(f)
    def decorator(request, *args, **kwargs):
        # Attempt to gather all required information to allow us to check the
        # incoming HTTP request for forgery. If any of this information is not
        # available, then we'll throw a HTTP 403 error (forbidden).

        # Ensure the request method is POST
        if request.method != "POST":
            logger.error("Twilio: Expected POST request", extra={"request": request})
            return HttpResponseNotAllowed(request.method)

        if not getattr(settings, "TWILIO_SKIP_SIGNATURE_VALIDATION"):
            # Validate the request
            try:
                validator = RequestValidator(settings.TWILIO_AUTH_TOKEN)
                url = request.build_absolute_uri()
                # Ensure the original requested url is tested for validation
                # Prevents breakage when processed behind a proxy server
                if "HTTP_X_FORWARDED_SERVER" in request.META:
                    protocol = "https" if request.META["HTTP_X_TWILIO_SSL"] == "Enabled" else "http"
                    url = "{0}://{1}{2}".format(
                        protocol, request.META["HTTP_X_FORWARDED_SERVER"], request.META["REQUEST_URI"]
                    )
                signature = request.META["HTTP_X_TWILIO_SIGNATURE"]
            except (AttributeError, KeyError) as e:
                logger.exception("Twilio: Missing META param", extra={"request": request})
                return HttpResponseForbidden("Missing META param: %s" % e)

            # Now that we have all the required information to perform forgery
            # checks, we'll actually do the forgery check.
            if not validator.validate(url, request.POST, signature):
                logger.error(
                    "Twilio: Invalid url signature %s - %s - %s",
                    url, request.POST, signature, extra={"request": request}
                )
                return HttpResponseForbidden("Invalid signature")

        # Run the wrapped view, and capture the data returned.
        response = f(request, *args, **kwargs)

        # If the view returns a string (or a ``twilio.Verb`` object), we'll
        # assume it is XML TwilML data and pass it back with the appropriate
        # mimetype. We won't check the XML data because that would be too time
        # consuming for every request. Instead, we'll let the errors pass
        # through to be dealt with by the developer.
        if isinstance(response, six.text_type):
            return HttpResponse(response, mimetype="application/xml")
        elif isinstance(response, Verb):
            return HttpResponse(force_text(response), mimetype="application/xml")
        else:
            return response
    return decorator

This decorator provides several helpful shortcuts for writing Twilio views .


def _get_color_string(self):
        """Adobe output string for defining colors"""
        s = ''
        if self.color_type == 'd':
            if self.name is "black":
                s = '%.3f G' % 0
            else:
                s = '%.3f %.3f %.3f RG' % (
                    self.red / 255.0, self.green / 255.0, self.blue / 255.0)
        elif self.color_type == 'f' or self.color_type == 't':
            if self.name is "black":
                s = '%.3f g' % 0
            else:
                s = '%.3f %.3f %.3f rg' % (
                    self.red / 255.0, self.green / 255.0, self.blue / 255.0)
        return s

def
_get_color_string
(
self
)
:
s
=
''
if
self
.
color_type
==
'd'
:
if
self
.
name
is
"black"
:
s
=
'%.3f G'
%
0
else
:
s
=
'%.3f %.3f %.3f RG'
%
(
self
.
red
/
255.0
,
self
.
green
/
255.0
,
self
.
blue
/
255.0
)
elif
self
.
color_type
==
'f'
or
self
.
color_type
==
't'
:
if
self
.
name
is
"black"
:
s
=
'%.3f g'
%
0
else
:
s
=
'%.3f %.3f %.3f rg'
%
(
self
.
red
/
255.0
,
self
.
green
/
255.0
,
self
.
blue
/
255.0
)
return
s


def get_ttf(self):
        """ Given a search path, find file with requested extension """
        font_dict = {}
        families = []
        rootdirlist = string.split(self.search_path, os.pathsep)

        #for rootdir in rootdirlist:
        #    rootdir = os.path.expanduser(rootdir)
        for dirName, subdirList, filelist in itertools.chain.from_iterable(os.walk(path) for path in rootdirlist):
            for item in filelist:
                root, ext = os.path.splitext(item)
                if ext == '.ttf':
                    if root[0].lower() in english:
                        source = os.path.join(dirName, item)
                        name = root.lower().replace('_', ' ')
                        if ' bold' in name:
                            name = name.replace(' bold', '_bold')
                            if ' italic' in name:
                                name = name.replace(' italic', '_italic')
                        elif 'bold' in name:
                            name = name.replace('bold', '_bold')
                            if 'italic' in name:
                                name = name.replace('italic', '_italic')
                        elif ' italic' in name:
                            name = name.replace(' italic', '_italic')
                        elif 'italic' in name:
                            name = name.replace('italic', '_italic')
                        elif 'oblique' in name:
                            name = name.replace('oblique', '_italic')
                        else:
                            families.append(name)
                        font_dict[name] = source
                    else:
                        source = os.path.join(dirName, item)
                        name = root.lower().replace('_', ' ')
                        font_dict[name] = source
                        families.append(name)
        self.font_dict = font_dict
        self.families = families

def
get_ttf
(
self
)
:
font_dict
=
{
}
families
=
[
]
rootdirlist
=
string
.
split
(
self
.
search_path
,
os
.
pathsep
)
for
dirName
,
subdirList
,
filelist
in
itertools
.
chain
.
from_iterable
(
os
.
walk
(
path
)
for
path
in
rootdirlist
)
:
for
item
in
filelist
:
root
,
ext
=
os
.
path
.
splitext
(
item
)
if
ext
==
'.ttf'
:
if
root
[
0
]
.
lower
(
)
in
english
:
source
=
os
.
path
.
join
(
dirName
,
item
)
name
=
root
.
lower
(
)
.
replace
(
'_'
,
' '
)
if
' bold'
in
name
:
name
=
name
.
replace
(
' bold'
,
'_bold'
)
if
' italic'
in
name
:
name
=
name
.
replace
(
' italic'
,
'_italic'
)
elif
'bold'
in
name
:
name
=
name
.
replace
(
'bold'
,
'_bold'
)
if
'italic'
in
name
:
name
=
name
.
replace
(
'italic'
,
'_italic'
)
elif
' italic'
in
name
:
name
=
name
.
replace
(
' italic'
,
'_italic'
)
elif
'italic'
in
name
:
name
=
name
.
replace
(
'italic'
,
'_italic'
)
elif
'oblique'
in
name
:
name
=
name
.
replace
(
'oblique'
,
'_italic'
)
else
:
families
.
append
(
name
)
font_dict
[
name
]
=
source
else
:
source
=
os
.
path
.
join
(
dirName
,
item
)
name
=
root
.
lower
(
)
.
replace
(
'_'
,
' '
)
font_dict
[
name
]
=
source
families
.
append
(
name
)
self
.
font_dict
=
font_dict
self
.
families
=
families

Given a search path find file with requested extension


def _set_compression(self, value):
        """ May be used to compress PDF files. Code is more readable
            for testing and inspection if not compressed. Requires a boolean. """
        if isinstance(value, bool):
            self.compression = value
        else:
            raise Exception(
                TypeError, "%s is not a valid option for compression" % value)

May be used to compress PDF files . Code is more readable for testing and inspection if not compressed . Requires a boolean .


def _add_object(self, flag=None):
        """ The flag is a simple integer to force the placement
            of the object into position in the object array.
            Used for overwriting the placeholder objects.

        """
        self.offset = len(self.buffer)
        if flag is None:
            objnum = len(self.objects)
            obj = _PDFObject(objnum, self.offset)
            self.objects.append(obj)
        else:
            objnum = flag
            obj = _PDFObject(objnum, self.offset)
            self.objects[flag] = obj
        self._out(str(objnum) + ' 0 obj')
        return obj

def
_add_object
(
self
,
flag
=
)
:
self
.
offset
=
len
(
self
.
buffer
)
if
flag
is
:
objnum
=
len
(
self
.
objects
)
obj
=
_PDFObject
(
objnum
,
self
.
offset
)
self
.
objects
.
append
(
obj
)
else
:
objnum
=
flag
obj
=
_PDFObject
(
objnum
,
self
.
offset
)
self
.
objects
[
flag
]
=
obj
self
.
_out
(
str
(
objnum
)
+
' 0 obj'
)
return
obj

The flag is a simple integer to force the placement of the object into position in the object array . Used for overwriting the placeholder objects .


def _out(self, stream, page=None):
        """ Stores the pdf code in a buffer. If it is page related,
            provide the page object.

        """
        if page is not None:
            page.buffer += str(stream) + "\n"
        else:
            self.buffer += str(stream) + "\n"

def _out ( self , stream , page = None ) : if page is not None : page . buffer += str ( stream ) + "\n" else : self . buffer += str ( stream ) + "\n"

Stores the pdf code in a buffer . If it is page related provide the page object .


def _put_stream(self, stream):
        """ Creates a PDF text stream sandwich.

        """
        self._out('stream')
        self._out(stream)
        self._out('endstream')

def _put_stream ( self , stream ) : self . _out ( 'stream' ) self . _out ( stream ) self . _out ( 'endstream' )


def _add_page(self, text):
        """ Helper function for PDFText, to have the document
            add a page, and retry adding a large block of
            text that would otherwise have been to long for the
            page.

        """
        save_cursor = self.parent.document.page.cursor.copy()
        save_cursor.x_reset()
        save_cursor.y_reset()
        self.parent.document.add_page()
        self.parent.document.set_cursor(save_cursor)
        self.parent.document.add_text(text)

def _add_page ( self , text ) : save_cursor = self . parent . document . page . cursor . copy ( ) save_cursor . x_reset ( ) save_cursor . y_reset ( ) self . parent . document . add_page ( ) self . parent . document . set_cursor ( save_cursor ) self . parent . document . add_text ( text )

Helper function for PDFText to have the document add a page and retry adding a large block of text that would otherwise have been to long for the page .


def _set_color_scheme(self, draw_color=None, fill_color=None, text_color=None):
        """ Default color object is black letters
            & black lines."""
        if draw_color is None:
            draw_color = PDFColor()
            draw_color._set_type('d')
        if fill_color is None:
            fill_color = PDFColor()
            fill_color._set_type('f')
        if text_color is None:
            text_color = PDFColor()
            text_color._set_type('t')

        self.draw_color = draw_color
        self.fill_color = fill_color
        self.text_color = text_color

def _set_color_scheme ( self , draw_color = None , fill_color = None , text_color = None ) : if draw_color is None : draw_color = PDFColor ( ) draw_color . _set_type ( 'd' ) if fill_color is None : fill_color = PDFColor ( ) fill_color . _set_type ( 'f' ) if text_color is None : text_color = PDFColor ( ) text_color . _set_type ( 't' ) self . draw_color = draw_color self . fill_color = fill_color self . text_color = text_color

Default color object is black letters & black lines .


def _set_default_font(self):
        """ Internal method to set the initial default font. Change
            the font using set_font method."""
        self.font = PDFFont(self.session)
        self.font._set_index()
        self.fonts.append(self.font)
        self.fontkeys.append(self.font.font_key)

def _set_default_font ( self ) : self . font = PDFFont ( self . session ) self . font . _set_index ( ) self . fonts . append ( self . font ) self . fontkeys . append ( self . font . font_key )

Internal method to set the initial default font . Change the font using set_font method .


def add_page(self, page=None):
        """ May generate and add a PDFPage separately, or use this to generate
            a default page."""
        if page is None:
            self.page = PDFPage(self.orientation_default, self.layout_default, self.margins)
        else:
            self.page = page
        self.page._set_index(len(self.pages))
        self.pages.append(self.page)
        currentfont = self.font
        self.set_font(font=currentfont)
        self.session._reset_colors()

def add_page ( self , page = None ) : if page is None : self . page = PDFPage ( self . orientation_default , self . layout_default , self . margins ) else : self . page = page self . page . _set_index ( len ( self . pages ) ) self . pages . append ( self . page ) currentfont = self . font self . set_font ( font = currentfont ) self . session . _reset_colors ( )

May generate and add a PDFPage separately or use this to generate a default page .


def set_font_size(self, size):
        """Convenience method for just changing font size."""
        if self.font.font_size == size:
            pass
        else:
            self.font._set_size(size)

def set_font_size ( self , size ) : if self . font . font_size == size : pass else : self . font . _set_size ( size )

Convenience method for just changing font size .


def add_text(self, text, cursor=None, justification=None):
        """ Input text, short or long. Writes in order, within the defined page boundaries. Sequential add_text commands will print without
            additional whitespace. """
        if cursor is None:
            cursor = self.page.cursor

        text = re.sub("\s\s+" , " ", text)

        if justification is None:
            justification = self.justification

        if '\n' in text:
            text_list = text.split('\n')
            for text in text_list:
                PDFText(self.session, self.page, text, self.font, self.text_color, cursor, justification, self.double_spacing)
                self.add_newline()
        else:
            PDFText(self.session, self.page, text, self.font, self.text_color, cursor, justification, self.double_spacing)

def
add_text
(
self
,
text
,
cursor
=
,
justification
=
)
:
if
cursor
is
:
cursor
=
self
.
page
.
cursor
text
=
re
.
sub
(
"\s\s+"
,
" "
,
text
)
if
justification
is
:
justification
=
self
.
justification
if
'\n'
in
text
:
text_list
=
text
.
split
(
'\n'
)
for
text
in
text_list
:
PDFText
(
self
.
session
,
self
.
page
,
text
,
self
.
font
,
self
.
text_color
,
cursor
,
justification
,
self
.
double_spacing
)
self
.
add_newline
(
)
else
:
PDFText
(
self
.
session
,
self
.
page
,
text
,
self
.
font
,
self
.
text_color
,
cursor
,
justification
,
self
.
double_spacing
)

Input text short or long . Writes in order within the defined page boundaries . Sequential add_text commands will print without additional whitespace .


def add_newline(self, number=1):
        """ Starts over again at the new line. If number is specified,
            it will leave multiple lines."""
        if isinstance(number, int):
            try:
                self.page._add_newline(self.font, number, self.double_spacing)
            except ValueError:
                self.add_page()
        else:
            raise TypeError("Number of newlines must be an integer.")

Starts over again at the new line . If number is specified it will leave multiple lines .


def add_pie_chart(self, data, cursor, width, height, title=None, data_type="raw", fill_colors=None, labels=False, background=None, legend=None):
        """ Data type may be "raw" or "percent" """
        save_draw_color = self.draw_color
        save_fill_color = self.fill_color

        chart = PDFPieChart(self.session, self.page, data, cursor, width, height, title, data_type, fill_colors, labels, background, legend)

        self.set_draw_color(save_draw_color)
        self.set_fill_color(save_fill_color)

def add_pie_chart ( self , data , cursor , width , height , title = None , data_type = "raw" , fill_colors = None , labels = False , background = None , legend = None ) : save_draw_color = self . draw_color save_fill_color = self . fill_color chart = PDFPieChart ( self . session , self . page , data , cursor , width , height , title , data_type , fill_colors , labels , background , legend ) self . set_draw_color ( save_draw_color ) self . set_fill_color ( save_fill_color )


def _output_pages(self):
        """ Called by the PDFLite object to prompt creating
            the page objects."""
        if not self.orientation_changes:
            self._get_orientation_changes()

        # Page
        for page in self.pages:
            obj = self.session._add_object()
            self.session._out('<</Type /Page')
            self.session._out('/Parent 1 0 R')
            if self.orientation_changes:
                self.session._out('/MediaBox [0 0 %.2f %.2f]' % (page.width, page.height))
            self.session._out('/Resources 2 0 R')
            self.session._out('/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>')
            self.session._out('/Contents %s 0 R>>' % (obj.id + 1))
            self.session._out('endobj')

            # Page content
            self.session._add_object()
            if self.session.compression is True:
                textfilter = ' /Filter /FlateDecode '
                page._compress()
            else:
                textfilter = ''
            self.session._out('<<%s/Length %s >>' % (textfilter, len(page.buffer)))
            self.session._put_stream(page.buffer)
            self.session._out('endobj')

Called by the PDFLite object to prompt creating the page objects .


def _get_orientation_changes(self):
        """ Returns a list of the pages that have
            orientation changes."""
        self.orientation_changes = []
        for page in self.pages:
            if page.orientation_change is True:
                self.orientation_changes.append(page.index)
            else:
                pass
        return self.orientation_changes

def _get_orientation_changes ( self ) : self . orientation_changes = [ ] for page in self . pages : if page . orientation_change is True : self . orientation_changes . append ( page . index ) else : pass return self . orientation_changes

Returns a list of the pages that have orientation changes .


def _output_fonts(self):
        """ Called by the PDFLite object to prompt creating
            the font objects."""
        self.session._save_object_number()
        self._output_encoding_diffs()
        self._output_font_files()

        for font in self.fonts:
            obj = self.session._add_object()
            font._set_number(obj.id)
            font._output()

def _output_fonts ( self ) : self . session . _save_object_number ( ) self . _output_encoding_diffs ( ) self . _output_font_files ( ) for font in self . fonts : obj = self . session . _add_object ( ) font . _set_number ( obj . id ) font . _output ( )

Called by the PDFLite object to prompt creating the font objects .


def _output_images(self):
        """ Creates reference images, that can be
            drawn throughout the document."""
        for image in self.images:
            obj = self.session._add_object()
            image._set_number(obj.id)
            image._output()

def _output_images ( self ) : for image in self . images : obj = self . session . _add_object ( ) image . _set_number ( obj . id ) image . _output ( )

Creates reference images that can be drawn throughout the document .


def _output(self):
        """ Prompts the creating of image objects.

        """
        self.session._out('<</Type /XObject')
        self.session._out('/Subtype /Image')
        self.session._out('/Width %s' % self.width)
        self.session._out('/Height %s' % self.height)

        if self.colorspace is 'Indexed':
            self.session._out('/ColorSpace [/Indexed /DeviceRGB %s %s 0 R' %
                              (self.pal, self.number + 1))
        else:
            self.session._out('/ColorSpace /%s' % self.colorspace)
            if self.colorspace is 'DeviceCMYK':
                self.session._out('/Decode [1 0 1 0 1 0 1 0]')

        self.session._out('/BitsPerComponent %s' % self.bits_per_component)

        if self.filter:
            self.session._out('/Filter /%s' % self.filter)
        if self.decode:
            self.session._out('/DecodeParms << %s >>' % self.decode)
        if self.transparent:
            self.session._out('/Mask [%s]' % self.transparent_string)
        if self.soft_mask:
            self.session._out('/SMask %s 0 R' % (self.number + 1))
        self.session._out('/Length %s >>' % self.size)
        self.session._put_stream(self.image_data)
        self.session._out('endobj')

        if self.colorspace is 'Indexed':
            self.session._out('<<%s /Length %s >>' % (self.palette_filter, self.palette_length))
            self.session._put_stream(self.palette)
            self.session._out('endobj')

        if isinstance(self.soft_mask, PDFImage):
            obj = self.session._add_object()
            self.soft_mask._set_number(obj.id)
            self.soft_mask._output()


def transform(self, a, b, c, d, e, f):
        """ Adjust the current transformation state of the current graphics state
        matrix. Not recommended for the faint of heart.
        """
        a0, b0, c0, d0, e0, f0 = self._currentMatrix
        self._currentMatrix = (a0 * a + c0 * b, b0 * a + d0 * b,
                               a0 * c + c0 * d, b0 * c + d0 * d,
                               a0 * e + c0 * f + e0, b0 * e + d0 * f + f0)
        a1, b1, c1, d1, e1, f1 = self._currentMatrix
        self.session._out('%.2f %.2f %.2f %.2f %.2f %.2f cm' % (a1, b1, c1, d1, e1, f1), self.page)

def
transform
(
self
,
a
,
b
,
c
,
d
,
e
,
f
)
:
a0
,
b0
,
c0
,
d0
,
e0
,
f0
=
self
.
_currentMatrix
self
.
_currentMatrix
=
(
a0
*
a
+
c0
*
b
,
b0
*
a
+
d0
*
b
,
a0
*
c
+
c0
*
d
,
b0
*
c
+
d0
*
d
,
a0
*
e
+
c0
*
f
+
e0
,
b0
*
e
+
d0
*
f
+
f0
)
a1
,
b1
,
c1
,
d1
,
e1
,
f1
=
self
.
_currentMatrix
self
.
session
.
_out
(
'%.2f %.2f %.2f %.2f %.2f %.2f cm'
%
(
a1
,
b1
,
c1
,
d1
,
e1
,
f1
)
,
self
.
page
)

Adjust the current transformation state of the current graphics state matrix . Not recommended for the faint of heart .


def absolute_position(self, x, y):
        """return the absolute position of x,y in user space w.r.t. default user space"""
        (a, b, c, d, e, f) = self._currentMatrix
        xp = a * x + c * y + e
        yp = b * x + d * y + f
        return xp, yp

def absolute_position ( self , x , y ) : ( a , b , c , d , e , f ) = self . _currentMatrix xp = a * x + c * y + e yp = b * x + d * y + f return xp , yp

return the absolute position of x y in user space w . r . t . default user space


def _set_style(self, style=None):
        """ Style should be a string, containing the letters 'B' for bold,
        'U' for underline, or 'I' for italic, or should be '', for no style.
        Symbol will not be underlined. The underline style can further be
        modified by specifying the underline thickness and position.

        """
        if style is None:
            self.style = ''
            self.underline = False
        # No syling for symbol
        elif self.family == ('symbol' or 'zapfdingbats'):
            self.style = ''
            self.underline = False

        self.style = style.upper()
            # SetUnderline

        if 'U' in self.style or self.style == 'U':
            self.underline = True
        else:
            self.underline = False

def _set_style ( self , style = None ) : if style is None : self . style = '' self . underline = False elif self . family == ( 'symbol' or 'zapfdingbats' ) : self . style = '' self . underline = False self . style = style . upper ( ) if 'U' in self . style or self . style == 'U' : self . underline = True else : self . underline = False

Style should be a string containing the letters B for bold U for underline or I for italic or should be for no style . Symbol will not be underlined . The underline style can further be modified by specifying the underline thickness and position .


def rotatePoint(self, pointX, pointY):
        """
        Rotates a point relative to the mesh origin by the angle specified in the angle property.
        Uses the angle formed between the segment linking the point of interest to the origin and
        the parallel intersecting the origin. This angle is called beta in the code.
        """
        if(self.angle == 0 or self.angle == None):
            return(pointX, pointY)

        # 1. Compute the segment length
        length = math.sqrt((pointX - self.xll) ** 2 + (pointY - self.yll) ** 2)

        # 2. Compute beta
        beta = math.acos((pointX - self.xll) / length)
        if(pointY < self.yll):
            beta = math.pi * 2 - beta

        # 3. Compute offsets
        offsetX = math.cos(beta) * length - math.cos(self._angle_rd + beta) * length
        offsetY = math.sin(self._angle_rd + beta) * length - math.sin(beta) * length
        return (pointX - offsetX, pointY + offsetY)

def rotatePoint ( self , pointX , pointY ) : if ( self . angle == 0 or self . angle == None ) : return ( pointX , pointY ) length = math . sqrt ( ( pointX - self . xll ) ** 2 + ( pointY - self . yll ) ** 2 ) beta = math . acos ( ( pointX - self . xll ) / length ) if ( pointY < self . yll ) : beta = math . pi * 2 - beta offsetX = math . cos ( beta ) * length - math . cos ( self . _angle_rd + beta ) * length offsetY = math . sin ( self . _angle_rd + beta ) * length - math . sin ( beta ) * length return ( pointX - offsetX , pointY + offsetY )

Rotates a point relative to the mesh origin by the angle specified in the angle property . Uses the angle formed between the segment linking the point of interest to the origin and the parallel intersecting the origin . This angle is called beta in the code .


def set_information(self, title=None, subject=None, author=None, keywords=None, creator=None):
        """ Convenience function to add property info, can set any attribute and leave the others blank, it won't over-write
            previously set items. """
        info_dict = {"title": title, "subject": subject,
                     "author": author, "keywords": keywords,
                     "creator": creator}

        for att, value in info_dict.iteritems():
            if hasattr(self, att):
                if value:
                    setattr(self, att, value)
            else:
                setattr(self, att, None)

def set_information ( self , title = None , subject = None , author = None , keywords = None , creator = None ) : info_dict = { "title" : title , "subject" : subject , "author" : author , "keywords" : keywords , "creator" : creator } for att , value in info_dict . iteritems ( ) : if hasattr ( self , att ) : if value : setattr ( self , att , value ) else : setattr ( self , att , None )

Convenience function to add property info can set any attribute and leave the others blank it won t over - write previously set items .


def set_display_mode(self, zoom='fullpage', layout='continuous'):
        """ Set the default viewing options. """
        self.zoom_options = ["fullpage", "fullwidth", "real", "default"]
        self.layout_options = ["single", "continuous", "two", "default"]

        if zoom in self.zoom_options or (isinstance(zoom, int) and 0 < zoom <= 100):
            self.zoom_mode = zoom
        else:
            raise Exception('Incorrect zoom display mode: ' + zoom)

        if layout in self.layout_options:
            self.layout_mode = layout
        else:
            raise Exception('Incorrect layout display mode: ' + layout)

def
set_display_mode
(
self
,
zoom
=
'fullpage'
,
layout
=
'continuous'
)
:
self
.
zoom_options
=
[
"fullpage"
,
"fullwidth"
,
"real"
,
"default"
]
self
.
layout_options
=
[
"single"
,
"continuous"
,
"two"
,
"default"
]
if
zoom
in
self
.
zoom_options
or
(
isinstance
(
zoom
,
int
)
and
0
<
zoom
<=
100
)
:
self
.
zoom_mode
=
zoom
else
:
raise
Exception
(
'Incorrect zoom display mode: '
+
zoom
)
if
layout
in
self
.
layout_options
:
self
.
layout_mode
=
layout
else
:
raise
Exception
(
'Incorrect layout display mode: '
+
layout
)


def close(self):
        """ Prompt the objects to output pdf code, and save to file. """
        self.document._set_page_numbers()
        # Places header, pages, page content first.
        self._put_header()
        self._put_pages()
        self._put_resources()
        # Information object
        self._put_information()
        # Catalog object
        self._put_catalog()
        # Cross-reference object
        #self._put_cross_reference()
        # Trailer object
        self._put_trailer()

        if hasattr(self.destination, "write"):
            output = self._output_to_io()
        elif self.destination == 'string':
            output = self._output_to_string()
        else:
            self._output_to_file()
            output = None
        return output

def close ( self ) : self . document . _set_page_numbers ( ) self . _put_header ( ) self . _put_pages ( ) self . _put_resources ( ) self . _put_information ( ) self . _put_catalog ( ) self . _put_trailer ( ) if hasattr ( self . destination , "write" ) : output = self . _output_to_io ( ) elif self . destination == 'string' : output = self . _output_to_string ( ) else : self . _output_to_file ( ) output = None return output

Prompt the objects to output pdf code and save to file .


def _put_header(self):
        """ Standard first line in a PDF. """
        self.session._out('%%PDF-%s' % self.pdf_version)
        if self.session.compression:
            self.session.buffer += '%' + chr(235) + chr(236) + chr(237) + chr(238) + "\n"

def _put_header ( self ) : self . session . _out ( '%%PDF-%s' % self . pdf_version ) if self . session . compression : self . session . buffer += '%' + chr ( 235 ) + chr ( 236 ) + chr ( 237 ) + chr ( 238 ) + "\n"


def _put_pages(self):
        """ First, the Document object does the heavy-lifting for the
            individual page objects and content.

            Then, the overall "Pages" object is generated.

        """
        self.document._get_orientation_changes()
        self.document._output_pages()

        # Pages Object, provides reference to page objects (Kids list).
        self.session._add_object(1)
        self.session._out('<</Type /Pages')
        kids = '/Kids ['
        for i in xrange(0, len(self.document.pages)):
            kids += str(3 + 2 * i) + ' 0 R '
        self.session._out(kids + ']')
        self.session._out('/Count %s' % len(self.document.pages))

        # Overall size of the default PDF page
        self.session._out('/MediaBox [0 0 %.2f %.2f]' %
                          (self.document.page.width,
                           self.document.page.height))
        self.session._out('>>')
        self.session._out('endobj')

def
_put_pages
(
self
)
:
self
.
document
.
_get_orientation_changes
(
)
self
.
document
.
_output_pages
(
)
self
.
session
.
_add_object
(
1
)
self
.
session
.
_out
(
'<</Type /Pages'
)
kids
=
'/Kids ['
for
i
in
xrange
(
0
,
len
(
self
.
document
.
pages
)
)
:
kids
+=
str
(
3
+
2
*
i
)
+
' 0 R '
self
.
session
.
_out
(
kids
+
']'
)
self
.
session
.
_out
(
'/Count %s'
%
len
(
self
.
document
.
pages
)
)
self
.
session
.
_out
(
'/MediaBox [0 0 %.2f %.2f]'
%
(
self
.
document
.
page
.
width
,
self
.
document
.
page
.
height
)
)
self
.
session
.
_out
(
'>>'
)
self
.
session
.
_out
(
'endobj'
)

First the Document object does the heavy - lifting for the individual page objects and content . Then the overall Pages object is generated .


def _put_resource_dict(self):
        """ Creates PDF reference to resource objects.

        """
        self.session._add_object(2)
        self.session._out('<<')
        self.session._out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]')
        self.session._out('/Font <<')
        for font in self.document.fonts:
            self.session._out('/F%s %s 0 R' % (font.index, font.number))
        self.session._out('>>')
        if self.document.images:
            self.session._out('/XObject <<')
            for image in self.document.images:
                self.session._out('/I%s %s 0 R' % (image.index, image.number))
            self.session._out('>>')
        self.session._out('>>')
        self.session._out('endobj')

Creates PDF reference to resource objects .


def _put_information(self):
        """PDF Information object."""
        self.session._add_object()
        self.session._out('<<')
        self.session._out('/Producer ' + self._text_to_string(
            'PDFLite, https://github.com/katerina7479'))
        if self.title:
            self.session._out('/Title ' + self._text_to_string(self.title))
        if self.subject:
            self.session._out('/Subject ' + self._text_to_string(self.subject))
        if self.author:
            self.session._out('/Author ' + self._text_to_string(self.author))
        if self.keywords:
            self.session._out('/Keywords ' +
                              self._text_to_string(self.keywords))
        if self.creator:
            self.session._out('/Creator ' + self._text_to_string(self.creator))
        self.session._out('/CreationDate ' + self._text_to_string(
            'D:' + datetime.now().strftime('%Y%m%d%H%M%S')))
        self.session._out('>>')
        self.session._out('endobj')


def _put_catalog(self):
        """Catalog object."""
        self.session._add_object()
        self.session._out('<<')

        self.session._out('/Type /Catalog')
        self.session._out('/Pages 1 0 R')
        if self.zoom_mode == 'fullpage':
            self.session._out('/OpenAction [3 0 R /Fit]')
        elif self.zoom_mode == 'fullwidth':
            self.session._out('/OpenAction [3 0 R /FitH null]')
        elif self.zoom_mode == 'real':
            self.session._out('/OpenAction [3 0 R /XYZ null null 1]')
        elif not isinstance(self.zoom_mode, basestring):
            self.session._out(
                '/OpenAction [3 0 R /XYZ null null ' +
                (self.zoom_mode / 100) + ']')

        if self.layout_mode == 'single':
            self.session._out('/PageLayout /SinglePage')
        elif self.layout_mode == 'continuous':
            self.session._out('/PageLayout /OneColumn')
        elif self.layout_mode == 'two':
            self.session._out('/PageLayout /TwoColumnLeft')
        self.session._out('>>')
        self.session._out('endobj')

def
_put_catalog
(
self
)
:
self
.
session
.
_add_object
(
)
self
.
session
.
_out
(
'<<'
)
self
.
session
.
_out
(
'/Type /Catalog'
)
self
.
session
.
_out
(
'/Pages 1 0 R'
)
if
self
.
zoom_mode
==
'fullpage'
:
self
.
session
.
_out
(
'/OpenAction [3 0 R /Fit]'
)
elif
self
.
zoom_mode
==
'fullwidth'
:
self
.
session
.
_out
(
'/OpenAction [3 0 R /FitH null]'
)
elif
self
.
zoom_mode
==
'real'
:
self
.
session
.
_out
(
'/OpenAction [3 0 R /XYZ null null 1]'
)
elif
not
isinstance
(
self
.
zoom_mode
,
basestring
)
:
self
.
session
.
_out
(
'/OpenAction [3 0 R /XYZ null null '
+
(
self
.
zoom_mode
/
100
)
+
']'
)
if
self
.
layout_mode
==
'single'
:
self
.
session
.
_out
(
'/PageLayout /SinglePage'
)
elif
self
.
layout_mode
==
'continuous'
:
self
.
session
.
_out
(
'/PageLayout /OneColumn'
)
elif
self
.
layout_mode
==
'two'
:
self
.
session
.
_out
(
'/PageLayout /TwoColumnLeft'
)
self
.
session
.
_out
(
'>>'
)
self
.
session
.
_out
(
'endobj'
)


def _put_trailer(self):
        """ Final Trailer calculations, and end-of-file
            reference.

        """
        startxref = len(self.session.buffer)

        self._put_cross_reference()

        md5 = hashlib.md5()
        md5.update(datetime.now().strftime('%Y%m%d%H%M%S'))
        try:
            md5.update(self.filepath)
        except TypeError:
            pass
        if self.title:
            md5.update(self.title)
        if self.subject:
            md5.update(self.subject)
        if self.author:
            md5.update(self.author)
        if self.keywords:
            md5.update(self.keywords)
        if self.creator:
            md5.update(self.creator)

        objnum = len(self.session.objects)
        self.session._out('trailer')
        self.session._out('<<')
        self.session._out('/Size %s' % objnum)
        self.session._out('/Root %s 0 R' % (objnum - 1))
        self.session._out('/Info %s 0 R' % (objnum - 2))
        self.session._out('/ID [ <%s> <%s>]' % (md5.hexdigest(),md5.hexdigest()))
        self.session._out('>>')
        self.session._out('startxref')
        self.session._out(startxref)
        self.session._out('%%EOF')

def
_put_trailer
(
self
)
:
startxref
=
len
(
self
.
session
.
buffer
)
self
.
_put_cross_reference
(
)
md5
=
hashlib
.
md5
(
)
md5
.
update
(
datetime
.
now
(
)
.
strftime
(
'%Y%m%d%H%M%S'
)
)
try
:
md5
.
update
(
self
.
filepath
)
except
TypeError
:
pass
if
self
.
title
:
md5
.
update
(
self
.
title
)
if
self
.
subject
:
md5
.
update
(
self
.
subject
)
if
self
.
author
:
md5
.
update
(
self
.
author
)
if
self
.
keywords
:
md5
.
update
(
self
.
keywords
)
if
self
.
creator
:
md5
.
update
(
self
.
creator
)
objnum
=
len
(
self
.
session
.
objects
)
self
.
session
.
_out
(
'trailer'
)
self
.
session
.
_out
(
'<<'
)
self
.
session
.
_out
(
'/Size %s'
%
objnum
)
self
.
session
.
_out
(
'/Root %s 0 R'
%
(
objnum
1
)
)
self
.
session
.
_out
(
'/Info %s 0 R'
%
(
objnum
2
)
)
self
.
session
.
_out
(
'/ID [ <%s> <%s>]'
%
(
md5
.
hexdigest
(
)
,
md5
.
hexdigest
(
)
)
)
self
.
session
.
_out
(
'>>'
)
self
.
session
.
_out
(
'startxref'
)
self
.
session
.
_out
(
startxref
)
self
.
session
.
_out
(
'%%EOF'
)

Final Trailer calculations and end - of - file reference .


def floyd(seqs, f=None, start=None, key=lambda x: x):
    """Floyd's Cycle Detector.

    See help(cycle_detector) for more context.

    Args:

      *args: Two iterators issueing the exact same sequence:
      -or-
      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found; if called with f and `start`,
      the parametres `first` and `period` will be defined indicating
      the offset of start of the cycle and the cycle's period.
    """

    tortise, hare = seqs

    yield hare.next()
    tortise_value = tortise.next()
    hare_value = hare.next()
    while hare_value != tortise_value:
        yield hare_value
        yield hare.next()
        hare_value = hare.next()
        tortise_value = tortise.next()

    if f is None:
        raise CycleDetected()

    hare_value = f(hare_value)
    first = 0
    tortise_value = start
    while key(tortise_value) != key(hare_value):
        tortise_value = f(tortise_value)
        hare_value = f(hare_value)
        first += 1

    period = 1
    hare_value = f(tortise_value)
    while key(tortise_value) != key(hare_value):
        hare_value = f(hare_value)
        period += 1

    raise CycleDetected(period=period, first=first)

def floyd ( seqs , f = None , start = None , key = lambda x : x ) : tortise , hare = seqs yield hare . next ( ) tortise_value = tortise . next ( ) hare_value = hare . next ( ) while hare_value != tortise_value : yield hare_value yield hare . next ( ) hare_value = hare . next ( ) tortise_value = tortise . next ( ) if f is None : raise CycleDetected ( ) hare_value = f ( hare_value ) first = 0 tortise_value = start while key ( tortise_value ) != key ( hare_value ) : tortise_value = f ( tortise_value ) hare_value = f ( hare_value ) first += 1 period = 1 hare_value = f ( tortise_value ) while key ( tortise_value ) != key ( hare_value ) : hare_value = f ( hare_value ) period += 1 raise CycleDetected ( period = period , first = first )


def naive(seqs, f=None, start=None, key=lambda x: x):
    """Naive cycle detector

    See help(cycle_detector) for more context.

    Args:

      sequence: A sequence to detect cyles in.

      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found.  Will always generate a first
      and period value no matter which of the `seqs` or `f` interface
      is used.
    """
    history = {}
    for step, value in enumerate(seqs[0]):
        keyed = key(value)
        yield value
        if keyed in history:
            raise CycleDetected(
                first=history[keyed], period=step - history[keyed])
        history[keyed] = step

def naive ( seqs , f = None , start = None , key = lambda x : x ) : history = { } for step , value in enumerate ( seqs [ 0 ] ) : keyed = key ( value ) yield value if keyed in history : raise CycleDetected ( first = history [ keyed ] , period = step - history [ keyed ] ) history [ keyed ] = step


def gosper(seqs, f=None, start=None, key=lambda x: x):
    """Gosper's cycle detector

    See help(cycle_detector) for more context.

    Args:

      sequence: A sequence to detect cyles in.

      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found.  Unlike Floyd and Brent's,
      Gosper's can only detect period of a cycle.  It cannot
      compute the first position
    """

    tab = []
    for c, value in enumerate(seqs[0], start=1):
        yield value
        try:
            e = tab.index(key(value))
            raise CycleDetected(
                period=c - ((((c >> e) - 1) | 1) << e))
        except ValueError:
            try:
                tab[(c ^ (c - 1)).bit_length() - 1] = key(value)
            except IndexError:
                tab.append(value)

def gosper ( seqs , f = None , start = None , key = lambda x : x ) : tab = [ ] for c , value in enumerate ( seqs [ 0 ] , start = 1 ) : yield value try : e = tab . index ( key ( value ) ) raise CycleDetected ( period = c - ( ( ( ( c >> e ) - 1 ) | 1 ) << e ) ) except ValueError : try : tab [ ( c ^ ( c - 1 ) ) . bit_length ( ) - 1 ] = key ( value ) except IndexError : tab . append ( value )


def brent(seqs, f=None, start=None, key=lambda x: x):
    """Brent's Cycle Detector.

    See help(cycle_detector) for more context.

    Args:

      *args: Two iterators issueing the exact same sequence:
      -or-
      f, start: Function and starting state for finite state machine

    Yields:

      Values yielded by sequence_a if it terminates, undefined if a
      cycle is found.

    Raises:

      CycleFound if exception is found; if called with f and `start`,
      the parametres `first` and `period` will be defined indicating
      the offset of start of the cycle and the cycle's period.
    """

    power = period = 1
    tortise, hare = seqs

    yield hare.next()
    tortise_value = tortise.next()
    hare_value = hare.next()
    while key(tortise_value) != key(hare_value):
        yield hare_value
        if power == period:
            power *= 2
            period = 0
            if f:
                tortise = f_generator(f, hare_value)
                tortise_value = tortise.next()
            else:
                while tortise_value != hare_value:
                    tortise_value = tortise.next()
        hare_value = hare.next()
        period += 1

    if f is None:
        raise CycleDetected()

    first = 0
    tortise_value = hare_value = start
    for _ in xrange(period):
        hare_value = f(hare_value)

    while key(tortise_value) != key(hare_value):
        tortise_value = f(tortise_value)
        hare_value = f(hare_value)
        first += 1
    raise CycleDetected(period=period, first=first)

def brent ( seqs , f = None , start = None , key = lambda x : x ) : power = period = 1 tortise , hare = seqs yield hare . next ( ) tortise_value = tortise . next ( ) hare_value = hare . next ( ) while key ( tortise_value ) != key ( hare_value ) : yield hare_value if power == period : power *= 2 period = 0 if f : tortise = f_generator ( f , hare_value ) tortise_value = tortise . next ( ) else : while tortise_value != hare_value : tortise_value = tortise . next ( ) hare_value = hare . next ( ) period += 1 if f is None : raise CycleDetected ( ) first = 0 tortise_value = hare_value = start for _ in xrange ( period ) : hare_value = f ( hare_value ) while key ( tortise_value ) != key ( hare_value ) : tortise_value = f ( tortise_value ) hare_value = f ( hare_value ) first += 1 raise CycleDetected ( period = period , first = first )


def x_fit(self, test_length):
        """ Test to see if the line can has enough space for the given length. """
        if (self.x + test_length) >= self.xmax:
            return False
        else:
            return True

def x_fit ( self , test_length ) : if ( self . x + test_length ) >= self . xmax : return False else : return True

Test to see if the line can has enough space for the given length .


def y_fit(self, test_length):
        """ Test to see if the page has enough space for the given text height. """
        if (self.y + test_length) >= self.ymax:
            return False
        else:
            return True

def y_fit ( self , test_length ) : if ( self . y + test_length ) >= self . ymax : return False else : return True

Test to see if the page has enough space for the given text height .


def x_is_greater_than(self, test_ordinate):
        """ Comparison for x coordinate"""
        self._is_coordinate(test_ordinate)
        if self.x > test_ordinate.x:
            return True
        else:
            return False

def x_is_greater_than ( self , test_ordinate ) : self . _is_coordinate ( test_ordinate ) if self . x > test_ordinate . x : return True else : return False


def y_is_greater_than(self, test_ordinate):
        """Comparison for y coordinate"""
        self._is_coordinate(test_ordinate)
        if self.y > test_ordinate.y:
            return True
        else:
            return False

def y_is_greater_than ( self , test_ordinate ) : self . _is_coordinate ( test_ordinate ) if self . y > test_ordinate . y : return True else : return False


def copy(self):
        """ Create a copy, and return it."""
        new_cursor = self.__class__(self.x, self.y)
        new_cursor.set_bounds(self.xmin, self.ymin, self.xmax, self.ymax, self.ymaxmax)
        new_cursor.set_deltas(self.dx, self.dy)
        return new_cursor

def copy ( self ) : new_cursor = self . __class__ ( self . x , self . y ) new_cursor . set_bounds ( self . xmin , self . ymin , self . xmax , self . ymax , self . ymaxmax ) new_cursor . set_deltas ( self . dx , self . dy ) return new_cursor


def x_plus(self, dx=None):
        """ Mutable x addition. Defaults to set delta value. """
        if dx is None:
            self.x += self.dx
        else:
            self.x = self.x + dx

def x_plus ( self , dx = None ) : if dx is None : self . x += self . dx else : self . x = self . x + dx

Mutable x addition . Defaults to set delta value .


def y_plus(self, dy=None):
        """ Mutable y addition. Defaults to set delta value. """
        if dy is None:
            self.y += self.dy
        else:
            self.y = self.y + dy

def y_plus ( self , dy = None ) : if dy is None : self . y += self . dy else : self . y = self . y + dy

Mutable y addition . Defaults to set delta value .


def _draw(self):
        """ Don't use this, use document.draw_table """
        self._compile()
        self.rows[0]._advance_first_row()
        self._set_borders()
        self._draw_fill()
        self._draw_borders()
        self._draw_text()
        self._set_final_cursor()

def _draw ( self ) : self . _compile ( ) self . rows [ 0 ] . _advance_first_row ( ) self . _set_borders ( ) self . _draw_fill ( ) self . _draw_borders ( ) self . _draw_text ( ) self . _set_final_cursor ( )

Don t use this use document . draw_table


def create(self, name, description=None, color=None):
        """
        Creates a new label and returns the response

        :param name: The label name
        :type name: str

        :param description: An optional description for the label. The name is
            used if no description is provided.
        :type description: str

        :param color: The hex color for the label (ex: 'ff0000' for red). If no
            color is provided, a random one will be assigned.
        :type color: str

        :returns: The response of your post
        :rtype: dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        data = {
            'name': name,
            'title': name,
            'description': description or name,
            'appearance': {
                'color': color or random_color()
            }
        }
        # Yes, it's confusing. the `/tags/` endpoint is used for labels
        return self._post(
            request=ApiActions.CREATE.value,
            uri=ApiUri.TAGS.value,
            params=data
        )

def create ( self , name , description = None , color = None ) : data = { 'name' : name , 'title' : name , 'description' : description or name , 'appearance' : { 'color' : color or random_color ( ) } } return self . _post ( request = ApiActions . CREATE . value , uri = ApiUri . TAGS . value , params = data )


def list(self):
        """
        Get all current labels

        :return: The Logentries API response
        :rtype: list of dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        return self._post(
            request='list',
            uri=ApiUri.TAGS.value,
        ).get('tags')

def list ( self ) : return self . _post ( request = 'list' , uri = ApiUri . TAGS . value , ) . get ( 'tags' )


def get(self, name):
        """
        Get labels by name

        :param name: The label name, it must be an exact match.
        :type name: str

        :return: A list of matching labels. An empty list is returned if there are
            not any matches
        :rtype: list of dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        labels = self.list()
        return [
            label
            for label
            in labels
            if name == label.get('name')
        ]

def get ( self , name ) : labels = self . list ( ) return [ label for label in labels if name == label . get ( 'name' ) ]


def update(self, label):
        """
        Update a Label

        :param label: The data to update. Must include keys:

            * id (str)
            * appearance (dict)
            * description (str)
            * name (str)
            * title (str)
        :type label: dict

        Example:

        .. code-block:: python

            Labels().update(
                label={
                    'id': 'd9d4596e-49e4-4135-b3b3-847f9e7c1f43',
                    'appearance': {'color': '278abe'},
                    'name': 'My Sandbox',
                    'description': 'My Sandbox',
                    'title': 'My Sandbox',
                }
            )

        :return:
        :rtype: dict
        """
        data = {
            'id': label['id'],
            'name': label['name'],
            'appearance': label['appearance'],
            'description': label['description'],
            'title': label['title'],
        }
        return self._post(
            request=ApiActions.UPDATE.value,
            uri=ApiUri.TAGS.value,
            params=data
        )

def update ( self , label ) : data = { 'id' : label [ 'id' ] , 'name' : label [ 'name' ] , 'appearance' : label [ 'appearance' ] , 'description' : label [ 'description' ] , 'title' : label [ 'title' ] , } return self . _post ( request = ApiActions . UPDATE . value , uri = ApiUri . TAGS . value , params = data )


def delete(self, id):
        """
        Delete the specified label

        :param id: the label's ID
        :type id: str

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        return self._post(
            request=ApiActions.DELETE.value,
            uri=ApiUri.TAGS.value,
            params={'id': id}
        )

def delete ( self , id ) : return self . _post ( request = ApiActions . DELETE . value , uri = ApiUri . TAGS . value , params = { 'id' : id } )


def create(self, label_id):
        """
        Create a new tag

        :param label_id: The Label ID (the 'sn' key of the create label response)
        :type label_id: str

        :returns: The response of your post
        :rtype: dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        data = {
            'type': 'tagit',
            'rate_count': 0,
            'rate_range': 'day',
            'limit_count': 0,
            'limit_range': 'day',
            'schedule': [],
            'enabled': True,
            'args': {
                'sn': label_id,
                'tag_sn': label_id
            }
        }
        # Yes, it's confusing. the `/actions/` endpoint is used for tags, while
        # the /tags/ endpoint is used for labels.
        return self._post(
            request=ApiActions.CREATE.value,
            uri=ApiUri.ACTIONS.value,
            params=data
        )

def create ( self , label_id ) : data = { 'type' : 'tagit' , 'rate_count' : 0 , 'rate_range' : 'day' , 'limit_count' : 0 , 'limit_range' : 'day' , 'schedule' : [ ] , 'enabled' : True , 'args' : { 'sn' : label_id , 'tag_sn' : label_id } } return self . _post ( request = ApiActions . CREATE . value , uri = ApiUri . ACTIONS . value , params = data )


def list(self):
        """
        Get all current tags

        :return: All tags
        :rtype: list of dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        return list(
            filter(
                lambda x: x.get('type') == 'tagit',  # pragma: no cover
                self._post(
                    request=ApiActions.LIST.value,
                    uri=ApiUri.ACTIONS.value,
                ).get('actions')
            )
        )

def list ( self ) : return list ( filter ( lambda x : x . get ( 'type' ) == 'tagit' , self . _post ( request = ApiActions . LIST . value , uri = ApiUri . ACTIONS . value , ) . get ( 'actions' ) ) )


def get(self, label_sn):
        """
        Get tags by a label's sn key

        :param label_sn: A corresponding label's ``sn`` key.
        :type label_sn: str or int

        :return: A list of matching tags. An empty list is returned if there are
            not any matches
        :rtype: list of dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        tags = self.list()
        return [
            tag
            for tag
            in tags
            if str(label_sn) in tag.get('args', {}).values()
        ]

def get ( self , label_sn ) : tags = self . list ( ) return [ tag for tag in tags if str ( label_sn ) in tag . get ( 'args' , { } ) . values ( ) ]


def create(self, name, regexes, tag_ids, logs=None):
        """
        Create a hook

        :param name: The hook's name (should be the same as the tag)
        :type name: str

        :param regexes: The list of regular expressions that Logentries expects.
            Ex: `['user_agent = /curl\/[\d.]*/']` Would match where the
            user-agent is curl.
        :type regexes: list of str

        :param tag_id: The ids of the tags to associate the hook with.
            (The 'id' key of the create tag response)
        :type tag_id: list of str

        :param logs: The logs to add the hook to. Comes from the 'key'
            key in the log dict.
        :type logs: list of str

        :returns: The response of your post
        :rtype: dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        data = {
            'name': name,
            'triggers': regexes,
            'sources': logs or [],
            'groups': [],
            'actions': tag_ids
        }
        return self._post(
            request=ApiActions.CREATE.value,
            uri=ApiUri.HOOKS.value,
            params=data
        )

def create ( self , name , regexes , tag_ids , logs = None ) : data = { 'name' : name , 'triggers' : regexes , 'sources' : logs or [ ] , 'groups' : [ ] , 'actions' : tag_ids } return self . _post ( request = ApiActions . CREATE . value , uri = ApiUri . HOOKS . value , params = data )


def list(self):
        """
        Get all current hooks

        :return: All hooks
        :rtype: list of dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        return self._post(
            request=ApiActions.LIST.value,
            uri=ApiUri.HOOKS.value,
        ).get('hooks')

def list ( self ) : return self . _post ( request = ApiActions . LIST . value , uri = ApiUri . HOOKS . value , ) . get ( 'hooks' )


def update(self, hook):
        """
        Update a hook

        :param hook: The data to update. Must include keys:

            * id (str)
            * name (str)
            * triggers (list of str)
            * sources (list of str)
            * groups (list of str)
            * actions (list of str)
        :type hook: dict

        Example:

        .. code-block:: python

            Hooks().update(
                hook={
                    'id': 'd9d4596e-49e4-4135-b3b3-847f9e7c1f43',
                    'name': 'My Sandbox',
                    'triggers': [
                        'host = you.example.com'
                    ],
                    'sources': [
                        '4d42c719-4005-4929-aa4a-994da4b95040'
                    ],
                    'groups': [],
                    'actions': [
                        '9f6adf69-37b9-4a4b-88fb-c3fc4c781a11',
                        'ddc36d71-33cb-4f4f-be1b-8591814b1946'
                    ],
                }
            )

        :return:
        :rtype: dict
        """
        data = {
            'id': hook['id'],
            'name': hook['name'],
            'triggers': hook['triggers'],
            'sources': hook['sources'],
            'groups': hook['groups'],
            'actions': hook['actions'],
        }
        return self._post(
            request=ApiActions.UPDATE.value,
            uri=ApiUri.HOOKS.value,
            params=data
        )

def update ( self , hook ) : data = { 'id' : hook [ 'id' ] , 'name' : hook [ 'name' ] , 'triggers' : hook [ 'triggers' ] , 'sources' : hook [ 'sources' ] , 'groups' : hook [ 'groups' ] , 'actions' : hook [ 'actions' ] , } return self . _post ( request = ApiActions . UPDATE . value , uri = ApiUri . HOOKS . value , params = data )


def create(self,
               alert_config,
               occurrence_frequency_count=None,
               occurrence_frequency_unit=None,
               alert_frequency_count=None,
               alert_frequency_unit=None):
        """
        Create a new alert

        :param alert_config: A list of AlertConfig classes (Ex:
            ``[EmailAlertConfig('me@mydomain.com')]``)
        :type alert_config: list of
            :class:`PagerDutyAlertConfig<logentries_api.alerts.PagerDutyAlertConfig>`,
            :class:`WebHookAlertConfig<logentries_api.alerts.WebHookAlertConfig>`,
            :class:`EmailAlertConfig<logentries_api.alerts.EmailAlertConfig>`,
            :class:`SlackAlertConfig<logentries_api.alerts.SlackAlertConfig>`, or
            :class:`HipChatAlertConfig<logentries_api.alerts.HipChatAlertConfig>`

        :param occurrence_frequency_count: How many times per
            ``alert_frequency_unit`` for a match before issuing an alert.
            Defaults to 1
        :type occurrence_frequency_count: int

        :param occurrence_frequency_unit: The time period to monitor for sending
            an alert. Must be 'day', or 'hour'. Defaults to 'hour'
        :type occurrence_frequency_unit: str

        :param alert_frequency_count: How many times per
            ``alert_frequency_unit`` to issue an alert. Defaults to 1
        :type alert_frequency_count: int

        :param alert_frequency_unit: How often to regulate sending alerts.
            Must be 'day', or 'hour'. Defaults to 'hour'
        :type alert_frequency_unit: str

        :returns: The response of your post
        :rtype: dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        data = {
            'rate_count': occurrence_frequency_count or 1,
            'rate_range': occurrence_frequency_unit or 'hour',
            'limit_count': alert_frequency_count or 1,
            'limit_range': alert_frequency_unit or 'hour',
            'schedule': [],
            'enabled': True,
        }
        data.update(alert_config.args())

        # Yes, it's confusing. the `/actions/` endpoint is used for alerts, while
        # the /tags/ endpoint is used for labels.
        return self._post(
            request=ApiActions.CREATE.value,
            uri=ApiUri.ACTIONS.value,
            params=data
        )

def create ( self , alert_config , occurrence_frequency_count = None , occurrence_frequency_unit = None , alert_frequency_count = None , alert_frequency_unit = None ) : data = { 'rate_count' : occurrence_frequency_count or 1 , 'rate_range' : occurrence_frequency_unit or 'hour' , 'limit_count' : alert_frequency_count or 1 , 'limit_range' : alert_frequency_unit or 'hour' , 'schedule' : [ ] , 'enabled' : True , } data . update ( alert_config . args ( ) ) return self . _post ( request = ApiActions . CREATE . value , uri = ApiUri . ACTIONS . value , params = data )


def get(self, alert_type, alert_args=None):
        """
        Get alerts that match the alert type and args.

        :param alert_type: The type of the alert. Must be one of 'pagerduty',
            'mailto', 'webhook', 'slack', or 'hipchat'
        :type alert_type: str

        :param alert_args: The args for the alert. The provided args must be a
            subset of the actual alert args. If no args are provided, all
            alerts matching the ``alert_type`` are returned. For example:
            ``.get('mailto', alert_args={'direct': 'me@mydomain.com'})`` or
            ``.get('slack', {'url': 'https://hooks.slack.com/services...'})``

        :return: A list of matching alerts. An empty list is returned if there
            are not any matches
        :rtype: list of dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        alert_args = alert_args or {}

        alerts = self.list()
        return [
            alert
            for alert
            in alerts
            if alert.get('type') == alert_type
            and dict_is_subset(alert_args, alert.get('args'))
        ]

def get ( self , alert_type , alert_args = None ) : alert_args = alert_args or { } alerts = self . list ( ) return [ alert for alert in alerts if alert . get ( 'type' ) == alert_type and dict_is_subset ( alert_args , alert . get ( 'args' ) ) ]

Get alerts that match the alert type and args .


def update(self, alert):
        """
        Update an alert

        :param alert: The data to update. Must include keys:

            * id (str)
            * rate_count (int)
            * rate_range (str): 'day' or 'hour'
            * limit_count (int)
            * limit_range (str): 'day' or 'hour'
            * type (str)
            * schedule (list)
            * args (dict)
        :type alert: dict

        Example:

        .. code-block:: python

            Alert().update(
                alert={
                    'id': 'd9d4596e-49e4-4135-b3b3-847f9e7c1f43',
                    'args': {'direct': 'you@example.com'},
                    'rate_count': 1,
                    'rate_range': 'hour',
                    'limit_count': 1,
                    'limit_range': 'hour',
                    'schedule': [],
                    'enabled': True,
                    'type': 'mailto',
                }
            )

        :return:
        :rtype: dict
        """
        data = {
            'id': alert['id'],
            'args': alert['args'],
            'rate_count': alert['rate_count'],
            'rate_range': alert['rate_range'],
            'limit_count': alert['limit_count'],
            'limit_range': alert['limit_range'],
            'schedule': alert['schedule'],
            'enabled': alert['enabled'],
            'type': alert['type'],
        }

        return self._post(
            request=ApiActions.UPDATE.value,
            uri=ApiUri.ACTIONS.value,
            params=data
        )

def update ( self , alert ) : data = { 'id' : alert [ 'id' ] , 'args' : alert [ 'args' ] , 'rate_count' : alert [ 'rate_count' ] , 'rate_range' : alert [ 'rate_range' ] , 'limit_count' : alert [ 'limit_count' ] , 'limit_range' : alert [ 'limit_range' ] , 'schedule' : alert [ 'schedule' ] , 'enabled' : alert [ 'enabled' ] , 'type' : alert [ 'type' ] , } return self . _post ( request = ApiActions . UPDATE . value , uri = ApiUri . ACTIONS . value , params = data )


def setup(app):
    """
    Initialize this Sphinx extension
    """
    app.setup_extension('sphinx.ext.todo')
    app.setup_extension('sphinx.ext.mathjax')

    app.setup_extension("sphinx.ext.intersphinx")
    app.config.intersphinx_mapping.update({
        'https://docs.python.org/': None
        })
    app.config.intersphinx_mapping.update({
        sage_doc_url + doc + "/": None
        for doc in sage_documents
        })
    app.config.intersphinx_mapping.update({
        sage_doc_url + "reference/" + module: None
        for module in sage_modules
        })

    app.setup_extension("sphinx.ext.extlinks")
    app.config.extlinks.update({
        'python': ('https://docs.python.org/release/'+pythonversion+'/%s', ''),
        # Sage trac ticket shortcuts. For example, :trac:`7549` .
        'trac': ('https://trac.sagemath.org/%s', 'trac ticket #'),
        'wikipedia': ('https://en.wikipedia.org/wiki/%s', 'Wikipedia article '),
        'arxiv': ('http://arxiv.org/abs/%s', 'Arxiv '),
        'oeis': ('https://oeis.org/%s', 'OEIS sequence '),
        'doi': ('https://dx.doi.org/%s', 'doi:'),
        'pari': ('http://pari.math.u-bordeaux.fr/dochtml/help/%s', 'pari:'),
        'mathscinet': ('http://www.ams.org/mathscinet-getitem?mr=%s', 'MathSciNet ')
        })

    app.config.html_theme = 'sage'


def themes_path():
    """
    Retrieve the location of the themes directory from the location of this package

    This is taken from Sphinx's theme documentation
    """
    package_dir = os.path.abspath(os.path.dirname(__file__))
    return os.path.join(package_dir, 'themes')

def themes_path ( ) : package_dir = os . path . abspath ( os . path . dirname ( __file__ ) ) return os . path . join ( package_dir , 'themes' )


def _post(self, request, uri, params=None):
        """
        A wrapper for posting things.

        :param request: The request type. Must be one of the
            :class:`ApiActions<logentries_api.base.ApiActions>`
        :type request: str

        :param uri: The API endpoint to hit. Must be one of
            :class:`ApiUri<logentries_api.base.ApiUri>`
        :type uri: str

        :param params: A dictionary of supplemental kw args
        :type params: dict

        :returns: The response of your post
        :rtype: dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        request_data = {
            'acl': self.account_key,
            'account': self.account_key,
            'request': request,
        }

        request_data.update(params or {})

        response = requests.post(
            url='https://api.logentries.com/v2/{}'.format(uri),
            headers=self.headers,
            data=json.dumps(request_data)
        )

        if not response.ok:
            raise ServerException(
                '{}: {}'.format(response.status_code, response.text))
        return response.json()

def
_post
(
self
,
request
,
uri
,
params
=
)
:
request_data
=
{
'acl'
:
self
.
account_key
,
'account'
:
self
.
account_key
,
'request'
:
request
,
}
request_data
.
update
(
params
or
{
}
)
response
=
requests
.
post
(
url
=
'https://api.logentries.com/v2/{}'
.
format
(
uri
)
,
headers
=
self
.
headers
,
data
=
json
.
dumps
(
request_data
)
)
if
not
response
.
ok
:
raise
ServerException
(
'{}: {}'
.
format
(
response
.
status_code
,
response
.
text
)
)
return
response
.
json
(
)


def list(self):
        """
        Get all log sets

        :return: Returns a dictionary where the key is the hostname or log set,
            and the value is a list of the log keys
        :rtype: dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        response = requests.get(self.base_url)

        if not response.ok:
            raise ServerException(
                '{}: {}'.format(response.status_code, response.text))

        return {
            host.get('name'): [
                log.get('key')
                for log
                in host.get('logs')]
            for host
            in response.json().get('list')
        }

def
list
(
self
)
:
response
=
requests
.
get
(
self
.
base_url
)
if
not
response
.
ok
:
raise
ServerException
(
'{}: {}'
.
format
(
response
.
status_code
,
response
.
text
)
)
return
{
host
.
get
(
'name'
)
:
[
log
.
get
(
'key'
)
for
log
in
host
.
get
(
'logs'
)
]
for
host
in
response
.
json
(
)
.
get
(
'list'
)
}


def get(self, log_set):
        """
        Get a specific log or log set

        :param log_set: The log set or log to get. Ex: `.get(log_set='app')` or
            `.get(log_set='app/log')`
        :type log_set: str

        :returns: The response of your log set or log
        :rtype: dict

        :raises: This will raise a
            :class:`ServerException<logentries_api.exceptions.ServerException>`
            if there is an error from Logentries
        """
        response = requests.get(self.base_url + log_set.rstrip('/'))

        if not response.ok:
            raise ServerException(
                '{}: {}'.format(response.status_code, response.text))
        return response.json()

def
get
(
self
,
log_set
)
:
response
=
requests
.
get
(
self
.
base_url
+
log_set
.
rstrip
(
'/'
)
)
if
not
response
.
ok
:
raise
ServerException
(
'{}: {}'
.
format
(
response
.
status_code
,
response
.
text
)
)
return
response
.
json
(
)


def find_attacker_slider(dest_list, occ_bb, piece_bb, target_bb, pos,
                             domain):
    """ Find a slider attacker

    Parameters
    ----------
    dest_list : list
        To store the results.
    occ_bb : int, bitboard
        Occupancy bitboard.
    piece_bb : int, bitboard
        Bitboard with the position of the attacker piece.
    target_bb : int, bitboard
        Occupancy bitboard without any of the sliders in question.
    pos : int
        Target position.
    pos_map : function
        Mapping between a board position and its position in a single
        rotated/translated rank produced with domain_trans.
    domain_trans : function
        Transformation from a rank/file/diagonal/anti-diagonal containing pos
        to a single rank
    pos_inv_map : function
        Inverse of pos_map
    """
    pos_map, domain_trans, pos_inv_map = domain
    r = reach[pos_map(pos)][domain_trans(target_bb, pos)]
    m = r & domain_trans(piece_bb, pos)
    while m:
        r = m&-m
        rpos = r.bit_length()-1
        if not (ray[rpos][pos_map(pos)] & domain_trans(occ_bb, pos)):
            dest_list.append(pos_inv_map(rpos, pos))
        m ^= r

def find_attacker_slider ( dest_list , occ_bb , piece_bb , target_bb , pos , domain ) : pos_map , domain_trans , pos_inv_map = domain r = reach [ pos_map ( pos ) ] [ domain_trans ( target_bb , pos ) ] m = r & domain_trans ( piece_bb , pos ) while m : r = m & - m rpos = r . bit_length ( ) - 1 if not ( ray [ rpos ] [ pos_map ( pos ) ] & domain_trans ( occ_bb , pos ) ) : dest_list . append ( pos_inv_map ( rpos , pos ) ) m ^= r


def duration(self):
        '''
        The approximate transit duration for the general case of an eccentric orbit

        '''
        ecc = self.ecc if not np.isnan(self.ecc) else np.sqrt(self.ecw**2 + self.esw**2)
        esw = self.esw if not np.isnan(self.esw) else ecc * np.sin(self.w)
        aRs = ((G * self.rhos * (1. + self.MpMs) *
              (self.per * DAYSEC)**2.) / (3. * np.pi))**(1./3.)
        inc = np.arccos(self.bcirc/aRs)
        becc = self.bcirc * (1 - ecc**2)/(1 - esw)
        tdur = self.per / 2. / np.pi * np.arcsin(((1. + self.RpRs)**2 -
               becc**2)**0.5 / (np.sin(inc) * aRs))
        tdur *= np.sqrt(1. - ecc**2.)/(1. - esw)
        return tdur

def duration ( self ) : ecc = self . ecc if not np . isnan ( self . ecc ) else np . sqrt ( self . ecw ** 2 + self . esw ** 2 ) esw = self . esw if not np . isnan ( self . esw ) else ecc * np . sin ( self . w ) aRs = ( ( G * self . rhos * ( 1. + self . MpMs ) * ( self . per * DAYSEC ) ** 2. ) / ( 3. * np . pi ) ) ** ( 1. / 3. ) inc = np . arccos ( self . bcirc / aRs ) becc = self . bcirc * ( 1 - ecc ** 2 ) / ( 1 - esw ) tdur = self . per / 2. / np . pi * np . arcsin ( ( ( 1. + self . RpRs ) ** 2 - becc ** 2 ) ** 0.5 / ( np . sin ( inc ) * aRs ) ) tdur *= np . sqrt ( 1. - ecc ** 2. ) / ( 1. - esw ) return tdur


def update(self, **kwargs):
    '''
    Update the transit keyword arguments

    '''

    if kwargs.get('verify_kwargs', True):
      valid = [y[0] for x in [TRANSIT, LIMBDARK, SETTINGS] for y in x._fields_]       # List of valid kwargs
      valid += ['b', 'times']                                                         # These are special!
      for k in kwargs.keys():
        if k not in valid:
          raise Exception("Invalid kwarg '%s'." % k)

    if ('q1' in kwargs.keys()) and ('q2' in kwargs.keys()):
      kwargs.update({'ldmodel': KIPPING})
    elif ('c1' in kwargs.keys()) and ('c2' in kwargs.keys()) and \
         ('c3' in kwargs.keys()) and ('c4' in kwargs.keys()):
      kwargs.update({'ldmodel': NONLINEAR})

    self.limbdark.update(**kwargs)
    self.transit.update(**kwargs)
    self.settings.update(**kwargs)

def
update
(
self
,
**
kwargs
)
:
if
kwargs
.
get
(
'verify_kwargs'
,
True
)
:
valid
=
[
y
[
0
]
for
x
in
[
TRANSIT
,
LIMBDARK
,
SETTINGS
]
for
y
in
x
.
_fields_
]
valid
+=
[
'b'
,
'times'
]
for
k
in
kwargs
.
keys
(
)
:
if
k
not
in
valid
:
raise
Exception
(
"Invalid kwarg '%s'."
%
k
)
if
(
'q1'
in
kwargs
.
keys
(
)
)
and
(
'q2'
in
kwargs
.
keys
(
)
)
:
kwargs
.
update
(
{
'ldmodel'
:
KIPPING
}
)
elif
(
'c1'
in
kwargs
.
keys
(
)
)
and
(
'c2'
in
kwargs
.
keys
(
)
)
and
(
'c3'
in
kwargs
.
keys
(
)
)
and
(
'c4'
in
kwargs
.
keys
(
)
)
:
kwargs
.
update
(
{
'ldmodel'
:
NONLINEAR
}
)
self
.
limbdark
.
update
(
**
kwargs
)
self
.
transit
.
update
(
**
kwargs
)
self
.
settings
.
update
(
**
kwargs
)


def Compute(self):
    '''
    Computes the light curve model

    '''

    err = _Compute(self.transit, self.limbdark, self.settings, self.arrays)
    if err != _ERR_NONE: RaiseError(err)

def Compute ( self ) : err = _Compute ( self . transit , self . limbdark , self . settings , self . arrays ) if err != _ERR_NONE : RaiseError ( err )


def Bin(self):
    '''
    Bins the light curve model to the provided time array

    '''

    err = _Bin(self.transit, self.limbdark, self.settings, self.arrays)
    if err != _ERR_NONE: RaiseError(err)

def Bin ( self ) : err = _Bin ( self . transit , self . limbdark , self . settings , self . arrays ) if err != _ERR_NONE : RaiseError ( err )


def Free(self):
    '''
    Frees the memory used by all of the dynamically allocated C arrays.

    '''

    if self.arrays._calloc:
      _dbl_free(self.arrays._time)
      _dbl_free(self.arrays._flux)
      _dbl_free(self.arrays._bflx)
      _dbl_free(self.arrays._M)
      _dbl_free(self.arrays._E)
      _dbl_free(self.arrays._f)
      _dbl_free(self.arrays._r)
      _dbl_free(self.arrays._x)
      _dbl_free(self.arrays._y)
      _dbl_free(self.arrays._z)
      self.arrays._calloc = 0
    if self.arrays._balloc:
      _dbl_free(self.arrays._b)
      self.arrays._balloc = 0
    if self.arrays._ialloc:
      _dbl_free(self.arrays._iarr)
      self.arrays._ialloc = 0

def Free ( self ) : if self . arrays . _calloc : _dbl_free ( self . arrays . _time ) _dbl_free ( self . arrays . _flux ) _dbl_free ( self . arrays . _bflx ) _dbl_free ( self . arrays . _M ) _dbl_free ( self . arrays . _E ) _dbl_free ( self . arrays . _f ) _dbl_free ( self . arrays . _r ) _dbl_free ( self . arrays . _x ) _dbl_free ( self . arrays . _y ) _dbl_free ( self . arrays . _z ) self . arrays . _calloc = 0 if self . arrays . _balloc : _dbl_free ( self . arrays . _b ) self . arrays . _balloc = 0 if self . arrays . _ialloc : _dbl_free ( self . arrays . _iarr ) self . arrays . _ialloc = 0

Frees the memory used by all of the dynamically allocated C arrays .


def __recv(self, size=4096):
        """Reads data from the socket.

        Raises:
            NNTPError: When connection times out or read from socket fails.
        """
        data = self.socket.recv(size)
        if not data:
            raise NNTPError("Failed to read from socket")
        self.__buffer.write(data)

def
__recv
(
self
,
size
=
4096
)
:
data
=
self
.
socket
.
recv
(
size
)
if
not
data
:
raise
NNTPError
(
"Failed to read from socket"
)
self
.
__buffer
.
write
(
data
)


def __line_gen(self):
        """Generator that reads a line of data from the server.

        It first attempts to read from the internal buffer. If there is not
        enough data to read a line it then requests more data from the server
        and adds it to the buffer. This process repeats until a line of data
        can be read from the internal buffer.

        Yields:
            A line of data when it becomes available.
        """
        while True:
            line = self.__buffer.readline()
            if not line:
                self.__recv()
                continue
            yield line

def __line_gen ( self ) : while True : line = self . __buffer . readline ( ) if not line : self . __recv ( ) continue yield line

Generator that reads a line of data from the server .


def __buf_gen(self, length=0):
        """Generator that reads a block of data from the server.

        It first attempts to read from the internal buffer. If there is not
        enough data in the internal buffer it then requests more data from the
        server and adds it to the buffer.

        Args:
            length: An optional amount of data to retrieve. A length of 0 (the
                default) will retrieve a least one buffer of data.

        Yields:
            A block of data when enough data becomes available.

        Note:
            If a length of 0 is supplied then the size of the yielded buffer can
            vary. If there is data in the internal buffer it will yield all of
            that data otherwise it will yield the the data returned by a recv
            on the socket.
        """
        while True:
            buf = self.__buffer.read(length)
            if not buf:
                self.__recv()
                continue
            yield buf

def __buf_gen ( self , length = 0 ) : while True : buf = self . __buffer . read ( length ) if not buf : self . __recv ( ) continue yield buf

Generator that reads a block of data from the server .


def status(self):
        """Reads a command response status.

        If there is no response message then the returned status message will
        be an empty string.

        Raises:
            NNTPError: If data is required to be read from the socket and fails.
            NNTPProtocolError: If the status line can't be parsed.
            NNTPTemporaryError: For status code 400-499
            NNTPPermanentError: For status code 500-599

        Returns:
            A tuple of status code (as an integer) and status message.
        """
        line = next(self.__line_gen()).rstrip()
        parts = line.split(None, 1)

        try:
            code, message = int(parts[0]), ""
        except ValueError:
            raise NNTPProtocolError(line)

        if code < 100 or code >= 600:
            raise NNTPProtocolError(line)

        if len(parts) > 1:
            message = parts[1]

        if 400 <= code <= 499:
            raise NNTPTemporaryError(code, message)

        if 500 <= code <= 599:
            raise NNTPPermanentError(code, message)

        return code, message

def status ( self ) : line = next ( self . __line_gen ( ) ) . rstrip ( ) parts = line . split ( None , 1 ) try : code , message = int ( parts [ 0 ] ) , "" except ValueError : raise NNTPProtocolError ( line ) if code < 100 or code >= 600 : raise NNTPProtocolError ( line ) if len ( parts ) > 1 : message = parts [ 1 ] if 400 <= code <= 499 : raise NNTPTemporaryError ( code , message ) if 500 <= code <= 599 : raise NNTPPermanentError ( code , message ) return code , message


def info_gen(self, code, message, compressed=False):
        """Dispatcher for the info generators.

        Determines which __info_*_gen() should be used based on the supplied
        parameters.

        Args:
            code: The status code for the command response.
            message: The status message for the command reponse.
            compressed: Force decompression. Useful for xz* commands.

        Returns:
            An info generator.
        """
        if "COMPRESS=GZIP" in message:
            return self.__info_gzip_gen()
        if compressed:
            return self.__info_yenczlib_gen()
        return self.__info_plain_gen()

def info_gen ( self , code , message , compressed = False ) : if "COMPRESS=GZIP" in message : return self . __info_gzip_gen ( ) if compressed : return self . __info_yenczlib_gen ( ) return self . __info_plain_gen ( )


def info(self, code, message, compressed=False):
        """The complete content of an info response.

        This should only used for commands that return small or known amounts of
        data.

        Returns:
            A the complete content of a textual response.
        """
        return "".join([x for x in self.info_gen(code, message, compressed)])

def info ( self , code , message , compressed = False ) : return "" . join ( [ x for x in self . info_gen ( code , message , compressed ) ] )

The complete content of an info response .


def command(self, verb, args=None):
        """Call a command on the server.

        If the user has not authenticated then authentication will be done
        as part of calling the command on the server.

        For commands that don't return a status message the status message
        will default to an empty string.

        Args:
            verb: The verb of the command to call.
            args: The arguments of the command as a string (default None).

        Returns:
            A tuple of status code (as an integer) and status message.

        Note:
            You can run raw commands by supplying the full command (including
            args) in the verb.

        Note: Although it is possible you shouldn't issue more than one command
            at a time by adding newlines to the verb as it will most likely lead
            to undesirable results.
        """
        if self.__generating:
            raise NNTPSyncError("Command issued while a generator is active")

        cmd = verb
        if args:
            cmd += " " + args
        cmd += "\r\n"

        self.socket.sendall(cmd)

        try:
            code, message = self.status()
        except NNTPTemporaryError as e:
            if e.code() != 480:
                raise e
            code, message = self.command("AUTHINFO USER", self.username)
            if code == 381:
                code, message = self.command("AUTHINFO PASS", self.password)
            if code != 281:
                raise NNTPReplyError(code, message)
            code, message = self.command(verb, args)

        return code, message


def capabilities(self, keyword=None):
        """CAPABILITIES command.

        Determines the capabilities of the server.

        Although RFC3977 states that this is a required command for servers to
        implement not all servers do, so expect that NNTPPermanentError may be
        raised when this command is issued.

        See <http://tools.ietf.org/html/rfc3977#section-5.2>

        Args:
            keyword: Passed directly to the server, however, this is unused by
                the server according to RFC3977.

        Returns:
            A list of capabilities supported by the server. The VERSION
            capability is the first capability in the list.
        """
        args = keyword

        code, message = self.command("CAPABILITIES", args)
        if code != 101:
            raise NNTPReplyError(code, message)

        return [x.strip() for x in self.info_gen(code, message)]

def capabilities ( self , keyword = None ) : args = keyword code , message = self . command ( "CAPABILITIES" , args ) if code != 101 : raise NNTPReplyError ( code , message ) return [ x . strip ( ) for x in self . info_gen ( code , message ) ]


def mode_reader(self):
        """MODE READER command.

        Instructs a mode-switching server to switch modes.

        See <http://tools.ietf.org/html/rfc3977#section-5.3>

        Returns:
            Boolean value indicating whether posting is allowed or not.
        """
        code, message = self.command("MODE READER")
        if not code in [200, 201]:
            raise NNTPReplyError(code, message)

        return code == 200

def
mode_reader
(
self
)
:
code
,
message
=
self
.
command
(
"MODE READER"
)
if
not
code
in
[
200
,
201
]
:
raise
NNTPReplyError
(
code
,
message
)
return
code
==
200


def quit(self):
        """QUIT command.

        Tells the server to close the connection. After the server acknowledges
        the request to quit the connection is closed both at the server and
        client. Only useful for graceful shutdown. If you are in a generator
        use close() instead.

        Once this method has been called, no other methods of the NNTPClient
        object should be called.

        See <http://tools.ietf.org/html/rfc3977#section-5.4>
        """
        code, message = self.command("QUIT")
        if code != 205:
            raise NNTPReplyError(code, message)

        self.socket.close()

def quit ( self ) : code , message = self . command ( "QUIT" ) if code != 205 : raise NNTPReplyError ( code , message ) self . socket . close ( )


def date(self):
        """DATE command.

        Coordinated Universal time from the perspective of the usenet server.
        It can be used to provide information that might be useful when using
        the NEWNEWS command.

        See <http://tools.ietf.org/html/rfc3977#section-7.1>

        Returns:
            The UTC time according to the server as a datetime object.

        Raises:
            NNTPDataError: If the timestamp can't be parsed.
        """
        code, message = self.command("DATE")
        if code != 111:
            raise NNTPReplyError(code, message)

        ts = date.datetimeobj(message, fmt="%Y%m%d%H%M%S")

        return ts

def date ( self ) : code , message = self . command ( "DATE" ) if code != 111 : raise NNTPReplyError ( code , message ) ts = date . datetimeobj ( message , fmt = "%Y%m%d%H%M%S" ) return ts


def help(self):
        """HELP command.

        Provides a short summary of commands that are understood by the usenet
        server.

        See <http://tools.ietf.org/html/rfc3977#section-7.2>

        Returns:
            The help text from the server.
        """
        code, message = self.command("HELP")
        if code != 100:
            raise NNTPReplyError(code, message)

        return self.info(code, message)

def help ( self ) : code , message = self . command ( "HELP" ) if code != 100 : raise NNTPReplyError ( code , message ) return self . info ( code , message )


def newgroups_gen(self, timestamp):
        """Generator for the NEWGROUPS command.

        Generates a list of newsgroups created on the server since the specified
        timestamp.

        See <http://tools.ietf.org/html/rfc3977#section-7.3>

        Args:
            timestamp: Datetime object giving 'created since' datetime.

        Yields:
            A tuple containing the name, low water mark, high water mark,
            and status for the newsgroup.

        Note: If the datetime object supplied as the timestamp is naive (tzinfo
            is None) then it is assumed to be given as GMT.
        """
        if timestamp.tzinfo:
            ts = timestamp.asttimezone(date.TZ_GMT)
        else:
            ts = timestamp.replace(tzinfo=date.TZ_GMT)

        args = ts.strftime("%Y%m%d %H%M%S %Z")

        code, message = self.command("NEWGROUPS", args)
        if code != 231:
            raise NNTPReplyError(code, message)

        for line in self.info_gen(code, message):
            yield utils.parse_newsgroup(line)

def
newgroups_gen
(
self
,
timestamp
)
:
if
timestamp
.
tzinfo
:
ts
=
timestamp
.
asttimezone
(
date
.
TZ_GMT
)
else
:
ts
=
timestamp
.
replace
(
tzinfo
=
date
.
TZ_GMT
)
args
=
ts
.
strftime
(
"%Y%m%d %H%M%S %Z"
)
code
,
message
=
self
.
command
(
"NEWGROUPS"
,
args
)
if
code
!=
231
:
raise
NNTPReplyError
(
code
,
message
)
for
line
in
self
.
info_gen
(
code
,
message
)
:
yield
utils
.
parse_newsgroup
(
line
)


def newnews_gen(self, pattern, timestamp):
        """Generator for the NEWNEWS command.

        Generates a list of message-ids for articles created since the specified
        timestamp for newsgroups with names that match the given pattern.

        See <http://tools.ietf.org/html/rfc3977#section-7.4>

        Args:
            pattern: Glob matching newsgroups of intrest.
            timestamp: Datetime object giving 'created since' datetime.

        Yields:
            A message-id as string.

        Note: If the datetime object supplied as the timestamp is naive (tzinfo
            is None) then it is assumed to be given as GMT. If tzinfo is set
            then it will be converted to GMT by this function.
        """
        if timestamp.tzinfo:
            ts = timestamp.asttimezone(date.TZ_GMT)
        else:
            ts = timestamp.replace(tzinfo=date.TZ_GMT)

        args = pattern
        args += " " + ts.strftime("%Y%m%d %H%M%S %Z")

        code, message = self.command("NEWNEWS", args)
        if code != 230:
            raise NNTPReplyError(code, message)

        for line in self.info_gen(code, message):
            yield line.strip()

def
newnews_gen
(
self
,
pattern
,
timestamp
)
:
if
timestamp
.
tzinfo
:
ts
=
timestamp
.
asttimezone
(
date
.
TZ_GMT
)
else
:
ts
=
timestamp
.
replace
(
tzinfo
=
date
.
TZ_GMT
)
args
=
pattern
args
+=
" "
+
ts
.
strftime
(
"%Y%m%d %H%M%S %Z"
)
code
,
message
=
self
.
command
(
"NEWNEWS"
,
args
)
if
code
!=
230
:
raise
NNTPReplyError
(
code
,
message
)
for
line
in
self
.
info_gen
(
code
,
message
)
:
yield
line
.
strip
(
)


def newnews(self, pattern, timestamp):
        """NEWNEWS command.

        Retrieves a list of message-ids for articles created since the specified
        timestamp for newsgroups with names that match the given pattern. See
        newnews_gen() for more details.

        See <http://tools.ietf.org/html/rfc3977#section-7.4>

        Args:
            pattern: Glob matching newsgroups of intrest.
            timestamp: Datetime object giving 'created since' datetime.

        Returns:
            A list of message-ids as given by newnews_gen()
        """
        return [x for x in self.newnews_gen(pattern, timestamp)]

def newnews ( self , pattern , timestamp ) : return [ x for x in self . newnews_gen ( pattern , timestamp ) ]


def list_active_gen(self, pattern=None):
        """Generator for the LIST ACTIVE command.

        Generates a list of active newsgroups that match the specified pattern.
        If no pattern is specfied then all active groups are generated.

        See <http://tools.ietf.org/html/rfc3977#section-7.6.3>

        Args:
            pattern: Glob matching newsgroups of intrest.

        Yields:
            A tuple containing the name, low water mark, high water mark,
            and status for the newsgroup.
        """
        args = pattern

        if args is None:
            cmd = "LIST"
        else:
            cmd = "LIST ACTIVE"

        code, message = self.command(cmd, args)
        if code != 215:
            raise NNTPReplyError(code, message)

        for line in self.info_gen(code, message):
            yield utils.parse_newsgroup(line)

def
list_active_gen
(
self
,
pattern
=
)
:
args
=
pattern
if
args
is
:
cmd
=
"LIST"
else
:
cmd
=
"LIST ACTIVE"
code
,
message
=
self
.
command
(
cmd
,
args
)
if
code
!=
215
:
raise
NNTPReplyError
(
code
,
message
)
for
line
in
self
.
info_gen
(
code
,
message
)
:
yield
utils
.
parse_newsgroup
(
line
)


def list_active_times_gen(self):
        """Generator for the LIST ACTIVE.TIMES command.

        Generates a list of newsgroups including the creation time and who
        created them.

        See <http://tools.ietf.org/html/rfc3977#section-7.6.4>

        Yields:
            A tuple containing the name, creation date as a datetime object and
            creator as a string for the newsgroup.
        """
        code, message = self.command("LIST ACTIVE.TIMES")
        if code != 215:
            raise NNTPReplyError(code, message)

        for line in self.info_gen(code, message):
            parts = line.split()
            try:
                name = parts[0]
                timestamp = date.datetimeobj_epoch(parts[1])
                creator = parts[2]
            except (IndexError, ValueError):
                raise NNTPDataError("Invalid LIST ACTIVE.TIMES")
            yield name, timestamp, creator

def
list_active_times_gen
(
self
)
:
code
,
message
=
self
.
command
(
"LIST ACTIVE.TIMES"
)
if
code
!=
215
:
raise
NNTPReplyError
(
code
,
message
)
for
line
in
self
.
info_gen
(
code
,
message
)
:
parts
=
line
.
split
(
)
try
:
name
=
parts
[
0
]
timestamp
=
date
.
datetimeobj_epoch
(
parts
[
1
]
)
creator
=
parts
[
2
]
except
(
IndexError
,
ValueError
)
:
raise
NNTPDataError
(
"Invalid LIST ACTIVE.TIMES"
)
yield
name
,
timestamp
,
creator

Generator for the LIST ACTIVE . TIMES command .


def list_newsgroups_gen(self, pattern=None):
        """Generator for the LIST NEWSGROUPS command.

        Generates a list of newsgroups including the name and a short
        description.

        See <http://tools.ietf.org/html/rfc3977#section-7.6.6>

        Args:
            pattern: Glob matching newsgroups of intrest.

        Yields:
            A tuple containing the name, and description for the newsgroup.
        """
        args = pattern

        code, message = self.command("LIST NEWSGROUPS", args)
        if code != 215:
            raise NNTPReplyError(code, message)

        for line in self.info_gen(code, message):
            parts = line.strip().split()
            name, description = parts[0], ""
            if len(parts) > 1:
                description = parts[1]
            yield name, description

def
list_newsgroups_gen
(
self
,
pattern
=
)
:
args
=
pattern
code
,
message
=
self
.
command
(
"LIST NEWSGROUPS"
,
args
)
if
code
!=
215
:
raise
NNTPReplyError
(
code
,
message
)
for
line
in
self
.
info_gen
(
code
,
message
)
:
parts
=
line
.
strip
(
)
.
split
(
)
name
,
description
=
parts
[
0
]
,
""
if
len
(
parts
)
>
1
:
description
=
parts
[
1
]
yield
name
,
description

Generator for the LIST NEWSGROUPS command .


def list_overview_fmt_gen(self):
        """Generator for the LIST OVERVIEW.FMT

        See list_overview_fmt() for more information.

        Yields:
            An element in the list returned by list_overview_fmt().
        """
        code, message = self.command("LIST OVERVIEW.FMT")
        if code != 215:
            raise NNTPReplyError(code, message)

        for line in self.info_gen(code, message):
            try:
                name, suffix = line.rstrip().split(":")
            except ValueError:
                raise NNTPDataError("Invalid LIST OVERVIEW.FMT")
            if suffix and not name:
                name, suffix = suffix, name
            if suffix and suffix != "full":
                raise NNTPDataError("Invalid LIST OVERVIEW.FMT")
            yield (name, suffix == "full")

def
list_overview_fmt_gen
(
self
)
:
code
,
message
=
self
.
command
(
"LIST OVERVIEW.FMT"
)
if
code
!=
215
:
raise
NNTPReplyError
(
code
,
message
)
for
line
in
self
.
info_gen
(
code
,
message
)
:
try
:
name
,
suffix
=
line
.
rstrip
(
)
.
split
(
":"
)
except
ValueError
:
raise
NNTPDataError
(
"Invalid LIST OVERVIEW.FMT"
)
if
suffix
and
not
name
:
name
,
suffix
=
suffix
,
name
if
suffix
and
suffix
!=
"full"
:
raise
NNTPDataError
(
"Invalid LIST OVERVIEW.FMT"
)
yield
(
name
,
suffix
==
"full"
)