<commit_before>import logging
logger = logging.getLogger(__name__)

from urlparse import urljoin

import eventlet

# Use Eventlet for parallel processing of HTTP requests
feedparser = eventlet.import_patched('feedparser')
from eventlet.green import urllib2

from lxml import html

from django.conf import settings
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError

from .models import Feed, FeedEntry, FeedContent, FeedEnclosure
from .utils import (
    datetime_from_struct, get_or_create_object, keywords_to_regex
)

def extract_xpath(url, xpath):
    """
    Extract XPath expression from the HTML at specified URL and return the
    HTML/text representation of its contents, with all links made absolute.
    """
    # Fetch and parse
    logger.debug(u'Fetching %s', url)

    # Use urllib2 directly for enabled SSL support (LXML doesn't by default)
    timeout = 30

    try:
        opener = urllib2.urlopen(url, None, timeout)

        # Fetch HTTP data in one batch, as handling the 'file-like' object to
        # lxml results in thread-locking behaviour.
        htmldata = opener.read()

    except urllib2.URLError, urllib2.HTTPError:
        # These type of errors are non-fatal - but *should* be logged.
        logger.exception(u'HTTP Error during XPath extraction for %s, returning emtpy string.',
            url
        )

        return ''

    # Parse
    logger.debug(u'Parsing HTML for %s', url)
    parsed = html.fromstring(htmldata, base_url=url)

    # Execute XPath
    logger.debug(u'Resolving XPath %s for %s', xpath, url)
    result = parsed.xpath(xpath)

    if not result:
        logger.warning(
            u'XPath %s did not return a value for %s, returning empty string.',
            xpath, url)

        return ''

    # If the result is already a string, we're done now
    if isinstance(result, basestring):
        return result

    # The result should ideally only contain a single element
    if len(result) > 1:
        logger.warning(
            u'XPath %s returned multiple elements for %s, ignoring all but '
            u' the first.'
        )

    # Take the first element in the XPath result set
    result = result[0]

    # Again, if the result is simply a string, we're done
    if isinstance(result, basestring):
        return result

    # From now on, we will assume it is some HTML element
    assert isinstance(result, html.HtmlMixin)

    # Make all links in the result absolute
    result.make_links_absolute(url)

    # Turn the result into a string
    result = html.tostring(result)

    return result

def filter_entry(feed, entry):
    """
    Return the result of applying filters to a feed entry. True when entry
    is to be included, False if the entry is to be discarded.
    """
    for feed_filter in feed.filters.filter(active=True):
        logger.debug(u'Applying filter %s to entry %s',
            feed_filter, entry.title
        )

        pattern = keywords_to_regex(feed_filter.keywords)

        if feed_filter.filter_inclusive:
            # Keep only matched entries

            if feed_filter.filter_title and \
                pattern.search(entry.title):

                # Pass: process next filter
                break

            if feed_filter.filter_summary and \
                pattern.search(entry.summary):

                # Pass: process next filter
                break

            # No match: discard entry
            return False

        else:
            # Exclusive filtering - discard matching entries
            if feed_filter.filter_title and \
                pattern.search(entry.title):

                # Match: discard this entry
                return False

            if feed_filter.filter_summary and \
                pattern.search(entry.summary):

                # Match: discard this entry
                return False

    # By default, include all entries
    return True

def update_entry(feed, entry):
    """ Update a specified entry for the feed. """

    # Consider whether or not to discard the item
    if not filter_entry(feed, entry):
        # Entry to be discarded - stop further processing
        logger.debug(u'Discarding entry %s', entry.title)

        # Possible problem: we might want to delete existing entries now
        # that they are filtered. Then again: we might not.
        return

    if 'id' in entry:
        logger.debug(u'Attempt matching by entry ID %s', entry.id)

        db_entry = get_or_create_object(
            FeedEntry, feed=feed, entry_id=entry.id)

    elif 'link' in entry:
        logger.debug(u'Attempt matching by entry link %s', entry.link)

        db_entry = get_or_create_object(
            FeedEntry, feed=feed, entry_id=None, link=entry.link)

    else:
        raise Exception('Could not identify entry by link or ID.')

    # Copy entry information
    db_entry.title = entry.title
    db_entry.link = entry.link
    db_entry.summary = entry.summary

    db_entry.author = getattr(db_entry, 'author', None)

    db_entry.published = datetime_from_struct(entry.published_parsed)

    # Only set updated when available - do not assume it to be there
    raw_updated_parsed = getattr(entry, 'updated_parsed', None)
    if raw_updated_parsed:
        db_entry.updated = datetime_from_struct(raw_updated_parsed)

    # Extraction of summary
    if feed.summary_xpath and (not db_entry.summary or feed.summary_override):
        extracted_summary = extract_xpath(entry.link, feed.summary_xpath)

        if extracted_summary:
            # Some value was found, add it to the entry
            db_entry.summary = extracted_summary

            logger.debug(u'Extracted summary for %s from %s',
                db_entry, entry.link
            )

    # Save it to the database
    # (Required before being able to link stuff like content/enclosures)
    db_entry.save()

    # Feed content
    if 'content' in entry:
        for entry_content in entry.content:
            # Even though standards require mimetype to be set,
            # we are going to assume only value is set - the absolute minimum.
            db_content = FeedContent(
                entry=db_entry,
                value=entry_content.value,
                mime_type=entry_content.type or '',
                language=entry_content.language or ''
            )
            db_content.save()

        logger.debug(u'%d contents added to entry %s',
            len(entry.content), db_entry)

    # Feed enclosures
    if 'enclosures' in entry:
        for entry_enclosure in entry.enclosures:
            # Even though standards require length and mimetype to be set,
            # we are going to assume only href is set - the absolute minimum.
            db_enclosure = FeedEnclosure(
                entry=db_entry,
                href=entry_enclosure.href,
                length=entry_enclosure.length or 0,
                mime_type=entry_enclosure.type or ''
            )
            db_enclosure.save()

        logger.debug(u'%d enclosures added to entry %s',
            len(entry.enclosures), db_entry)

    # Extraction of enclosures
    if feed.enclosure_xpath:
        extracted_href = extract_xpath(entry.link, feed.enclosure_xpath)

        # Make the resulting URL absolute
        extracted_href = urljoin(entry.link, extracted_href)

        # Only add if an enclosure with the same URL does not
        # already exist
        if FeedEnclosure.objects.filter(href=extracted_href).exists():
            logger.debug(
                u'Extracted enclosure with href \'%s\' already exists, not saving.',
                extracted_href
            )

        else:
            db_enclosure = FeedEnclosure(
                entry=db_entry,
                href=extracted_href,
                length=0,
                mime_type=feed.enclosure_mime_type
            )

            # Validate the results - the URL might be invalid
            try:
                db_enclosure.full_clean()

            except ValidationError:
                # Log the exception, don't save
                logger.exception(u'Error validating enclosure data.')

            else:
                # All went fine, saving
                db_enclosure.save()

                logger.debug(u'Saved extracted enclosure %s for %s from %s',
                    db_enclosure, db_entry, entry.link
                )

def update_feed(feed):
    """ Update a single feed. """

    logger.info(u'Updating feed %s', feed)

    try:
        # Fetch and parse the feed
        # etag and modified parameters will trigger a conditional GET
        parsed = feedparser.parse(feed.url,\
            etag=feed.etag, modified=feed.modified)

        # Data not changed
        if parsed.status == 304:
            logger.debug(u'Feed %s not changed, aborting', feed)

            return feed

        # Feed gone, disable crawling
        if parsed.status == 410:
            logger.error(u'Feed %s gone, disabling', feed)

            feed.error_state = True
            feed.error_description = _(
                'Feed returns 410: Gone. Crawling deactivated.'
            )
            feed.active = False
            feed.save()

            return feed

        # Permanent redirect, update URL
        if parsed.status == 301:
            logger.warning(
                u'Feed %s has permanent redirect, updating URL to %s',
                feed, parsed.href)

            feed.url = parsed.href

        # Check for well-formedness
        if parsed.bozo:
            logger.warning(
                u'Feed data was not well-formed. Error: %s',
                unicode(parsed.bozo_exception)
            )

        # Assert the feed id is continuous
        # assert not feed.feed_id or parsed.id == feed.feed_id

        update = True
        if 'updated_parsed' in parsed.feed:
            # Convert feedparser's time_struct to datetime
            parsed_updated = datetime_from_struct(parsed.feed.updated_parsed)

            if feed.updated and feed.updated >= parsed_updated:
                update = False
        else:
            parsed_updated = None

        # Only update if newer
        if update:
            logger.debug(u'Updating feed %s', feed)

            # Update all entries
            for entry in parsed.entries:
                # Only update posts which are changed after the latest feed
                # update - this saves a lot of effort in the filtering
                # process down the road

                entry_update = True
                if 'updated_parsed' in entry:
                    entry_parsed_updated = \
                        datetime_from_struct(entry.updated_parsed)

                    if feed.updated and feed.updated >= entry_parsed_updated:
                        entry_update = False

                if entry_update:
                    logger.debug(u'Updating %s', entry.title)
                    update_entry(feed, entry)
                else:
                    logger.debug(u'Not updating %s', entry.title)

            # Make sure the feed ID is synchronized
            # feed.feed_id = parsed.id

            if parsed_updated:
                # Get latest update from feed
                feed.updated = parsed_updated

            else:
                # Get latest update from database
                updated_entries = feed.entries.filter(updated__isnull=False)

                try:
                    latest = updated_entries.order_by('-updated')[0]

                    logger.debug(u'Latest updated entry `%s` at `%s`',
                        latest, latest.updated)

                    feed.updated = latest.updated

                except IndexError:
                    # No entries exist in feed or none have updated set
                    feed.updated = None

            # Set title and subtitle only if not already set
            if not feed.title:
                feed.title = getattr(parsed.feed, 'title', 'No title')

            if not feed.subtitle:
                feed.subtitle = getattr(parsed.feed, 'subtitle', '')

            # Clear any possible error state
            feed.error_state = False

            # Store last modified and etag
            feed.etag = getattr(parsed, 'etag', '')
            feed.modified = getattr(parsed, 'modified', '')

            feed.save()

        else:
            logger.debug(u'Not updating feed %s', feed)

    except Exception as e:
        # Log any exception and pass the status on to the database
        feed.error_state = True
        feed.error_description = unicode(e)
        feed.error_date = now()
        feed.save()

        logger.exception(u'Exception while updating feed %s', feed)

    finally:
        return feed

