<commit_before>#! /usr/bin/env python
# -*- coding: utf-8 -*-

import time
import gettext
_ = gettext.gettext
import dbconf
from utils import DBM
import urllib
import urllib2
import socket

"""
ALTER TABLE  `meneame`.`users` ADD INDEX (  `user_url` );

ALTER TABLE  `blogs` ADD  `blog_feed` CHAR( 128 ) NULL DEFAULT NULL AFTER  `blog_url` ,
ADD  `blog_feed_checked` TIMESTAMP NULL AFTER  `blog_feed`,
ADD  `blog_feed_read` TIMESTAMP NULL AFTER  `blog_feed_checked`;

ALTER TABLE  `blogs` ADD  `blog_title` CHAR( 128 ) NULL DEFAULT NULL;

CREATE TABLE  `meneame`.`rss` (
`blog_id` INT UNSIGNED NOT NULL ,
`user_id` INT UNSIGNED NOT NULL DEFAULT  '0',
`link_id` INT UNSIGNED NULL ,
`date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`date_parsed` TIMESTAMP NULL ,
`url` CHAR( 250 ) NOT NULL ,
`title` CHAR( 250 ) NOT NULL
) ENGINE = INNODB;

ALTER TABLE  `meneame`.`rss` ADD INDEX (  `date` );
ALTER TABLE  `meneame`.`rss` ADD INDEX (  `blog_id` ,  `date` );
ALTER TABLE  `meneame`.`rss` ADD INDEX (  `user_id` ,  `date` );
ALTER TABLE  `meneame`.`rss` ADD UNIQUE ( `url` );
"""

def main():

	# timeout in seconds
	timeout = 10
	socket.setdefaulttimeout(timeout)

	# Delete old entries
	c = DBM.cursor('update')
	c.execute("delete from rss where date < date_sub(now(), interval %s day)", (dbconf.blogs['days_to_keep'],))
	DBM.commit()
	c.close()

	users = set()
	news = set()
	blogs = get_candidate_blogs(dbconf.blogs['days_published'], dbconf.blogs['min_karma'])
	for o in blogs:
		entries = o.read_feed()
		time.sleep(3)
		if entries > 0:
			users.add(o.user)
			news.add(o)

	if dbconf.blogs['post_user'] and dbconf.blogs['post_key'] and users:
		post = _('Nuevo apunte en el blog de: ')
		for o in news:
			post += "@" + o.user
			for l in o.links:
				post += " " + l
			post += "\n"

		post += '\nhttp://'+dbconf.domain+dbconf.blogs['viewer']+" #blogs"
		print post
		try:
			f = urllib2.urlopen('http://'+dbconf.domain+dbconf.blogs['newpost']+'?user='+dbconf.blogs['post_user']+'&key='+dbconf.blogs['post_key']+'&text='+urllib.quote_plus(post))
			print f.read(100)
			f.close()
		except KeyError:
			pass

def get_candidate_blogs(days, min_karma):
	now = time.time()
	blogs = set()
	results = set()
	blogs_ids = set()
	users_ids = set()
	cursor = DBM.cursor()
	c = DBM.cursor()

	# Select users that have at least one published
	cursor.execute("SELECT link_blog, blog_url, blog_feed, UNIX_TIMESTAMP(blog_feed_checked), UNIX_TIMESTAMP(blog_feed_read), count(*) as n  from links, blogs where link_status in ('published') and link_date > date_sub(now(), interval %s day) and blog_id = link_blog and blog_type='blog' and (blog_feed_read is null or blog_feed_read < date_sub(now(), interval 1 hour)) group by blog_id", (days,))
	for row in cursor:
		o = BaseBlogs()
		o.id, o.url, o.feed, o.checked, o.read, o.counter = row
		o.base_url = o.url.replace('http://', '').replace('https://', '').replace('www.', '')
		if o.is_banned():
			continue

		if o.counter < days:
			c.execute("select user_login, user_id, user_karma from users where user_url in (%s, %s, %s, %s, %s, %s) and user_karma > %s and user_level not in ('disabled', 'autodisabled') order by user_karma desc limit 1",
					('http://'+o.base_url, 'http://www.'+o.base_url, 'http://'+o.base_url+'/', 'http://www.'+o.base_url+'/', o.base_url, 'www.'+o.base_url, min_karma))
			r = c.fetchone()
			if r is not None:
				o.user, o.user_id, o.karma = r
				blogs.add(o)
				blogs_ids.add(o.id)
				users_ids.add(o.user_id)

	# Select active users that have no published posts
	cursor.execute("select blog_id, blog_url, blog_feed, UNIX_TIMESTAMP(blog_feed_checked), UNIX_TIMESTAMP(blog_feed_read), user_login, user_id, user_karma from users, blogs \
			where user_karma >= %s and user_url like 'http://%%' and user_level not in ('disabled', 'autodisabled') \
			and user_modification > date_sub(now(), interval %s day) \
			and user_date < date_sub(now(), interval %s day) \
			and blog_url in ( \
				concat('http://www.',replace(replace(user_url, 'http://', ''), 'www.', '')), \
				concat('http://',replace(replace(user_url, 'http://', ''), 'www.', '')), \
				concat('http://www.',replace(replace(user_url, 'http://', ''), 'www.', ''), '/'), \
				concat('http://',replace(replace(user_url, 'http://', ''), 'www.', ''), '/') \
			) \
			and (blog_feed_read is null or blog_feed_read < date_sub(now(), interval 1 hour)) \
			order by blog_id desc, user_karma desc", (dbconf.blogs['active_min_karma'], dbconf.blogs['active_min_activity'], dbconf.blogs['active_min_age']) )
	for row in cursor:
		o = BaseBlogs()
		o.id, o.url, o.feed, o.checked, o.read, o.user, o.user_id, o.karma = row
		o.base_url = o.url.replace('http://', '').replace('https://', '').replace('www.', '')
		if o.id not in blogs_ids and o.user_id not in users_ids:
				blogs.add(o)
				users_ids.add(o.user_id)
				blogs_ids.add(o.id)

	feeds_read = 0
	sorted_blogs = sorted(blogs, cmp=lambda x,y: cmp(x.read, y.read))
	for o in sorted_blogs:
		if feeds_read >= dbconf.blogs['max_feeds']: break
		if not o.is_banned():
				# Check the number of remaining entries
				c.execute("select count(*) from rss where user_id = %s and date > date_sub(now(), interval 1 day)", (o.user_id,))
				n_entries, = c.fetchone()
				# Calculate the number of remaining entries
				o.max = int(round(o.karma/dbconf.blogs['karma_divisor'])) - n_entries
				if not o.max > 0:
					print "Max entries <= 0:", n_entries, o.karma, o.url
					continue

				if (not o.feed and (not o.checked or o.checked < now - 86400)) or (o.checked and o.checked < now - 86400*7):
					o.get_feed_info()

				if o.feed and (not o.read or o.read < now - 3600):
					results.add(o)
					print "Added ", o.id, o.user, o.url
					feeds_read += 1
	cursor.close()
	return results

if __name__ == "__main__":
	main()
<commit_msg>Now using multi-line queries instead of single-line. solving some PEP-C0301<commit_after>#! /usr/bin/env python
# -*- coding: utf-8 -*-

import time
import gettext
_ = gettext.gettext
import dbconf
from utils import DBM
import urllib
import urllib2
import socket

"""
ALTER TABLE  `meneame`.`users` ADD INDEX (  `user_url` );

ALTER TABLE  `blogs` ADD  `blog_feed` CHAR( 128 ) NULL DEFAULT NULL AFTER  `blog_url` ,
ADD  `blog_feed_checked` TIMESTAMP NULL AFTER  `blog_feed`,
ADD  `blog_feed_read` TIMESTAMP NULL AFTER  `blog_feed_checked`;

ALTER TABLE  `blogs` ADD  `blog_title` CHAR( 128 ) NULL DEFAULT NULL;

CREATE TABLE  `meneame`.`rss` (
`blog_id` INT UNSIGNED NOT NULL ,
`user_id` INT UNSIGNED NOT NULL DEFAULT  '0',
`link_id` INT UNSIGNED NULL ,
`date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`date_parsed` TIMESTAMP NULL ,
`url` CHAR( 250 ) NOT NULL ,
`title` CHAR( 250 ) NOT NULL
) ENGINE = INNODB;

ALTER TABLE  `meneame`.`rss` ADD INDEX (  `date` );
ALTER TABLE  `meneame`.`rss` ADD INDEX (  `blog_id` ,  `date` );
ALTER TABLE  `meneame`.`rss` ADD INDEX (  `user_id` ,  `date` );
ALTER TABLE  `meneame`.`rss` ADD UNIQUE ( `url` );
"""

def main():

	# timeout in seconds
	timeout = 10
	socket.setdefaulttimeout(timeout)

	# Delete old entries
	c = DBM.cursor('update')
	query = """
		DELETE FROM rss
			WHERE date < date_sub(now(), interval %s day)
	"""
	c.execute(query, (dbconf.blogs['days_to_keep'],))
	DBM.commit()
	c.close()

	users = set()
	news = set()
	blogs = get_candidate_blogs(dbconf.blogs['days_published'], dbconf.blogs['min_karma'])
	for o in blogs:
		entries = o.read_feed()
		time.sleep(3)
		if entries > 0:
			users.add(o.user)
			news.add(o)

	if dbconf.blogs['post_user'] and dbconf.blogs['post_key'] and users:
		post = _('Nuevo apunte en el blog de: ')
		for o in news:
			post += "@" + o.user
			for l in o.links:
				post += " " + l
			post += "\n"

		post += '\nhttp://'+dbconf.domain+dbconf.blogs['viewer']+" #blogs"
		print post
		try:
			f = urllib2.urlopen('http://'+dbconf.domain+dbconf.blogs['newpost']+'?user='+dbconf.blogs['post_user']+'&key='+dbconf.blogs['post_key']+'&text='+urllib.quote_plus(post))
			print f.read(100)
			f.close()
		except KeyError:
			pass

