<commit_before>from __future__ import unicode_literals

import logging

from mopidy import backend, models
from mopidy.models import SearchResult

from .translator import assemble_uri, parse_uri

logger = logging.getLogger(__name__)

class AlbumsCategoryBrowser:

    field = None
    sort_fields = None
    label_fields = None

    def __init__(self, ref, api):
        self.ref = ref
        self.api = api

    def get_toplevel(self):
        keys = self.api.get_sorted_unique_album_attributes(self.field)
        return [models.Ref.directory(name=unicode(key), uri=assemble_uri(
            self.ref.uri, id_value=key)) for key in keys]

    def get_label(self, album):
        artist_names = [artist.name for artist in album.artists]
        if artist_names:
            return ' - '.join([' / '.join(artist_names), album.name])
        else:
            return album.name

    def get_directory(self, key):
        albums = self.api.get_albums_by([(self.field, key)], True,
                                        self.sort_fields)
        return [models.Ref.album(uri=album.uri, name=self.get_label(album))
                for album in albums]

class AlbumsByArtistBrowser(AlbumsCategoryBrowser):
    field = 'albumartist'
    sort_fields = ('original_year+', 'year+', 'album+')

    def get_label(self, album):
        return album.name

class AlbumsByGenreBrowser(AlbumsCategoryBrowser):
    field = 'genre'
    sort_fields = ('album+', )

class AlbumsByYearBrowser(AlbumsCategoryBrowser):
    field = 'year'
    sort_fields = ('month+', 'day+', 'album+')

class BeetsLibraryProvider(backend.LibraryProvider):

    root_directory = models.Ref.directory(uri='beets:library',
                                          name='Beets library')
    root_categorie_list = [
        ('albums-by-artist', 'Albums by Artist', AlbumsByArtistBrowser),
        ('albums-by-genre', 'Albums by Genre', AlbumsByGenreBrowser),
        ('albums-by-year', 'Albums by Year', AlbumsByYearBrowser),
    ]

    def __init__(self, *args, **kwargs):
        super(BeetsLibraryProvider, self).__init__(*args, **kwargs)
        self.remote = self.backend.beets_api
        self.category_browsers = []
        for key, label, browser_class in self.root_categorie_list:
            ref = models.Ref.directory(name=label, uri=assemble_uri(
                self.root_directory.uri, key))
            browser = browser_class(ref, self.remote)
            self.category_browsers.append(browser)

    def browse(self, uri):
        logger.debug('Browsing Beets at: %s', uri)
        parsed = parse_uri(uri, uri_prefix=self.root_directory.uri)
        if not parsed:
            logger.error('Beets - failed to parse uri: %s', uri)
            return []
        elif uri == self.root_directory.uri:
            # top level - show the categories
            refs = [browser.ref for browser in self.category_browsers]
            refs.sort(key=lambda item: item.name)
            return refs
        elif parsed[0] == 'album':
            # show an album
            try:
                album_id = parse_uri(uri, id_type=int)[1]
            except IndexError:
                logger.error('Beets - invalid album ID in URI: %s', uri)
                return []
            tracks = self.remote.get_tracks_by([('album_id', album_id)], True,
                                               ['track+'])
            return [models.Ref.track(uri=track.uri, name=track.name)
                    for track in tracks]
        else:
            # show a generic category directory
            parsed_uri, id_value = parse_uri(uri)
            for browser in self.category_browsers:
                if parsed_uri == browser.ref.uri:
                    if id_value is None:
                        return browser.get_toplevel()
                    else:
                        return browser.get_directory(parsed[1])
            else:
                logger.error('Invalid browse URI: %s / %s', uri, parsed[0])
                return []

    def search(self, query=None, uris=None, exact=False):
        # TODO: restrict the result to 'uris'
        logger.debug('Beets Query (exact=%s) within "%s": %s',
                     exact, uris, query)
        if not self.remote.has_connection:
            return []

        self._validate_query(query)
        search_list = []
        for (field, values) in query.items():
            for val in values:
                # missing / unsupported fields: uri, performer
                if field == 'any':
                    search_list.append(val)
                elif field == 'album':
                    search_list.append(('album', val))
                elif field == 'artist':
                    search_list.append(('artist', val))
                elif field == 'albumartist':
                    search_list.append(('albumartist', val))
                elif field == 'track_name':
                    search_list.append(('title', val))
                elif field == 'track_no':
                    search_list.append(('track', val))
                elif field == 'composer':
                    search_list.append(('composer', val))
                elif field == 'genre':
                    search_list.append(('genre', val))
                elif field == 'comment':
                    search_list.append(('comments', val))
                elif field == 'date':
                    # TODO: there is no 'date' in beets - just 'day', 'month'
                    #       and 'year'. Determine the format of 'date' and
                    #       define a suitable date format string?
                    search_list.append(('date', val))
                else:
                    logger.info('Beets: ignoring unknown query key: %s', field)
                    break
        logger.debug('Search query: %s', search_list)
        tracks = self.remote.get_tracks_by(search_list, exact, [])
        uri = '-'.join([item if isinstance(item, str) else '='.join(item)
                        for item in search_list])
        return SearchResult(uri='beets:search-' + uri, tracks=tracks)

    def lookup(self, uri=None, uris=None):
        logger.info('Beets lookup: %s', uri or uris)
        if uri:
            # the older method (mopidy < 1.0): return a list of tracks
            # handle one or more tracks given with multiple semicolons
            track_ids = uri.split(';')[1:]
            tracks = [self.remote.get_track(track_id, True)
                      for track_id in track_ids]
            # remove occourences of None
            return [track for track in tracks if track]
        else:
            # the newer method (mopidy >= 1.0): return a dict of uris and tracks
            return {uri: self.lookup(uri=uri) for uri in uris}

    def _validate_query(self, query):
        for values in query.values():
            if not values:
                raise LookupError('Missing query')
            for value in values:
                if not value:
                    raise LookupError('Missing query')
<commit_msg>"search": return a SearchResult even in case of problems<commit_after>from __future__ import unicode_literals

import logging

from mopidy import backend, models
from mopidy.models import SearchResult

from .translator import assemble_uri, parse_uri

logger = logging.getLogger(__name__)

class AlbumsCategoryBrowser:

    field = None
    sort_fields = None
    label_fields = None

    def __init__(self, ref, api):
        self.ref = ref
        self.api = api

    def get_toplevel(self):
        keys = self.api.get_sorted_unique_album_attributes(self.field)
        return [models.Ref.directory(name=unicode(key), uri=assemble_uri(
            self.ref.uri, id_value=key)) for key in keys]

    def get_label(self, album):
        artist_names = [artist.name for artist in album.artists]
        if artist_names:
            return ' - '.join([' / '.join(artist_names), album.name])
        else:
            return album.name

    def get_directory(self, key):
        albums = self.api.get_albums_by([(self.field, key)], True,
                                        self.sort_fields)
        return [models.Ref.album(uri=album.uri, name=self.get_label(album))
                for album in albums]

class AlbumsByArtistBrowser(AlbumsCategoryBrowser):
    field = 'albumartist'
    sort_fields = ('original_year+', 'year+', 'album+')

    def get_label(self, album):
        return album.name

class AlbumsByGenreBrowser(AlbumsCategoryBrowser):
    field = 'genre'
    sort_fields = ('album+', )

class AlbumsByYearBrowser(AlbumsCategoryBrowser):
    field = 'year'
    sort_fields = ('month+', 'day+', 'album+')

class BeetsLibraryProvider(backend.LibraryProvider):

    root_directory = models.Ref.directory(uri='beets:library',
                                          name='Beets library')
    root_categorie_list = [
        ('albums-by-artist', 'Albums by Artist', AlbumsByArtistBrowser),
        ('albums-by-genre', 'Albums by Genre', AlbumsByGenreBrowser),
        ('albums-by-year', 'Albums by Year', AlbumsByYearBrowser),
    ]

    def __init__(self, *args, **kwargs):
        super(BeetsLibraryProvider, self).__init__(*args, **kwargs)
        self.remote = self.backend.beets_api
        self.category_browsers = []
        for key, label, browser_class in self.root_categorie_list:
            ref = models.Ref.directory(name=label, uri=assemble_uri(
                self.root_directory.uri, key))
            browser = browser_class(ref, self.remote)
            self.category_browsers.append(browser)

    def browse(self, uri):
        logger.debug('Browsing Beets at: %s', uri)
        parsed = parse_uri(uri, uri_prefix=self.root_directory.uri)
        if not parsed:
            logger.error('Beets - failed to parse uri: %s', uri)
            return []
        elif uri == self.root_directory.uri:
            # top level - show the categories
            refs = [browser.ref for browser in self.category_browsers]
            refs.sort(key=lambda item: item.name)
            return refs
        elif parsed[0] == 'album':
            # show an album
            try:
                album_id = parse_uri(uri, id_type=int)[1]
            except IndexError:
                logger.error('Beets - invalid album ID in URI: %s', uri)
                return []
            tracks = self.remote.get_tracks_by([('album_id', album_id)], True,
                                               ['track+'])
            return [models.Ref.track(uri=track.uri, name=track.name)
                    for track in tracks]
        else:
            # show a generic category directory
            parsed_uri, id_value = parse_uri(uri)
            for browser in self.category_browsers:
                if parsed_uri == browser.ref.uri:
                    if id_value is None:
                        return browser.get_toplevel()
                    else:
                        return browser.get_directory(parsed[1])
            else:
                logger.error('Invalid browse URI: %s / %s', uri, parsed[0])
                return []

    def search(self, query=None, uris=None, exact=False):
        # TODO: restrict the result to 'uris'
        logger.debug('Beets Query (exact=%s) within "%s": %s',
                     exact, uris, query)
        if not self.remote.has_connection:
            return SearchResult(uri='beets:search-disconnected', tracks=[])

        self._validate_query(query)
        search_list = []
        for (field, values) in query.items():
            for val in values:
                # missing / unsupported fields: uri, performer
                if field == 'any':
                    search_list.append(val)
                elif field == 'album':
                    search_list.append(('album', val))
                elif field == 'artist':
                    search_list.append(('artist', val))
                elif field == 'albumartist':
                    search_list.append(('albumartist', val))
                elif field == 'track_name':
                    search_list.append(('title', val))
                elif field == 'track_no':
                    search_list.append(('track', val))
                elif field == 'composer':
                    search_list.append(('composer', val))
                elif field == 'genre':
                    search_list.append(('genre', val))
                elif field == 'comment':
                    search_list.append(('comments', val))
                elif field == 'date':
                    # TODO: there is no 'date' in beets - just 'day', 'month'
                    #       and 'year'. Determine the format of 'date' and
                    #       define a suitable date format string?
                    search_list.append(('date', val))
                else:
                    logger.info('Beets: ignoring unknown query key: %s', field)
                    break
        logger.debug('Search query: %s', search_list)
        tracks = self.remote.get_tracks_by(search_list, exact, [])
        uri = '-'.join([item if isinstance(item, str) else '='.join(item)
                        for item in search_list])
        return SearchResult(uri='beets:search-' + uri, tracks=tracks)

    def lookup(self, uri=None, uris=None):
        logger.info('Beets lookup: %s', uri or uris)
        if uri:
            # the older method (mopidy < 1.0): return a list of tracks
            # handle one or more tracks given with multiple semicolons
            track_ids = uri.split(';')[1:]
            tracks = [self.remote.get_track(track_id, True)
                      for track_id in track_ids]
            # remove occourences of None
            return [track for track in tracks if track]
        else:
            # the newer method (mopidy >= 1.0): return a dict of uris and tracks
            return {uri: self.lookup(uri=uri) for uri in uris}

    def _validate_query(self, query):
        for values in query.values():
            if not values:
                raise LookupError('Missing query')
            for value in values:
                if not value:
                    raise LookupError('Missing query')