def update_feeds():
    """ Update all feeds. """

    logger.info(u'Updating all feeds')

    # List all active feeds, randomized ordering for greater concurrency
    feed_qs = Feed.objects.filter(active=True).order_by('?')

    threads = settings.NEWSPEAK_THREADS

    # Create a pool for workers to swim in
    pool = eventlet.GreenPool(size=threads)

    feed_total = feed_qs.count()
    feed_count = 0
    logger.debug(u'Crawling %d feeds with %d lightweight threads.', feed_total, threads)

    for feed in pool.imap(update_feed, feed_qs):
        feed_count += 1
        logger.debug(u'Finished processing feed %s (%d/%d)',
        feed, feed_count, feed_total)

    logger.debug(u'Finished crawling succesfully. %d feeds updated',
        feed_total
    )

    # Wait untill all threads are done
    pool.waitall()
<commit_msg>No duplication in enclosures and content.<commit_after>import logging
logger = logging.getLogger(__name__)

from urlparse import urljoin

import eventlet

# Use Eventlet for parallel processing of HTTP requests
feedparser = eventlet.import_patched('feedparser')
from eventlet.green import urllib2

from lxml import html

from django.conf import settings
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError

from .models import Feed, FeedEntry, FeedContent, FeedEnclosure
from .utils import (
    datetime_from_struct, get_or_create_object, keywords_to_regex
)

def extract_xpath(url, xpath):
    """
    Extract XPath expression from the HTML at specified URL and return the
    HTML/text representation of its contents, with all links made absolute.
    """
    # Fetch and parse
    logger.debug(u'Fetching %s', url)

    # Use urllib2 directly for enabled SSL support (LXML doesn't by default)
    timeout = 30

    try:
        opener = urllib2.urlopen(url, None, timeout)

        # Fetch HTTP data in one batch, as handling the 'file-like' object to
        # lxml results in thread-locking behaviour.
        htmldata = opener.read()

    except urllib2.URLError, urllib2.HTTPError:
        # These type of errors are non-fatal - but *should* be logged.
        logger.exception(u'HTTP Error during XPath extraction for %s, returning emtpy string.',
            url
        )

        return ''

    # Parse
    logger.debug(u'Parsing HTML for %s', url)
    parsed = html.fromstring(htmldata, base_url=url)

    # Execute XPath
    logger.debug(u'Resolving XPath %s for %s', xpath, url)
    result = parsed.xpath(xpath)

    if not result:
        logger.warning(
            u'XPath %s did not return a value for %s, returning empty string.',
            xpath, url)

        return ''

    # If the result is already a string, we're done now
    if isinstance(result, basestring):
        return result

    # The result should ideally only contain a single element
    if len(result) > 1:
        logger.warning(
            u'XPath %s returned multiple elements for %s, ignoring all but '
            u' the first.'
        )

    # Take the first element in the XPath result set
    result = result[0]

    # Again, if the result is simply a string, we're done
    if isinstance(result, basestring):
        return result

    # From now on, we will assume it is some HTML element
    assert isinstance(result, html.HtmlMixin)

    # Make all links in the result absolute
    result.make_links_absolute(url)

    # Turn the result into a string
    result = html.tostring(result)

    return result

def filter_entry(feed, entry):
    """
    Return the result of applying filters to a feed entry. True when entry
    is to be included, False if the entry is to be discarded.
    """
    for feed_filter in feed.filters.filter(active=True):
        logger.debug(u'Applying filter %s to entry %s',
            feed_filter, entry.title
        )

        pattern = keywords_to_regex(feed_filter.keywords)

        if feed_filter.filter_inclusive:
            # Keep only matched entries

            if feed_filter.filter_title and \
                pattern.search(entry.title):

                # Pass: process next filter
                break

            if feed_filter.filter_summary and \
                pattern.search(entry.summary):

                # Pass: process next filter
                break

            # No match: discard entry
            return False

        else:
            # Exclusive filtering - discard matching entries
            if feed_filter.filter_title and \
                pattern.search(entry.title):

                # Match: discard this entry
                return False

            if feed_filter.filter_summary and \
                pattern.search(entry.summary):

                # Match: discard this entry
                return False

    # By default, include all entries
    return True

def update_entry(feed, entry):
    """ Update a specified entry for the feed. """

    # Consider whether or not to discard the item
    if not filter_entry(feed, entry):
        # Entry to be discarded - stop further processing
        logger.debug(u'Discarding entry %s', entry.title)

        # Possible problem: we might want to delete existing entries now
        # that they are filtered. Then again: we might not.
        return

    if 'id' in entry:
        logger.debug(u'Attempt matching by entry ID %s', entry.id)

        db_entry = get_or_create_object(
            FeedEntry, feed=feed, entry_id=entry.id)

    elif 'link' in entry:
        logger.debug(u'Attempt matching by entry link %s', entry.link)

        db_entry = get_or_create_object(
            FeedEntry, feed=feed, entry_id=None, link=entry.link)

    else:
        raise Exception('Could not identify entry by link or ID.')

    # Copy entry information
    db_entry.title = entry.title
    db_entry.link = entry.link
    db_entry.summary = entry.summary

    db_entry.author = getattr(db_entry, 'author', None)

    db_entry.published = datetime_from_struct(entry.published_parsed)

    # Only set updated when available - do not assume it to be there
    raw_updated_parsed = getattr(entry, 'updated_parsed', None)
    if raw_updated_parsed:
        db_entry.updated = datetime_from_struct(raw_updated_parsed)

    # Extraction of summary
    if feed.summary_xpath and (not db_entry.summary or feed.summary_override):
        extracted_summary = extract_xpath(entry.link, feed.summary_xpath)

        if extracted_summary:
            # Some value was found, add it to the entry
            db_entry.summary = extracted_summary

            logger.debug(u'Extracted summary for %s from %s',
                db_entry, entry.link
            )

    # Save it to the database
    # (Required before being able to link stuff like content/enclosures)
    db_entry.save()

    # Feed content
    if 'content' in entry:
        for entry_content in entry.content:
            # Only add if content with the same mime type and
            # language does not already exist. If it does, update if it differs.
            try:
                feed_content = FeedContent.objects.get(
                    entry=db_entry,
                    mime_type=entry_content.type or '',
                    language=entry_content.language or ''
                )

                # Update existing content, if differs
                if not feed_content.value == entry_content.value:
                    feed_content.value = entry_content.value
                    feed_content.save()

            except FeedContent.DoesNotExist:
                # Even though standards require mimetype to be set,
                # we are going to assume only value is set - the absolute minimum.
                db_content = FeedContent(
                    entry=db_entry,
                    value=entry_content.value,
                    mime_type=entry_content.type or '',
                    language=entry_content.language or ''
                )
                db_content.save()

        logger.debug(u'%d contents added to entry %s',
            len(entry.content), db_entry)

    # Feed enclosures
    if 'enclosures' in entry:
        for entry_enclosure in entry.enclosures:
            # Only add if an enclosure with the same URL does not
            # already exist
            if FeedEnclosure.objects.filter(
                entry=db_entry, href=entry_enclosure.href).exists():
                logger.debug(
                    u'Enclosure with href \'%s\' already exists, not saving.',
                    entry_enclosure.href
                )

            else:
                # Even though standards require length and mimetype to be set,
                # we are going to assume only href is set - the absolute minimum.
                db_enclosure = FeedEnclosure(
                    entry=db_entry,
                    href=entry_enclosure.href,
                    length=entry_enclosure.length or 0,
                    mime_type=entry_enclosure.type or ''
                )
                db_enclosure.save()

        logger.debug(u'%d enclosures added to entry %s',
            len(entry.enclosures), db_entry)

    # Extraction of enclosures
    if feed.enclosure_xpath:
        extracted_href = extract_xpath(entry.link, feed.enclosure_xpath)

        # Make the resulting URL absolute
        extracted_href = urljoin(entry.link, extracted_href)

        # Only add if an enclosure with the same URL does not
        # already exist
        if FeedEnclosure.objects.filter(
            entry=db_entry, href=extracted_href).exists():
            logger.debug(
                u'Extracted enclosure with href \'%s\' already exists, not saving.',
                extracted_href
            )

        else:
            db_enclosure = FeedEnclosure(
                entry=db_entry,
                href=extracted_href,
                length=0,
                mime_type=feed.enclosure_mime_type
            )

            # Validate the results - the URL might be invalid
            try:
                db_enclosure.full_clean()

            except ValidationError:
                # Log the exception, don't save
                logger.exception(u'Error validating enclosure data.')

            else:
                # All went fine, saving
                db_enclosure.save()

                logger.debug(u'Saved extracted enclosure %s for %s from %s',
                    db_enclosure, db_entry, entry.link
                )

def update_feed(feed):
    """ Update a single feed. """

    logger.info(u'Updating feed %s', feed)

    try:
        # Fetch and parse the feed
        # etag and modified parameters will trigger a conditional GET
        parsed = feedparser.parse(feed.url,\
            etag=feed.etag, modified=feed.modified)

        # Data not changed
        if parsed.status == 304:
            logger.debug(u'Feed %s not changed, aborting', feed)

            return feed

        # Feed gone, disable crawling
        if parsed.status == 410:
            logger.error(u'Feed %s gone, disabling', feed)

            feed.error_state = True
            feed.error_description = _(
                'Feed returns 410: Gone. Crawling deactivated.'
            )
            feed.active = False
            feed.save()

            return feed

        # Permanent redirect, update URL
        if parsed.status == 301:
            logger.warning(
                u'Feed %s has permanent redirect, updating URL to %s',
                feed, parsed.href)

            feed.url = parsed.href

        # Check for well-formedness
        if parsed.bozo:
            logger.warning(
                u'Feed data was not well-formed. Error: %s',
                unicode(parsed.bozo_exception)
            )

        # Assert the feed id is continuous
        # assert not feed.feed_id or parsed.id == feed.feed_id

        update = True
        if 'updated_parsed' in parsed.feed:
            # Convert feedparser's time_struct to datetime
            parsed_updated = datetime_from_struct(parsed.feed.updated_parsed)

            if feed.updated and feed.updated >= parsed_updated:
                update = False
        else:
            parsed_updated = None

        # Only update if newer
        if update:
            logger.debug(u'Updating feed %s', feed)

            # Update all entries
            for entry in parsed.entries:
                # Only update posts which are changed after the latest feed
                # update - this saves a lot of effort in the filtering
                # process down the road

                entry_update = True
                if 'updated_parsed' in entry:
                    entry_parsed_updated = \
                        datetime_from_struct(entry.updated_parsed)

                    if feed.updated and feed.updated >= entry_parsed_updated:
                        entry_update = False

                if entry_update:
                    logger.debug(u'Updating %s', entry.title)
                    update_entry(feed, entry)
                else:
                    logger.debug(u'Not updating %s', entry.title)

            # Make sure the feed ID is synchronized
            # feed.feed_id = parsed.id

            if parsed_updated:
                # Get latest update from feed
                feed.updated = parsed_updated

            else:
                # Get latest update from database
                updated_entries = feed.entries.filter(updated__isnull=False)

                try:
                    latest = updated_entries.order_by('-updated')[0]

                    logger.debug(u'Latest updated entry `%s` at `%s`',
                        latest, latest.updated)

                    feed.updated = latest.updated

                except IndexError:
                    # No entries exist in feed or none have updated set
                    feed.updated = None

            # Set title and subtitle only if not already set
            if not feed.title:
                feed.title = getattr(parsed.feed, 'title', 'No title')

            if not feed.subtitle:
                feed.subtitle = getattr(parsed.feed, 'subtitle', '')

            # Clear any possible error state
            feed.error_state = False

            # Store last modified and etag
            feed.etag = getattr(parsed, 'etag', '')
            feed.modified = getattr(parsed, 'modified', '')

            feed.save()

        else:
            logger.debug(u'Not updating feed %s', feed)

    except Exception as e:
        # Log any exception and pass the status on to the database
        feed.error_state = True
        feed.error_description = unicode(e)
        feed.error_date = now()
        feed.save()

        logger.exception(u'Exception while updating feed %s', feed)

    finally:
        return feed

