<commit_before>##
# Copyright (c) 2008-2010 Sprymix Inc.
# All rights reserved.
#
# See LICENSE for details.
##

import datetime
import dateutil.parser
import dateutil.relativedelta
import dateutil.tz
import re

from semantix.utils import config

@config.configurable
class DateTime(datetime.datetime):
    local_timezone = config.cvalue(type=str, default=None, doc='Default local time-zone')
    local_tz = None

    def __new__(cls, value=None):
        if isinstance(value, datetime.datetime):
            d = value
        elif isinstance(value, str):
            try:
                d = dateutil.parser.parse(value)
            except ValueError as e:
                raise ValueError("invalid value for DateTime object: %s" % value) from e
        else:
            raise ValueError("invalid value for DateTime object: %s" % value)

        tzinfo = d.tzinfo or cls.get_tz()

        return super().__new__(cls, d.year, d.month, d.day, d.hour, d.minute, d.second,
                                    d.microsecond, tzinfo)

    @classmethod
    def get_tz(cls):
        if cls.local_tz is None:
            cls.local_tz = dateutil.tz.gettz(name=cls.local_timezone)
        return cls.local_tz

    @classmethod
    def now(cls, tz=None):
        if not tz:
            tz = cls.get_tz()
        return cls(datetime.datetime.now(tz=tz))

class TimeDelta(dateutil.relativedelta.relativedelta):
    _interval_tokens = {'year': 'years', 'years': 'years',
                        'month': 'months', 'months': 'months',
                        'week': 'weeks', 'weeks': 'weeks',
                        'day': 'days', 'days': 'days',
                        'hour': 'hours', 'hours': 'hours',
                        'minute': 'minutes', 'minutes': 'minutes',
                        'second': 'seconds', 'seconds': 'seconds',
                        'microsecond': 'microseconds', 'microseconds': 'microseconds'}

    def __new__(cls, value=None, *, dt1=None, dt2=None, years=0, months=0, days=0, leapdays=0,
                      weeks=0, hours=0, minutes=0, seconds=0, microseconds=0, year=None,
                      month=None, day=None, weekday=None, yearday=None, nlyearday=None, hour=None,
                      minute=None, second=None, microsecond=None):

        if value is None:
            result = super().__new__(cls)
            super().__init__(result,
                             dt1=dt1, dt2=dt2, years=years, months=months, days=days,
                             hours=hours, minutes=minutes,
                             seconds=seconds, microseconds=microseconds,
                             leapdays=leapdays, year=year, weeks=weeks,
                             month=month, day=day, weekday=weekday,
                             hour=hour, minute=minute, second=second,
                             microsecond=microsecond)

        elif isinstance(value, dateutil.relativedelta.relativedelta):
            result = super().__new__(cls)
            super().__init__(result,
                             years=value.years, months=value.months, days=value.days,
                             hours=value.hours, minutes=value.minutes,
                             seconds=value.seconds, microseconds=value.microseconds,
                             leapdays=value.leapdays, year=value.year,
                             month=value.month, day=value.day, weekday=value.weekday,
                             hour=value.hour, minute=value.minute,
                             second=value.second, microsecond=value.microsecond)

        elif isinstance(value, datetime.timedelta):
            result = super().__new__(cls)
            super().__init__(result,
                             days=value.days, seconds=value.seconds,
                             microseconds=value.microseconds)

        elif isinstance(value, str):
            expecting_number = True

            intervals = {}
            interval_tokens = cls._interval_tokens

            try:
                number = None

                for token in re.split('\s+', value):
                    if expecting_number:
                        number = int(token)
                    else:
                        interval = interval_tokens[token]
                        if interval in intervals:
                            raise ValueError
                        intervals[interval] = number
                    expecting_number = not expecting_number
                if not expecting_number:
                    raise ValueError
            except (ValueError, KeyError):
                raise ValueError("invalid timedelta value: '%s'" % value)

            result = super().__new__(cls)
            super().__init__(result, **intervals)

        else:
            raise ValueError("invalid timedelta value: '%s'" % value)

        return result

    def __init__(self, *args, **kwargs):
        # We initialize in __new__, so nothing to do here
        pass

    def __str__(self):
        s = []
        for k in ('years', 'months', 'days', 'hours', 'minutes', 'seconds', 'microseconds'):
            v = getattr(self, k)
            if v:
                s.append('%s %s' % (v, k if v != 1 else k[:-1]))
        return ' '.join(s)

    def __hash__(self):
        return hash((self.weekday, self.year, self.months, self.days, self.hours,
                     self.minutes, self.seconds, self.leapdays, self.year, self.month,
                     self.day, self.hour, self.minute, self.second, self.microsecond))

    def __gt__(self, other):
        if not isinstance(other, TimeDelta):
            return NotImplemented

        if self.weekday or other.weekday:
            raise TypeError('TimeDeltas with non-empty weekday are not orderable')

        return self.years > other.years or self.years == other.years and \
               (self.months > other.months or self.months == other.months and \
               (self.days > other.days or self.days == other.days and \
               (self.hours > other.hours or self.hours == other.hours and \
               (self.minutes > other.minutes or self.minutes == other.minutes and \
               (self.seconds > other.seconds or self.seconds == other.seconds and \
               (self.microseconds > other.microseconds))))))

    def __ge__(self, other):
        return self == other or self > other

    def __lt__(self, other):
        return not self >= other

    def __le__(self, other):
        return not self > other

    def to_months_days_seconds_microseconds(self):
        months = self.months + self.years * 12
        days = self.days
        seconds = self.seconds + self.minutes * 60 + self.hours * 3600
        microseconds = self.microseconds
        return months, days, seconds, microseconds

class Time(TimeDelta):
    def __new__(cls, value=None, *, format=None):
        if isinstance(value, datetime.time):
            d = value
        elif isinstance(value, str):
            try:
                if format:
                    d = datetime.datetime.strptime(value, format)
                else:
                    d = dateutil.parser.parse(value)
            except ValueError as e:
                raise ValueError("invalid value for Time object: %s" % value) from e
        else:
            raise ValueError("invalid value for Time object: %s" % value)

        return super().__new__(cls, hour=d.hour, minute=d.minute, second=d.second,
                                    microsecond=d.microsecond)

    def __str__(self):
        return '%d:%d:%d.%d' % (self.hour, self.minute, self.second, self.microsecond)

    def __repr__(self):
        return "'%d:%d:%d.%d'" % (self.hour, self.minute, self.second, self.microsecond)
<commit_msg>utils.datetime: Fix a typo in TimeDelta hash function<commit_after>##
# Copyright (c) 2008-2010 Sprymix Inc.
# All rights reserved.
#
# See LICENSE for details.
##

import datetime
import dateutil.parser
import dateutil.relativedelta
import dateutil.tz
import re

from semantix.utils import config

@config.configurable
class DateTime(datetime.datetime):
    local_timezone = config.cvalue(type=str, default=None, doc='Default local time-zone')
    local_tz = None

    def __new__(cls, value=None):
        if isinstance(value, datetime.datetime):
            d = value
        elif isinstance(value, str):
            try:
                d = dateutil.parser.parse(value)
            except ValueError as e:
                raise ValueError("invalid value for DateTime object: %s" % value) from e
        else:
            raise ValueError("invalid value for DateTime object: %s" % value)

        tzinfo = d.tzinfo or cls.get_tz()

        return super().__new__(cls, d.year, d.month, d.day, d.hour, d.minute, d.second,
                                    d.microsecond, tzinfo)

    @classmethod
    def get_tz(cls):
        if cls.local_tz is None:
            cls.local_tz = dateutil.tz.gettz(name=cls.local_timezone)
        return cls.local_tz

    @classmethod
    def now(cls, tz=None):
        if not tz:
            tz = cls.get_tz()
        return cls(datetime.datetime.now(tz=tz))

class TimeDelta(dateutil.relativedelta.relativedelta):
    _interval_tokens = {'year': 'years', 'years': 'years',
                        'month': 'months', 'months': 'months',
                        'week': 'weeks', 'weeks': 'weeks',
                        'day': 'days', 'days': 'days',
                        'hour': 'hours', 'hours': 'hours',
                        'minute': 'minutes', 'minutes': 'minutes',
                        'second': 'seconds', 'seconds': 'seconds',
                        'microsecond': 'microseconds', 'microseconds': 'microseconds'}

    def __new__(cls, value=None, *, dt1=None, dt2=None, years=0, months=0, days=0, leapdays=0,
                      weeks=0, hours=0, minutes=0, seconds=0, microseconds=0, year=None,
                      month=None, day=None, weekday=None, yearday=None, nlyearday=None, hour=None,
                      minute=None, second=None, microsecond=None):

        if value is None:
            result = super().__new__(cls)
            super().__init__(result,
                             dt1=dt1, dt2=dt2, years=years, months=months, days=days,
                             hours=hours, minutes=minutes,
                             seconds=seconds, microseconds=microseconds,
                             leapdays=leapdays, year=year, weeks=weeks,
                             month=month, day=day, weekday=weekday,
                             hour=hour, minute=minute, second=second,
                             microsecond=microsecond)

        elif isinstance(value, dateutil.relativedelta.relativedelta):
            result = super().__new__(cls)
            super().__init__(result,
                             years=value.years, months=value.months, days=value.days,
                             hours=value.hours, minutes=value.minutes,
                             seconds=value.seconds, microseconds=value.microseconds,
                             leapdays=value.leapdays, year=value.year,
                             month=value.month, day=value.day, weekday=value.weekday,
                             hour=value.hour, minute=value.minute,
                             second=value.second, microsecond=value.microsecond)

        elif isinstance(value, datetime.timedelta):
            result = super().__new__(cls)
            super().__init__(result,
                             days=value.days, seconds=value.seconds,
                             microseconds=value.microseconds)

        elif isinstance(value, str):
            expecting_number = True

            intervals = {}
            interval_tokens = cls._interval_tokens

            try:
                number = None

                for token in re.split('\s+', value):
                    if expecting_number:
                        number = int(token)
                    else:
                        interval = interval_tokens[token]
                        if interval in intervals:
                            raise ValueError
                        intervals[interval] = number
                    expecting_number = not expecting_number
                if not expecting_number:
                    raise ValueError
            except (ValueError, KeyError):
                raise ValueError("invalid timedelta value: '%s'" % value)

            result = super().__new__(cls)
            super().__init__(result, **intervals)

        else:
            raise ValueError("invalid timedelta value: '%s'" % value)

        return result

    def __init__(self, *args, **kwargs):
        # We initialize in __new__, so nothing to do here
        pass

    def __str__(self):
        s = []
        for k in ('years', 'months', 'days', 'hours', 'minutes', 'seconds', 'microseconds'):
            v = getattr(self, k)
            if v:
                s.append('%s %s' % (v, k if v != 1 else k[:-1]))
        return ' '.join(s)

    def __hash__(self):
        return hash((self.weekday, self.years, self.months, self.days, self.hours,
                     self.minutes, self.seconds, self.leapdays, self.year, self.month,
                     self.day, self.hour, self.minute, self.second, self.microsecond))

    def __gt__(self, other):
        if not isinstance(other, TimeDelta):
            return NotImplemented

        if self.weekday or other.weekday:
            raise TypeError('TimeDeltas with non-empty weekday are not orderable')

        return self.years > other.years or self.years == other.years and \
               (self.months > other.months or self.months == other.months and \
               (self.days > other.days or self.days == other.days and \
               (self.hours > other.hours or self.hours == other.hours and \
               (self.minutes > other.minutes or self.minutes == other.minutes and \
               (self.seconds > other.seconds or self.seconds == other.seconds and \
               (self.microseconds > other.microseconds))))))

    def __ge__(self, other):
        return self == other or self > other

    def __lt__(self, other):
        return not self >= other

    def __le__(self, other):
        return not self > other

    def to_months_days_seconds_microseconds(self):
        months = self.months + self.years * 12
        days = self.days
        seconds = self.seconds + self.minutes * 60 + self.hours * 3600
        microseconds = self.microseconds
        return months, days, seconds, microseconds