<|endoftext|>


<commit_before>from . import celery
from .models import Result

from bson import ObjectId
import re

@celery.task(name='app.motif_analysis.analyze_sequence')
def analyze_sequence(query_id, sequence_description, sequence, motif_list, motif_frequency, motif_frame_size, user):
    """
    Analyzes single sequence and inserts
    results of analysis into MongoDB
    :param query_id:
    :param sequence_description:
    :param sequence:
    :param motif_list:
    :param motif_frequency:
    :param motif_frame_size:
    :param user:
    :return:
    """
    sequence_regex_matches = []
    has_motif = False

    for motif_str in motif_list:
        motif_regex = re.compile(motif_str)
        regex_match_list = []

        for match in motif_regex.finditer(sequence):
            substr_start = int(match.start())
            substr_end = substr_start + motif_frame_size
            substr_analysis = [match for match in motif_regex.finditer(sequence[substr_start:substr_end])]
            substr_match_list = []

            if len(substr_analysis) >= motif_frequency:
                for substr_match in substr_analysis:
                    substr = {
                        'match': substr_match.group(),
                        'span': [(substr_start + substr_match.span()[0]), (substr_start + substr_match.span()[1])]
                    }
                    substr_match_list.append(substr)
                has_motif = True
                regex_match_list.append(substr_match_list)
        regex_data = {
            motif_str: regex_match_list
        }
        sequence_regex_matches.append(regex_data)

    Result.insert_one(
        query_id=ObjectId(query_id),
        sequence_description=sequence_description,
        sequence=sequence,
        analysis=sequence_regex_matches,
        has_motif=has_motif,
        user=user
    )
<commit_msg>DONE MUST TEST CELERY TASK  QUEUE<commit_after>from . import celery
from .models import Result

from bson import ObjectId
import re

@celery.task(name='app.motif_analysis')
def analyze_sequence(query_id, sequence_description, sequence, motif_list, motif_frequency, motif_frame_size, user):
    """
    Analyzes single sequence and inserts
    results of analysis into MongoDB
    :param query_id:
    :param sequence_description:
    :param sequence:
    :param motif_list:
    :param motif_frequency:
    :param motif_frame_size:
    :param user:
    :return:
    """
    sequence_regex_matches = []
    has_motif = False

    for motif_str in motif_list:
        motif_regex = re.compile(motif_str)
        regex_match_list = []

        for match in motif_regex.finditer(sequence):
            substr_start = int(match.start())
            substr_end = substr_start + motif_frame_size
            substr_analysis = [match for match in motif_regex.finditer(sequence[substr_start:substr_end])]
            substr_match_list = []

            if len(substr_analysis) >= motif_frequency:
                for substr_match in substr_analysis:
                    substr = {
                        'match': substr_match.group(),
                        'span': [(substr_start + substr_match.span()[0]), (substr_start + substr_match.span()[1])]
                    }
                    substr_match_list.append(substr)
                has_motif = True
                regex_match_list.append(substr_match_list)
        regex_data = {
            motif_str: regex_match_list
        }
        sequence_regex_matches.append(regex_data)

    Result.insert_one(
        query_id=ObjectId(query_id),
        sequence_description=sequence_description,
        sequence=sequence,
        analysis=sequence_regex_matches,
        has_motif=has_motif,
        user=user
    )
<|endoftext|>


<commit_before>from django.core.cache import cache
from django.core.paginator import Paginator, Page
from django.utils import six

import constance.config

import hashlib
import logging
import urlparse
import urllib
import urllib2

from compat import json

class API:
    class DataSet:
        """Lazy dataset container for pagination purposes. Loads slices on demand."""
        def __init__(self, path, query, total_count, request):
            self._path = path
            self._query = query
            self._total_count = total_count
            self._request = request

        def __len__(self):
            return self._total_count

        def __getitem__(self, val):
            if not isinstance(val, (slice,) + six.integer_types):
                raise TypeError

            q = {}
            q.update(self._query)

            if isinstance(val, slice):
                q['limit'] = val.stop - val.start
                q['offset'] = val.start
            else:
                q['limit'] = 1
                q['offset'] = val

            data = self._request(self._path, q)

            if data is None:
                return None
            elif isinstance(val, slice):
                return data['objects']
            else:
                return data['objects'][0]

    def __init__(self, name=None, key=None, endpoint=None):
        self.name = name
        self.key = key
        self.endpoint = endpoint

    def _request(self, path, query={}, ignore_cache=False):
        MOZILLIANS_API_BASE_URL = constance.config.MOZILLIANS_API_BASE_URL
        MOZILLIANS_API_APPNAME = constance.config.MOZILLIANS_API_APPNAME
        MOZILLIANS_API_KEY = constance.config.MOZILLIANS_API_KEY
        MOZILLIANS_API_CACHE_KEY_PREFIX = constance.config.MOZILLIANS_API_CACHE_KEY_PREFIX
        MOZILLIANS_API_CACHE_TIMEOUT = constance.config.MOZILLIANS_API_CACHE_TIMEOUT

        endpoint = self.endpoint or MOZILLIANS_API_BASE_URL
        app_name = self.name or MOZILLIANS_API_APPNAME
        app_key = self.key or MOZILLIANS_API_KEY

        if not app_name or not app_key:
            logging.warning('Missing Mozillians app name or key')
            return None

        query['app_name'] = app_name
        query['app_key'] = app_key

        base = urlparse.urljoin(endpoint.rstrip('/') + '/', path.lstrip('/'))
        qs = urllib.urlencode(sorted([(key, value) for key, value in query.iteritems()]))
        url = '%s?%s' % (base, qs,)

        cache_key = '%s:%s' % (MOZILLIANS_API_CACHE_KEY_PREFIX,
                               hashlib.md5(url.encode('utf-8')).hexdigest())

        content = None if ignore_cache else cache.get(cache_key)

        if not content:
            try:
                request = urllib2.Request(url)
                response = urllib2.urlopen(request)
                content = response.read()
                cache.set(cache_key, content, MOZILLIANS_API_CACHE_TIMEOUT)
            except urllib2.URLError as e:
                logging.error('Mozillians request failed:\n - %s\n - %s', e, url)
                return None

        try:
            return json.loads(content)
        except ValueError as e:
            logging.error('Parsing Mozillians response failed:\n - %s\n - %s', e, url)
            return None

    def _get_dataset(self, path, page, per_page, query={}):
        q = {}
        q.update(query)
        q['limit'] = per_page
        q['offset'] = (page - 1) * per_page

        response = self._request(path, q)
        if response is None:
            return None

        meta = response['meta']
        objects = response['objects']

        dataset = API.DataSet(path, query, meta['total_count'], self._request)
        paginator = Paginator(dataset, per_page)
        return Page(objects, page, paginator)

    def get_users(self, page=1, per_page=20, **query):
        return self._get_dataset('/users/', page, per_page, query)

    def get_user(self, id):
        return self._request('/users/%d/' % id)

    def get_groups(self, page=1, per_page=20, order_by='id'):
        return self._get_dataset('/groups/', page, per_page, {order_by: order_by})

    def get_group(self, id):
        return self._request('/groups/%d/' % id)

    def get_skills(self, page=1, per_page=20, order_by='id'):
        return self._get_dataset('/skills/', page, per_page, {order_by: order_by})

    def get_skill(self, id):
        return self._request('/skills/%d/' % id)

api = API()
<commit_msg>Minor tweaks to mozillians API wrapper<commit_after>from django.core.cache import cache
from django.core.paginator import Paginator, Page, EmptyPage
from django.utils import six

import constance.config

import hashlib
import logging
import math
import urlparse
import urllib
import urllib2

from compat import json

