Include API validation response into `TalonOneAPIError` details

--- talon_one/exceptions.py
+++ talon_one/exceptions.py
@@ -11,7 +11,11 @@
         # try to enhance with detailed error from API
         if len(args) > 0 and isinstance(args[0], requests.exceptions.HTTPError):
             hints = json.loads(args[0].response.text)
+
             if "errors" in hints:
                 self.message += " - %s" % hints["errors"][0]["title"]

+            if "message" in hints:
+                self.message += " - %s" % hints["message"]
+
         super(TalonOneAPIError, self).__init__(self.message, *args)

<|original_code|>
import json
import requests

class TalonOneAPIError(Exception):
    """
    TalonOne API Exceptions
    """
    def __init__(self, message, *args):
        self.message = message

        # try to enhance with detailed error from API
        if len(args) > 0 and isinstance(args[0], requests.exceptions.HTTPError):
            hints = json.loads(args[0].response.text)
            if "errors" in hints:
                self.message += " - %s" % hints["errors"][0]["title"]

        super(TalonOneAPIError, self).__init__(self.message, *args)

<|edits_diff|>
--- talon_one/exceptions.py
+++ talon_one/exceptions.py
@@ -11,6 +11,7 @@
         # try to enhance with detailed error from API
         if len(args) > 0 and isinstance(args[0], requests.exceptions.HTTPError):
             hints = json.loads(args[0].response.text)
+
             if "errors" in hints:
                 self.message += " - %s" % hints["errors"][0]["title"]

<|current_version|>
import json
import requests

class TalonOneAPIError(Exception):
    """
    TalonOne API Exceptions
    """
    def __init__(self, message, *args):
        self.message = message

        # try to enhance with detailed error from API
        if len(args) > 0 and isinstance(args[0], requests.exceptions.HTTPError):
            hints = json.loads(args[0].response.text)

            if "errors" in hints:
                self.message += " - %s" % hints["errors"][0]["title"]

        super(TalonOneAPIError, self).__init__(self.message, *args)

<|next_version|>
import json
import requests

class TalonOneAPIError(Exception):
    """
    TalonOne API Exceptions
    """
    def __init__(self, message, *args):
        self.message = message

        # try to enhance with detailed error from API
        if len(args) > 0 and isinstance(args[0], requests.exceptions.HTTPError):
            hints = json.loads(args[0].response.text)

            if "errors" in hints:
                self.message += " - %s" % hints["errors"][0]["title"]

            if "message" in hints:
                self.message += " - %s" % hints["message"]

        super(TalonOneAPIError, self).__init__(self.message, *args)


Add additional application for gunicorn.

--- app/__init__.py
+++ app/__init__.py
@@ -1,4 +1,9 @@
+import os
 from app.main import bundle_app # noqa

 # NOTE: uncomment out while genrating migration
 # app = bundle_app({'MIGRATION': True})
+
+application = bundle_app({
+    'CLI_OR_DEPLOY': True,
+    'GUNICORN': 'gunicorn' in os.environ.get('SERVER_SOFTWARE', '')})  # noqa

<|original_code|>
from app.main import bundle_app # noqa

# NOTE: uncomment out while genrating migration
# app = bundle_app({'MIGRATION': True})

<|edits_diff|>
--- app/__init__.py
+++ app/__init__.py
@@ -1,3 +1,4 @@
+import os
 from app.main import bundle_app # noqa

 # NOTE: uncomment out while genrating migration
<|current_version|>
import os
from app.main import bundle_app # noqa

# NOTE: uncomment out while genrating migration
# app = bundle_app({'MIGRATION': True})

<|next_version|>
import os
from app.main import bundle_app # noqa

# NOTE: uncomment out while genrating migration
# app = bundle_app({'MIGRATION': True})

application = bundle_app({
    'CLI_OR_DEPLOY': True,
    'GUNICORN': 'gunicorn' in os.environ.get('SERVER_SOFTWARE', '')})  # noqa


Speed up deep copy of fields

Speed up deep copy of fields

--- marshmallow/base.py
+++ marshmallow/base.py
@@ -3,6 +3,7 @@

 These are necessary to avoid circular imports between core.py and fields.py.
 '''
+import copy

 class FieldABC(object):
@@ -16,6 +17,10 @@

     def output(self, key, obj):
         raise NotImplementedError
+
+    def __deepcopy__(self, memo):
+        ret = copy.copy(self)
+        return ret

     def __repr__(self):
         return "<{0} Field>".format(self.__class__.__name__)

<|original_code|>
# -*- coding: utf-8 -*-
'''Abstract base classes.

These are necessary to avoid circular imports between core.py and fields.py.
'''

class FieldABC(object):
    '''Abstract base class from which all Field classes inherit.
    '''
    parent = None
    name = None

    def format(self, value):
        raise NotImplementedError

    def output(self, key, obj):
        raise NotImplementedError

    def __repr__(self):
        return "<{0} Field>".format(self.__class__.__name__)

    __str__ = __repr__

class SerializerABC(object):
    '''Abstract base class from which all Serializers inherit.'''

    @property
    def errors(self):
        raise NotImplementedError

    def is_valid(self, fields=None):
        raise NotImplementedError

<|edits_diff|>
--- marshmallow/base.py
+++ marshmallow/base.py
@@ -3,6 +3,7 @@

 These are necessary to avoid circular imports between core.py and fields.py.
 '''
+import copy

 class FieldABC(object):
<|current_version|>
# -*- coding: utf-8 -*-
'''Abstract base classes.

These are necessary to avoid circular imports between core.py and fields.py.
'''
import copy

class FieldABC(object):
    '''Abstract base class from which all Field classes inherit.
    '''
    parent = None
    name = None

    def format(self, value):
        raise NotImplementedError

    def output(self, key, obj):
        raise NotImplementedError

    def __repr__(self):
        return "<{0} Field>".format(self.__class__.__name__)

    __str__ = __repr__

class SerializerABC(object):
    '''Abstract base class from which all Serializers inherit.'''

    @property
    def errors(self):
        raise NotImplementedError

    def is_valid(self, fields=None):
        raise NotImplementedError

<|next_version|>
# -*- coding: utf-8 -*-
'''Abstract base classes.

These are necessary to avoid circular imports between core.py and fields.py.
'''
import copy

class FieldABC(object):
    '''Abstract base class from which all Field classes inherit.
    '''
    parent = None
    name = None

    def format(self, value):
        raise NotImplementedError

    def output(self, key, obj):
        raise NotImplementedError

    def __deepcopy__(self, memo):
        ret = copy.copy(self)
        return ret

    def __repr__(self):
        return "<{0} Field>".format(self.__class__.__name__)

    __str__ = __repr__

class SerializerABC(object):
    '''Abstract base class from which all Serializers inherit.'''

    @property
    def errors(self):
        raise NotImplementedError

    def is_valid(self, fields=None):
        raise NotImplementedError


Fix CameraDevice's send method is not called

Add send method @gen.coroutine decorator

--- gateway/camera/device.py
+++ gateway/camera/device.py
@@ -1,3 +1,5 @@
+from tornado import gen
+
 from gateway import net

@@ -8,6 +10,7 @@
         self.__stream = stream
         self.__address = address

+    @gen.coroutine
     def send(self, opcode, body=None):
         packet = net.encode_packet(opcode, body)
         yield self.__stream.write(packet)

<|original_code|>
from gateway import net

class CameraDevice(object):
    def __init__(self, stream, address):
        self.resolution = None
        self.framerate = None
        self.__stream = stream
        self.__address = address

    def send(self, opcode, body=None):
        packet = net.encode_packet(opcode, body)
        yield self.__stream.write(packet)

<|edits_diff|>
--- gateway/camera/device.py
+++ gateway/camera/device.py
@@ -1,3 +1,5 @@
+from tornado import gen
+
 from gateway import net

<|current_version|>
from tornado import gen

from gateway import net

class CameraDevice(object):
    def __init__(self, stream, address):
        self.resolution = None
        self.framerate = None
        self.__stream = stream
        self.__address = address

    def send(self, opcode, body=None):
        packet = net.encode_packet(opcode, body)
        yield self.__stream.write(packet)

<|next_version|>
from tornado import gen

from gateway import net

class CameraDevice(object):
    def __init__(self, stream, address):
        self.resolution = None
        self.framerate = None
        self.__stream = stream
        self.__address = address

    @gen.coroutine
    def send(self, opcode, body=None):
        packet = net.encode_packet(opcode, body)
        yield self.__stream.write(packet)


Allow filtering and ordering on API

Allow filtering and ordering on API

--- music/api.py
+++ music/api.py
@@ -1,6 +1,7 @@
 from django.conf.urls.defaults import url

 from tastypie.resources import ModelResource
+from tastypie.constants import ALL
 from jmbo.api import ModelBaseResource

 from music.models import Track
@@ -11,6 +12,9 @@
     class Meta:
         queryset = Track.permitted.all()
         resource_name = 'track'
+        filtering = {
+            'last_played': ALL
+        }
         ordering = ['last_played']

     def override_urls(self):

<|original_code|>
from django.conf.urls.defaults import url

from tastypie.resources import ModelResource
from jmbo.api import ModelBaseResource

from music.models import Track