def get_candidate_blogs(days, min_karma):
	now = time.time()
	blogs = set()
	results = set()
	blogs_ids = set()
	users_ids = set()
	cursor = DBM.cursor()
	c = DBM.cursor()

	# Select users that have at least one published
	query = """
		SELECT link_blog, blog_url, blog_feed,
				UNIX_TIMESTAMP(blog_feed_checked),
				UNIX_TIMESTAMP(blog_feed_read),
				count(*) as n
			FROM links, blogs
			WHERE link_status in ('published')
				AND link_date > date_sub(now(), interval %s day)
				AND blog_id = link_blog
				AND blog_type='blog'
				AND (blog_feed_read is null
						OR blog_feed_read < date_sub(now(), interval 1 hour))
			GROUP BY blog_id
	"""
	cursor.execute(query, (days,))
	for row in cursor:
		o = BaseBlogs()
		o.id, o.url, o.feed, o.checked, o.read, o.counter = row
		o.base_url = o.url.replace('http://', '').replace('https://', '').replace('www.', '')
		if o.is_banned():
			continue

		if o.counter < days:
			query = """
				SELECT user_login, user_id, user_karma
					FROM users
					WHERE user_url in (%s, %s, %s, %s, %s, %s)
						AND user_karma > %s
						AND user_level not in ('disabled', 'autodisabled')
					ORDER BY user_karma desc limit 1"
			"""
			c.execute(query,('http://'+o.base_url,
							 'http://www.'+o.base_url,
							 'http://'+o.base_url+'/',
							 'http://www.'+o.base_url+'/',
							 o.base_url, 'www.'+o.base_url, min_karma))
			r = c.fetchone()
			if r is not None:
				o.user, o.user_id, o.karma = r
				blogs.add(o)
				blogs_ids.add(o.id)
				users_ids.add(o.user_id)

	# Select active users that have no published posts
	query = """
	SELECT blog_id, blog_url, blog_feed, UNIX_TIMESTAMP(blog_feed_checked),
			UNIX_TIMESTAMP(blog_feed_read), user_login, user_id, user_karma
		FROM users, blogs
		WHERE user_karma >= %s
			AND user_url like 'http://%%'
			AND user_level not in ('disabled', 'autodisabled')
			AND user_modification > date_sub(now(), interval %s day)
			AND user_date < date_sub(now(), interval %s day)
			AND blog_url in (
				concat('http://www.',replace(replace(user_url, 'http://', ''), 'www.', '')),
				concat('http://',replace(replace(user_url, 'http://', ''), 'www.', '')),
				concat('http://www.',replace(replace(user_url, 'http://', ''), 'www.', ''), '/'),
				concat('http://',replace(replace(user_url, 'http://', ''), 'www.', ''), '/')
			)
			AND (blog_feed_read is null or blog_feed_read < date_sub(now(), interval 1 hour))
			order by blog_id desc, user_karma desc
	"""
	cursor.execute(query, (dbconf.blogs['active_min_karma'],
							dbconf.blogs['active_min_activity'],
							dbconf.blogs['active_min_age']) )
	for row in cursor:
		o = BaseBlogs()
		o.id, o.url, o.feed, o.checked, o.read, o.user, o.user_id, o.karma = row
		o.base_url = o.url.replace('http://', '').replace('https://', '').replace('www.', '')
		if o.id not in blogs_ids and o.user_id not in users_ids:
				blogs.add(o)
				users_ids.add(o.user_id)
				blogs_ids.add(o.id)

	feeds_read = 0
	sorted_blogs = sorted(blogs, cmp=lambda x,y: cmp(x.read, y.read))
	for o in sorted_blogs:
		if feeds_read >= dbconf.blogs['max_feeds']: break
		if not o.is_banned():
				# Check the number of remaining entries
				query = """
				SELECT count(*)
					FROM rss
					WHERE user_id = %s
						AND date > date_sub(now(), interval 1 day)
				"""
				c.execute(query, (o.user_id,))
				n_entries, = c.fetchone()
				# Calculate the number of remaining entries
				o.max = int(round(o.karma/dbconf.blogs['karma_divisor'])) - n_entries
				if not o.max > 0:
					print "Max entries <= 0:", n_entries, o.karma, o.url
					continue

				if (not o.feed and (not o.checked or o.checked < now - 86400)) or (o.checked and o.checked < now - 86400*7):
					o.get_feed_info()

				if o.feed and (not o.read or o.read < now - 3600):
					results.add(o)
					print "Added ", o.id, o.user, o.url
					feeds_read += 1
	cursor.close()
	return results

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


<commit_before># Import libnacl libs
import libnacl.public
import libnacl.dual

# Import python libs
import unittest

class TestPublic(unittest.TestCase):
    '''
    '''
    def test_secretkey(self):
        '''
        '''
        msg = b'You\'ve got two empty halves of coconut and you\'re bangin\' \'em together.'
        bob = libnacl.dual.DualSecret()
        alice = libnacl.dual.DualSecret()
        bob_box = libnacl.public.Box(bob.sk, alice.pk)
        alice_box = libnacl.public.Box(alice.sk, bob.pk)
        bob_ctxt = bob_box.encrypt(msg)
        self.assertNotEqual(msg, bob_ctxt)
        bclear = alice_box.decrypt(bob_ctxt)
        self.assertEqual(msg, bclear)
        alice_ctxt = alice_box.encrypt(msg)
        self.assertNotEqual(msg, alice_ctxt)
        aclear = alice_box.decrypt(alice_ctxt)
        self.assertEqual(msg, aclear)
        self.assertNotEqual(bob_ctxt, alice_ctxt)

    def test_publickey(self):
        '''
        '''
        msg = b'You\'ve got two empty halves of coconut and you\'re bangin\' \'em together.'
        bob = libnacl.dual.DualSecret()
        alice = libnacl.dual.DualSecret()
        alice_pk = libnacl.public.PublicKey(alice.pk)
        bob_box = libnacl.public.Box(bob.sk, alice_pk)
        alice_box = libnacl.public.Box(alice.sk, bob.pk)
        bob_ctxt = bob_box.encrypt(msg)
        self.assertNotEqual(msg, bob_ctxt)
        bclear = alice_box.decrypt(bob_ctxt)
        self.assertEqual(msg, bclear)

<commit_msg>Add signing tests to dual tests<commit_after># Import libnacl libs
import libnacl.public
import libnacl.dual

# Import python libs
import unittest

class TestDual(unittest.TestCase):
    '''
    '''
    def test_secretkey(self):
        '''
        '''
        msg = b'You\'ve got two empty halves of coconut and you\'re bangin\' \'em together.'
        bob = libnacl.dual.DualSecret()
        alice = libnacl.dual.DualSecret()
        bob_box = libnacl.public.Box(bob.sk, alice.pk)
        alice_box = libnacl.public.Box(alice.sk, bob.pk)
        bob_ctxt = bob_box.encrypt(msg)
        self.assertNotEqual(msg, bob_ctxt)
        bclear = alice_box.decrypt(bob_ctxt)
        self.assertEqual(msg, bclear)
        alice_ctxt = alice_box.encrypt(msg)
        self.assertNotEqual(msg, alice_ctxt)
        aclear = alice_box.decrypt(alice_ctxt)
        self.assertEqual(msg, aclear)
        self.assertNotEqual(bob_ctxt, alice_ctxt)

    def test_publickey(self):
        '''
        '''
        msg = b'You\'ve got two empty halves of coconut and you\'re bangin\' \'em together.'
        bob = libnacl.dual.DualSecret()
        alice = libnacl.dual.DualSecret()
        alice_pk = libnacl.public.PublicKey(alice.pk)
        bob_box = libnacl.public.Box(bob.sk, alice_pk)
        alice_box = libnacl.public.Box(alice.sk, bob.pk)
        bob_ctxt = bob_box.encrypt(msg)
        self.assertNotEqual(msg, bob_ctxt)
        bclear = alice_box.decrypt(bob_ctxt)
        self.assertEqual(msg, bclear)

    def test_sign(self):
        msg = (b'Well, that\'s no ordinary rabbit.  That\'s the most foul, '
               b'cruel, and bad-tempered rodent you ever set eyes on.')
        signer = libnacl.dual.DualSecret()
        signed = signer.sign(msg)
        signature = signer.signature(msg)
        self.assertNotEqual(msg, signed)
        veri = libnacl.sign.Verifier(signer.hex_vk())
        verified = veri.verify(signed)
        verified2 = veri.verify(signature + msg)
        self.assertEqual(verified, msg)
        self.assertEqual(verified2, msg)
<|endoftext|>


<commit_before>NOTHING = 0
UP = 1
RIGHT = 2
DOWN = 3
LEFT = 4

GRASS = 0
LAVA = 1
BERRIES = 2
KATS = 3
WALLS  = 4<commit_msg>Fix plurality bullshit<commit_after>NOTHING = 0
UP = 1
RIGHT = 2
DOWN = 3
LEFT = 4

GRASS = 0
LAVA = 1
BERRY = 2
KAT = 3
WALL  = 4<|endoftext|>


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

import unittest2

from train import util