class API:
    class DataSet:
        """Lazy dataset container for pagination purposes. Loads slices on demand."""
        def __init__(self, path, query, total_count, request):
            self._path = path
            self._query = query
            self._total_count = total_count
            self._request = request

        def __len__(self):
            return self._total_count

        def __getitem__(self, val):
            if not isinstance(val, (slice,) + six.integer_types):
                raise TypeError

            q = {}
            q.update(self._query)

            if isinstance(val, slice):
                q['limit'] = val.stop - val.start
                q['offset'] = val.start
            else:
                q['limit'] = 1
                q['offset'] = val

            data = self._request(self._path, q)

            if data is None:
                return None
            elif isinstance(val, slice):
                return data['objects']
            else:
                return data['objects'][0]

    def __init__(self, name=None, key=None, endpoint=None):
        self.name = name
        self.key = key
        self.endpoint = endpoint

    def _request(self, path, query={}, ignore_cache=False, cache_timeout=None):
        MOZILLIANS_API_BASE_URL = constance.config.MOZILLIANS_API_BASE_URL
        MOZILLIANS_API_APPNAME = constance.config.MOZILLIANS_API_APPNAME
        MOZILLIANS_API_KEY = constance.config.MOZILLIANS_API_KEY
        MOZILLIANS_API_CACHE_KEY_PREFIX = constance.config.MOZILLIANS_API_CACHE_KEY_PREFIX
        MOZILLIANS_API_CACHE_TIMEOUT = constance.config.MOZILLIANS_API_CACHE_TIMEOUT

        endpoint = self.endpoint or MOZILLIANS_API_BASE_URL
        app_name = self.name or MOZILLIANS_API_APPNAME
        app_key = self.key or MOZILLIANS_API_KEY
        if cache_timeout is None:
            cache_timeout = MOZILLIANS_API_CACHE_TIMEOUT

        if not app_name or not app_key:
            logging.warning('Missing Mozillians app name or key')
            return None

        query['app_name'] = app_name
        query['app_key'] = app_key

        base = urlparse.urljoin(endpoint.rstrip('/') + '/', path.lstrip('/'))
        qs = urllib.urlencode(sorted([(key, value) for key, value in query.iteritems()]))
        url = '%s?%s' % (base, qs,)

        cache_key = '%s:%s' % (MOZILLIANS_API_CACHE_KEY_PREFIX,
                               hashlib.md5(url.encode('utf-8')).hexdigest())

        content = None if ignore_cache else cache.get(cache_key)

        if not content:
            try:
                request = urllib2.Request(url)
                response = urllib2.urlopen(request)
                content = response.read()
                cache.set(cache_key, content, cache_timeout)
            except urllib2.URLError as e:
                logging.error('Mozillians request failed:\n - %s\n - %s', e, url)
                return None

        try:
            return json.loads(content)
        except ValueError as e:
            logging.error('Parsing Mozillians response failed:\n - %s\n - %s', e, url)
            return None

    def _get_dataset(self, path, page, per_page, query={}, cache_timeout=None):
        q = {}
        q.update(query)
        q['limit'] = per_page
        q['offset'] = (page - 1) * per_page

        response = self._request(path, q)

        if response is None:
            response = {
                'meta': {'total_count': 0},
                'objects': [],
            }

        meta = response['meta']
        objects = response['objects']

        dataset = API.DataSet(path, query, meta['total_count'], self._request)
        paginator = Paginator(dataset, per_page)
        return Page(objects, paginator.validate_number(page), paginator)

    def get_users(self, page=1, per_page=20, cache_timeout=None, **query):
        return self._get_dataset('/users/', page, per_page, query, cache_timeout)

    def get_user(self, id, cache_timeout=None):
        return self._request('/users/%d/' % id, cache_timeout=cache_timeout)

    def get_groups(self, page=1, per_page=20, order_by='id', cache_timeout=None):
        return self._get_dataset('/groups/', page, per_page, {order_by: order_by}, cache_timeout)

    def get_group(self, id, cache_timeout=None):
        return self._request('/groups/%d/' % id, cache_timeout=cache_timeout)

    def get_skills(self, page=1, per_page=20, order_by='id', cache_timeout=None):
        return self._get_dataset('/skills/', page, per_page, {order_by: order_by}, cache_timeout)

    def get_skill(self, id, cache_timeout=None):
        return self._request('/skills/%d/' % id, cache_timeout=cache_timeout)

api = API()
<|endoftext|>


<commit_before>from unittest.mock import MagicMock
from mpf.tests.MpfTestCase import MpfTestCase

class TestModes(MpfTestCase):

    def getConfigFile(self):
        return 'test_modes.yaml'

    def getMachinePath(self):
        return 'tests/machine_files/mode_tests/'

    def test_loading_modes(self):
        # Tests multi-case mode listing in config and checking here

        # lowercase in config, lowercase folder
        self.assertIn('mode1', self.machine.modes)
        # uppercase in config, lowercase folder
        self.assertIn('mode2', self.machine.modes)
        # lowercase config, uppercase folder
        self.assertIn('mode3', self.machine.modes)
        # lowercase config, lowercase folder, uppercase here
        self.assertIn('Mode4', self.machine.modes)

    def test_mode_start_stop(self):
        # start mode 1
        self.machine.events.post('start_mode1')
        self.advance_time_and_run()
        self.assertTrue(self.machine.mode_controller.is_active('mode1'))
        self.assertTrue(self.machine.modes.mode1.active)
        self.assertIn(self.machine.modes.mode1,
                      self.machine.mode_controller.active_modes)
        self.assertFalse(self.machine.mode_controller.is_active('mode2'))
        self.assertFalse(self.machine.modes.mode2.active)
        self.assertIn(self.machine.modes.mode1,
                      self.machine.mode_controller.active_modes)

        # test config via include
        self.assertEqual(123, self.machine.modes.mode1.config['mode_settings']['test'])

        # start a mode that's already started and make sure it doesn't explode
        self.machine.modes.mode1.start()

        # stop mode 1
        self.machine.events.post('stop_mode1')
        self.advance_time_and_run()
        self.assertFalse(self.machine.mode_controller.is_active('mode1'))
        self.assertFalse(self.machine.modes.mode1.active)

    def test_custom_mode_code(self):
        self.assertTrue(self.machine.modes.mode3.custom_code)

    def test_mode_priorities(self):

        # test the start priorities TODO there's got to be a better way?
        found_it = False

        for handler in self.machine.events.registered_handlers['start_mode1']:

            if handler.callback == self.machine.modes.mode1.start:
                found_it = True
                self.assertEqual(handler.priority, 201)

        self.assertTrue(found_it)

        # default priorities
        self.machine.modes.mode1.start()
        self.machine.modes.mode2.start()
        self.advance_time_and_run()
        self.assertEqual(self.machine.modes.mode1.priority, 200)
        self.assertEqual(self.machine.modes.mode2.priority, 100)
        self.assertEqual(self.machine.modes.attract.priority, 10)

        # test the stop priorities
        found_it = False
        for handler in self.machine.events.registered_handlers['stop_mode1']:
            if handler.callback == self.machine.modes.mode1.stop:
                found_it = True
                # 201 because stop priorities are always +1 over mode priority
                self.assertEqual(handler.priority, 201)
        self.assertTrue(found_it)

        found_it = False
        for handler in self.machine.events.registered_handlers['stop_mode2']:
            if handler.callback == self.machine.modes.mode2.stop:
                found_it = True
                # base priority 100, +1 default bump, +2 stop_priority config
                self.assertEqual(handler.priority, 103)
        self.assertTrue(found_it)

        # pass a priority at start
        self.machine.modes.mode1.stop()
        self.advance_time_and_run()
        self.machine.modes.mode1.start(mode_priority=500)
        self.advance_time_and_run()
        self.assertEqual(self.machine.modes.mode1.priority, 500)
        self.advance_time_and_run()

        # test the order of the active modes list
        self.assertEqual(self.machine.modes.mode1,
                         self.machine.mode_controller.active_modes[0])
        self.assertEqual(self.machine.modes.mode2,
                         self.machine.mode_controller.active_modes[1])
        self.assertEqual(self.machine.modes.attract,
                         self.machine.mode_controller.active_modes[2])

    def test_mode_start_with_callback(self):
        self.mode_start_callback = MagicMock()

        self.machine.modes.mode1.start(callback=self.mode_start_callback)
        self.advance_time_and_run()
        self.mode_start_callback.assert_called_once_with()

    def test_use_wait_queue(self):
        self.callback = MagicMock()
        self.machine.events.post_queue('start_mode4',
                                       callback=self.callback)
        self.advance_time_and_run()

        # make sure the mode started
        self.assertTrue(self.machine.modes.mode4.active)
        self.advance_time_and_run()

        # callback should not be called since mode is set to use wait queue
        self.callback.assert_not_called()

        self.machine.modes.mode4.stop()
        self.advance_time_and_run()

        # once mode stops, verify that callback was called
        self.callback.assert_called_once_with()

    def test_ball_end(self):
        # mode1 is set to keep running on ball end
        # mode2 should stop and restart on ball end
        # mode3 should stop and stay stopped
        self.assertFalse(self.machine.modes.mode1.config['mode']['stop_on_ball_end'])
        self.assertTrue(self.machine.modes.mode2.config['mode']['stop_on_ball_end'])
        self.assertTrue(self.machine.modes.mode3.config['mode']['stop_on_ball_end'])

        # start a game
        self.machine.playfield.add_ball = MagicMock()
        self.machine.events.post('game_start')
        self.advance_time_and_run()
        self.machine.game.balls_in_play = 1
        self.assertTrue(self.machine.game)

        # start some modes
        self.machine.modes.mode1.start()
        self.machine.modes.mode2.start()
        self.machine.modes.mode3.start()
        self.advance_time_and_run()
        self.assertTrue(self.machine.modes.mode1.active)
        self.assertTrue(self.machine.modes.mode2.active)
        self.assertTrue(self.machine.modes.mode3.active)

        # change the config of modes 1 and 2 so we can verify whether they
        # actually stopped and restarted since the configs are used to start
        # the modes
        self.machine.modes.mode1.config['mode']['priority'] = 999
        self.machine.modes.mode2.config['mode']['priority'] = 999

        # end the ball
        self.machine.game.end_ball()
        self.advance_time_and_run()

        self.assertTrue(self.machine.modes.mode1.active)
        self.assertTrue(self.machine.modes.mode2.active)
        self.assertFalse(self.machine.modes.mode3.active)

        # since mode1 should have stayed running, its config should not change
        self.assertNotEqual(self.machine.modes.mode1.priority, 999)
        # mode2 should use the new priority since it should have restarted
        self.assertEqual(self.machine.modes.mode2.priority, 999)

        # end ball 2
        self.machine.game.end_ball()
        self.advance_time_and_run()

        # end ball 3 and end the game
        self.machine.game.end_ball()
        self.advance_time_and_run()

        self.assertTrue(self.machine.modes.attract.active)
        self.assertFalse(self.machine.modes.game.active)
        self.assertTrue(self.machine.modes.mode1.active)
        self.assertFalse(self.machine.modes.mode2.active)
        self.assertFalse(self.machine.modes.mode3.active)
<commit_msg>Extended mode test to check for all mode events<commit_after>from unittest.mock import MagicMock
from mpf.tests.MpfTestCase import MpfTestCase

