<commit_before>from django import forms
from django.db import models
from django.utils.translation import ugettext as _

from haystack.forms import SearchForm

from models import Image
from models import UserProfile
from models import Location
from models import DeepSky_Acquisition

from search_indexes import xapian_escape

import string

class ImageUploadForm(forms.Form):
    file = forms.ImageField()

class ImageEditBasicForm(forms.Form):
    title = forms.CharField(max_length=64)
    subjects = forms.CharField(required=False, help_text="*")
    locations = forms.CharField(required=False, help_text="*")
    description = forms.CharField(widget=forms.Textarea, required=False)

    def __init__(self, user=None, **kwargs):
        super(ImageEditBasicForm, self).__init__(**kwargs)
        self.fields['title'].label = _("Title")
        self.fields['subjects'].label = _("Subjects")
        self.fields['locations'].label = _("Locations")
        self.fields['description'].label = _("Description")

class ImageEditGearForm(forms.ModelForm):
    def __init__(self, user=None, **kwargs):
        super(ImageEditGearForm, self).__init__(**kwargs)
        profile = UserProfile.objects.get(user=user)
        telescopes = profile.telescopes.all()
        self.fields['imaging_telescopes'].queryset = telescopes
        self.fields['guiding_telescopes'].queryset = telescopes
        cameras = profile.cameras.all()
        self.fields['imaging_cameras'].queryset = cameras
        self.fields['guiding_cameras'].queryset = cameras
        for attr in ('mounts',
                     'focal_reducers',
                     'software',
                     'filters',
                     'accessories',
                    ):
            self.fields[attr].queryset = getattr(profile, attr).all()

        self.fields['imaging_telescopes'].label = _("Imaging telescopes")
        self.fields['guiding_telescopes'].label = _("Guiding telescopes")
        self.fields['mounts'].label = _("Mounts")
        self.fields['imaging_cameras'].label = _("Imaging cameras")
        self.fields['guiding_cameras'].label = _("Guiding cameras")
        self.fields['focal_reducers'].label = _("Focal reducers")
        self.fields['software'].label = _("Software")
        self.fields['filters'].label = _("Filters")
        self.fields['accessories'].label = _("Accessories")

    class Meta:
        model = Image
        fields = ('imaging_telescopes',
                  'guiding_telescopes',
                  'mounts',
                  'imaging_cameras',
                  'guiding_cameras',
                  'focal_reducers',
                  'software',
                  'filters',
                  'accessories',
                 )

class UserProfileEditBasicForm(forms.ModelForm):
    locations = forms.CharField(max_length=64, required=False, help_text="*")

    class Meta:
        model = UserProfile
        fields = ('website', 'job', 'hobbies')

    def __init__(self, user=None, **kwargs):
        super(UserProfileEditBasicForm, self).__init__(**kwargs)
        self.fields['locations'].label = _("Locations")

class UserProfileEditGearForm(forms.Form):
    telescopes = forms.CharField(max_length=256, help_text="*")
    mounts = forms.CharField(max_length=256, help_text="*")
    cameras = forms.CharField(max_length=256, help_text="*")
    focal_reducers = forms.CharField(max_length=256, help_text="*")
    software = forms.CharField(max_length=256, help_text="*")
    filters = forms.CharField(max_length=256, help_text="*")
    accessories = forms.CharField(max_length=256, help_text="*")

    def __init__(self, user=None, **kwargs):
        super(UserProfileEditGearForm, self).__init__(**kwargs)
        self.fields['telescopes'].label = _("Telescopes")
        self.fields['mounts'].label = _("Mounts")
        self.fields['cameras'].label = _("Cameras")
        self.fields['focal_reducers'].label = _("Focal reducers")
        self.fields['software'].label = _("Software")
        self.fields['filters'].label = _("Filters")
        self.fields['accessories'].label = _("Accessories")

class PrivateMessageForm(forms.Form):
    subject = forms.CharField(max_length=255, required=False)
    body = forms.CharField(widget=forms.Textarea, max_length=4096, required=False)

class BringToAttentionForm(forms.Form):
    user = forms.CharField(max_length=64, required=False)

class ImageRevisionUploadForm(forms.Form):
    file = forms.ImageField()

class AdvancedSearchForm(SearchForm):
    start_date = forms.DateField(
        required=False,
        widget=forms.TextInput(attrs={'class':'datepickerclass'}),
        help_text=_("Please use the following format: yyyy-mm-dd"))
    end_date = forms.DateField(
        required=False,
        widget=forms.TextInput(attrs={'class':'datepickerclass'}),
        help_text=_("Please use the following format: yyyy-mm-dd"))
    integration_min = forms.FloatField(
        required=False,
        help_text=_("Express value in hours"))
    integration_max = forms.FloatField(
        required=False,
        help_text=_("Express value in hours"))
    moon_phase_min = forms.FloatField(
        required=False,
        help_text="0-100")
    moon_phase_max = forms.FloatField(
        required=False,
        help_text="0-100")

    def __init__(self, data=None, **kwargs):
        super(AdvancedSearchForm, self).__init__(data, **kwargs)
        self.fields['q'].help_text = _("Search for astronomical objects, telescopes, cameras, filters...")

        self.fields['start_date'].label = _("Min. upload date")
        self.fields['end_date'].label = _("Max. upload date")
        self.fields['integration_min'].label = _("Min. integration")
        self.fields['integration_max'].label = _("Max. integration")
        self.fields['moon_phase_min'].label = _("Min. Moon phase %")
        self.fields['moon_phase_max'].label = _("Max. Moon phase %")

    def search(self):
        exclude = set(string.punctuation)
        self.cleaned_data['q'] = xapian_escape(self.cleaned_data['q'])
        self.cleaned_data['q'] = ''.join(ch for ch in self.cleaned_data['q'] if ch not in exclude)

        # First, store the SearchQuerySet received from other processing.
        sqs = super(AdvancedSearchForm, self).search()

        if self.is_valid():
            if self.cleaned_data['start_date']:
                sqs = sqs.filter(last_acquisition_date__gte=self.cleaned_data['start_date'])

            if self.cleaned_data['end_date']:
                sqs = sqs.filter(first_acquisition_date__lte=self.cleaned_data['end_date'])

            if self.cleaned_data['integration_min']:
                sqs = sqs.filter(integration__gte=int(self.cleaned_data['integration_min'] * 3600))

            if self.cleaned_data['integration_max']:
                sqs = sqs.filter(integration__lte=int(self.cleaned_data['integration_max'] * 3600))

            if self.cleaned_data['moon_phase_min']:
                sqs = sqs.filter(moon_phase__gte=self.cleaned_data['moon_phase_min'])

            if self.cleaned_data['moon_phase_max']:
                sqs = sqs.filter(moon_phase__lte=self.cleaned_data['moon_phase_max'])

        return sqs