def update_feeds():
    """ Update all feeds. """

    logger.info(u'Updating all feeds')

    # List all active feeds, randomized ordering for greater concurrency
    feed_qs = Feed.objects.filter(active=True).order_by('?')

    threads = settings.NEWSPEAK_THREADS

    # Create a pool for workers to swim in
    pool = eventlet.GreenPool(size=threads)

    feed_total = feed_qs.count()
    feed_count = 0
    logger.debug(u'Crawling %d feeds with %d lightweight threads.', feed_total, threads)

    for feed in pool.imap(update_feed, feed_qs):
        feed_count += 1
        logger.debug(u'Finished processing feed %s (%d/%d)',
        feed, feed_count, feed_total)

    logger.debug(u'Finished crawling succesfully. %d feeds updated',
        feed_total
    )

    # Wait untill all threads are done
    pool.waitall()
<|endoftext|>


<commit_before># Copyright 2011 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitaions under the License.
import logging
import re

class OpenDialogBase(object):
  def __init__(self, settings, db):
    settings.register("filter_text", str, "")
    self._filter_text = settings.filter_text
    self._settings = settings
    self._db = db
    self._can_process_queries = False

  def on_tick(self,*args):
    try:
      stat = self._db.sync_status()
      status = stat.status
      enabled = stat.is_syncd
    except Exception, ex:
      print ex
      status = "quickopend not running"
      enabled = False
    self.set_status("DB Status: %s" % status)
    self.set_can_process_queries(enabled)

  def set_can_process_queries(self, can_process):
    could_process = self._can_process_queries
    self._can_process_queries = can_process

    self.set_results_enabled(can_process)
    if not could_process and can_process:
      self.refresh()

  def just_before_closed(self):
    self._settings.filter_text = self._filter_text

  def set_filter_text(self, text):
    self._filter_text = text
    if self._can_process_queries:
      self.refresh()

  def rescan(self):
    self._db.sync()
    self.refresh()

  def refresh(self):
    # TODO(nduca) save the selection
    if self._filter_text != "":
      ft = str(self._filter_text)
      res = self._db.search(ft)
      self.update_results_list(res.hits)
    else:
      self.update_results_list([])
<commit_msg>Remove debug spew<commit_after># Copyright 2011 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitaions under the License.
import logging
import re

class OpenDialogBase(object):
  def __init__(self, settings, db):
    settings.register("filter_text", str, "")
    self._filter_text = settings.filter_text
    self._settings = settings
    self._db = db
    self._can_process_queries = False

  def on_tick(self,*args):
    try:
      stat = self._db.sync_status()
      status = stat.status
      enabled = stat.is_syncd
    except Exception, ex:
      status = "quickopend not running"
      enabled = False
    self.set_status("DB Status: %s" % status)
    self.set_can_process_queries(enabled)

  def set_can_process_queries(self, can_process):
    could_process = self._can_process_queries
    self._can_process_queries = can_process

    self.set_results_enabled(can_process)
    if not could_process and can_process:
      self.refresh()

  def just_before_closed(self):
    self._settings.filter_text = self._filter_text

  def set_filter_text(self, text):
    self._filter_text = text
    if self._can_process_queries:
      self.refresh()

  def rescan(self):
    self._db.sync()
    self.refresh()

  def refresh(self):
    # TODO(nduca) save the selection
    if self._filter_text != "":
      ft = str(self._filter_text)
      res = self._db.search(ft)
      self.update_results_list(res.hits)
    else:
      self.update_results_list([])
<|endoftext|>


<commit_before>__version__ = '1.4.1'
<commit_msg>version bump (1.4.2)<commit_after>__version__ = '1.4.2'
<|endoftext|>


<commit_before>from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect

def iucas_validate(request):
    user = authenticate(ticket=request.GET["casticket"],casurl=request.build_absolute_uri())
    redirect_url = request.GET["next"]
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
            pass
    else:
        # Return an 'invalid login' error message.
        pass
    return HttpResponseRedirect(redirect_url)
<commit_msg>Adding support to put in a django message if the CAS user hasn't registered with the application yet (to give an indication of what's happening when it inevitabley loops back to the login page)<commit_after>from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect
from django.contrib import messages
from django.conf import settings

def iucas_validate(request):
    user = authenticate(ticket=request.GET["casticket"],casurl=request.build_absolute_uri())
    redirect_url = request.GET["next"]
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
            pass
    else:
        messages.error(request, settings.CAS_NOT_REGISTERED_MSG)
    return HttpResponseRedirect(redirect_url)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# Python AR.Drone 2.0
#
# Copyright (C) 2013 Quadeare <lacrampe.florian@gmail.com>
# Copyright (C) 2016 LegoNigel <legonigel@gmail.com>
# Twitter : @quadeare

from pygame import *
import pygame
import libardrone
import threading
import time
from subprocess import call

import signal
import sys

class video(threading.Thread):
	"""Video class to launch media flux"""
	def __init__(self, nom = ''):
		threading.Thread.__init__(self)
		self.process = None
	def run(self):
		print "Video"
		call(["ffplay", "tcp://192.168.1.1:5555/"])
	def stop(self):
		call(["killall", "ffplay"])
		if self.process is not None:
			self.process.terminate()
			self.process = None

class controle(threading.Thread):
	"""Control class (to control the drone)"""

	def __init__(self, nom = ''):
		threading.Thread.__init__(self)
		self._stopevent = threading.Event( )
	def stop(self):
		self._stopevent.set( )

	def run(self):
		"""We call pygame (to use controler)"""
		pygame.init()

		"""Launch drone class"""
		drone = libardrone.ARDrone(True)
		clock = pygame.time.Clock()
		running = True

		screen = pygame.display.set_mode((640, 400))

		"""Set up and init joystick"""
		#j=joystick.Joystick(0)
		#j.init()

		print "running"

		move_forward = 0
		move_backward = 0
		move_left = 0
		move_right = 0
		turn = 0

		while running:
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					running = False
				elif event.type == pygame.KEYUP:
					drone.hover()
				elif event.type == pygame.KEYDOWN:
					if event.key == pygame.K_ESCAPE:
						drone.reset()
						running = False
						# takeoff / land
					elif event.key == pygame.K_RETURN:
						drone.takeoff()
					elif event.key == pygame.K_SPACE:
						drone.land()
						# emergency
					elif event.key == pygame.K_BACKSPACE:
						drone.reset()
						# forward / backward
					elif event.key == pygame.K_w:
						drone.move_forward()
					elif event.key == pygame.K_s:
						drone.move_backward()
						# left / right
					elif event.key == pygame.K_a:
						drone.move_left()
					elif event.key == pygame.K_d:
						drone.move_right()
						# up / down
					elif event.key == pygame.K_UP:
						drone.move_up()
					elif event.key == pygame.K_DOWN:
						drone.move_down()
						# turn left / turn right
					elif event.key == pygame.K_LEFT:
						drone.turn_left()
					elif event.key == pygame.K_RIGHT:
						drone.turn_right()
						# speed
					elif event.key == pygame.K_1:
						drone.speed = 0.1
					elif event.key == pygame.K_2:
						drone.speed = 0.2
					elif event.key == pygame.K_3:
						drone.speed = 0.3
					elif event.key == pygame.K_4:
						drone.speed = 0.4
					elif event.key == pygame.K_5:
						drone.speed = 0.5
					elif event.key == pygame.K_6:
						drone.speed = 0.6
					elif event.key == pygame.K_7:
						drone.speed = 0.7
					elif event.key == pygame.K_8:
						drone.speed = 0.8
					elif event.key == pygame.K_9:
						drone.speed = 0.9
					elif event.key == pygame.K_0:
						drone.speed = 1.0
			clock.tick(1000)

		print "Shutting down...",
		drone.reset()
		drone.halt()
		print "Ok."
		quit()

if __name__ == '__main__':
	try:
		# Controle
		controle = controle('Thread Controle')
		controle.start()
		time.sleep(5)
		# Video
		video = video('Thread Video')
		video.start()
	except (KeyboardInterrupt, SystemExit):
		controle.stop()
		video.stop()
		sys.exit()
<commit_msg>Change screen size, not really important<commit_after>#!/usr/bin/env python
# Python AR.Drone 2.0
#
# Copyright (C) 2013 Quadeare <lacrampe.florian@gmail.com>
# Copyright (C) 2016 LegoNigel <legonigel@gmail.com>
# Twitter : @quadeare

from pygame import *
import pygame
import libardrone
import threading
import time
from subprocess import call

import signal
import sys

class video(threading.Thread):
	"""Video class to launch media flux"""
	def __init__(self, nom = ''):
		threading.Thread.__init__(self)
		self.process = None
	def run(self):
		print "Video"
		call(["ffplay", "tcp://192.168.1.1:5555/"])
	def stop(self):
		call(["killall", "ffplay"])
		if self.process is not None:
			self.process.terminate()
			self.process = None