class TestModes(MpfTestCase):

    def getConfigFile(self):
        return 'test_modes.yaml'

    def getMachinePath(self):
        return 'tests/machine_files/mode_tests/'

    def test_loading_modes(self):
        # Tests multi-case mode listing in config and checking here

        # lowercase in config, lowercase folder
        self.assertIn('mode1', self.machine.modes)
        # uppercase in config, lowercase folder
        self.assertIn('mode2', self.machine.modes)
        # lowercase config, uppercase folder
        self.assertIn('mode3', self.machine.modes)
        # lowercase config, lowercase folder, uppercase here
        self.assertIn('Mode4', self.machine.modes)

    def test_mode_start_stop(self):
        # Setup mocked event handlers for mode start/stop sequence
        self.mode1_will_start_event_handler = MagicMock()
        self.mode1_starting_event_handler = MagicMock()
        self.mode1_started_event_handler = MagicMock()
        self.mode1_will_stop_event_handler = MagicMock()
        self.mode1_stopping_event_handler = MagicMock()
        self.mode1_stopped_event_handler = MagicMock()

        self.machine.events.add_handler('mode_mode1_will_start', self.mode1_will_start_event_handler)
        self.machine.events.add_handler('mode_mode1_starting', self.mode1_starting_event_handler)
        self.machine.events.add_handler('mode_mode1_started', self.mode1_started_event_handler)
        self.machine.events.add_handler('mode_mode1_will_stop', self.mode1_will_stop_event_handler)
        self.machine.events.add_handler('mode_mode1_stopping', self.mode1_stopping_event_handler)
        self.machine.events.add_handler('mode_mode1_stopped', self.mode1_stopped_event_handler)

        # start mode 1
        self.machine.events.post('start_mode1')
        self.advance_time_and_run()
        self.assertTrue(self.machine.mode_controller.is_active('mode1'))
        self.assertTrue(self.machine.modes.mode1.active)
        self.assertIn(self.machine.modes.mode1,
                      self.machine.mode_controller.active_modes)
        self.assertFalse(self.machine.mode_controller.is_active('mode2'))
        self.assertFalse(self.machine.modes.mode2.active)
        self.assertIn(self.machine.modes.mode1,
                      self.machine.mode_controller.active_modes)

        # test config via include
        self.assertEqual(123, self.machine.modes.mode1.config['mode_settings']['test'])

        # start a mode that's already started and make sure it doesn't explode
        self.machine.modes.mode1.start()

        # make sure event handler were called for mode start process
        self.assertEquals(1, self.mode1_will_start_event_handler.call_count)
        self.assertEquals(1, self.mode1_starting_event_handler.call_count)
        self.assertEquals(1, self.mode1_started_event_handler.call_count)

        # stop mode 1
        self.machine.events.post('stop_mode1')
        self.advance_time_and_run()
        self.assertFalse(self.machine.mode_controller.is_active('mode1'))
        self.assertFalse(self.machine.modes.mode1.active)

        # make sure event handler were called for mode stop process
        self.assertEquals(1, self.mode1_will_stop_event_handler.call_count)
        self.assertEquals(1, self.mode1_stopping_event_handler.call_count)
        self.assertEquals(1, self.mode1_stopped_event_handler.call_count)

    def test_custom_mode_code(self):
        self.assertTrue(self.machine.modes.mode3.custom_code)

    def test_mode_priorities(self):

        # test the start priorities TODO there's got to be a better way?
        found_it = False

        for handler in self.machine.events.registered_handlers['start_mode1']:

            if handler.callback == self.machine.modes.mode1.start:
                found_it = True
                self.assertEqual(handler.priority, 201)

        self.assertTrue(found_it)

        # default priorities
        self.machine.modes.mode1.start()
        self.machine.modes.mode2.start()
        self.advance_time_and_run()
        self.assertEqual(self.machine.modes.mode1.priority, 200)
        self.assertEqual(self.machine.modes.mode2.priority, 100)
        self.assertEqual(self.machine.modes.attract.priority, 10)

        # test the stop priorities
        found_it = False
        for handler in self.machine.events.registered_handlers['stop_mode1']:
            if handler.callback == self.machine.modes.mode1.stop:
                found_it = True
                # 201 because stop priorities are always +1 over mode priority
                self.assertEqual(handler.priority, 201)
        self.assertTrue(found_it)

        found_it = False
        for handler in self.machine.events.registered_handlers['stop_mode2']:
            if handler.callback == self.machine.modes.mode2.stop:
                found_it = True
                # base priority 100, +1 default bump, +2 stop_priority config
                self.assertEqual(handler.priority, 103)
        self.assertTrue(found_it)

        # pass a priority at start
        self.machine.modes.mode1.stop()
        self.advance_time_and_run()
        self.machine.modes.mode1.start(mode_priority=500)
        self.advance_time_and_run()
        self.assertEqual(self.machine.modes.mode1.priority, 500)
        self.advance_time_and_run()

        # test the order of the active modes list
        self.assertEqual(self.machine.modes.mode1,
                         self.machine.mode_controller.active_modes[0])
        self.assertEqual(self.machine.modes.mode2,
                         self.machine.mode_controller.active_modes[1])
        self.assertEqual(self.machine.modes.attract,
                         self.machine.mode_controller.active_modes[2])

    def test_mode_start_with_callback(self):
        self.mode_start_callback = MagicMock()

        self.machine.modes.mode1.start(callback=self.mode_start_callback)
        self.advance_time_and_run()
        self.mode_start_callback.assert_called_once_with()

    def test_use_wait_queue(self):
        self.callback = MagicMock()
        self.machine.events.post_queue('start_mode4',
                                       callback=self.callback)
        self.advance_time_and_run()

        # make sure the mode started
        self.assertTrue(self.machine.modes.mode4.active)
        self.advance_time_and_run()

        # callback should not be called since mode is set to use wait queue
        self.callback.assert_not_called()

        self.machine.modes.mode4.stop()
        self.advance_time_and_run()

        # once mode stops, verify that callback was called
        self.callback.assert_called_once_with()

    def test_ball_end(self):
        # mode1 is set to keep running on ball end
        # mode2 should stop and restart on ball end
        # mode3 should stop and stay stopped
        self.assertFalse(self.machine.modes.mode1.config['mode']['stop_on_ball_end'])
        self.assertTrue(self.machine.modes.mode2.config['mode']['stop_on_ball_end'])
        self.assertTrue(self.machine.modes.mode3.config['mode']['stop_on_ball_end'])

        # start a game
        self.machine.playfield.add_ball = MagicMock()
        self.machine.events.post('game_start')
        self.advance_time_and_run()
        self.machine.game.balls_in_play = 1
        self.assertTrue(self.machine.game)

        # start some modes
        self.machine.modes.mode1.start()
        self.machine.modes.mode2.start()
        self.machine.modes.mode3.start()
        self.advance_time_and_run()
        self.assertTrue(self.machine.modes.mode1.active)
        self.assertTrue(self.machine.modes.mode2.active)
        self.assertTrue(self.machine.modes.mode3.active)

        # change the config of modes 1 and 2 so we can verify whether they
        # actually stopped and restarted since the configs are used to start
        # the modes
        self.machine.modes.mode1.config['mode']['priority'] = 999
        self.machine.modes.mode2.config['mode']['priority'] = 999

        # end the ball
        self.machine.game.end_ball()
        self.advance_time_and_run()

        self.assertTrue(self.machine.modes.mode1.active)
        self.assertTrue(self.machine.modes.mode2.active)
        self.assertFalse(self.machine.modes.mode3.active)

        # since mode1 should have stayed running, its config should not change
        self.assertNotEqual(self.machine.modes.mode1.priority, 999)
        # mode2 should use the new priority since it should have restarted
        self.assertEqual(self.machine.modes.mode2.priority, 999)

        # end ball 2
        self.machine.game.end_ball()
        self.advance_time_and_run()

        # end ball 3 and end the game
        self.machine.game.end_ball()
        self.advance_time_and_run()

        self.assertTrue(self.machine.modes.attract.active)
        self.assertFalse(self.machine.modes.game.active)
        self.assertTrue(self.machine.modes.mode1.active)
        self.assertFalse(self.machine.modes.mode2.active)
        self.assertFalse(self.machine.modes.mode3.active)
<|endoftext|>


<commit_before>"""
MPP Solar Inverter Command Library
reference library of serial commands (and responses) for PIP-4048MS inverters
mppcommands.py
"""

import serial
import time
import re
import logging
import json
import glob
import os
# from pprint import pprint
from os import path
from argparse import ArgumentParser

from .mppcommand import mppCommand

logger = logging.getLogger()

class MppSolarError(Exception):
    pass

class NoDeviceError(MppSolarError):
    pass

class NoTestResponseDefined(MppSolarError):
    pass

# Read in all the json files in the commands subdirectory
# this builds a list of all valid commands
COMMANDS = []
here = path.abspath(path.dirname(__file__))
files = glob.glob(here + '/commands/*.json')
for file in sorted(files):
    with open(file) as f:
        try:
            data = json.load(f)
        except Exception as e:
            print("Error processing JSON in {}".format(file))
            print(e)
        # print("Command: {} ({}) - expects {} response(s) [regex: {}]".format(data['name'], data['description'], len(data['response']), data['regex']))
        if data['regex']:
            regex = re.compile(data['regex'])
        else:
            regex = None
        COMMANDS.append(mppCommand(data['name'], data['description'], data['type'], data['response'], data['test_responses'], regex))

def trunc(text):
    """
    Truncates / right pads supplied text
    """
    if len(text) >= 30:
        text = text[:30]
        return '{:<30}...'.format(text)
    return '{:<30}   '.format(text)

def getKnownCommands():
    """
    Provides a human readable list of all defined commands
    """
    msgs = []
    msgs.append('-------- List of known commands --------')
    for cmd in COMMANDS:
        msgs.append('{}: {}'.format(cmd.name, cmd.description))
    return msgs

def getCommand(cmd):
    """
    Returns the mppcommand object of the supplied cmd string
    """
    logging.debug("Searching for cmd '{}'".format(cmd))
    for command in COMMANDS:
        if not command.regex:
            if cmd == command.name:
                return command
        else:
            match = command.regex.match(cmd)
            if match:
                logging.debug(command.name, command.regex)
                logging.debug("Matched: {} Value: {}".format(command.name, match.group(1)))
                command.set_value(match.group(1))
                return command
    return None