class LocationEditForm(forms.ModelForm):
    latitude = forms.FloatField(
        required=False,
        help_text=_("Examples: +12.44, -51.25"))
    longitude = forms.FloatField(
        required=False,
        help_text=_("Examples: +12.44, -51.25"))

    def __init__(self, *args, **kwargs):
        super(LocationEditForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.id:
            self.fields['name'].widget.attrs['readonly'] = True

    class Meta:
        model = Location
        fields = (
            'name',
            'latitude',
            'longitude',
            'altitude',
        )

class DeepSky_AcquisitionForm(forms.ModelForm):
    date = forms.DateField(
        required=False,
        widget=forms.TextInput(attrs={'class':'datepickerclass'}),
        help_text=_("Please use the following format: yyyy-mm-dd"))

    class Meta:
        model = DeepSky_Acquisition

    def __init__(self, user=None, **kwargs):
        queryset = None
        try:
            queryset = kwargs.pop('queryset')
        except KeyError:
            pass

        super(DeepSky_AcquisitionForm, self).__init__(**kwargs)
        self.fields['date'].label = _("Date")
        if queryset:
            self.fields['filter'].queryset = queryset

<commit_msg>All gear parts are not required, so form will validate.<commit_after>from django import forms
from django.db import models
from django.utils.translation import ugettext as _

from haystack.forms import SearchForm

from models import Image
from models import UserProfile
from models import Location
from models import DeepSky_Acquisition

from search_indexes import xapian_escape

import string

class ImageUploadForm(forms.Form):
    file = forms.ImageField()

class ImageEditBasicForm(forms.Form):
    title = forms.CharField(max_length=64)
    subjects = forms.CharField(required=False, help_text="*")
    locations = forms.CharField(required=False, help_text="*")
    description = forms.CharField(widget=forms.Textarea, required=False)

    def __init__(self, user=None, **kwargs):
        super(ImageEditBasicForm, self).__init__(**kwargs)
        self.fields['title'].label = _("Title")
        self.fields['subjects'].label = _("Subjects")
        self.fields['locations'].label = _("Locations")
        self.fields['description'].label = _("Description")

class ImageEditGearForm(forms.ModelForm):
    def __init__(self, user=None, **kwargs):
        super(ImageEditGearForm, self).__init__(**kwargs)
        profile = UserProfile.objects.get(user=user)
        telescopes = profile.telescopes.all()
        self.fields['imaging_telescopes'].queryset = telescopes
        self.fields['guiding_telescopes'].queryset = telescopes
        cameras = profile.cameras.all()
        self.fields['imaging_cameras'].queryset = cameras
        self.fields['guiding_cameras'].queryset = cameras
        for attr in ('mounts',
                     'focal_reducers',
                     'software',
                     'filters',
                     'accessories',
                    ):
            self.fields[attr].queryset = getattr(profile, attr).all()

        self.fields['imaging_telescopes'].label = _("Imaging telescopes")
        self.fields['guiding_telescopes'].label = _("Guiding telescopes")
        self.fields['mounts'].label = _("Mounts")
        self.fields['imaging_cameras'].label = _("Imaging cameras")
        self.fields['guiding_cameras'].label = _("Guiding cameras")
        self.fields['focal_reducers'].label = _("Focal reducers")
        self.fields['software'].label = _("Software")
        self.fields['filters'].label = _("Filters")
        self.fields['accessories'].label = _("Accessories")

    class Meta:
        model = Image
        fields = ('imaging_telescopes',
                  'guiding_telescopes',
                  'mounts',
                  'imaging_cameras',
                  'guiding_cameras',
                  'focal_reducers',
                  'software',
                  'filters',
                  'accessories',
                 )

class UserProfileEditBasicForm(forms.ModelForm):
    locations = forms.CharField(max_length=64, required=False, help_text="*")

    class Meta:
        model = UserProfile
        fields = ('website', 'job', 'hobbies')

    def __init__(self, user=None, **kwargs):
        super(UserProfileEditBasicForm, self).__init__(**kwargs)
        self.fields['locations'].label = _("Locations")

class UserProfileEditGearForm(forms.Form):
    telescopes = forms.CharField(max_length=256, help_text="*", required=False)
    mounts = forms.CharField(max_length=256, help_text="*", required=False)
    cameras = forms.CharField(max_length=256, help_text="*", required=False)
    focal_reducers = forms.CharField(max_length=256, help_text="*", required=False)
    software = forms.CharField(max_length=256, help_text="*", required=False)
    filters = forms.CharField(max_length=256, help_text="*", required=False)
    accessories = forms.CharField(max_length=256, help_text="*", required=False)

    def __init__(self, user=None, **kwargs):
        super(UserProfileEditGearForm, self).__init__(**kwargs)
        self.fields['telescopes'].label = _("Telescopes")
        self.fields['mounts'].label = _("Mounts")
        self.fields['cameras'].label = _("Cameras")
        self.fields['focal_reducers'].label = _("Focal reducers")
        self.fields['software'].label = _("Software")
        self.fields['filters'].label = _("Filters")
        self.fields['accessories'].label = _("Accessories")

class PrivateMessageForm(forms.Form):
    subject = forms.CharField(max_length=255, required=False)
    body = forms.CharField(widget=forms.Textarea, max_length=4096, required=False)

class BringToAttentionForm(forms.Form):
    user = forms.CharField(max_length=64, required=False)

class ImageRevisionUploadForm(forms.Form):
    file = forms.ImageField()

class AdvancedSearchForm(SearchForm):
    start_date = forms.DateField(
        required=False,
        widget=forms.TextInput(attrs={'class':'datepickerclass'}),
        help_text=_("Please use the following format: yyyy-mm-dd"))
    end_date = forms.DateField(
        required=False,
        widget=forms.TextInput(attrs={'class':'datepickerclass'}),
        help_text=_("Please use the following format: yyyy-mm-dd"))
    integration_min = forms.FloatField(
        required=False,
        help_text=_("Express value in hours"))
    integration_max = forms.FloatField(
        required=False,
        help_text=_("Express value in hours"))
    moon_phase_min = forms.FloatField(
        required=False,
        help_text="0-100")
    moon_phase_max = forms.FloatField(
        required=False,
        help_text="0-100")

    def __init__(self, data=None, **kwargs):
        super(AdvancedSearchForm, self).__init__(data, **kwargs)
        self.fields['q'].help_text = _("Search for astronomical objects, telescopes, cameras, filters...")

        self.fields['start_date'].label = _("Min. upload date")
        self.fields['end_date'].label = _("Max. upload date")
        self.fields['integration_min'].label = _("Min. integration")
        self.fields['integration_max'].label = _("Max. integration")
        self.fields['moon_phase_min'].label = _("Min. Moon phase %")
        self.fields['moon_phase_max'].label = _("Max. Moon phase %")

    def search(self):
        exclude = set(string.punctuation)
        self.cleaned_data['q'] = xapian_escape(self.cleaned_data['q'])
        self.cleaned_data['q'] = ''.join(ch for ch in self.cleaned_data['q'] if ch not in exclude)

        # First, store the SearchQuerySet received from other processing.
        sqs = super(AdvancedSearchForm, self).search()

        if self.is_valid():
            if self.cleaned_data['start_date']:
                sqs = sqs.filter(last_acquisition_date__gte=self.cleaned_data['start_date'])

            if self.cleaned_data['end_date']:
                sqs = sqs.filter(first_acquisition_date__lte=self.cleaned_data['end_date'])

            if self.cleaned_data['integration_min']:
                sqs = sqs.filter(integration__gte=int(self.cleaned_data['integration_min'] * 3600))

            if self.cleaned_data['integration_max']:
                sqs = sqs.filter(integration__lte=int(self.cleaned_data['integration_max'] * 3600))

            if self.cleaned_data['moon_phase_min']:
                sqs = sqs.filter(moon_phase__gte=self.cleaned_data['moon_phase_min'])

            if self.cleaned_data['moon_phase_max']:
                sqs = sqs.filter(moon_phase__lte=self.cleaned_data['moon_phase_max'])

        return sqs

class LocationEditForm(forms.ModelForm):
    latitude = forms.FloatField(
        required=False,
        help_text=_("Examples: +12.44, -51.25"))
    longitude = forms.FloatField(
        required=False,
        help_text=_("Examples: +12.44, -51.25"))

    def __init__(self, *args, **kwargs):
        super(LocationEditForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.id:
            self.fields['name'].widget.attrs['readonly'] = True

    class Meta:
        model = Location
        fields = (
            'name',
            'latitude',
            'longitude',
            'altitude',
        )

class DeepSky_AcquisitionForm(forms.ModelForm):
    date = forms.DateField(
        required=False,
        widget=forms.TextInput(attrs={'class':'datepickerclass'}),
        help_text=_("Please use the following format: yyyy-mm-dd"))

    class Meta:
        model = DeepSky_Acquisition

    def __init__(self, user=None, **kwargs):
        queryset = None
        try:
            queryset = kwargs.pop('queryset')
        except KeyError:
            pass

        super(DeepSky_AcquisitionForm, self).__init__(**kwargs)
        self.fields['date'].label = _("Date")
        if queryset:
            self.fields['filter'].queryset = queryset

<|endoftext|>


<commit_before>"""graphing.py -- helper functions for graphing with matplotlib/pyplot

This software is licensed under the terms of the MIT License as
follows:

Copyright (c) 2013 Jessica B. Hamrick

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import os
import sys

mpl.rc('text', usetex=True)
mpl.rc('font', family='serif', size=12)

def save(path, fignum=None, close=True, width=None, height=None,
         ext=None, verbose=False):
    """Save a figure from pyplot.

    Parameters:

    path [string] : The path (and filename, without the extension) to
    save the figure to.

    fignum [integer] : The id of the figure to save. If None, saves the
    current figure.

    close [boolean] : (default=True) Whether to close the figure after
    saving.  If you want to save the figure multiple times (e.g., to
    multiple formats), you should NOT close it in between saves or you
    will have to re-plot it.

    width [number] : The width that the figure should be saved with. If
    None, the current width is used.

    height [number] : The height that the figure should be saved with. If
    None, the current height is used.

    ext [string or list of strings] : (default='png') The file
    extension. This must be supported by the active matplotlib backend
    (see matplotlib.backends module).  Most backends support 'png',
    'pdf', 'ps', 'eps', and 'svg'.

    verbose [boolean] : (default=True) Whether to print information
    about when and where the image has been saved.

    """

    # make sure we have a list of extensions
    if ext is not None and not hasattr(ext, '__iter__'):
        ext = [ext]

    # Extract the directory and filename from the given path
    directory, basename = os.path.split(path)
    if directory == '':
        directory = '.'

    # If the directory does not exist, create it
    if not os.path.exists(directory):
        os.makedirs(directory)

    # infer the extension if ext is None
    if ext is None:
        basename, ex = os.path.splitext(basename)
        ext = [ex[1:]]

    for ex in ext:
        # The final path to save to
        filename = "%s.%s" % (basename, ex)
        savepath = os.path.join(directory, filename)

        if verbose:
            sys.stdout.write("Saving figure to '%s'..." % savepath)

        # Actually save the figure
        plt.savefig(savepath)

    # Close it
    if close:
        plt.close()

    if verbose:
        sys.stdout.write("Done\n")

def plot_to_array(fig=None):
    """Convert a matplotlib figure `fig` to RGB pixels.

    Note that this DOES include things like ticks, labels, title, etc.

    Parameters
    ----------
    fig : int or matplotlib.figure.Figure (default=None)
        A matplotlib figure or figure identifier. If None, the current
        figure is used.

    Returns
    -------
    out : numpy.ndarray
        (width, height, 4) array of RGB values

    """

    # get the figure object
    if fig is None:
        fig = plt.gcf()
    try:
        fig = int(fig)
    except TypeError:
        pass
    else:
        fig = plt.figure(fig)

    # render the figure
    fig.canvas.draw()

    # convert the figure to a rgb string, and read that buffer into a
    # numpy array
    w, h = fig.canvas.get_width_height()
    buf = fig.canvas.renderer.tostring_rgb()
    arr = np.fromstring(buf, dtype=np.uint8)
    arr.resize(h, w, 3)

    # convert values from 0-255 to 0-1
    farr = arr / 255.

    return farr
<commit_msg>Actually do stuff with fignum, width, and height<commit_after>"""graphing.py -- helper functions for graphing with matplotlib/pyplot

This software is licensed under the terms of the MIT License as
follows:

Copyright (c) 2013 Jessica B. Hamrick

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import os
import sys

mpl.rc('text', usetex=True)
mpl.rc('font', family='serif', size=12)

def save(path, fignum=None, close=True, width=None, height=None,
         ext=None, verbose=False):
    """Save a figure from pyplot.

    Parameters:

    path [string] : The path (and filename, without the extension) to
    save the figure to.

    fignum [integer] : The id of the figure to save. If None, saves the
    current figure.

    close [boolean] : (default=True) Whether to close the figure after
    saving.  If you want to save the figure multiple times (e.g., to
    multiple formats), you should NOT close it in between saves or you
    will have to re-plot it.

    width [number] : The width that the figure should be saved with. If
    None, the current width is used.

    height [number] : The height that the figure should be saved with. If
    None, the current height is used.

    ext [string or list of strings] : (default='png') The file
    extension. This must be supported by the active matplotlib backend
    (see matplotlib.backends module).  Most backends support 'png',
    'pdf', 'ps', 'eps', and 'svg'.

    verbose [boolean] : (default=True) Whether to print information
    about when and where the image has been saved.

    """

    # get the figure
    if fignum is not None:
        fig = plt.figure(fignum)
    else:
        fig = plt.gcf()

    # set its dimenions
    if width:
        fig.set_figwidth(width)
    if height:
        fig.set_figheight(height)

    # make sure we have a list of extensions
    if ext is not None and not hasattr(ext, '__iter__'):
        ext = [ext]

    # Extract the directory and filename from the given path
    directory, basename = os.path.split(path)
    if directory == '':
        directory = '.'

    # If the directory does not exist, create it
    if not os.path.exists(directory):
        os.makedirs(directory)

    # infer the extension if ext is None
    if ext is None:
        basename, ex = os.path.splitext(basename)
        ext = [ex[1:]]

    for ex in ext:
        # The final path to save to
        filename = "%s.%s" % (basename, ex)
        savepath = os.path.join(directory, filename)

        if verbose:
            sys.stdout.write("Saving figure to '%s'..." % savepath)

        # Actually save the figure
        plt.savefig(savepath)

    # Close it
    if close:
        plt.close()

    if verbose:
        sys.stdout.write("Done\n")

def plot_to_array(fig=None):
    """Convert a matplotlib figure `fig` to RGB pixels.

    Note that this DOES include things like ticks, labels, title, etc.

    Parameters
    ----------
    fig : int or matplotlib.figure.Figure (default=None)
        A matplotlib figure or figure identifier. If None, the current
        figure is used.

    Returns
    -------
    out : numpy.ndarray
        (width, height, 4) array of RGB values

    """

    # get the figure object
    if fig is None:
        fig = plt.gcf()
    try:
        fig = int(fig)
    except TypeError:
        pass
    else:
        fig = plt.figure(fig)

    # render the figure
    fig.canvas.draw()

    # convert the figure to a rgb string, and read that buffer into a
    # numpy array
    w, h = fig.canvas.get_width_height()
    buf = fig.canvas.renderer.tostring_rgb()
    arr = np.fromstring(buf, dtype=np.uint8)
    arr.resize(h, w, 3)

    # convert values from 0-255 to 0-1
    farr = arr / 255.

    return farr
<|endoftext|>


<commit_before>from itertools import ifilter
from numbers import Number

def is_rangestmt(x):
    return isinstance(x, RangeStmt)

def join_p(xs, d=1):
    if not xs:
        return ''
    lines = "".join(map(str, xs)).splitlines()
    prefix = '    ' * d if isinstance(d, Number) else d
    return "".join(prefix + line + '\n' for line in lines)

class DHCPMixin(object):
    side = ''

    def __ne__(self, other):
        return not self == other

    def join_side(self, x):
        return join_p(x, self.side)

class Statement(DHCPMixin):
    def __init__(self, statement):
        self.statement = statement

    def __eq__(self, other):
        if not isinstance(other, Statement):
            return NotImplemented
        else:
            return ((self.side, self.statement) ==
                    (other.side, other.statement))

    def __hash__(self):
        return hash(self.side + self.statement)

    def __str__(self):
        return self.join_side(self.statement + ';\n')

class RangeStmt(Statement):
    def __init__(self, start, end):
        self.statement = 'range {0} {1}'.format(start, end)
        self.start = start
        self.end = end

class Pool(DHCPMixin):
    def __init__(self, contents):
        self.contents = set(contents)

        rs = next(ifilter(is_rangestmt, contents), None)
        self.start, self.end = rs.start, rs.end

    def __eq__(self, other):
        if not isinstance(other, Pool):
            return NotImplemented
        else:
            return ((self.side, self.start, self.end) ==
                    (other.side, other.start, other.end))

    def __hash__(self):
        return hash(self.side + self.start + self.end)

    def __str__(self):
        return self.join_side(
            'pool {{\n'
            '{0}'
            '}}\n'
            .format(join_p(self.contents))
        )

class Subnet(DHCPMixin):
    def __init__(self, netaddr, netmask, contents):
        self.netaddr = netaddr
        self.netmask = netmask
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Subnet):
            return NotImplemented
        else:
            return ((self.side, self.netaddr, self.netmask) ==
                    (other.side, other.netaddr, other.netmask))

    def __hash__(self):
        return hash(self.side + self.netaddr + self.netmask)

    def __str__(self):
        return self.join_side(
            'subnet {0} netmask {1} {{\n'
            '{2}'
            '}}\n'
            .format(self.netaddr, self.netmask, join_p(self.contents))
        )

class Subclass(DHCPMixin):
    def __init__(self, classname, match, contents):
        self.classname = classname
        self.match = match
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Subclass):
            return NotImplemented
        else:
            return ((self.side, self.classname, self.match) ==
                    (other.side, other.classname, other.match))

    def __hash__(self):
        return hash(self.side + self.classname + self.match)

    def __str__(self):
        if self.contents:
            end = (' {{\n'
                   '{0}'
                   '}}\n'
                   .format(join_p(self.contents)))
        else:
            end = ';\n'
        return self.join_side(
            'subclass "{0}" {1}{2}'
            .format(self.classname, self.match, end)
        )