class controle(threading.Thread):
	"""Control class (to control the drone)"""

	def __init__(self, nom = ''):
		threading.Thread.__init__(self)
		self._stopevent = threading.Event( )
	def stop(self):
		self._stopevent.set( )

	def run(self):
		"""We call pygame (to use controler)"""
		pygame.init()

		"""Launch drone class"""
		drone = libardrone.ARDrone(True)
		clock = pygame.time.Clock()
		running = True

		screen = pygame.display.set_mode((640, 360))

		"""Set up and init joystick"""
		#j=joystick.Joystick(0)
		#j.init()

		print "running"

		move_forward = 0
		move_backward = 0
		move_left = 0
		move_right = 0
		turn = 0

		while running:
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					running = False
				elif event.type == pygame.KEYUP:
					drone.hover()
				elif event.type == pygame.KEYDOWN:
					if event.key == pygame.K_ESCAPE:
						drone.reset()
						running = False
						# takeoff / land
					elif event.key == pygame.K_RETURN:
						drone.takeoff()
					elif event.key == pygame.K_SPACE:
						drone.land()
						# emergency
					elif event.key == pygame.K_BACKSPACE:
						drone.reset()
						# forward / backward
					elif event.key == pygame.K_w:
						drone.move_forward()
					elif event.key == pygame.K_s:
						drone.move_backward()
						# left / right
					elif event.key == pygame.K_a:
						drone.move_left()
					elif event.key == pygame.K_d:
						drone.move_right()
						# up / down
					elif event.key == pygame.K_UP:
						drone.move_up()
					elif event.key == pygame.K_DOWN:
						drone.move_down()
						# turn left / turn right
					elif event.key == pygame.K_LEFT:
						drone.turn_left()
					elif event.key == pygame.K_RIGHT:
						drone.turn_right()
						# speed
					elif event.key == pygame.K_1:
						drone.speed = 0.1
					elif event.key == pygame.K_2:
						drone.speed = 0.2
					elif event.key == pygame.K_3:
						drone.speed = 0.3
					elif event.key == pygame.K_4:
						drone.speed = 0.4
					elif event.key == pygame.K_5:
						drone.speed = 0.5
					elif event.key == pygame.K_6:
						drone.speed = 0.6
					elif event.key == pygame.K_7:
						drone.speed = 0.7
					elif event.key == pygame.K_8:
						drone.speed = 0.8
					elif event.key == pygame.K_9:
						drone.speed = 0.9
					elif event.key == pygame.K_0:
						drone.speed = 1.0
			clock.tick(1000)

		print "Shutting down...",
		drone.reset()
		drone.halt()
		print "Ok."
		quit()

if __name__ == '__main__':
	try:
		# Controle
		controle = controle('Thread Controle')
		controle.start()
		time.sleep(5)
		# Video
		video = video('Thread Video')
		video.start()
	except (KeyboardInterrupt, SystemExit):
		controle.stop()
		video.stop()
		sys.exit()
<|endoftext|>


<commit_before>#!/usr/bin/env python

import argparse
import time
import random
import operator
from collections import namedtuple
import signal
import logging

from strip import Strip
from led import MAX_RGB

logger = logging.getLogger(__name__)

def init_logging(log_level):
    logging.basicConfig(level=log_level)

# catch signals for tidy exit
_exiting = False
def signal_handler(signal, frame):
    global _exiting
    _exiting = True

DEFAULT_NUM_LEDS = 120
DEFAULT_SPI_BUS = 0
DEFAULT_SPI_DEVICE = 0
DEFAULT_RATE = 5.0  # Hz
DEFAULT_BRIGHTNESS = 1

def main():
    signal.signal(signal.SIGINT, signal_handler)

    parser = argparse.ArgumentParser()
    parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Show debugging output")
    parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", help="Show verbose output")
    parser.add_argument("-n", "--num-leds", dest="num_leds", type=int, help="Number of LEDs in strip", default=DEFAULT_NUM_LEDS)
    parser.add_argument("-o", "--offset", dest="offset", type=int, help="First LED to address", default=0)
    parser.add_argument("--spi-bus", dest="spi_bus", type=int, help="SPI bus", default=DEFAULT_SPI_BUS)
    parser.add_argument("--spi-device", dest="spi_device", type=int, help="SPI device", default=DEFAULT_SPI_DEVICE)
    parser.add_argument("-b", "--brightness", dest="brightness", type=int, help="Global brightness (0-31)", default=DEFAULT_BRIGHTNESS)

    subparsers = parser.add_subparsers(help="Subcommand help")
    random_flash_parser = subparsers.add_parser("flash", help="Random flash")
    random_flash_parser.add_argument("-r", "--rate", dest="rate", type=float, help="Animation rate (Hz)", default=5)
    random_flash_parser.set_defaults(subparser="flash")

    rgb_fader_parser = subparsers.add_parser("fade", help="RGB fader")
    rgb_fader_parser.add_argument("-r", "--rate", dest="rate", type=float, help="Animation rate (Hz)", default=200)
    rgb_fader_parser.add_argument("-s", "--steps", dest="steps", type=int, help="Steps per target colour", default=100)
    rgb_fader_parser.set_defaults(subparser="fade")

    comet_parser = subparsers.add_parser("comet", help="Comet")
    comet_parser.add_argument("-s", "--speed", dest="speed", type=float, help="Speed of descent", default=200)
    comet_parser.add_argument("-l", "--length", dest="length", type=int, help="Length of tail", default=20)
    comet_parser.add_argument("-x", "--colour", dest="colour", choices={"red", "green", "blue"}, help="Colour", default="red")
    comet_parser.add_argument("-c", "--cycle", dest="cycle", action="store_true", help="Cycle comet colour")
    comet_parser.add_argument("-r", "--reverse", dest="reverse", action="store_true", help="Reverse direction")
    comet_parser.set_defaults(subparser="comet", brightness=31)

    chaser_parser = subparsers.add_parser("chaser", help="Chaser")
    chaser_parser.add_argument("-n", "--number", dest="number", type=int, help="Number of chasers", default=10)
    chaser_parser.add_argument("-s", "--speed", dest="speed", type=float, help="Speed of descent", default=100)
    chaser_parser.add_argument("-p", "--proximity", dest="proximity", type=int, help="Maximum distance between chasers", default=15)
    chaser_parser.add_argument("-l", "--length", dest="length", type=int, help="Length of chaser", default=10)
    chaser_parser.add_argument("-e", "--decrease", dest="decrease", action="store_true", help="Decrease length of chasers")
    chaser_parser.add_argument("-r", "--reverse", dest="reverse", action="store_true", help="Reverse direction")
    chaser_parser.set_defaults(subparser="chaser")

    pixel_parser = subparsers.add_parser("pixel", help="Direct pixel control")
    pixel_parser.add_argument("-p", "--pos", dest="position", type=int, help="LED position")
    pixel_parser.add_argument("-r", "--red", dest="red", type=int, help="Red value (0-255)", default=0)
    pixel_parser.add_argument("-g", "--green", dest="green", type=int, help="Green value (0-255)", default=0)
    pixel_parser.add_argument("-b", "--blue", dest="blue", type=int, help="Blue value (0-255)", default=0)
    pixel_parser.add_argument("-l", "--length", dest="length", type=int, help="Number of pixels", default=1)
    pixel_parser.add_argument("-x", "--random", dest="random", action="store_true", help="Randomise colours")
    pixel_parser.set_defaults(subparser="pixel")

    all_parser = subparsers.add_parser("all", help="All LED control")
    all_parser.add_argument("-r", "--red", dest="red", type=int, help="Red value (0-255)", default=0)
    all_parser.add_argument("-g", "--green", dest="green", type=int, help="Green value (0-255)", default=0)
    all_parser.add_argument("-b", "--blue", dest="blue", type=int, help="Blue value (0-255)", default=0)
    all_parser.add_argument("-o", "--off", dest="off", action="store_true", help="All LEDS off")
    all_parser.add_argument("-x", "--random", dest="random", action="store_true", help="Randomise colours")
    all_parser.set_defaults(subparser="all")

    args = parser.parse_args()

    init_logging(logging.DEBUG if args.debug else (logging.INFO if args.verbose else logging.WARNING))

    strip = Strip(args.num_leds, args.spi_bus, args.spi_device)
    strip.set_offset(args.offset)
    persist = False

    if args.subparser == "flash":
        demo_random_flash(strip, args.rate, args.brightness)
    elif args.subparser == "fade":
        demo_rgb_fader(strip, args.rate, args.steps, args.brightness)
    elif args.subparser == "comet":
        demo_comet(strip, args.speed, args.length, args.colour, args.cycle, args.reverse, args.brightness)
    elif args.subparser == "chaser":
        demo_chaser(strip, args.number, args.speed, args.proximity, args.length, args.decrease, args.reverse, args.brightness)
    elif args.subparser == "pixel":
        demo_pixel(strip, args.position, args.length, args.random, args.red, args.green, args.blue, args.brightness)
        persist = True
    elif args.subparser == "all":
        demo_all(strip, args.random, args.off, args.red, args.green, args.blue, args.brightness)
        persist = True

    if not persist:
        strip.set_all_off()
        strip.update()

def demo_random_flash(strip, rate, brightness=1):
    """Rate in Hz."""
    delay_time = 1.0 / rate
    updates = 0
    start_time = time.time()
    last_report_time = start_time
    while not _exiting:
        strip.set_all(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), brightness)
        strip.update()
        time.sleep(delay_time)
        updates += 1
        now = time.time()
        if now - last_report_time > 1.0:
            elapsed = now - start_time
            updates_per_second = updates / elapsed
            logger.info("Updates per second: {0}".format(updates_per_second))
            last_report_time = now