class mppCommands:
    """
    MPP Solar Inverter Command Library
    """

    def __init__(self, serial_device=None, baud_rate=2400):
        if (serial_device is None):
            raise NoDeviceError("A device to communicate by must be supplied, e.g. /dev/ttyUSB0")
        self._baud_rate = baud_rate
        self._serial_device = serial_device

    def is_rawdevice(self):
        """
        Determine if this instance is using direct USB connection
        (instead of a serial connection)
        """
        ##### TODO: expand usb definition
        if (self._serial_device is None):
            return False
        if (self._serial_device == '/dev/hidraw0'):
            return true
        return false

    def getKnownCommands(self):
        """
        Return list of defined commands
        """
        return getKnownCommands()

    def doSerialCommand(self, command):
        """
        Opens serial connection, sends command (multiple times if needed)
        and returns the response
        """
        response_line = None
        logging.debug('port %s, baudrate %s', self._serial_device, self._baud_rate)
        if (self._serial_device == 'TEST'):
            # Return a valid response if _serial_device is TEST
            # - for those commands that have test responses defined
            # print "TEST"
            # print command.get_test_response()
            command.set_response(command.get_test_response())
            return command
        elif (self.is_rawdevice()):
            #Do stuff with usb...
            usb0 = os.open(self._serial_device, os.O_RDWR | os.O_NONBLOCK)
            response_line = ""
            #for x in (1, 2, 3, 4):
            command_crc = command.full_command
            if len(command_crc) < 9:
                time.sleep(0.35)
                os.write(usb0, command_crc)
            else:
                cmd1 = command_crc[:8]
                cmd2 = command_crc[8:]
                time.sleep(0.35)
                os.write(usb0, cmd1)
                time.sleep(0.35)
                os.write(usb0, cmd2)
                time.sleep(0.25)

            while True:
                time.sleep(0.15)
                r = os.read(usb0, 256)
                print("USB read.....")
                print(r)
                response_line += r
                if '\r' in r: break
            logging.debug('usb response was: %s', response_line)
            if command.is_response_valid(response_line):
                command.set_response(response_line)
                # return response without the start byte and the crc
                return command

        else:
            with serial.serial_for_url(self._serial_device, self._baud_rate) as s:
            # Execute command multiple times, increase timeouts each time
            for x in (1, 2, 3, 4):
                logging.debug('Command execution attempt %d...', x)
                s.timeout = 1 + x
                s.write_timeout = 1 + x
                s.flushInput()
                s.flushOutput()
                s.write(command.full_command)
                time.sleep(0.5 * x)  # give serial port time to receive the data
                response_line = s.readline()
                logging.debug('serial response was: %s', response_line)
                if command.is_response_valid(response_line):
                    command.set_response(response_line)
                    # return response without the start byte and the crc
                    return command
        logging.critical('Command execution failed')
        return None

    def execute(self, cmd):
        """
        Sends a command (as supplied) to inverter and returns the raw response
        """
        command = getCommand(cmd)
        if command is None:
            logging.critical("Command not found")
            return None
        else:
            logging.debug("Command valid {}".format(command.name))
            logging.debug('called: execute with query %s', command)
            return self.doSerialCommand(command)

if __name__ == '__main__':
    parser = ArgumentParser(description='MPP Solar Command Utility')
    parser.add_argument('-c', '--command', help='Command to run', default='QID')
    args = parser.parse_args()

    logging.basicConfig(level='DEBUG')

    mp = mppCommands("TEST")
    cmd = mp.execute(args.command)
    print("response: ", cmd.response)
    # print len(cmd.response_definition)
    print("valid? ", cmd.valid_response)
    print("response_dict: ", cmd.response_dict)
    # for line in getKnownCommands():
    #    print line
<commit_msg>fix indentation<commit_after>"""
MPP Solar Inverter Command Library
reference library of serial commands (and responses) for PIP-4048MS inverters
mppcommands.py
"""

import serial
import time
import re
import logging
import json
import glob
import os
# from pprint import pprint
from os import path
from argparse import ArgumentParser

from .mppcommand import mppCommand

logger = logging.getLogger()

class MppSolarError(Exception):
    pass

class NoDeviceError(MppSolarError):
    pass

class NoTestResponseDefined(MppSolarError):
    pass

# Read in all the json files in the commands subdirectory
# this builds a list of all valid commands
COMMANDS = []
here = path.abspath(path.dirname(__file__))
files = glob.glob(here + '/commands/*.json')
for file in sorted(files):
    with open(file) as f:
        try:
            data = json.load(f)
        except Exception as e:
            print("Error processing JSON in {}".format(file))
            print(e)
        # print("Command: {} ({}) - expects {} response(s) [regex: {}]".format(data['name'], data['description'], len(data['response']), data['regex']))
        if data['regex']:
            regex = re.compile(data['regex'])
        else:
            regex = None
        COMMANDS.append(mppCommand(data['name'], data['description'], data['type'], data['response'], data['test_responses'], regex))

def trunc(text):
    """
    Truncates / right pads supplied text
    """
    if len(text) >= 30:
        text = text[:30]
        return '{:<30}...'.format(text)
    return '{:<30}   '.format(text)

def getKnownCommands():
    """
    Provides a human readable list of all defined commands
    """
    msgs = []
    msgs.append('-------- List of known commands --------')
    for cmd in COMMANDS:
        msgs.append('{}: {}'.format(cmd.name, cmd.description))
    return msgs

def getCommand(cmd):
    """
    Returns the mppcommand object of the supplied cmd string
    """
    logging.debug("Searching for cmd '{}'".format(cmd))
    for command in COMMANDS:
        if not command.regex:
            if cmd == command.name:
                return command
        else:
            match = command.regex.match(cmd)
            if match:
                logging.debug(command.name, command.regex)
                logging.debug("Matched: {} Value: {}".format(command.name, match.group(1)))
                command.set_value(match.group(1))
                return command
    return None

class mppCommands:
    """
    MPP Solar Inverter Command Library
    """

    def __init__(self, serial_device=None, baud_rate=2400):
        if (serial_device is None):
            raise NoDeviceError("A device to communicate by must be supplied, e.g. /dev/ttyUSB0")
        self._baud_rate = baud_rate
        self._serial_device = serial_device

    def is_rawdevice(self):
        """
        Determine if this instance is using direct USB connection
        (instead of a serial connection)
        """
        ##### TODO: expand usb definition
        if (self._serial_device is None):
            return False
        if (self._serial_device == '/dev/hidraw0'):
            return true
        return false

    def getKnownCommands(self):
        """
        Return list of defined commands
        """
        return getKnownCommands()

    def doSerialCommand(self, command):
        """
        Opens serial connection, sends command (multiple times if needed)
        and returns the response
        """
        response_line = None
        logging.debug('port %s, baudrate %s', self._serial_device, self._baud_rate)
        if (self._serial_device == 'TEST'):
            # Return a valid response if _serial_device is TEST
            # - for those commands that have test responses defined
            # print "TEST"
            # print command.get_test_response()
            command.set_response(command.get_test_response())
            return command
        elif (self.is_rawdevice()):
            #Do stuff with usb...
            usb0 = os.open(self._serial_device, os.O_RDWR | os.O_NONBLOCK)
            response_line = ""
            #for x in (1, 2, 3, 4):
            command_crc = command.full_command
            if len(command_crc) < 9:
                time.sleep(0.35)
                os.write(usb0, command_crc)
            else:
                cmd1 = command_crc[:8]
                cmd2 = command_crc[8:]
                time.sleep(0.35)
                os.write(usb0, cmd1)
                time.sleep(0.35)
                os.write(usb0, cmd2)
                time.sleep(0.25)

            while True:
                time.sleep(0.15)
                r = os.read(usb0, 256)
                print("USB read.....")
                print(r)
                response_line += r
                if '\r' in r: break
            logging.debug('usb response was: %s', response_line)
            if command.is_response_valid(response_line):
                command.set_response(response_line)
                # return response without the start byte and the crc
                return command

        else:
            with serial.serial_for_url(self._serial_device, self._baud_rate) as s:
            # Execute command multiple times, increase timeouts each time
                for x in (1, 2, 3, 4):
                    logging.debug('Command execution attempt %d...', x)
                    s.timeout = 1 + x
                    s.write_timeout = 1 + x
                    s.flushInput()
                    s.flushOutput()
                    s.write(command.full_command)
                    time.sleep(0.5 * x)  # give serial port time to receive the data
                    response_line = s.readline()
                    logging.debug('serial response was: %s', response_line)
                    if command.is_response_valid(response_line):
                        command.set_response(response_line)
                        # return response without the start byte and the crc
                        return command
        logging.critical('Command execution failed')
        return None

    def execute(self, cmd):
        """
        Sends a command (as supplied) to inverter and returns the raw response
        """
        command = getCommand(cmd)
        if command is None:
            logging.critical("Command not found")
            return None
        else:
            logging.debug("Command valid {}".format(command.name))
            logging.debug('called: execute with query %s', command)
            return self.doSerialCommand(command)

if __name__ == '__main__':
    parser = ArgumentParser(description='MPP Solar Command Utility')
    parser.add_argument('-c', '--command', help='Command to run', default='QID')
    args = parser.parse_args()

    logging.basicConfig(level='DEBUG')

    mp = mppCommands("TEST")
    cmd = mp.execute(args.command)
    print("response: ", cmd.response)
    # print len(cmd.response_definition)
    print("valid? ", cmd.valid_response)
    print("response_dict: ", cmd.response_dict)
    # for line in getKnownCommands():
    #    print line
<|endoftext|>


<commit_before>"""log object instantiation of (almost) all python classes

Import the module using ``from mtoolbox import instancelog``

Note:
    You have to run ``enable()`` BEFORE importing
    the module, which has classes you would like to log.
    The reason for this is, that the name ``object`` from the
    ``__builtin__`` namespace has to point to the object class overwrite
    of the instancelog module, when a new class is defined. For the same
    reason builtin objects will never be logged.

Example:

In this example ``MyClass1`` objects will not be logged, while
``MyClass2`` objects will be logged:

>>> import instancelog
>>> class MyClass1(object):
...     def __repr__(self):
...         return 'MyClass1 object'
>>> instancelog.enable()
>>> class MyClass2(object):
...     def __repr__(self):
...         return 'MyClass2 object'
>>> objlist = []
>>> def my_callback(obj, cls, args, kwargs):
...   objlist.append(obj)
>>> instancelog.callbacks.append(my_callback)
>>> obj1 = MyClass1()
>>> obj2 = MyClass2()
>>> print(objlist)
[MyClass2 object]
"""

import sys

if sys.version_info[0] == 2:
    import __builtin__ as builtins
else:
    import builtins

_object = object
callbacks = []

class Object(object):
    """Class to replace (builtin) object"""
    def __new__(cls, *args, **kwargs):
        obj = _object.__new__(cls, *args, **kwargs)
        for func in callbacks:
            func(obj, cls, args, kwargs)
        return obj

def enable():
    """Enable the logging of objects."""
    builtins.object = Object

def disable():
    """Disable the logging of objects."""
    builtins.object = _object

if __name__ == '__main__':
    import doctest
    doctest.testmod()
<commit_msg>Still fixing the bux in doctest for instancelog...<commit_after>"""log object instantiation of (almost) all python classes

Import the module using ``from mtoolbox import instancelog``

Note:
    You have to run ``enable()`` BEFORE importing
    the module, which has classes you would like to log.
    The reason for this is, that the name ``object`` from the
    ``__builtin__`` namespace has to point to the object class overwrite
    of the instancelog module, when a new class is defined. For the same
    reason builtin objects will never be logged.

Example:

In this example ``MyClass1`` objects will not be logged, while
``MyClass2`` objects will be logged:

>>> from . import instancelog
>>> class MyClass1(object):
...     def __repr__(self):
...         return 'MyClass1 object'
>>> instancelog.enable()
>>> class MyClass2(object):
...     def __repr__(self):
...         return 'MyClass2 object'
>>> objlist = []
>>> def my_callback(obj, cls, args, kwargs):
...   objlist.append(obj)
>>> instancelog.callbacks.append(my_callback)
>>> obj1 = MyClass1()
>>> obj2 = MyClass2()
>>> print(objlist)
[MyClass2 object]
"""

