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

"""

  Copyright (c) 2012, Davyd McColl; 2013, 2014 Jaime Soffer

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

   Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

   Neither the name of the involved organizations nor the names of its
   contributors may be used to endorse or promote products derived from this
   software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   THE POSSIBILITY OF SUCH DAMAGE.

"""

from PyQt4.QtGui import (QWidget, QProgressBar, QStatusBar, QGridLayout,
                         QFrame, QLabel, QLineEdit, QCompleter, QKeyEvent)
from PyQt4.QtWebKit import QWebPage, QWebSettings
from PyQt4.QtCore import Qt, QEvent

from functools import partial

# local
from WebView import WebView
from DatabaseLog import DatabaseLogLite
from libeilat import set_shortcuts, osd
from global_store import mainwin, clipboard

class WebTab(QWidget):
    """ Cada tab contiene una página web """
    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)

        self.current_title = "[EMPTY]"

        # address bar
        self.address_bar = AddressBar(parent=self)

        # notifier

        self.notifier = QLabel("")

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        self.webkit.prefix_set.connect(partial(setattr, self, 'prefix'))
        self.webkit.prefix_set.connect(self.address_bar.set_model)

        def update_address(qurl):
            """ Just because the 'connect' gives a QUrl and setText receives
            a string

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            """
            self.address_bar.setText(qurl.toString())

        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.show_progress_bar)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)

        # status bar
        self.statusbar = QStatusBar(self)

        self.statusbar.setVisible(False)
        self.statusbar.setMaximumHeight(25)

        self.webkit.page().linkHovered.connect(self.on_link_hovered)

        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)

        grid.addWidget(self.webkit, 1, 0, 1, 2)
        grid.setRowStretch(1, 1)
        grid.addWidget(self.search_frame, 2, 0)
        grid.addWidget(self.address_bar, 0, 0)
        grid.addWidget(self.notifier, 0, 1, 1, 1)
        grid.addWidget(self.pbar, 3, 0)
        grid.addWidget(self.statusbar, 4, 0)

        def toggle_status():
            """ One-time callback for QShortcut """
            self.statusbar.setVisible(not self.statusbar.isVisible())

        def show_search():
            """ One-time callback for QShortcut """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        set_shortcuts([
            # search
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page
            ("Ctrl+J", self.address_bar, partial(
                self.webkit.navigate, self.address_bar.text)),
            ("Return", self.address_bar, partial(
                self.webkit.navigate, self.address_bar.text)),
            # address bar interaction
            ("Ctrl+L", self.webkit, self.address_bar.setFocus),
            ("Escape", self.address_bar, self.webkit.setFocus),
            ("Ctrl+I", self.address_bar, navigate_completion),
            ("Ctrl+O", self.address_bar, partial(
                navigate_completion, Qt.Key_Up)),
            # toggle
            ("Ctrl+Space", self.webkit, toggle_status),
            ("Q", self.webkit, self.toggle_script),
            # clipboard
            ("E", self, partial(clipboard, self.address_bar.text))
            ])

    def toggle_script(self):
        """ Activa o desactiva javascript, y notifica cambiando el color
        del address bar

        Callback for shortcut action
        """

        javascript_on = self.webkit.settings().testAttribute(
            QWebSettings.JavascriptEnabled)

        if javascript_on:
            self.webkit.settings().setAttribute(
                QWebSettings.JavascriptEnabled, False)
            self.address_bar.set_color()
        else:
            self.webkit.settings().setAttribute(
                QWebSettings.JavascriptEnabled, True)
            self.address_bar.set_color((230, 230, 255))

    def load_progress(self, val):
        """ Callback for connection """
        if self.pbar.isVisible():
            self.pbar.setValue(val)
            self.set_title(str(val) + "% " + self.current_title)

    # connect (en constructor)
    def show_progress_bar(self):
        """ Callback for connection """

        self.address_bar.completer().popup().close()
        self.search_frame.setVisible(False)

        self.pbar.setValue(0)
        self.pbar.setVisible(True)

    # connect (en constructor)
    def load_finished(self, success):
        """ Callback for connection """

        self.webkit.navlist = []

        self.pbar.setVisible(False)
        self.set_title(self.current_title)

        if self.address_bar.hasFocus():
            self.webkit.setFocus()

        if not success:
            osd("loadFinished: failed", corner=True)
            print("loadFinished: failed")

    # connect (en constructor)
    def on_link_hovered(self, link, unused_title, unused_content):
        """ The mouse is over an image or link.
        Display the href (if there's no href, it's '') on the status bar.

        """
        self.statusbar.showMessage(link)

    # connect (en constructor)

    def save_title(self, title):
        """ Store a recently changed title, and display it """
        self.current_title = title
        self.set_title(title)

    def set_title(self, title):
        """ Go upwards to the main window's tab widget and set this
        tab's title
        """

        if title is None:
            title = "[NO TITLE]"

        mainwin().tab_widget.setTabText(
            mainwin().tab_widget.indexOf(self),
            title[:40])

    # connection in constructor and action
    def do_search(self, search=None):
        """ Find text on the currently loaded web page. If no text
        is provided, it's extracted from the search widget.

        """
        if search is None:
            search = self.search_frame.search_line.text()
        self.webkit.findText(search, QWebPage.FindWrapsAroundDocument)

class SearchFrame(QFrame):
    """ A frame with a label and a text entry. The text is provided to
    the application upwards to perform in-page search.

    """

    def __init__(self, parent=None):
        super(SearchFrame, self).__init__(parent)

        self.search_grid = QGridLayout(self)
        self.search_grid.setSpacing(0)
        self.search_grid.setContentsMargins(0, 0, 0, 0)
        self.label = QLabel("Find in page:")
        self.search_line = QLineEdit()
        self.search_grid.addWidget(self.label, 0, 0)
        self.search_grid.addWidget(self.search_line, 0, 1)
        self.setVisible(False)

        set_shortcuts([
            ("Ctrl+H", self, self.search_line.backspace),
            ])

class AddressBar(QLineEdit):
    """ A command line of sorts; receives addresses, search terms or
    app-defined commands

    """

    def __init__(self, parent=None):
        super(AddressBar, self).__init__(parent)

        self.database = DatabaseLogLite()
        self.__completer = None
        self.set_model(None)

        self.set_color()

        set_shortcuts([
            ("Ctrl+H", self, self.backspace),
            # do not create a new tab when on the address bar;
            # popup related trouble
            ("Ctrl+T", self, lambda: None)
        ])

    def set_model(self, prefix):
        """ Update the completion model when the prefix is known. Has to
        be done through an instance variable because of a bug (will not
        complete the line edit otherwise)

        """
        self.__completer = QCompleter(self.database.model(prefix), self)
        self.setCompleter(self.__completer)

    def set_color(self, rgb=(255, 255, 255)):
        """ Sets the background color of the address bar """
        self.setStyleSheet(
            "QLineEdit { background-color: rgb(%s, %s, %s)}" % rgb)
<commit_msg>successfully hidden notify after a timer<commit_after># -*- coding: utf-8 -*-

"""

  Copyright (c) 2012, Davyd McColl; 2013, 2014 Jaime Soffer

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

   Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

   Neither the name of the involved organizations nor the names of its
   contributors may be used to endorse or promote products derived from this
   software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   THE POSSIBILITY OF SUCH DAMAGE.

"""

from PyQt4.QtGui import (QWidget, QProgressBar, QStatusBar, QGridLayout,
                         QFrame, QLabel, QLineEdit, QCompleter, QKeyEvent)
from PyQt4.QtWebKit import QWebPage, QWebSettings
from PyQt4.QtCore import Qt, QEvent, QTimer

from functools import partial

# local
from WebView import WebView
from DatabaseLog import DatabaseLogLite
from libeilat import set_shortcuts
from global_store import mainwin, clipboard