def demo_rgb_fader(strip, rate, steps, brightness):
    """Fade entire strip through a range of colours."""
    # red, green, blue
    targets = ((255,   0,   0),
               (255, 165,   0),  # orange
               (255, 255,   0),  # yellow
               (173, 255,  47),  # yellow green
               (  0, 255,   0),  # green
               ( 32, 178, 170),  # sea green
               (  0,   0, 255),  # blue
               (138,  43, 226))  # violet

    delay_time = 1.0 / rate
    steps_per_target = float(steps)  # must be a float
    step_count = 0
    rgb = (0, 0, 0)
    target = 0
    delta = tuple((y - x)/steps_per_target for x, y in zip(rgb, targets[target]))

    while not _exiting:
        if step_count < steps_per_target:
            rgb = tuple(map(operator.add, rgb, delta))
            step_count += 1
        else:
            rgb = targets[target]
            target = (target + 1) % len(targets)
            delta = tuple((y - x)/steps_per_target for x, y in zip(rgb, targets[target]))
            logger.info("Current {0}, new target: {1}, delta {2}".format(rgb, targets[target], delta))
            step_count = 0
        logger.debug("r {0}, g {1}, b {2}".format(rgb[0], rgb[1], rgb[2]))
        strip.set_all(rgb[0], rgb[1], rgb[2], brightness)
        strip.update()
        time.sleep(delay_time)

def demo_comet(strip, speed, length, colour, cycle, reverse, brightness):

    if reverse:
        strip.reverse()
    pos = 0
    delay_time = 1. / speed

    mod = (0.0, 30.0 / (length / 20.0), 50.0 / (length / 20.0))
    if colour == "red":
        r_mod, g_mod, b_mod = mod
    elif colour == "green":
        g_mod, b_mod, r_mod = mod
    elif colour == "blue":
        b_mod, r_mod, g_mod = mod
    else:
        raise Exception("unknown colour")

    bright_mod = 2.5 / (length / 20.0)

    while not _exiting:
        for i in range(length):
            try:
                strip.set_led(pos - i, 255 - i * r_mod, 255 - i * g_mod, 255 - i * b_mod, brightness - i * bright_mod)
            except IndexError:
                pass
        try:
            strip.set_led(pos - length, 0, 0, 0, 0)
        except IndexError:
            pass
        strip.update()
        pos = (pos + 1) % (len(strip) + 2 * length)
        if cycle and pos == 0:
            x_mod = r_mod
            r_mod = g_mod
            g_mod = b_mod
            b_mod = x_mod
        time.sleep(delay_time)

def demo_chaser(strip, number, speed, proximity, length, decrease, reverse, brightness):

    pos = 0
    delay_time = 1.0 / speed

    Chaser = namedtuple("Chaser", ("red", "green", "blue", "offset", "length"))

    def mod_length(x):
        if decrease:
            k = length ** (1.0 / (number - 1.0))
            return int(length / k ** x + 0.5)
        else:
            return length

    chasers = [Chaser(random.randint(0, MAX_RGB), random.randint(0, MAX_RGB), random.randint(0, MAX_RGB), -i * proximity, mod_length(i)) for i in range(number)]
    logger.debug(chasers)

    if reverse:
        strip.reverse()

    while not _exiting:
        for chaser in chasers:
            for i in range(chaser.length):
                try:
                    strip.set_off(chaser.offset + pos - i)
                except IndexError:
                    pass
        pos = (pos + 1) % (len(strip) + number * proximity)
        logger.debug(pos)
        for chaser in chasers:
            for i in range(chaser.length):
                try:
                    strip.set_led(chaser.offset + pos - i, chaser.red, chaser.green, chaser.blue, brightness)
                except IndexError:
                    pass
        strip.update()
        time.sleep(delay_time)

def demo_pixel(strip, position, length, randomise, red, green, blue, brightness):
    for i in range(length):
        if randomise:
            red = random.randint(0, MAX_RGB)
            green = random.randint(0, MAX_RGB)
            blue = random.randint(0, MAX_RGB)
        strip.set_led(position + i, red, green, blue, brightness)
    strip.update()

def demo_all(strip, randomise, off, red, green, blue, brightness):
    if off:
        strip.set_all_off()
    else:
        if randomise:
            red = random.randint(0, MAX_RGB)
            green = random.randint(0, MAX_RGB)
            blue = random.randint(0, MAX_RGB)
        strip.set_all(red, green, blue, brightness)
    strip.update()

if __name__ == "__main__":
    main()
<commit_msg>Added duty-cycle option to random flash.<commit_after>#!/usr/bin/env python

import argparse
import time
import random
import operator
from collections import namedtuple
import signal
import logging

from strip import Strip
from led import MAX_RGB

logger = logging.getLogger(__name__)

def init_logging(log_level):
    logging.basicConfig(level=log_level)

# catch signals for tidy exit
_exiting = False
def signal_handler(signal, frame):
    global _exiting
    _exiting = True

DEFAULT_NUM_LEDS = 120
DEFAULT_SPI_BUS = 0
DEFAULT_SPI_DEVICE = 0
DEFAULT_RATE = 5.0  # Hz
DEFAULT_BRIGHTNESS = 1

def main():
    signal.signal(signal.SIGINT, signal_handler)

    parser = argparse.ArgumentParser()
    parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Show debugging output")
    parser.add_argument("-v", "--verbose", dest="verbose", action="store_true", help="Show verbose output")
    parser.add_argument("-n", "--num-leds", dest="num_leds", type=int, help="Number of LEDs in strip", default=DEFAULT_NUM_LEDS)
    parser.add_argument("-o", "--offset", dest="offset", type=int, help="First LED to address", default=0)
    parser.add_argument("--spi-bus", dest="spi_bus", type=int, help="SPI bus", default=DEFAULT_SPI_BUS)
    parser.add_argument("--spi-device", dest="spi_device", type=int, help="SPI device", default=DEFAULT_SPI_DEVICE)
    parser.add_argument("-b", "--brightness", dest="brightness", type=int, help="Global brightness (0-31)", default=DEFAULT_BRIGHTNESS)

    subparsers = parser.add_subparsers(help="Subcommand help")
    random_flash_parser = subparsers.add_parser("flash", help="Random flash")
    random_flash_parser.add_argument("-r", "--rate", dest="rate", type=float, help="Animation rate (Hz)", default=5)
    random_flash_parser.add_argument("-d", "--dutycycle", dest="dutycycle", type=float, help="Duty cycle (on time, 1.0 = always on)", default=1.0)
    random_flash_parser.set_defaults(subparser="flash")

    rgb_fader_parser = subparsers.add_parser("fade", help="RGB fader")
    rgb_fader_parser.add_argument("-r", "--rate", dest="rate", type=float, help="Animation rate (Hz)", default=200)
    rgb_fader_parser.add_argument("-s", "--steps", dest="steps", type=int, help="Steps per target colour", default=100)
    rgb_fader_parser.set_defaults(subparser="fade")

    comet_parser = subparsers.add_parser("comet", help="Comet")
    comet_parser.add_argument("-s", "--speed", dest="speed", type=float, help="Speed of descent", default=200)
    comet_parser.add_argument("-l", "--length", dest="length", type=int, help="Length of tail", default=20)
    comet_parser.add_argument("-x", "--colour", dest="colour", choices={"red", "green", "blue"}, help="Colour", default="red")
    comet_parser.add_argument("-c", "--cycle", dest="cycle", action="store_true", help="Cycle comet colour")
    comet_parser.add_argument("-r", "--reverse", dest="reverse", action="store_true", help="Reverse direction")
    comet_parser.set_defaults(subparser="comet", brightness=31)

    chaser_parser = subparsers.add_parser("chaser", help="Chaser")
    chaser_parser.add_argument("-n", "--number", dest="number", type=int, help="Number of chasers", default=10)
    chaser_parser.add_argument("-s", "--speed", dest="speed", type=float, help="Speed of descent", default=100)
    chaser_parser.add_argument("-p", "--proximity", dest="proximity", type=int, help="Maximum distance between chasers", default=15)
    chaser_parser.add_argument("-l", "--length", dest="length", type=int, help="Length of chaser", default=10)
    chaser_parser.add_argument("-e", "--decrease", dest="decrease", action="store_true", help="Decrease length of chasers")
    chaser_parser.add_argument("-r", "--reverse", dest="reverse", action="store_true", help="Reverse direction")
    chaser_parser.set_defaults(subparser="chaser")

    pixel_parser = subparsers.add_parser("pixel", help="Direct pixel control")
    pixel_parser.add_argument("-p", "--pos", dest="position", type=int, help="LED position")
    pixel_parser.add_argument("-r", "--red", dest="red", type=int, help="Red value (0-255)", default=0)
    pixel_parser.add_argument("-g", "--green", dest="green", type=int, help="Green value (0-255)", default=0)
    pixel_parser.add_argument("-b", "--blue", dest="blue", type=int, help="Blue value (0-255)", default=0)
    pixel_parser.add_argument("-l", "--length", dest="length", type=int, help="Number of pixels", default=1)
    pixel_parser.add_argument("-x", "--random", dest="random", action="store_true", help="Randomise colours")
    pixel_parser.set_defaults(subparser="pixel")

    all_parser = subparsers.add_parser("all", help="All LED control")
    all_parser.add_argument("-r", "--red", dest="red", type=int, help="Red value (0-255)", default=0)
    all_parser.add_argument("-g", "--green", dest="green", type=int, help="Green value (0-255)", default=0)
    all_parser.add_argument("-b", "--blue", dest="blue", type=int, help="Blue value (0-255)", default=0)
    all_parser.add_argument("-o", "--off", dest="off", action="store_true", help="All LEDS off")
    all_parser.add_argument("-x", "--random", dest="random", action="store_true", help="Randomise colours")
    all_parser.set_defaults(subparser="all")

    args = parser.parse_args()

    init_logging(logging.DEBUG if args.debug else (logging.INFO if args.verbose else logging.WARNING))

    strip = Strip(args.num_leds, args.spi_bus, args.spi_device)
    strip.set_offset(args.offset)
    persist = False

    if args.subparser == "flash":
        demo_random_flash(strip, args.rate, args.brightness, args.dutycycle)
    elif args.subparser == "fade":
        demo_rgb_fader(strip, args.rate, args.steps, args.brightness)
    elif args.subparser == "comet":
        demo_comet(strip, args.speed, args.length, args.colour, args.cycle, args.reverse, args.brightness)
    elif args.subparser == "chaser":
        demo_chaser(strip, args.number, args.speed, args.proximity, args.length, args.decrease, args.reverse, args.brightness)
    elif args.subparser == "pixel":
        demo_pixel(strip, args.position, args.length, args.random, args.red, args.green, args.blue, args.brightness)
        persist = True
    elif args.subparser == "all":
        demo_all(strip, args.random, args.off, args.red, args.green, args.blue, args.brightness)
        persist = True

    if not persist:
        strip.set_all_off()
        strip.update()