class Class(DHCPMixin):
    def __init__(self, name, contents):
        self.name = name
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Class):
            return NotImplemented
        else:
            return ((self.side, self.name) ==
                    (other.side, other.name))

    def __hash__(self):
        return hash(self.side + self.name)

    def __str__(self):
        return self.join_side(
            'class "{0}" {{\n'
            '{1}'
            '}}\n'
            .format(self.name, join_p(self.contents))
        )

class Group(DHCPMixin):
    def __init__(self, name, contents):
        self.name = name
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Group):
            return NotImplemented
        else:
            return ((self.side, self.name) ==
                    (other.side, other.name))

    def __hash__(self):
        return hash(self.side + self.name)

    def __str__(self):
        return self.join_side(
            'group {{ # {0}\n'
            '{1}'
            '}}\n'
            .format(self.name, join_p(self.contents))
        )

class Host(DHCPMixin):
    def __init__(self, name, contents):
        self.name = name
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Host):
            return NotImplemented
        else:
            return ((self.side, self.name) ==
                    (other.side, other.name))

    def __hash__(self):
        return hash(self.side + self.name)

    def __str__(self):
        return self.join_side(
            'host {0} {{\n'
            '{1}'
            '}}\n'
            .format(self.name, join_p(self.contents))
        )

class ConfigFile(DHCPMixin):
    def __init__(self, contents=None):
        self.contents = set(contents or [])

    def __eq__(self, other):
        return NotImplemented

    def __hash__(self):
        return NotImplemented

    def __str__(self):
        return join_p(self.contents, 0)
<commit_msg>Just test for ints<commit_after>from itertools import ifilter

def is_rangestmt(x):
    return isinstance(x, RangeStmt)

def join_p(xs, d=1):
    if not xs:
        return ''
    lines = "".join(map(str, xs)).splitlines()
    prefix = '    ' * d if isinstance(d, int) else d
    return "".join(prefix + line + '\n' for line in lines)

class DHCPMixin(object):
    side = ''

    def __ne__(self, other):
        return not self == other

    def join_side(self, x):
        return join_p(x, self.side)

class Statement(DHCPMixin):
    def __init__(self, statement):
        self.statement = statement

    def __eq__(self, other):
        if not isinstance(other, Statement):
            return NotImplemented
        else:
            return ((self.side, self.statement) ==
                    (other.side, other.statement))

    def __hash__(self):
        return hash(self.side + self.statement)

    def __str__(self):
        return self.join_side(self.statement + ';\n')

class RangeStmt(Statement):
    def __init__(self, start, end):
        self.statement = 'range {0} {1}'.format(start, end)
        self.start = start
        self.end = end

class Pool(DHCPMixin):
    def __init__(self, contents):
        self.contents = set(contents)

        rs = next(ifilter(is_rangestmt, contents), None)
        self.start, self.end = rs.start, rs.end

    def __eq__(self, other):
        if not isinstance(other, Pool):
            return NotImplemented
        else:
            return ((self.side, self.start, self.end) ==
                    (other.side, other.start, other.end))

    def __hash__(self):
        return hash(self.side + self.start + self.end)

    def __str__(self):
        return self.join_side(
            'pool {{\n'
            '{0}'
            '}}\n'
            .format(join_p(self.contents))
        )

class Subnet(DHCPMixin):
    def __init__(self, netaddr, netmask, contents):
        self.netaddr = netaddr
        self.netmask = netmask
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Subnet):
            return NotImplemented
        else:
            return ((self.side, self.netaddr, self.netmask) ==
                    (other.side, other.netaddr, other.netmask))

    def __hash__(self):
        return hash(self.side + self.netaddr + self.netmask)

    def __str__(self):
        return self.join_side(
            'subnet {0} netmask {1} {{\n'
            '{2}'
            '}}\n'
            .format(self.netaddr, self.netmask, join_p(self.contents))
        )