class WebTab(QWidget):
    """ Cada tab contiene una página web """
    def __init__(self, parent=None):
        super(WebTab, self).__init__(parent)

        self.current_title = "[EMPTY]"

        # address bar
        self.address_bar = AddressBar(parent=self)

        # notifier

        self.notifier = QLabel("")
        self.notifier.hide()

        # webkit (the actual "web engine")
        self.webkit = WebView(parent=self)

        self.webkit.prefix_set.connect(partial(setattr, self, 'prefix'))
        self.webkit.prefix_set.connect(self.address_bar.set_model)

        def update_address(qurl):
            """ Just because the 'connect' gives a QUrl and setText receives
            a string

            Required because a 3XX HTTP redirection will change the address,
            and without updating, the address bar will be left stale

            """
            self.address_bar.setText(qurl.toString())

        self.webkit.urlChanged.connect(update_address)
        self.webkit.loadStarted.connect(self.show_progress_bar)
        self.webkit.loadFinished.connect(self.load_finished)
        self.webkit.titleChanged.connect(self.save_title)
        self.webkit.loadProgress.connect(self.load_progress)

        # progress bar
        self.pbar = QProgressBar(self)

        self.pbar.setRange(0, 100)
        self.pbar.setTextVisible(False)
        self.pbar.setVisible(False)
        self.pbar.setMaximumHeight(7)

        # search in page
        self.search_frame = SearchFrame(parent=self)

        # status bar
        self.statusbar = QStatusBar(self)

        self.statusbar.setVisible(False)
        self.statusbar.setMaximumHeight(25)

        self.webkit.page().linkHovered.connect(self.on_link_hovered)

        self.search_frame.search_line.textChanged.connect(self.do_search)

        # layout
        grid = QGridLayout(self)
        grid.setSpacing(0)
        grid.setVerticalSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)

        grid.addWidget(self.webkit, 1, 0, 1, 2)
        grid.setRowStretch(1, 1)
        grid.addWidget(self.search_frame, 2, 0)
        grid.addWidget(self.address_bar, 0, 0)
        grid.addWidget(self.notifier, 0, 1, 1, 1)
        grid.addWidget(self.pbar, 3, 0)
        grid.addWidget(self.statusbar, 4, 0)

        def toggle_status():
            """ One-time callback for QShortcut """
            self.statusbar.setVisible(not self.statusbar.isVisible())

        def show_search():
            """ One-time callback for QShortcut """
            self.search_frame.setVisible(True)
            self.search_frame.search_line.setFocus()

        def hide_search():
            """ One-time callback for QShortcut """
            self.search_frame.setVisible(False)
            self.webkit.findText("")
            self.webkit.setFocus()

        def navigate_completion(key=Qt.Key_Down):
            """ Sends an "arrow press" to the completion popup to navigate
            results.

            Not the best way to do this. It would be better to find out what
            function is being called by that arrow press.

            """
            event = QKeyEvent(QEvent.KeyPress, key, Qt.NoModifier)

            self.address_bar.completer().popup().keyPressEvent(event)

        set_shortcuts([
            # search
            ("G", self.webkit, show_search),
            ("Escape", self.search_frame, hide_search),
            ("Return", self.search_frame, self.do_search),
            ("Ctrl+J", self.search_frame, self.do_search),
            # go to page
            ("Ctrl+J", self.address_bar, partial(
                self.webkit.navigate, self.address_bar.text)),
            ("Return", self.address_bar, partial(
                self.webkit.navigate, self.address_bar.text)),
            # address bar interaction
            ("Ctrl+L", self.webkit, self.address_bar.setFocus),
            ("Escape", self.address_bar, self.webkit.setFocus),
            ("Ctrl+I", self.address_bar, navigate_completion),
            ("Ctrl+O", self.address_bar, partial(
                navigate_completion, Qt.Key_Up)),
            # toggle
            ("Ctrl+Space", self.webkit, toggle_status),
            ("Q", self.webkit, self.toggle_script),
            # clipboard
            ("E", self, partial(clipboard, self.address_bar.text))
            ])

    def toggle_script(self):
        """ Activa o desactiva javascript, y notifica cambiando el color
        del address bar

        Callback for shortcut action
        """

        javascript_on = self.webkit.settings().testAttribute(
            QWebSettings.JavascriptEnabled)

        if javascript_on:
            self.webkit.settings().setAttribute(
                QWebSettings.JavascriptEnabled, False)
            self.address_bar.set_color()
        else:
            self.webkit.settings().setAttribute(
                QWebSettings.JavascriptEnabled, True)
            self.address_bar.set_color((230, 230, 255))

    def load_progress(self, val):
        """ Callback for connection """
        if self.pbar.isVisible():
            self.pbar.setValue(val)
            self.set_title(str(val) + "% " + self.current_title)

    # connect (en constructor)
    def show_progress_bar(self):
        """ Callback for connection """

        self.address_bar.completer().popup().close()
        self.search_frame.setVisible(False)

        self.pbar.setValue(0)
        self.pbar.setVisible(True)

    # connect (en constructor)
    def load_finished(self, success):
        """ Callback for connection """

        self.webkit.navlist = []

        self.pbar.setVisible(False)
        self.set_title(self.current_title)

        if self.address_bar.hasFocus():
            self.webkit.setFocus()

        if not success:
            self.notifier.setText("loadFinished: failed")
            self.notifier.show()
            QTimer.singleShot(8000, self.notifier.hide)
            print("loadFinished: failed")

    # connect (en constructor)
    def on_link_hovered(self, link, unused_title, unused_content):
        """ The mouse is over an image or link.
        Display the href (if there's no href, it's '') on the status bar.

        """
        self.statusbar.showMessage(link)

    # connect (en constructor)

    def save_title(self, title):
        """ Store a recently changed title, and display it """
        self.current_title = title
        self.set_title(title)

    def set_title(self, title):
        """ Go upwards to the main window's tab widget and set this
        tab's title
        """

        if title is None:
            title = "[NO TITLE]"

        mainwin().tab_widget.setTabText(
            mainwin().tab_widget.indexOf(self),
            title[:40])

    # connection in constructor and action
    def do_search(self, search=None):
        """ Find text on the currently loaded web page. If no text
        is provided, it's extracted from the search widget.

        """
        if search is None:
            search = self.search_frame.search_line.text()
        self.webkit.findText(search, QWebPage.FindWrapsAroundDocument)

class SearchFrame(QFrame):
    """ A frame with a label and a text entry. The text is provided to
    the application upwards to perform in-page search.

    """

    def __init__(self, parent=None):
        super(SearchFrame, self).__init__(parent)

        self.search_grid = QGridLayout(self)
        self.search_grid.setSpacing(0)
        self.search_grid.setContentsMargins(0, 0, 0, 0)
        self.label = QLabel("Find in page:")
        self.search_line = QLineEdit()
        self.search_grid.addWidget(self.label, 0, 0)
        self.search_grid.addWidget(self.search_line, 0, 1)
        self.setVisible(False)

        set_shortcuts([
            ("Ctrl+H", self, self.search_line.backspace),
            ])

class AddressBar(QLineEdit):
    """ A command line of sorts; receives addresses, search terms or
    app-defined commands

    """

    def __init__(self, parent=None):
        super(AddressBar, self).__init__(parent)

        self.database = DatabaseLogLite()
        self.__completer = None
        self.set_model(None)

        self.set_color()

        set_shortcuts([
            ("Ctrl+H", self, self.backspace),
            # do not create a new tab when on the address bar;
            # popup related trouble
            ("Ctrl+T", self, lambda: None)
        ])

    def set_model(self, prefix):
        """ Update the completion model when the prefix is known. Has to
        be done through an instance variable because of a bug (will not
        complete the line edit otherwise)

        """
        self.__completer = QCompleter(self.database.model(prefix), self)
        self.setCompleter(self.__completer)

    def set_color(self, rgb=(255, 255, 255)):
        """ Sets the background color of the address bar """
        self.setStyleSheet(
            "QLineEdit { background-color: rgb(%s, %s, %s)}" % rgb)
<|endoftext|>


<commit_before>"""
This is a setup.py script generated by py2applet

Usage:
    python setup.py py2app
"""

from setuptools import setup
from glob import glob
import syncplay

APP = ['syncplayClient.py']
DATA_FILES = [
    ('resources', glob('resources/*.png') + glob('resources/*.rtf') + glob('resources/*.lua')),
]
OPTIONS = {
	'iconfile':'resources/icon.icns',
	'includes': {'PySide2.QtCore', 'PySide2.QtUiTools', 'PySide2.QtGui','PySide2.QtWidgets', 'certifi'},
    'excludes': {'PySide', 'PySide.QtCore', 'PySide.QtUiTools', 'PySide.QtGui'},
    'qt_plugins': ['platforms/libqcocoa.dylib', 'platforms/libqminimal.dylib','platforms/libqoffscreen.dylib', 'styles/libqmacstyle.dylib'],
	'plist': {
		'CFBundleName':'Syncplay',
		'CFBundleShortVersionString':syncplay.version,
		'CFBundleIdentifier':'pl.syncplay.Syncplay',
		'LSMinimumSystemVersion':'10.11.0',
		'NSHumanReadableCopyright': '@ 2018 Syncplay All Rights Reserved'
	}
}