def demo_random_flash(strip, rate, brightness=1, duty_cycle=1.0):
    """Rate in Hz."""
    delay_time = 1.0 / rate
    updates = 0
    start_time = time.time()
    last_report_time = start_time

    duty_cycle = max(0.01, min(1.0, duty_cycle))
    on_time = delay_time * duty_cycle
    off_time = delay_time * (1.0 - duty_cycle)
    logger.debug("on_time {}, off_time {}".format(on_time, off_time))

    while not _exiting:
        strip.set_all(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), brightness)
        strip.update()
        time.sleep(on_time)
        if off_time:
            strip.set_all_off()
            strip.update()
            time.sleep(off_time)
        updates += 1
        now = time.time()
        if now - last_report_time > 1.0:
            elapsed = now - start_time
            updates_per_second = updates / elapsed
            logger.info("Updates per second: {0}".format(updates_per_second))
            last_report_time = now

def demo_rgb_fader(strip, rate, steps, brightness):
    """Fade entire strip through a range of colours."""
    # red, green, blue
    targets = ((255,   0,   0),
               (255, 165,   0),  # orange
               (255, 255,   0),  # yellow
               (173, 255,  47),  # yellow green
               (  0, 255,   0),  # green
               ( 32, 178, 170),  # sea green
               (  0,   0, 255),  # blue
               (138,  43, 226))  # violet

    delay_time = 1.0 / rate
    steps_per_target = float(steps)  # must be a float
    step_count = 0
    rgb = (0, 0, 0)
    target = 0
    delta = tuple((y - x)/steps_per_target for x, y in zip(rgb, targets[target]))

    while not _exiting:
        if step_count < steps_per_target:
            rgb = tuple(map(operator.add, rgb, delta))
            step_count += 1
        else:
            rgb = targets[target]
            target = (target + 1) % len(targets)
            delta = tuple((y - x)/steps_per_target for x, y in zip(rgb, targets[target]))
            logger.info("Current {0}, new target: {1}, delta {2}".format(rgb, targets[target], delta))
            step_count = 0
        logger.debug("r {0}, g {1}, b {2}".format(rgb[0], rgb[1], rgb[2]))
        strip.set_all(rgb[0], rgb[1], rgb[2], brightness)
        strip.update()
        time.sleep(delay_time)

def demo_comet(strip, speed, length, colour, cycle, reverse, brightness):

    if reverse:
        strip.reverse()
    pos = 0
    delay_time = 1. / speed

    mod = (0.0, 30.0 / (length / 20.0), 50.0 / (length / 20.0))
    if colour == "red":
        r_mod, g_mod, b_mod = mod
    elif colour == "green":
        g_mod, b_mod, r_mod = mod
    elif colour == "blue":
        b_mod, r_mod, g_mod = mod
    else:
        raise Exception("unknown colour")

    bright_mod = 2.5 / (length / 20.0)

    while not _exiting:
        for i in range(length):
            try:
                strip.set_led(pos - i, 255 - i * r_mod, 255 - i * g_mod, 255 - i * b_mod, brightness - i * bright_mod)
            except IndexError:
                pass
        try:
            strip.set_led(pos - length, 0, 0, 0, 0)
        except IndexError:
            pass
        strip.update()
        pos = (pos + 1) % (len(strip) + 2 * length)
        if cycle and pos == 0:
            x_mod = r_mod
            r_mod = g_mod
            g_mod = b_mod
            b_mod = x_mod
        time.sleep(delay_time)

def demo_chaser(strip, number, speed, proximity, length, decrease, reverse, brightness):

    pos = 0
    delay_time = 1.0 / speed

    Chaser = namedtuple("Chaser", ("red", "green", "blue", "offset", "length"))

    def mod_length(x):
        if decrease:
            k = length ** (1.0 / (number - 1.0))
            return int(length / k ** x + 0.5)
        else:
            return length

    chasers = [Chaser(random.randint(0, MAX_RGB), random.randint(0, MAX_RGB), random.randint(0, MAX_RGB), -i * proximity, mod_length(i)) for i in range(number)]
    logger.debug(chasers)

    if reverse:
        strip.reverse()

    while not _exiting:
        for chaser in chasers:
            for i in range(chaser.length):
                try:
                    strip.set_off(chaser.offset + pos - i)
                except IndexError:
                    pass
        pos = (pos + 1) % (len(strip) + number * proximity)
        logger.debug(pos)
        for chaser in chasers:
            for i in range(chaser.length):
                try:
                    strip.set_led(chaser.offset + pos - i, chaser.red, chaser.green, chaser.blue, brightness)
                except IndexError:
                    pass
        strip.update()
        time.sleep(delay_time)

def demo_pixel(strip, position, length, randomise, red, green, blue, brightness):
    for i in range(length):
        if randomise:
            red = random.randint(0, MAX_RGB)
            green = random.randint(0, MAX_RGB)
            blue = random.randint(0, MAX_RGB)
        strip.set_led(position + i, red, green, blue, brightness)
    strip.update()

def demo_all(strip, randomise, off, red, green, blue, brightness):
    if off:
        strip.set_all_off()
    else:
        if randomise:
            red = random.randint(0, MAX_RGB)
            green = random.randint(0, MAX_RGB)
            blue = random.randint(0, MAX_RGB)
        strip.set_all(red, green, blue, brightness)
    strip.update()

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>
import sys, curses

from cwidgets import *

def demo(window):
    # Create the root of the widget hierarchy.
    root = WidgetRoot(window)
    # Make the display less monochrome.
    root.styler = ClassStyler(do_colors=True)
    root.styler.add_style(Widget, background=('white', 'blue'),
                          default=('black', 'white'))
    root.styler.add_style(Focusable, default=('red', 'white'),
                          highlight=('black', 'red'), focus=('white', 'red'))
    root.styler.add_style(EntryBox, default=('white', 'black'),
                          focus=('black', 'white'))
    # Wrap the UI in a Viewport to avoid crashes at small resolutions.
    vp = root.add(Viewport())
    # Push the UI together to avoid spreading everyting over the screen.
    cont = vp.add(AlignContainer())
    # The user-visible "window"; with a border and the bottom line pushed
    # inside by one line height.
    win = cont.add(MarginContainer(border=True, insets=(0, 0, 1, 0)))
    # Decoratively enclose the title
    title_wrapper = win.add(TeeContainer(), slot=MarginContainer.POS_TOP)
    # Add the title
    title = title_wrapper.add(Label('cwidgets demo'))
    # Add the content. This could also be a nested Viewport containing
    # a more complex UI.
    # When text is typed into the entry box, it will increase smoothly (along
    # with the remaining UI) until it's 70 columns or 20 rows (because of the
    # multiline setting, it can have multiple lines) large, then, it will not
    # grow further (along the corresponding axis), and scroll instead.
    content = win.add(EntryBox('Lorem ipsum dolor sit amet', multiline=True,
                               cmaxsize=(70, 20)))
    # Bind a vertical scrollbar to the content
    sbv = win.add(content.bind(Scrollbar(Scrollbar.DIR_VERTICAL)),
                  slot=MarginContainer.POS_RIGHT)
    # The bottom contains a line of buttons stacked below a scrollbar.
    bottom = win.add(VerticalContainer(), slot=MarginContainer.POS_BOTTOM)
    # Add the horizontal scrollbar.
    sbh = bottom.add(content.bind(Scrollbar(Scrollbar.DIR_HORIZONTAL)))
    # The buttons are laid out horizontally.
    buttons = bottom.add(HorizontalContainer())
    # A bare Widget as "glue" to fill the space. An AlignContainer would
    # have been possible as well.
    buttons.add(Widget(), weight=1)
    # The first button
    buttons.add(Button('OK', sys.exit))
    # A little spacer between the buttons
    buttons.add(Widget(cminsize=(1, 1)))
    # The second button
    buttons.add(Button('Cancel', lambda: sys.exit(1)))
    # Another glue
    buttons.add(Widget(), weight=1)
    # Run it.
    root.main()

def main():
    init()
    curses.wrapper(demo)

if __name__ == '__main__': main()
<commit_msg>Make the demo script executable<commit_after>#!/usr/bin/env python3

"""
cwidgets demo script, as taken from the module docstring.
"""

import sys, curses

from cwidgets import *

def demo(window):
    # Create the root of the widget hierarchy.
    root = WidgetRoot(window)
    # Make the display less monochrome.
    root.styler = ClassStyler(do_colors=True)
    root.styler.add_style(Widget, background=('white', 'blue'),
                          default=('black', 'white'))
    root.styler.add_style(Focusable, default=('red', 'white'),
                          highlight=('black', 'red'), focus=('white', 'red'))
    root.styler.add_style(EntryBox, default=('white', 'black'),
                          focus=('black', 'white'))
    # Wrap the UI in a Viewport to avoid crashes at small resolutions.
    vp = root.add(Viewport())
    # Push the UI together to avoid spreading everyting over the screen.
    cont = vp.add(AlignContainer())
    # The user-visible "window"; with a border and the bottom line pushed
    # inside by one line height.
    win = cont.add(MarginContainer(border=True, insets=(0, 0, 1, 0)))
    # Decoratively enclose the title
    title_wrapper = win.add(TeeContainer(), slot=MarginContainer.POS_TOP)
    # Add the title
    title = title_wrapper.add(Label('cwidgets demo'))
    # Add the content. This could also be a nested Viewport containing
    # a more complex UI.
    # When text is typed into the entry box, it will increase smoothly (along
    # with the remaining UI) until it's 70 columns or 20 rows (because of the
    # multiline setting, it can have multiple lines) large, then, it will not
    # grow further (along the corresponding axis), and scroll instead.
    content = win.add(EntryBox('Lorem ipsum dolor sit amet', multiline=True,
                               cmaxsize=(70, 20)))
    # Bind a vertical scrollbar to the content
    sbv = win.add(content.bind(Scrollbar(Scrollbar.DIR_VERTICAL)),
                  slot=MarginContainer.POS_RIGHT)
    # The bottom contains a line of buttons stacked below a scrollbar.
    bottom = win.add(VerticalContainer(), slot=MarginContainer.POS_BOTTOM)
    # Add the horizontal scrollbar.
    sbh = bottom.add(content.bind(Scrollbar(Scrollbar.DIR_HORIZONTAL)))
    # The buttons are laid out horizontally.
    buttons = bottom.add(HorizontalContainer())
    # A bare Widget as "glue" to fill the space. An AlignContainer would
    # have been possible as well.
    buttons.add(Widget(), weight=1)
    # The first button
    buttons.add(Button('OK', sys.exit))
    # A little spacer between the buttons
    buttons.add(Widget(cminsize=(1, 1)))
    # The second button
    buttons.add(Button('Cancel', lambda: sys.exit(1)))
    # Another glue
    buttons.add(Widget(), weight=1)
    # Run it.
    root.main()