class Subclass(DHCPMixin):
    def __init__(self, classname, match, contents):
        self.classname = classname
        self.match = match
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Subclass):
            return NotImplemented
        else:
            return ((self.side, self.classname, self.match) ==
                    (other.side, other.classname, other.match))

    def __hash__(self):
        return hash(self.side + self.classname + self.match)

    def __str__(self):
        if self.contents:
            end = (' {{\n'
                   '{0}'
                   '}}\n'
                   .format(join_p(self.contents)))
        else:
            end = ';\n'
        return self.join_side(
            'subclass "{0}" {1}{2}'
            .format(self.classname, self.match, end)
        )

class Class(DHCPMixin):
    def __init__(self, name, contents):
        self.name = name
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Class):
            return NotImplemented
        else:
            return ((self.side, self.name) ==
                    (other.side, other.name))

    def __hash__(self):
        return hash(self.side + self.name)

    def __str__(self):
        return self.join_side(
            'class "{0}" {{\n'
            '{1}'
            '}}\n'
            .format(self.name, join_p(self.contents))
        )

class Group(DHCPMixin):
    def __init__(self, name, contents):
        self.name = name
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Group):
            return NotImplemented
        else:
            return ((self.side, self.name) ==
                    (other.side, other.name))

    def __hash__(self):
        return hash(self.side + self.name)

    def __str__(self):
        return self.join_side(
            'group {{ # {0}\n'
            '{1}'
            '}}\n'
            .format(self.name, join_p(self.contents))
        )

class Host(DHCPMixin):
    def __init__(self, name, contents):
        self.name = name
        self.contents = set(contents or [])

    def __eq__(self, other):
        if not isinstance(other, Host):
            return NotImplemented
        else:
            return ((self.side, self.name) ==
                    (other.side, other.name))

    def __hash__(self):
        return hash(self.side + self.name)

    def __str__(self):
        return self.join_side(
            'host {0} {{\n'
            '{1}'
            '}}\n'
            .format(self.name, join_p(self.contents))
        )

class ConfigFile(DHCPMixin):
    def __init__(self, contents=None):
        self.contents = set(contents or [])

    def __eq__(self, other):
        return NotImplemented

    def __hash__(self):
        return NotImplemented

    def __str__(self):
        return join_p(self.contents, 0)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""UNIT TESTS FOR IMAGE

This module contains unit tests for the sf_tools.image module.

:Author: Samuel Farrens <samuel.farrens@gmail.com>

:Version: 1.0

:Date: 17/11/2017

"""

import numpy as np
from numpy.testing import *
from unittest import main, TestCase
from sf_tools.image import *

class QualityTestCase(TestCase):

    def setUp(self):

        np.random.seed(1)
        self.data1 = np.random.ranf((5, 5))
        np.random.seed(2)
        self.data2 = np.random.ranf((5, 5))

    def tearDown(self):

        self.data1 = None
        self.data2 = None

    def test_nmse(self):

        assert_almost_equal(quality.nmse(self.data1, self.data2),
                            0.57003829763446101, err_msg='Incorrect NMSE')

    def test_e_error(self):

        assert_almost_equal(quality.e_error(self.data1, self.data2),
                            0.21172107960738937, err_msg='Incorrect '
                            'ellipticity error')

class ShapeTestCase(TestCase):
    """Ellipticity Test Case

    This class defines a test suite for the ellipticity measurement methods
    in sf_tools.import.shape.

    """

    def setUp(self):

        self.data = np.arange(25).reshape((5, 5))

    def tearDown(self):

        self.data = None

    def test_ellipticity_chi(self):

        assert_almost_equal(shape.Ellipticity(self.data,
                            ellip_type='chi').e,
                            np.array([-0.20338994, -0.08474559]),
                            err_msg='Incorrect ellipticity: chi')

    def test_ellipticity_epsilon(self):

        assert_almost_equal(shape.Ellipticity(self.data,
                            ellip_type='epsilon').e,
                            np.array([-0.10296018, -0.04289996]),
                            err_msg='Incorrect ellipticity: epsilon')

    def test_ellipticity_atoms(self):

        assert_almost_equal(shape.ellipticity_atoms(self.data),
                            np.array([-0.20338983, -0.08474576]),
                            err_msg='Incorrect ellipticity: atoms')

    def test_shape_project(self):

        assert_array_equal(shape.shape_project((2, 2)),
                           (np.array([[[0.,  0.], [1.,  1.]], [[0.,  1.],
                            [0.,  1.]], [[1.,  1.], [1.,  1.]],
                            [[0.,  1.], [1.,  2.]], [[0., -1.], [1.,  0.]],
                            [[0.,  0.], [0.,  1.]]])),
                           err_msg='Incorrect shape projection')

if __name__ == '__main__':
    main(verbosity=2)
<commit_msg>added more unit tests for convolve<commit_after># -*- coding: utf-8 -*-

"""UNIT TESTS FOR IMAGE

This module contains unit tests for the sf_tools.image module.

:Author: Samuel Farrens <samuel.farrens@gmail.com>

:Version: 1.0

:Date: 17/11/2017