class Time(TimeDelta):
    def __new__(cls, value=None, *, format=None):
        if isinstance(value, datetime.time):
            d = value
        elif isinstance(value, str):
            try:
                if format:
                    d = datetime.datetime.strptime(value, format)
                else:
                    d = dateutil.parser.parse(value)
            except ValueError as e:
                raise ValueError("invalid value for Time object: %s" % value) from e
        else:
            raise ValueError("invalid value for Time object: %s" % value)

        return super().__new__(cls, hour=d.hour, minute=d.minute, second=d.second,
                                    microsecond=d.microsecond)

    def __str__(self):
        return '%d:%d:%d.%d' % (self.hour, self.minute, self.second, self.microsecond)

    def __repr__(self):
        return "'%d:%d:%d.%d'" % (self.hour, self.minute, self.second, self.microsecond)
<|endoftext|>


<commit_before>import unittest
from ggame import App, KeyEvent, MouseEvent

class keyevent(object):
  def __init__(self, ktype, code):
    self.keyCode = code
    self.type = ktype

class mouseevent(object):
  def __init__(self, etype, x, y, value):
    self.type = etype
    self.clientX = x
    self.clientY = y
    self.deltaY = value

class TestAppMethods(unittest.TestCase):

  def __init__(self, arg):
    super().__init__(arg)
    self.keyevtx = 0
    self.mouseevtx = 0

  def test_app(self):
    a3 = App(100,100)
    # event handling
    a3.listenKeyEvent(KeyEvent.keydown, "space", self.spacehandler)
    a3.listenMouseEvent(MouseEvent.mousewheel, self.wheelhandler)
    key = keyevent('keydown', 32)
    a3._keyEvent(key)
    mouse = mouseevent('wheel', 1, 2, 99)
    a3._mouseEvent(mouse)
    # confirm no events after unlisten
    a3.unlistenKeyEvent(KeyEvent.keydown, "space", self.spacehandler)
    a3.unlistenMouseEvent(MouseEvent.mousewheel, self.wheelhandler)
    a3._keyEvent(key)
    a3._mouseEvent(mouse)
    # assert that each handler was executed only once
    self.assertEqual(self.keyevtx, 1)
    self.assertEqual(self.mouseevtx, 1)
    # run the app
    a3.run()
    # and destroy it
    a3.destroy()

  def spacehandler(self, event):
    self.assertEqual(type(event), KeyEvent)
    self.keyevtx += 1

  def wheelhandler(self, event):
    self.assertEqual(type(event), MouseEvent)
    self.assertEqual(event.wheelDelta, 99)
    self.mouseevtx += 1

if __name__ == '__main__':
    unittest.main()
<commit_msg>New destroy api<commit_after>import unittest
from ggame import App, KeyEvent, MouseEvent

class keyevent(object):
  def __init__(self, ktype, code):
    self.keyCode = code
    self.type = ktype

class mouseevent(object):
  def __init__(self, etype, x, y, value):
    self.type = etype
    self.clientX = x
    self.clientY = y
    self.deltaY = value

class TestAppMethods(unittest.TestCase):

  def __init__(self, arg):
    super().__init__(arg)
    self.keyevtx = 0
    self.mouseevtx = 0

  def test_app(self):
    a3 = App(100,100)
    # event handling
    a3.listenKeyEvent(KeyEvent.keydown, "space", self.spacehandler)
    a3.listenMouseEvent(MouseEvent.mousewheel, self.wheelhandler)
    key = keyevent('keydown', 32)
    a3._keyEvent(key)
    mouse = mouseevent('wheel', 1, 2, 99)
    a3._mouseEvent(mouse)
    # confirm no events after unlisten
    a3.unlistenKeyEvent(KeyEvent.keydown, "space", self.spacehandler)
    a3.unlistenMouseEvent(MouseEvent.mousewheel, self.wheelhandler)
    a3._keyEvent(key)
    a3._mouseEvent(mouse)
    # assert that each handler was executed only once
    self.assertEqual(self.keyevtx, 1)
    self.assertEqual(self.mouseevtx, 1)
    # run the app
    a3.run()
    # and destroy it
    a3._destroy()

  def spacehandler(self, event):
    self.assertEqual(type(event), KeyEvent)
    self.keyevtx += 1

  def wheelhandler(self, event):
    self.assertEqual(type(event), MouseEvent)
    self.assertEqual(event.wheelDelta, 99)
    self.mouseevtx += 1

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


<commit_before>#!/usr/bin/env python
# encoding: utf-8
"""
server.py

Created by David Farrar  on 2011-11-30.
Copyright (c) 2011 Exa Networks. All rights reserved.
"""

# XXX: David, please add logging here ..

import socket
import errno

from exaproxy.network.poller import errno_block
from exaproxy.util.logger import logger

class Client(object):
	eor = '\r\n\r\n'

	def __init__(self, name, sock, peer):
		self.name = name
		self.sock = sock
		self.peer = peer
		self.reader = self._read(sock)
		self.writer = self._write(sock)

		self.blockupload = None

		# start the _read coroutine
		self.reader.next()

	def _read(self, sock, read_size=16*1024):
		"""Coroutine managing data read from the client"""
		r_buffer = ''
		request = ''
		r_size = yield ''

		while True:
			try:
				while True:
					data = sock.recv(r_size or read_size)
					if not data:   # read failed - abort
						break

					if request:
						r_size = yield '', data
						continue

					r_buffer += data

					if self.eor in r_buffer:       # we have a complete request
						request, r_buffer = r_buffer.split(self.eor, 1)

						r_size = yield request + self.eor, ''  # yield to manager.readRequest
						r_size = yield '', r_buffer            # yield to manager.startData
						r_buffer = ''
					else:
						r_size = yield '', ''                  # nothing seen yet

				# break out of the outer loop as soon as we leave the inner loop
				# through normal execution
				break

			except socket.error, e:
				if e.errno in errno_block:
					yield '', ''
				else:
					break

		yield None

	def readData(self):
		name, peer = self.name, self.peer
		res = self.reader.send(0) if self.reader else None

		if res is not None:
			request, content = res
		else:
			request, content = None, None

		return name, peer, request, content

	def _write(self, sock):
		"""Coroutine managing data sent to the client"""

		# TODO: use an open file for buffering data rather than storing
		#       it in memory

		w_buffer = ''
		filename = yield None

		# check to see if we are returning data directly from a local file
		if filename is not None:
			try:
				# XXX: reading the file contents into memory while we have a
				# are storing buffered data in ram rather than on the filesystem
				with open(filename) as fd:
					w_buffer = fd.read()

				found = True, False
			except IOError:
				found = None

			data = yield found
			w_buffer = data + w_buffer
		else:
			found = None

		data = yield found
		finished = False

		while True:
			try:
				while True:
					had_buffer = True if w_buffer else False

					if data is not None:
						w_buffer += data
					else:
						# We've finished downloading, even if the client hasn't yet
						finished = True

					if finished:
						if not w_buffer:
							break      # terminate the client connection
						elif data:
							logger.error('client', 'Tried to send data to client after we told it to close. Dropping it.')

					if not had_buffer or data == '':
						sent = sock.send(w_buffer)
						logger.info('client', 'wrote to socket %s sent %d bytes' % (str(sock),sent))
						w_buffer = w_buffer[sent:]

					buffered = True if w_buffer else False
					data = yield buffered, had_buffer

				# break out of the outer loop as soon as we leave the inner loop
				# through normal execution
				break

			except socket.error, e:
				if e.errno in errno_block:
					logger.error('client','failed to sent %d bytes' % len(data))
					logger.error('client','it would have blocked, why were we woken up !?!')
					logger.error('client','error %d: %s' % (e.errno, errno.errorcode.get(e.errno, '')))
					data = yield (True if w_buffer else False), had_buffer
				else:
					logger.critical('client','????? ARRGH ?????')
					yield None # stop the client connection
					break # and don't come back

		yield None

	def writeData(self, data):
		if self.blockupload:
			if self.reader:
				self.reader.send(None)
				self.reader = None

		res = self.writer.send(data)
		return res

	def startData(self, command, data, blockupload):
		# start the _write coroutine
		self.writer.next()

		self.blockupload = blockupload

		if command == 'stream':
			self.writer.send(None)  # no local file
			res = self.writer.send(data)

		elif command == 'close':
			self.writer.send(None)  # no local file
			self.writer.send(data)
			res = self.writer.send(None)  # close the connection once the buffer is empty

		elif command == 'file':
			header, filename = data
			res = self.writer.send(filename)  # use local file
			self.writer.send(header)      # write the response headers before the file

			self.writer.send(None)        # close the connection once the buffer is empty
		else:
			res = None

		# buffered, had_buffer
		return res

	def shutdown(self):
		try:
			self.sock.shutdown(socket.SHUT_RDWR)
			self.sock.close()
		except socket.error:
			pass

		self.writer.close()
		if self.reader:
			self.reader.close()