setup(
    app=APP,
    name='Syncplay',
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
<commit_msg>Bundle syncplayServer in py2app<commit_after>"""
This is a setup.py script generated by py2applet

Usage:
    python setup.py py2app
"""

from setuptools import setup
from glob import glob
import syncplay

APP = ['syncplayClient.py']
DATA_FILES = [
    ('resources', glob('resources/*.png') + glob('resources/*.rtf') + glob('resources/*.lua')),
]
OPTIONS = {
    'iconfile':'resources/icon.icns',
    'extra_scripts': 'syncplayServer.py',
    'includes': {'PySide2.QtCore', 'PySide2.QtUiTools', 'PySide2.QtGui','PySide2.QtWidgets', 'certifi'},
    'excludes': {'PySide', 'PySide.QtCore', 'PySide.QtUiTools', 'PySide.QtGui'},
    'qt_plugins': ['platforms/libqcocoa.dylib', 'platforms/libqminimal.dylib','platforms/libqoffscreen.dylib', 'styles/libqmacstyle.dylib'],
    'plist': {
        'CFBundleName':'Syncplay',
        'CFBundleShortVersionString':syncplay.version,
        'CFBundleIdentifier':'pl.syncplay.Syncplay',
        'LSMinimumSystemVersion':'10.11.0',
        'NSHumanReadableCopyright': '@ 2018 Syncplay All Rights Reserved'
        }
}

setup(
    app=APP,
    name='Syncplay',
    data_files=DATA_FILES,
    options={'py2app': OPTIONS},
    setup_requires=['py2app'],
)
<|endoftext|>


<commit_before>import django.contrib.auth.forms
from django.contrib.auth.models import User
import django.forms
from mysite.profile.models import Person
import StringIO
from django.core.files.images import get_image_dimensions
from django.core.files.uploadedfile import InMemoryUploadedFile
import PIL.Image
from django.conf import settings
from invitation.models import InvitationKey
from models import InvitationRequest

class UserCreationFormWithEmail(django.contrib.auth.forms.UserCreationForm):
    username = django.forms.RegexField(label="Username", max_length=30, regex=r'^\w+$',
        help_text = "Please pick a username, of 30 characters or fewer. Stick to letters, digits and underscores.",
        error_messages = {'invalid': "Stick to letters, digits and underscores.", 'required': "Gotta pick a username!"})
    email = django.forms.EmailField(error_messages={
        'required': "Your email address is required. We promise to use it respectfully.",
        'invalid': "This email address looks fishy. Real, or malarkey?"})
    class Meta:
        model = django.contrib.auth.models.User
        fields = ('username', 'email', 'password1')

    def __init__(self, *args, **kw):
        super(django.contrib.auth.forms.UserCreationForm,
                self).__init__(*args, **kw)

        custom_error_messages = {}
        custom_error_messages_dict = {
                "A user with that username already exists.": "Oops, we've already got a user in our database with that username. Pick another one!",
                "A user with that email already exists.": "We've already got a user in our database with that email address. Have you signed up before? (We'll have a password reset thinger shortly.)",
                }

        for fieldname in self.errors:
            for index, error_text in enumerate(self.errors[fieldname]):
                uet = unicode(error_text)
                self.errors[fieldname][index] = custom_error_messages_dict.get(uet, uet)

    def clean_email(self):
        """Verify that their email is unique."""
        email = self.cleaned_data["email"]
        try:
            User.objects.get(email=email)
        except User.DoesNotExist:
            return email
        raise django.forms.ValidationError(
            "A user with that email already exists.")

class ShowEmailForm(django.forms.Form):
    show_email = django.forms.BooleanField(required=False, label="Make email publicly visible?")

class EditEmailForm(django.forms.ModelForm):
    class Meta:
        model = django.contrib.auth.models.User
        fields = ('email',)

    def clean_email(self):
        """Verify that their email is unique."""
        email = self.cleaned_data["email"]
        other_users_with_this_email = list(
                User.objects.filter(email=email).exclude(
                    username=self.instance.username))
        if not other_users_with_this_email:
            return email
        else:
            raise django.forms.ValidationError(
                "A user with that email already exists.")

class EditLocationForm(django.forms.ModelForm):
    class Meta:
        model = Person
        fields = ('location_display_name',)
    def clean_location_display_name(self):
        return self.cleaned_data['location_display_name'].strip()

class EditNameForm(django.forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name')

class EditPhotoForm(django.forms.ModelForm):
    class Meta:
        model = Person
        fields = ('photo',)

    def clean_photo(self):
        # Safe copy of data...
        self.cleaned_data['photo'].seek(0)
        data = self.cleaned_data['photo'].read()
        self.cleaned_data['photo'].seek(0)
        data_fd = StringIO.StringIO(data)

        w, h = get_image_dimensions(data_fd)
        if w > 200:
            # Scale it down.
            too_big = PIL.Image.open(StringIO.StringIO(data))
            format = too_big.format
            new_w = 200
            new_h = (h * 1.0 / w) * 200

            smaller = too_big.resize((new_w, new_h),
                                     PIL.Image.ANTIALIAS)

            # "Save" it to memory
            new_image_fd = StringIO.StringIO()
            smaller.save(new_image_fd, format=format)
            new_image_fd.seek(0)

            old = self.cleaned_data['photo']

            new_image_uploaded_file = InMemoryUploadedFile(
                name='',
                file=new_image_fd,
                content_type=None,
                size=new_image_fd.len,
                charset=None)

            # Modify the self.cleaned_data[]
            self.cleaned_data['photo'] = new_image_uploaded_file
        return self.cleaned_data['photo']

class InvitationRequestForm(django.forms.ModelForm):

    class Meta:
        model = InvitationRequest

    first_name = django.forms.CharField(error_messages = {
        'required': "We need at least your first name."})
    last_name = django.forms.CharField(required=False)
    email = django.forms.EmailField(error_messages={
        'required': "Uh, we want to email you an invitation.",
        'invalid': "This email address got caught in a regex; try again."})
from django_authopenid.forms import OpenidRegisterForm
import django.forms
from django.conf import settings
from invitation.models import InvitationKey

OpenidRegisterFormWithInviteCode = OpenidRegisterForm
<commit_msg>The smallest possible delta to fix the problem Mako had.<commit_after>import django.contrib.auth.forms
from django.contrib.auth.models import User
import django.forms
from mysite.profile.models import Person
import StringIO
from django.core.files.images import get_image_dimensions
from django.core.files.uploadedfile import InMemoryUploadedFile
import PIL.Image
from django.conf import settings
from invitation.models import InvitationKey
from models import InvitationRequest

class UserCreationFormWithEmail(django.contrib.auth.forms.UserCreationForm):
    username = django.forms.RegexField(label="Username", max_length=30, regex=r'^\w+$',
        help_text = "Please pick a username, of 30 characters or fewer. Stick to letters, digits and underscores.",
        error_messages = {'invalid': "Stick to letters, digits and underscores.", 'required': "Gotta pick a username!"})
    email = django.forms.EmailField(error_messages={
        'required': "Your email address is required. We promise to use it respectfully.",
        'invalid': "This email address looks fishy. Real, or malarkey?"})
    class Meta:
        model = django.contrib.auth.models.User
        fields = ('username', 'email', 'password1')

    def __init__(self, *args, **kw):
        super(django.contrib.auth.forms.UserCreationForm,
                self).__init__(*args, **kw)

        custom_error_messages = {}
        custom_error_messages_dict = {
                "A user with that username already exists.": "Oops, we've already got a user in our database with that username. Pick another one!",
                "A user with that email already exists.": "We've already got a user in our database with that email address. Have you signed up before? (We'll have a password reset thinger shortly.)",
                }

        for fieldname in self.errors:
            for index, error_text in enumerate(self.errors[fieldname]):
                uet = unicode(error_text)
                self.errors[fieldname][index] = custom_error_messages_dict.get(uet, uet)

    def clean_email(self):
        """Verify that their email is unique."""
        email = self.cleaned_data["email"]
        try:
            User.objects.get(email=email)
        except User.DoesNotExist:
            return email
        raise django.forms.ValidationError(
            "A user with that email already exists.")

class ShowEmailForm(django.forms.Form):
    show_email = django.forms.BooleanField(required=False, label="Make email publicly visible?")

class EditEmailForm(django.forms.ModelForm):
    class Meta:
        model = django.contrib.auth.models.User
        fields = ('email',)

    def clean_email(self):
        """Verify that their email is unique."""
        email = self.cleaned_data["email"]
        other_users_with_this_email = list(
                User.objects.filter(email=email).exclude(
                    username=self.instance.username))
        if not other_users_with_this_email:
            return email
        else:
            raise django.forms.ValidationError(
                "A user with that email already exists.")

class EditLocationForm(django.forms.ModelForm):
    class Meta:
        model = Person
        fields = ('location_display_name',)
    def clean_location_display_name(self):
        return self.cleaned_data['location_display_name'].strip()

class EditNameForm(django.forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name')

class EditPhotoForm(django.forms.ModelForm):
    class Meta:
        model = Person
        fields = ('photo',)

    def clean_photo(self):
        # Safe copy of data...
        self.cleaned_data['photo'].seek(0)
        data = self.cleaned_data['photo'].read()
        self.cleaned_data['photo'].seek(0)
        data_fd = StringIO.StringIO(data)

        w, h = get_image_dimensions(data_fd)
        if w > 200:
            # Scale it down.
            too_big = PIL.Image.open(StringIO.StringIO(data))
            format = too_big.format
            new_w = 200
            new_h = (h * 1.0 / w) * 200

            smaller = too_big.resize((new_w, new_h),
                                     PIL.Image.ANTIALIAS)

            # "Save" it to memory
            new_image_fd = StringIO.StringIO()
            smaller.save(new_image_fd, format=format)
            new_image_fd.seek(0)

            old = self.cleaned_data['photo']

            new_image_uploaded_file = InMemoryUploadedFile(
                new_image_fd, '', old.name,
                old.content_type, new_image_fd.len, old.charset)

            # Modify the self.cleaned_data[]
            self.cleaned_data['photo'] = new_image_uploaded_file
        return self.cleaned_data['photo']

class InvitationRequestForm(django.forms.ModelForm):

    class Meta:
        model = InvitationRequest

    first_name = django.forms.CharField(error_messages = {
        'required': "We need at least your first name."})
    last_name = django.forms.CharField(required=False)
    email = django.forms.EmailField(error_messages={
        'required': "Uh, we want to email you an invitation.",
        'invalid': "This email address got caught in a regex; try again."})
from django_authopenid.forms import OpenidRegisterForm
import django.forms
from django.conf import settings
from invitation.models import InvitationKey

OpenidRegisterFormWithInviteCode = OpenidRegisterForm
<|endoftext|>


<commit_before>
from discord.ext import commands

import inspect
import re
from typing import Optional

import clarifai.rest
import imgurpython

from modules import utilities
from utilities import checks

def setup(bot):
	bot.add_cog(Images(bot))

class Images(commands.Cog):

	def __init__(self, bot):
		self.bot = bot
		# Add commands as image subcommands
		for name, command in inspect.getmembers(self):
			if isinstance(command, commands.Command) and command.parent is None and name != "image":
				self.bot.add_command(command)
				self.image.add_command(command)
		# Add image google subcommand as google images subcommand
		utilities.add_as_subcommand(self, self.image_google, "Search.google", "images", aliases = ["image"])
		# Add imgur search subcommand as search imgur subcommand
		utilities.add_as_subcommand(self, self.imgur_search, "Search.search", "imgur")

	def cog_unload(self):
		utilities.remove_as_subcommand(self, "Search.google", "images")
		utilities.remove_as_subcommand(self, "Search.search", "imgur")

	def cog_check(self, ctx):
		return checks.not_forbidden_predicate(ctx)

	@commands.group(aliases = ["images"], invoke_without_command = True)
	async def image(self, ctx):
		'''
		Images
		All image subcommands are also commands
		'''
		await ctx.invoke(ctx.bot.get_command("help"), ctx.invoked_with)

	@image.command(name = "color", aliases = ["colour"])
	async def image_color(self, ctx, image_url : str):
		'''
		Image color density values
		and the closest W3C color name for each identified color
		'''
		try:
			response = self.bot.clarifai_app.public_models.color_model.predict_by_url(image_url)
		except clarifai.rest.ApiError as e:
			return await ctx.embed_reply(f":no_entry: Error: `{e.response.json()['outputs'][0]['status']['details']}`")
		if response["status"]["description"] != "Ok":
			return await ctx.embed_reply(":no_entry: Error")
		fields = []
		for color in sorted(response["outputs"][0]["data"]["colors"], key = lambda c: c["value"], reverse = True):
			fields.append((color["raw_hex"].upper(), f"{color['value'] * 100:.2f}%\n"
														f"{re.sub(r'(?!^)(?=[A-Z])', ' ', color['w3c']['name'])}\n"
														f"({color['w3c']['hex'].upper()})"))
		await ctx.embed_reply(title = "Color Density", fields = fields, thumbnail_url = image_url)

	@image.command(name = "google", aliases = ["search"])
	async def image_google(self, ctx, *, search : str):
		'''Google image search something'''
		url = "https://www.googleapis.com/customsearch/v1"
		params = {"key": ctx.bot.GOOGLE_API_KEY, "cx": ctx.bot.GOOGLE_CUSTOM_SEARCH_ENGINE_ID,
					"searchType": "image", 'q': search, "num": 1, "safe": "active"}
		# TODO: Option to disable SafeSearch
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			if resp.status == 403:
				return await ctx.embed_reply(":no_entry: Daily limit exceeded")
			data = await resp.json()
		if "items" not in data:
			return await ctx.embed_reply(":no_entry: No images with that search found")
		await ctx.embed_reply(image_url = data["items"][0]["link"],
								title = f"Image of {search}",
								title_url = data["items"][0]["link"])
		# TODO: handle 403 daily limit exceeded error

	@image.command(name = "recognition")
	async def image_recognition(self, ctx, image_url : Optional[str]):
		'''Image recognition'''
		if not image_url:
			if not ctx.message.attachments:
				return await ctx.embed_reply(":no_entry: Please input an image and/or url")
			image_url = ctx.message.attachments[0].url
		try:
			response = self.bot.clarifai_app.public_models.general_model.predict_by_url(image_url)
		except clarifai.rest.ApiError as e:
			return await ctx.embed_reply(f":no_entry: Error: `{e.response.json()['outputs'][0]['status']['details']}`")
		if response["status"]["description"] != "Ok":
			return await ctx.embed_reply(":no_entry: Error")
		names = {}
		for concept in response["outputs"][0]["data"]["concepts"]:
			names[concept["name"]] = concept["value"] * 100
		output = ""
		for name, value in sorted(names.items(), key = lambda i: i[1], reverse = True):
			output += f"**{name}**: {value:.2f}%, "
		output = output[:-2]
		await ctx.embed_reply(output, thumbnail_url = image_url)

	# TODO: add as search subcommand
	@commands.group(invoke_without_command = True)
	async def giphy(self, ctx, *, search : str):
		'''Find an image on giphy'''
		url = "http://api.giphy.com/v1/gifs/search"
		params = {"api_key": ctx.bot.GIPHY_API_KEY, 'q': search, "limit": 1}
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			data = await resp.json()
		await ctx.embed_reply(image_url = data["data"][0]["images"]["original"]["url"])

	@giphy.command(name = "trending")
	async def giphy_trending(self, ctx):
		'''Trending gif'''
		url = "http://api.giphy.com/v1/gifs/trending"
		params = {"api_key": ctx.bot.GIPHY_API_KEY}
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			data = await resp.json()
		await ctx.embed_reply(image_url = data["data"][0]["images"]["original"]["url"])

	@commands.group(invoke_without_command = True)
	async def imgur(self, ctx):
		'''Imgur'''
		await ctx.invoke(self.bot.get_command("help"), ctx.invoked_with)

	@imgur.command(name = "upload")
	async def imgur_upload(self, ctx, url : str = ""):
		'''Upload images to Imgur'''
		if not (url or ctx.message.attachments):
			return await ctx.embed_reply(":no_entry: Please input an image and/or url")
		image = url or ctx.message.attachments[0].url
		try:
			await ctx.embed_reply(self.bot.imgur_client.upload_from_url(image)["link"])
		except imgurpython.helpers.error.ImgurClientError as e:
			await ctx.embed_reply(f":no_entry: Error: {e}")

	@imgur.command(name = "search")
	async def imgur_search(self, ctx, *, search : str):
		'''Search images on Imgur'''
		result = self.bot.imgur_client.gallery_search(search, sort = "top")
		if not result:
			await ctx.embed_reply(":no_entry: No results found")
			return
		result = result[0]
		if result.is_album:
			result = self.bot.imgur_client.get_album(result.id).images[0]
			await ctx.embed_reply(image_url = result["link"])
		else:
			await ctx.embed_reply(image_url = result.link)

	@commands.command()
	async def nsfw(self, ctx, image_url : str):
		'''NSFW recognition'''
		try:
			response = self.bot.clarifai_app.public_models.nsfw_model.predict_by_url(image_url)
		except clarifai.rest.ApiError as e:
			await ctx.embed_reply(":no_entry: Error: `{}`".format(e.response.json()["outputs"][0]["status"]["details"]))
			return
		if response["status"]["description"] != "Ok":
			await ctx.embed_reply(":no_entry: Error")
			return
		percentages = {}
		for concept in response["outputs"][0]["data"]["concepts"]:
			percentages[concept["name"]] = concept["value"] * 100
		await ctx.embed_reply("NSFW: {:.2f}%".format(percentages["nsfw"]), thumbnail_url = image_url)

<commit_msg>[Discord] Handle attachments for image color command<commit_after>
from discord.ext import commands

import inspect
import re
from typing import Optional

import clarifai.rest
import imgurpython

from modules import utilities
from utilities import checks

def setup(bot):
	bot.add_cog(Images(bot))

class Images(commands.Cog):

	def __init__(self, bot):
		self.bot = bot
		# Add commands as image subcommands
		for name, command in inspect.getmembers(self):
			if isinstance(command, commands.Command) and command.parent is None and name != "image":
				self.bot.add_command(command)
				self.image.add_command(command)
		# Add image google subcommand as google images subcommand
		utilities.add_as_subcommand(self, self.image_google, "Search.google", "images", aliases = ["image"])
		# Add imgur search subcommand as search imgur subcommand
		utilities.add_as_subcommand(self, self.imgur_search, "Search.search", "imgur")

	def cog_unload(self):
		utilities.remove_as_subcommand(self, "Search.google", "images")
		utilities.remove_as_subcommand(self, "Search.search", "imgur")

	def cog_check(self, ctx):
		return checks.not_forbidden_predicate(ctx)

	@commands.group(aliases = ["images"], invoke_without_command = True)
	async def image(self, ctx):
		'''
		Images
		All image subcommands are also commands
		'''
		await ctx.invoke(ctx.bot.get_command("help"), ctx.invoked_with)

	@image.command(name = "color", aliases = ["colour"])
	async def image_color(self, ctx, image_url : Optional[str]):
		'''
		Image color density values
		and the closest W3C color name for each identified color
		'''
		if not image_url:
			if not ctx.message.attachments:
				return await ctx.embed_reply(":no_entry: Please input an image and/or url")
			image_url = ctx.message.attachments[0].url
		try:
			response = self.bot.clarifai_app.public_models.color_model.predict_by_url(image_url)
		except clarifai.rest.ApiError as e:
			return await ctx.embed_reply(f":no_entry: Error: `{e.response.json()['outputs'][0]['status']['details']}`")
		if response["status"]["description"] != "Ok":
			return await ctx.embed_reply(":no_entry: Error")
		fields = []
		for color in sorted(response["outputs"][0]["data"]["colors"], key = lambda c: c["value"], reverse = True):
			fields.append((color["raw_hex"].upper(), f"{color['value'] * 100:.2f}%\n"
														f"{re.sub(r'(?!^)(?=[A-Z])', ' ', color['w3c']['name'])}\n"
														f"({color['w3c']['hex'].upper()})"))
		await ctx.embed_reply(title = "Color Density", fields = fields, thumbnail_url = image_url)

	@image.command(name = "google", aliases = ["search"])
	async def image_google(self, ctx, *, search : str):
		'''Google image search something'''
		url = "https://www.googleapis.com/customsearch/v1"
		params = {"key": ctx.bot.GOOGLE_API_KEY, "cx": ctx.bot.GOOGLE_CUSTOM_SEARCH_ENGINE_ID,
					"searchType": "image", 'q': search, "num": 1, "safe": "active"}
		# TODO: Option to disable SafeSearch
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			if resp.status == 403:
				return await ctx.embed_reply(":no_entry: Daily limit exceeded")
			data = await resp.json()
		if "items" not in data:
			return await ctx.embed_reply(":no_entry: No images with that search found")
		await ctx.embed_reply(image_url = data["items"][0]["link"],
								title = f"Image of {search}",
								title_url = data["items"][0]["link"])
		# TODO: handle 403 daily limit exceeded error

	@image.command(name = "recognition")
	async def image_recognition(self, ctx, image_url : Optional[str]):
		'''Image recognition'''
		if not image_url:
			if not ctx.message.attachments:
				return await ctx.embed_reply(":no_entry: Please input an image and/or url")
			image_url = ctx.message.attachments[0].url
		try:
			response = self.bot.clarifai_app.public_models.general_model.predict_by_url(image_url)
		except clarifai.rest.ApiError as e:
			return await ctx.embed_reply(f":no_entry: Error: `{e.response.json()['outputs'][0]['status']['details']}`")
		if response["status"]["description"] != "Ok":
			return await ctx.embed_reply(":no_entry: Error")
		names = {}
		for concept in response["outputs"][0]["data"]["concepts"]:
			names[concept["name"]] = concept["value"] * 100
		output = ""
		for name, value in sorted(names.items(), key = lambda i: i[1], reverse = True):
			output += f"**{name}**: {value:.2f}%, "
		output = output[:-2]
		await ctx.embed_reply(output, thumbnail_url = image_url)

	# TODO: add as search subcommand
	@commands.group(invoke_without_command = True)
	async def giphy(self, ctx, *, search : str):
		'''Find an image on giphy'''
		url = "http://api.giphy.com/v1/gifs/search"
		params = {"api_key": ctx.bot.GIPHY_API_KEY, 'q': search, "limit": 1}
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			data = await resp.json()
		await ctx.embed_reply(image_url = data["data"][0]["images"]["original"]["url"])

	@giphy.command(name = "trending")
	async def giphy_trending(self, ctx):
		'''Trending gif'''
		url = "http://api.giphy.com/v1/gifs/trending"
		params = {"api_key": ctx.bot.GIPHY_API_KEY}
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			data = await resp.json()
		await ctx.embed_reply(image_url = data["data"][0]["images"]["original"]["url"])

	@commands.group(invoke_without_command = True)
	async def imgur(self, ctx):
		'''Imgur'''
		await ctx.invoke(self.bot.get_command("help"), ctx.invoked_with)

	@imgur.command(name = "upload")
	async def imgur_upload(self, ctx, url : str = ""):
		'''Upload images to Imgur'''
		if not (url or ctx.message.attachments):
			return await ctx.embed_reply(":no_entry: Please input an image and/or url")
		image = url or ctx.message.attachments[0].url
		try:
			await ctx.embed_reply(self.bot.imgur_client.upload_from_url(image)["link"])
		except imgurpython.helpers.error.ImgurClientError as e:
			await ctx.embed_reply(f":no_entry: Error: {e}")

	@imgur.command(name = "search")
	async def imgur_search(self, ctx, *, search : str):
		'''Search images on Imgur'''
		result = self.bot.imgur_client.gallery_search(search, sort = "top")
		if not result:
			await ctx.embed_reply(":no_entry: No results found")
			return
		result = result[0]
		if result.is_album:
			result = self.bot.imgur_client.get_album(result.id).images[0]
			await ctx.embed_reply(image_url = result["link"])
		else:
			await ctx.embed_reply(image_url = result.link)

	@commands.command()
	async def nsfw(self, ctx, image_url : str):
		'''NSFW recognition'''
		try:
			response = self.bot.clarifai_app.public_models.nsfw_model.predict_by_url(image_url)
		except clarifai.rest.ApiError as e:
			await ctx.embed_reply(":no_entry: Error: `{}`".format(e.response.json()["outputs"][0]["status"]["details"]))
			return
		if response["status"]["description"] != "Ok":
			await ctx.embed_reply(":no_entry: Error")
			return
		percentages = {}
		for concept in response["outputs"][0]["data"]["concepts"]:
			percentages[concept["name"]] = concept["value"] * 100
		await ctx.embed_reply("NSFW: {:.2f}%".format(percentages["nsfw"]), thumbnail_url = image_url)

<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
    Solve the N queens problem http://en.wikipedia.org/wiki/Eight_queens_puzzle
    using naive constraint propagation.

    Usage:
        python n_queens.py <N>
    e.g.
        python .n_queens.py 20

    NOTES:
        Uses NumPy and Numba so the best way to run this is to get the latest Anaconda disto
        from https://store.continuum.io/
        If you don't want to use Numba then remove the @autojit.
        If you don't want to even use Numpy then make board a list of lists.
        This program only works for N with value up to about 900 (on Windows 64 bit) due to
        stack size limitations in python. If you want to solve for large values of N then convert
        add_queen() from a recursive to an iterative function.
"""
from __future__ import division
import numpy as np
import sys, random
from numba import autojit

def make_board(N):
    """Create a N x N chessboard
        Returns: An N X N integer NumPy array
    """
    return np.zeros((N, N), dtype=np.int)

@autojit
def propagate(N, board, x, y, d):
    """Propagate the constraints that arise from adding (d = +1) or removing (d = -1) a queen to the
        board at (x, y)

        N: Width of chessboard
        board: State of chessboard for current queens which does not include the one at (x, y).
               board[x, y] = 1 if (x, y) is threatened by any of queens
        x, y: Coordinates of queen to be added/removed
        d: +1 to add a queen, -1 to remove a queen
    """

    # Add d to the elements in the column and row that intersect (x, y) including (x, y)
    board[x, :] += d
    board[:, y] += d
    board[x, y] -= d

    # Add d to the elements in the diagonals that intersect (x, y) excluding (x, y)
    # This looks at a bit funny because of the current limitations of Numba but this is the
    #  inner loop of this script so we put up with the odd looking code for the speed.
    x1 = x - 1
    y1 = y - 1
    x2 = x + 1
    y2 = y - 1
    x3 = x - 1
    y3 = y + 1
    x4 = x + 1
    y4 = y + 1

    while x1 >= 0 and y1 >= 0:
        board[x1, y1] += d
        x1 -= 1
        y1 -= 1

    while x2 < N and y2 >= 0:
        board[x2, y2] += d
        x2 += 1
        y2 -= 1

    while x3 >= 0 and y3 < N:
        board[x3, y3] += d
        x3 -= 1
        y3 += 1

    while x4 < N and y4 < N:
        board[x4, y4] += d
        x4 += 1
        y4 += 1

def add_queen(N, queens, board):
    """Add a queen to board
        Board is filled from left column to right.
        This function called recursively.
        It gets called with a valid list of queens and attempts to add one more queen.

        N: Width of chessboard
        queens: List of queens that have been placed so far. queens[i] = row of queen on column i
        board: State of chessboard. board[x, y] = 1 if (x, y) is threatened by any of queens
        Returns: Valid list of N queens if one has been found, None otherwise

        Note: board gets modified then restored to its state at entry to this function.
    """
    # The queens are valid by design. If there are N of them so we must have a full solution.
    if len(queens) == N:
        return queens

    # Checking rows in random order makes this run fast
    row_order = list(range(N))
    random.shuffle(row_order)

    x = len(queens)
    for y in row_order:
        # Don't check threatened positions. The efficiency of this program is basically due to the
        # pruning of the search space that results from this.
        if board[x, y] != 0:
            continue

        # Add the contraints for the new queen at (x, y)
        propagate(N, board, x, y, 1)
        # Recurse
        valid_queens = add_queen(N, queens + [y], board)
        # Undo the constraints added for queen at x, y
        propagate(N, board, x, y, -1)

        # If we found a valid board deeper in the recursion just return it.
        if valid_queens:
            return valid_queens

    # If we got here then queens could be not be extended to a valid N queens list
    return None

def solve(N):
    """Solve the N queens problem with constraint propagation
        queens = solve(N) => queens[i] is the row of the queen in column i
                           where 0 <= row < N and 0 <= column < N
        Returns: List of rows for queens.
    """
    return add_queen(N, [], make_board(N))

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print __doc__
        exit()

    N = int(sys.argv[1])
    print 'Solving %d queens problem' % N

    queens = solve(N)

    print queens

    if N > 80:
        print 'Chessboard too big to display'
        exit()

    print '-' * 80
    for y in range(N):
        print ''.join(' Q' if x == y else ' +' for x in queens)

<commit_msg>alternatve methods<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
    Solve the N queens problem http://en.wikipedia.org/wiki/Eight_queens_puzzle
    using naive constraint propagation.

    Usage:
        python n_queens.py <N>
    e.g.
        python .n_queens.py 20

    NOTES:
        1 Uses NumPy and Numba so the best way to run this is to get the latest Anaconda disto
          from https://store.continuum.io/
        2 If you don't want to use Numba then remove the @autojit.
        3 If you don't want to even use Numpy then make board a list of lists.
        4 This program only works for N with value up to about 900 (on Windows 64 bit) due to
          stack size limitations in python. If you want to solve for large values of N then convert
          add_queen() from a recursive to an iterative function.
        5 Alternative solutions include
            Local search http://en.wikipedia.org/wiki/Min-conflicts_algorithm#Example
            MIP: http://scip.zib.de/download/files/scip_intro_01.pdf
            A solver: e.g Comet: http://www.hakank.org/comet/queensn.co
"""
from __future__ import division
import numpy as np
import sys, random
from numba import autojit

def make_board(N):
    """Create a N x N chessboard
        Returns: An N X N integer NumPy array
    """
    return np.zeros((N, N), dtype=np.int)

@autojit
def propagate(N, board, x, y, d):
    """Propagate the constraints that arise from adding (d = +1) or removing (d = -1) a queen to the
        board at (x, y)

        N: Width of chessboard
        board: State of chessboard for current queens which does not include the one at (x, y).
               board[a, b] = 1 if (a, b) is threatened by any of the queens
               board will be updated to inclue the queen at (x, y) when this function returns
        x, y: Coordinates of queen to be added/removed
        d: +1 to add a queen, -1 to remove a queen
    """

    # Add d to the elements in the column and row that intersect (x, y) including (x, y)
    board[x, :] += d
    board[:, y] += d
    board[x, y] -= d

    # Add d to the elements in the diagonals that intersect (x, y) excluding (x, y)
    # This looks at a bit funny because of the current limitations of Numba but this is the
    #  inner loop of this script so we put up with the odd looking code for the speed.
    x1 = x - 1
    y1 = y - 1
    x2 = x + 1
    y2 = y - 1
    x3 = x - 1
    y3 = y + 1
    x4 = x + 1
    y4 = y + 1

    while x1 >= 0 and y1 >= 0:
        board[x1, y1] += d
        x1 -= 1
        y1 -= 1

    while x2 < N and y2 >= 0:
        board[x2, y2] += d
        x2 += 1
        y2 -= 1

    while x3 >= 0 and y3 < N:
        board[x3, y3] += d
        x3 -= 1
        y3 += 1

    while x4 < N and y4 < N:
        board[x4, y4] += d
        x4 += 1
        y4 += 1

def add_queen(N, queens, board):
    """Add a queen to board
        Board is filled from left column to right.
        This function called recursively.
        It gets called with a valid list of queens and attempts to add one more queen.

        N: Width of chessboard
        queens: List of queens that have been placed so far. queens[i] = row of queen on column i
        board: State of chessboard. board[x, y] = 1 if (x, y) is threatened by any of queens
        Returns: Valid list of N queens if one has been found, None otherwise

        Note: board gets modified then restored to its state at entry to this function.
    """
    # The queens are valid by design. If there are N of them so we must have a full solution.
    if len(queens) == N:
        return queens

    # Checking rows in random order makes this run fast
    row_order = list(range(N))
    random.shuffle(row_order)

    x = len(queens)
    for y in row_order:
        # Don't check threatened positions. The efficiency of this program is basically due to the
        # pruning of the search space that results from this.
        if board[x, y] != 0:
            continue

        # Add the contraints for the new queen at (x, y)
        propagate(N, board, x, y, 1)
        # Recurse
        valid_queens = add_queen(N, queens + [y], board)
        # Undo the constraints added for queen at x, y
        propagate(N, board, x, y, -1)

        # If we found a valid board deeper in the recursion just return it.
        if valid_queens:
            return valid_queens

    # If we got here then queens could be not be extended to a valid N queens list
    return None

def solve(N):
    """Solve the N queens problem with constraint propagation
        queens = solve(N) => queens[i] is the row of the queen in column i
                           where 0 <= row < N and 0 <= column < N
        Returns: List of rows for queens.
    """
    return add_queen(N, [], make_board(N))

if __name__ == '__main__':
    if len(sys.argv) != 2:
        print __doc__
        exit()

    N = int(sys.argv[1])
    print 'Solving %d queens problem' % N

    queens = solve(N)

    print queens

    if N > 80:
        print 'Chessboard too big to display'
        exit()

    print '-' * 80
    for y in range(N):
        print ''.join(' Q' if x == y else ' +' for x in queens)

<|endoftext|>


<commit_before># Copyright 2013,2014 Music Technology Group - Universitat Pompeu Fabra
#
# This file is part of Dunya
#
# Dunya is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free Software
# Foundation (FSF), either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see http://www.gnu.org/licenses/

from django.core.files.base import ContentFile
import os

import data.models

from compmusic import wikipedia
from compmusic import kutcheris
from compmusic import image
from compmusic import file

def import_artist_kutcheris(a, overwrite):
    artist = kutcheris.search_artist(a.name)
    if artist:
        print "Found data on kutcheris.com"
        aid = artist.values()[0]
        i, b, u = kutcheris.get_artist_details(aid)
        u = "http://kutcheris.com/artist.php?id=%s" % aid
        if b:
            sn = data.models.SourceName.objects.get(name="kutcheris.com")

    if b:
        source, created = data.models.Source.objects.get_or_create(source_name=sn, uri=u, defaults={"title": a.name})
        description = data.models.Description.objects.create(description=b, source=source)
        if overwrite or not a.description:
            a.description = description
            a.save()

def import_artist_wikipedia(artist, overwrite):
    print "Looking for data on wikipedia"
    sn = data.models.SourceName.objects.get(name="Wikipedia")
    refs = artist.references.filter(source_name=sn)
    if refs.exists():
        source = refs.all()[0]
        wikiurl = source.uri
        name = os.path.basename(wikiurl)

        img, bio = wikipedia.get_artist_details(name)
        if bio:
            description = data.models.Description.objects.create(description=bio, source=source)
            if overwrite or not artist.description:
                artist.description = description
                artist.save()
        if img:
            try:
                existingimg = artist.images.get(image__contains="%s" % artist.mbid)
                if not os.path.exists(existingimg.image.path):
                    existingimg.delete()
                elif existingimg.image.size != len(i) or overwrite:
                    # If the imagesize has changed, or overwrite is set, remove the image
                    os.unlink(existingimg.image.path)
                    existingimg.delete()
            except data.models.Image.DoesNotExist:
                pass

            im = data.models.Image()
            im.image.save("artist-%s.jpg" % artist.mbid, ContentFile(img))
            artist.images.add(im)

def import_release_image(release, directories=[], overwrite=False):
    for existing in release.images.all():
        name = os.path.splitext(os.path.basename(existing.image.name))
        if name == release.mbid:
            print "Image for release %s exists, skipping" % release.mbid
            return

    i = image.get_coverart_from_caa(release.mbid)
    caa = True
    if not i:
        caa = False
        print "No image on CAA for %s, looking in directory" % release.mbid
        i = image.get_coverart_from_directories(directories)
    if i:
        im = data.models.Image()
        if caa:
            uri = "http://archive.org/details/mbid-%s" % release.mbid
            sn = data.models.SourceName.objects.get(name="Cover Art Archive")
            source, created = data.models.Source.objects.get_or_create(source_name=sn, uri=uri, defaults={"title": release.title})
            im.source = source
        im.image.save("release-%s.jpg" % release.mbid, ContentFile(i))

        # If the image is a different size from one that already exists, then
        # replace it. Also remove if we have an item, but can't find the image
        # for it.
        try:
            existingimg = release.images.get(image__contains="%s" % release.mbid)
            if not os.path.exists(existingimg.image.path):
                existingimg.delete()
            elif existingimg.image.size != len(i) or overwrite:
                # If the imagesize has changed, or overwrite is set, remove the image
                os.unlink(existingimg.image.path)
                existingimg.delete()
        except data.models.Image.DoesNotExist:
            pass

        release.images.add(im)
        release.save()
    else:
        print "Can't find an image for %s" % release.mbid

<commit_msg>error in wikipedia importer<commit_after># Copyright 2013,2014 Music Technology Group - Universitat Pompeu Fabra
#
# This file is part of Dunya
#
# Dunya is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free Software
# Foundation (FSF), either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see http://www.gnu.org/licenses/

from django.core.files.base import ContentFile
import os

import data.models

from compmusic import wikipedia
from compmusic import kutcheris
from compmusic import image
from compmusic import file

def import_artist_kutcheris(a, overwrite):
    artist = kutcheris.search_artist(a.name)
    if artist:
        print "Found data on kutcheris.com"
        aid = artist.values()[0]
        i, b, u = kutcheris.get_artist_details(aid)
        u = "http://kutcheris.com/artist.php?id=%s" % aid
        if b:
            sn = data.models.SourceName.objects.get(name="kutcheris.com")

    if b:
        source, created = data.models.Source.objects.get_or_create(source_name=sn, uri=u, defaults={"title": a.name})
        description = data.models.Description.objects.create(description=b, source=source)
        if overwrite or not a.description:
            a.description = description
            a.save()

def import_artist_wikipedia(artist, overwrite):
    print "Looking for data on wikipedia"
    sn = data.models.SourceName.objects.get(name="Wikipedia")
    refs = artist.references.filter(source_name=sn)
    if refs.exists():
        source = refs.all()[0]
        wikiurl = source.uri
        name = os.path.basename(wikiurl)

        img, bio = wikipedia.get_artist_details(name)
        if bio:
            description = data.models.Description.objects.create(description=bio, source=source)
            if overwrite or not artist.description:
                artist.description = description
                artist.save()
        if img:
            try:
                existingimg = artist.images.get(image__contains="%s" % artist.mbid)
                if not os.path.exists(existingimg.image.path):
                    existingimg.delete()
                elif existingimg.image.size != len(img) or overwrite:
                    # If the imagesize has changed, or overwrite is set, remove the image
                    os.unlink(existingimg.image.path)
                    existingimg.delete()
            except data.models.Image.DoesNotExist:
                pass

            im = data.models.Image()
            im.image.save("artist-%s.jpg" % artist.mbid, ContentFile(img))
            artist.images.add(im)

def import_release_image(release, directories=[], overwrite=False):
    for existing in release.images.all():
        name = os.path.splitext(os.path.basename(existing.image.name))
        if name == release.mbid:
            print "Image for release %s exists, skipping" % release.mbid
            return

    i = image.get_coverart_from_caa(release.mbid)
    caa = True
    if not i:
        caa = False
        print "No image on CAA for %s, looking in directory" % release.mbid
        i = image.get_coverart_from_directories(directories)
    if i:
        im = data.models.Image()
        if caa:
            uri = "http://archive.org/details/mbid-%s" % release.mbid
            sn = data.models.SourceName.objects.get(name="Cover Art Archive")
            source, created = data.models.Source.objects.get_or_create(source_name=sn, uri=uri, defaults={"title": release.title})
            im.source = source
        im.image.save("release-%s.jpg" % release.mbid, ContentFile(i))

        # If the image is a different size from one that already exists, then
        # replace it. Also remove if we have an item, but can't find the image
        # for it.
        try:
            existingimg = release.images.get(image__contains="%s" % release.mbid)
            if not os.path.exists(existingimg.image.path):
                existingimg.delete()
            elif existingimg.image.size != len(i) or overwrite:
                # If the imagesize has changed, or overwrite is set, remove the image
                os.unlink(existingimg.image.path)
                existingimg.delete()
        except data.models.Image.DoesNotExist:
            pass

        release.images.add(im)
        release.save()
    else:
        print "Can't find an image for %s" % release.mbid

<|endoftext|>


<commit_before>from django.test import TestCase
from myuw.dao.canvas import _get_canvas_enrollment_dict_for_regid
from myuw.dao.schedule import _get_schedule
from myuw.dao.term import get_current_quarter
from myuw.test import fdao_sws_override, get_request_with_user, get_request

@fdao_sws_override
class TestCanvas(TestCase):
    def setUp(self):
        get_request()

    def test_crosslinks(self):
        data = _get_canvas_enrollment_dict_for_regid(
            "12345678901234567890123456789012")

        physics = data['2013,spring,PHYS,121/A']
        self.assertEquals(physics.course_url,
                          'https://canvas.uw.edu/courses/249652')

        has_section_b = '2013,spring,TRAIN,100/B' in data
        self.assertTrue(has_section_b)

        has_section_a = '2013,spring,TRAIN,100/A' in data
        self.assertTrue(has_section_a)

        train = data['2013,spring,TRAIN,100/A']
        self.assertEquals(train.course_url,
                          'https://canvas.uw.edu/courses/249650')
        self.assertFalse(physics.is_unpublished())
<commit_msg>tracks canvas tests with develop<commit_after>from django.test import TestCase
<<<<<<< HEAD
=======
from django.test.client import RequestFactory
from userservice.user import UserServiceMiddleware
>>>>>>> dcf0d3a63c30e729c8e6b43e20f4d26c08b01079
from myuw.dao.canvas import _get_canvas_enrollment_dict_for_regid
from myuw.dao.schedule import _get_schedule
from myuw.dao.term import get_current_quarter
from myuw.test import fdao_sws_override, get_request_with_user, get_request

@fdao_sws_override
class TestCanvas(TestCase):
    def setUp(self):
        get_request()

    def test_crosslinks(self):
<<<<<<< HEAD
        data = _get_canvas_enrollment_dict_for_regid(
            "12345678901234567890123456789012")

        physics = data['2013,spring,PHYS,121/A']
        self.assertEquals(physics.course_url,
                          'https://canvas.uw.edu/courses/249652')

        has_section_b = '2013,spring,TRAIN,100/B' in data
        self.assertTrue(has_section_b)

        has_section_a = '2013,spring,TRAIN,100/A' in data
        self.assertTrue(has_section_a)

        train = data['2013,spring,TRAIN,100/A']
        self.assertEquals(train.course_url,
                          'https://canvas.uw.edu/courses/249650')
        self.assertFalse(physics.is_unpublished())
=======
        with self.settings(RESTCLIENTS_SWS_DAO_CLASS=FDAO_SWS):

            data = _get_canvas_enrollment_dict_for_regid(
                "12345678901234567890123456789012")

            physics = data['2013,spring,PHYS,121/A']
            self.assertEquals(physics.course_url,
                              'https://canvas.uw.edu/courses/249652')

            has_section_b = '2013,spring,TRAIN,100/B' in data
            self.assertTrue(has_section_b)

            has_section_a = '2013,spring,TRAIN,100/A' in data
            self.assertTrue(has_section_a)

            train = data['2013,spring,TRAIN,100/A']
            self.assertEquals(train.course_url,
                              'https://canvas.uw.edu/courses/249650')
>>>>>>> dcf0d3a63c30e729c8e6b43e20f4d26c08b01079
<|endoftext|>


<commit_before>import csv

from django.contrib import admin
from django.http import HttpResponse

from . import importer
from . import models

from myvoice.core.utils import extract_qset_data

class SurveyQuestionInline(admin.TabularInline):
    """
    Disallow adding or deleting SurveyQuestions through the admin - they must
    be managed through the automatic import of Surveys.

    Also disallow editing most of the fields that we import from TextIt.
    """

    extra = 0
    fields = ['id', 'question_id', 'question', 'label', 'question_type',
              'categories']
    model = models.SurveyQuestion
    readonly_fields = ['id', 'question_id', 'label', 'question_type',
                       'categories']

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

class SurveyAdmin(admin.ModelAdmin):
    """
    To add a Survey, the user should enter the flow id and let us handle
    importing the rest of the data from TextIt. After that, nothing is
    editable save some data fields on each question. If edits need to be made
    the Survey should be deleted and re-added.
    """

    add_fieldsets = [
        (None, {
            'description': "Enter the flow id and we will import its details "
                           "from TextIt.",
            'classes': ['wide'],
            'fields': ['flow_id', 'role'],
        }),
    ]
    fields = ['flow_id', 'name', 'role', 'active']
    list_display = ['name', 'flow_id', 'role', 'active']
    list_filter = ['active']
    save_on_top = True

    def add_view(self, *args, **kwargs):
        self.inlines = []
        self.readonly_fields = []
        return super(SurveyAdmin, self).add_view(*args, **kwargs)

    def change_view(self, *args, **kwargs):
        self.inlines = [SurveyQuestionInline]
        self.readonly_fields = ['flow_id']
        return super(SurveyAdmin, self).change_view(*args, **kwargs)

    def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        return super(SurveyAdmin, self).get_fieldsets(request, obj)

    def save_model(self, request, obj, form, change):
        """If we're adding the survey, import its name and questions."""
        super(SurveyAdmin, self).save_model(request, obj, form, change)
        if not change:
            # FIXME - An exception is raised if this flow doesn't exist
            # on TextIt; instead we should check for this in form validation.
            importer.import_survey(obj.flow_id)

class SurveyQuestionResponseAdmin(admin.ModelAdmin):
    """
    Disallow adding or deleting responses through the admin - they must be
    managed through automatic import.

    Also disallow editing the fields that we import from TextIt.
    """

    fieldsets = [
        (None, {
            'fields': ['question', 'visit', 'clinic', 'service', 'response',
                       'datetime'],
        }),
        ('Metadata', {
            'fields': ['created', 'updated'],
        }),
    ]
    list_display = ['mobile', 'visit_time', 'clinic', 'service', 'survey',
                    'question', 'question_type', 'response']
    list_filter = ['question__survey', 'clinic', 'service',
                   'question__question_type']
    list_select_related = True
    ordering = ['visit', 'question']
    search_fields = ['visit__mobile', 'response', 'question__label']
    actions = ['export_to_csv']

    def __init__(self, *args, **kwargs):
        super(SurveyQuestionResponseAdmin, self).__init__(*args, **kwargs)
        self.readonly_fields = ['question', 'response', 'datetime', 'visit',
                                'clinic', 'service', 'created', 'updated']

    def change_view(self, request, *args, **kwargs):
        """
        Allow admins with a permission to edit response text that is typically
        imported directly from TextIt. This is intended as a workaround for
        issues we are experiencing when a user sends a long response.
        """
        if request.user.has_perm('survey.change_response_text'):
            self.readonly_fields.remove('response')
        return super(SurveyQuestionResponseAdmin, self).change_view(
            request, *args, **kwargs)

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def visit_time(self, obj):
        return obj.visit.visit_time

    def question_type(self, obj):
        return obj.question.get_question_type_display()

    def survey(self, obj):
        return obj.question.survey

    def mobile(self, obj):
        return obj.visit.mobile

    def export_to_csv(self, request, queryset):
        headers = ['question', 'response', 'datetime', 'visit.patient.serial',
                   'clinic', 'service', 'created', 'updated']
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename=response_data.csv'
        data = extract_qset_data(queryset, headers)
        writer = csv.writer(response)
        for line in data:
            writer.writerow(line)
        return response

admin.site.register(models.Survey, SurveyAdmin)
admin.site.register(models.SurveyQuestionResponse, SurveyQuestionResponseAdmin)
<commit_msg>Don't change readonly_fields in __init__<commit_after>import csv

from django.contrib import admin
from django.http import HttpResponse

from . import importer
from . import models

from myvoice.core.utils import extract_qset_data

class SurveyQuestionInline(admin.TabularInline):
    """
    Disallow adding or deleting SurveyQuestions through the admin - they must
    be managed through the automatic import of Surveys.

    Also disallow editing most of the fields that we import from TextIt.
    """

    extra = 0
    fields = ['id', 'question_id', 'question', 'label', 'question_type',
              'categories']
    model = models.SurveyQuestion
    readonly_fields = ['id', 'question_id', 'label', 'question_type',
                       'categories']

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

class SurveyAdmin(admin.ModelAdmin):
    """
    To add a Survey, the user should enter the flow id and let us handle
    importing the rest of the data from TextIt. After that, nothing is
    editable save some data fields on each question. If edits need to be made
    the Survey should be deleted and re-added.
    """

    add_fieldsets = [
        (None, {
            'description': "Enter the flow id and we will import its details "
                           "from TextIt.",
            'classes': ['wide'],
            'fields': ['flow_id', 'role'],
        }),
    ]
    fields = ['flow_id', 'name', 'role', 'active']
    list_display = ['name', 'flow_id', 'role', 'active']
    list_filter = ['active']
    save_on_top = True

    def add_view(self, *args, **kwargs):
        self.inlines = []
        self.readonly_fields = []
        return super(SurveyAdmin, self).add_view(*args, **kwargs)

    def change_view(self, *args, **kwargs):
        self.inlines = [SurveyQuestionInline]
        self.readonly_fields = ['flow_id']
        return super(SurveyAdmin, self).change_view(*args, **kwargs)

    def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        return super(SurveyAdmin, self).get_fieldsets(request, obj)

    def save_model(self, request, obj, form, change):
        """If we're adding the survey, import its name and questions."""
        super(SurveyAdmin, self).save_model(request, obj, form, change)
        if not change:
            # FIXME - An exception is raised if this flow doesn't exist
            # on TextIt; instead we should check for this in form validation.
            importer.import_survey(obj.flow_id)

class SurveyQuestionResponseAdmin(admin.ModelAdmin):
    """
    Disallow adding or deleting responses through the admin - they must be
    managed through automatic import.

    Also disallow editing the fields that we import from TextIt.
    """

    fieldsets = [
        (None, {
            'fields': ['question', 'visit', 'clinic', 'service', 'response',
                       'datetime'],
        }),
        ('Metadata', {
            'fields': ['created', 'updated'],
        }),
    ]
    list_display = ['mobile', 'visit_time', 'clinic', 'service', 'survey',
                    'question', 'question_type', 'response']
    list_filter = ['question__survey', 'clinic', 'service',
                   'question__question_type']
    list_select_related = True
    ordering = ['visit', 'question']
    search_fields = ['visit__mobile', 'response', 'question__label']
    actions = ['export_to_csv']

    def change_view(self, request, *args, **kwargs):
        """
        Allow admins with a permission to edit response text that is typically
        imported directly from TextIt. This is intended as a workaround for
        issues we are experiencing when a user sends a long response.
        """
        if request.user.has_perm('survey.change_response_text'):
            self.readonly_fields = ['question', 'datetime', 'visit', 'clinic',
                                    'service', 'created', 'updated']
        else:
            self.readonly_fields = ['question', 'response', 'datetime',
                                    'visit', 'clinic', 'service', 'created',
                                    'updated']
        return super(SurveyQuestionResponseAdmin, self).change_view(
            request, *args, **kwargs)

    def has_add_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def visit_time(self, obj):
        return obj.visit.visit_time

    def question_type(self, obj):
        return obj.question.get_question_type_display()

    def survey(self, obj):
        return obj.question.survey

    def mobile(self, obj):
        return obj.visit.mobile

    def export_to_csv(self, request, queryset):
        headers = ['question', 'response', 'datetime', 'visit.patient.serial',
                   'clinic', 'service', 'created', 'updated']
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename=response_data.csv'
        data = extract_qset_data(queryset, headers)
        writer = csv.writer(response)
        for line in data:
            writer.writerow(line)
        return response

admin.site.register(models.Survey, SurveyAdmin)
admin.site.register(models.SurveyQuestionResponse, SurveyQuestionResponseAdmin)
<|endoftext|>


<commit_before>import os
import sys
import web

curdir = os.path.dirname(__file__)
sys.path.insert(0, curdir)

from nailgun.settings import settings
from nailgun.api.handlers import check_client_content_type
from nailgun.api.handlers import forbid_client_caching
from nailgun.db import load_db_driver
from nailgun.urls import urls
from nailgun.logger import logger, FileLoggerMiddleware

class FlushingLogger(object):
    def __init__(self):
        self.opened = False
        self.fd = None

    @property
    def _fd(self):
        if not self.opened:
            self.fd = open(settings.ACCESS_LOG, "a+")
            self.opened = True
        return self.fd

    def __enter__(self):
        return self._fd

    def __exit__(self, type, value, traceback):
        self._fd.close()
        self.opened = False

    def write(self, data):
        self._fd.write(data)
        self._fd.flush()

    def close(self):
        self._fd.close()
        self.opened = False

def build_app():
    app = web.application(urls, locals())
    app.add_processor(load_db_driver)
    app.add_processor(forbid_client_caching)
    return app

def appstart():
    from nailgun.rpc import processed
    from nailgun.keepalive import keep_alive
    app = build_app()

    if not settings.FAKE_TASKS:
        rpc_process = processed.RPCProcess()
        logger.info("Running RPC process...")
        rpc_process.start()
    logger.info("Running KeepAlive watcher...")
    keep_alive.start()
    logger.info("Running WSGI app...")
    # seizes control
    if not int(settings.DEVELOPMENT):
        wsgifunc = app.wsgifunc(FileLoggerMiddleware)
    else:
        wsgifunc = app.wsgifunc()
    web.httpserver.runsimple(
        wsgifunc,
        (
            settings.LISTEN_ADDRESS,
            int(settings.LISTEN_PORT)
        )
    )
    logger.info("Stopping WSGI app...")
    if not settings.FAKE_TASKS:
        logger.info("Stopping RPC process...")
        rpc_process.terminate()
    logger.info("Stopping KeepAlive watcher...")
    keep_alive.join()
    logger.info("Done")
<commit_msg>keepalive only for non-fake tasks<commit_after>import os
import sys
import web

curdir = os.path.dirname(__file__)
sys.path.insert(0, curdir)

from nailgun.settings import settings
from nailgun.api.handlers import check_client_content_type
from nailgun.api.handlers import forbid_client_caching
from nailgun.db import load_db_driver
from nailgun.urls import urls
from nailgun.logger import logger, FileLoggerMiddleware

class FlushingLogger(object):
    def __init__(self):
        self.opened = False
        self.fd = None

    @property
    def _fd(self):
        if not self.opened:
            self.fd = open(settings.ACCESS_LOG, "a+")
            self.opened = True
        return self.fd

    def __enter__(self):
        return self._fd

    def __exit__(self, type, value, traceback):
        self._fd.close()
        self.opened = False

    def write(self, data):
        self._fd.write(data)
        self._fd.flush()

    def close(self):
        self._fd.close()
        self.opened = False

def build_app():
    app = web.application(urls, locals())
    app.add_processor(load_db_driver)
    app.add_processor(forbid_client_caching)
    return app

def appstart():
    from nailgun.rpc import processed
    from nailgun.keepalive import keep_alive
    app = build_app()

    if not settings.FAKE_TASKS:
        logger.info("Running KeepAlive watcher...")
        keep_alive.start()
        rpc_process = processed.RPCProcess()
        logger.info("Running RPC process...")
        rpc_process.start()
    logger.info("Running WSGI app...")
    # seizes control
    if not int(settings.DEVELOPMENT):
        wsgifunc = app.wsgifunc(FileLoggerMiddleware)
    else:
        wsgifunc = app.wsgifunc()
    web.httpserver.runsimple(
        wsgifunc,
        (
            settings.LISTEN_ADDRESS,
            int(settings.LISTEN_PORT)
        )
    )
    logger.info("Stopping WSGI app...")
    if not settings.FAKE_TASKS:
        logger.info("Stopping KeepAlive watcher...")
        keep_alive.join()
        logger.info("Stopping RPC process...")
        rpc_process.terminate()
    logger.info("Done")
<|endoftext|>


<commit_before># Copyright (C) 2010 Linaro Limited
#
# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
#
# This file is part of Launch Control.
#
# Launch Control is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License version 3
# as published by the Free Software Foundation
#
# Launch Control is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Launch Control.  If not, see <http://www.gnu.org/licenses/>.

import os

from lava_server.extension import LavaServerExtension, Menu

class DashboardExtension(LavaServerExtension):

    @property
    def app_name(self):
        return "dashboard_app"

    @property
    def name(self):
        return "Dashboard"

    @property
    def main_view_name(self):
        return "dashboard_app.views.index"

    def get_menu(self):
        from django.core.urlresolvers import reverse
        menu = super(DashboardExtension, self).get_menu()
        menu.sub_menu = [
            Menu("About", reverse(self.main_view_name)),
            Menu("Testing Efforts", reverse("dashboard_app.views.testing_effort_list")),
            Menu("Bundle Streams", reverse("dashboard_app.views.bundle_stream_list")),
            Menu("Tests", reverse("dashboard_app.views.test_list")),
            Menu("Data Views", reverse("dashboard_app.views.data_view_list")),
            Menu("Reports", reverse("dashboard_app.views.report_list")),
            Menu("Image Reports", reverse("dashboard_app.views.images.image_report_list")),
            Menu("[BETA] Filters", reverse("dashboard_app.views.filters.views.filters_list")),
            ]
        return menu

    @property
    def front_page_template(self):
        return "dashboard_app/front_page_snippet.html"

    def get_front_page_context(self):
        from dashboard_app.models import DataReport
        return {
            'report_list': DataReport.repository.filter(front_page=True),
        }

    @property
    def description(self):
        return "Validation Dashboard"

    @property
    def version(self):
        import dashboard_app
        import versiontools
        return versiontools.format_version(dashboard_app.__version__, hint=dashboard_app)

    @property
    def api_class(self):
        from dashboard_app.xmlrpc import DashboardAPI
        return DashboardAPI

    def contribute_to_settings(self, settings_module):
        super(DashboardExtension, self).contribute_to_settings(settings_module)
        settings_module['INSTALLED_APPS'].append("linaro_django_pagination")
        settings_module['MIDDLEWARE_CLASSES'].append(
            'linaro_django_pagination.middleware.PaginationMiddleware')
        root_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
        settings_module['DATAVIEW_DIRS'] = [
            os.path.join(root_dir, 'examples', 'views'),
            os.path.join(root_dir, 'production', 'views')]
        settings_module['DATAREPORT_DIRS'] = [
            os.path.join(root_dir, 'examples', 'reports'),
            os.path.join(root_dir, 'production', 'reports')]

    def contribute_to_settings_ex(self, settings_module, settings_object):
        settings_module['DATAVIEW_DIRS'] = settings_object._settings.get(
            "DATAVIEW_DIRS", [])
        settings_module['DATAREPORT_DIRS'] = settings_object._settings.get(
            "DATAREPORT_DIRS", [])

        # Enable constrained dataview database if requested
        if settings_object._settings.get("use_dataview_database"):
            # Copy everything from the default database and append _dataview to user
            # name. The rest is out of scope (making sure it's actually setup
            # properly, having permissions to login, permissions to view proper data)
            settings_module['DATABASES']['dataview'] = dict(settings_module['DATABASES']['default'])
            settings_module['DATABASES']['dataview']['USER'] += "_dataview"
<commit_msg>remove [BETA] tag from filters menu entry<commit_after># Copyright (C) 2010 Linaro Limited
#
# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
#
# This file is part of Launch Control.
#
# Launch Control is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License version 3
# as published by the Free Software Foundation
#
# Launch Control is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Launch Control.  If not, see <http://www.gnu.org/licenses/>.

import os

from lava_server.extension import LavaServerExtension, Menu

class DashboardExtension(LavaServerExtension):

    @property
    def app_name(self):
        return "dashboard_app"

    @property
    def name(self):
        return "Dashboard"

    @property
    def main_view_name(self):
        return "dashboard_app.views.index"

    def get_menu(self):
        from django.core.urlresolvers import reverse
        menu = super(DashboardExtension, self).get_menu()
        menu.sub_menu = [
            Menu("About", reverse(self.main_view_name)),
            Menu("Testing Efforts", reverse("dashboard_app.views.testing_effort_list")),
            Menu("Bundle Streams", reverse("dashboard_app.views.bundle_stream_list")),
            Menu("Tests", reverse("dashboard_app.views.test_list")),
            Menu("Data Views", reverse("dashboard_app.views.data_view_list")),
            Menu("Reports", reverse("dashboard_app.views.report_list")),
            Menu("Image Reports", reverse("dashboard_app.views.images.image_report_list")),
            Menu("Filters", reverse("dashboard_app.views.filters.views.filters_list")),
            ]
        return menu

    @property
    def front_page_template(self):
        return "dashboard_app/front_page_snippet.html"

    def get_front_page_context(self):
        from dashboard_app.models import DataReport
        return {
            'report_list': DataReport.repository.filter(front_page=True),
        }

    @property
    def description(self):
        return "Validation Dashboard"

    @property
    def version(self):
        import dashboard_app
        import versiontools
        return versiontools.format_version(dashboard_app.__version__, hint=dashboard_app)

    @property
    def api_class(self):
        from dashboard_app.xmlrpc import DashboardAPI
        return DashboardAPI

    def contribute_to_settings(self, settings_module):
        super(DashboardExtension, self).contribute_to_settings(settings_module)
        settings_module['INSTALLED_APPS'].append("linaro_django_pagination")
        settings_module['MIDDLEWARE_CLASSES'].append(
            'linaro_django_pagination.middleware.PaginationMiddleware')
        root_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
        settings_module['DATAVIEW_DIRS'] = [
            os.path.join(root_dir, 'examples', 'views'),
            os.path.join(root_dir, 'production', 'views')]
        settings_module['DATAREPORT_DIRS'] = [
            os.path.join(root_dir, 'examples', 'reports'),
            os.path.join(root_dir, 'production', 'reports')]

    def contribute_to_settings_ex(self, settings_module, settings_object):
        settings_module['DATAVIEW_DIRS'] = settings_object._settings.get(
            "DATAVIEW_DIRS", [])
        settings_module['DATAREPORT_DIRS'] = settings_object._settings.get(
            "DATAREPORT_DIRS", [])

        # Enable constrained dataview database if requested
        if settings_object._settings.get("use_dataview_database"):
            # Copy everything from the default database and append _dataview to user
            # name. The rest is out of scope (making sure it's actually setup
            # properly, having permissions to login, permissions to view proper data)
            settings_module['DATABASES']['dataview'] = dict(settings_module['DATABASES']['default'])
            settings_module['DATABASES']['dataview']['USER'] += "_dataview"
<|endoftext|>