def main():
    init()
    curses.wrapper(demo)

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


<commit_before>#!/usr/bin/python3

import random
import re
import sys
import aux_functions as auxf
# import pdb

class RollInputError(Exception):
    '''    raised if the input syntax is wrong, tells the use how it should be done'''
    def __init__(self):
        self.msg = 'Try "!r n" (n>0) or "!r help" to find more roll options...'

class SuccessConditionError(Exception):
    '''raised if the success condition is greater than the dice size'''
    def __init__(self):
        self.msg = 'Success condition value should not be greater than the dice size...'

class ExplodingDiceError(Exception):
    '''raised if the explode value is greater than the dice size'''
    def __init__(self):
        self.msg = 'Exploding value should not be greater than dice size'

class ExplodingDiceTooSmallError(Exception):
    '''raised if the explode value is 1 or 2 (avoids long loops)'''
    def __init__(self):
        self.msg = 'Exploding value should be greater than 2'

def dice_input_verification(input_command, default_mode = 'wod'):
    '''
    checks the input command, match0 provides a link to the documentation
    matches 01 and 02 set the default roll mode (!r n)
    match1 is the default roll mode
    matches 2, 22, 3 and 32 are the arbitrary roll modes
    '''
    match0 = re.match('!r help$', input_command)
    match01 = re.match('!r set wod$', input_command)
    match02 = re.match('!r set simple$', input_command)
    match1 = re.match('!r (\d+)$', input_command)
    match2 = re.match('!r (\d+)d(\d+)$', input_command)
    match22 = re.match('!r (\d+)d(\d+)\?(\d+)$', input_command)
    match3 = re.match('!r (\d+)d(\d+)x(\d+)$', input_command)
    match32 = re.match('!r (\d+)d(\d+)x(\d+)\?(\d+)$', input_command)

    if match0 != None:
        auxiliar_message = 'Find the documentation at:\nhttps://github.com/brmedeiros/dicey9000/blob/master/README.md'
        return 0, 0, 0, 0, None, None, auxiliar_message

    elif match01 != None:
        mode_message = 'Default mode (!r n) set to World of Darksness (WoD)'
        return 0, 0, 0, 0, 'wod', mode_message, None

    elif match02 != None:
        mode_message = 'Default mode (!r n) set to simple (nd6)'
        return 0, 0, 0, 0, 'simple', mode_message, None

    elif match1 != None and default_mode == 'wod':
        return int(match1.group(1)), 10, 10, 7, 'wod', None, None

    elif match1 != None and default_mode == 'simple':
        return int(match1.group(1)), 6, 0, 0, 'simple', None, None

    elif match2 != None:
        return int(match2.group(1)), int(match2.group(2)), 0, 0, None, None, None

    elif match22 != None:
        if int(match22.group(3)) > int(match22.group(2)):
            raise SuccessConditionError
            return 0, 0, 0, 0, None, None, None
        else:
            return int(match22.group(1)), int(match22.group(2)), 0, int(match22.group(3)), None, None, None

    elif match3 != None:
        if int(match3.group(3)) > int(match3.group(2)):
            raise ExplodingDiceError
            return 0, 0, 0, 0, None, None, None
        elif int(match3.group(3)) < 3:
            raise ExplodingDiceTooSmallError
            return 0, 0, 0, 0, None, None, None
        else:
            return int(match3.group(1)), int(match3.group(2)), int(match3.group(3)), 0, None, None, None

    elif match32 != None:
        if int(match32.group(3)) > int(match32.group(2)):
            raise ExplodingDiceError
            return 0, 0, 0, 0, None, None, None
        elif int(match32.group(3)) < 3:
            raise ExplodingDiceTooSmallError
            return 0, 0, 0, 0, None, None, None
        elif int(match32.group(4)) > int(match32.group(2)):
            raise SuccessConditionError
            return 0, 0, 0, 0, None, None, None
        else:
            return int(match32.group(1)), int(match32.group(2)), int(match32.group(3)), int(match32.group(4)), None, None, None

    else:
        raise RollInputError
        return 0, 0, 0, 0, None, None, None

def results_recorder(results_list, single_result, formated_results, format_option = False):
    '''
    creates 2 lists of the results, one formated for printing
    no exploding dice: format_option = False
    exploding dice: format_option = True
    '''
    results_list.append(single_result)
    if format_option == False:
        formated_results.append('{0}'.format(single_result))
    else:
        formated_results.append('x.{0}'.format(single_result))

def exploding_dice_check(explode_value, dice_type, results_list, single_result, formated_results):
    '''
    checks if there is an exploding dice condition
    if so the dice is rerolled if its result exceeds the explode value
    '''
    if explode_value > 0:
        while single_result >= explode_value:
            single_result = random.randint(1,dice_type)
            # auxf.sp_print('x.{}'.format(single_result))
            results_recorder(results_list, single_result, formated_results, 1)

def count_resuts_success(results_list, success_condition):
    '''
    counts the number of successes and informs the user about it
    '''
    if success_condition > 0:
        success_counter = 0
        for single_result in results_list:
            if single_result >= success_condition:
                success_counter += 1

        if success_counter == 0:
            success_msg = 'Failure...'
        elif success_counter == 1:
            success_msg = '1 success!'
        elif success_counter > 1:
            success_msg = '{} successes!'.format(success_counter)
        return success_msg

def dice_roll(number_of_dice, dice_type = 10, explode = 0, success_condition = 0):
    '''
    rolls the dice...
    the results list saves the dice rolls if there is a success condition > 0
    formated_results saves the information about exploded dice
    '''
    results = []
    formated_results = []
    for i in range(number_of_dice):
        result = random.randint(1,dice_type)
        # auxf.sp_print('{0:2}.'.format(i+1), result) # for printing in a 2-ish column table
        # auxf.sp_print(result) # for printing in a single line
        results_recorder(results, result, formated_results)
        exploding_dice_check(explode, dice_type, results, result, formated_results)
        # print() # for printing in a 2-ish column table
    # print() # for printing in a single line

    success_msg = count_resuts_success(results, success_condition)
    return results, formated_results, success_msg

def dice_exception_msg(exception, exception_message):
    '''
    returns the exception message and returns False
    (later used to decide if the roll will be made)
    '''
    s1 = 'An exception of type {0} occurred.'.format(type(exception).__name__)
    s2 = '------\n{0}'.format(exception_message)
    msg_string = '\n'.join([s1, s2])
    return msg_string, False

def should_it_roll(input_command, exception_tuple):
    '''
    Makes a dice roll if no dice exception occurs
    If an exception happens, the exception message
    is printed to the user
    '''
    pass

def main():
    try:
        will_roll = True
        n, d, x, s, mode, mode_msg, aux_msg = dice_input_verification(input('Type the roll you want to make...\n'))

        # while mode_msg != None:
        #     print(mode_msg)
        #     n, d, x, s, mode, mode_msg, aux_msg = dice_input_verification(input('Ready...\n'), mode)

        # while aux_msg != None:
        #     print(aux_msg)
        #     n, d, x, s, mode, mode_msg, aux_msg = dice_input_verification(input('Ready...\n'), mode)

    except (SuccessConditionError, ExplodingDiceError, ExplodingDiceTooSmallError, RollInputError) as ex:
        exception_msg_string, will_roll = dice_exception_msg(ex, ex.msg)
        print(exception_msg_string)

    if will_roll == True:
        res, formated_results, r_msg = dice_roll(n, d, x, s)
        results_string = ' '.join(formated_results)
        print(results_string)
        if r_msg != None:
            print(r_msg)

if __name__ == '__main__':
    main()

<commit_msg>fixes wod mode<commit_after>#!/usr/bin/python3

import random
import re
import sys
import aux_functions as auxf
# import pdb

class RollInputError(Exception):
    '''    raised if the input syntax is wrong, tells the use how it should be done'''
    def __init__(self):
        self.msg = 'Try "!r n" (n>0) or "!r help" to find more roll options...'

class SuccessConditionError(Exception):
    '''raised if the success condition is greater than the dice size'''
    def __init__(self):
        self.msg = 'Success condition value should not be greater than the dice size...'

class ExplodingDiceError(Exception):
    '''raised if the explode value is greater than the dice size'''
    def __init__(self):
        self.msg = 'Exploding value should not be greater than dice size'

class ExplodingDiceTooSmallError(Exception):
    '''raised if the explode value is 1 or 2 (avoids long loops)'''
    def __init__(self):
        self.msg = 'Exploding value should be greater than 2'

def dice_input_verification(input_command, default_mode = 'wod'):
    '''
    checks the input command, match0 provides a link to the documentation
    matches 01 and 02 set the default roll mode (!r n)
    match1 is the default roll mode
    matches 2, 22, 3 and 32 are the arbitrary roll modes
    '''
    match0 = re.match('!r help$', input_command)
    match01 = re.match('!r set wod$', input_command)
    match02 = re.match('!r set simple$', input_command)
    match1 = re.match('!r (\d+)$', input_command)
    match2 = re.match('!r (\d+)d(\d+)$', input_command)
    match22 = re.match('!r (\d+)d(\d+)\?(\d+)$', input_command)
    match3 = re.match('!r (\d+)d(\d+)x(\d+)$', input_command)
    match32 = re.match('!r (\d+)d(\d+)x(\d+)\?(\d+)$', input_command)

    if match0 != None:
        auxiliar_message = 'Find the documentation at:\nhttps://github.com/brmedeiros/dicey9000/blob/master/README.md'
        return 0, 0, 0, 0, None, None, auxiliar_message

    elif match01 != None:
        mode_message = 'Default mode (!r n) set to World of Darksness (WoD)'
        return 0, 0, 0, 0, 'wod', mode_message, None

    elif match02 != None:
        mode_message = 'Default mode (!r n) set to simple (nd6)'
        return 0, 0, 0, 0, 'simple', mode_message, None

    elif match1 != None and default_mode == 'wod':
        return int(match1.group(1)), 10, 10, 8, 'wod', None, None

    elif match1 != None and default_mode == 'simple':
        return int(match1.group(1)), 6, 0, 0, 'simple', None, None

    elif match2 != None:
        return int(match2.group(1)), int(match2.group(2)), 0, 0, None, None, None

    elif match22 != None:
        if int(match22.group(3)) > int(match22.group(2)):
            raise SuccessConditionError
            return 0, 0, 0, 0, None, None, None
        else:
            return int(match22.group(1)), int(match22.group(2)), 0, int(match22.group(3)), None, None, None

    elif match3 != None:
        if int(match3.group(3)) > int(match3.group(2)):
            raise ExplodingDiceError
            return 0, 0, 0, 0, None, None, None
        elif int(match3.group(3)) < 3:
            raise ExplodingDiceTooSmallError
            return 0, 0, 0, 0, None, None, None
        else:
            return int(match3.group(1)), int(match3.group(2)), int(match3.group(3)), 0, None, None, None

    elif match32 != None:
        if int(match32.group(3)) > int(match32.group(2)):
            raise ExplodingDiceError
            return 0, 0, 0, 0, None, None, None
        elif int(match32.group(3)) < 3:
            raise ExplodingDiceTooSmallError
            return 0, 0, 0, 0, None, None, None
        elif int(match32.group(4)) > int(match32.group(2)):
            raise SuccessConditionError
            return 0, 0, 0, 0, None, None, None
        else:
            return int(match32.group(1)), int(match32.group(2)), int(match32.group(3)), int(match32.group(4)), None, None, None

    else:
        raise RollInputError
        return 0, 0, 0, 0, None, None, None