import sys

if sys.version_info[0] == 2:
    import __builtin__ as builtins
else:
    import builtins

_object = object
callbacks = []

class Object(object):
    """Class to replace (builtin) object"""
    def __new__(cls, *args, **kwargs):
        obj = _object.__new__(cls, *args, **kwargs)
        for func in callbacks:
            func(obj, cls, args, kwargs)
        return obj

def enable():
    """Enable the logging of objects."""
    builtins.object = Object

def disable():
    """Disable the logging of objects."""
    builtins.object = _object

if __name__ == '__main__':
    import doctest
    doctest.testmod()
<|endoftext|>


<commit_before>"""
multiplication-table.py
Author: Roger Danilek
Credit: <list sources used, if any>
Assignment:

Write and submit a Python program that prints a multiplication table. The user
must be able to determine the width and height of the table before it is printed.

The final multiplication table should look like this:

Width of multiplication table: 10
Height of multiplication table: 8

  1   2   3   4   5   6   7   8   9  10
  2   4   6   8  10  12  14  16  18  20
  3   6   9  12  15  18  21  24  27  30
  4   8  12  16  20  24  28  32  36  40
  5  10  15  20  25  30  35  40  45  50
  6  12  18  24  30  36  42  48  54  60
  7  14  21  28  35  42  49  56  63  70
  8  16  24  32  40  48  56  64  72  80
"""

a = int(input("Width of multiplication table: "))
b = int(input("Height of multiplication table: "))
for l in range(1,a):
    for i in range(1,b):
        print("{0:>3}".format(i*l), end=' ')
        <commit_msg>Updated from Brython Server: 9/21/2015 2:42:45 PM<commit_after>"""
multiplication-table.py
Author: Roger Danilek
Credit: <list sources used, if any>
Assignment:

Write and submit a Python program that prints a multiplication table. The user
must be able to determine the width and height of the table before it is printed.

The final multiplication table should look like this:

Width of multiplication table: 10
Height of multiplication table: 8

  1   2   3   4   5   6   7   8   9  10
  2   4   6   8  10  12  14  16  18  20
  3   6   9  12  15  18  21  24  27  30
  4   8  12  16  20  24  28  32  36  40
  5  10  15  20  25  30  35  40  45  50
  6  12  18  24  30  36  42  48  54  60
  7  14  21  28  35  42  49  56  63  70
  8  16  24  32  40  48  56  64  72  80
"""

a = int(input("Width of multiplication table: "))
b = int(input("Height of multiplication table: "))
for l in range(1,a+1):
    for i in range(1,b+1):
        print("{0:>3}".format(i*l), end=' ')
        <|endoftext|>


<commit_before>"""
multiplication-table.py
Author: Payton
Credit: Ethan
Assignment:

Write and submit a Python program that prints a multiplication table. The user
must be able to determine the width and height of the table before it is printed.

The final multiplication table should look like this:

Width of multiplication table: 10
Height of multiplication table: 8

  1   2   3   4   5   6   7   8   9  10
  2   4   6   8  10  12  14  16  18  20
  3   6   9  12  15  18  21  24  27  30
  4   8  12  16  20  24  28  32  36  40
  5  10  15  20  25  30  35  40  45  50
  6  12  18  24  30  36  42  48  54  60
  7  14  21  28  35  42  49  56  63  70
  8  16  24  32  40  48  56  64  72  80
"""
ten = [1 2 3 4 5 6 7 8 9 10]
print(ten)<commit_msg>Updated from Brython Server: 2/4/2016 2:28:52 PM<commit_after>"""
multiplication-table.py
Author: Payton
Credit: Ethan
Assignment:

Write and submit a Python program that prints a multiplication table. The user
must be able to determine the width and height of the table before it is printed.

The final multiplication table should look like this:

Width of multiplication table: 10
Height of multiplication table: 8

  1   2   3   4   5   6   7   8   9  10
  2   4   6   8  10  12  14  16  18  20
  3   6   9  12  15  18  21  24  27  30
  4   8  12  16  20  24  28  32  36  40
  5  10  15  20  25  30  35  40  45  50
  6  12  18  24  30  36  42  48  54  60
  7  14  21  28  35  42  49  56  63  70
  8  16  24  32  40  48  56  64  72  80
"""
wq = int(float("What is the width of the multiplication table? ")))
hq = int(float("What is the height of the multiplication table? ")))

for y in height:
    print(" ")
    for x in width:
        print(y*x, " ", end = <|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright (C) 2013-Today  Carlos Eduardo Vercelino - CLVsol
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

from __future__ import print_function

import sqlite3

def address_category_export_sqlite(client, args, db_path, table_name):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute('''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            parent_id,
            name,
            code,
            description,
            notes,
            color,
            new_id INTEGER
            );
    ''')

    myo_address_category = client.model('myo.address.category')
    address_category_browse = myo_address_category.browse(args)

    address_category_count = 0
    for address_category in address_category_browse:
        address_category_count += 1

        print(
            address_category_count, address_category.id, address_category.code,
            address_category.name.encode("utf-8"), address_category.notes
        )

        parent_id = None
        if address_category.parent_id:
            parent_id = address_category.parent_id.id

        notes = None
        if address_category.notes:
            notes = address_category.notes

        color = None
        if address_category.color:
            color = address_category.color

        cursor.execute('''
                       INSERT INTO ''' + table_name + '''(
                           id,
                           parent_id,
                           name,
                           code,
                           description,
                           notes,
                           color
                           )
                       VALUES(?,?,?,?,?,?,?)''',
                       (address_category.id,
                        parent_id,
                        address_category.name,
                        address_category.code,
                        address_category.description,
                        notes,
                        color
                        )
                       )

    conn.commit()
    conn.close()

    print()
    print('--> address_category_count: ', address_category_count)
<commit_msg>[IMP] myo_address_category.py<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
#
# Copyright (C) 2013-Today  Carlos Eduardo Vercelino - CLVsol
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

from __future__ import print_function

import sqlite3

def address_category_export_sqlite(client, args, db_path, table_name):

    conn = sqlite3.connect(db_path)
    conn.text_factory = str

    cursor = conn.cursor()
    try:
        cursor.execute('''DROP TABLE ''' + table_name + ''';''')
    except Exception as e:
        print('------->', e)
    cursor.execute('''
        CREATE TABLE ''' + table_name + ''' (
            id INTEGER NOT NULL PRIMARY KEY,
            parent_id,
            name,
            code,
            description,
            notes,
            color,
            new_id INTEGER
            );
    ''')

    myo_address_category = client.model('myo.address.category')
    address_category_browse = myo_address_category.browse(args)

    address_category_count = 0
    for address_category in address_category_browse:
        address_category_count += 1

        print(
            address_category_count, address_category.id, address_category.code,
            address_category.name.encode("utf-8"), address_category.notes
        )

        parent_id = None
        if address_category.parent_id:
            parent_id = address_category.parent_id.id

        notes = None
        if address_category.notes:
            notes = address_category.notes

        color = None
        if address_category.color:
            color = address_category.color

        cursor.execute('''
                       INSERT INTO ''' + table_name + '''(
                           id,
                           parent_id,
                           name,
                           code,
                           description,
                           notes,
                           color
                           )
                       VALUES(?,?,?,?,?,?,?)''',
                       (address_category.id,
                        parent_id,
                        address_category.name,
                        address_category.code,
                        address_category.description,
                        notes,
                        color
                        )
                       )

    conn.commit()
    conn.close()

    print()
    print('--> address_category_count: ', address_category_count)

def address_category_import_sqlite(client, args, db_path, table_name):

    address_category_model = client.model('myo.address.category')

    conn = sqlite3.connect(db_path)
    # conn.text_factory = str
    conn.row_factory = sqlite3.Row

    cursor = conn.cursor()

    cursor2 = conn.cursor()

    data = cursor.execute('''
        SELECT
            id,
            parent_id,
            name,
            code,
            description,
            notes,
            color,
            new_id
        FROM ''' + table_name + ''';
    ''')

    print(data)
    print([field[0] for field in cursor.description])

    address_category_count = 0
    for row in cursor:
        address_category_count += 1

        print(
            address_category_count, row['id'], row['parent_id'], row['name'], row['code'],
            row['description'], row['notes'], row['color']
        )

        values = {
            'name': row['name'],
            'code': row['code'],
            'description': row['description'],
            'notes': row['notes'],
            'color': row['color'],
        }
        address_category_id = address_category_model.create(values).id

        cursor2.execute(
            '''
            UPDATE ''' + table_name + '''
            SET new_id = ?
            WHERE id = ?;''',
            (address_category_id,
             row['id']
             )
        )

    conn.commit()

    data = cursor.execute('''
        SELECT
            id,
            parent_id,
            name,
            code,
            description,
            notes,
            color,
            new_id
        FROM ''' + table_name + '''
        WHERE parent_id IS NOT NULL;
    ''')

    address_category_count_2 = 0
    for row in cursor:
        address_category_count_2 += 1

        print(address_category_count_2, row['id'], row['parent_id'], row['name'], row['code'], row['new_id'])

        cursor2.execute(
            '''
            SELECT new_id
            FROM ''' + table_name + '''
            WHERE id = ?;''',
            (row['parent_id'],
             )
        )
        new_parent_id = cursor2.fetchone()[0]

        print('>>>>>', row['id'], row['new_id'], row['parent_id'], new_parent_id)

        values = {
            'parent_id': new_parent_id,
        }
        address_category_model.write(row['new_id'], values)

    conn.commit()
    conn.close()

    print()
    print('--> address_category_count: ', address_category_count)
    print('--> address_category_count_2: ', address_category_count_2)
<|endoftext|>


<commit_before>from django.core.mail import send_mail
import socket
from mysite.search.models import Project, ProjectInvolvementQuestion, Answer
from mysite.profile.models import Person
import mysite.project.controllers
import django.template
import mysite.base.decorators
import mysite.profile.views
import mysite.project.forms

from django.http import HttpResponse, HttpResponseRedirect, \
        HttpResponsePermanentRedirect, HttpResponseServerError, HttpResponseBadRequest
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.template.loader import render_to_string

import random

def create_project_page_do(request):
    project_name = request.POST.get('project_name', None)
    if project_name:
        matches = Project.objects.filter(name__iexact=project_name)
        if matches:
            our_project = matches[0]
        else:
            our_project, was_created = Project.objects.get_or_create(name=project_name)
        return HttpResponseRedirect(our_project.get_url())

    return HttpResponseBadRequest('Bad request')

@mysite.base.decorators.view
def project(request, project__name = None):
    p = get_object_or_404(Project, name=project__name)

    if (request.user.is_authenticated() and
        request.user.get_profile() in p.people_who_wanna_help.all()):
        user_wants_to_help = True
    else:
        user_wants_to_help = False

    wanna_help = (bool(request.GET.get('wanna_help', False)) and
                  user_wants_to_help)

    pfentries = p.portfolioentry_set.exclude(project_description='')
    only_good_pfentries = lambda pfe: pfe.project_description.strip()
    pfentries = filter(only_good_pfentries, pfentries)

    context = {}
    if pfentries:
        context['random_pfentry'] = random.choice(pfentries)

    # If description is too popular, and there are alternatives,
    # don't use the popular description. (This avoids a feeling of
    # 'Oh, everybody wrote the same thing.')
    # Calculate popularity case-insensitively.

    context['people'] = [pfe.person for pfe in pfentries]

    # Get or create two paragraph-y questions.
    questions = [
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='where_to_start', is_bug_style=False)[0],
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='non_code_participation', is_bug_style=True)[0],
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='newcomers', is_bug_style=True)[0],
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='stress', is_bug_style=True)[0],
    ]
    context['question2answer'] = [(question, question.get_answers_for_project(p))
        for question in questions]

    if request.GET.get('cookies', '') == 'disabled':
        context['cookies_disabled'] = True

    if wanna_help:
        people_to_show = list(p.people_who_wanna_help.exclude(user=request.user))
        people_to_show.insert(0, request.user.get_profile())
    else:
        people_to_show = p.people_who_wanna_help.all()

    button_widget_data = mysite.base.controllers.get_uri_metadata_for_generating_absolute_links(request)
    button_widget_data['project'] = p
    button_as_widget_source = render_to_string(
        'project/button_as_widget.html', button_widget_data)

    context.update({
        'project': p,
        'contributors': p.get_contributors()[:3],
        'mentors': (mysite.profile.controllers.people_matching(
            'can_mentor', project__name)),
        'language_mentors': (mysite.profile.controllers.people_matching(
            'can_mentor', p.language)),
        'explain_to_anonymous_users': True,
        'wanna_help_form': mysite.project.forms.WannaHelpForm(),
        'user_wants_to_help': request.user.is_authenticated() and request.user.get_profile() in p.people_who_wanna_help.all(),
        'user_just_signed_up_as_wants_to_help': wanna_help,
        'people_to_show': people_to_show,
        'button_as_widget_source': button_as_widget_source,
        })

    question_suggestion_response = request.GET.get('question_suggestion_response', None)
    context['notifications'] = []
    if question_suggestion_response == 'success':
        context['notifications'].append({
            'id': 'question_suggestion_response',
            'text': 'Thanks for your suggestion!'
            })
    elif question_suggestion_response == 'failure':
        context['notifications'].append({
            'id': 'question_suggestion_response',
            'text': "Oops, there was an error submitting your suggested question--we probably couldn't connect to our outgoing mailserver. Try just sending an email to hello@openhatch.org"
            })

    return (request,
            'project/project.html',
            context)