"""

import numpy as np
from numpy.testing import *
from unittest import main, TestCase
from sf_tools.image import *

class ConvolveTestCase(TestCase):

    def setUp(self):

        self.data1 = np.arange(18).reshape(2, 3, 3)
        self.data2 = self.data1 + 1

    def tearDown(self):

        self.data1 = None
        self.data2 = None

    def test_convolve_astropy(self):

        assert_allclose(convolve.convolve(self.data1[0], self.data2[0],
                        method='astropy'),
                        np.array([[210., 201., 210.], [129., 120., 129.],
                                 [210., 201., 210.]]),
                        err_msg='Incorrect convolution: astropy')

    def test_convolve_scipy(self):

        assert_allclose(convolve.convolve(self.data1[0], self.data2[0],
                        method='scipy'),
                        np.array([[14., 35., 38.], [57., 120., 111.],
                                 [110., 197., 158.]]),
                        err_msg='Incorrect convolution: scipy')

    def test_convolve_stack(self):

        assert_allclose(convolve.convolve_stack(self.data1, self.data2),
                        np.array([[[210., 201., 210.], [129., 120., 129.],
                                  [210., 201., 210.]],
                                 [[1668., 1659., 1668.], [1587., 1578., 1587.],
                                  [1668., 1659., 1668.]]]),
                        err_msg='Incorrect convolution: stack')

    def test_convolve_stack_rot(self):

        assert_allclose(convolve.convolve_stack(self.data1, self.data2,
                        rot_kernel=True),
                        np.array([[[150., 159., 150.], [231., 240., 231.],
                                  [150., 159., 150.]],
                                 [[1608., 1617., 1608.], [1689., 1698., 1689.],
                                  [1608., 1617., 1608.]]]),
                        err_msg='Incorrect convolution: stack rot')

class QualityTestCase(TestCase):

    def setUp(self):

        self.data1 = np.arange(25).reshape(5, 5)
        data2 = np.copy(self.data1)
        data2[2] = 0
        self.data2 = data2

    def tearDown(self):

        self.data1 = None
        self.data2 = None

    def test_nmse(self):

        assert_almost_equal(quality.nmse(self.data1, self.data2),
                            0.1489795918367347, err_msg='Incorrect NMSE')

    def test_e_error(self):

        assert_almost_equal(quality.e_error(self.data1, self.data2),
                            0.042727397878588612, err_msg='Incorrect '
                            'ellipticity error')

class ShapeTestCase(TestCase):
    """Ellipticity Test Case

    This class defines a test suite for the ellipticity measurement methods
    in sf_tools.import.shape.

    """

    def setUp(self):

        self.data = np.arange(25).reshape((5, 5))

    def tearDown(self):

        self.data = None

    def test_ellipticity_chi(self):

        assert_almost_equal(shape.Ellipticity(self.data,
                            ellip_type='chi').e,
                            np.array([-0.20338994, -0.08474559]),
                            err_msg='Incorrect ellipticity: chi')

    def test_ellipticity_epsilon(self):

        assert_almost_equal(shape.Ellipticity(self.data,
                            ellip_type='epsilon').e,
                            np.array([-0.10296018, -0.04289996]),
                            err_msg='Incorrect ellipticity: epsilon')

    def test_ellipticity_atoms(self):

        assert_almost_equal(shape.ellipticity_atoms(self.data),
                            np.array([-0.20338983, -0.08474576]),
                            err_msg='Incorrect ellipticity: atoms')

    def test_shape_project(self):

        assert_array_equal(shape.shape_project((2, 2)),
                           (np.array([[[0.,  0.], [1.,  1.]], [[0.,  1.],
                            [0.,  1.]], [[1.,  1.], [1.,  1.]],
                            [[0.,  1.], [1.,  2.]], [[0., -1.], [1.,  0.]],
                            [[0.,  0.], [0.,  1.]]])),
                           err_msg='Incorrect shape projection')

if __name__ == '__main__':
    main(verbosity=2)
<|endoftext|>


<commit_before>#!/usr/bin/python3

# We do the config stuff very first, so that we can pull debug from there
import configparser

import os

config = configparser.ConfigParser()
for inifile in [os.path.expanduser('~')+'/.feed2discord.ini','feed2discord.local.ini','feed2discord.ini']:
  if os.path.isfile(inifile):
    config.read(inifile)
    break # First config file wins

MAIN = config['MAIN']

debug = MAIN.getint('debug',0)

if debug:
    os.environ['PYTHONASYNCIODEBUG'] = '1' # needs to be set before asyncio is pulled in

import feedparser
import discord
import asyncio
import aiohttp
import sqlite3
import re
import time
import logging
import warnings

if debug >= 3:
    logging.basicConfig(level=logging.DEBUG)
elif debug >= 2:
    logging.basicConfig(level=logging.INFO)
else:
    logging.basicConfig(level=logging.WARNING)

logger = logging.getLogger(__name__)

if debug >= 1:
    logger.setLevel(logging.DEBUG)
else:
    logger.setLevel(logging.INFO)

warnings.resetwarnings()

db_path = MAIN.get('db_path','feed2discord.db')

feeds = config.sections()
feeds.remove('MAIN')
feeds.remove('CHANNELS')

# Crazy workaround for a bug with parsing that doesn't apply on all pythons:
feedparser.PREFERRED_XML_PARSERS.remove('drv_libxml2')

conn = sqlite3.connect(db_path)

conn.execute('''CREATE TABLE IF NOT EXISTS feed_items
              (id text PRIMARY KEY,published text,title text,url text,reposted text)''')

client = discord.Client()

@asyncio.coroutine
def background_check_feed(feed):
    logger.info('Starting up background_check_feed for '+feed)
    yield from client.wait_until_ready()
    # make sure debug output has this check run in the right order...
    yield from asyncio.sleep(1)

    feed_url = config[feed]['feed_url']
    item_url_base = config[feed]['item_url_base']
    rss_refresh_time = config.getint(feed,'rss_refresh_time')
    max_age = config.getint(feed,'max_age')
    channels = []
    for key in config[feed]['channels'].split(','):
        logger.debug(' adding '+key+' to '+feed)
        channels.append(discord.Object(id=config['CHANNELS'][key]))

    while not client.is_closed:
        try:
            logger.info('processing feed:'+feed)
            http_response = yield from aiohttp.request('GET', feed_url)
            http_data = yield from http_response.read()
            feed_data = feedparser.parse(http_data)
            logger.debug('done fetching')
            for item in feed_data.entries:
                id=item.id
                pubDate=item.published
                title=item.title
                original_description=item.description
                url = item_url_base + id

                cursor = conn.cursor()
                cursor.execute("SELECT published,title,url,reposted FROM feed_items WHERE id=? or url=?",[id,url])

                data=cursor.fetchone()
                if data is None:
                    logger.info('item '+id+' unseen, processing:')
                    cursor.execute("INSERT INTO feed_items (id,published,title,url) VALUES (?,?,?,?)",[id,pubDate,title,url])
                    conn.commit()
                    if time.mktime(item.published_parsed) > (time.time() - max_age):
                        logger.info(' fresh and ready for parsing')
                        description = re.sub('<br */>',"\n",original_description)
                        description = re.sub("\n+","\n",description)
                        if len(description) > 1800:
                          description = description[:1000] + "\n..."
                        logger.debug(' published: '+pubDate)
                        logger.debug(' title: '+title)
                        logger.debug(' url: '+url)
                        for channel in channels:
                            logger.debug('sending message to '+channel.name()+' on '+channel.server())
                            yield from client.send_message(channel,
                               url+"\n"+
                               "**"+title+"**\n"+
                               "*"+pubDate+"*\n"+
                               description)
                    else:
                        logger.info(' too old; skipping')
                else:
                    logger.debug('item '+id+' seen before, skipping')
        finally:
            # No matter what goes wrong, wait same time and try again
            logger.debug('sleeping '+feed+' for '+str(rss_refresh_time)+' seconds')
            yield from asyncio.sleep(rss_refresh_time)

@client.async_event
def on_ready():
    logger.info('Logged in as '+client.user.name+'('+client.user.id+')')

if __name__ == "__main__":
    loop = asyncio.get_event_loop()

    try:
        for feed in feeds:
            loop.create_task(background_check_feed(feed))
        loop.run_until_complete(client.login(MAIN.get('login_email'), MAIN.get('login_password')))
        loop.run_until_complete(client.connect())
    except Exception:
        loop.run_until_complete(client.close())
    finally:
        loop.close()
<commit_msg>Log unexpected problems as errors<commit_after>#!/usr/bin/python3

# We do the config stuff very first, so that we can pull debug from there
import configparser

import os

config = configparser.ConfigParser()
for inifile in [os.path.expanduser('~')+'/.feed2discord.ini','feed2discord.local.ini','feed2discord.ini']:
  if os.path.isfile(inifile):
    config.read(inifile)
    break # First config file wins

MAIN = config['MAIN']

debug = MAIN.getint('debug',0)

if debug:
    os.environ['PYTHONASYNCIODEBUG'] = '1' # needs to be set before asyncio is pulled in

import feedparser
import discord
import asyncio
import aiohttp
import sqlite3
import re
import time
import logging
import warnings

if debug >= 3:
    logging.basicConfig(level=logging.DEBUG)
elif debug >= 2:
    logging.basicConfig(level=logging.INFO)
else:
    logging.basicConfig(level=logging.WARNING)

logger = logging.getLogger(__name__)

if debug >= 1:
    logger.setLevel(logging.DEBUG)
else:
    logger.setLevel(logging.INFO)

warnings.resetwarnings()

db_path = MAIN.get('db_path','feed2discord.db')

feeds = config.sections()
feeds.remove('MAIN')
feeds.remove('CHANNELS')

# Crazy workaround for a bug with parsing that doesn't apply on all pythons:
feedparser.PREFERRED_XML_PARSERS.remove('drv_libxml2')

conn = sqlite3.connect(db_path)

conn.execute('''CREATE TABLE IF NOT EXISTS feed_items
              (id text PRIMARY KEY,published text,title text,url text,reposted text)''')

client = discord.Client()

@asyncio.coroutine
def background_check_feed(feed):
    logger.info('Starting up background_check_feed for '+feed)
    yield from client.wait_until_ready()
    # make sure debug output has this check run in the right order...
    yield from asyncio.sleep(1)

    feed_url = config[feed]['feed_url']
    item_url_base = config[feed]['item_url_base']
    rss_refresh_time = config.getint(feed,'rss_refresh_time')
    max_age = config.getint(feed,'max_age')
    channels = []
    for key in config[feed]['channels'].split(','):
        logger.debug(' adding '+key+' to '+feed)
        channels.append(discord.Object(id=config['CHANNELS'][key]))

    while not client.is_closed:
        try:
            logger.info('processing feed:'+feed)
            http_response = yield from aiohttp.request('GET', feed_url)
            http_data = yield from http_response.read()
            feed_data = feedparser.parse(http_data)
            logger.debug('done fetching')
            for item in feed_data.entries:
                id=item.id
                pubDate=item.published
                title=item.title
                original_description=item.description
                url = item_url_base + id

                cursor = conn.cursor()
                cursor.execute("SELECT published,title,url,reposted FROM feed_items WHERE id=? or url=?",[id,url])

                data=cursor.fetchone()
                if data is None:
                    logger.info('item '+id+' unseen, processing:')
                    cursor.execute("INSERT INTO feed_items (id,published,title,url) VALUES (?,?,?,?)",[id,pubDate,title,url])
                    conn.commit()
                    if time.mktime(item.published_parsed) > (time.time() - max_age):
                        logger.info(' fresh and ready for parsing')
                        description = re.sub('<br */>',"\n",original_description)
                        description = re.sub("\n+","\n",description)
                        if len(description) > 1800:
                          description = description[:1000] + "\n..."
                        logger.debug(' published: '+pubDate)
                        logger.debug(' title: '+title)
                        logger.debug(' url: '+url)
                        for channel in channels:
                            logger.debug('sending message to '+channel.name()+' on '+channel.server())
                            yield from client.send_message(channel,
                               url+"\n"+
                               "**"+title+"**\n"+
                               "*"+pubDate+"*\n"+
                               description)
                    else:
                        logger.info(' too old; skipping')
                else:
                    logger.debug('item '+id+' seen before, skipping')
        except Exception as exc:
            logger.error('Unexpected error: '+exc)
        finally:
            # No matter what goes wrong, wait same time and try again
            logger.debug('sleeping '+feed+' for '+str(rss_refresh_time)+' seconds')
            yield from asyncio.sleep(rss_refresh_time)

@client.async_event
def on_ready():
    logger.info('Logged in as '+client.user.name+'('+client.user.id+')')

if __name__ == "__main__":
    loop = asyncio.get_event_loop()

    try:
        for feed in feeds:
            loop.create_task(background_check_feed(feed))
        loop.run_until_complete(client.login(MAIN.get('login_email'), MAIN.get('login_password')))
        loop.run_until_complete(client.connect())
    except Exception:
        loop.run_until_complete(client.close())
    finally:
        loop.close()
<|endoftext|>


<commit_before>"""
Computational domain for isogeometric analysis.
"""
import os.path as op

import numpy as nm

from sfepy.base.base import Struct
from sfepy.discrete.common.domain import Domain
import sfepy.discrete.iga as iga
import sfepy.discrete.iga.io as io

class IGDomain(Domain):
    """
    Bezier extraction based NURBS domain for isogeometric analysis.
    """

    @staticmethod
    def from_file(filename):
        """
        filename : str
            The name of the IGA domain file.
        """
        (knots, degrees, cps, weights, cs, conn,
         bcps, bweights, bconn, regions) = io.read_iga_data(filename)

        nurbs = Struct(name='nurbs', knots=knots, degrees=degrees, cps=cps,
                       weights=weights, cs=cs, conn=conn)
        bmesh = Struct(name='bmesh', cps=bcps, weights=bweights, conn=bconn)

        name = op.splitext(filename)[0]
        domain = IGDomain(name, nurbs=nurbs, bmesh=bmesh, regions=regions)
        return domain

    def __init__(self, name, nurbs, bmesh, regions=None, **kwargs):
        """
        Create an IGA domain.

        Parameters
        ----------
        name : str
            The domain name.
        """
        Domain.__init__(self, name, nurbs=nurbs, bmesh=bmesh, regions=regions,
                        **kwargs)
        from sfepy.discrete.fem.geometry_element import create_geometry_elements
        from sfepy.discrete.fem import Mesh
        from sfepy.discrete.fem.extmods.cmesh import CMesh
        from sfepy.discrete.fem.utils import prepare_remap

        self.facets = iga.get_bezier_element_entities(nurbs.degrees)

        tconn = iga.get_bezier_topology(bmesh.conn, nurbs.degrees)
        itc = nm.unique(tconn)

        remap = prepare_remap(itc, bmesh.conn.max() + 1)

        ltcoors = bmesh.cps[itc]
        ltconn = remap[tconn]

        n_nod, dim = ltcoors.shape
        n_el = ltconn.shape[0]
        self.shape = Struct(n_nod=n_nod, dim=dim, tdim=0, n_el=n_el, n_gr=1)

        desc = '%d_%d' % (dim, 2**dim)
        mat_id = nm.zeros(ltconn.shape[0], dtype=nm.int32)
        self.mesh = Mesh.from_data(self.name + '_topo', ltcoors, None, [ltconn],
                                   [mat_id], [desc])

        self.cmesh = CMesh.from_mesh(self.mesh)
        gels = create_geometry_elements()
        self.cmesh.set_local_entities(gels)
        self.cmesh.setup_entities()

        self.shape.tdim = self.cmesh.tdim

        if regions is not None:
            self.vertex_set_bcs = {}
            for key, val in self.regions.iteritems():
                self.vertex_set_bcs[key] = remap[val]

        self.cell_offsets = {0 : 0}
<commit_msg>update IGDomain.__init__() to initialize gel attribute<commit_after>"""
Computational domain for isogeometric analysis.
"""
import os.path as op

import numpy as nm

from sfepy.base.base import Struct
from sfepy.discrete.common.domain import Domain
import sfepy.discrete.iga as iga
import sfepy.discrete.iga.io as io

class IGDomain(Domain):
    """
    Bezier extraction based NURBS domain for isogeometric analysis.
    """

    @staticmethod
    def from_file(filename):
        """
        filename : str
            The name of the IGA domain file.
        """
        (knots, degrees, cps, weights, cs, conn,
         bcps, bweights, bconn, regions) = io.read_iga_data(filename)

        nurbs = Struct(name='nurbs', knots=knots, degrees=degrees, cps=cps,
                       weights=weights, cs=cs, conn=conn)
        bmesh = Struct(name='bmesh', cps=bcps, weights=bweights, conn=bconn)

        name = op.splitext(filename)[0]
        domain = IGDomain(name, nurbs=nurbs, bmesh=bmesh, regions=regions)
        return domain

    def __init__(self, name, nurbs, bmesh, regions=None, **kwargs):
        """
        Create an IGA domain.

        Parameters
        ----------
        name : str
            The domain name.
        """
        Domain.__init__(self, name, nurbs=nurbs, bmesh=bmesh, regions=regions,
                        **kwargs)
        from sfepy.discrete.fem.geometry_element import create_geometry_elements
        from sfepy.discrete.fem import Mesh
        from sfepy.discrete.fem.extmods.cmesh import CMesh
        from sfepy.discrete.fem.utils import prepare_remap

        self.facets = iga.get_bezier_element_entities(nurbs.degrees)

        tconn = iga.get_bezier_topology(bmesh.conn, nurbs.degrees)
        itc = nm.unique(tconn)

        remap = prepare_remap(itc, bmesh.conn.max() + 1)

        ltcoors = bmesh.cps[itc]
        ltconn = remap[tconn]

        n_nod, dim = ltcoors.shape
        n_el = ltconn.shape[0]
        self.shape = Struct(n_nod=n_nod, dim=dim, tdim=0, n_el=n_el, n_gr=1)

        desc = '%d_%d' % (dim, 2**dim)
        mat_id = nm.zeros(ltconn.shape[0], dtype=nm.int32)
        self.mesh = Mesh.from_data(self.name + '_topo', ltcoors, None, [ltconn],
                                   [mat_id], [desc])

        self.cmesh = CMesh.from_mesh(self.mesh)
        gels = create_geometry_elements()
        self.cmesh.set_local_entities(gels)
        self.cmesh.setup_entities()

        self.shape.tdim = self.cmesh.tdim

        self.gel = gels[desc]

        if regions is not None:
            self.vertex_set_bcs = {}
            for key, val in self.regions.iteritems():
                self.vertex_set_bcs[key] = remap[val]

        self.cell_offsets = {0 : 0}
<|endoftext|>


<commit_before>from __future__ import print_function, unicode_literals

import base64
import json
import mimetypes
import os
import posixpath
import re
import sys
import threading
import time
from traceback import format_exc
try:
    from urlparse import urlparse
except ImportError:
    from urllib.parse import urlparse

import requests
from flask import (
    Flask, Response, abort, redirect, render_template, request,
    send_from_directory, url_for)

from . import __version__
from .assets import AssetManager, GitHubAssetManager
from .browser import start_browser_when_ready
from .constants import (
    DEFAULT_GRIPHOME, DEFAULT_GRIPURL, STYLE_ASSET_URLS_INLINE_FORMAT)
from .exceptions import AlreadyRunningError
from .readers import DirectoryReader
from .renderers import GitHubRenderer, ReadmeRenderer

class Grip(Flask):
    """
    A Flask application that can serve the specified file or directory
    containing a README.
    """
    def __init__(self, source=None, auth=None, renderer=None,
                 assets=None, render_wide=None, render_inline=None, title=None,
                 autorefresh=None, quiet=None, grip_url=None,
                 static_url_path=None, instance_path=None, **kwargs):
        # Defaults from ENV
        if instance_path is None:
            instance_path = os.environ.get('GRIPHOME')
            if instance_path is None:
                instance_path = DEFAULT_GRIPHOME
        instance_path = os.path.abspath(os.path.expanduser(instance_path))
        if grip_url is None:
            grip_url = os.environ.get('GRIPURL')
            if grip_url is None:
                grip_url = DEFAULT_GRIPURL
        grip_url = grip_url.rstrip('/')
        if static_url_path is None:
            static_url_path = posixpath.join(grip_url, 'static')

        # Flask application
        super(Grip, self).__init__(
            __name__, static_url_path=static_url_path,
            instance_path=instance_path, **kwargs)
        self.config.from_object('grip.settings')
        self.config.from_pyfile('settings_local.py', silent=True)
        self.config.from_pyfile(
            os.path.join(instance_path, 'settings.py'), silent=True)

        # Defaults from settings
        if render_inline is None:
            render_inline = False
        if autorefresh is None:
            autorefresh = self.config['AUTOREFRESH']

        # Thread-safe event to signal to the polling threads to exit
        self._run_mutex = threading.Lock()
        self._shutdown_event = None

        # Parameterized attributes
        self.auth = auth
        self.autorefresh = autorefresh
        self.reader = (DirectoryReader(source)
                       if source is None or isinstance(source, basestring)
                       else source)
        self.renderer = renderer
        self.assets = assets
        self.render_wide = render_wide
        self.render_inline = render_inline
        self.title = title
        self.quiet = self.config['QUIET']

        # Contextual attributes
        if self.renderer is None:
            self.renderer = self.default_renderer()
            if not isinstance(self.renderer, ReadmeRenderer):
                raise ValueError(
                    'Expected Grip.default_renderer to return '
                    'a ReadmeRenderer instance, got None.')
        if self.assets is None:
            assets = self.default_asset_manager()
            if not isinstance(assets, AssetManager):
                raise ValueError(
                    'Expected Grip.default_asset_manager to return '
                    'an AssetManager instance, got {}.'.format(type(assets)))
            self.assets = assets

        # Add missing content types
        self.add_content_types()

        # Construct routes
        asset_route = posixpath.join(grip_url, 'asset', '')
        asset_subpath = posixpath.join(asset_route, '<path:subpath>')
        refresh_route = posixpath.join(grip_url, 'refresh', '')
        refresh_subpath = posixpath.join(refresh_route, '<path:subpath>')
        rate_limit_route = posixpath.join(grip_url, 'rate-limit-preview')

        # Initialize views
        self.before_first_request(self.retrieve_styles)
        self.add_url_rule(asset_route, 'asset', self._render_asset)
        self.add_url_rule(asset_subpath, 'asset', self._render_asset)
        self.add_url_rule('/', 'render', self._render_page)
        self.add_url_rule('/<path:subpath>', 'render', self._render_page)
        self.add_url_rule(refresh_route, 'refresh', self._render_refresh)
        self.add_url_rule(refresh_subpath, 'refresh', self._render_refresh)
        self.add_url_rule(rate_limit_route, 'rate_limit',
                          self._render_rate_limit_page)
        self.errorhandler(403)(self._render_rate_limit_page)

    def _render_asset(self, subpath):
        """
        Renders the specified cache file.
        """
        return send_from_directory(
            self.assets.cache_path, self.assets.cache_filename(subpath))

    def _render_page(self, subpath=None):
        # Normalize the subpath
        normalized = self.reader.normalize(subpath)
        if normalized != subpath:
            return redirect(normalized)

        # Get the contextual or overridden title
        title = ('{} - Grip'.format(self.reader.filename_for(subpath))
                 if self.title is None
                 else self.title)

        # Read the Readme text or asset
        data = self.reader.read(subpath)
        if data is None:
            abort(404)

        # Return binary asset
        if self.reader.is_binary(subpath):
            mimetype = self.reader.mimetype_for(subpath)
            return Response(data, mimetype=mimetype)

        # Render the Readme content
        content = self.renderer.render(data)

        # Inline favicon asset
        favicon = None
        if self.render_inline:
            favicon_url = url_for('static', filename='favicon.ico')
            favicon = self._to_data_url(favicon_url, 'image/x-icon')

        autorefresh_url = (url_for('refresh', subpath=subpath)
                           if self.autorefresh
                           else None)

        return render_template(
            'index.html', title=title, content=content, favicon=favicon,
            user_content=self.renderer.user_content,
            wide_style=self.render_wide, style_urls=self.assets.style_urls,
            styles=self.assets.styles, autorefresh_url=autorefresh_url)

    def _render_refresh(self, subpath=None):
        if not self.autorefresh:
            abort(404)

        # Normalize the subpath
        normalized = self.reader.normalize(subpath)
        if normalized != subpath:
            return redirect(normalized)

        # Get the full filename for display
        filename = self.reader.filename_for(subpath)

        # Check whether app is running
        shutdown_event = self._shutdown_event
        if not shutdown_event or shutdown_event.is_set():
            return ''

        def gen():
            last_updated = self.reader.last_updated(subpath)
            try:
                while not shutdown_event.is_set():
                    time.sleep(0.3)

                    # Check for update
                    updated = self.reader.last_updated(subpath)
                    if updated == last_updated:
                        continue
                    last_updated = updated
                    # Notify user that a refresh is in progress
                    if not self.quiet:
                        print(' * Change detected in {}, refreshing'
                              .format(filename))
                    yield 'data: {}\r\n\r\n'.format(
                        json.dumps({'updating': True}))
                    # Binary assets not supported
                    if self.reader.is_binary(subpath):
                        return
                    # Read the Readme text
                    text = self.reader.read(subpath)
                    if text is None:
                        return
                    # Render the Readme content
                    content = self.renderer.render(text)
                    # Return the Readme content
                    yield 'data: {}\r\n\r\n'.format(
                        json.dumps({'content': content}))
            except GeneratorExit:
                pass

        return Response(gen(), mimetype='text/event-stream')

    def _render_rate_limit_page(self, exception=None):
        """
        Renders the rate limit page.
        """
        auth = request.args.get('auth')
        is_auth = auth == '1' if auth else bool(self.auth)
        return render_template('limit.html', is_authenticated=is_auth), 403

    def _download(self, url, binary=False):
        if urlparse(url).netloc:
            r = requests.get(url)
            return r.content if binary else r.text

        with self.test_client() as c:
            r = c.get(url)
            charset = r.mimetype_params.get('charset', 'utf-8')
            data = c.get(url).data
            return data if binary else data.decode(charset)

    def _to_data_url(self, url, content_type):
        asset = self._download(url, binary=True)
        asset64_bytes = base64.b64encode(asset)
        asset64_string = asset64_bytes.decode('ascii')
        return 'data:{0};base64,{1}'.format(content_type, asset64_string)

    def _match_asset(self, match):
        url = match.group(1)
        ext = os.path.splitext(url)[1][1:]
        return 'url({0})'.format(
            self._to_data_url(url, 'font/' + ext))

    def _get_styles(self, style_urls, asset_url_path):
        """
        Gets the content of the given list of style URLs and
        inlines assets.
        """
        styles = []
        for style_url in style_urls:
            urls_inline = STYLE_ASSET_URLS_INLINE_FORMAT.format(
                asset_url_path.rstrip('/'))
            asset_content = self._download(style_url)
            content = re.sub(urls_inline, self._match_asset, asset_content)
            styles.append(content)

        return styles

    def _inline_styles(self):
        """
        Downloads the assets from the style URL list, clears it, and adds
        each style with its embedded asset to the literal style list.
        """
        styles = self._get_styles(self.assets.style_urls, url_for('asset'))
        self.assets.styles.extend(styles)
        self.assets.style_urls[:] = []

    def retrieve_styles(self):
        """
        Retrieves the style URLs from the source and caches them. This
        is called before the first request is dispatched.
        """
        try:
            self.assets.retrieve_styles(url_for('asset'))
        except Exception as ex:
            if self.debug:
                print(format_exc(), file=sys.stderr)
            else:
                print(' * Error: could not retrieve styles:', ex,
                      file=sys.stderr)
        if self.render_inline:
            self._inline_styles()

    def default_renderer(self):
        """
        Returns the default renderer using the current config.

        This is only used if renderer is set to None in the constructor.
        """
        return GitHubRenderer(api_url=self.config['API_URL'])

    def default_asset_manager(self):
        """
        Returns the default asset manager using the current config.

        This is only used if asset_manager is set to None in the constructor.
        """
        cache_path = None
        cache_directory = self.config['CACHE_DIRECTORY']
        if cache_directory:
            cache_directory = cache_directory.format(version=__version__)
            cache_path = os.path.join(self.instance_path, cache_directory)
        return GitHubAssetManager(
            cache_path, self.config['STYLE_URLS'], self.config['DEBUG_GRIP'])

    def add_content_types(self):
        """
        Adds the application/x-font-woff and application/octet-stream
        content types if they are missing.

        Override to add additional content types on initialization.
        """
        mimetypes.add_type('application/x-font-woff', '.woff')
        mimetypes.add_type('application/octet-stream', '.ttf')

    def clear_cache(self):
        self.assets.clear()
        if not self.quiet:
            print('Cache cleared.')

    def render(self, route=None):
        """
        Renders the application and returns the HTML unicode that would
        normally appear when visiting in the browser.
        """
        if route is None:
            route = '/'
        with self.test_client() as c:
            response = c.get(route)
            encoding = response.charset
            return response.data.decode(encoding)

    def run(self, host=None, port=None, debug=None, use_reloader=None,
            open_browser=False):
        """
        Starts a server to render the README.
        """
        if host is None:
            host = self.config['HOST']
        if port is None:
            port = self.config['PORT']
        if debug is None:
            debug = self.debug
        if use_reloader is None:
            use_reloader = self.config['DEBUG_GRIP']

        # Verify the server is not already running and start
        with self._run_mutex:
            if self._shutdown_event:
                raise AlreadyRunningError()
            self._shutdown_event = threading.Event()

        # Authentication message
        if self.auth and not self.quiet:
            auth_method = ('credentials: {}'.format(self.renderer.username)
                           if (isinstance(self.renderer, GitHubRenderer) and
                               self.renderer.username)
                           else 'personal access token')
            print(' * Using', auth_method, file=sys.stderr)

        # Open browser
        browser_thread = (
            start_browser_when_ready(host, port, self._shutdown_event)
            if open_browser else None)

        # Run local server
        super(Grip, self).run(host, port, debug=debug,
                              use_reloader=use_reloader,
                              threaded=True)

        # Signal to the polling and browser threads that they should exit
        if not self.quiet:
            print(' * Shutting down...')
        self._shutdown_event.set()

        # Wait for browser thread to finish
        if browser_thread:
            browser_thread.join()

        # Cleanup
        self._shutdown_event = None
<commit_msg>Fix and rename overridable attributes.<commit_after>from __future__ import print_function, unicode_literals

import base64
import json
import mimetypes
import os
import posixpath
import re
import sys
import threading
import time
from traceback import format_exc
try:
    from urlparse import urlparse
except ImportError:
    from urllib.parse import urlparse

import requests
from flask import (
    Flask, Response, abort, redirect, render_template, request,
    send_from_directory, url_for)

from . import __version__
from .assets import AssetManager, GitHubAssetManager
from .browser import start_browser_when_ready
from .constants import (
    DEFAULT_GRIPHOME, DEFAULT_GRIPURL, STYLE_ASSET_URLS_INLINE_FORMAT)
from .exceptions import AlreadyRunningError
from .readers import DirectoryReader
from .renderers import GitHubRenderer, ReadmeRenderer

class Grip(Flask):
    """
    A Flask application that can serve the specified file or directory
    containing a README.
    """
    def __init__(self, source=None, auth=None, renderer=None,
                 assets=None, render_wide=None, render_inline=None, title=None,
                 autorefresh=None, quiet=None, grip_url=None,
                 static_url_path=None, instance_path=None, **kwargs):
        # Defaults from ENV
        if instance_path is None:
            instance_path = os.environ.get('GRIPHOME')
            if instance_path is None:
                instance_path = DEFAULT_GRIPHOME
        instance_path = os.path.abspath(os.path.expanduser(instance_path))
        if grip_url is None:
            grip_url = os.environ.get('GRIPURL')
            if grip_url is None:
                grip_url = DEFAULT_GRIPURL
        grip_url = grip_url.rstrip('/')
        if static_url_path is None:
            static_url_path = posixpath.join(grip_url, 'static')

        # Flask application
        super(Grip, self).__init__(
            __name__, static_url_path=static_url_path,
            instance_path=instance_path, **kwargs)
        self.config.from_object('grip.settings')
        self.config.from_pyfile('settings_local.py', silent=True)
        self.config.from_pyfile(
            os.path.join(instance_path, 'settings.py'), silent=True)

        # Defaults from settings
        if render_inline is None:
            render_inline = False
        if autorefresh is None:
            autorefresh = self.config['AUTOREFRESH']

        # Thread-safe event to signal to the polling threads to exit
        self._run_mutex = threading.Lock()
        self._shutdown_event = None

        # Parameterized attributes
        self.auth = auth
        self.autorefresh = autorefresh
        self.reader = (DirectoryReader(source)
                       if source is None or isinstance(source, basestring)
                       else source)
        self.renderer = renderer
        self.assets = assets
        self.render_wide = render_wide
        self.render_inline = render_inline
        self.title = title
        self.quiet = self.config['QUIET']

        # Overridable attributes
        if self.renderer is None:
            renderer = self.default_renderer()
            if not isinstance(renderer, ReadmeRenderer):
                raise ValueError(
                    'Expected Grip.default_renderer to return a '
                    'ReadmeRenderer instance, got {}.'.format(type(renderer)))
            self.renderer = renderer
        if self.assets is None:
            assets = self.default_asset_manager()
            if not isinstance(assets, AssetManager):
                raise ValueError(
                    'Expected Grip.default_asset_manager to return an '
                    'AssetManager instance, got {}.'.format(type(assets)))
            self.assets = assets

        # Add missing content types
        self.add_content_types()

        # Construct routes
        asset_route = posixpath.join(grip_url, 'asset', '')
        asset_subpath = posixpath.join(asset_route, '<path:subpath>')
        refresh_route = posixpath.join(grip_url, 'refresh', '')
        refresh_subpath = posixpath.join(refresh_route, '<path:subpath>')
        rate_limit_route = posixpath.join(grip_url, 'rate-limit-preview')

        # Initialize views
        self.before_first_request(self.retrieve_styles)
        self.add_url_rule(asset_route, 'asset', self._render_asset)
        self.add_url_rule(asset_subpath, 'asset', self._render_asset)
        self.add_url_rule('/', 'render', self._render_page)
        self.add_url_rule('/<path:subpath>', 'render', self._render_page)
        self.add_url_rule(refresh_route, 'refresh', self._render_refresh)
        self.add_url_rule(refresh_subpath, 'refresh', self._render_refresh)
        self.add_url_rule(rate_limit_route, 'rate_limit',
                          self._render_rate_limit_page)
        self.errorhandler(403)(self._render_rate_limit_page)

    def _render_asset(self, subpath):
        """
        Renders the specified cache file.
        """
        return send_from_directory(
            self.assets.cache_path, self.assets.cache_filename(subpath))

    def _render_page(self, subpath=None):
        # Normalize the subpath
        normalized = self.reader.normalize(subpath)
        if normalized != subpath:
            return redirect(normalized)

        # Get the contextual or overridden title
        title = ('{} - Grip'.format(self.reader.filename_for(subpath))
                 if self.title is None
                 else self.title)

        # Read the Readme text or asset
        data = self.reader.read(subpath)
        if data is None:
            abort(404)

        # Return binary asset
        if self.reader.is_binary(subpath):
            mimetype = self.reader.mimetype_for(subpath)
            return Response(data, mimetype=mimetype)

        # Render the Readme content
        content = self.renderer.render(data)

        # Inline favicon asset
        favicon = None
        if self.render_inline:
            favicon_url = url_for('static', filename='favicon.ico')
            favicon = self._to_data_url(favicon_url, 'image/x-icon')

        autorefresh_url = (url_for('refresh', subpath=subpath)
                           if self.autorefresh
                           else None)

        return render_template(
            'index.html', title=title, content=content, favicon=favicon,
            user_content=self.renderer.user_content,
            wide_style=self.render_wide, style_urls=self.assets.style_urls,
            styles=self.assets.styles, autorefresh_url=autorefresh_url)

    def _render_refresh(self, subpath=None):
        if not self.autorefresh:
            abort(404)

        # Normalize the subpath
        normalized = self.reader.normalize(subpath)
        if normalized != subpath:
            return redirect(normalized)

        # Get the full filename for display
        filename = self.reader.filename_for(subpath)

        # Check whether app is running
        shutdown_event = self._shutdown_event
        if not shutdown_event or shutdown_event.is_set():
            return ''

        def gen():
            last_updated = self.reader.last_updated(subpath)
            try:
                while not shutdown_event.is_set():
                    time.sleep(0.3)

                    # Check for update
                    updated = self.reader.last_updated(subpath)
                    if updated == last_updated:
                        continue
                    last_updated = updated
                    # Notify user that a refresh is in progress
                    if not self.quiet:
                        print(' * Change detected in {}, refreshing'
                              .format(filename))
                    yield 'data: {}\r\n\r\n'.format(
                        json.dumps({'updating': True}))
                    # Binary assets not supported
                    if self.reader.is_binary(subpath):
                        return
                    # Read the Readme text
                    text = self.reader.read(subpath)
                    if text is None:
                        return
                    # Render the Readme content
                    content = self.renderer.render(text)
                    # Return the Readme content
                    yield 'data: {}\r\n\r\n'.format(
                        json.dumps({'content': content}))
            except GeneratorExit:
                pass

        return Response(gen(), mimetype='text/event-stream')

    def _render_rate_limit_page(self, exception=None):
        """
        Renders the rate limit page.
        """
        auth = request.args.get('auth')
        is_auth = auth == '1' if auth else bool(self.auth)
        return render_template('limit.html', is_authenticated=is_auth), 403

    def _download(self, url, binary=False):
        if urlparse(url).netloc:
            r = requests.get(url)
            return r.content if binary else r.text

        with self.test_client() as c:
            r = c.get(url)
            charset = r.mimetype_params.get('charset', 'utf-8')
            data = c.get(url).data
            return data if binary else data.decode(charset)

    def _to_data_url(self, url, content_type):
        asset = self._download(url, binary=True)
        asset64_bytes = base64.b64encode(asset)
        asset64_string = asset64_bytes.decode('ascii')
        return 'data:{0};base64,{1}'.format(content_type, asset64_string)

    def _match_asset(self, match):
        url = match.group(1)
        ext = os.path.splitext(url)[1][1:]
        return 'url({0})'.format(
            self._to_data_url(url, 'font/' + ext))

    def _get_styles(self, style_urls, asset_url_path):
        """
        Gets the content of the given list of style URLs and
        inlines assets.
        """
        styles = []
        for style_url in style_urls:
            urls_inline = STYLE_ASSET_URLS_INLINE_FORMAT.format(
                asset_url_path.rstrip('/'))
            asset_content = self._download(style_url)
            content = re.sub(urls_inline, self._match_asset, asset_content)
            styles.append(content)

        return styles

    def _inline_styles(self):
        """
        Downloads the assets from the style URL list, clears it, and adds
        each style with its embedded asset to the literal style list.
        """
        styles = self._get_styles(self.assets.style_urls, url_for('asset'))
        self.assets.styles.extend(styles)
        self.assets.style_urls[:] = []

    def retrieve_styles(self):
        """
        Retrieves the style URLs from the source and caches them. This
        is called before the first request is dispatched.
        """
        try:
            self.assets.retrieve_styles(url_for('asset'))
        except Exception as ex:
            if self.debug:
                print(format_exc(), file=sys.stderr)
            else:
                print(' * Error: could not retrieve styles:', ex,
                      file=sys.stderr)
        if self.render_inline:
            self._inline_styles()

    def default_renderer(self):
        """
        Returns the default renderer using the current config.

        This is only used if renderer is set to None in the constructor.
        """
        return GitHubRenderer(api_url=self.config['API_URL'])

    def default_asset_manager(self):
        """
        Returns the default asset manager using the current config.

        This is only used if asset_manager is set to None in the constructor.
        """
        cache_path = None
        cache_directory = self.config['CACHE_DIRECTORY']
        if cache_directory:
            cache_directory = cache_directory.format(version=__version__)
            cache_path = os.path.join(self.instance_path, cache_directory)
        return GitHubAssetManager(
            cache_path, self.config['STYLE_URLS'], self.config['DEBUG_GRIP'])

    def add_content_types(self):
        """
        Adds the application/x-font-woff and application/octet-stream
        content types if they are missing.

        Override to add additional content types on initialization.
        """
        mimetypes.add_type('application/x-font-woff', '.woff')
        mimetypes.add_type('application/octet-stream', '.ttf')

    def clear_cache(self):
        self.assets.clear()
        if not self.quiet:
            print('Cache cleared.')

    def render(self, route=None):
        """
        Renders the application and returns the HTML unicode that would
        normally appear when visiting in the browser.
        """
        if route is None:
            route = '/'
        with self.test_client() as c:
            response = c.get(route)
            encoding = response.charset
            return response.data.decode(encoding)

    def run(self, host=None, port=None, debug=None, use_reloader=None,
            open_browser=False):
        """
        Starts a server to render the README.
        """
        if host is None:
            host = self.config['HOST']
        if port is None:
            port = self.config['PORT']
        if debug is None:
            debug = self.debug
        if use_reloader is None:
            use_reloader = self.config['DEBUG_GRIP']

        # Verify the server is not already running and start
        with self._run_mutex:
            if self._shutdown_event:
                raise AlreadyRunningError()
            self._shutdown_event = threading.Event()

        # Authentication message
        if self.auth and not self.quiet:
            auth_method = ('credentials: {}'.format(self.renderer.username)
                           if (isinstance(self.renderer, GitHubRenderer) and
                               self.renderer.username)
                           else 'personal access token')
            print(' * Using', auth_method, file=sys.stderr)

        # Open browser
        browser_thread = (
            start_browser_when_ready(host, port, self._shutdown_event)
            if open_browser else None)

        # Run local server
        super(Grip, self).run(host, port, debug=debug,
                              use_reloader=use_reloader,
                              threaded=True)

        # Signal to the polling and browser threads that they should exit
        if not self.quiet:
            print(' * Shutting down...')
        self._shutdown_event.set()

        # Wait for browser thread to finish
        if browser_thread:
            browser_thread.join()

        # Cleanup
        self._shutdown_event = None
<|endoftext|>