<commit_msg>Make sure we always close the connection when we should<commit_after>#!/usr/bin/env python
# encoding: utf-8
"""
server.py

Created by David Farrar  on 2011-11-30.
Copyright (c) 2011 Exa Networks. All rights reserved.
"""

# XXX: David, please add logging here ..

import socket
import errno

from exaproxy.network.poller import errno_block
from exaproxy.util.logger import logger

class Client(object):
	eor = '\r\n\r\n'

	def __init__(self, name, sock, peer):
		self.name = name
		self.sock = sock
		self.peer = peer
		self.reader = self._read(sock)
		self.writer = self._write(sock)

		self.blockupload = None

		# start the _read coroutine
		self.reader.next()

	def _read(self, sock, read_size=16*1024):
		"""Coroutine managing data read from the client"""
		r_buffer = ''
		request = ''
		r_size = yield ''

		while True:
			try:
				while True:
					data = sock.recv(r_size or read_size)
					if not data:   # read failed - abort
						break

					if request:
						r_size = yield '', data
						continue

					r_buffer += data

					if self.eor in r_buffer:       # we have a complete request
						request, r_buffer = r_buffer.split(self.eor, 1)

						r_size = yield request + self.eor, ''  # yield to manager.readRequest
						r_size = yield '', r_buffer            # yield to manager.startData
						r_buffer = ''
					else:
						r_size = yield '', ''                  # nothing seen yet

				# break out of the outer loop as soon as we leave the inner loop
				# through normal execution
				break

			except socket.error, e:
				if e.errno in errno_block:
					yield '', ''
				else:
					break

		yield None

	def readData(self):
		name, peer = self.name, self.peer
		res = self.reader.send(0) if self.reader else None

		if res is not None:
			request, content = res
		else:
			request, content = None, None

		return name, peer, request, content

	def _write(self, sock):
		"""Coroutine managing data sent to the client"""

		# TODO: use an open file for buffering data rather than storing
		#       it in memory

		w_buffer = ''
		filename = yield None

		# check to see if we are returning data directly from a local file
		if filename is not None:
			try:
				# XXX: reading the file contents into memory while we have a
				# are storing buffered data in ram rather than on the filesystem
				with open(filename) as fd:
					w_buffer = fd.read()

				found = True, False
			except IOError:
				found = None

			data = yield found
			w_buffer = data + w_buffer
		else:
			found = None

		data = yield found
		finished = False

		while True:
			try:
				while True:
					had_buffer = bool(w_buffer)

					if data is not None:
						w_buffer += data
					else:
						# We've finished downloading, even if the client hasn't yet
						finished = True

					if finished:
						if not w_buffer:
							break      # terminate the client connection
						elif data:
							logger.error('client', 'Tried to send data to client after we told it to close. Dropping it.')

					if not had_buffer or data == '':
						sent = sock.send(w_buffer)
						logger.info('client', 'wrote to socket %s sent %d bytes' % (str(sock),sent))
						w_buffer = w_buffer[sent:]

					buffered = bool(w_buffer) or finished
					data = yield buffered, had_buffer

				# break out of the outer loop as soon as we leave the inner loop
				# through normal execution
				break

			except socket.error, e:
				if e.errno in errno_block:
					logger.error('client','failed to sent %d bytes' % len(data))
					logger.error('client','it would have blocked, why were we woken up !?!')
					logger.error('client','error %d: %s' % (e.errno, errno.errorcode.get(e.errno, '')))
					data = yield (True if w_buffer else False), had_buffer
				else:
					logger.critical('client','????? ARRGH ?????')
					yield None # stop the client connection
					break # and don't come back

		yield None

	def writeData(self, data):
		if self.blockupload:
			if self.reader:
				self.reader.send(None)
				self.reader = None

		res = self.writer.send(data)
		return res

	def startData(self, command, data, blockupload):
		# start the _write coroutine
		self.writer.next()

		self.blockupload = blockupload

		if command == 'stream':
			self.writer.send(None)  # no local file
			res = self.writer.send(data)

		elif command == 'close':
			self.writer.send(None)  # no local file
			self.writer.send(data)
			res = self.writer.send(None)  # close the connection once the buffer is empty

		elif command == 'file':
			header, filename = data
			res = self.writer.send(filename)  # use local file
			self.writer.send(header)      # write the response headers before the file

			self.writer.send(None)        # close the connection once the buffer is empty
		else:
			res = None

		# buffered, had_buffer
		return res

	def shutdown(self):
		try:
			self.sock.shutdown(socket.SHUT_RDWR)
			self.sock.close()
		except socket.error:
			pass

		self.writer.close()
		if self.reader:
			self.reader.close()
<|endoftext|>


<commit_before>import yaml
import argparse
import tempfile
import os
import tarfile
import datetime
import time
import json
import sys
import logging
import docker
import docker.utils
import jinja2

logger = logging.getLogger('potter')