from django.views.decorators.cache import cache_page
@cache_page(60 * 15)

def projects(request):
    data = {}
    query = request.GET.get('q', '')
    matching_projects = []
    project_matches_query_exactly = False
    if query:
        query = query.strip()
        matching_projects = mysite.project.controllers.similar_project_names(
            query)
        project_matches_query_exactly = query.lower() in [p.name.lower() for p in matching_projects]
        if len(matching_projects) == 1 and project_matches_query_exactly:
            return HttpResponseRedirect(matching_projects[0].get_url())

    if not query:
        data['projects_with_bugs'] = mysite.search.controllers.get_projects_with_bugs()
        data['cited_projects_lacking_bugs'] = (mysite.search.controllers.
                get_cited_projects_lacking_bugs())

    data.update({
            'query': query,
            'matching_projects': matching_projects,
            'no_project_matches_query_exactly': not project_matches_query_exactly,
            'explain_to_anonymous_users': True
            })
    return mysite.base.decorators.as_view(request, "project/projects.html", data,
            slug=projects.__name__)

def redirect_project_to_projects(request, project__name):
    new_url = reverse(project, kwargs={'project__name': project__name})
    return HttpResponsePermanentRedirect(new_url)

@login_required
def delete_paragraph_answer_do(request):
    answer__pk = request.POST['answer__pk']
    # grab the answer from the database.  delete it.  done.
    our_answer = Answer.objects.get(pk=answer__pk, author=request.user)
    our_answer.delete()
    return HttpResponseRedirect(reverse(project, kwargs={'project__name': our_answer.project.name}))

def create_answer_do(request):

    if 'is_edit' in request.POST:
        answer = Answer.objects.get(pk=request.POST['answer__pk'])
    else:
        answer = Answer()

    answer.project = mysite.search.models.Project.objects.get(pk=request.POST['project__pk'])

    question = ProjectInvolvementQuestion.objects.get(pk=request.POST['question__pk'])
    question.save()
    answer.question = question

    answer.text = request.POST['answer__text']

    answer.title = request.POST.get('answer__title', None)

    # loltrolled--you dont have cookies, so we will throw away your data at the last minute
    if (request.user.is_authenticated() or
        'cookies_work' in request.session):
        suffix = ''
    else:
        suffix = '?cookies=disabled'
        return HttpResponseRedirect(reverse(project, kwargs={'project__name': answer.project.name}) + suffix)

    answer.save()
    if answer.author is None:
        mysite.project.controllers.note_in_session_we_control_answer_id(request.session,
                                                                        answer.pk)
    if not request.user.is_authenticated():
        # If user isn't logged in, send them to the login page with next
        # parameter populated.
        url = reverse('oh_login')
        url += "?" + mysite.base.unicode_sanity.urlencode({u'next':
            unicode(answer.project.get_url())})
        return HttpResponseRedirect(url)
    else:
        answer.author = request.user

    return HttpResponseRedirect(reverse(project, kwargs={'project__name': answer.project.name}) + suffix)

@login_required
@mysite.base.decorators.view
def suggest_question(request):
    template = "project/suggest_question.html"
    data = {
            'project__pk': request.GET['project__pk']
            }
    return (request, template, data)

@login_required
def suggest_question_do(request):
    project = mysite.search.models.Project.objects.get(pk=request.POST['project__pk'])
    user = request.user
    body = request.POST['suggested_question']
    body += "\nproject name: " + project.name
    body += "\nproject pk: " + str(project.pk)
    body += "\nuser name: " + user.username
    body += "\nuser pk: " + str(user.pk)
    question_suggestion_response = ""
    #TODO: Asheesh would really rather this be enqueued as a background job
    try:
        send_mail('Project Page Question Suggestion: ', body, 'all@openhatch.org', ['all@openhatch.org'], fail_silently=False)
        question_suggestion_response = "success"
    except socket.error:
        #NOTE: this will probably only happen on a local server (not on the live site)
        question_suggestion_response = "failure"
    template = "project/project.html"
    return HttpResponseRedirect(reverse(mysite.project.views.project, kwargs={'project__name': project.name}) + '?question_suggestion_response=' + question_suggestion_response)

def wanna_help_do(request):
    wanna_help_form = mysite.project.forms.WannaHelpForm(request.POST)
    if wanna_help_form.is_valid():
        project = wanna_help_form.cleaned_data['project']
    else:
        return HttpResponseBadRequest("No project id submitted.")

    if request.user.is_authenticated():
        person = request.user.get_profile()
        project.people_who_wanna_help.add(person)
        project.save()

        # Reindex the guy
        person.reindex_for_person_search()

        if request.is_ajax():
            people_to_show = list(project.people_who_wanna_help.exclude(user=request.user))
            people_to_show.insert(0, person)

            t = django.template.loader.get_template('project/project-wanna-help-box.html')
            c = django.template.Context({
                'project': project,
                'person': request.user.get_profile(),
                'people_to_show': people_to_show,
                'just_added_myself': True})
            rendered = t.render(c)
            return HttpResponse(rendered)
        else:
            return HttpResponseRedirect(project.get_url() + "?success=1")
    else:
        # Then store a note in the session...
        wanna_help_queue = request.session.get('projects_we_want_to_help_out', [])
        wanna_help_queue.append(project.id)
        request.session['projects_we_want_to_help_out'] = wanna_help_queue

        # If the user came from offsite, note that in the session too
        if wanna_help_form.cleaned_data['from_offsite']:
            request.session['from_offsite'] = True

        # If user isn't logged in, send them to the login page with next
        # parameter populated.
        url = reverse('oh_login')
        url += "?"
        if wanna_help_form.cleaned_data['from_offsite']:
            url += mysite.base.unicode_sanity.urlencode(
                {u'from_offsite': u'True'}) + '&'
        url += mysite.base.unicode_sanity.urlencode({u'next':
            unicode(project.get_url()) + '?wanna_help=true'})
        if request.is_ajax():
            return HttpResponse("redirect: " + url)
        else:
            return HttpResponseRedirect(url)

    if request.is_ajax():
        return HttpResponse("0")
    else:
        return HttpResponseRedirect(project.get_url() + "?success=0")

@login_required
def unlist_self_from_wanna_help_do(request):
    wanna_help_form = mysite.project.forms.WannaHelpForm(request.POST)
    if wanna_help_form.is_valid():
        project = wanna_help_form.cleaned_data['project']
        project.people_who_wanna_help.remove(request.user.get_profile())
        request.user.get_profile().reindex_for_person_search()
        return HttpResponseRedirect(project.get_url())
    else:
        return HttpResponseBadRequest("No project id submitted.")

@login_required
@mysite.base.decorators.view
def nextsteps4helpers(request):
    lucky_project = Project.objects.get(name='Ubuntu')
    context = {
            'the_lucky_project': lucky_project,
            'helpers': lucky_project.people_who_wanna_help.exclude(pk__exact=request.user.get_profile().pk)
            }
    return (request, "nextsteps4helpers.html", context)
<commit_msg>Remove from_offsite=True from URLs.<commit_after>from django.core.mail import send_mail
import socket
from mysite.search.models import Project, ProjectInvolvementQuestion, Answer
from mysite.profile.models import Person
import mysite.project.controllers
import django.template
import mysite.base.decorators
import mysite.profile.views
import mysite.project.forms