class TestStackedDict(unittest2.TestCase):
    def test_init(self):
        sd = util.StackedDict('parent')

        self.assertEqual(sd._parent, 'parent')
        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_getitem_deleted(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._values['spam'] = 'alternate'
        sd._deleted.add('spam')

        with self.assertRaises(KeyError):
            dummy = sd['spam']

    def test_getitem_local(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._values['spam'] = 'alternate'

        self.assertEqual(sd['spam'], 'alternate')

    def test_getitem_noparent(self):
        sd = util.StackedDict()

        with self.assertRaises(KeyError):
            dummy = sd['spam']

    def test_getitem_parent(self):
        sd = util.StackedDict(dict(spam='spammer'))

        self.assertEqual(sd['spam'], 'spammer')

    def test_setitem(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar'])

        sd['spam'] = 'alternate'

        self.assertEqual(sd._values, dict(spam='alternate'))
        self.assertEqual(sd._deleted, set(['foobar']))

    def test_setitem_deleted(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar', 'spam'])

        sd['spam'] = 'alternate'

        self.assertEqual(sd._values, dict(spam='alternate'))
        self.assertEqual(sd._deleted, set(['foobar']))

    def test_delitem_deleted(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._deleted = set(['spam'])

        with self.assertRaises(KeyError):
            del sd['spam']

        self.assertEqual(sd._deleted, set(['spam']))
        self.assertEqual(sd._values, {})

    def test_delitem_local(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._values['spam'] = 'alternate'

        del sd['spam']

        self.assertEqual(sd._deleted, set(['spam']))
        self.assertEqual(sd._values, {})

    def test_delitem_noparent(self):
        sd = util.StackedDict()

        with self.assertRaises(KeyError):
            del sd['spam']

        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_delitem_parent_nokey(self):
        sd = util.StackedDict({})

        with self.assertRaises(KeyError):
            del sd['spam']

        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_delitem_parent_only(self):
        sd = util.StackedDict(dict(spam='spammer'))

        del sd['spam']

        self.assertEqual(sd._deleted, set(['spam']))
        self.assertEqual(sd._values, {})

    def test_iter_noparent(self):
        sd = util.StackedDict()
        sd._values = dict(a=1, b=2, c=3)

        result = list(iter(sd))

        self.assertEqual(len(result), 3)
        self.assertEqual(set(result), set('abc'))

    def test_iter_withparent(self):
        sd = util.StackedDict(dict(b=2, d=4, e=5, f=6, g=7))
        sd._deleted = set('fg')
        sd._values = dict(a=1, b=2, c=3)

        result = list(iter(sd))

        self.assertEqual(len(result), 5)
        self.assertEqual(set(result), set('abcde'))

    def test_len(self):
        sd = util.StackedDict(dict(b=2, d=4, e=5, f=6, g=7))
        sd._deleted = set('fg')
        sd._values = dict(a=1, b=2, c=3)

        result = len(sd)

        self.assertEqual(result, 5)

    def test_reset_deleted(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar', 'spam'])
        sd._values = dict(barfoo='foobar')

        sd.reset('spam')

        self.assertEqual(sd._deleted, set(['foobar']))
        self.assertEqual(sd._values, dict(barfoo='foobar'))

    def test_reset_overridden(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar'])
        sd._values = dict(barfoo='foobar', spam='spammer')

        sd.reset('spam')

        self.assertEqual(sd._deleted, set(['foobar']))
        self.assertEqual(sd._values, dict(barfoo='foobar'))

    def test_reset_all(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar'])
        sd._values = dict(barfoo='foobar')

        sd.reset()

        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_copy(self):
        parent = dict(b=22, d=4, e=5, f=6, g=7)
        sd = util.StackedDict(parent)
        sd._deleted = set('fg')
        sd._values = dict(a=1, b=2, c=3)

        result = sd.copy()

        del parent['d']
        parent['e'] = 55
        sd._deleted.add('a')
        del sd._values['a']
        del sd._values['b']
        sd._values['f'] = 66

        self.assertEqual(result, dict(a=1, b=2, c=3, d=4, e=5))
<commit_msg>Add tests for Launcher and related utilities.<commit_after># Copyright 2013 Rackspace
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import signal

import mock
import unittest2

from train import util

class TestStackedDict(unittest2.TestCase):
    def test_init(self):
        sd = util.StackedDict('parent')

        self.assertEqual(sd._parent, 'parent')
        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_getitem_deleted(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._values['spam'] = 'alternate'
        sd._deleted.add('spam')

        with self.assertRaises(KeyError):
            dummy = sd['spam']

    def test_getitem_local(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._values['spam'] = 'alternate'

        self.assertEqual(sd['spam'], 'alternate')

    def test_getitem_noparent(self):
        sd = util.StackedDict()

        with self.assertRaises(KeyError):
            dummy = sd['spam']

    def test_getitem_parent(self):
        sd = util.StackedDict(dict(spam='spammer'))

        self.assertEqual(sd['spam'], 'spammer')

    def test_setitem(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar'])

        sd['spam'] = 'alternate'

        self.assertEqual(sd._values, dict(spam='alternate'))
        self.assertEqual(sd._deleted, set(['foobar']))

    def test_setitem_deleted(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar', 'spam'])

        sd['spam'] = 'alternate'

        self.assertEqual(sd._values, dict(spam='alternate'))
        self.assertEqual(sd._deleted, set(['foobar']))

    def test_delitem_deleted(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._deleted = set(['spam'])

        with self.assertRaises(KeyError):
            del sd['spam']

        self.assertEqual(sd._deleted, set(['spam']))
        self.assertEqual(sd._values, {})

    def test_delitem_local(self):
        sd = util.StackedDict(dict(spam='spammer'))
        sd._values['spam'] = 'alternate'

        del sd['spam']

        self.assertEqual(sd._deleted, set(['spam']))
        self.assertEqual(sd._values, {})

    def test_delitem_noparent(self):
        sd = util.StackedDict()

        with self.assertRaises(KeyError):
            del sd['spam']

        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_delitem_parent_nokey(self):
        sd = util.StackedDict({})

        with self.assertRaises(KeyError):
            del sd['spam']

        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_delitem_parent_only(self):
        sd = util.StackedDict(dict(spam='spammer'))

        del sd['spam']

        self.assertEqual(sd._deleted, set(['spam']))
        self.assertEqual(sd._values, {})

    def test_iter_noparent(self):
        sd = util.StackedDict()
        sd._values = dict(a=1, b=2, c=3)

        result = list(iter(sd))

        self.assertEqual(len(result), 3)
        self.assertEqual(set(result), set('abc'))

    def test_iter_withparent(self):
        sd = util.StackedDict(dict(b=2, d=4, e=5, f=6, g=7))
        sd._deleted = set('fg')
        sd._values = dict(a=1, b=2, c=3)

        result = list(iter(sd))

        self.assertEqual(len(result), 5)
        self.assertEqual(set(result), set('abcde'))

    def test_len(self):
        sd = util.StackedDict(dict(b=2, d=4, e=5, f=6, g=7))
        sd._deleted = set('fg')
        sd._values = dict(a=1, b=2, c=3)

        result = len(sd)

        self.assertEqual(result, 5)

    def test_reset_deleted(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar', 'spam'])
        sd._values = dict(barfoo='foobar')

        sd.reset('spam')

        self.assertEqual(sd._deleted, set(['foobar']))
        self.assertEqual(sd._values, dict(barfoo='foobar'))

    def test_reset_overridden(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar'])
        sd._values = dict(barfoo='foobar', spam='spammer')

        sd.reset('spam')

        self.assertEqual(sd._deleted, set(['foobar']))
        self.assertEqual(sd._values, dict(barfoo='foobar'))

    def test_reset_all(self):
        sd = util.StackedDict()
        sd._deleted = set(['foobar'])
        sd._values = dict(barfoo='foobar')

        sd.reset()

        self.assertEqual(sd._deleted, set())
        self.assertEqual(sd._values, {})

    def test_copy(self):
        parent = dict(b=22, d=4, e=5, f=6, g=7)
        sd = util.StackedDict(parent)
        sd._deleted = set('fg')
        sd._values = dict(a=1, b=2, c=3)

        result = sd.copy()

        del parent['d']
        parent['e'] = 55
        sd._deleted.add('a')
        del sd._values['a']
        del sd._values['b']
        sd._values['f'] = 66

        self.assertEqual(result, dict(a=1, b=2, c=3, d=4, e=5))

class TestSignalExit(unittest2.TestCase):
    def test_init(self):
        se = util.SignalExit(signal.SIGTERM, 25)

        self.assertEqual(se.signo, signal.SIGTERM)
        self.assertEqual(se.code, 25)

class TestException(BaseException):
    pass

class TestLauncher(unittest2.TestCase):
    def test_class_attrs(self):
        self.assertEqual(util.Launcher.signames[signal.SIGTERM], 'SIGTERM')
        self.assertEqual(util.Launcher.signames[signal.SIGINT], 'SIGINT')
        self.assertTrue(signal.SIGTERM in util.Launcher.death_sigs)
        self.assertTrue(signal.SIGINT in util.Launcher.death_sigs)

    def test_init_noargs(self):
        self.assertRaises(TypeError, util.Launcher, a=1, b=2, c=3)

    def test_init(self):
        launcher = util.Launcher('start', 'arg1', 'arg2', 'arg3',
                                 a='arg4', b='arg5', c='arg6')

        self.assertEqual(launcher.start_func, 'start')
        self.assertEqual(launcher.start_args, ('arg1', 'arg2', 'arg3'))
        self.assertEqual(launcher.start_kwargs,
                         dict(a='arg4', b='arg5', c='arg6'))

    @mock.patch.object(signal, 'signal')
    def test_install_handler(self, mock_signal):
        launcher = util.Launcher('start')

        launcher._install_handler('handler')

        mock_signal.assert_has_calls([
            mock.call(signal.SIGTERM, 'handler'),
            mock.call(signal.SIGINT, 'handler'),
        ], any_order=True)

    @mock.patch.object(util.Launcher, '_install_handler')
    def test_handle_signal(self, mock_install_handler):
        launcher = util.Launcher('start')

        with self.assertRaises(util.SignalExit) as exc:
            launcher._handle_signal(25, 'some frame')

        self.assertEqual(exc.exception.signo, 25)
        mock_install_handler.assert_called_once_with(signal.SIG_DFL)

    @mock.patch('os.getpid', return_value=5678)
    @mock.patch('os.fork', return_value=1234)
    @mock.patch('os._exit')
    @mock.patch.object(util, 'LOG')
    @mock.patch.object(util.Launcher, '_install_handler')
    def test_start_parent(self, mock_install_handler, mock_LOG, mock_exit,
                          mock_fork, mock_getpid):
        starter = mock.Mock()
        launcher = util.Launcher(starter)

        result = launcher.start()

        self.assertEqual(result, 1234)
        mock_fork.assert_called_once_with()
        self.assertFalse(mock_install_handler.called)
        self.assertFalse(mock_getpid.called)
        self.assertFalse(starter.called)
        self.assertEqual(mock_LOG.method_calls, [])
        self.assertFalse(mock_exit.called)

    @mock.patch('os.getpid', return_value=1234)
    @mock.patch('os.fork', return_value=0)
    @mock.patch('os._exit')
    @mock.patch.object(util, 'LOG')
    @mock.patch.object(util.Launcher, '_install_handler')
    def test_start_normal(self, mock_install_handler, mock_LOG, mock_exit,
                          mock_fork, mock_getpid):
        starter = mock.Mock()
        launcher = util.Launcher(starter, 'arg1', 'arg2', a='arg3', b='arg4')

        result = launcher.start()

        self.assertEqual(result, None)
        mock_fork.assert_called_once_with()
        mock_install_handler.assert_called_once_with(launcher._handle_signal)
        mock_getpid.assert_called_once_with()
        starter.assert_called_once_with('arg1', 'arg2', a='arg3', b='arg4')
        self.assertEqual(mock_LOG.method_calls, [])
        mock_exit.assert_called_once_with(0)

    @mock.patch('os.getpid', return_value=1234)
    @mock.patch('os.fork', return_value=0)
    @mock.patch('os._exit')
    @mock.patch.object(util, 'LOG')
    @mock.patch.object(util.Launcher, '_install_handler')
    def test_start_signal(self, mock_install_handler, mock_LOG, mock_exit,
                          mock_fork, mock_getpid):
        starter = mock.Mock(side_effect=util.SignalExit(signal.SIGTERM))
        launcher = util.Launcher(starter)

        result = launcher.start()

        self.assertEqual(result, None)
        mock_fork.assert_called_once_with()
        mock_install_handler.assert_called_once_with(launcher._handle_signal)
        mock_getpid.assert_called_once_with()
        starter.assert_called_once_with()
        mock_LOG.assert_has_calls([
            mock.call.info("1234: Caught SIGTERM, exiting"),
        ])
        self.assertEqual(len(mock_LOG.method_calls), 1)
        mock_exit.assert_called_once_with(1)

    @mock.patch('os.getpid', return_value=1234)
    @mock.patch('os.fork', return_value=0)
    @mock.patch('os._exit')
    @mock.patch.object(util, 'LOG')
    @mock.patch.object(util.Launcher, '_install_handler')
    def test_start_exit(self, mock_install_handler, mock_LOG, mock_exit,
                        mock_fork, mock_getpid):
        starter = mock.Mock(side_effect=SystemExit(5))
        launcher = util.Launcher(starter)

        result = launcher.start()

        self.assertEqual(result, None)
        mock_fork.assert_called_once_with()
        mock_install_handler.assert_called_once_with(launcher._handle_signal)
        mock_getpid.assert_called_once_with()
        starter.assert_called_once_with()
        self.assertEqual(mock_LOG.method_calls, [])
        mock_exit.assert_called_once_with(5)

    @mock.patch('os.getpid', return_value=1234)
    @mock.patch('os.fork', return_value=0)
    @mock.patch('os._exit')
    @mock.patch.object(util, 'LOG')
    @mock.patch.object(util.Launcher, '_install_handler')
    def test_start_exception(self, mock_install_handler, mock_LOG, mock_exit,
                             mock_fork, mock_getpid):
        starter = mock.Mock(side_effect=TestException)
        launcher = util.Launcher(starter)

        result = launcher.start()

        self.assertEqual(result, None)
        mock_fork.assert_called_once_with()
        mock_install_handler.assert_called_once_with(launcher._handle_signal)
        mock_getpid.assert_called_once_with()
        starter.assert_called_once_with()
        mock_LOG.assert_has_calls([
            mock.call.exception("1234: Unhandled exception"),
        ])
        self.assertEqual(len(mock_LOG.method_calls), 1)
        mock_exit.assert_called_once_with(2)
<|endoftext|>


<commit_before># Shamelessly ripped and modified from
# https://github.com/SublimeText/TrailingSpaces

import sublime
import sublime_plugin

DEFAULT_MAX_FILE_SIZE = 1048576
DEFAULT_COLOR_SCOPE_NAME = "invalid"
DEFAULT_COLOR_SCOPE_NAME_COOL = "constant.character.entity.html"
DEFAULT_IS_ENABLED = True
DEFAULT_REGEX = '(\t+ +(?![*]))|( +\t+)|([\t ]+$)'
DEFAULT_REGEX_COOL = '[\u2026\u2018\u2019\u201c\u201d\u2013\u2014]'
DEFAULT_DELAY = 3000
DEFAULT_SYNTAX_IGNORE = []

class Preferences:
    def load(self, settings):
        self.enabled = bool(settings.get('highlighter_enabled', DEFAULT_IS_ENABLED))
        self.regex = settings.get('highlighter_regex', DEFAULT_REGEX)
        self.regex_cool = settings.get('highlighter_regex_cool', DEFAULT_REGEX_COOL)
        self.max_size = settings.get('highlighter_max_file_size', DEFAULT_MAX_FILE_SIZE)
        self.color_scope_name = settings.get('highlighter_scope_name', DEFAULT_COLOR_SCOPE_NAME)
        self.color_scope_name_cool = settings.get('highlighter_scope_name_cool', DEFAULT_COLOR_SCOPE_NAME_COOL)
        self.delay = settings.get('highlighter_delay', DEFAULT_DELAY)
        self.syntax_ignore = settings.get('highlighter_syntax_ignore', DEFAULT_SYNTAX_IGNORE)

Pref = Preferences()

def plugin_loaded():
    settings = sublime.load_settings('highlighter.sublime-settings')
    Pref.load(settings)
    settings.add_on_change('reload', lambda: Pref.load(settings))

# Determine if the view is a find results view.
def is_find_results(view):
    import sublime_api

    return view.settings().get('syntax') and \
        "Find Results" in view.settings().get('syntax')

# Returns True if the view should be ignored, False otherwise.
def ignore_view(view):
    view_syntax = view.settings().get('syntax')

    if not view_syntax:
        return False

    for syntax_ignore in Pref.syntax_ignore:
        if syntax_ignore in view_syntax:
            return True

    return False

# Return an array of regions matching regex.
def find_regexes(view):
    return view.find_all(Pref.regex)

def find_regexes_cool(view):
    return view.find_all(Pref.regex_cool)

# Highlight regex matches.
def highlighter(view):
    if view.size() <= Pref.max_size and not ignore_view(view) and not is_find_results(view):
        regions = find_regexes(view)
        regions_cool = find_regexes_cool(view)
        view.add_regions('HighlighterListener', regions,
                         Pref.color_scope_name, "", sublime.DRAW_EMPTY)
        view.add_regions('HighlighterListenerCool', regions_cool,
                         Pref.color_scope_name_cool, "dot",
                         sublime.DRAW_STIPPLED_UNDERLINE | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE)

# Highlight matching regions.
class HighlighterListener(sublime_plugin.EventListener):
    def __init__(self):
        self.pending = 0

    def on_modified(self, view):
        if Pref.enabled:
            self.pending = self.pending + 1
            sublime.set_timeout(lambda: self.parse(view), Pref.delay)

    def parse(self, view):
        self.pending = self.pending - 1
        if self.pending > 0:
            return
        highlighter(view)

    def on_activated(self, view):
        if Pref.enabled:
            highlighter(view)

    def on_load(self, view):
        if Pref.enabled:
            highlighter(view)

# ST2 backwards compatibility
if int(sublime.version()) < 3000:
    plugin_loaded()
<commit_msg>Syntax ignore configuration added<commit_after># Shamelessly ripped and modified from
# https://github.com/SublimeText/TrailingSpaces

import sublime
import sublime_plugin

DEFAULT_MAX_FILE_SIZE = 1048576
DEFAULT_COLOR_SCOPE_NAME = "invalid"
DEFAULT_COLOR_SCOPE_NAME_COOL = "constant.character.entity.html"
DEFAULT_IS_ENABLED = True
DEFAULT_REGEX = '(\t+ +(?![*]))|( +\t+)|([\t ]+$)'
DEFAULT_REGEX_COOL = '[\u2026\u2018\u2019\u201c\u201d\u2013\u2014]'
DEFAULT_DELAY = 3000
DEFAULT_SYNTAX_IGNORE = []

class Preferences:
    def load(self, settings):
        self.enabled = bool(settings.get('highlighter_enabled', DEFAULT_IS_ENABLED))
        self.regex = settings.get('highlighter_regex', DEFAULT_REGEX)
        self.regex_cool = settings.get('highlighter_regex_cool', DEFAULT_REGEX_COOL)
        self.max_size = settings.get('highlighter_max_file_size', DEFAULT_MAX_FILE_SIZE)
        self.color_scope_name = settings.get('highlighter_scope_name', DEFAULT_COLOR_SCOPE_NAME)
        self.color_scope_name_cool = settings.get('highlighter_scope_name_cool', DEFAULT_COLOR_SCOPE_NAME_COOL)
        self.delay = settings.get('highlighter_delay', DEFAULT_DELAY)
        self.syntax_ignore = settings.get('highlighter_syntax_ignore', DEFAULT_SYNTAX_IGNORE)

Pref = Preferences()

def plugin_loaded():
    settings = sublime.load_settings('highlighter.sublime-settings')
    Pref.load(settings)
    settings.add_on_change('reload', lambda: Pref.load(settings))

# Determine if the view is a find results view.
def is_find_results(view):
    return view.settings().get('syntax') and \
        "Find Results" in view.settings().get('syntax')

# Returns True if the view should be ignored, False otherwise.
def ignore_view(view):
    view_syntax = view.settings().get('syntax')

    if not view_syntax:
        return False

    for syntax_ignore in Pref.syntax_ignore:
        if syntax_ignore in view_syntax:
            return True

    return False

# Return an array of regions matching regex.
def find_regexes(view):
    return view.find_all(Pref.regex)

def find_regexes_cool(view):
    return view.find_all(Pref.regex_cool)

# Highlight regex matches.
def highlighter(view):
    if view.size() <= Pref.max_size and not ignore_view(view) and not is_find_results(view):
        regions = find_regexes(view)
        regions_cool = find_regexes_cool(view)
        view.add_regions('HighlighterListener', regions,
                         Pref.color_scope_name, "", sublime.DRAW_EMPTY)
        view.add_regions('HighlighterListenerCool', regions_cool,
                         Pref.color_scope_name_cool, "dot",
                         sublime.DRAW_STIPPLED_UNDERLINE | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE)

# Highlight matching regions.
class HighlighterListener(sublime_plugin.EventListener):
    def __init__(self):
        self.pending = 0

    def on_modified(self, view):
        if Pref.enabled:
            self.pending = self.pending + 1
            sublime.set_timeout(lambda: self.parse(view), Pref.delay)

    def parse(self, view):
        self.pending = self.pending - 1
        if self.pending > 0:
            return
        highlighter(view)

    def on_activated(self, view):
        if Pref.enabled:
            highlighter(view)

    def on_load(self, view):
        if Pref.enabled:
            highlighter(view)

# ST2 backwards compatibility
if int(sublime.version()) < 3000:
    plugin_loaded()
<|endoftext|>


<commit_before>import signal
from subprocess import Popen, PIPE
from collections import defaultdict

import logbook
from logbook.queues import ZeroMQSubscriber

from onitu.utils import get_logs_uri

from .loop import CounterLoop
from .logs import logs

FORMAT_STRING = (
    u'[{record.time:%H:%M:%S}] '
    u'{record.level_name}: {record.channel}: {record.message}'
)

class Event(object):
    def __init__(self, triggers, action, unique):
        self.triggers = triggers
        self.state = [False] * len(triggers)
        self.action = action
        self.unique = unique

class Launcher(object):
    def __init__(self,
                 setup,
                 background=True,
                 debug=True):
        self.setup = setup
        self.bg = background
        self.debug = debug

        self.process = None
        self.dispatcher = None
        self.event_triggers = defaultdict(set)

    def set_event(self, triggers, action, unique):
        event = Event(list(triggers), action, unique)

        for trigger in event.triggers:
            self.event_triggers[trigger].add(event)
        return event

    def unset_event(self, event):
        for trigger in event.triggers:
            self.event_triggers[trigger].discard(event)

    def unset_all_events(self):
        self.event_triggers = defaultdict(set)

    def _kill(self, sig, wait):
        if self.process is None:
            return

        try:
            self.process.send_signal(sig)
        except OSError:  # Process already exited
            self.process = None

        if wait:
            self.wait()

    def quit(self, wait=True):
        self._kill(signal.SIGINT, wait)

    def kill(self, wait=True):
        self._kill(signal.SIGTERM, wait)

    def close(self):
        try:
            self.kill(wait=True)
        finally:
            if self.dispatcher:
                self.dispatcher.stop()
                self.dispatcher.subscriber.close()

    def wait(self):
        if self.process is not None:
            self.process.wait()

    def process_record(self, record):
        trigger = (record.channel, record.message)
        events = self.event_triggers.get(trigger)

        if not events:
            return

        unset_events = set()
        for event in events:
            event.state[event.triggers.index(trigger)] = True
            if all(event.state):
                if event.unique:
                    unset_events.add(event)
                event.action()
        for event in unset_events:
            self.unset_event(event)

    def start_dispatcher(self):
        logs_uri = get_logs_uri(self.setup.name)

        level = logbook.DEBUG if self.debug else logbook.INFO
        handlers = logbook.NestedSetup([
            logbook.NullHandler(),
            logbook.StderrHandler(
                level=level, format_string=FORMAT_STRING
            ),
            logbook.Processor(self.process_record),
        ])
        subscriber = ZeroMQSubscriber(logs_uri, multi=True)
        self.dispatcher = subscriber.dispatch_in_background(setup=handlers)

    def __call__(self, wait=True, api=False, save_setup=True,
                 stdout=False, stderr=False):
        self.start_dispatcher()

        if save_setup:
            self.setup.save()

        if wait:
            loop = CounterLoop(len(self.setup.entries) + api + 1)
            self.on_referee_started(loop.check)
            if api:
                self.on_api_started(loop.check)
            for entry in self.setup.entries.values():
                self.on_driver_started(loop.check, driver=entry.name)

        self.process = Popen(
            ('onitu', '--setup', self.setup.filename, '--no-dispatcher'),
            stdout=PIPE if stdout else None,
            stderr=PIPE if stderr else None,
        )

        if wait:
            try:
                loop.run(timeout=5)
            except:
                self.close()
                raise

        return self.process

    def __del__(self):
        self.close()

    def _on_event(self, name):
        log_triggers = logs[name]

        def caller(action, unique=True, **kwargs):
            triggers = set(
                (
                    channel.format(**kwargs),
                    message.format(**kwargs)
                )
                for (channel, message) in log_triggers
            )
            return self.set_event(triggers, action, unique)

        return caller

    def __getattr__(self, name):
        if name.startswith('on_'):
            return self._on_event(name[3:])
        return self.__getattribute__(name)

    @property
    def entries(self):
        return self.setup.entries

    def get_entries(self, *names):
        return [self.entries[name] for name in names]
<commit_msg>Tests: Read unicode log lines correctly<commit_after>import signal
from subprocess import Popen, PIPE
from collections import defaultdict

import logbook
from logbook.queues import ZeroMQSubscriber

from onitu.utils import get_logs_uri, u

from .loop import CounterLoop
from .logs import logs

FORMAT_STRING = (
    u'[{record.time:%H:%M:%S}] '
    u'{record.level_name}: {record.channel}: {record.message}'
)

class Event(object):
    def __init__(self, triggers, action, unique):
        self.triggers = triggers
        self.state = [False] * len(triggers)
        self.action = action
        self.unique = unique

class Launcher(object):
    def __init__(self,
                 setup,
                 background=True,
                 debug=True):
        self.setup = setup
        self.bg = background
        self.debug = debug

        self.process = None
        self.dispatcher = None
        self.event_triggers = defaultdict(set)

    def set_event(self, triggers, action, unique):
        event = Event(list(triggers), action, unique)

        for trigger in event.triggers:
            self.event_triggers[trigger].add(event)
        return event

    def unset_event(self, event):
        for trigger in event.triggers:
            self.event_triggers[trigger].discard(event)

    def unset_all_events(self):
        self.event_triggers = defaultdict(set)

    def _kill(self, sig, wait):
        if self.process is None:
            return

        try:
            self.process.send_signal(sig)
        except OSError:  # Process already exited
            self.process = None

        if wait:
            self.wait()

    def quit(self, wait=True):
        self._kill(signal.SIGINT, wait)

    def kill(self, wait=True):
        self._kill(signal.SIGTERM, wait)

    def close(self):
        try:
            self.kill(wait=True)
        finally:
            if self.dispatcher:
                self.dispatcher.stop()
                self.dispatcher.subscriber.close()

    def wait(self):
        if self.process is not None:
            self.process.wait()

    def process_record(self, record):
        trigger = (record.channel, record.message)
        events = self.event_triggers.get(trigger)

        if not events:
            return

        unset_events = set()
        for event in events:
            event.state[event.triggers.index(trigger)] = True
            if all(event.state):
                if event.unique:
                    unset_events.add(event)
                event.action()
        for event in unset_events:
            self.unset_event(event)

    def start_dispatcher(self):
        logs_uri = get_logs_uri(self.setup.name)

        level = logbook.DEBUG if self.debug else logbook.INFO
        handlers = logbook.NestedSetup([
            logbook.NullHandler(),
            logbook.StderrHandler(
                level=level, format_string=FORMAT_STRING
            ),
            logbook.Processor(self.process_record),
        ])
        subscriber = ZeroMQSubscriber(logs_uri, multi=True)
        self.dispatcher = subscriber.dispatch_in_background(setup=handlers)

    def __call__(self, wait=True, api=False, save_setup=True,
                 stdout=False, stderr=False):
        self.start_dispatcher()

        if save_setup:
            self.setup.save()

        if wait:
            loop = CounterLoop(len(self.setup.entries) + api + 1)
            self.on_referee_started(loop.check)
            if api:
                self.on_api_started(loop.check)
            for entry in self.setup.entries.values():
                self.on_driver_started(loop.check, driver=entry.name)

        self.process = Popen(
            ('onitu', '--setup', self.setup.filename, '--no-dispatcher'),
            stdout=PIPE if stdout else None,
            stderr=PIPE if stderr else None,
        )

        if wait:
            try:
                loop.run(timeout=5)
            except:
                self.close()
                raise

        return self.process

    def __del__(self):
        self.close()

    def _on_event(self, name):
        log_triggers = logs[name]

        def caller(action, unique=True, **kwargs):
            triggers = set(
                (
                    u(channel).format(**kwargs),
                    u(message).format(**kwargs)
                )
                for (channel, message) in log_triggers
            )
            return self.set_event(triggers, action, unique)

        return caller

    def __getattr__(self, name):
        if name.startswith('on_'):
            return self._on_event(name[3:])
        return self.__getattribute__(name)

    @property
    def entries(self):
        return self.setup.entries

    def get_entries(self, *names):
        return [self.entries[name] for name in names]
<|endoftext|>


<commit_before># Copyright 2016 hm authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

__version__ = '0.6.9'
<commit_msg>bump to 0.6.10<commit_after># Copyright 2016 hm authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

__version__ = '0.6.10'
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    TextPress Management
    ~~~~~~~~~~~~~~~~~~~~

    This script starts a server or a shell for a textpress
    instance. Useful for plugin development and debugging.

    :copyright: 2007-2008 by Armin Ronacher, Pedro Algarvio.
    :license: GNU GPL.
"""
import os
import sys
from werkzeug import script
from werkzeug.contrib import profiler

INSTANCE_FOLDER = os.environ.get('TEXTPRESS_INSTANCE')
if not INSTANCE_FOLDER:
    INSTANCE_FOLDER = os.path.join(os.path.dirname(__file__), 'instance')

def make_app():
    from textpress import make_app
    return make_app(INSTANCE_FOLDER)

def make_shell():
    from textpress import make_textpress
    app = make_textpress(INSTANCE_FOLDER, True)
    from textpress import models
    from textpress.database import db
    del make_textpress
    return locals()

def action_deployplugin(plugin_path='', output_path='./'):
    """Deploys a plugin"""

    USAGE = """\
usage: %(script)s deployplugin [options]

examples:
    %(script)s deployplugin /path/to/plugin/foo
    %(script)s deployplugin /path/to/plugin/foo /path/to/output/dir
    %(script)s deployplugin --plugin-path=/path/to/plugin/foo
    %(script)s deployplugin --plugin-path=/path/to/plugin/foo --output-dir=/path/to/output/dir
""" % {'script': sys.argv[0]}

    from textpress import make_textpress
    app = make_textpress(INSTANCE_FOLDER, True)

    if not plugin_path:
        print "Please pass the plugin directory path"
        print USAGE
        sys.exit(1)

    plugin_name = [p for p in plugin_path.split(os.sep) if p][-1]
    try:
        plugin = app.plugins[plugin_name]
    except KeyError:
        print "Plugin '%s' not known" % plugin_name
        print USAGE
        sys.exit(1)

    if output_path != './':
        if not os.path.exists(output_path):
            print "Output directory '%s' does not exist" % output_path
            print USAGE
            sys.exit(1)
        elif not os.access(output_path, os.R_OK|os.W_OK|os.X_OK):
            print "cannot write to '%s'" % output_path
            print USAGE
            sys.exit(1)
    plugin = app.plugins[plugin_name]
    output_plugin_name = '%s-%s.plugin' % (
        ''.join(plugin.display_name.split()),
        plugin.version
    )
    plugin.dump('%s%s' % (
        output_path, output_plugin_name)
    )
    print "Created '%s' in '%s'" % (output_plugin_name, output_path)

action_runserver = script.make_runserver(make_app, use_reloader=True,
                                         port=4000, use_debugger=True)
action_profile = profiler.make_action(make_app, port=4000)
action_shell = script.make_shell(make_shell)

if __name__ == '__main__':
    script.run()
<commit_msg>use os.path.join in textpress-management<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
    TextPress Management
    ~~~~~~~~~~~~~~~~~~~~

    This script starts a server or a shell for a textpress
    instance. Useful for plugin development and debugging.

    :copyright: 2007-2008 by Armin Ronacher, Pedro Algarvio.
    :license: GNU GPL.
"""
import os
import sys
from werkzeug import script
from werkzeug.contrib import profiler

INSTANCE_FOLDER = os.environ.get('TEXTPRESS_INSTANCE')
if not INSTANCE_FOLDER:
    INSTANCE_FOLDER = os.path.join(os.path.dirname(__file__), 'instance')

def make_app():
    from textpress import make_app
    return make_app(INSTANCE_FOLDER)

def make_shell():
    from textpress import make_textpress
    app = make_textpress(INSTANCE_FOLDER, True)
    from textpress import models
    from textpress.database import db
    del make_textpress
    return locals()

def action_deployplugin(plugin_path='', output_path='./'):
    """Deploys a plugin"""

    USAGE = """\
usage: %(script)s deployplugin [options]

examples:
    %(script)s deployplugin /path/to/plugin/foo
    %(script)s deployplugin /path/to/plugin/foo /path/to/output/dir
    %(script)s deployplugin --plugin-path=/path/to/plugin/foo
    %(script)s deployplugin --plugin-path=/path/to/plugin/foo --output-dir=/path/to/output/dir
""" % {'script': sys.argv[0]}

    from textpress import make_textpress
    app = make_textpress(INSTANCE_FOLDER, True)

    if not plugin_path:
        print "Please pass the plugin directory path"
        print USAGE
        sys.exit(1)

    plugin_name = [p for p in plugin_path.split(os.sep) if p][-1]
    try:
        plugin = app.plugins[plugin_name]
    except KeyError:
        print "Plugin '%s' not known" % plugin_name
        print USAGE
        sys.exit(1)

    if output_path != './':
        if not os.path.exists(output_path):
            print "Output directory '%s' does not exist" % output_path
            print USAGE
            sys.exit(1)
        elif not os.access(output_path, os.R_OK|os.W_OK|os.X_OK):
            print "cannot write to '%s'" % output_path
            print USAGE
            sys.exit(1)
    plugin = app.plugins[plugin_name]
    output_plugin_name = '%s-%s.plugin' % (
        ''.join(plugin.display_name.split()),
        plugin.version
    )
    plugin.dump(os.path.join(output_path, output_plugin_name))
    print "Created '%s' in '%s'" % (output_plugin_name, output_path)

action_runserver = script.make_runserver(make_app, use_reloader=True,
                                         port=4000, use_debugger=True)
action_profile = profiler.make_action(make_app, port=4000)
action_shell = script.make_shell(make_shell)

if __name__ == '__main__':
    script.run()
<|endoftext|>


<commit_before>#######################################################################
# This file is part of PyBlosxom.
#
# Copyright (c) 2003, 2004, 2005, 2006 Wari Wahab
#
# PyBlosxom is distributed under the MIT license.  See the file LICENSE
# for distribution details.
#
# $Id$
#######################################################################
"""
This is the default blosxom renderer.  It tries to match the behavior
of the blosxom renderer.
"""

__revision__ = "$Revision$"

import os
import sys
import codecs
import time

from Pyblosxom import tools
from Pyblosxom.renderers.base import RendererBase

class NoSuchFlavourException(Exception):
    """
    This exception gets thrown when the flavour requested is not
    available in this blog.
    """
    def __init__(self, msg):
        Exception.__init__(self)
        self._msg = msg

def get_included_flavour(taste):
    """
    PyBlosxom comes with flavours in taste.flav directories in the flavours
    subdirectory of the Pyblosxom package.  This method pulls the template
    files for the associated taste (assuming it exists) or None if it
    doesn't.

    @param taste: The name of the taste.  e.g. "html", "rss", ...
    @type  taste: string

    @returns: A dict of template type to template file or None
    @rtype: dict or None
    """
    path = __file__[:__file__.rfind(os.sep)]
    path = path[:path.rfind(os.sep)+1] + "flavours" + os.sep

    path = path + taste + ".flav"

    if os.path.isdir(path):
        template_files = os.listdir(path)
        template_d = {}
        for mem in template_files:
            name, ext = os.path.splitext(mem)
            if ext not in ["." + taste, ""]:
                continue
            template_d[name] = os.path.join(path, mem)
        return template_d

    return None

def get_flavour_from_dir(path, taste):
    """
    Tries to get the template files for the flavour of a certain
    taste (html, rss, atom10, ...) in a directory.  The files could
    be in the directory or in a taste.flav subdirectory.

    @param path: the path of the directory to look for the flavour
                 templates in
    @type  path: string

    @param taste: the flavour files to look for (e.g. html, rss, atom10, ...)
    @type  taste: string

    @returns: the map of template name to template file path
    @rtype: map
    """
    template_d = {}

    # if we have a taste.flav directory, we check there
    if os.path.isdir(path + os.sep + taste + ".flav"):
        newpath = path + os.sep + taste + ".flav"
        template_files = os.listdir(newpath)
        for mem in template_files:
            name, ext = os.path.splitext(mem)
            if ext not in ["." + taste, ""]:
                continue
            template_d[name] = os.path.join(path + os.sep + taste + ".flav", mem)
        return template_d

    # now we check the directory itself for flavour templates
    template_files = os.listdir(path)
    for mem in template_files:
        if not mem.endswith("." + taste):
            continue
        template_d[os.path.splitext(mem)[0]] = path + os.sep + mem

    if template_d:
        return template_d

    return None

class BlosxomRenderer(RendererBase):
    """
    This is the default blosxom renderer.  It tries to match the behavior
    of the blosxom renderer.
    """
    def __init__(self, request, stdoutput = sys.stdout):
        RendererBase.__init__(self, request, stdoutput)
        config = request.getConfiguration()
        sw = codecs.lookup(config.get('blog_encoding', 'iso-8859-1'))[3]
        self._out = sw(self._out)
        self._request = request
        self._encoding = config.get("blog_encoding", "iso-8859-1")
        self.flavour = None

        self._parsevars = dict(tools.STANDARD_FILTERS)
        self._parsevars.update(config)
        # NOTE: we update self._parsevars with the data dict in the render
        # method.  doing it here is too early.

    def _getParseVars(self):
        return dict(self._parsevars)

    def _getflavour(self, taste='html'):
        """
        This retrieves all the template files for a given flavour taste.
        This will first pull the templates for the default flavour
        of this taste if there are any.  Then it looks at EITHER
        the configured datadir OR the flavourdir (if configured).  It'll
        go through directories overriding the template files it has
        already picked up descending the category path of the PyBlosxom
        request.

        For example, if the user requested the "html" flavour and is
        looking at an entry in the category "dev/pyblosxom", then
        _getflavour will:

          1. pick up the flavour files in the default html flavour
          2. start in EITHER datadir OR flavourdir (if configured)
          3. override the default html flavour files with html flavour
             files in this directory or in html.flav/ subdirectory
          4. override the html flavour files it's picked up so far
             with html files in dev/ or dev/html.flav/
          5. override the html flavour files it's picked up so far
             with html files in dev/pyblosxom/ or
             dev/pyblosxom/html.flav/

        If it doesn't find any flavour files at all, then it returns
        None which indicates the flavour doesn't exist in this blog.

        @param taste: the taste to retrieve flavour files for.
        @type  taste: string

        @returns: mapping of template name to template file data
        @rtype: map
        """
        data = self._request.getData()
        config = self._request.getConfiguration()
        datadir = config["datadir"]

        # if they have flavourdir set, then we look there.  otherwise
        # we look in the datadir.
        flavourdir = config.get("flavourdir", datadir)

        # first we grab the flavour files for the included flavour (if
        # we have one).
        template_d = get_included_flavour(taste)
        if not template_d:
            template_d = {}

        pathinfo = list(data["path_info"])

        # check the root of flavourdir for templates
        new_files = get_flavour_from_dir(flavourdir, taste)
        if new_files:
            template_d.update(new_files)

        # go through all the directories from the flavourdir all
        # the way up to the root_datadir.  this way template files
        # can override template files in parent directories.
        while len(pathinfo) > 0:
            flavourdir = os.path.join(flavourdir, pathinfo.pop(0))
            if os.path.isfile(flavourdir):
                break

            if not os.path.isdir(flavourdir):
                break

            new_files = get_flavour_from_dir(flavourdir, taste)
            if new_files:
                template_d.update(new_files)

        # if we still haven't found our flavour files, we raise an exception
        if not template_d:
            raise NoSuchFlavourException("Flavour '%s' does not exist." % taste)

        for k in template_d.keys():
            flav_template = unicode(open(template_d[k]).read(),
                    config.get('blog_encoding', 'iso-8859-1'))
            template_d[k] = flav_template

        return template_d

    def renderContent(self, content):
        """
        Processes the content for the story portion of a page.

        @params: the content to be rendered
        @type: callable/dict/list

        @returns: the content string
        @rtype: string
        """
        data = self._request.getData()

        outputbuffer = []

        if callable(content):
            # if the content is a callable function, then we just spit out
            # whatever it returns as a string
            outputbuffer.append(content())

        elif isinstance(content, dict):
            # if the content is a dict, then we parse it as if it were an
            # entry--except it's distinctly not an EntryBase derivative
            var_dict = self._getParseVars()
            var_dict.update(content)

            output = tools.parse(self._request, self._encoding, var_dict,
                                 self.flavour['story'])
            outputbuffer.append(output)

        elif isinstance(content, list):

            if len(content) > 0:
                current_date = content[0]["date"]

                if current_date and "date_head" in self.flavour:
                    vars = self._getParseVars()
                    vars.update( { "date": current_date } )
                    outputbuffer.append(self.renderTemplate(vars, "date_head"))

                for entry in content:
                    if entry["date"] and entry["date"] != current_date:
                        if "date_foot" in self.flavour:
                            vars = self._getParseVars()
                            vars.update( { "date": current_date } )
                            outputbuffer.append(self.renderTemplate(vars, "date_foot"))

                        if "date_head" in self.flavour:
                            current_date = entry["date"]
                            vars = self._getParseVars()
                            vars.update( { "date": current_date } )
                            outputbuffer.append(self.renderTemplate(vars, "date_head"))

                    if data['content-type'] == 'text/plain':
                        s = tools.Stripper()
                        s.feed(entry.getData())
                        s.close()
                        p = ['  ' + line for line in s.gettext().split('\n')]
                        entry.setData('\n'.join(p))

                    vars = self._getParseVars()
                    vars.update(entry)

                    outputbuffer.append(self.renderTemplate(vars, "story", override=1))

                    args = { "entry": vars, "template": u"" }
                    args = self._run_callback("story_end", args)
                    outputbuffer.append( args["template"] )

                if current_date and "date_foot" in self.flavour:
                    vars = self._getParseVars()
                    vars.update( { "date": current_date } )
                    outputbuffer.append(self.renderTemplate(vars, "date_foot"))

        return outputbuffer

    def render(self, header=1):
        """
        Figures out flavours and such and then renders the content according
        to which flavour we're using.

        @param header: whether (1) or not (0) to render the HTTP headers
        @type  header: boolean
        """
        # if we've already rendered, then we don't want to do so again
        if self.rendered == 1:
            return

        data = self._request.getData()
        config = self._request.getConfiguration()

        # update it with data here because at this point, the data dict should
        # have all the data needed to render.
        self._parsevars.update(data)

        try:
            self.flavour = self._getflavour(data.get("flavour", "html"))

        except NoSuchFlavourException, nsfe:
            error_msg = nsfe._msg
            try:
                self.flavour = self._getflavour("error")
            except NoSuchFlavourException, nsfe2:
                self.flavour = get_included_flavour("error")
                error_msg = error_msg + "And your error flavour doesn't exist."

            self._content = { "title": "Flavour error",
                              "body": error_msg }

        data['content-type'] = self.flavour['content_type'].strip()
        if header:
            if self._needs_content_type and data['content-type'] != "":
                self.addHeader('Content-type', '%(content-type)s' % data)

            self.showHeaders()

        if self._content:
            if "head" in self.flavour:
                self.write(self.renderTemplate(self._getParseVars(), "head"))
            if "story" in self.flavour:
                self.write(u"".join(self.renderContent(self._content)))
            if "foot" in self.flavour:
                self.write(self.renderTemplate(self._getParseVars(), "foot"))

        self.rendered = 1

    def renderTemplate(self, entry, template_name, override=0):
        """
        Find the flavour template for template_name, run any blosxom callbacks,
        substitute entry into it and render the template.

        If the entry has a "template_name" property and override is 1
        (this happens in the story template), then we'll use that
        template instead.

        @param entry: the entry/variable-dict to use for expanding variables
        @type entry: dict-like

        @param template_name: template name (gets looked up in self.flavour)
        @type template_name: string

        @param override: whether (1) or not (0) this template can
            be overriden with the "template_name" value in the entry
        @type  override: boolean
        """
        template = ""
        if override == 1:
            # here we do a quick override...  if the entry has a template
            # field we use that instead of the template_name argument
            # passed in.
            actual_template_name = entry.get("template_name", template_name)
            template = self.flavour.get(actual_template_name, '')

        if not template:
            template = self.flavour.get(template_name, '')

        # we run this through the regular callbacks
        args = self._run_callback(template_name,
                                  { "entry": entry, "template": template })

        template = unicode(args["template"])
        entry = args["entry"]

        template = unicode(template)
        finaltext = tools.parse(self._request, self._encoding, entry, template)
        return finaltext.replace(r'\$', '$')

    def _run_callback(self, chain, input):
        """
        Makes calling blosxom callbacks a bit easier since they all have the
        same mechanics.  This function merely calls run_callback with
        the arguments given and a mappingfunc.

        The mappingfunc copies the "template" value from the output to the
        input for the next function.

        Refer to run_callback for more details.
        """
        input.update( { "renderer": self } )
        input.update( { "request": self._request } )

        return tools.run_callback(chain, input,
                            mappingfunc=lambda x,y: x,
                            defaultfunc=lambda x:x)

    def getContent(self):
        """
        Return the content field

        This is exposed for blosxom callbacks.

        @returns: content
        """
        return self._content

    def outputTemplate(self, output, entry, template_name):
        """
        Deprecated.  Here for backwards compatibility.
        """
        output.append(self.renderTemplate(entry, template_name))

class Renderer(BlosxomRenderer):
    """
    This is a null renderer.
    """
    pass

# vim: shiftwidth=4 tabstop=4 expandtab
<commit_msg>Adjusted the parsevars handling in the blosxom renderer so that config variables set in cb_start are available in all template rendering.<commit_after>#######################################################################
# This file is part of PyBlosxom.
#
# Copyright (c) 2003, 2004, 2005, 2006 Wari Wahab
#
# PyBlosxom is distributed under the MIT license.  See the file LICENSE
# for distribution details.
#
# $Id$
#######################################################################
"""
This is the default blosxom renderer.  It tries to match the behavior
of the blosxom renderer.
"""

__revision__ = "$Revision$"

import os
import sys
import codecs
import time

from Pyblosxom import tools
from Pyblosxom.renderers.base import RendererBase

class NoSuchFlavourException(Exception):
    """
    This exception gets thrown when the flavour requested is not
    available in this blog.
    """
    def __init__(self, msg):
        Exception.__init__(self)
        self._msg = msg

def get_included_flavour(taste):
    """
    PyBlosxom comes with flavours in taste.flav directories in the flavours
    subdirectory of the Pyblosxom package.  This method pulls the template
    files for the associated taste (assuming it exists) or None if it
    doesn't.

    @param taste: The name of the taste.  e.g. "html", "rss", ...
    @type  taste: string

    @returns: A dict of template type to template file or None
    @rtype: dict or None
    """
    path = __file__[:__file__.rfind(os.sep)]
    path = path[:path.rfind(os.sep)+1] + "flavours" + os.sep

    path = path + taste + ".flav"

    if os.path.isdir(path):
        template_files = os.listdir(path)
        template_d = {}
        for mem in template_files:
            name, ext = os.path.splitext(mem)
            if ext not in ["." + taste, ""]:
                continue
            template_d[name] = os.path.join(path, mem)
        return template_d

    return None

def get_flavour_from_dir(path, taste):
    """
    Tries to get the template files for the flavour of a certain
    taste (html, rss, atom10, ...) in a directory.  The files could
    be in the directory or in a taste.flav subdirectory.

    @param path: the path of the directory to look for the flavour
                 templates in
    @type  path: string

    @param taste: the flavour files to look for (e.g. html, rss, atom10, ...)
    @type  taste: string

    @returns: the map of template name to template file path
    @rtype: map
    """
    template_d = {}

    # if we have a taste.flav directory, we check there
    if os.path.isdir(path + os.sep + taste + ".flav"):
        newpath = path + os.sep + taste + ".flav"
        template_files = os.listdir(newpath)
        for mem in template_files:
            name, ext = os.path.splitext(mem)
            if ext not in ["." + taste, ""]:
                continue
            template_d[name] = os.path.join(path + os.sep + taste + ".flav", mem)
        return template_d

    # now we check the directory itself for flavour templates
    template_files = os.listdir(path)
    for mem in template_files:
        if not mem.endswith("." + taste):
            continue
        template_d[os.path.splitext(mem)[0]] = path + os.sep + mem

    if template_d:
        return template_d

    return None

class BlosxomRenderer(RendererBase):
    """
    This is the default blosxom renderer.  It tries to match the behavior
    of the blosxom renderer.
    """
    def __init__(self, request, stdoutput = sys.stdout):
        RendererBase.__init__(self, request, stdoutput)
        config = request.getConfiguration()
        sw = codecs.lookup(config.get('blog_encoding', 'iso-8859-1'))[3]
        self._out = sw(self._out)
        self._request = request
        self._encoding = config.get("blog_encoding", "iso-8859-1")
        self.flavour = None

        self._parsevars = dict(tools.STANDARD_FILTERS)
        # NOTE: we update self._parsevars with the data dict in the render
        # method.  doing it here is too early.

    def getParseVars(self):
        parsevars = dict(self._parsevars)
        parsevars.update(self._request.config)
        parsevars.update(self._request.data)
        return parsevars

    def _getflavour(self, taste='html'):
        """
        This retrieves all the template files for a given flavour taste.
        This will first pull the templates for the default flavour
        of this taste if there are any.  Then it looks at EITHER
        the configured datadir OR the flavourdir (if configured).  It'll
        go through directories overriding the template files it has
        already picked up descending the category path of the PyBlosxom
        request.

        For example, if the user requested the "html" flavour and is
        looking at an entry in the category "dev/pyblosxom", then
        _getflavour will:

          1. pick up the flavour files in the default html flavour
          2. start in EITHER datadir OR flavourdir (if configured)
          3. override the default html flavour files with html flavour
             files in this directory or in html.flav/ subdirectory
          4. override the html flavour files it's picked up so far
             with html files in dev/ or dev/html.flav/
          5. override the html flavour files it's picked up so far
             with html files in dev/pyblosxom/ or
             dev/pyblosxom/html.flav/

        If it doesn't find any flavour files at all, then it returns
        None which indicates the flavour doesn't exist in this blog.

        @param taste: the taste to retrieve flavour files for.
        @type  taste: string

        @returns: mapping of template name to template file data
        @rtype: map
        """
        data = self._request.getData()
        config = self._request.getConfiguration()
        datadir = config["datadir"]

        # if they have flavourdir set, then we look there.  otherwise
        # we look in the datadir.
        flavourdir = config.get("flavourdir", datadir)

        # first we grab the flavour files for the included flavour (if
        # we have one).
        template_d = get_included_flavour(taste)
        if not template_d:
            template_d = {}

        pathinfo = list(data["path_info"])

        # check the root of flavourdir for templates
        new_files = get_flavour_from_dir(flavourdir, taste)
        if new_files:
            template_d.update(new_files)

        # go through all the directories from the flavourdir all
        # the way up to the root_datadir.  this way template files
        # can override template files in parent directories.
        while len(pathinfo) > 0:
            flavourdir = os.path.join(flavourdir, pathinfo.pop(0))
            if os.path.isfile(flavourdir):
                break

            if not os.path.isdir(flavourdir):
                break

            new_files = get_flavour_from_dir(flavourdir, taste)
            if new_files:
                template_d.update(new_files)

        # if we still haven't found our flavour files, we raise an exception
        if not template_d:
            raise NoSuchFlavourException("Flavour '%s' does not exist." % taste)

        for k in template_d.keys():
            flav_template = unicode(open(template_d[k]).read(),
                    config.get('blog_encoding', 'iso-8859-1'))
            template_d[k] = flav_template

        return template_d

    def renderContent(self, content):
        """
        Processes the content for the story portion of a page.

        @params: the content to be rendered
        @type: callable/dict/list

        @returns: the content string
        @rtype: string
        """
        data = self._request.getData()

        outputbuffer = []

        if callable(content):
            # if the content is a callable function, then we just spit out
            # whatever it returns as a string
            outputbuffer.append(content())

        elif isinstance(content, dict):
            # if the content is a dict, then we parse it as if it were an
            # entry--except it's distinctly not an EntryBase derivative
            var_dict = self.getParseVars()
            var_dict.update(content)

            output = tools.parse(self._request, self._encoding, var_dict,
                                 self.flavour['story'])
            outputbuffer.append(output)

        elif isinstance(content, list):

            if len(content) > 0:
                current_date = content[0]["date"]

                if current_date and "date_head" in self.flavour:
                    vars = self.getParseVars()
                    vars.update( { "date": current_date } )
                    outputbuffer.append(self.renderTemplate(vars, "date_head"))

                for entry in content:
                    if entry["date"] and entry["date"] != current_date:
                        if "date_foot" in self.flavour:
                            vars = self.getParseVars()
                            vars.update( { "date": current_date } )
                            outputbuffer.append(self.renderTemplate(vars, "date_foot"))

                        if "date_head" in self.flavour:
                            current_date = entry["date"]
                            vars = self.getParseVars()
                            vars.update( { "date": current_date } )
                            outputbuffer.append(self.renderTemplate(vars, "date_head"))

                    if data['content-type'] == 'text/plain':
                        s = tools.Stripper()
                        s.feed(entry.getData())
                        s.close()
                        p = ['  ' + line for line in s.gettext().split('\n')]
                        entry.setData('\n'.join(p))

                    vars = self.getParseVars()
                    vars.update(entry)

                    outputbuffer.append(self.renderTemplate(vars, "story", override=1))

                    args = { "entry": vars, "template": u"" }
                    args = self._run_callback("story_end", args)
                    outputbuffer.append( args["template"] )

                if current_date and "date_foot" in self.flavour:
                    vars = self.getParseVars()
                    vars.update( { "date": current_date } )
                    outputbuffer.append(self.renderTemplate(vars, "date_foot"))

        return outputbuffer

    def render(self, header=1):
        """
        Figures out flavours and such and then renders the content according
        to which flavour we're using.

        @param header: whether (1) or not (0) to render the HTTP headers
        @type  header: boolean
        """
        # if we've already rendered, then we don't want to do so again
        if self.rendered == 1:
            return

        data = self._request.getData()
        config = self._request.getConfiguration()

        try:
            self.flavour = self._getflavour(data.get("flavour", "html"))

        except NoSuchFlavourException, nsfe:
            error_msg = nsfe._msg
            try:
                self.flavour = self._getflavour("error")
            except NoSuchFlavourException, nsfe2:
                self.flavour = get_included_flavour("error")
                error_msg = error_msg + "And your error flavour doesn't exist."

            self._content = { "title": "Flavour error",
                              "body": error_msg }

        data['content-type'] = self.flavour['content_type'].strip()
        if header:
            if self._needs_content_type and data['content-type'] != "":
                self.addHeader('Content-type', '%(content-type)s' % data)

            self.showHeaders()

        if self._content:
            if "head" in self.flavour:
                self.write(self.renderTemplate(self.getParseVars(), "head"))
            if "story" in self.flavour:
                self.write(u"".join(self.renderContent(self._content)))
            if "foot" in self.flavour:
                self.write(self.renderTemplate(self.getParseVars(), "foot"))

        self.rendered = 1

    def renderTemplate(self, entry, template_name, override=0):
        """
        Find the flavour template for template_name, run any blosxom callbacks,
        substitute entry into it and render the template.

        If the entry has a "template_name" property and override is 1
        (this happens in the story template), then we'll use that
        template instead.

        @param entry: the entry/variable-dict to use for expanding variables
        @type entry: dict-like

        @param template_name: template name (gets looked up in self.flavour)
        @type template_name: string

        @param override: whether (1) or not (0) this template can
            be overriden with the "template_name" value in the entry
        @type  override: boolean
        """
        template = ""
        if override == 1:
            # here we do a quick override...  if the entry has a template
            # field we use that instead of the template_name argument
            # passed in.
            actual_template_name = entry.get("template_name", template_name)
            template = self.flavour.get(actual_template_name, '')

        if not template:
            template = self.flavour.get(template_name, '')

        # we run this through the regular callbacks
        args = self._run_callback(template_name,
                                  { "entry": entry, "template": template })

        template = unicode(args["template"])
        entry = args["entry"]

        template = unicode(template)
        finaltext = tools.parse(self._request, self._encoding, entry, template)
        return finaltext.replace(r'\$', '$')

    def _run_callback(self, chain, input):
        """
        Makes calling blosxom callbacks a bit easier since they all have the
        same mechanics.  This function merely calls run_callback with
        the arguments given and a mappingfunc.

        The mappingfunc copies the "template" value from the output to the
        input for the next function.

        Refer to run_callback for more details.
        """
        input.update( { "renderer": self } )
        input.update( { "request": self._request } )

        return tools.run_callback(chain, input,
                            mappingfunc=lambda x,y: x,
                            defaultfunc=lambda x:x)

    def getContent(self):
        """
        Return the content field

        This is exposed for blosxom callbacks.

        @returns: content
        """
        return self._content

    def outputTemplate(self, output, entry, template_name):
        """
        Deprecated.  Here for backwards compatibility.
        """
        output.append(self.renderTemplate(entry, template_name))

class Renderer(BlosxomRenderer):
    """
    This is a null renderer.
    """
    pass

# vim: shiftwidth=4 tabstop=4 expandtab
<|endoftext|>


<commit_before>"""Public Suffix List support for Python.
"""

import os.path

class PublicSuffixList(object):
	def __init__(self, input_file=None):
		"""Reads and parses public suffix list.

		input_file is an iterable object that returns lines of a
		public suffix list file (standard Python file-like objects
		work). If input_file is None, a file named
		"publicsuffix.txt" in the same directory as this Python
		module is used.

		The file format is described at http://publicsuffix.org/list/
		"""

		if input_file is None:
			input_path = os.path.join(os.path.dirname(__file__), 'publicsuffix.txt')
			input_file = file(input_path)

		root = self._build_structure(input_file)
		self.root = self._simplify(root)

	def _find_node(self, parent, parts):
		if not parts:
			return parent

		if len(parent) == 1:
			parent.append({})

		assert len(parent) == 2
		negate, children = parent

		child = parts.pop()
		try:
			child = child.encode('ascii')
		except:
			pass

		child_node = children.get(child, None)

		if not child_node:
			children[child] = child_node = [0]

		return self._find_node(child_node, parts)

	def _add_rule(self, root, rule):
		if rule.startswith('!'):
			negate = 1
			rule = rule[1:]
		else:
			negate = 0

		parts = rule.split('.')
		self._find_node(root, parts)[0] = negate

	def _simplify(self, node):
		if len(node) == 1:
			return node[0]

		return (node[0], dict((k, self._simplify(v)) for (k, v) in node[1].iteritems()))

	def _build_structure(self, fp):
		root = [0]

		for line in fp:
			line = line.decode('utf-8').strip()
			if line.startswith('//') or not line:
				continue

			self._add_rule(root, line.split()[0].lstrip('.'))

		return root

	def _lookup_node(self, matches, depth, parent, parts):
		if parent in (0, 1):
			negate = parent
			children = None
		else:
			negate, children = parent

		matches[-depth] = matches[-depth] or negate

		if depth < len(parts) and children:
			for name in (parts[-depth], '*'):
				child = children.get(name, None)
				if child is not None:
					self._lookup_node(matches, depth+1, child, parts)

	def get_public_suffix(self, domain):
		"""get_public_suffix("www.example.com") -> "example.com"

		Calling this function with a DNS name will return the
		public suffix for that name.
		"""

		parts = domain.lower().lstrip('.').split('.')
		hits = [None] * len(parts)

		self._lookup_node(hits, 1, self.root, parts)

		for i, what in enumerate(hits):
			if what is not None:
				return '.'.join(parts[i:])
<commit_msg>Fix for exception to the wildcard rule.<commit_after>"""Public Suffix List support for Python.
"""

import os.path

class PublicSuffixList(object):
	def __init__(self, input_file=None):
		"""Reads and parses public suffix list.

		input_file is an iterable object that returns lines of a
		public suffix list file (standard Python file-like objects
		work). If input_file is None, a file named
		"publicsuffix.txt" in the same directory as this Python
		module is used.

		The file format is described at http://publicsuffix.org/list/
		"""

		if input_file is None:
			input_path = os.path.join(os.path.dirname(__file__), 'publicsuffix.txt')
			input_file = file(input_path)

		root = self._build_structure(input_file)
		self.root = self._simplify(root)

	def _find_node(self, parent, parts):
		if not parts:
			return parent

		if len(parent) == 1:
			parent.append({})

		assert len(parent) == 2
		negate, children = parent

		child = parts.pop()
		try:
			child = child.encode('ascii')
		except:
			pass

		child_node = children.get(child, None)

		if not child_node:
			children[child] = child_node = [0]

		return self._find_node(child_node, parts)

	def _add_rule(self, root, rule):
		if rule.startswith('!'):
			negate = 1
			rule = rule[1:]
		else:
			negate = 0

		parts = rule.split('.')
		self._find_node(root, parts)[0] = negate

	def _simplify(self, node):
		if len(node) == 1:
			return node[0]

		return (node[0], dict((k, self._simplify(v)) for (k, v) in node[1].iteritems()))

	def _build_structure(self, fp):
		root = [0]

		for line in fp:
			line = line.decode('utf-8').strip()
			if line.startswith('//') or not line:
				continue

			self._add_rule(root, line.split()[0].lstrip('.'))

		return root

	def _lookup_node(self, matches, depth, parent, parts):
		if parent in (0, 1):
			negate = parent
			children = None
		else:
			negate, children = parent

		matches[-depth] = negate

		if depth < len(parts) and children:
			for name in ('*', parts[-depth]):
				child = children.get(name, None)
				if child is not None:
					self._lookup_node(matches, depth+1, child, parts)

	def get_public_suffix(self, domain):
		"""get_public_suffix("www.example.com") -> "example.com"

		Calling this function with a DNS name will return the
		public suffix for that name.
		"""

		parts = domain.lower().lstrip('.').split('.')
		hits = [None] * len(parts)

		self._lookup_node(hits, 1, self.root, parts)

		for i, what in enumerate(hits):
			if what is not None and what == 0:
				return '.'.join(parts[i:])
<|endoftext|>


<commit_before>from ws4py.client.threadedclient import WebSocketClient
import Adafruit_BBIO.GPIO as GPIO

class DummyClient(WebSocketClient):
    def opened(self):
        GPIO.setup("USR3", GPIO.OUT)

        for i in range(0, 200, 25):
            self.send("#" * i)

    def closed(self, code, reason=None):
        print "Closed down", code, reason

    def received_message(self, m):
        print m
        if len(m) == 175:
            self.close(reason='Bye bye')

        if len(m) == 100:
             GPIO.output("USR3", GPIO.HIGH)

if __name__ == '__main__':
    try:
        ws = DummyClient('ws://echo.websocket.org', protocols=['http-only', 'chat'])
        ws.connect()
        ws.run_forever()
    except KeyboardInterrupt:
        ws.close()<commit_msg>commit mit PyCharm<commit_after>from ws4py.client.threadedclient import WebSocketClient
import Adafruit_BBIO.GPIO as GPIO

class DummyClient(WebSocketClient):
    def opened(self):
        GPIO.setup("USR3", GPIO.OUT)

        for i in range(0, 200, 25):
            self.send("#" * i)

    def closed(self, code, reason=None):
        GPIO.cleanup()
        print "Closed down", code, reason

    def received_message(self, m):
        print m
        if len(m) == 175:
            self.close(reason='Bye bye')

        if len(m) == 100:
             GPIO.output("USR3", GPIO.HIGH)

if __name__ == '__main__':
    try:
        ws = DummyClient('ws://echo.websocket.org', protocols=['http-only', 'chat'])
        ws.connect()
        ws.run_forever()
    except KeyboardInterrupt:
        ws.close()<|endoftext|>