class Run(object):
    colors = dict(HEADER='\033[95m', OKBLUE='\033[94m', OKGREEN='\033[92m',
                  WARNING='\033[93m', FAIL='\033[91m')

    def __init__(self, context=None, **kwargs):
        self.use_color = True
        self.images = []
        self.containers = []
        self.__dict__.update(kwargs)
        yml = jinja2.Template(self.config_file.read()).render(env=os.environ, **context or {})
        config_unpacked = yaml.load(yml)
        self.config = config_unpacked['config']
        self.build = config_unpacked['build']
        self.client = docker.Client(**docker.utils.kwargs_from_env(assert_hostname=False))

    def log(self, msg, level=logging.INFO, color=None):
        if color and self.use_color:
            msg = "{}{}\033[0m".format(self.colors[color], msg)
        logger.log(level, msg)

    def debug(self, msg, color=None):
        return self.log(msg, level=logging.DEBUG, color=color)

    def run(self):
        try:
            start = time.time()
            cache_by_step, unused_cache = self.load_cache()
            target_image, unused_cache = self.run_steps(cache_by_step, unused_cache)
            self.remove_unused(unused_cache)
            self.log("=====> Created image {} in {}".format(target_image, time.time() - start), color='OKGREEN')
        except:
            logger.error("Exception raised, cleaning up ==========================")
            raise

    def load_cache(self):
        # Lookup all potential caching candidates
        resps = self.client.images(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        cache_by_step = {}
        unused_cache = set()
        for resp in resps:
            image = Image(resp, cache=True)
            unused_cache.add(image)
            cache_by_step.setdefault(image.step, []).append(image)

        return cache_by_step, unused_cache

    def create_steps(self):
        builtins = dict(pull=Pull, command=Command, copy=Copy)
        steps = []
        for i, step in enumerate(self.build):
            typ = list(step.keys())[0]
            step_cls = builtins.get(typ)
            if step_cls is None:
                logger.error("{} is an invalid step type".format(typ))
                raise Exception()
            steps.append(step_cls(self, step[typ], i))
        return steps

    def run_steps(self, cache_by_step, unused_cache):
        cache_enabled = True
        target_image = None
        steps = self.create_steps()
        for i, step in enumerate(steps):
            self.log("==> Step {} {} cfg:{}".format(
                i, step.__class__.__name__, step.config), color="HEADER")
            cache_objs = cache_by_step.get(i, []) if cache_enabled else []
            target_image = step.execute(cache_objs, target_image)
            # We've stopped using the cache, must disable moving forward
            if target_image.cache is False:
                cache_enabled = False
            else:
                unused_cache.remove(target_image)

        return target_image, unused_cache

    def remove_unused(self, unused_cache):
        for image in unused_cache:
            try:
                self.client.remove_image(image=image.id)
            except docker.errors.APIError:
                pass
            else:
                self.log("Removing unused cache image {}".format(image))

    def info(self):
        steps = self.create_steps()
        resps = self.client.images(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        self.log("All images related to {}".format(self.config['repo']), color='HEADER')
        self.log("{step:7}{short_id:15}{delta:20}{attrs:40}{config}"
                 .format(step="Step#", short_id="Image ID", delta="Created", config="Config", attrs="Attributes"))
        images = [Image(r) for r in resps]
        images.sort(key=lambda i: i.step, reverse=True)
        for image in images:
            attrs = []
            if steps[image.step].valid_cache(image):
                attrs.append("Valid Cache")

            attrs = ", ".join(attrs)
            self.log("{s.step:<7}{s.short_id:15}{s.delta:20}{attrs:<40}{s.config}".format(attrs=attrs, s=image))

    def clean(self):
        resps = self.client.containers(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        self.log("Deleting all containers related to {}"
                 .format(self.config['repo']), color='HEADER')
        for resp in resps:
            self.log("Removing {}".format(resp['Id']))
            self.client.remove_container(container=resp['Id'], force=True)

        resps = self.client.images(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        self.log("Deleting all images related to {}"
                 .format(self.config['repo']), color='HEADER')
        images = [Image(r) for r in resps]
        images.sort(key=lambda i: i.step, reverse=True)
        for image in images:
            self.log("{s.step:<7}{s.short_id:15}{s.delta:30}{s.config}".format(s=image))
            try:
                self.client.remove_image(image=image.id, force=True, noprune=True)
            except docker.errors.NotFound:
                pass

class Image(object):
    """ A wrapper for images that potter has generated """
    def __init__(self, resp, cache=False):
        self.id = resp.pop('Id')
        self.created = datetime.datetime.utcfromtimestamp(resp.pop('Created', 0))
        self.extra = resp
        self.cache = cache  # Is this image cached?

        labels = {key[7:]: val for key, val in resp['Labels'].items() if key.startswith("potter_")}
        self.config = json.loads(labels.pop('config'))
        self.config_hash = labels.pop('config_hash')
        self.step = int(labels.pop('step'))
        self.runtime = float(labels.pop('runtime', 0))
        self.potter_labels = labels

        assert len(self.id) == 64

    @classmethod
    def from_inspect(cls, resp):
        new_resp = resp['Config']
        new_resp['Id'] = resp['Id']
        obj = cls(new_resp)
        without_milli = resp['Created'].rsplit(".", 1)[0]
        obj.created = datetime.datetime.strptime(without_milli, "%Y-%m-%dT%H:%M:%S")
        return obj

    @property
    def delta(self):
        return str(datetime.datetime.utcnow() - self.created)

    @property
    def short_id(self):
        return self.id[:12]

    def __hash__(self):
        return int(self.id, 16)

    def __str__(self):
        return "<Image {}>".format(self.id[:12])

class Step(object):
    def __init__(self, run, config, step_num):
        self.step_num = step_num
        self.run = run
        self.config = config

        self.start_time = time.time()
        self.cacheable = True
        self.labels = self.gen_labels()

    def gen_labels(self):
        return {
            "potter_repo": self.run.config['repo'],
            "potter_step": str(self.step_num),
            "potter_config_hash": self.config_hash,
            "potter_config": json.dumps(self.config)
        }

    def valid_cache(self, image):
        """ Check if this image is a valid cached version of this step """
        checks = [self._config_hash_changed, self._cache_disabled_flag, self._invalidation_timer_expired]
        for check in checks:
            if check(image) is False:
                return False

        return True

    def _config_hash_changed(self, image):
        if image.config_hash != self.config_hash:
            self.run.debug("Skipping {} cache because step configuration has changed"
                           .format(image))
            return False

    def _cache_disabled_flag(self, image):
        if self.config.get('nocache') is True:
            self.run.debug("Skipping {} cache because nocache flag".format(image))
            return False

    def _invalidation_timer_expired(self, image):
        invalidate_after = self.config.get('invalidate_after')
        if invalidate_after is not None:
            delta = datetime.timedelta(seconds=int(invalidate_after))
            if image.created < datetime.datetime.utcnow() - delta:
                self.run.debug("Skipping {} cache because cache image is too old."
                               .format(image))
                return False

    def execute(self, cached_images, target_image):
        if self.cacheable and cached_images:
            self.run.log("Found {} cached image(s) from previous run".format(len(cached_images)))
            cached_images = [i for i in cached_images if self.valid_cache(i)]
            # Use the most recently generated of valid cache images
            cached_images.sort(key=lambda img: img.created, reverse=True)
            if cached_images:
                image = cached_images[0]
                self.run.log("==> Using cached {}, saved {:.2f}".format(image, image.runtime), color="OKBLUE")
                return image

        return self._execute(target_image)

    def _execute(self, target_image):
        raise NotImplemented("_execute must be defined")

    def commit_container(self, container_id):
        assert len(container_id) == 64
        self.labels['potter_runtime'] = str(time.time() - self.start_time)
        resp = self.run.client.commit(container=container_id, conf={'Labels': self.labels},
                                      repository=self.run.config['repo'])
        self.run.client.remove_container(container=container_id)
        resp = self.run.client.inspect_image(image=resp['Id'])
        image = Image.from_inspect(resp)
        self.run.log("==> New image {} generated in {}".format(image, image.runtime), color="OKGREEN")
        return image

    @property
    def config_hash(self):
        return str(hash(json.dumps(self.config)))

class Command(Step):
    def _execute(self, target_image):
        if isinstance(self.config['run'], list):
            command = self.config.get('join', " && ").join(self.config['run'])
        else:
            command = self.config['run']
        cmd = self.config.get('shell', '/bin/sh')
        container = self.run.client.create_container(image=target_image.id, command=[cmd, "-c", command])
        self.run.client.start(container['Id'])
        for log in self.run.client.attach(container=container['Id'], stdout=True, stderr=True, stream=True, logs=True):
            sys.stdout.write(log)
            sys.stdout.flush()
        if self.run.client.wait(container=container['Id']) != 0:
            raise Exception("Command step {} failed".format(self.step_num))
        return self.commit_container(container['Id'])

class Copy(Step):
    def _execute(self, target_image):
        container = self.run.client.create_container(image=target_image.id)
        uploadpath = os.path.join(self.config['dest'], os.path.basename(self.config['source']))
        self.run.log("Creating temporary tar file to upload {} to {}"
                     .format(self.config['source'], uploadpath))
        fo = tempfile.TemporaryFile()
        tar = tarfile.open(fileobj=fo, mode='w|')
        tar.add(self.config['source'], arcname=uploadpath)
        tar.close()

        def next_chunk(fo):
            total = float(fo.tell())
            fo.seek(0)
            read = 0
            while 1:
                data = fo.read(1024)
                if not data:
                    sys.stdout.write('\n')
                    break
                yield data
                read += 1024
                equals = int(read / total * 20)
                sys.stdout.write('\r[{}{}] {:.2f}%        '.format(
                    "=" * equals,
                    " " * (20 - equals),
                    read * 100 / total))
                sys.stdout.flush()
        self.run.log("Uploading and unpacking tar into container")
        self.run.client.put_archive(container=container['Id'], path='/', data=next_chunk(fo))
        fo.close()
        return self.commit_container(container['Id'])

class Pull(Step):
    def _execute(self, target_image):
        assert target_image is None  # Pull can only be first step
        tag = self.config.get('tag', 'latest')
        self.run.log("Pulling docker image {}:{}".format(self.config['image'], tag))
        progress = False
        for log in self.run.client.pull(repository=self.config['image'], tag=tag, stream=True):

            data = json.loads(log)
            if 'progress' in data:
                if progress:
                    sys.stdout.write('\r')
                sys.stdout.write(data['progress'])
                progress = True
            else:
                if progress:
                    progress = False
                    sys.stdout.write('\n')
                print(data['status'])
        self.start_time = time.time()  # Don't count the pull time as part of runtime
        self.run.log("==> Using image {}:{} as base".format(self.config['image'], tag), color="OKGREEN")
        container = self.run.client.create_container(image="{}:{}".format(self.config['image'], tag))
        return self.commit_container(container['Id'])

def main():
    console = logging.StreamHandler()
    console.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(message)s')
    console.setFormatter(formatter)
    logger.addHandler(console)
    logger.setLevel(logging.DEBUG)

    class StoreNameValuePair(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            if getattr(namespace, self.dest) is None:
                setattr(namespace, self.dest, {})
            n, v = values.split('=')
            getattr(namespace, self.dest)[n] = v

    parser = argparse.ArgumentParser(description='Build a docker container from a potter config file')
    parser.add_argument('config_file', help='the configuration file to load', type=argparse.FileType('r'))
    parser.add_argument('command', choices=['build', 'info'])
    parser.add_argument('--context', help='key value pairs to feed to jinja', action=StoreNameValuePair)

    args = parser.parse_args()
    potter = Run(**vars(args))
    if args.command == 'build':
        potter.run()
    elif args.command == 'clean':
        potter.clean()
    elif args.command == 'info':
        potter.info()

if __name__ == "__main__":
    main()
<commit_msg>Make logging level adjustable<commit_after>import yaml
import argparse
import tempfile
import os
import tarfile
import datetime
import time
import json
import sys
import logging
import docker
import docker.utils
import jinja2

logger = logging.getLogger('potter')

class Run(object):
    colors = dict(HEADER='\033[95m', OKBLUE='\033[94m', OKGREEN='\033[92m',
                  WARNING='\033[93m', FAIL='\033[91m')

    def __init__(self, context=None, **kwargs):
        self.use_color = True
        self.images = []
        self.containers = []
        self.__dict__.update(kwargs)
        yml = jinja2.Template(self.config_file.read()).render(env=os.environ, **context or {})
        config_unpacked = yaml.load(yml)
        self.config = config_unpacked['config']
        self.build = config_unpacked['build']
        self.client = docker.Client(**docker.utils.kwargs_from_env(assert_hostname=False))

    def log(self, msg, level=logging.INFO, color=None):
        if color and self.use_color:
            msg = "{}{}\033[0m".format(self.colors[color], msg)
        logger.log(level, msg)

    def debug(self, msg, color=None):
        return self.log(msg, level=logging.DEBUG, color=color)

    def run(self):
        try:
            start = time.time()
            cache_by_step, unused_cache = self.load_cache()
            target_image, unused_cache = self.run_steps(cache_by_step, unused_cache)
            self.remove_unused(unused_cache)
            self.log("=====> Created image {} in {}".format(target_image, time.time() - start), color='OKGREEN')
        except:
            logger.error("Exception raised, cleaning up ==========================")
            raise

    def load_cache(self):
        # Lookup all potential caching candidates
        resps = self.client.images(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        cache_by_step = {}
        unused_cache = set()
        for resp in resps:
            image = Image(resp, cache=True)
            unused_cache.add(image)
            cache_by_step.setdefault(image.step, []).append(image)

        return cache_by_step, unused_cache

    def create_steps(self):
        builtins = dict(pull=Pull, command=Command, copy=Copy)
        steps = []
        for i, step in enumerate(self.build):
            typ = list(step.keys())[0]
            step_cls = builtins.get(typ)
            if step_cls is None:
                logger.error("{} is an invalid step type".format(typ))
                raise Exception()
            steps.append(step_cls(self, step[typ], i))
        return steps

    def run_steps(self, cache_by_step, unused_cache):
        cache_enabled = True
        target_image = None
        steps = self.create_steps()
        for i, step in enumerate(steps):
            self.log("==> Step {} {} cfg:{}".format(
                i, step.__class__.__name__, step.config), color="HEADER")
            cache_objs = cache_by_step.get(i, []) if cache_enabled else []
            target_image = step.execute(cache_objs, target_image)
            # We've stopped using the cache, must disable moving forward
            if target_image.cache is False:
                cache_enabled = False
            else:
                unused_cache.remove(target_image)

        return target_image, unused_cache

    def remove_unused(self, unused_cache):
        for image in unused_cache:
            try:
                self.client.remove_image(image=image.id)
            except docker.errors.APIError:
                pass
            else:
                self.log("Removing unused cache image {}".format(image))

    def info(self):
        steps = self.create_steps()
        resps = self.client.images(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        self.log("All images related to {}".format(self.config['repo']), color='HEADER')
        self.log("{step:7}{short_id:15}{delta:20}{attrs:40}{config}"
                 .format(step="Step#", short_id="Image ID", delta="Created", config="Config", attrs="Attributes"))
        images = [Image(r) for r in resps]
        images.sort(key=lambda i: i.step, reverse=True)
        for image in images:
            attrs = []
            if steps[image.step].valid_cache(image):
                attrs.append("Valid Cache")

            attrs = ", ".join(attrs)
            self.log("{s.step:<7}{s.short_id:15}{s.delta:20}{attrs:<40}{s.config}".format(attrs=attrs, s=image))

    def clean(self):
        resps = self.client.containers(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        self.log("Deleting all containers related to {}"
                 .format(self.config['repo']), color='HEADER')
        for resp in resps:
            self.log("Removing {}".format(resp['Id']))
            self.client.remove_container(container=resp['Id'], force=True)

        resps = self.client.images(all=True, filters={'label': "potter_repo={}".format(self.config['repo'])})
        self.log("Deleting all images related to {}"
                 .format(self.config['repo']), color='HEADER')
        images = [Image(r) for r in resps]
        images.sort(key=lambda i: i.step, reverse=True)
        for image in images:
            self.log("{s.step:<7}{s.short_id:15}{s.delta:30}{s.config}".format(s=image))
            try:
                self.client.remove_image(image=image.id, force=True, noprune=True)
            except docker.errors.NotFound:
                pass

class Image(object):
    """ A wrapper for images that potter has generated """
    def __init__(self, resp, cache=False):
        self.id = resp.pop('Id')
        self.created = datetime.datetime.utcfromtimestamp(resp.pop('Created', 0))
        self.extra = resp
        self.cache = cache  # Is this image cached?

        labels = {key[7:]: val for key, val in resp['Labels'].items() if key.startswith("potter_")}
        self.config = json.loads(labels.pop('config'))
        self.config_hash = labels.pop('config_hash')
        self.step = int(labels.pop('step'))
        self.runtime = float(labels.pop('runtime', 0))
        self.potter_labels = labels

        assert len(self.id) == 64

    @classmethod
    def from_inspect(cls, resp):
        new_resp = resp['Config']
        new_resp['Id'] = resp['Id']
        obj = cls(new_resp)
        without_milli = resp['Created'].rsplit(".", 1)[0]
        obj.created = datetime.datetime.strptime(without_milli, "%Y-%m-%dT%H:%M:%S")
        return obj

    @property
    def delta(self):
        return str(datetime.datetime.utcnow() - self.created)

    @property
    def short_id(self):
        return self.id[:12]

    def __hash__(self):
        return int(self.id, 16)

    def __str__(self):
        return "<Image {}>".format(self.id[:12])

class Step(object):
    def __init__(self, run, config, step_num):
        self.step_num = step_num
        self.run = run
        self.config = config

        self.start_time = time.time()
        self.cacheable = True
        self.labels = self.gen_labels()

    def gen_labels(self):
        return {
            "potter_repo": self.run.config['repo'],
            "potter_step": str(self.step_num),
            "potter_config_hash": self.config_hash,
            "potter_config": json.dumps(self.config)
        }

    def valid_cache(self, image):
        """ Check if this image is a valid cached version of this step """
        checks = [self._config_hash_changed, self._cache_disabled_flag, self._invalidation_timer_expired]
        for check in checks:
            if check(image) is False:
                return False

        return True

    def _config_hash_changed(self, image):
        if image.config_hash != self.config_hash:
            self.run.debug("Skipping {} cache because step configuration has changed"
                           .format(image))
            return False

    def _cache_disabled_flag(self, image):
        if self.config.get('nocache') is True:
            self.run.debug("Skipping {} cache because nocache flag".format(image))
            return False

    def _invalidation_timer_expired(self, image):
        invalidate_after = self.config.get('invalidate_after')
        if invalidate_after is not None:
            delta = datetime.timedelta(seconds=int(invalidate_after))
            if image.created < datetime.datetime.utcnow() - delta:
                self.run.debug("Skipping {} cache because cache image is too old."
                               .format(image))
                return False

    def execute(self, cached_images, target_image):
        if self.cacheable and cached_images:
            self.run.log("Found {} cached image(s) from previous run".format(len(cached_images)))
            cached_images = [i for i in cached_images if self.valid_cache(i)]
            # Use the most recently generated of valid cache images
            cached_images.sort(key=lambda img: img.created, reverse=True)
            if cached_images:
                image = cached_images[0]
                self.run.log("==> Using cached {}, saved {:.2f}".format(image, image.runtime), color="OKBLUE")
                return image

        return self._execute(target_image)

    def _execute(self, target_image):
        raise NotImplemented("_execute must be defined")

    def commit_container(self, container_id):
        assert len(container_id) == 64
        self.labels['potter_runtime'] = str(time.time() - self.start_time)
        resp = self.run.client.commit(container=container_id, conf={'Labels': self.labels},
                                      repository=self.run.config['repo'])
        self.run.client.remove_container(container=container_id)
        resp = self.run.client.inspect_image(image=resp['Id'])
        image = Image.from_inspect(resp)
        self.run.log("==> New image {} generated in {}".format(image, image.runtime), color="OKGREEN")
        return image

    @property
    def config_hash(self):
        return str(hash(json.dumps(self.config)))

class Command(Step):
    def _execute(self, target_image):
        if isinstance(self.config['run'], list):
            command = self.config.get('join', " && ").join(self.config['run'])
        else:
            command = self.config['run']
        cmd = self.config.get('shell', '/bin/sh')
        container = self.run.client.create_container(image=target_image.id, command=[cmd, "-c", command])
        self.run.client.start(container['Id'])
        for log in self.run.client.attach(container=container['Id'], stdout=True, stderr=True, stream=True, logs=True):
            sys.stdout.write(log)
            sys.stdout.flush()
        if self.run.client.wait(container=container['Id']) != 0:
            raise Exception("Command step {} failed".format(self.step_num))
        return self.commit_container(container['Id'])

class Copy(Step):
    def _execute(self, target_image):
        container = self.run.client.create_container(image=target_image.id)
        uploadpath = os.path.join(self.config['dest'], os.path.basename(self.config['source']))
        self.run.log("Creating temporary tar file to upload {} to {}"
                     .format(self.config['source'], uploadpath))
        fo = tempfile.TemporaryFile()
        tar = tarfile.open(fileobj=fo, mode='w|')
        tar.add(self.config['source'], arcname=uploadpath)
        tar.close()

        def next_chunk(fo):
            total = float(fo.tell())
            fo.seek(0)
            read = 0
            while 1:
                data = fo.read(1024)
                if not data:
                    sys.stdout.write('\n')
                    break
                yield data
                read += 1024
                equals = int(read / total * 20)
                sys.stdout.write('\r[{}{}] {:.2f}%        '.format(
                    "=" * equals,
                    " " * (20 - equals),
                    read * 100 / total))
                sys.stdout.flush()
        self.run.log("Uploading and unpacking tar into container")
        self.run.client.put_archive(container=container['Id'], path='/', data=next_chunk(fo))
        fo.close()
        return self.commit_container(container['Id'])

class Pull(Step):
    def _execute(self, target_image):
        assert target_image is None  # Pull can only be first step
        tag = self.config.get('tag', 'latest')
        self.run.log("Pulling docker image {}:{}".format(self.config['image'], tag))
        progress = False
        for log in self.run.client.pull(repository=self.config['image'], tag=tag, stream=True):

            data = json.loads(log)
            if 'progress' in data:
                if progress:
                    sys.stdout.write('\r')
                sys.stdout.write(data['progress'])
                progress = True
            else:
                if progress:
                    progress = False
                    sys.stdout.write('\n')
                print(data['status'])
        self.start_time = time.time()  # Don't count the pull time as part of runtime
        self.run.log("==> Using image {}:{} as base".format(self.config['image'], tag), color="OKGREEN")
        container = self.run.client.create_container(image="{}:{}".format(self.config['image'], tag))
        return self.commit_container(container['Id'])

def main():
    class StoreNameValuePair(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            if getattr(namespace, self.dest) is None:
                setattr(namespace, self.dest, {})
            n, v = values.split('=')
            getattr(namespace, self.dest)[n] = v

    parser = argparse.ArgumentParser(description='Build a docker container from a potter config file')
    parser.add_argument('config_file', help='the configuration file to load', type=argparse.FileType('r'))
    parser.add_argument('command', choices=['build', 'info'])
    parser.add_argument('--log-level', '-l', help='how verbose to log',
                        choices=['DEBUG', 'INFO', 'WARN', 'ERROR'], default='INFO')
    parser.add_argument('--context', help='key value pairs to feed to jinja in key=val format', action=StoreNameValuePair)
    args = parser.parse_args()

    console = logging.StreamHandler()
    console.setLevel(getattr(logging, args.log_level))
    formatter = logging.Formatter('%(message)s')
    console.setFormatter(formatter)
    logger.addHandler(console)
    logger.setLevel(getattr(logging, args.log_level))

    potter = Run(**vars(args))
    if args.command == 'build':
        potter.run()
    elif args.command == 'clean':
        potter.clean()
    elif args.command == 'info':
        potter.info()

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


<commit_before># -*- coding: utf-8 -*-
import dulwich
import StringIO
from eforge.browser.interface import *

class GitRepository(IRepository):
    def __init__(self, path):
        self.repo = dulwich.repo.Repo(path)

    def __findrefs(self, prefix):
        grefs = self.repo.refs
        refs = {}
        for ref in grefs.keys():
            if ref.startswith(prefix):
                refs[ref[len(prefix):]] = GitRevision(self, self.repo.refs.follow(ref))

        return refs

    @property
    def branches(self):
        return self.__findrefs('refs/heads/')

    @property
    def tags(self):
        return self.__findrefs('refs/tags/')

    def revision(self, id):
        return GitRevision(self, id)

    @property
    def head(self):
        return GitRevision(self, self.repo.head())

    @property
    def revisions(self, num):
        revs = []

        walk = self.repo.get_graph_walker()
        ob = walk.next()
        while ob and len(revs) < num:
            revs.append(GitRevision(self, ob))
            ob = walk.next()

        return revs

class GitRevision(IRevision):
    def __init__(self, repo, rev):
        self.repo = repo
        if not isinstance(rev, dulwich.objects.Commit):
            self.rev  = repo.repo[rev]
        else:
            self.rev = rev

    @property
    def id(self):
        return self.rev.id

    @property
    def short_id(self):
        return self.id[0:8]

    @property
    def author_email(self):
        try:
            return self.rev.author.split('<')[1][:-1]
        except:
            return None

    @property
    def message(self):
        return self.rev.message

    @property
    def author_name(self):
        try:
            return self.rev.author.split('<')[0].strip()
        except:
            return self.rev.author

    @property
    def parents(self):
        return [GitRevision(self.repo, x) for x in self.rev.parents]

    @property
    def children(self):
        return []

    @property
    def root(self):
        return GitDirectory(self.repo, self.repo.repo[self.rev.tree], None, None)

class GitDirectory(IDirectory):
    def __init__(self, repo, tree, parent, name):
        self.repo = repo
        self.tree = tree
        IDirectory.__init__(self, parent, name)

    @property
    def children(self):
        children = []
        entries = self.tree.entries()
        print 'children %s' % entries
        for ent in entries:
            print ent
            name = ent[1]
            obj  = self.repo.repo[ent[2]]
            print obj
            try:
                if isinstance(obj, dulwich.objects.Tree):
                    children.append(GitDirectory(self.repo, obj, self, name))
                else:
                    children.append(GitFile(self.repo, obj, self, name))
            except Exception, e:
                print "Exception: %s" % e

        return children

    def child(self, name):
        obj = self.repo.repo[self.tree[name][1]]
        if isinstance(obj, dulwich.objects.Tree):
            return GitDirectory(self.repo, obj, self, name)
        else:
            return GitFile(self.repo, obj, self, name)

class GitFile(IFile, StringIO.StringIO):
    def __init__(self, repo, file, parent, name):
        self.repo = repo
        self.file = file

        self.data = file.data

        IFile.__init__(self, parent, name)
        StringIO.StringIO.__init__(self, self.data)
        self.__size = len(self.data)

    @property
    def size(self):
        return self.__size

<commit_msg>I left the @property marker on the GitRepository::revisions method. Gaah.<commit_after># -*- coding: utf-8 -*-
import dulwich
import StringIO
from eforge.browser.interface import *

class GitRepository(IRepository):
    def __init__(self, path):
        self.repo = dulwich.repo.Repo(path)

    def __findrefs(self, prefix):
        grefs = self.repo.refs
        refs = {}
        for ref in grefs.keys():
            if ref.startswith(prefix):
                refs[ref[len(prefix):]] = GitRevision(self, self.repo.refs.follow(ref))

        return refs

    @property
    def branches(self):
        return self.__findrefs('refs/heads/')

    @property
    def tags(self):
        return self.__findrefs('refs/tags/')

    def revision(self, id):
        return GitRevision(self, id)

    @property
    def head(self):
        return GitRevision(self, self.repo.head())

    def revisions(self, num):
        revs = []

        walk = self.repo.get_graph_walker()
        ob = walk.next()
        while ob and len(revs) < num:
            revs.append(GitRevision(self, ob))
            ob = walk.next()

        return revs

class GitRevision(IRevision):
    def __init__(self, repo, rev):
        self.repo = repo
        if not isinstance(rev, dulwich.objects.Commit):
            self.rev  = repo.repo[rev]
        else:
            self.rev = rev

    @property
    def id(self):
        return self.rev.id

    @property
    def short_id(self):
        return self.id[0:8]

    @property
    def author_email(self):
        try:
            return self.rev.author.split('<')[1][:-1]
        except:
            return None

    @property
    def message(self):
        return self.rev.message

    @property
    def author_name(self):
        try:
            return self.rev.author.split('<')[0].strip()
        except:
            return self.rev.author

    @property
    def parents(self):
        return [GitRevision(self.repo, x) for x in self.rev.parents]

    @property
    def children(self):
        return []

    @property
    def root(self):
        return GitDirectory(self.repo, self.repo.repo[self.rev.tree], None, None)

class GitDirectory(IDirectory):
    def __init__(self, repo, tree, parent, name):
        self.repo = repo
        self.tree = tree
        IDirectory.__init__(self, parent, name)

    @property
    def children(self):
        children = []
        entries = self.tree.entries()
        print 'children %s' % entries
        for ent in entries:
            print ent
            name = ent[1]
            obj  = self.repo.repo[ent[2]]
            print obj
            try:
                if isinstance(obj, dulwich.objects.Tree):
                    children.append(GitDirectory(self.repo, obj, self, name))
                else:
                    children.append(GitFile(self.repo, obj, self, name))
            except Exception, e:
                print "Exception: %s" % e

        return children

    def child(self, name):
        obj = self.repo.repo[self.tree[name][1]]
        if isinstance(obj, dulwich.objects.Tree):
            return GitDirectory(self.repo, obj, self, name)
        else:
            return GitFile(self.repo, obj, self, name)

class GitFile(IFile, StringIO.StringIO):
    def __init__(self, repo, file, parent, name):
        self.repo = repo
        self.file = file

        self.data = file.data

        IFile.__init__(self, parent, name)
        StringIO.StringIO.__init__(self, self.data)
        self.__size = len(self.data)

    @property
    def size(self):
        return self.__size

<|endoftext|>


<commit_before>
import time

class Timer:
    def __init__(self, verbose=False, messagelen=20):
        now = time.time()
        self.times = [(now, now, "", [])]
        self.subtimes = []
        self.verbose = verbose
        self.messagelen = messagelen
    def duration_ms(self, entry):
        return int((entry[1] - entry[0]) * 1000)
    def print_message(self, message, time_ms):
        print "{{:{}}} {{:8}}ms".format(self.messagelen).format(message, time_ms)
    def measure(self, message):
        if len(message) > self.messagelen:
            self.messagelen = len(message) + 10
        now = time.time()
        self.times.append((self.times[-1][1], now, message, self.subtimes))
        self.subtimes = []
        if self.verbose:
            self.print_message(message, self.duration_ms(self.times[-1]))
    def submeasure(self, message):
        message = "    " + message
        if len(message) > self.messagelen:
            self.messagelen = len(message) + 10
        now = time.time()
        if self.subtimes:
            self.subtimes.append((self.subtimes[-1][1], now, message))
        else:
            self.subtimes.append((self.times[-1][1], now, message))
        if self.verbose:
            if len(self.subtimes) == 1:
                print
            self.print_message(message, self.duration_ms(self.subtimes[-1]))
    def print_all(self):
        for t in self.times[1:]:
            begin, end, message, subtimes = t
            self.print_message(message, self.duration_ms(t))
            for st in subtimes:
                sbegin, send, smessage = st
                self.print_message(message, self.duration_ms(st))
    def full_duration(self):
        return self.times[-1][1] - self.times[0][0]
    def print_total(self):
        print "in total: {}".format(self.duration_ms(self.full_duration()))
<commit_msg>might fix instrumenting.py<commit_after>
import time

class Timer:
    def __init__(self, verbose=False, messagelen=20):
        now = time.time()
        self.times = [(now, now, "", [])]
        self.subtimes = []
        self.verbose = verbose
        self.messagelen = messagelen
    def duration_ms(self, entry):
        return int((entry[1] - entry[0]) * 1000)
    def print_message(self, message, time_ms):
        print "{{:{}}} {{:8}}ms".format(self.messagelen).format(message, time_ms)
    def measure(self, message):
        if len(message) > self.messagelen:
            self.messagelen = len(message) + 10
        now = time.time()
        self.times.append((self.times[-1][1], now, message, self.subtimes))
        self.subtimes = []
        if self.verbose:
            self.print_message(message, self.duration_ms(self.times[-1]))
    def submeasure(self, message):
        message = "    " + message
        if len(message) > self.messagelen:
            self.messagelen = len(message) + 10
        now = time.time()
        if self.subtimes:
            self.subtimes.append((self.subtimes[-1][1], now, message))
        else:
            self.subtimes.append((self.times[-1][1], now, message))
        if self.verbose:
            if len(self.subtimes) == 1:
                print
            self.print_message(message, self.duration_ms(self.subtimes[-1]))
    def print_all(self):
        for t in self.times[1:]:
            begin, end, message, subtimes = t
            self.print_message(message, self.duration_ms(t))
            for st in subtimes:
                sbegin, send, smessage = st
                self.print_message(message, self.duration_ms(st))
    def full_duration(self):
        return self.times[-1][1] - self.times[0][0]
    def print_total(self):
        print "in total: {}".format(int(self.full_duration() * 1000))
<|endoftext|>


<commit_before>#! /usr/bin/python3

import xml.etree.ElementTree as ET
from copy import deepcopy

def print_comment(s, multiline=False):
    if not multiline:
        print('/*', s.strip(), '*/')
        return
    print('/*')
    for line in s.splitlines():
        print(' *', line.strip())
    print(' */')

def objc_case(name, first_capital=False):
    res = name.replace('_', ' ').title().replace(' ', '')
    if not first_capital:
        res = res[0].lower() + res[1:]
    return res

class Protocol:
    def parse(node):
        assert(node.tag == 'protocol')
        res = Protocol()
        res.name = node.attrib['name']
        res.interfaces = []
        for child in node:
            if child.tag == 'copyright':
                res.copyright = child.text
            if child.tag == 'interface':
                interface = Interface.parse(child, protocol=res)
                res.interfaces.append(interface)
        return res

    def print_decl(self):
        print_comment(self.name + ' protocol')
        if self.copyright:
            print_comment(self.copyright, multiline=True)
        for interface in self.interfaces:
            interface.print_decl()
            print()

class Interface:
    def parse(node, protocol):
        assert(node.tag == 'interface')
        res = Interface()
        res.name = node.attrib['name']
        res.version = node.attrib['version']
        res.requests = []
        res.events = []
        for child in node:
            if child.tag == 'description':
                res.description = child.text
            if child.tag == 'request':
                request = Request.parse(child, interface=res)
                res.requests.append(request)
            if child.tag == 'event':
                event = Event.parse(child, interface=res)
                res.events.append(event)
        return res

    def objc_name(name):
        if isinstance(name, Interface):
            name = name.name
        res = objc_case(name, first_capital=True)
        for prefix in 'wl', 'wp', 'xdg', 'zxdg':
            if res.lower().startswith(prefix):
                l = len(prefix)
                res = prefix.upper() + res[l:]
        return res

    def print_decl(self):
        if self.description:
            print_comment(self.description, multiline=True)
        print('@interface', self.objc_name(), '{')
        print('struct', self.name, '*rawHandle;')
        print('}')
        for request in self.requests:
            request.print_decl()
        for event in self.events:
            event.print_decl()
        print('@end')

class Request:
    def parse(node, interface):
        assert(node.tag == 'request')
        res = Request()
        res.name = node.attrib['name']
        res.args = []
        for child in node:
            if child.tag == 'description':
                res.description = child.text
            if child.tag == 'arg':
                arg = Arg.parse(child)
                res.args.append(arg)
        # generate objc names and args
        if not res.name.startswith('get'):
            res.objc_name = objc_case(res.name)
        else:
            res.objc_name = objc_case(res.name[3:])
        if not res.args:
            res.new_id = None
            res.objc_args = []
            return res
        if res.args[0].type == 'new_id':
            res.new_id = res.args[0]
            res.args = res.args[1:]
        else:
            res.new_id = None
        res.objc_args = deepcopy(res.args)
        for arg in res.objc_args:
            arg.name = objc_case(arg.name)
            if arg.type == 'object':
                arg.type = Interface.objc_name(arg.interface) + ' *'
            elif arg.type == 'string':
                arg.type = 'NSString *'
            elif arg.type == 'uint':
                arg.type = 'uint32_t'
            else:
                # TODO: other types
                pass
        if res.args:
            a0n = objc_case(res.args[0].name, first_capital=True)
            if not res.objc_name.endswith(a0n):
                res.objc_name += 'With' + a0n
        return res

    def print_decl(self):
        if self.description:
            print_comment(self.description, multiline=True)
        return_type = 'void'
        if self.new_id is not None:
            return_type = Interface.objc_name(self.new_id.interface) + ' *'
        print('- ({})'.format(return_type), end='')
        if not self.objc_args:
            print(' {};'.format(self.objc_name))
        else:
            print(end=' ')
            self.objc_args[0].print_decl(label=self.objc_name)
            for arg in self.objc_args[1:]:
                print(end=' ')
                arg.print_decl()
            print(';')

class Event:
    def parse(node, interface):
        assert(node.tag == 'event')
        res = Event()
        res.name = node.attrib['name']
        res.args = []
        for child in node:
            if child.tag == 'description':
                res.description = child.text
            if child.tag == 'arg':
                arg = Arg.parse(child)
                res.args.append(arg)
        return res

    def print_decl(self):
        if self.description:
            print_comment(self.description, multiline=True)
        name = objc_case('set_{}_handler'.format(self.name))
        args_decl = ', '.join(arg.cdecl() for arg in self.args)
        print('- (void) {}: (void (^)({})) handler;'.format(name, args_decl))

class Arg:
    def parse(node):
        assert(node.tag == 'arg')
        res = Arg()
        res.name = node.attrib['name']
        res.type = node.attrib['type']
        res.summary = node.attrib['summary']
        if 'interface' in node.attrib:
            res.interface = node.attrib['interface']
            res.allow_null = False
        if 'allow-null' in node.attrib:
            res.allow_null = node.attrib['allow-null'] == 'true'
        return res

    def print_decl(self, label=None):
        if label is None:
            label = self.name
        print('{}: ({}) {}'.format(label, self.type, self.name), end='')

    def cdecl(self):
        return '{} {}'.format(self.type, self.name)

print_comment('Automatically generated by wl-objc bindings generator')
tree = ET.parse('/dev/stdin')
root = tree.getroot()
Protocol.parse(root).print_decl()
<commit_msg>More work<commit_after>#! /usr/bin/python3

import xml.etree.ElementTree as ET
from copy import deepcopy

def print_comment(s, multiline=False):
    if not multiline:
        print('/*', s.strip(), '*/')
        return
    print('/*')
    for line in s.splitlines():
        print(' *', line.strip())
    print(' */')

def objc_case(name, first_capital=False):
    res = name.replace('_', ' ').title().replace(' ', '')
    if not first_capital:
        res = res[0].lower() + res[1:]
    return res

class Protocol:
    def parse(node):
        assert(node.tag == 'protocol')
        res = Protocol()
        res.name = node.attrib['name']
        res.interfaces = []
        for child in node:
            if child.tag == 'copyright':
                res.copyright = child.text
            if child.tag == 'interface':
                interface = Interface.parse(child, protocol=res)
                res.interfaces.append(interface)
        return res

    def print_decl(self):
        print_comment(self.name + ' protocol')
        if self.copyright:
            print_comment(self.copyright, multiline=True)
        for interface in self.interfaces:
            interface.print_decl()
            print()

class Interface:
    def parse(node, protocol):
        assert(node.tag == 'interface')
        res = Interface()
        res.name = node.attrib['name']
        res.version = node.attrib['version']
        res.requests = []
        res.events = []
        for child in node:
            if child.tag == 'description':
                res.description = child.text
            if child.tag == 'request':
                request = Request.parse(child, interface=res)
                res.requests.append(request)
            if child.tag == 'event':
                event = Event.parse(child, interface=res)
                res.events.append(event)
        if res.name == 'wl_display':
            res.requests += [
                Interface.gen_connect(),
                Interface.gen_connect_with_name(),
                Interface.gen_connect_to_fd(),
                Interface.gen_disconnect(),
            ]
        return res

    def gen_connect():
        r = Request()
        r.name = 'connect'
        r.static = True
        r.description = None
        r.objc_name = 'connect'
        r.args = []
        r.objc_args = []
        r.new_id = Arg()
        r.new_id.type = 'interface'
        r.new_id.interface = 'wl_display'
        return r
    def gen_connect_with_name():
        r = Request()
        r.name = 'connect'
        r.static = True
        r.description = None
        r.objc_name = 'connectWithName'
        r.args = [Arg()]
        r.objc_args = [Arg()]
        r.args[0].name = 'name'
        r.args[0].type = 'string'
        r.objc_args[0].name = 'name'
        r.objc_args[0].type = 'NSString *'
        r.new_id = Arg()
        r.new_id.type = 'interface'
        r.new_id.interface = 'wl_display'
        return r
    def gen_connect_to_fd():
        r = Request()
        r.name = 'connect'
        r.static = True
        r.description = None
        r.objc_name = 'connectToFd'
        r.args = [Arg()]
        r.objc_args = [Arg()]
        r.args[0].name = 'fd'
        r.args[0].type = 'fd'
        r.objc_args[0].name = 'fd'
        r.objc_args[0].type = 'int'
        r.new_id = Arg()
        r.new_id.type = 'interface'
        r.new_id.interface = 'wl_display'
        return r
    def gen_disconnect():
        r = Request()
        r.name = 'disconnect'
        r.static = False
        r.description = None
        r.objc_name = 'disconnect'
        r.args = []
        r.objc_args = []
        r.new_id = None
        return r

    def objc_name(name):
        if isinstance(name, Interface):
            name = name.name
        res = objc_case(name, first_capital=True)
        for prefix in 'wl', 'wp', 'xdg', 'zxdg':
            if res.lower().startswith(prefix):
                l = len(prefix)
                res = prefix.upper() + res[l:]
        return res

    def print_decl(self):
        if self.description:
            print_comment(self.description, multiline=True)
        print('@interface', self.objc_name(), '{')
        print('struct', self.name, '*rawHandle;')
        print('}')
        for request in self.requests:
            request.print_decl()
        for event in self.events:
            event.print_decl()
        print('@end')

class Request:
    def parse(node, interface):
        assert(node.tag == 'request')
        res = Request()
        res.name = node.attrib['name']
        res.static = False
        res.args = []
        for child in node:
            if child.tag == 'description':
                res.description = child.text
            if child.tag == 'arg':
                arg = Arg.parse(child)
                res.args.append(arg)
        # generate objc names and args
        if not res.name.startswith('get'):
            res.objc_name = objc_case(res.name)
        else:
            res.objc_name = objc_case(res.name[3:])
        if not res.args:
            res.new_id = None
            res.objc_args = []
            return res
        if res.args[0].type == 'new_id':
            res.new_id = res.args[0]
            res.args = res.args[1:]
        else:
            res.new_id = None
        res.objc_args = [arg.objcify() for arg in res.args]
        if res.args:
            a0n = objc_case(res.args[0].name, first_capital=True)
            if not res.objc_name.endswith(a0n):
                res.objc_name += 'With' + a0n
        return res

    def print_decl(self):
        if self.description:
            print_comment(self.description, multiline=True)
        return_type = 'void'
        if self.new_id is not None:
            return_type = Interface.objc_name(self.new_id.interface) + ' *'
        print('{} ({})'.format('+' if self.static else '-', return_type), end='')
        if not self.objc_args:
            print(' {};'.format(self.objc_name))
        else:
            print(end=' ')
            self.objc_args[0].print_decl(label=self.objc_name)
            for arg in self.objc_args[1:]:
                print(end=' ')
                arg.print_decl()
            print(';')

class Event:
    def parse(node, interface):
        assert(node.tag == 'event')
        res = Event()
        res.name = node.attrib['name']
        res.args = []
        for child in node:
            if child.tag == 'description':
                res.description = child.text
            if child.tag == 'arg':
                arg = Arg.parse(child)
                res.args.append(arg)
        return res

    def print_decl(self):
        if self.description:
            print_comment(self.description, multiline=True)
        name = objc_case('set_{}_handler'.format(self.name))
        args_decl = ', '.join(arg.objcify().cdecl() for arg in self.args)
        print('- (void) {}: (void (^)({})) handler;'.format(name, args_decl))

class Arg:
    def parse(node):
        assert(node.tag == 'arg')
        res = Arg()
        res.name = node.attrib['name']
        res.type = node.attrib['type']
        res.summary = node.attrib['summary']
        if 'interface' in node.attrib:
            res.interface = node.attrib['interface']
            res.allow_null = False
        if 'allow-null' in node.attrib:
            res.allow_null = node.attrib['allow-null'] == 'true'
        return res

    def objcify(self):
        res = Arg()
        res.name = objc_case(self.name)
        res.summary = self.summary
        if self.type == 'object':
            if hasattr(self, 'interface'):
                res.type = Interface.objc_name(self.interface) + ' *'
            else:
                res.type = 'id'
        elif self.type == 'string':
            res.type = 'NSString *'
        elif self.type == 'uint':
            res.type = 'uint32_t'
        else:
            # TODO: other types
            res.type = self.type
        return res

    def print_decl(self, label=None):
        if label is None:
            label = self.name
        print('{}: ({}) {}'.format(label, self.type, self.name), end='')

    def cdecl(self):
        return '{} {}'.format(self.type, self.name)

print_comment('Automatically generated by wl-objc bindings generator')
tree = ET.parse('/dev/stdin')
root = tree.getroot()
Protocol.parse(root).print_decl()
<|endoftext|>


<commit_before>import math
import random
import sys

import pygame
from pygame.locals import *
from noise import pnoise1, pnoise2, snoise2

BEIGE  = (200, 200, 100)
BLACK  = (  0,   0,   0)
BLUE   = (  0,   0, 200)
GREEN  = (  0, 255,   0)
RED    = (255,   0,   0)
WHITE  = (255, 255, 255)
CYAN = (  0, 255, 255)

def setup_screen(screen_size=(900, 900)):
    surf = pygame.display.set_mode(screen_size, RESIZABLE)
    pygame.display.set_caption('Pyland Gen 1.0')
    return surf

def gen_border():
    """
    Generate a border to apply to our island to build shoreline.

    Returns a list of (x, y) points of generated pnoise.
    """
    points = 360
    span = 8.0
    octaves = 8
    scale = 40
    base = random.randint(0, 500)
    border = []
    for i in range(points):
        x = float(i) * span / points
        y = pnoise1(x + base, octaves) * 1.5
        y += pnoise1(x + base, octaves + 4) * 5
        y *= scale
        border.append((i, y))
    return border

def scale_to_polar(border, radius=200):
    """ Apply our border to our island. """
    radii = (radius + y for _, y in border)  # Adjust radii
    angles = (x * math.pi / 180.0 for x, _ in border)  # Convert to radians
    return zip(radii, angles)

def polar_to_rectangular(polar_coords):
    return [(r * math.cos(theta) + 450, r * math.sin(theta) + 450) \
            for r, theta in polar_coords]  # To rectangular coords

def render_island(surf, coords, radius):
    """ Renders an aaline of a series of points. """
    pygame.draw.circle(surf, RED, (450, 450), radius, 1)  # Original centre
    pygame.draw.aalines(surf, BEIGE, True, coords, False)  # Island shore
    for point in coords:  # Data points
        pygame.draw.circle(surf, GREEN, (int(point[0]), int(point[1])), 1)

def render_border(surf, points):
    """ Renders an aaline of a series of points. """
    point_list = [(x + 50, -y + 800) for x, y in points]  # Up is -ve
    pygame.draw.line(surf, CYAN, (50, 800), (410, 800), 1)  # x-axis
    pygame.draw.line(surf, CYAN, (50, 800), (50, 700), 1)  # y-axis

    pygame.draw.lines(surf, WHITE, False, point_list, 1)
    for x, y in point_list:  # points
        pygame.draw.circle(surf, RED, (int(x), int(y)), 1)

def flood_fill(surf):
    screen_size = surf.get_size()
    center_x, center_y = screen_size[0]/2, screen_size[1]/2
    start_color = surf.get_at((center_x, center_y))
    seen = []
    WHITE = (255, 255, 255, 255)
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        x, y = center_x + dx, center_y + dy
        surf.set_at((x, y), WHITE)
        if surf.get_at((x, y)) == start_color:
            pass

def get_input():
    """ Wait for input. """
    for event in pygame.event.get():
        if event.type == QUIT:
            return 'quit'
        elif event.type == KEYDOWN:
            if event.key in (K_q, K_ESCAPE):
                return 'quit'
            elif event.key == K_SPACE:
                return 'regen'

def main():
    print('Pyland Gen 1.0')
    pygame.init()
    clock = pygame.time.Clock()
    surface = setup_screen()

    radius = 200
    result = 'regen'
    while True:
        clock.tick(10)

        if result == 'quit':
            pygame.quit()
            sys.exit()
        elif result == 'regen':
            surface.fill(BLACK)
            border = gen_border()  # Generate random noise
            render_border(surface, border)  # Draw it

            polar_coords = scale_to_polar(border, radius=radius)  # Wrap it around a circle
            rect_coords = polar_to_rectangular(polar_coords)  # Conver to (x, y)
            render_island(surface, rect_coords, radius)  # Graph island

            flood_fill(surface)  # Fill Island w/ color
            pygame.display.flip()

        result = get_input()

if __name__ == '__main__':
    main()

<commit_msg>Add args to gen_border()<commit_after>import math
import random
import sys

import pygame
from pygame.locals import *
from noise import pnoise1, pnoise2, snoise2

BEIGE  = (200, 200, 100)
BLACK  = (  0,   0,   0)
BLUE   = (  0,   0, 200)
GREEN  = (  0, 255,   0)
RED    = (255,   0,   0)
WHITE  = (255, 255, 255)
CYAN = (  0, 255, 255)

def setup_screen(screen_size=(900, 900)):
    surf = pygame.display.set_mode(screen_size, RESIZABLE)
    pygame.display.set_caption('Pyland Gen 1.0')
    return surf

def gen_border(span=8.0, octaves=8, scale=40):
    """
    Generate a border to apply to our island to build shoreline.

    Returns a list of (x, y) points of generated pnoise.
    """
    points = 360
    base = random.randint(0, 500)
    border = []
    for i in range(points):
        x = float(i) * span / points
        y = pnoise1(x + base, octaves) * 1.5
        y += pnoise1(x + base, octaves + 4) * 4
        y *= scale
        border.append((i, y))
    return border

def scale_to_polar(border, radius=200):
    """ Apply our border to our island. """
    radii = (radius + y for _, y in border)  # Adjust radii
    angles = (x * math.pi / 180.0 for x, _ in border)  # Convert to radians
    return zip(radii, angles)

def polar_to_rectangular(polar_coords):
    return [(r * math.cos(theta) + 450, r * math.sin(theta) + 450) \
            for r, theta in polar_coords]  # To rectangular coords

def render_island(surf, coords, radius):
    """ Renders an aaline of a series of points. """
    pygame.draw.circle(surf, RED, (450, 450), radius, 1)  # Original centre
    pygame.draw.aalines(surf, BEIGE, True, coords, False)  # Island shore
    for point in coords:  # Data points
        pygame.draw.circle(surf, GREEN, (int(point[0]), int(point[1])), 1)

def render_border(surf, points):
    """ Renders an aaline of a series of points. """
    point_list = [(x + 50, -y + 800) for x, y in points]  # Up is -ve
    pygame.draw.line(surf, CYAN, (50, 800), (410, 800), 1)  # x-axis
    pygame.draw.line(surf, CYAN, (50, 800), (50, 700), 1)  # y-axis

    pygame.draw.lines(surf, WHITE, False, point_list, 1)
    for x, y in point_list:  # points
        pygame.draw.circle(surf, RED, (int(x), int(y)), 1)

def flood_fill(surf):
    screen_size = surf.get_size()
    center_x, center_y = screen_size[0]/2, screen_size[1]/2
    start_color = surf.get_at((center_x, center_y))
    seen = []
    WHITE = (255, 255, 255, 255)
    for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
        x, y = center_x + dx, center_y + dy
        surf.set_at((x, y), WHITE)
        if surf.get_at((x, y)) == start_color:
            pass

def get_input():
    """ Wait for input. """
    for event in pygame.event.get():
        if event.type == QUIT:
            return 'quit'
        elif event.type == KEYDOWN:
            if event.key in (K_q, K_ESCAPE):
                return 'quit'
            elif event.key == K_SPACE:
                return 'regen'

def main():
    print('Pyland Gen 1.0')
    pygame.init()
    clock = pygame.time.Clock()
    surface = setup_screen()

    radius = 200
    result = 'regen'
    while True:
        clock.tick(10)

        if result == 'quit':
            pygame.quit()
            sys.exit()
        elif result == 'regen':
            surface.fill(BLACK)
            border = gen_border(span=8.0, octaves=8, scale=40)  # Generate random noise
            render_border(surface, border)  # Draw it

            polar_coords = scale_to_polar(border, radius=radius)  # Wrap it around a circle
            rect_coords = polar_to_rectangular(polar_coords)  # Conver to (x, y)
            render_island(surface, rect_coords, radius)  # Graph island

            flood_fill(surface)  # Fill Island w/ color
            pygame.display.flip()

        result = get_input()

if __name__ == '__main__':
    main()

<|endoftext|>