from django.http import HttpResponse, HttpResponseRedirect, \
        HttpResponsePermanentRedirect, HttpResponseServerError, HttpResponseBadRequest
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.template.loader import render_to_string

import random

def create_project_page_do(request):
    project_name = request.POST.get('project_name', None)
    if project_name:
        matches = Project.objects.filter(name__iexact=project_name)
        if matches:
            our_project = matches[0]
        else:
            our_project, was_created = Project.objects.get_or_create(name=project_name)
        return HttpResponseRedirect(our_project.get_url())

    return HttpResponseBadRequest('Bad request')

@mysite.base.decorators.view
def project(request, project__name = None):
    p = get_object_or_404(Project, name=project__name)

    if (request.user.is_authenticated() and
        request.user.get_profile() in p.people_who_wanna_help.all()):
        user_wants_to_help = True
    else:
        user_wants_to_help = False

    wanna_help = (bool(request.GET.get('wanna_help', False)) and
                  user_wants_to_help)

    pfentries = p.portfolioentry_set.exclude(project_description='')
    only_good_pfentries = lambda pfe: pfe.project_description.strip()
    pfentries = filter(only_good_pfentries, pfentries)

    context = {}
    if pfentries:
        context['random_pfentry'] = random.choice(pfentries)

    # If description is too popular, and there are alternatives,
    # don't use the popular description. (This avoids a feeling of
    # 'Oh, everybody wrote the same thing.')
    # Calculate popularity case-insensitively.

    context['people'] = [pfe.person for pfe in pfentries]

    # Get or create two paragraph-y questions.
    questions = [
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='where_to_start', is_bug_style=False)[0],
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='non_code_participation', is_bug_style=True)[0],
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='newcomers', is_bug_style=True)[0],
            ProjectInvolvementQuestion.objects.get_or_create(
                    key_string='stress', is_bug_style=True)[0],
    ]
    context['question2answer'] = [(question, question.get_answers_for_project(p))
        for question in questions]

    if request.GET.get('cookies', '') == 'disabled':
        context['cookies_disabled'] = True

    if wanna_help:
        people_to_show = list(p.people_who_wanna_help.exclude(user=request.user))
        people_to_show.insert(0, request.user.get_profile())
    else:
        people_to_show = p.people_who_wanna_help.all()

    button_widget_data = mysite.base.controllers.get_uri_metadata_for_generating_absolute_links(request)
    button_widget_data['project'] = p
    button_as_widget_source = render_to_string(
        'project/button_as_widget.html', button_widget_data)

    context.update({
        'project': p,
        'contributors': p.get_contributors()[:3],
        'mentors': (mysite.profile.controllers.people_matching(
            'can_mentor', project__name)),
        'language_mentors': (mysite.profile.controllers.people_matching(
            'can_mentor', p.language)),
        'explain_to_anonymous_users': True,
        'wanna_help_form': mysite.project.forms.WannaHelpForm(),
        'user_wants_to_help': request.user.is_authenticated() and request.user.get_profile() in p.people_who_wanna_help.all(),
        'user_just_signed_up_as_wants_to_help': wanna_help,
        'people_to_show': people_to_show,
        'button_as_widget_source': button_as_widget_source,
        })

    question_suggestion_response = request.GET.get('question_suggestion_response', None)
    context['notifications'] = []
    if question_suggestion_response == 'success':
        context['notifications'].append({
            'id': 'question_suggestion_response',
            'text': 'Thanks for your suggestion!'
            })
    elif question_suggestion_response == 'failure':
        context['notifications'].append({
            'id': 'question_suggestion_response',
            'text': "Oops, there was an error submitting your suggested question--we probably couldn't connect to our outgoing mailserver. Try just sending an email to hello@openhatch.org"
            })

    return (request,
            'project/project.html',
            context)

from django.views.decorators.cache import cache_page
@cache_page(60 * 15)

def projects(request):
    data = {}
    query = request.GET.get('q', '')
    matching_projects = []
    project_matches_query_exactly = False
    if query:
        query = query.strip()
        matching_projects = mysite.project.controllers.similar_project_names(
            query)
        project_matches_query_exactly = query.lower() in [p.name.lower() for p in matching_projects]
        if len(matching_projects) == 1 and project_matches_query_exactly:
            return HttpResponseRedirect(matching_projects[0].get_url())

    if not query:
        data['projects_with_bugs'] = mysite.search.controllers.get_projects_with_bugs()
        data['cited_projects_lacking_bugs'] = (mysite.search.controllers.
                get_cited_projects_lacking_bugs())

    data.update({
            'query': query,
            'matching_projects': matching_projects,
            'no_project_matches_query_exactly': not project_matches_query_exactly,
            'explain_to_anonymous_users': True
            })
    return mysite.base.decorators.as_view(request, "project/projects.html", data,
            slug=projects.__name__)

def redirect_project_to_projects(request, project__name):
    new_url = reverse(project, kwargs={'project__name': project__name})
    return HttpResponsePermanentRedirect(new_url)

@login_required
def delete_paragraph_answer_do(request):
    answer__pk = request.POST['answer__pk']
    # grab the answer from the database.  delete it.  done.
    our_answer = Answer.objects.get(pk=answer__pk, author=request.user)
    our_answer.delete()
    return HttpResponseRedirect(reverse(project, kwargs={'project__name': our_answer.project.name}))

def create_answer_do(request):

    if 'is_edit' in request.POST:
        answer = Answer.objects.get(pk=request.POST['answer__pk'])
    else:
        answer = Answer()

    answer.project = mysite.search.models.Project.objects.get(pk=request.POST['project__pk'])

    question = ProjectInvolvementQuestion.objects.get(pk=request.POST['question__pk'])
    question.save()
    answer.question = question

    answer.text = request.POST['answer__text']

    answer.title = request.POST.get('answer__title', None)

    # loltrolled--you dont have cookies, so we will throw away your data at the last minute
    if (request.user.is_authenticated() or
        'cookies_work' in request.session):
        suffix = ''
    else:
        suffix = '?cookies=disabled'
        return HttpResponseRedirect(reverse(project, kwargs={'project__name': answer.project.name}) + suffix)

    answer.save()
    if answer.author is None:
        mysite.project.controllers.note_in_session_we_control_answer_id(request.session,
                                                                        answer.pk)
    if not request.user.is_authenticated():
        # If user isn't logged in, send them to the login page with next
        # parameter populated.
        url = reverse('oh_login')
        url += "?" + mysite.base.unicode_sanity.urlencode({u'next':
            unicode(answer.project.get_url())})
        return HttpResponseRedirect(url)
    else:
        answer.author = request.user

    return HttpResponseRedirect(reverse(project, kwargs={'project__name': answer.project.name}) + suffix)

@login_required
@mysite.base.decorators.view
def suggest_question(request):
    template = "project/suggest_question.html"
    data = {
            'project__pk': request.GET['project__pk']
            }
    return (request, template, data)

@login_required
def suggest_question_do(request):
    project = mysite.search.models.Project.objects.get(pk=request.POST['project__pk'])
    user = request.user
    body = request.POST['suggested_question']
    body += "\nproject name: " + project.name
    body += "\nproject pk: " + str(project.pk)
    body += "\nuser name: " + user.username
    body += "\nuser pk: " + str(user.pk)
    question_suggestion_response = ""
    #TODO: Asheesh would really rather this be enqueued as a background job
    try:
        send_mail('Project Page Question Suggestion: ', body, 'all@openhatch.org', ['all@openhatch.org'], fail_silently=False)
        question_suggestion_response = "success"
    except socket.error:
        #NOTE: this will probably only happen on a local server (not on the live site)
        question_suggestion_response = "failure"
    template = "project/project.html"
    return HttpResponseRedirect(reverse(mysite.project.views.project, kwargs={'project__name': project.name}) + '?question_suggestion_response=' + question_suggestion_response)

def wanna_help_do(request):
    wanna_help_form = mysite.project.forms.WannaHelpForm(request.POST)
    if wanna_help_form.is_valid():
        project = wanna_help_form.cleaned_data['project']
    else:
        return HttpResponseBadRequest("No project id submitted.")

    if request.user.is_authenticated():
        person = request.user.get_profile()
        project.people_who_wanna_help.add(person)
        project.save()

        # Reindex the guy
        person.reindex_for_person_search()

        if request.is_ajax():
            people_to_show = list(project.people_who_wanna_help.exclude(user=request.user))
            people_to_show.insert(0, person)

            t = django.template.loader.get_template('project/project-wanna-help-box.html')
            c = django.template.Context({
                'project': project,
                'person': request.user.get_profile(),
                'people_to_show': people_to_show,
                'just_added_myself': True})
            rendered = t.render(c)
            return HttpResponse(rendered)
        else:
            return HttpResponseRedirect(project.get_url() + "?success=1")
    else:
        # Then store a note in the session...
        wanna_help_queue = request.session.get('projects_we_want_to_help_out', [])
        wanna_help_queue.append(project.id)
        request.session['projects_we_want_to_help_out'] = wanna_help_queue

        # If the user came from offsite, note that in the session too
        if wanna_help_form.cleaned_data['from_offsite']:
            request.session['from_offsite'] = True

        # If user isn't logged in, send them to the login page with next
        # parameter populated.
        url = reverse('oh_login')
        url += "?"
        url += mysite.base.unicode_sanity.urlencode({u'next':
            unicode(project.get_url()) + '?wanna_help=true'})
        if request.is_ajax():
            return HttpResponse("redirect: " + url)
        else:
            return HttpResponseRedirect(url)

    if request.is_ajax():
        return HttpResponse("0")
    else:
        return HttpResponseRedirect(project.get_url() + "?success=0")

@login_required
def unlist_self_from_wanna_help_do(request):
    wanna_help_form = mysite.project.forms.WannaHelpForm(request.POST)
    if wanna_help_form.is_valid():
        project = wanna_help_form.cleaned_data['project']
        project.people_who_wanna_help.remove(request.user.get_profile())
        request.user.get_profile().reindex_for_person_search()
        return HttpResponseRedirect(project.get_url())
    else:
        return HttpResponseBadRequest("No project id submitted.")

@login_required
@mysite.base.decorators.view
def nextsteps4helpers(request):
    lucky_project = Project.objects.get(name='Ubuntu')
    context = {
            'the_lucky_project': lucky_project,
            'helpers': lucky_project.people_who_wanna_help.exclude(pk__exact=request.user.get_profile().pk)
            }
    return (request, "nextsteps4helpers.html", context)
<|endoftext|>