class TrackResource(ModelBaseResource):

    class Meta:
        queryset = Track.permitted.all()
        resource_name = 'track'
        ordering = ['last_played']

    def override_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/(?P<slug>[\w-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
        ]

<|edits_diff|>
--- music/api.py
+++ music/api.py
@@ -1,6 +1,7 @@
 from django.conf.urls.defaults import url

 from tastypie.resources import ModelResource
+from tastypie.constants import ALL
 from jmbo.api import ModelBaseResource

 from music.models import Track
<|current_version|>
from django.conf.urls.defaults import url

from tastypie.resources import ModelResource
from tastypie.constants import ALL
from jmbo.api import ModelBaseResource

from music.models import Track

class TrackResource(ModelBaseResource):

    class Meta:
        queryset = Track.permitted.all()
        resource_name = 'track'
        ordering = ['last_played']

    def override_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/(?P<slug>[\w-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
        ]

<|next_version|>
from django.conf.urls.defaults import url

from tastypie.resources import ModelResource
from tastypie.constants import ALL
from jmbo.api import ModelBaseResource

from music.models import Track

class TrackResource(ModelBaseResource):

    class Meta:
        queryset = Track.permitted.all()
        resource_name = 'track'
        filtering = {
            'last_played': ALL
        }
        ordering = ['last_played']

    def override_urls(self):
        return [
            url(r"^(?P<resource_name>%s)/(?P<slug>[\w-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
        ]


Set timeout on pca test

Set timeout on pca test

--- test/viz/test_pca.py
+++ test/viz/test_pca.py
@@ -1,5 +1,7 @@

+import pytest

+@pytest.mark.timeout(10)
 def test_pca():
     from sequana.viz.pca import PCA
     from sequana import sequana_data

<|original_code|>

def test_pca():
    from sequana.viz.pca import PCA
    from sequana import sequana_data
    import pandas as pd

    data = sequana_data("test_pca.csv")
    df = pd.read_csv(data)
    df = df.set_index("Id")
    p = PCA(df, colors={
        "A1": 'r', "A2": 'r', 'A3': 'r',
        "B1": 'b', "B2": 'b', 'B3': 'b'})

    p.plot(n_components=2, switch_y=True)
    p.plot(n_components=2, switch_x=True)
    p.plot(n_components=3, switch_z=True)

    p.plot_pca_vs_max_features(n_components=4)
    p.plot_pca_vs_max_features(step=50000)

<|edits_diff|>
--- test/viz/test_pca.py
+++ test/viz/test_pca.py
@@ -1,4 +1,5 @@

+import pytest

 def test_pca():
     from sequana.viz.pca import PCA
<|current_version|>

import pytest

def test_pca():
    from sequana.viz.pca import PCA
    from sequana import sequana_data
    import pandas as pd

    data = sequana_data("test_pca.csv")
    df = pd.read_csv(data)
    df = df.set_index("Id")
    p = PCA(df, colors={
        "A1": 'r', "A2": 'r', 'A3': 'r',
        "B1": 'b', "B2": 'b', 'B3': 'b'})

    p.plot(n_components=2, switch_y=True)
    p.plot(n_components=2, switch_x=True)
    p.plot(n_components=3, switch_z=True)

    p.plot_pca_vs_max_features(n_components=4)
    p.plot_pca_vs_max_features(step=50000)

<|next_version|>

import pytest

@pytest.mark.timeout(10)
def test_pca():
    from sequana.viz.pca import PCA
    from sequana import sequana_data
    import pandas as pd

    data = sequana_data("test_pca.csv")
    df = pd.read_csv(data)
    df = df.set_index("Id")
    p = PCA(df, colors={
        "A1": 'r', "A2": 'r', 'A3': 'r',
        "B1": 'b', "B2": 'b', 'B3': 'b'})

    p.plot(n_components=2, switch_y=True)
    p.plot(n_components=2, switch_x=True)
    p.plot(n_components=3, switch_z=True)

    p.plot_pca_vs_max_features(n_components=4)
    p.plot_pca_vs_max_features(step=50000)


Add a test that calls exec_cmd

Add a test that calls exec_cmd

--- tests/tools_tests.py
+++ tests/tools_tests.py
@@ -5,6 +5,7 @@
 import unittest

 import ifcfg
+from ifcfg.tools import exec_cmd
 from nose.tools import eq_

@@ -15,3 +16,7 @@
         log = ifcfg.tools.minimal_logger(__name__)
         eq_(log.level, logging.DEBUG)
         os.environ['IFCFG_DEBUG'] = '0'
+
+    def test_command(self):
+        output, __, __ = exec_cmd("echo -n 'this is a test'")
+        self.assertEqual(output, "this is a test")

<|original_code|>
"""Tests for ifcfg.tools."""

import logging
import os
import unittest

import ifcfg
from nose.tools import eq_

class IfcfgToolsTestCase(unittest.TestCase):

    def test_minimal_logger(self):
        os.environ['IFCFG_DEBUG'] = '1'
        log = ifcfg.tools.minimal_logger(__name__)
        eq_(log.level, logging.DEBUG)
        os.environ['IFCFG_DEBUG'] = '0'

<|edits_diff|>
--- tests/tools_tests.py
+++ tests/tools_tests.py
@@ -5,6 +5,7 @@
 import unittest

 import ifcfg
+from ifcfg.tools import exec_cmd
 from nose.tools import eq_

<|current_version|>
"""Tests for ifcfg.tools."""

import logging
import os
import unittest

import ifcfg
from ifcfg.tools import exec_cmd
from nose.tools import eq_

class IfcfgToolsTestCase(unittest.TestCase):

    def test_minimal_logger(self):
        os.environ['IFCFG_DEBUG'] = '1'
        log = ifcfg.tools.minimal_logger(__name__)
        eq_(log.level, logging.DEBUG)
        os.environ['IFCFG_DEBUG'] = '0'

<|next_version|>
"""Tests for ifcfg.tools."""

import logging
import os
import unittest

import ifcfg
from ifcfg.tools import exec_cmd
from nose.tools import eq_

class IfcfgToolsTestCase(unittest.TestCase):

    def test_minimal_logger(self):
        os.environ['IFCFG_DEBUG'] = '1'
        log = ifcfg.tools.minimal_logger(__name__)
        eq_(log.level, logging.DEBUG)
        os.environ['IFCFG_DEBUG'] = '0'

    def test_command(self):
        output, __, __ = exec_cmd("echo -n 'this is a test'")
        self.assertEqual(output, "this is a test")


Add alternative warning if sqlite is >=3.19 but is missing fts5 support

--- wagtail/search/apps.py
+++ wagtail/search/apps.py
@@ -29,6 +29,11 @@
     def check_if_sqlite_version_is_supported(app_configs, **kwargs):
         if connection.vendor == 'sqlite':
             import sqlite3
+
+            from wagtail.search.backends.database.sqlite.utils import fts5_available
+
             if sqlite3.sqlite_version_info < (3, 19, 0):
                 return [Warning('Your SQLite version is older than 3.19.0. A fallback search backend will be used instead.', hint='Upgrade your SQLite version to at least 3.19.0', id='wagtailsearch.W002', obj=WagtailSearchAppConfig)]
+            elif not fts5_available():
+                return [Warning('Your SQLite installation is missing the fts5 extension. A fallback search backend will be used instead.', hint='Upgrade your SQLite installation to a version with fts5 enabled', id='wagtailsearch.W003', obj=WagtailSearchAppConfig)]
         return []

<|original_code|>
from django.apps import AppConfig
from django.core.checks import Tags, Warning, register
from django.db import connection
from django.utils.translation import gettext_lazy as _

from wagtail.search.signal_handlers import register_signal_handlers

from . import checks  # NOQA

class WagtailSearchAppConfig(AppConfig):
    name = 'wagtail.search'
    label = 'wagtailsearch'
    verbose_name = _("Wagtail search")
    default_auto_field = 'django.db.models.AutoField'

    def ready(self):
        register_signal_handlers()

        if connection.vendor == 'postgresql':
            # Only PostgreSQL has support for tsvector weights
            from wagtail.search.backends.database.postgres.weights import set_weights
            set_weights()

        from wagtail.search.models import IndexEntry
        IndexEntry.add_generic_relations()

    @register(Tags.compatibility, Tags.database)
    def check_if_sqlite_version_is_supported(app_configs, **kwargs):
        if connection.vendor == 'sqlite':
            import sqlite3
            if sqlite3.sqlite_version_info < (3, 19, 0):
                return [Warning('Your SQLite version is older than 3.19.0. A fallback search backend will be used instead.', hint='Upgrade your SQLite version to at least 3.19.0', id='wagtailsearch.W002', obj=WagtailSearchAppConfig)]
        return []

<|edits_diff|>
--- wagtail/search/apps.py
+++ wagtail/search/apps.py
@@ -29,6 +29,9 @@
     def check_if_sqlite_version_is_supported(app_configs, **kwargs):
         if connection.vendor == 'sqlite':
             import sqlite3
+
+            from wagtail.search.backends.database.sqlite.utils import fts5_available
+
             if sqlite3.sqlite_version_info < (3, 19, 0):
                 return [Warning('Your SQLite version is older than 3.19.0. A fallback search backend will be used instead.', hint='Upgrade your SQLite version to at least 3.19.0', id='wagtailsearch.W002', obj=WagtailSearchAppConfig)]
         return []
<|current_version|>
from django.apps import AppConfig
from django.core.checks import Tags, Warning, register
from django.db import connection
from django.utils.translation import gettext_lazy as _

from wagtail.search.signal_handlers import register_signal_handlers

from . import checks  # NOQA

class WagtailSearchAppConfig(AppConfig):
    name = 'wagtail.search'
    label = 'wagtailsearch'
    verbose_name = _("Wagtail search")
    default_auto_field = 'django.db.models.AutoField'

    def ready(self):
        register_signal_handlers()

        if connection.vendor == 'postgresql':
            # Only PostgreSQL has support for tsvector weights
            from wagtail.search.backends.database.postgres.weights import set_weights
            set_weights()

        from wagtail.search.models import IndexEntry
        IndexEntry.add_generic_relations()

    @register(Tags.compatibility, Tags.database)
    def check_if_sqlite_version_is_supported(app_configs, **kwargs):
        if connection.vendor == 'sqlite':
            import sqlite3

            from wagtail.search.backends.database.sqlite.utils import fts5_available

            if sqlite3.sqlite_version_info < (3, 19, 0):
                return [Warning('Your SQLite version is older than 3.19.0. A fallback search backend will be used instead.', hint='Upgrade your SQLite version to at least 3.19.0', id='wagtailsearch.W002', obj=WagtailSearchAppConfig)]
        return []

<|next_version|>
from django.apps import AppConfig
from django.core.checks import Tags, Warning, register
from django.db import connection
from django.utils.translation import gettext_lazy as _

from wagtail.search.signal_handlers import register_signal_handlers

from . import checks  # NOQA

class WagtailSearchAppConfig(AppConfig):
    name = 'wagtail.search'
    label = 'wagtailsearch'
    verbose_name = _("Wagtail search")
    default_auto_field = 'django.db.models.AutoField'

    def ready(self):
        register_signal_handlers()

        if connection.vendor == 'postgresql':
            # Only PostgreSQL has support for tsvector weights
            from wagtail.search.backends.database.postgres.weights import set_weights
            set_weights()

        from wagtail.search.models import IndexEntry
        IndexEntry.add_generic_relations()

    @register(Tags.compatibility, Tags.database)
    def check_if_sqlite_version_is_supported(app_configs, **kwargs):
        if connection.vendor == 'sqlite':
            import sqlite3

            from wagtail.search.backends.database.sqlite.utils import fts5_available

            if sqlite3.sqlite_version_info < (3, 19, 0):
                return [Warning('Your SQLite version is older than 3.19.0. A fallback search backend will be used instead.', hint='Upgrade your SQLite version to at least 3.19.0', id='wagtailsearch.W002', obj=WagtailSearchAppConfig)]
            elif not fts5_available():
                return [Warning('Your SQLite installation is missing the fts5 extension. A fallback search backend will be used instead.', hint='Upgrade your SQLite installation to a version with fts5 enabled', id='wagtailsearch.W003', obj=WagtailSearchAppConfig)]
        return []


Set googleapiclient logging level to WARNING.

--- modules/google-earth-engine/docker/sepal-ee/sepal/drive/__init__.py
+++ modules/google-earth-engine/docker/sepal-ee/sepal/drive/__init__.py
@@ -1,8 +1,10 @@
+import logging
 from threading import local

 from apiclient import discovery

 _local = local()
+logging.getLogger('googleapiclient').setLevel(logging.WARNING)

 def get_service(credentials):

<|original_code|>
from threading import local

from apiclient import discovery

_local = local()

def get_service(credentials):
    service = getattr(_local, 'service', None)
    if not service:
        service = discovery.build(serviceName='drive', version='v3', cache_discovery=False, credentials=credentials)
        _local.service = service
    return service

def is_folder(file):
    return file['mimeType'] == 'application/vnd.google-apps.folder'

<|edits_diff|>
--- modules/google-earth-engine/docker/sepal-ee/sepal/drive/__init__.py
+++ modules/google-earth-engine/docker/sepal-ee/sepal/drive/__init__.py
@@ -1,3 +1,4 @@
+import logging
 from threading import local

 from apiclient import discovery
<|current_version|>
import logging
from threading import local

from apiclient import discovery

_local = local()

def get_service(credentials):
    service = getattr(_local, 'service', None)
    if not service:
        service = discovery.build(serviceName='drive', version='v3', cache_discovery=False, credentials=credentials)
        _local.service = service
    return service

def is_folder(file):
    return file['mimeType'] == 'application/vnd.google-apps.folder'

<|next_version|>
import logging
from threading import local

from apiclient import discovery

_local = local()
logging.getLogger('googleapiclient').setLevel(logging.WARNING)

def get_service(credentials):
    service = getattr(_local, 'service', None)
    if not service:
        service = discovery.build(serviceName='drive', version='v3', cache_discovery=False, credentials=credentials)
        _local.service = service
    return service

def is_folder(file):
    return file['mimeType'] == 'application/vnd.google-apps.folder'


Add ability to control read rate

Add ability to control read rate

--- app/sense.py
+++ app/sense.py
@@ -4,9 +4,11 @@
 from KeyDispatcher import KeyDispatcher
 from Display import Display
 from DataLogger import SQLiteLogger
+import time

 DEVICE = "PiSense"
+DELAY = 0.0

 class Handler:
@@ -47,3 +49,4 @@
                 break
         else:
             handler.read()
+            time.sleep(DELAY)

<|original_code|>
#!/usr/bin/env python3

from Sensor import SenseController
from KeyDispatcher import KeyDispatcher
from Display import Display
from DataLogger import SQLiteLogger

DEVICE = "PiSense"

class Handler:
    def __init__(self, display, logger, sensor):
        self.display = display
        self.logger = logger
        self.sensor = sensor
        self.logger.log(DEVICE, "running", 1)

    def read(self):
        values = {}

        for reading in self.sensor.get_data():
            values[reading[1]] = reading[2]
            self.logger.log(DEVICE, reading[1], reading[2], reading[0])

        display.show_properties(values, self.sensor.get_properties())
        return True

    def quit(self):
        self.logger.log(DEVICE, "running", 0)
        return False

with SenseController() as sensor, KeyDispatcher() as dispatcher, SQLiteLogger() as logger:
    # setup display
    display = Display("PiSense")

    # setup key handlers
    handler = Handler(display, logger, sensor)

    dispatcher.add("q", handler, "quit")

    # start processing key presses
    while True:
        if dispatcher.can_process_key():
            if not dispatcher.process_key():
                break
        else:
            handler.read()

<|edits_diff|>
--- app/sense.py
+++ app/sense.py
@@ -4,9 +4,11 @@
 from KeyDispatcher import KeyDispatcher
 from Display import Display
 from DataLogger import SQLiteLogger
+import time

 DEVICE = "PiSense"
+DELAY = 0.0

 class Handler:
<|current_version|>
#!/usr/bin/env python3

from Sensor import SenseController
from KeyDispatcher import KeyDispatcher
from Display import Display
from DataLogger import SQLiteLogger
import time

DEVICE = "PiSense"
DELAY = 0.0

class Handler:
    def __init__(self, display, logger, sensor):
        self.display = display
        self.logger = logger
        self.sensor = sensor
        self.logger.log(DEVICE, "running", 1)

    def read(self):
        values = {}

        for reading in self.sensor.get_data():
            values[reading[1]] = reading[2]
            self.logger.log(DEVICE, reading[1], reading[2], reading[0])

        display.show_properties(values, self.sensor.get_properties())
        return True

    def quit(self):
        self.logger.log(DEVICE, "running", 0)
        return False

with SenseController() as sensor, KeyDispatcher() as dispatcher, SQLiteLogger() as logger:
    # setup display
    display = Display("PiSense")

    # setup key handlers
    handler = Handler(display, logger, sensor)

    dispatcher.add("q", handler, "quit")

    # start processing key presses
    while True:
        if dispatcher.can_process_key():
            if not dispatcher.process_key():
                break
        else:
            handler.read()

<|next_version|>
#!/usr/bin/env python3

from Sensor import SenseController
from KeyDispatcher import KeyDispatcher
from Display import Display
from DataLogger import SQLiteLogger
import time

DEVICE = "PiSense"
DELAY = 0.0

class Handler:
    def __init__(self, display, logger, sensor):
        self.display = display
        self.logger = logger
        self.sensor = sensor
        self.logger.log(DEVICE, "running", 1)

    def read(self):
        values = {}

        for reading in self.sensor.get_data():
            values[reading[1]] = reading[2]
            self.logger.log(DEVICE, reading[1], reading[2], reading[0])

        display.show_properties(values, self.sensor.get_properties())
        return True

    def quit(self):
        self.logger.log(DEVICE, "running", 0)
        return False

with SenseController() as sensor, KeyDispatcher() as dispatcher, SQLiteLogger() as logger:
    # setup display
    display = Display("PiSense")

    # setup key handlers
    handler = Handler(display, logger, sensor)

    dispatcher.add("q", handler, "quit")

    # start processing key presses
    while True:
        if dispatcher.can_process_key():
            if not dispatcher.process_key():
                break
        else:
            handler.read()
            time.sleep(DELAY)


Add people and other fields to page update options

--- wafer/pages/serializers.py
+++ wafer/pages/serializers.py
@@ -1,3 +1,5 @@
+from django.contrib.auth import get_user_model
+
 from rest_framework import serializers
 from reversion import revisions

@@ -5,6 +7,10 @@

 class PageSerializer(serializers.ModelSerializer):
+
+    people = serializers.PrimaryKeyRelatedField(
+        many=True, allow_null=True,
+        queryset=get_user_model().objects.all())

     class Meta:
         model = Page
@@ -20,5 +26,8 @@
         revisions.set_comment("Changed via REST api")
         page.parent = validated_data['parent']
         page.content = validated_data['content']
+        page.include_in_menu = validated_data['include_in_menu']
+        page.exclude_from_static = validated_data['exclude_from_static']
+        page.people = validated_data.get('people')
         page.save()
         return page

<|original_code|>
from rest_framework import serializers
from reversion import revisions

from wafer.pages.models import Page

class PageSerializer(serializers.ModelSerializer):

    class Meta:
        model = Page
        exclude = ('_content_rendered',)

    @revisions.create_revision()
    def create(self, validated_data):
        revisions.set_comment("Created via REST api")
        return super(PageSerializer, self).create(validated_data)

    @revisions.create_revision()
    def update(self, page, validated_data):
        revisions.set_comment("Changed via REST api")
        page.parent = validated_data['parent']
        page.content = validated_data['content']
        page.save()
        return page

<|edits_diff|>
--- wafer/pages/serializers.py
+++ wafer/pages/serializers.py
@@ -1,3 +1,5 @@
+from django.contrib.auth import get_user_model
+
 from rest_framework import serializers
 from reversion import revisions

@@ -5,6 +7,10 @@

 class PageSerializer(serializers.ModelSerializer):
+
+    people = serializers.PrimaryKeyRelatedField(
+        many=True, allow_null=True,
+        queryset=get_user_model().objects.all())

     class Meta:
         model = Page
<|current_version|>
from django.contrib.auth import get_user_model

from rest_framework import serializers
from reversion import revisions

from wafer.pages.models import Page

class PageSerializer(serializers.ModelSerializer):

    people = serializers.PrimaryKeyRelatedField(
        many=True, allow_null=True,
        queryset=get_user_model().objects.all())

    class Meta:
        model = Page
        exclude = ('_content_rendered',)

    @revisions.create_revision()
    def create(self, validated_data):
        revisions.set_comment("Created via REST api")
        return super(PageSerializer, self).create(validated_data)

    @revisions.create_revision()
    def update(self, page, validated_data):
        revisions.set_comment("Changed via REST api")
        page.parent = validated_data['parent']
        page.content = validated_data['content']
        page.save()
        return page

<|next_version|>
from django.contrib.auth import get_user_model

from rest_framework import serializers
from reversion import revisions

from wafer.pages.models import Page

class PageSerializer(serializers.ModelSerializer):

    people = serializers.PrimaryKeyRelatedField(
        many=True, allow_null=True,
        queryset=get_user_model().objects.all())

    class Meta:
        model = Page
        exclude = ('_content_rendered',)

    @revisions.create_revision()
    def create(self, validated_data):
        revisions.set_comment("Created via REST api")
        return super(PageSerializer, self).create(validated_data)

    @revisions.create_revision()
    def update(self, page, validated_data):
        revisions.set_comment("Changed via REST api")
        page.parent = validated_data['parent']
        page.content = validated_data['content']
        page.include_in_menu = validated_data['include_in_menu']
        page.exclude_from_static = validated_data['exclude_from_static']
        page.people = validated_data.get('people')
        page.save()
        return page


Add some sleep in tests to not exceed allowed request limits

--- test_base.py
+++ test_base.py
@@ -1,5 +1,6 @@
 import pytest
 from pynoaa import PyNOAA
+from time import sleep

 noaa = PyNOAA("KEQrNcMDIrZMyWtDslGKEkgETXbgIvjZ")
 @pytest.mark.parametrize('startdate,locationid',(
@@ -11,6 +12,7 @@
     results = datasets["results"]
     assert datasets["metadata"]["resultset"]["limit"] == 1
     assert results[0]["id"] == "GHCND"
+    sleep(0.2)

 @pytest.mark.parametrize('fun,id',(
     ['datasets','NEXRAD2',],
@@ -23,3 +25,4 @@
 def test_id(fun, id):
     results = getattr(noaa, fun)(id=id)
     assert results["id"] == id
+    sleep(0.2)

<|original_code|>
import pytest
from pynoaa import PyNOAA

noaa = PyNOAA("KEQrNcMDIrZMyWtDslGKEkgETXbgIvjZ")
@pytest.mark.parametrize('startdate,locationid',(
    ['1994-05-20',None],
    [None,['FIPS:36','FIPS:37']],
))
def test_datasets(startdate, locationid):
    datasets = noaa.datasets(limit = 1, startdate = startdate, locationid = locationid)
    results = datasets["results"]
    assert datasets["metadata"]["resultset"]["limit"] == 1
    assert results[0]["id"] == "GHCND"

@pytest.mark.parametrize('fun,id',(
    ['datasets','NEXRAD2',],
    ['datacategories','ANNPRCP',],
    ['datatypes','ANN-DUTR-NORMAL',],
    ['locationcategories','CNTRY',],
    ['locations','CITY:AG000007',],
    ['stations','COOP:010148',],
))
def test_id(fun, id):
    results = getattr(noaa, fun)(id=id)
    assert results["id"] == id
<|edits_diff|>
--- test_base.py
+++ test_base.py
@@ -1,5 +1,6 @@
 import pytest
 from pynoaa import PyNOAA
+from time import sleep

 noaa = PyNOAA("KEQrNcMDIrZMyWtDslGKEkgETXbgIvjZ")
 @pytest.mark.parametrize('startdate,locationid',(
@@ -23,3 +24,4 @@
 def test_id(fun, id):
     results = getattr(noaa, fun)(id=id)
     assert results["id"] == id
+    sleep(0.2)
<|current_version|>
import pytest
from pynoaa import PyNOAA
from time import sleep

noaa = PyNOAA("KEQrNcMDIrZMyWtDslGKEkgETXbgIvjZ")
@pytest.mark.parametrize('startdate,locationid',(
    ['1994-05-20',None],
    [None,['FIPS:36','FIPS:37']],
))
def test_datasets(startdate, locationid):
    datasets = noaa.datasets(limit = 1, startdate = startdate, locationid = locationid)
    results = datasets["results"]
    assert datasets["metadata"]["resultset"]["limit"] == 1
    assert results[0]["id"] == "GHCND"

@pytest.mark.parametrize('fun,id',(
    ['datasets','NEXRAD2',],
    ['datacategories','ANNPRCP',],
    ['datatypes','ANN-DUTR-NORMAL',],
    ['locationcategories','CNTRY',],
    ['locations','CITY:AG000007',],
    ['stations','COOP:010148',],
))
def test_id(fun, id):
    results = getattr(noaa, fun)(id=id)
    assert results["id"] == id
    sleep(0.2)

<|next_version|>
import pytest
from pynoaa import PyNOAA
from time import sleep

noaa = PyNOAA("KEQrNcMDIrZMyWtDslGKEkgETXbgIvjZ")
@pytest.mark.parametrize('startdate,locationid',(
    ['1994-05-20',None],
    [None,['FIPS:36','FIPS:37']],
))
def test_datasets(startdate, locationid):
    datasets = noaa.datasets(limit = 1, startdate = startdate, locationid = locationid)
    results = datasets["results"]
    assert datasets["metadata"]["resultset"]["limit"] == 1
    assert results[0]["id"] == "GHCND"
    sleep(0.2)

@pytest.mark.parametrize('fun,id',(
    ['datasets','NEXRAD2',],
    ['datacategories','ANNPRCP',],
    ['datatypes','ANN-DUTR-NORMAL',],
    ['locationcategories','CNTRY',],
    ['locations','CITY:AG000007',],
    ['stations','COOP:010148',],
))
def test_id(fun, id):
    results = getattr(noaa, fun)(id=id)
    assert results["id"] == id
    sleep(0.2)


Add name and promotion to Card.

Add name and promotion to Card.

--- matches/models.py
+++ matches/models.py
@@ -1,6 +1,7 @@
 from django.contrib.auth.models import User
 from django.db import models

+from promotions.models import Promotion
 from wrestlers.models import WrestlingEntity

@@ -16,6 +17,9 @@
 class Card(models.Model):

     date = models.DateField()
+    promotion = models.ForeignKey(Promotion)
+
+    name = models.CharField(max_length=127, null=True, blank=True)

     def __unicode__(self):
         return unicode(self.date)

<|original_code|>
from django.contrib.auth.models import User
from django.db import models

from wrestlers.models import WrestlingEntity

class Review(models.Model):

    reviewed_by = models.ForeignKey(User)
    reviewed_at = models.DateTimeField()

    class Meta:
        abstract = True

class Card(models.Model):

    date = models.DateField()

    def __unicode__(self):
        return unicode(self.date)

class Match(Review):

    card = models.ForeignKey(Card)
    participants = models.ManyToManyField(WrestlingEntity)
    winner = models.ForeignKey(WrestlingEntity, related_name="won_matches",
                               null=True, blank=True)

    def __unicode__(self):
        return " vs. ".join([p.name for p in self.participants.all()])

<|edits_diff|>
--- matches/models.py
+++ matches/models.py
@@ -1,6 +1,7 @@
 from django.contrib.auth.models import User
 from django.db import models

+from promotions.models import Promotion
 from wrestlers.models import WrestlingEntity

<|current_version|>
from django.contrib.auth.models import User
from django.db import models

from promotions.models import Promotion
from wrestlers.models import WrestlingEntity

class Review(models.Model):

    reviewed_by = models.ForeignKey(User)
    reviewed_at = models.DateTimeField()

    class Meta:
        abstract = True

class Card(models.Model):

    date = models.DateField()

    def __unicode__(self):
        return unicode(self.date)

class Match(Review):

    card = models.ForeignKey(Card)
    participants = models.ManyToManyField(WrestlingEntity)
    winner = models.ForeignKey(WrestlingEntity, related_name="won_matches",
                               null=True, blank=True)

    def __unicode__(self):
        return " vs. ".join([p.name for p in self.participants.all()])

<|next_version|>
from django.contrib.auth.models import User
from django.db import models

from promotions.models import Promotion
from wrestlers.models import WrestlingEntity

class Review(models.Model):

    reviewed_by = models.ForeignKey(User)
    reviewed_at = models.DateTimeField()

    class Meta:
        abstract = True

class Card(models.Model):

    date = models.DateField()
    promotion = models.ForeignKey(Promotion)

    name = models.CharField(max_length=127, null=True, blank=True)

    def __unicode__(self):
        return unicode(self.date)

class Match(Review):

    card = models.ForeignKey(Card)
    participants = models.ManyToManyField(WrestlingEntity)
    winner = models.ForeignKey(WrestlingEntity, related_name="won_matches",
                               null=True, blank=True)

    def __unicode__(self):
        return " vs. ".join([p.name for p in self.participants.all()])


Set up the proposal tasks on app startup

--- server/proposal/__init__.py
+++ server/proposal/__init__.py
@@ -1,4 +1,5 @@
 from django.apps import AppConfig
+

 class ProposalConfig(AppConfig):
     name = "proposal"
@@ -6,3 +7,4 @@
     def ready(self):
         # Register tasks with Celery:
         from . import tasks
+        tasks.set_up_hooks()

<|original_code|>
from django.apps import AppConfig

class ProposalConfig(AppConfig):
    name = "proposal"

    def ready(self):
        # Register tasks with Celery:
        from . import tasks

<|edits_diff|>
--- server/proposal/__init__.py
+++ server/proposal/__init__.py
@@ -1,4 +1,5 @@
 from django.apps import AppConfig
+

 class ProposalConfig(AppConfig):
     name = "proposal"
<|current_version|>
from django.apps import AppConfig

class ProposalConfig(AppConfig):
    name = "proposal"

    def ready(self):
        # Register tasks with Celery:
        from . import tasks

<|next_version|>
from django.apps import AppConfig

class ProposalConfig(AppConfig):
    name = "proposal"

    def ready(self):
        # Register tasks with Celery:
        from . import tasks
        tasks.set_up_hooks()


Add a User post_save hook for creating user profiles

--- src-django/authentication/signals/user_post_save.py
+++ src-django/authentication/signals/user_post_save.py
@@ -1,3 +1,4 @@
+from authentication.models import UserProfile
 from django.contrib.auth.models import User, Group
 from django.dispatch import receiver
 from django.db.models.signals import post_save
@@ -16,6 +17,9 @@
     # user registration endpoint can return a token back to Ember
     # (thus avoiding the need to hit login endpoint)
     if created:
+        user_profile = UserProfile.objects.create(user=instance, is_email_confirmed=False)
+        user_profile.save()
+
         Token.objects.create(user=instance)

     # Add new user to the proper user group

<|original_code|>
from django.contrib.auth.models import User, Group
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from rest_framework.authtoken.models import Token

@receiver(post_save, sender=User)
def on_user_post_save(sender, instance=None, created=False, **kwargs):
    # Normally, users automatically get a Token created for them (if they do not
    # already have one) when they hit
    #
    #   rest_framework.authtoken.views.obtain_auth_token view
    #
    # This will create an authentication token for newly created users so the
    # user registration endpoint can return a token back to Ember
    # (thus avoiding the need to hit login endpoint)
    if created:
        Token.objects.create(user=instance)

    # Add new user to the proper user group
    normal_users_group, created = Group.objects.get_or_create(name=settings.NORMAL_USER_GROUP)
    instance.groups.add(normal_users_group)

<|edits_diff|>
--- src-django/authentication/signals/user_post_save.py
+++ src-django/authentication/signals/user_post_save.py
@@ -1,3 +1,4 @@
+from authentication.models import UserProfile
 from django.contrib.auth.models import User, Group
 from django.dispatch import receiver
 from django.db.models.signals import post_save
<|current_version|>
from authentication.models import UserProfile
from django.contrib.auth.models import User, Group
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from rest_framework.authtoken.models import Token

@receiver(post_save, sender=User)
def on_user_post_save(sender, instance=None, created=False, **kwargs):
    # Normally, users automatically get a Token created for them (if they do not
    # already have one) when they hit
    #
    #   rest_framework.authtoken.views.obtain_auth_token view
    #
    # This will create an authentication token for newly created users so the
    # user registration endpoint can return a token back to Ember
    # (thus avoiding the need to hit login endpoint)
    if created:
        Token.objects.create(user=instance)

    # Add new user to the proper user group
    normal_users_group, created = Group.objects.get_or_create(name=settings.NORMAL_USER_GROUP)
    instance.groups.add(normal_users_group)

<|next_version|>
from authentication.models import UserProfile
from django.contrib.auth.models import User, Group
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from rest_framework.authtoken.models import Token

@receiver(post_save, sender=User)
def on_user_post_save(sender, instance=None, created=False, **kwargs):
    # Normally, users automatically get a Token created for them (if they do not
    # already have one) when they hit
    #
    #   rest_framework.authtoken.views.obtain_auth_token view
    #
    # This will create an authentication token for newly created users so the
    # user registration endpoint can return a token back to Ember
    # (thus avoiding the need to hit login endpoint)
    if created:
        user_profile = UserProfile.objects.create(user=instance, is_email_confirmed=False)
        user_profile.save()

        Token.objects.create(user=instance)

    # Add new user to the proper user group
    normal_users_group, created = Group.objects.get_or_create(name=settings.NORMAL_USER_GROUP)
    instance.groups.add(normal_users_group)


Add some simple optimizations into the mesh reader classes.

This yields a ~1.5% performance improvement.

--- pyfr/readers/base.py
+++ pyfr/readers/base.py
@@ -1,8 +1,12 @@
 # -*- coding: utf-8 -*-

+import re
 import uuid
+import itertools as it

 from abc import ABCMeta, abstractmethod
+
+import numpy as np

 class BaseReader(object):
@@ -16,8 +20,16 @@
     def _to_raw_pyfrm(self):
         pass

+    def _optimize(self, mesh):
+        # Sort interior interfaces
+        for f in it.ifilter(lambda f: re.match('con_p\d+', f), mesh):
+            mesh[f] = mesh[f][:,np.argsort(mesh[f][0])]
+
     def to_pyfrm(self):
         mesh = self._to_raw_pyfrm()
+
+        # Perform some simple optimizations on the mesh
+        self._optimize(mesh)

         # Add metadata
         mesh['mesh_uuid'] = str(uuid.uuid4())

<|original_code|>
# -*- coding: utf-8 -*-

import uuid

from abc import ABCMeta, abstractmethod

class BaseReader(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def __init__(self):
        pass

    @abstractmethod
    def _to_raw_pyfrm(self):
        pass

    def to_pyfrm(self):
        mesh = self._to_raw_pyfrm()

        # Add metadata
        mesh['mesh_uuid'] = str(uuid.uuid4())

        return mesh

<|edits_diff|>
--- pyfr/readers/base.py
+++ pyfr/readers/base.py
@@ -1,8 +1,12 @@
 # -*- coding: utf-8 -*-

+import re
 import uuid
+import itertools as it

 from abc import ABCMeta, abstractmethod
+
+import numpy as np

 class BaseReader(object):
@@ -16,6 +20,11 @@
     def _to_raw_pyfrm(self):
         pass

+    def _optimize(self, mesh):
+        # Sort interior interfaces
+        for f in it.ifilter(lambda f: re.match('con_p\d+', f), mesh):
+            mesh[f] = mesh[f][:,np.argsort(mesh[f][0])]
+
     def to_pyfrm(self):
         mesh = self._to_raw_pyfrm()

<|current_version|>
# -*- coding: utf-8 -*-

import re
import uuid
import itertools as it

from abc import ABCMeta, abstractmethod

import numpy as np

class BaseReader(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def __init__(self):
        pass

    @abstractmethod
    def _to_raw_pyfrm(self):
        pass

    def _optimize(self, mesh):
        # Sort interior interfaces
        for f in it.ifilter(lambda f: re.match('con_p\d+', f), mesh):
            mesh[f] = mesh[f][:,np.argsort(mesh[f][0])]

    def to_pyfrm(self):
        mesh = self._to_raw_pyfrm()

        # Add metadata
        mesh['mesh_uuid'] = str(uuid.uuid4())

        return mesh

<|next_version|>
# -*- coding: utf-8 -*-

import re
import uuid
import itertools as it

from abc import ABCMeta, abstractmethod

import numpy as np

class BaseReader(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def __init__(self):
        pass

    @abstractmethod
    def _to_raw_pyfrm(self):
        pass

    def _optimize(self, mesh):
        # Sort interior interfaces
        for f in it.ifilter(lambda f: re.match('con_p\d+', f), mesh):
            mesh[f] = mesh[f][:,np.argsort(mesh[f][0])]

    def to_pyfrm(self):
        mesh = self._to_raw_pyfrm()

        # Perform some simple optimizations on the mesh
        self._optimize(mesh)

        # Add metadata
        mesh['mesh_uuid'] = str(uuid.uuid4())

        return mesh


Add body_href method for getting a public url for a Style's body.

--- src/geoserver/style.py
+++ src/geoserver/style.py
@@ -1,4 +1,5 @@
 from geoserver.support import ResourceInfo, atom_link
+import re

 class Style(ResourceInfo):
   def __init__(self,catalog, node):
@@ -23,5 +24,9 @@
     self.sld_name = name_node.text if hasattr(name_node, 'text') else None
     self.sld_title = title_node.text if hasattr(title_node, 'text') else None

+  def body_href(self):
+      style_container = re.sub(r"/rest$", "/styles", self.catalog.service_url)
+      return "%s/%s" % (style_container, self.filename)
+
   def __repr__(self):
     return "Style[%s]" % self.name

<|original_code|>
from geoserver.support import ResourceInfo, atom_link

class Style(ResourceInfo):
  def __init__(self,catalog, node):
    self.catalog = catalog
    self.name = node.find("name").text
    self.href = atom_link(node)
    self.update()

  def update(self):
    ResourceInfo.update(self)
    self.name = self.metadata.find("name").text
    self.filename = self.metadata.find("filename").text
    # Get the raw sld
    sld_url = self.href.replace(".xml", ".sld")
    sld_xml = self.catalog.get_xml(sld_url)
    # Obtain the user style node where title and name are located
    user_style = sld_xml.find("{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle")
    # Extract name and title nodes from user_style
    name_node = user_style.find("{http://www.opengis.net/sld}Name")
    title_node = user_style.find("{http://www.opengis.net/sld}Title")
    # Store the text value of sld name and title if present
    self.sld_name = name_node.text if hasattr(name_node, 'text') else None
    self.sld_title = title_node.text if hasattr(title_node, 'text') else None

  def __repr__(self):
    return "Style[%s]" % self.name

<|edits_diff|>
--- src/geoserver/style.py
+++ src/geoserver/style.py
@@ -1,4 +1,5 @@
 from geoserver.support import ResourceInfo, atom_link
+import re

 class Style(ResourceInfo):
   def __init__(self,catalog, node):
<|current_version|>
from geoserver.support import ResourceInfo, atom_link
import re

class Style(ResourceInfo):
  def __init__(self,catalog, node):
    self.catalog = catalog
    self.name = node.find("name").text
    self.href = atom_link(node)
    self.update()

  def update(self):
    ResourceInfo.update(self)
    self.name = self.metadata.find("name").text
    self.filename = self.metadata.find("filename").text
    # Get the raw sld
    sld_url = self.href.replace(".xml", ".sld")
    sld_xml = self.catalog.get_xml(sld_url)
    # Obtain the user style node where title and name are located
    user_style = sld_xml.find("{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle")
    # Extract name and title nodes from user_style
    name_node = user_style.find("{http://www.opengis.net/sld}Name")
    title_node = user_style.find("{http://www.opengis.net/sld}Title")
    # Store the text value of sld name and title if present
    self.sld_name = name_node.text if hasattr(name_node, 'text') else None
    self.sld_title = title_node.text if hasattr(title_node, 'text') else None

  def __repr__(self):
    return "Style[%s]" % self.name

<|next_version|>
from geoserver.support import ResourceInfo, atom_link
import re

class Style(ResourceInfo):
  def __init__(self,catalog, node):
    self.catalog = catalog
    self.name = node.find("name").text
    self.href = atom_link(node)
    self.update()

  def update(self):
    ResourceInfo.update(self)
    self.name = self.metadata.find("name").text
    self.filename = self.metadata.find("filename").text
    # Get the raw sld
    sld_url = self.href.replace(".xml", ".sld")
    sld_xml = self.catalog.get_xml(sld_url)
    # Obtain the user style node where title and name are located
    user_style = sld_xml.find("{http://www.opengis.net/sld}NamedLayer/{http://www.opengis.net/sld}UserStyle")
    # Extract name and title nodes from user_style
    name_node = user_style.find("{http://www.opengis.net/sld}Name")
    title_node = user_style.find("{http://www.opengis.net/sld}Title")
    # Store the text value of sld name and title if present
    self.sld_name = name_node.text if hasattr(name_node, 'text') else None
    self.sld_title = title_node.text if hasattr(title_node, 'text') else None

  def body_href(self):
      style_container = re.sub(r"/rest$", "/styles", self.catalog.service_url)
      return "%s/%s" % (style_container, self.filename)

  def __repr__(self):
    return "Style[%s]" % self.name


Add updating of jobs if their state is now unknown

--- cluster/update_jobs.py
+++ cluster/update_jobs.py
@@ -10,13 +10,19 @@
         for i, cluster in enumerate(get_all_jobs(user)):
             cred = creds[i]
             jobs = {}
+            jobids = []
             for job in cluster["jobs"]:
                 status = job[-1]
                 job_id = job[0]
+                jobids.append(job_id)
                 if status in jobs:
                     jobs[status].append(job_id)
                 else:
                     jobs[status] = [job_id]
+            running = Job.get_running_jobs(credential=cred)
+            unknown = running.exclude(jobid__in=set(jobids)).values_list('jobid', flat=True)
+            if unknown:
+                jobs[Job.UNKNOWN] = list(unknown)
             Job.update_states(cred, jobs)

<|original_code|>
from django.contrib.auth.models import User

from models import Job
from interface import get_all_jobs

def run_all():
    for user in User.objects.all():
        creds = user.credentials.all()
        for i, cluster in enumerate(get_all_jobs(user)):
            cred = creds[i]
            jobs = {}
            for job in cluster["jobs"]:
                status = job[-1]
                job_id = job[0]
                if status in jobs:
                    jobs[status].append(job_id)
                else:
                    jobs[status] = [job_id]
            Job.update_states(cred, jobs)

if __name__ == "__main__":
    run_all()

<|edits_diff|>
--- cluster/update_jobs.py
+++ cluster/update_jobs.py
@@ -10,9 +10,11 @@
         for i, cluster in enumerate(get_all_jobs(user)):
             cred = creds[i]
             jobs = {}
+            jobids = []
             for job in cluster["jobs"]:
                 status = job[-1]
                 job_id = job[0]
+                jobids.append(job_id)
                 if status in jobs:
                     jobs[status].append(job_id)
                 else:
<|current_version|>
from django.contrib.auth.models import User

from models import Job
from interface import get_all_jobs

def run_all():
    for user in User.objects.all():
        creds = user.credentials.all()
        for i, cluster in enumerate(get_all_jobs(user)):
            cred = creds[i]
            jobs = {}
            jobids = []
            for job in cluster["jobs"]:
                status = job[-1]
                job_id = job[0]
                jobids.append(job_id)
                if status in jobs:
                    jobs[status].append(job_id)
                else:
                    jobs[status] = [job_id]
            Job.update_states(cred, jobs)

if __name__ == "__main__":
    run_all()

<|next_version|>
from django.contrib.auth.models import User

from models import Job
from interface import get_all_jobs

def run_all():
    for user in User.objects.all():
        creds = user.credentials.all()
        for i, cluster in enumerate(get_all_jobs(user)):
            cred = creds[i]
            jobs = {}
            jobids = []
            for job in cluster["jobs"]:
                status = job[-1]
                job_id = job[0]
                jobids.append(job_id)
                if status in jobs:
                    jobs[status].append(job_id)
                else:
                    jobs[status] = [job_id]
            running = Job.get_running_jobs(credential=cred)
            unknown = running.exclude(jobid__in=set(jobids)).values_list('jobid', flat=True)
            if unknown:
                jobs[Job.UNKNOWN] = list(unknown)
            Job.update_states(cred, jobs)

if __name__ == "__main__":
    run_all()


Add new packages to tests

Add new packages to tests

--- test/test_packages.py
+++ test/test_packages.py
@@ -11,6 +11,7 @@
   ("curl"),
   ("diod"),
   ("docker-engine"),
+  ("fonts-font-awesome"),
   ("git"),
   ("gnupg"),
   ("handbrake"),
@@ -30,6 +31,7 @@
   ("openssl"),
   ("python"),
   ("python-pip"),
+  ("suckless-tools"),
   ("sysstat"),
   ("tree"),
   ("vagrant"),
@@ -42,6 +44,8 @@
   ("wget"),
   ("whois"),
   ("x264"),
+  ("xfce4-terminal"),
+  ("xfonts-terminus"),
   ("xinit"),
 ])

<|original_code|>
import pytest

@pytest.mark.parametrize("name", [
  ("apt-file"),
  ("apt-transport-https"),
  ("atsar"),
  ("blktrace"),
  ("ca-certificates"),
  ("chromium-browser"),
  ("cron"),
  ("curl"),
  ("diod"),
  ("docker-engine"),
  ("git"),
  ("gnupg"),
  ("handbrake"),
  ("handbrake-cli"),
  ("haveged"),
  ("htop"),
  ("i3"),
  ("iotop"),
  ("language-pack-en-base"),
  ("laptop-mode-tools"),
  ("nfs-common"),
  ("ntop"),
  ("ntp"),
  ("openssh-client"),
  ("openssh-server"),
  ("openssh-sftp-server"),
  ("openssl"),
  ("python"),
  ("python-pip"),
  ("sysstat"),
  ("tree"),
  ("vagrant"),
  ("vim"),
  ("vim-addon-manager"),
  ("vim-puppet"),
  ("vim-syntax-docker"),
  ("virtualbox"),
  ("vlc"),
  ("wget"),
  ("whois"),
  ("x264"),
  ("xinit"),
])

def test_packages(Package, name):
  assert Package(name).is_installed

<|edits_diff|>
--- test/test_packages.py
+++ test/test_packages.py
@@ -11,6 +11,7 @@
   ("curl"),
   ("diod"),
   ("docker-engine"),
+  ("fonts-font-awesome"),
   ("git"),
   ("gnupg"),
   ("handbrake"),
@@ -30,6 +31,7 @@
   ("openssl"),
   ("python"),
   ("python-pip"),
+  ("suckless-tools"),
   ("sysstat"),
   ("tree"),
   ("vagrant"),
<|current_version|>
import pytest

@pytest.mark.parametrize("name", [
  ("apt-file"),
  ("apt-transport-https"),
  ("atsar"),
  ("blktrace"),
  ("ca-certificates"),
  ("chromium-browser"),
  ("cron"),
  ("curl"),
  ("diod"),
  ("docker-engine"),
  ("fonts-font-awesome"),
  ("git"),
  ("gnupg"),
  ("handbrake"),
  ("handbrake-cli"),
  ("haveged"),
  ("htop"),
  ("i3"),
  ("iotop"),
  ("language-pack-en-base"),
  ("laptop-mode-tools"),
  ("nfs-common"),
  ("ntop"),
  ("ntp"),
  ("openssh-client"),
  ("openssh-server"),
  ("openssh-sftp-server"),
  ("openssl"),
  ("python"),
  ("python-pip"),
  ("suckless-tools"),
  ("sysstat"),
  ("tree"),
  ("vagrant"),
  ("vim"),
  ("vim-addon-manager"),
  ("vim-puppet"),
  ("vim-syntax-docker"),
  ("virtualbox"),
  ("vlc"),
  ("wget"),
  ("whois"),
  ("x264"),
  ("xinit"),
])

def test_packages(Package, name):
  assert Package(name).is_installed

<|next_version|>
import pytest

@pytest.mark.parametrize("name", [
  ("apt-file"),
  ("apt-transport-https"),
  ("atsar"),
  ("blktrace"),
  ("ca-certificates"),
  ("chromium-browser"),
  ("cron"),
  ("curl"),
  ("diod"),
  ("docker-engine"),
  ("fonts-font-awesome"),
  ("git"),
  ("gnupg"),
  ("handbrake"),
  ("handbrake-cli"),
  ("haveged"),
  ("htop"),
  ("i3"),
  ("iotop"),
  ("language-pack-en-base"),
  ("laptop-mode-tools"),
  ("nfs-common"),
  ("ntop"),
  ("ntp"),
  ("openssh-client"),
  ("openssh-server"),
  ("openssh-sftp-server"),
  ("openssl"),
  ("python"),
  ("python-pip"),
  ("suckless-tools"),
  ("sysstat"),
  ("tree"),
  ("vagrant"),
  ("vim"),
  ("vim-addon-manager"),
  ("vim-puppet"),
  ("vim-syntax-docker"),
  ("virtualbox"),
  ("vlc"),
  ("wget"),
  ("whois"),
  ("x264"),
  ("xfce4-terminal"),
  ("xfonts-terminus"),
  ("xinit"),
])

def test_packages(Package, name):
  assert Package(name).is_installed


Mark some fields as readonly in the Admin panel as they are set by the server (Requires Django 1.2 or greater)

--- powerdns/admin.py
+++ powerdns/admin.py
@@ -6,11 +6,13 @@
     list_display = ('name', 'type', 'content', 'ttl', 'prio', 'change_date',)
     list_filter = ['type', 'ttl',]
     search_fields  = ('name','content',)
+    readonly_fields = ('change_date',)

 class DomainAdmin(admin.ModelAdmin):
     list_display = ('name', 'type', 'last_check', 'account',)
     list_filter = ['type', 'last_check', 'account',]
     search_fields  = ('name',)
+    readonly_fields = ('notified_serial',)

 class SupermasterAdmin(admin.ModelAdmin):
     list_display = ('ip', 'nameserver', 'account',)

<|original_code|>
# -*- coding: utf-8 -*-
from django.contrib import admin
from powerdns.models import Domain, Record, Supermaster

class RecordAdmin(admin.ModelAdmin):
    list_display = ('name', 'type', 'content', 'ttl', 'prio', 'change_date',)
    list_filter = ['type', 'ttl',]
    search_fields  = ('name','content',)

class DomainAdmin(admin.ModelAdmin):
    list_display = ('name', 'type', 'last_check', 'account',)
    list_filter = ['type', 'last_check', 'account',]
    search_fields  = ('name',)

class SupermasterAdmin(admin.ModelAdmin):
    list_display = ('ip', 'nameserver', 'account',)
    list_filter = ['ip', 'account',]
    search_fields  = ('ip', 'nameserver',)

admin.site.register(Domain,DomainAdmin)
admin.site.register(Record,RecordAdmin)
admin.site.register(Supermaster,SupermasterAdmin)

<|edits_diff|>
--- powerdns/admin.py
+++ powerdns/admin.py
@@ -6,6 +6,7 @@
     list_display = ('name', 'type', 'content', 'ttl', 'prio', 'change_date',)
     list_filter = ['type', 'ttl',]
     search_fields  = ('name','content',)
+    readonly_fields = ('change_date',)

 class DomainAdmin(admin.ModelAdmin):
     list_display = ('name', 'type', 'last_check', 'account',)
<|current_version|>
# -*- coding: utf-8 -*-
from django.contrib import admin
from powerdns.models import Domain, Record, Supermaster

class RecordAdmin(admin.ModelAdmin):
    list_display = ('name', 'type', 'content', 'ttl', 'prio', 'change_date',)
    list_filter = ['type', 'ttl',]
    search_fields  = ('name','content',)
    readonly_fields = ('change_date',)

class DomainAdmin(admin.ModelAdmin):
    list_display = ('name', 'type', 'last_check', 'account',)
    list_filter = ['type', 'last_check', 'account',]
    search_fields  = ('name',)

class SupermasterAdmin(admin.ModelAdmin):
    list_display = ('ip', 'nameserver', 'account',)
    list_filter = ['ip', 'account',]
    search_fields  = ('ip', 'nameserver',)

admin.site.register(Domain,DomainAdmin)
admin.site.register(Record,RecordAdmin)
admin.site.register(Supermaster,SupermasterAdmin)

<|next_version|>
# -*- coding: utf-8 -*-
from django.contrib import admin
from powerdns.models import Domain, Record, Supermaster

class RecordAdmin(admin.ModelAdmin):
    list_display = ('name', 'type', 'content', 'ttl', 'prio', 'change_date',)
    list_filter = ['type', 'ttl',]
    search_fields  = ('name','content',)
    readonly_fields = ('change_date',)

class DomainAdmin(admin.ModelAdmin):
    list_display = ('name', 'type', 'last_check', 'account',)
    list_filter = ['type', 'last_check', 'account',]
    search_fields  = ('name',)
    readonly_fields = ('notified_serial',)

class SupermasterAdmin(admin.ModelAdmin):
    list_display = ('ip', 'nameserver', 'account',)
    list_filter = ['ip', 'account',]
    search_fields  = ('ip', 'nameserver',)

admin.site.register(Domain,DomainAdmin)
admin.site.register(Record,RecordAdmin)
admin.site.register(Supermaster,SupermasterAdmin)


Use importlib to load custom fields by str

--- setmagic/admin.py
+++ setmagic/admin.py
@@ -1,5 +1,6 @@
 from django import forms
 from django.contrib import admin
+from django.utils.importlib import import_module

 from setmagic import settings
 from setmagic.models import Setting
@@ -43,6 +44,9 @@
                 # Set a custom field
                 custom_field = settings.defs[self.instance.name].get('field')
                 if custom_field:
+                    if isinstance(custom_field, str):
+                        module, name = custom_field.rsplit('.', 1)
+                        custom_field = getattr(import_module(module), name)()
                     self.fields['current_value'] = custom_field

         return Form

<|original_code|>
from django import forms
from django.contrib import admin

from setmagic import settings
from setmagic.models import Setting

_denied = lambda *args: False

class SetMagicAdmin(admin.ModelAdmin):
    list_display = 'label', 'current_value',
    list_editable = 'current_value',
    list_display_links = None

    has_add_permission = _denied
    has_delete_permission = _denied

    # Make all fields read-only at the change form
    def get_readonly_fields(self, *args, **kwargs):
        return self.opts.get_all_field_names()

    def changelist_view(self, *args, **kwargs):
        settings._sync()
        return super(SetMagicAdmin, self).changelist_view(*args, **kwargs)

    def get_queryset(self, request):
        return Setting.objects.filter(name__in=settings.defs)

    def get_changelist_form(self, *args, **kwargs):
        class Form(forms.ModelForm):

            class Meta:
                fields = self.list_editable

            def __init__(self, *args, **kwargs):
                super(Form, self).__init__(*args, **kwargs)

                # Do nothing for empty forms
                if not self.instance.pk:
                    return

                # Set a custom field
                custom_field = settings.defs[self.instance.name].get('field')
                if custom_field:
                    self.fields['current_value'] = custom_field

        return Form

admin.site.register(Setting, SetMagicAdmin)

<|edits_diff|>
--- setmagic/admin.py
+++ setmagic/admin.py
@@ -1,5 +1,6 @@
 from django import forms
 from django.contrib import admin
+from django.utils.importlib import import_module

 from setmagic import settings
 from setmagic.models import Setting
<|current_version|>
from django import forms
from django.contrib import admin
from django.utils.importlib import import_module

from setmagic import settings
from setmagic.models import Setting

_denied = lambda *args: False

class SetMagicAdmin(admin.ModelAdmin):
    list_display = 'label', 'current_value',
    list_editable = 'current_value',
    list_display_links = None

    has_add_permission = _denied
    has_delete_permission = _denied

    # Make all fields read-only at the change form
    def get_readonly_fields(self, *args, **kwargs):
        return self.opts.get_all_field_names()

    def changelist_view(self, *args, **kwargs):
        settings._sync()
        return super(SetMagicAdmin, self).changelist_view(*args, **kwargs)

    def get_queryset(self, request):
        return Setting.objects.filter(name__in=settings.defs)

    def get_changelist_form(self, *args, **kwargs):
        class Form(forms.ModelForm):

            class Meta:
                fields = self.list_editable

            def __init__(self, *args, **kwargs):
                super(Form, self).__init__(*args, **kwargs)

                # Do nothing for empty forms
                if not self.instance.pk:
                    return

                # Set a custom field
                custom_field = settings.defs[self.instance.name].get('field')
                if custom_field:
                    self.fields['current_value'] = custom_field

        return Form

admin.site.register(Setting, SetMagicAdmin)

<|next_version|>
from django import forms
from django.contrib import admin
from django.utils.importlib import import_module

from setmagic import settings
from setmagic.models import Setting

_denied = lambda *args: False

class SetMagicAdmin(admin.ModelAdmin):
    list_display = 'label', 'current_value',
    list_editable = 'current_value',
    list_display_links = None

    has_add_permission = _denied
    has_delete_permission = _denied

    # Make all fields read-only at the change form
    def get_readonly_fields(self, *args, **kwargs):
        return self.opts.get_all_field_names()

    def changelist_view(self, *args, **kwargs):
        settings._sync()
        return super(SetMagicAdmin, self).changelist_view(*args, **kwargs)

    def get_queryset(self, request):
        return Setting.objects.filter(name__in=settings.defs)

    def get_changelist_form(self, *args, **kwargs):
        class Form(forms.ModelForm):

            class Meta:
                fields = self.list_editable

            def __init__(self, *args, **kwargs):
                super(Form, self).__init__(*args, **kwargs)

                # Do nothing for empty forms
                if not self.instance.pk:
                    return

                # Set a custom field
                custom_field = settings.defs[self.instance.name].get('field')
                if custom_field:
                    if isinstance(custom_field, str):
                        module, name = custom_field.rsplit('.', 1)
                        custom_field = getattr(import_module(module), name)()
                    self.fields['current_value'] = custom_field

        return Form

admin.site.register(Setting, SetMagicAdmin)


emoji: Set default emoji to google-blob for existing users too.

This fixes an inconsistent test failure with test_users.py (that
depended on the ordering between this migration and the creation of
test database users like hamlet).

--- zerver/migrations/0189_userprofile_add_some_emojisets.py
+++ zerver/migrations/0189_userprofile_add_some_emojisets.py
@@ -3,7 +3,12 @@
 from __future__ import unicode_literals

 from django.db import migrations, models
+from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
+from django.db.migrations.state import StateApps

+def change_emojiset_choice(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
+    UserProfile = apps.get_model('zerver', 'UserProfile')
+    UserProfile.objects.filter(emojiset='google').update(emojiset='google-blob')

 class Migration(migrations.Migration):

@@ -17,4 +22,7 @@
             name='emojiset',
             field=models.CharField(choices=[('google', 'Google modern'), ('google-blob', 'Google classic'), ('twitter', 'Twitter'), ('text', 'Plain text')], default='google-blob', max_length=20),
         ),
+        migrations.RunPython(
+            change_emojiset_choice,
+            reverse_code=migrations.RunPython.noop),
     ]

<|original_code|>
# -*- coding: utf-8 -*-
# Generated by Django 1.11.14 on 2018-08-28 19:01
from __future__ import unicode_literals

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [
        ('zerver', '0188_userprofile_enable_login_emails'),
    ]

    operations = [
        migrations.AlterField(
            model_name='userprofile',
            name='emojiset',
            field=models.CharField(choices=[('google', 'Google modern'), ('google-blob', 'Google classic'), ('twitter', 'Twitter'), ('text', 'Plain text')], default='google-blob', max_length=20),
        ),
    ]

<|edits_diff|>
--- zerver/migrations/0189_userprofile_add_some_emojisets.py
+++ zerver/migrations/0189_userprofile_add_some_emojisets.py
@@ -3,7 +3,12 @@
 from __future__ import unicode_literals

 from django.db import migrations, models
+from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
+from django.db.migrations.state import StateApps

+def change_emojiset_choice(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
+    UserProfile = apps.get_model('zerver', 'UserProfile')
+    UserProfile.objects.filter(emojiset='google').update(emojiset='google-blob')

 class Migration(migrations.Migration):

<|current_version|>
# -*- coding: utf-8 -*-
# Generated by Django 1.11.14 on 2018-08-28 19:01
from __future__ import unicode_literals

from django.db import migrations, models
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps

def change_emojiset_choice(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
    UserProfile = apps.get_model('zerver', 'UserProfile')
    UserProfile.objects.filter(emojiset='google').update(emojiset='google-blob')

class Migration(migrations.Migration):

    dependencies = [
        ('zerver', '0188_userprofile_enable_login_emails'),
    ]

    operations = [
        migrations.AlterField(
            model_name='userprofile',
            name='emojiset',
            field=models.CharField(choices=[('google', 'Google modern'), ('google-blob', 'Google classic'), ('twitter', 'Twitter'), ('text', 'Plain text')], default='google-blob', max_length=20),
        ),
    ]

<|next_version|>
# -*- coding: utf-8 -*-
# Generated by Django 1.11.14 on 2018-08-28 19:01
from __future__ import unicode_literals

from django.db import migrations, models
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
from django.db.migrations.state import StateApps

def change_emojiset_choice(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
    UserProfile = apps.get_model('zerver', 'UserProfile')
    UserProfile.objects.filter(emojiset='google').update(emojiset='google-blob')

class Migration(migrations.Migration):

    dependencies = [
        ('zerver', '0188_userprofile_enable_login_emails'),
    ]

    operations = [
        migrations.AlterField(
            model_name='userprofile',
            name='emojiset',
            field=models.CharField(choices=[('google', 'Google modern'), ('google-blob', 'Google classic'), ('twitter', 'Twitter'), ('text', 'Plain text')], default='google-blob', max_length=20),
        ),
        migrations.RunPython(
            change_emojiset_choice,
            reverse_code=migrations.RunPython.noop),
    ]


Add current_user to app properties

Add current_user to app properties

--- bucky/__init__.py
+++ bucky/__init__.py
@@ -3,11 +3,13 @@
 from config import config

 database = {}
+current_user = {}
 login_manager = LoginManager()

 def create_app(config_name):
     app = Flask(__name__)
     app.database = database
+    app.current_user = current_user
     app.config.from_object(config[config_name])
     login_manager.init_app(app)

<|original_code|>
from flask import Flask
from flask_login import LoginManager
from config import config

database = {}
login_manager = LoginManager()

def create_app(config_name):
    app = Flask(__name__)
    app.database = database
    app.config.from_object(config[config_name])
    login_manager.init_app(app)

    @login_manager.user_loader
    def load_user(username):
        for user in app.database:
            if user.username == username:
                return user

    from . import views
    app.register_blueprint(views.views)
    return app

<|edits_diff|>
--- bucky/__init__.py
+++ bucky/__init__.py
@@ -3,6 +3,7 @@
 from config import config

 database = {}
+current_user = {}
 login_manager = LoginManager()

 def create_app(config_name):
<|current_version|>
from flask import Flask
from flask_login import LoginManager
from config import config

database = {}
current_user = {}
login_manager = LoginManager()

def create_app(config_name):
    app = Flask(__name__)
    app.database = database
    app.config.from_object(config[config_name])
    login_manager.init_app(app)

    @login_manager.user_loader
    def load_user(username):
        for user in app.database:
            if user.username == username:
                return user

    from . import views
    app.register_blueprint(views.views)
    return app

<|next_version|>
from flask import Flask
from flask_login import LoginManager
from config import config

database = {}
current_user = {}
login_manager = LoginManager()

def create_app(config_name):
    app = Flask(__name__)
    app.database = database
    app.current_user = current_user
    app.config.from_object(config[config_name])
    login_manager.init_app(app)

    @login_manager.user_loader
    def load_user(username):
        for user in app.database:
            if user.username == username:
                return user

    from . import views
    app.register_blueprint(views.views)
    return app


Add a new rating code

Add a new rating code

--- bisnode/constants.py
+++ bisnode/constants.py
@@ -4,6 +4,7 @@
 HIGH = 'AAA'
 GOOD = 'AA'
 WORTHY = 'A'
+NEW = 'AN'
 BELOW_AVERAGE = 'B'
 BAD = 'C'
 MISSING = '-'
@@ -12,6 +13,7 @@
     (HIGH, "high"),
     (GOOD, "good"),
     (WORTHY, "worthy"),
+    (NEW, "new"),
     (BELOW_AVERAGE, "below average"),
     (BAD, "bad"),
     (MISSING, "missing"),

<|original_code|>
COMPANY_STANDARD_REPORT = "NRGCompanyReportStandard"
COMPANY_RATING_REPORT = "NRGCompanyReportRating"

HIGH = 'AAA'
GOOD = 'AA'
WORTHY = 'A'
BELOW_AVERAGE = 'B'
BAD = 'C'
MISSING = '-'

RATING_CHOICES = (
    (HIGH, "high"),
    (GOOD, "good"),
    (WORTHY, "worthy"),
    (BELOW_AVERAGE, "below average"),
    (BAD, "bad"),
    (MISSING, "missing"),
)

<|edits_diff|>
--- bisnode/constants.py
+++ bisnode/constants.py
@@ -4,6 +4,7 @@
 HIGH = 'AAA'
 GOOD = 'AA'
 WORTHY = 'A'
+NEW = 'AN'
 BELOW_AVERAGE = 'B'
 BAD = 'C'
 MISSING = '-'
<|current_version|>
COMPANY_STANDARD_REPORT = "NRGCompanyReportStandard"
COMPANY_RATING_REPORT = "NRGCompanyReportRating"

HIGH = 'AAA'
GOOD = 'AA'
WORTHY = 'A'
NEW = 'AN'
BELOW_AVERAGE = 'B'
BAD = 'C'
MISSING = '-'

RATING_CHOICES = (
    (HIGH, "high"),
    (GOOD, "good"),
    (WORTHY, "worthy"),
    (BELOW_AVERAGE, "below average"),
    (BAD, "bad"),
    (MISSING, "missing"),
)

<|next_version|>
COMPANY_STANDARD_REPORT = "NRGCompanyReportStandard"
COMPANY_RATING_REPORT = "NRGCompanyReportRating"

HIGH = 'AAA'
GOOD = 'AA'
WORTHY = 'A'
NEW = 'AN'
BELOW_AVERAGE = 'B'
BAD = 'C'
MISSING = '-'

RATING_CHOICES = (
    (HIGH, "high"),
    (GOOD, "good"),
    (WORTHY, "worthy"),
    (NEW, "new"),
    (BELOW_AVERAGE, "below average"),
    (BAD, "bad"),
    (MISSING, "missing"),
)


Add missing index command in revision

Designer: Add missing index command in revision

--- indico/migrations/versions/201705221530_3ca338ed5192_remove_background_image_and_add.py
+++ indico/migrations/versions/201705221530_3ca338ed5192_remove_background_image_and_add.py
@@ -22,9 +22,11 @@
                           'designer_templates', 'designer_templates',
                           ['backside_template_id'], ['id'],
                           source_schema='indico', referent_schema='indico')
+    op.create_index(None, 'designer_templates', ['backside_template_id'], schema='indico')

 def downgrade():
+    op.drop_index('ix_designer_templates_backside_template_id', table_name='designer_templates', schema='indico')
     op.drop_constraint('fk_designer_templates_backside_template_id_designer_templates', 'designer_templates',
                        schema='indico')
     op.drop_column('designer_templates', 'backside_template_id', schema='indico')

<|original_code|>
"""Add backside_template column

Revision ID: 3ca338ed5192
Revises: 35d76c40ca48
Create Date: 2017-05-17 11:33:30.295538
"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = '3ca338ed5192'
down_revision = '35d76c40ca48'
branch_labels = None
depends_on = None

def upgrade():
    op.add_column('designer_templates', sa.Column('backside_template_id', sa.Integer(), nullable=True), schema='indico')
    op.create_foreign_key(None,
                          'designer_templates', 'designer_templates',
                          ['backside_template_id'], ['id'],
                          source_schema='indico', referent_schema='indico')

def downgrade():
    op.drop_constraint('fk_designer_templates_backside_template_id_designer_templates', 'designer_templates',
                       schema='indico')
    op.drop_column('designer_templates', 'backside_template_id', schema='indico')

<|edits_diff|>
--- indico/migrations/versions/201705221530_3ca338ed5192_remove_background_image_and_add.py
+++ indico/migrations/versions/201705221530_3ca338ed5192_remove_background_image_and_add.py
@@ -22,6 +22,7 @@
                           'designer_templates', 'designer_templates',
                           ['backside_template_id'], ['id'],
                           source_schema='indico', referent_schema='indico')
+    op.create_index(None, 'designer_templates', ['backside_template_id'], schema='indico')

 def downgrade():
<|current_version|>
"""Add backside_template column

Revision ID: 3ca338ed5192
Revises: 35d76c40ca48
Create Date: 2017-05-17 11:33:30.295538
"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = '3ca338ed5192'
down_revision = '35d76c40ca48'
branch_labels = None
depends_on = None

def upgrade():
    op.add_column('designer_templates', sa.Column('backside_template_id', sa.Integer(), nullable=True), schema='indico')
    op.create_foreign_key(None,
                          'designer_templates', 'designer_templates',
                          ['backside_template_id'], ['id'],
                          source_schema='indico', referent_schema='indico')
    op.create_index(None, 'designer_templates', ['backside_template_id'], schema='indico')

def downgrade():
    op.drop_constraint('fk_designer_templates_backside_template_id_designer_templates', 'designer_templates',
                       schema='indico')
    op.drop_column('designer_templates', 'backside_template_id', schema='indico')

<|next_version|>
"""Add backside_template column

Revision ID: 3ca338ed5192
Revises: 35d76c40ca48
Create Date: 2017-05-17 11:33:30.295538
"""

import sqlalchemy as sa
from alembic import op

# revision identifiers, used by Alembic.
revision = '3ca338ed5192'
down_revision = '35d76c40ca48'
branch_labels = None
depends_on = None

def upgrade():
    op.add_column('designer_templates', sa.Column('backside_template_id', sa.Integer(), nullable=True), schema='indico')
    op.create_foreign_key(None,
                          'designer_templates', 'designer_templates',
                          ['backside_template_id'], ['id'],
                          source_schema='indico', referent_schema='indico')
    op.create_index(None, 'designer_templates', ['backside_template_id'], schema='indico')

def downgrade():
    op.drop_index('ix_designer_templates_backside_template_id', table_name='designer_templates', schema='indico')
    op.drop_constraint('fk_designer_templates_backside_template_id_designer_templates', 'designer_templates',
                       schema='indico')
    op.drop_column('designer_templates', 'backside_template_id', schema='indico')


Fix Redis connection over TLS

Fix Redis connection over TLS

When Designate is configured to use Redis for coordination over a TLS connection, it will fail to connect with "ssl.SSLError: ('timed out',)".
This is caused by eventlet raising ssl.SSLError instead of the expected socket timeout the core libraries return.
This patch monkey-patches eventlet to return the proper exception.

Closes-Bug: #1989020
Change-Id: I5bd1c10d863212683752e05bb450e6f531ff7e72

--- designate/cmd/__init__.py
+++ designate/cmd/__init__.py
@@ -14,8 +14,15 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 import eventlet
+from eventlet.green import ssl
+import socket

 eventlet.monkey_patch(os=False)
+
+# Work around the eventlet issue that impacts redis using TLS.
+# https://github.com/eventlet/eventlet/issues/692
+ssl.timeout_exc = socket.timeout
+
 # Monkey patch the original current_thread to use the up-to-date _active
 # global variable. See https://bugs.launchpad.net/bugs/1863021 and
 # https://github.com/eventlet/eventlet/issues/592

<|original_code|>
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import eventlet

eventlet.monkey_patch(os=False)
# Monkey patch the original current_thread to use the up-to-date _active
# global variable. See https://bugs.launchpad.net/bugs/1863021 and
# https://github.com/eventlet/eventlet/issues/592
import __original_module_threading as orig_threading  # noqa
import threading  # noqa
orig_threading.current_thread.__globals__['_active'] = threading._active

<|edits_diff|>
--- designate/cmd/__init__.py
+++ designate/cmd/__init__.py
@@ -14,6 +14,8 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 import eventlet
+from eventlet.green import ssl
+import socket

 eventlet.monkey_patch(os=False)
 # Monkey patch the original current_thread to use the up-to-date _active
<|current_version|>
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import eventlet
from eventlet.green import ssl
import socket

eventlet.monkey_patch(os=False)
# Monkey patch the original current_thread to use the up-to-date _active
# global variable. See https://bugs.launchpad.net/bugs/1863021 and
# https://github.com/eventlet/eventlet/issues/592
import __original_module_threading as orig_threading  # noqa
import threading  # noqa
orig_threading.current_thread.__globals__['_active'] = threading._active

<|next_version|>
# Copyright 2013 Hewlett-Packard Development Company, L.P.
#
# Author: Kiall Mac Innes <kiall@hp.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import eventlet
from eventlet.green import ssl
import socket

eventlet.monkey_patch(os=False)

# Work around the eventlet issue that impacts redis using TLS.
# https://github.com/eventlet/eventlet/issues/692
ssl.timeout_exc = socket.timeout

# Monkey patch the original current_thread to use the up-to-date _active
# global variable. See https://bugs.launchpad.net/bugs/1863021 and
# https://github.com/eventlet/eventlet/issues/592
import __original_module_threading as orig_threading  # noqa
import threading  # noqa
orig_threading.current_thread.__globals__['_active'] = threading._active


Update BitbucketAuthenticatedMethodsTest's test_get_tags and test_get_branches methods.

Signed-off-by: Baptiste Millou <1cfd48a9a65a966defdcd720f66cd790094000c4@smoothie-creative.com>

--- bitbucket/tests/private/private.py
+++ bitbucket/tests/private/private.py
@@ -33,9 +33,15 @@
         success, result = self.bb.get_tags()
         self.assertTrue(success)
         self.assertIsInstance(result, dict)
+        # test with invalid repository name
+        success, result = self.bb.get_tags(repo_slug='azertyuiop')
+        self.assertFalse(success)

     def test_get_branches(self):
         """ Test get_branches."""
         success, result = self.bb.get_branches()
         self.assertTrue(success)
         self.assertIsInstance(result, dict)
+        # test with invalid repository name
+        success, result = self.bb.get_branches(repo_slug='azertyuiop')
+        self.assertFalse(success)

<|original_code|>
# -*- coding: utf-8 -*-
import unittest

from bitbucket.bitbucket import Bitbucket
from bitbucket.tests.private import USERNAME, PASSWORD

TEST_REPO_SLUG = 'test_bitbucket_api'

class AuthenticatedBitbucketTest(unittest.TestCase):
    """ Bitbucket test base class for authenticated methods."""
    def setUp(self):
        """Creating a new authenticated Bitbucket..."""
        self.bb = Bitbucket(USERNAME, PASSWORD)
        # Create a repository.
        success, result = self.bb.repository.create(TEST_REPO_SLUG, has_issues=True)
        # Save repository's id
        assert success
        self.bb.repo_slug = result[u'slug']

    def tearDown(self):
        """Destroying the Bitbucket..."""
        # Delete the repository.
        self.bb.repository.delete()
        self.bb = None

class BitbucketAuthenticatedMethodsTest(AuthenticatedBitbucketTest):
    """ Testing Bitbucket annonymous methods."""

    def test_get_tags(self):
        """ Test get_tags."""
        success, result = self.bb.get_tags()
        self.assertTrue(success)
        self.assertIsInstance(result, dict)

    def test_get_branches(self):
        """ Test get_branches."""
        success, result = self.bb.get_branches()
        self.assertTrue(success)
        self.assertIsInstance(result, dict)

<|edits_diff|>
--- bitbucket/tests/private/private.py
+++ bitbucket/tests/private/private.py
@@ -33,6 +33,9 @@
         success, result = self.bb.get_tags()
         self.assertTrue(success)
         self.assertIsInstance(result, dict)
+        # test with invalid repository name
+        success, result = self.bb.get_tags(repo_slug='azertyuiop')
+        self.assertFalse(success)

     def test_get_branches(self):
         """ Test get_branches."""
<|current_version|>
# -*- coding: utf-8 -*-
import unittest

from bitbucket.bitbucket import Bitbucket
from bitbucket.tests.private import USERNAME, PASSWORD

TEST_REPO_SLUG = 'test_bitbucket_api'

class AuthenticatedBitbucketTest(unittest.TestCase):
    """ Bitbucket test base class for authenticated methods."""
    def setUp(self):
        """Creating a new authenticated Bitbucket..."""
        self.bb = Bitbucket(USERNAME, PASSWORD)
        # Create a repository.
        success, result = self.bb.repository.create(TEST_REPO_SLUG, has_issues=True)
        # Save repository's id
        assert success
        self.bb.repo_slug = result[u'slug']

    def tearDown(self):
        """Destroying the Bitbucket..."""
        # Delete the repository.
        self.bb.repository.delete()
        self.bb = None

class BitbucketAuthenticatedMethodsTest(AuthenticatedBitbucketTest):
    """ Testing Bitbucket annonymous methods."""

    def test_get_tags(self):
        """ Test get_tags."""
        success, result = self.bb.get_tags()
        self.assertTrue(success)
        self.assertIsInstance(result, dict)
        # test with invalid repository name
        success, result = self.bb.get_tags(repo_slug='azertyuiop')
        self.assertFalse(success)

    def test_get_branches(self):
        """ Test get_branches."""
        success, result = self.bb.get_branches()
        self.assertTrue(success)
        self.assertIsInstance(result, dict)

<|next_version|>
# -*- coding: utf-8 -*-
import unittest

from bitbucket.bitbucket import Bitbucket
from bitbucket.tests.private import USERNAME, PASSWORD

TEST_REPO_SLUG = 'test_bitbucket_api'

class AuthenticatedBitbucketTest(unittest.TestCase):
    """ Bitbucket test base class for authenticated methods."""
    def setUp(self):
        """Creating a new authenticated Bitbucket..."""
        self.bb = Bitbucket(USERNAME, PASSWORD)
        # Create a repository.
        success, result = self.bb.repository.create(TEST_REPO_SLUG, has_issues=True)
        # Save repository's id
        assert success
        self.bb.repo_slug = result[u'slug']

    def tearDown(self):
        """Destroying the Bitbucket..."""
        # Delete the repository.
        self.bb.repository.delete()
        self.bb = None

class BitbucketAuthenticatedMethodsTest(AuthenticatedBitbucketTest):
    """ Testing Bitbucket annonymous methods."""

    def test_get_tags(self):
        """ Test get_tags."""
        success, result = self.bb.get_tags()
        self.assertTrue(success)
        self.assertIsInstance(result, dict)
        # test with invalid repository name
        success, result = self.bb.get_tags(repo_slug='azertyuiop')
        self.assertFalse(success)

    def test_get_branches(self):
        """ Test get_branches."""
        success, result = self.bb.get_branches()
        self.assertTrue(success)
        self.assertIsInstance(result, dict)
        # test with invalid repository name
        success, result = self.bb.get_branches(repo_slug='azertyuiop')
        self.assertFalse(success)


Add cache clear to sync command

Add cache clear to sync command

--- news/management/commands/sync_newsletters.py
+++ news/management/commands/sync_newsletters.py
@@ -2,6 +2,8 @@
 from django.core.management import BaseCommand

 from synctool.functions import sync_data
+
+from news.newsletters import clear_newsletter_cache, clear_sms_cache

 DEFAULT_SYNC_DOMAIN = 'basket.mozilla.org'
@@ -22,3 +24,5 @@
         sync_data(url='https://{}/news/sync/'.format(options['domain']),
                   clean=options['clean'],
                   api_token=options['key'])
+        clear_newsletter_cache()
+        clear_sms_cache()

<|original_code|>
from django.conf import settings
from django.core.management import BaseCommand

from synctool.functions import sync_data

DEFAULT_SYNC_DOMAIN = 'basket.mozilla.org'

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('-d', '--domain',
                            default=getattr(settings, 'SYNC_DOMAIN', DEFAULT_SYNC_DOMAIN),
                            help='Domain of the Basket from which to sync')
        parser.add_argument('-k', '--key',
                            default=settings.SYNC_KEY,
                            help='Auth key for the sync')
        parser.add_argument('-c', '--clean', action='store_true',
                            help='Delete all Newsletter data before sync')

    def handle(self, *args, **options):
        sync_data(url='https://{}/news/sync/'.format(options['domain']),
                  clean=options['clean'],
                  api_token=options['key'])

<|edits_diff|>
--- news/management/commands/sync_newsletters.py
+++ news/management/commands/sync_newsletters.py
@@ -2,6 +2,8 @@
 from django.core.management import BaseCommand

 from synctool.functions import sync_data
+
+from news.newsletters import clear_newsletter_cache, clear_sms_cache

 DEFAULT_SYNC_DOMAIN = 'basket.mozilla.org'
<|current_version|>
from django.conf import settings
from django.core.management import BaseCommand

from synctool.functions import sync_data

from news.newsletters import clear_newsletter_cache, clear_sms_cache

DEFAULT_SYNC_DOMAIN = 'basket.mozilla.org'

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('-d', '--domain',
                            default=getattr(settings, 'SYNC_DOMAIN', DEFAULT_SYNC_DOMAIN),
                            help='Domain of the Basket from which to sync')
        parser.add_argument('-k', '--key',
                            default=settings.SYNC_KEY,
                            help='Auth key for the sync')
        parser.add_argument('-c', '--clean', action='store_true',
                            help='Delete all Newsletter data before sync')

    def handle(self, *args, **options):
        sync_data(url='https://{}/news/sync/'.format(options['domain']),
                  clean=options['clean'],
                  api_token=options['key'])

<|next_version|>
from django.conf import settings
from django.core.management import BaseCommand

from synctool.functions import sync_data

from news.newsletters import clear_newsletter_cache, clear_sms_cache

DEFAULT_SYNC_DOMAIN = 'basket.mozilla.org'

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument('-d', '--domain',
                            default=getattr(settings, 'SYNC_DOMAIN', DEFAULT_SYNC_DOMAIN),
                            help='Domain of the Basket from which to sync')
        parser.add_argument('-k', '--key',
                            default=settings.SYNC_KEY,
                            help='Auth key for the sync')
        parser.add_argument('-c', '--clean', action='store_true',
                            help='Delete all Newsletter data before sync')

    def handle(self, *args, **options):
        sync_data(url='https://{}/news/sync/'.format(options['domain']),
                  clean=options['clean'],
                  api_token=options['key'])
        clear_newsletter_cache()
        clear_sms_cache()