def results_recorder(results_list, single_result, formated_results, format_option = False):
    '''
    creates 2 lists of the results, one formated for printing
    no exploding dice: format_option = False
    exploding dice: format_option = True
    '''
    results_list.append(single_result)
    if format_option == False:
        formated_results.append('{0}'.format(single_result))
    else:
        formated_results.append('x.{0}'.format(single_result))

def exploding_dice_check(explode_value, dice_type, results_list, single_result, formated_results):
    '''
    checks if there is an exploding dice condition
    if so the dice is rerolled if its result exceeds the explode value
    '''
    if explode_value > 0:
        while single_result >= explode_value:
            single_result = random.randint(1,dice_type)
            # auxf.sp_print('x.{}'.format(single_result))
            results_recorder(results_list, single_result, formated_results, 1)

def count_resuts_success(results_list, success_condition):
    '''
    counts the number of successes and informs the user about it
    '''
    if success_condition > 0:
        success_counter = 0
        for single_result in results_list:
            if single_result >= success_condition:
                success_counter += 1

        if success_counter == 0:
            success_msg = 'Failure...'
        elif success_counter == 1:
            success_msg = '1 success!'
        elif success_counter > 1:
            success_msg = '{} successes!'.format(success_counter)
        return success_msg

def dice_roll(number_of_dice, dice_type = 10, explode = 0, success_condition = 0):
    '''
    rolls the dice...
    the results list saves the dice rolls if there is a success condition > 0
    formated_results saves the information about exploded dice
    '''
    results = []
    formated_results = []
    for i in range(number_of_dice):
        result = random.randint(1,dice_type)
        # auxf.sp_print('{0:2}.'.format(i+1), result) # for printing in a 2-ish column table
        # auxf.sp_print(result) # for printing in a single line
        results_recorder(results, result, formated_results)
        exploding_dice_check(explode, dice_type, results, result, formated_results)
        # print() # for printing in a 2-ish column table
    # print() # for printing in a single line

    success_msg = count_resuts_success(results, success_condition)
    return results, formated_results, success_msg

def dice_exception_msg(exception, exception_message):
    '''
    returns the exception message and returns False
    (later used to decide if the roll will be made)
    '''
    s1 = 'An exception of type {0} occurred.'.format(type(exception).__name__)
    s2 = '------\n{0}'.format(exception_message)
    msg_string = '\n'.join([s1, s2])
    return msg_string, False

def should_it_roll(input_command, exception_tuple):
    '''
    Makes a dice roll if no dice exception occurs
    If an exception happens, the exception message
    is printed to the user
    '''
    pass

def main():
    try:
        will_roll = True
        n, d, x, s, mode, mode_msg, aux_msg = dice_input_verification(input('Type the roll you want to make...\n'))

        # while mode_msg != None:
        #     print(mode_msg)
        #     n, d, x, s, mode, mode_msg, aux_msg = dice_input_verification(input('Ready...\n'), mode)

        # while aux_msg != None:
        #     print(aux_msg)
        #     n, d, x, s, mode, mode_msg, aux_msg = dice_input_verification(input('Ready...\n'), mode)

    except (SuccessConditionError, ExplodingDiceError, ExplodingDiceTooSmallError, RollInputError) as ex:
        exception_msg_string, will_roll = dice_exception_msg(ex, ex.msg)
        print(exception_msg_string)

    if will_roll == True:
        res, formated_results, r_msg = dice_roll(n, d, x, s)
        results_string = ' '.join(formated_results)
        print(results_string)
        if r_msg != None:
            print(r_msg)

if __name__ == '__main__':
    main()

<|endoftext|>


<commit_before>###
# A permutation generation algorithm.
# this algorithm will generate sequence according as
# dict order.
#
# Under here is two implementation recursive and iterative
###
import math
from common import integer_to_ascending_system_number

def recursive_PGA_with_dict(width):
    '''
    Recursive permutation generation algorithm according
    to dict order.
    '''

    def _recursive_PGA_with_dict(sequence):
        '''
        Note:
            `sequence` must be dict-ordered.
        '''
        # boundary
        if not len(sequence):
            # Empty
            yield sequence
            return

        # recursion
        for i, first_index in enumerate(sequence):
            seq_copy = sequence.copy()
            del seq_copy[i]
            for sub_permutation in _recursive_PGA_with_dict(seq_copy):
                yield [first_index, ] + sub_permutation

    # condition
    assert width >= 0
    assert type(width) is int

    return _recursive_PGA_with_dict(list(range(width)))

def iterative_PGA_with_dict(width):
    '''
    Iterative permutation generation algorithm according
    to dict order.
    '''

    total_numbers = math.factorial(width)
    for i in range(total_numbers):
        asc_number = integer_to_ascending_system_number(i)
        asc_number += (width - len(asc_number)) * [0]  # align
        ret = []
        ordered_index = list(range(width))
        for n in reversed(asc_number):
            ret.append(ordered_index[n])
            del ordered_index[n]
        yield list(ret)

if __name__ == '__main__':
    # Verify results
    #for i_result, r_result in zip(iterative_PGA_with_dict(9), recursive_PGA_with_dict(9)):
    #    if i_result != r_result:
    #        # print(i_result, r_result)
    #        print('Failed!')

    # For profiler
    # python -m cProfile dict.py
    #for r_result in recursive_PGA_with_dict(9):
    #   pass

    # For profiler
    # python -m cProfile dict.py
    #for i_result in iterative_PGA_with_dict(9):
    #    pass
    pass
<commit_msg>simple implementation to generate dict order permutation with opencl<commit_after>###
# A permutation generation algorithm.
# this algorithm will generate sequence according as
# dict order.
#
# Under here is two implementation recursive and iterative
###
import math
import pyopencl as cl
import numpy as np

from common import integer_to_ascending_system_number

def recursive_PGA_with_dict(width):
    '''
    Recursive permutation generation algorithm according
    to dict order.
    '''

    def _recursive_PGA_with_dict(sequence):
        '''
        Note:
            `sequence` must be dict-ordered.
        '''
        # boundary
        if not len(sequence):
            # Empty
            yield sequence
            return

        # recursion
        for i, first_index in enumerate(sequence):
            seq_copy = sequence.copy()
            del seq_copy[i]
            for sub_permutation in _recursive_PGA_with_dict(seq_copy):
                yield [first_index, ] + sub_permutation

    # condition
    assert width >= 0
    assert type(width) is int

    return _recursive_PGA_with_dict(list(range(width)))

def iterative_PGA_with_dict(width):
    '''
    Iterative permutation generation algorithm according
    to dict order.
    '''

    total_numbers = math.factorial(width)
    for i in range(total_numbers):
        asc_number = integer_to_ascending_system_number(i)
        asc_number += (width - len(asc_number)) * [0]  # align
        ret = []
        ordered_index = list(range(width))
        for n in reversed(asc_number):
            ret.append(ordered_index[n])
            del ordered_index[n]
        yield list(ret)

def opencl_PGA_with_dict(width):
    total_numbers = math.factorial(width)

    ctx = cl.create_some_context()
    queue = cl.CommandQueue(ctx)

    program = cl.Program(ctx, """
        __kernel void integer_to_ascending_system_number(__global long* asc_number) {{
            int gid = get_global_id(0);
            int global_addr = gid * {width};
            int system = 1;
            while(gid) {{
                asc_number[global_addr+system-1] = gid % system;
                gid /= system;
                system += 1;
            }}
        }}

        __kernel void PGA_with_dict(__global const long* asc_number, __global long* result) {{
            int global_addr = get_global_id(0) * {width};
            int unpicked[{width}];
            int passby;
            int i, j;
            for (i = 0; i < {width}; i++)
                unpicked[i] = 1;

            for (i = {width}-1; i >= 0; i--) {{
                passby = 0;
                for (j = 0; j < {width}; j++) {{
                    passby += unpicked[j];
                    if (passby > asc_number[global_addr+i]) {{
                        unpicked[j] = 0;
                        result[global_addr+{width}-1-i] = j;
                        break;
                    }}
                }}
            }}
        }}
    """.format(width=width)).build()

    asc = np.zeros((total_numbers, width), np.long)
    asc_buf = cl.Buffer(ctx, cl.mem_flags.READ_WRITE, asc.nbytes)

    result = np.zeros((total_numbers, width), np.long)
    result_buf = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, result.nbytes)

    program.integer_to_ascending_system_number(queue, asc.shape, None, asc_buf)
    program.PGA_with_dict(queue, asc.shape, None, asc_buf, result_buf)

    cl.enqueue_copy(queue, result, result_buf)
    return result

if __name__ == '__main__':
    # Verify results
    #for i_result, r_result in zip(iterative_PGA_with_dict(9), recursive_PGA_with_dict(9)):
    #    if i_result != r_result:
    #        # print(i_result, r_result)
    #        print('Failed!')

    # For profiler
    # python -m cProfile dict.py
    #for r_result in recursive_PGA_with_dict(9):
    #   pass

    # For profiler
    # python -m cProfile dict.py
    #for i_result in iterative_PGA_with_dict(9):
    #    pass

    # For profiler
    # python -m cProfile dict.py
    #for cl_result in opencl_PGA_with_dict(6):
    #    pass
    pass
<|endoftext|>