<commit_before>import collections
import subprocess

from . import protocols
from . import transports
from .coroutines import coroutine
from .log import logger

class BaseSubprocessTransport(transports.SubprocessTransport):

    def __init__(self, loop, protocol, args, shell,
                 stdin, stdout, stderr, bufsize,
                 extra=None, **kwargs):
        super().__init__(extra)
        self._protocol = protocol
        self._loop = loop
        self._pid = None

        self._pipes = {}
        if stdin == subprocess.PIPE:
            self._pipes[0] = None
        if stdout == subprocess.PIPE:
            self._pipes[1] = None
        if stderr == subprocess.PIPE:
            self._pipes[2] = None
        self._pending_calls = collections.deque()
        self._finished = False
        self._returncode = None
        self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,
                    stderr=stderr, bufsize=bufsize, **kwargs)
        self._pid = self._proc.pid
        self._extra['subprocess'] = self._proc
        if self._loop.get_debug():
            if isinstance(args, (bytes, str)):
                program = args
            else:
                program = args[0]
            logger.debug('process %r created: pid %s',
                         program, self._pid)

    def __repr__(self):
        info = [self.__class__.__name__, 'pid=%s' % self._pid]
        if self._returncode is not None:
            info.append('returncode=%s' % self._returncode)

        stdin = self._pipes.get(0)
        if stdin is not None:
            info.append('stdin=%s' % stdin.pipe)

        stdout = self._pipes.get(1)
        stderr = self._pipes.get(2)
        if stdout is not None and stderr is stdout:
            info.append('stdout=stderr=%s' % stdout.pipe)
        else:
            if stdout is not None:
                info.append('stdout=%s' % stdout.pipe)
            if stderr is not None:
                info.append('stderr=%s' % stderr.pipe)

        return '<%s>' % ' '.join(info)

    def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
        raise NotImplementedError

    def _make_write_subprocess_pipe_proto(self, fd):
        raise NotImplementedError

    def _make_read_subprocess_pipe_proto(self, fd):
        raise NotImplementedError

    def close(self):
        for proto in self._pipes.values():
            proto.pipe.close()
        if self._returncode is None:
            self.terminate()

    def get_pid(self):
        return self._pid

    def get_returncode(self):
        return self._returncode

    def get_pipe_transport(self, fd):
        if fd in self._pipes:
            return self._pipes[fd].pipe
        else:
            return None

    def send_signal(self, signal):
        self._proc.send_signal(signal)

    def terminate(self):
        self._proc.terminate()

    def kill(self):
        self._proc.kill()

    @coroutine
    def _post_init(self):
        proc = self._proc
        loop = self._loop
        if proc.stdin is not None:
            _, pipe = yield from loop.connect_write_pipe(
                lambda: WriteSubprocessPipeProto(self, 0),
                proc.stdin)
            self._pipes[0] = pipe
        if proc.stdout is not None:
            _, pipe = yield from loop.connect_read_pipe(
                lambda: ReadSubprocessPipeProto(self, 1),
                proc.stdout)
            self._pipes[1] = pipe
        if proc.stderr is not None:
            _, pipe = yield from loop.connect_read_pipe(
                lambda: ReadSubprocessPipeProto(self, 2),
                proc.stderr)
            self._pipes[2] = pipe

        assert self._pending_calls is not None

        self._loop.call_soon(self._protocol.connection_made, self)
        for callback, data in self._pending_calls:
            self._loop.call_soon(callback, *data)
        self._pending_calls = None

    def _call(self, cb, *data):
        if self._pending_calls is not None:
            self._pending_calls.append((cb, data))
        else:
            self._loop.call_soon(cb, *data)

    def _pipe_connection_lost(self, fd, exc):
        self._call(self._protocol.pipe_connection_lost, fd, exc)
        self._try_finish()

    def _pipe_data_received(self, fd, data):
        self._call(self._protocol.pipe_data_received, fd, data)

    def _process_exited(self, returncode):
        assert returncode is not None, returncode
        assert self._returncode is None, self._returncode
        if self._loop.get_debug():
            logger.info('%r exited with return code %r',
                        self, returncode)
        self._returncode = returncode
        self._call(self._protocol.process_exited)
        self._try_finish()

    def _try_finish(self):
        assert not self._finished
        if self._returncode is None:
            return
        if all(p is not None and p.disconnected
               for p in self._pipes.values()):
            self._finished = True
            self._loop.call_soon(self._call_connection_lost, None)

    def _call_connection_lost(self, exc):
        try:
            self._protocol.connection_lost(exc)
        finally:
            self._proc = None
            self._protocol = None
            self._loop = None

class WriteSubprocessPipeProto(protocols.BaseProtocol):

    def __init__(self, proc, fd):
        self.proc = proc
        self.fd = fd
        self.pipe = None
        self.disconnected = False

    def connection_made(self, transport):
        self.pipe = transport

    def __repr__(self):
        return ('<%s fd=%s pipe=%r>'
                % (self.__class__.__name__, self.fd, self.pipe))

    def connection_lost(self, exc):
        self.disconnected = True
        self.proc._pipe_connection_lost(self.fd, exc)

    def pause_writing(self):
        self.proc._protocol.pause_writing()

    def resume_writing(self):
        self.proc._protocol.resume_writing()

class ReadSubprocessPipeProto(WriteSubprocessPipeProto,
                              protocols.Protocol):

    def data_received(self, data):
        self.proc._pipe_data_received(self.fd, data)
<commit_msg>Fix a race condition in BaseSubprocessTransport._try_finish()<commit_after>import collections
import subprocess

from . import protocols
from . import transports
from .coroutines import coroutine
from .log import logger

class BaseSubprocessTransport(transports.SubprocessTransport):

    def __init__(self, loop, protocol, args, shell,
                 stdin, stdout, stderr, bufsize,
                 extra=None, **kwargs):
        super().__init__(extra)
        self._protocol = protocol
        self._loop = loop
        self._pid = None

        self._pipes = {}
        if stdin == subprocess.PIPE:
            self._pipes[0] = None
        if stdout == subprocess.PIPE:
            self._pipes[1] = None
        if stderr == subprocess.PIPE:
            self._pipes[2] = None
        self._pending_calls = collections.deque()
        self._finished = False
        self._returncode = None
        self._start(args=args, shell=shell, stdin=stdin, stdout=stdout,
                    stderr=stderr, bufsize=bufsize, **kwargs)
        self._pid = self._proc.pid
        self._extra['subprocess'] = self._proc
        if self._loop.get_debug():
            if isinstance(args, (bytes, str)):
                program = args
            else:
                program = args[0]
            logger.debug('process %r created: pid %s',
                         program, self._pid)

    def __repr__(self):
        info = [self.__class__.__name__, 'pid=%s' % self._pid]
        if self._returncode is not None:
            info.append('returncode=%s' % self._returncode)

        stdin = self._pipes.get(0)
        if stdin is not None:
            info.append('stdin=%s' % stdin.pipe)

        stdout = self._pipes.get(1)
        stderr = self._pipes.get(2)
        if stdout is not None and stderr is stdout:
            info.append('stdout=stderr=%s' % stdout.pipe)
        else:
            if stdout is not None:
                info.append('stdout=%s' % stdout.pipe)
            if stderr is not None:
                info.append('stderr=%s' % stderr.pipe)

        return '<%s>' % ' '.join(info)

    def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
        raise NotImplementedError

    def _make_write_subprocess_pipe_proto(self, fd):
        raise NotImplementedError

    def _make_read_subprocess_pipe_proto(self, fd):
        raise NotImplementedError

    def close(self):
        for proto in self._pipes.values():
            proto.pipe.close()
        if self._returncode is None:
            self.terminate()

    def get_pid(self):
        return self._pid

    def get_returncode(self):
        return self._returncode

    def get_pipe_transport(self, fd):
        if fd in self._pipes:
            return self._pipes[fd].pipe
        else:
            return None

    def send_signal(self, signal):
        self._proc.send_signal(signal)

    def terminate(self):
        self._proc.terminate()

    def kill(self):
        self._proc.kill()

    @coroutine
    def _post_init(self):
        proc = self._proc
        loop = self._loop
        if proc.stdin is not None:
            _, pipe = yield from loop.connect_write_pipe(
                lambda: WriteSubprocessPipeProto(self, 0),
                proc.stdin)
            self._pipes[0] = pipe
        if proc.stdout is not None:
            _, pipe = yield from loop.connect_read_pipe(
                lambda: ReadSubprocessPipeProto(self, 1),
                proc.stdout)
            self._pipes[1] = pipe
        if proc.stderr is not None:
            _, pipe = yield from loop.connect_read_pipe(
                lambda: ReadSubprocessPipeProto(self, 2),
                proc.stderr)
            self._pipes[2] = pipe

        assert self._pending_calls is not None

        self._loop.call_soon(self._protocol.connection_made, self)
        for callback, data in self._pending_calls:
            self._loop.call_soon(callback, *data)
        self._pending_calls = None

    def _call(self, cb, *data):
        if self._pending_calls is not None:
            self._pending_calls.append((cb, data))
        else:
            self._loop.call_soon(cb, *data)

    def _pipe_connection_lost(self, fd, exc):
        self._call(self._protocol.pipe_connection_lost, fd, exc)
        self._try_finish()

    def _pipe_data_received(self, fd, data):
        self._call(self._protocol.pipe_data_received, fd, data)

    def _process_exited(self, returncode):
        assert returncode is not None, returncode
        assert self._returncode is None, self._returncode
        if self._loop.get_debug():
            logger.info('%r exited with return code %r',
                        self, returncode)
        self._returncode = returncode
        self._call(self._protocol.process_exited)
        self._try_finish()

    def _try_finish(self):
        assert not self._finished
        if self._returncode is None:
            return
        if all(p is not None and p.disconnected
               for p in self._pipes.values()):
            self._finished = True
            self._call(self._call_connection_lost, None)

    def _call_connection_lost(self, exc):
        try:
            self._protocol.connection_lost(exc)
        finally:
            self._proc = None
            self._protocol = None
            self._loop = None

class WriteSubprocessPipeProto(protocols.BaseProtocol):

    def __init__(self, proc, fd):
        self.proc = proc
        self.fd = fd
        self.pipe = None
        self.disconnected = False

    def connection_made(self, transport):
        self.pipe = transport

    def __repr__(self):
        return ('<%s fd=%s pipe=%r>'
                % (self.__class__.__name__, self.fd, self.pipe))

    def connection_lost(self, exc):
        self.disconnected = True
        self.proc._pipe_connection_lost(self.fd, exc)

    def pause_writing(self):
        self.proc._protocol.pause_writing()

    def resume_writing(self):
        self.proc._protocol.resume_writing()

class ReadSubprocessPipeProto(WriteSubprocessPipeProto,
                              protocols.Protocol):

    def data_received(self, data):
        self.proc._pipe_data_received(self.fd, data)
<|endoftext|>


<commit_before>"""
This module tests the auth_mac package
"""

from django.test import TestCase
from django.test.client import Client
from django.contrib.auth.models import User
from auth_mac.models import Credentials
import datetime
import hmac, hashlib, base64
import unittest
from auth_mac.tools import Signature

class Test_NoAuthorisation(TestCase):
  urls = "auth_mac.tests.urls"
  def test_access_restricted(self):
    "Tests accessing restricted functions without authentication"
    c = Client()
    response = c.get("/unattainable_resource")
    self.assertEqual(response.status_code, 401)
    self.assertEqual(response['WWW-Authenticate'], "MAC")

    response = c.get("/protected_resource")
    self.assertEqual(response.status_code, 401)
    self.assertEqual(response['WWW-Authenticate'], "MAC")

class Test_Signatures(TestCase):
  urls = "auth_mac.tests.urls"

  def setUp(self):
    # Create a user to authorise with
    self.user = User.objects.create_user("testuser", "test@test.com")
    self.user.save()
    # And, create a MAC access credentials for this user
    self.rfc_credentials = Credentials(user=self.user, identifier="h480djs93hd8", key="489dks293j39")

  @unittest.expectedFailure
  def test_credential_object(self):
    """Test the credentials object using the IETF Draft values.
    See: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 """

    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.sign_request(uri="/resource/1?b=1&a=2", timestamp="1336363200", nonce="dj83hs9s")
    # Validate that we calculated the base string correctly
    example_bs = "1336363200\ndj83hs9s\nGET\n/resource/1?b=1&a=2\nexample.com\n80\n\n"
    self.assertEqual(ms.base_string, example_bs)
    self.assertEqual(ms.signature, "bhCQXTVyfj5cmA9uKkPFx1zeOXM=")

  def test_possible_erroneous_credentials(self):
    "Test that we don't stray from our self-calculated output"
    # Same as above test, but with a different signature
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.sign_request(uri="/resource/1?b=1&a=2", timestamp="1336363200", nonce="dj83hs9s")
    example_bs = "1336363200\ndj83hs9s\nGET\n/resource/1?b=1&a=2\nexample.com\n80\n\n"
    self.assertEqual(ms.base_string, example_bs)
    self.assertEqual(ms.signature, "6T3zZzy2Emppni6bzL7kdRxUWL4=")

  def test_creating_authheader(self):
    "Test the creation of the auth header"
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.update(uri="/resource/1?b=1&a=2", timestamp="1336363200", nonce="dj83hs9s")
    expected_authheader = 'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200"'
    header = ms.get_header()
    self.assertEqual(expected_authheader, header)

class TestRequest(TestCase):
  "Test the sending of requests and validation against credentials"
  urls = "auth_mac.tests.urls"

  def setUp(self):
    # Create a user to authorise with
    self.user = User.objects.create_user("testuser", "test@test.com")
    self.user.save()
    # And, create a MAC access credentials for this user
    self.rfc_credentials = Credentials(user=self.user, identifier="h480djs93hd8", key="489dks293j39")
    self.rfc_credentials.save()

  def test_workingcredentials(self):
    "Tests that we can read a resource with working credentials"
    c = Client()
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.update(uri="/protected_resource")
    c.get("/protected_resource", HTTP_AUTHORIZATION=ms.get_header())

  def test_nonmac_credentials(self):
    "Tests that sending a non-mac authentication fails"
    c = Client()
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.update(uri="/protected_resource")
    header = ms.get_header()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION="Basic " + header[4:])
    self.assertEqual(response.status_code, 401)
    # Make sure we don't have an error string
    self.assertEqual(response['WWW-Authenticate'], "MAC")

  def test_refuse_repeats(self):
    "Tests that repeating auth information fails auth"
    c = Client()
    validheader = 'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200", ext="fsf"'
    for key in ["nonce", "mac", "id", "ts", "ext"]:
      keystr = validheader + ', {0}="rextra"'.format(key)
      response = c.get("/protected_resource", HTTP_AUTHORIZATION=keystr)
      self.assertEqual(response.status_code, 401)
      self.assertIn("Duplicate", response["WWW-Authenticate"])

  def test_incomplete_information(self):
    "Test that giving incomplete mac information fails"
    c = Client()
    keystrs = [ 'MAC mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200"',
                'MAC nonce="dj83hs9s", id="h480djs93hd8", ts="1336363200"',
                'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", ts="1336363200"',
                'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8"']
    for keystr in keystrs:
      response = c.get("/protected_resource", HTTP_AUTHORIZATION=keystr)
      self.assertEqual(response.status_code, 401)
      self.assertIn("Missing", response["WWW-Authenticate"])

  def test_invalid_credentials(self):
    "Test using credentials that are invalid, but signed correctly"
    c = Client()
    class CredShell(object):
      key = "NOTAVALIDKEY"
      identifier = "NOTANIDENTIFIER"
    bad = CredShell()
    # validheader = 'MAC nonce="dj83hss9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200", ext="fsf"'
    s = Signature(bad, method="GET", port=80, host="example.com", uri="protected_resource")
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=s.get_header())
    self.assertEqual(response.status_code, 401)
    self.assertIn("Invalid", response["WWW-Authenticate"])

  def test_expired_credentials(self):
    "Test using credentials that have expired"
    expired = Credentials(user=self.user, expiry=datetime.datetime.min, identifier="hdjs93hd8", key="489dks2939")
    expired.save()
    s = Signature(expired, method="GET", port=80, host="example.com", uri="protected_resource")
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=s.get_header())
    self.assertEqual(response.status_code, 401)
    self.assertIn("EXPIRED".upper(), response["WWW-Authenticate"].upper())

  def test_header_without_host(self):
    "Tests that signature does not proceed without a valid host value"
    validheader = 'MAC nonce="djd3hs9s", mac="INVALIDSIGNATURE=", id="h480djs93hd8", ts="1336363200"'
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=validheader)
    self.assertEqual(response.status_code, 401)
    self.assertIn("Host", response["WWW-Authenticate"])

  def test_invalid_signature(self):
    "Test using a valid credential with an invalid signature"
    validheader = 'MAC nonce="djd3hs9s", mac="INVALIDSIGNATURE=", id="h480djs93hd8", ts="1336363200"'
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=validheader, HTTP_HOST="example.com")
    self.assertEqual(response.status_code, 401)
    self.assertIn("SIGNATURE".upper(), response["WWW-Authenticate"].upper())

  def test_valid_signature(self):
    "Test using a valid credential with a valid signature"
    s = Signature(self.rfc_credentials, method="GET", port=80, host="example.com", uri="/protected_resource")
    header = s.get_header()
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=header, HTTP_HOST="example.com")
    self.assertEqual(response.status_code, 200)
    self.assertEqual(response.content, "testuser")

class TestUsers(TestCase):
  urls = "auth_mac.tests.urls"

  def setUp(self):
    # Create a user to authorise with
    self.user = User.objects.create_user("testuser", "test@test.com")
    self.user.save()
    # And, create a MAC access credentials for this user
    self.rfc_credentials = Credentials(user=self.user, identifier="h480djs93hd8", key="489dks293j39")
    self.rfc_credentials.save()

  def test_anonymousaccess(self):
    "Test the access of an optionally anonymous resource"
    c = Client()
    response = c.get("/optional_resource")
    self.assertEqual(response.status_code, 200)
    self.assertEqual(response.content, "AnonymousUser")

  def test_authaccess(self):
    "Test optional authorisation access with user credentials"
    s = Signature(self.rfc_credentials, method="GET", port=80, host="example.com", uri="/optional_resource")
    header = s.get_header()
    c = Client()
    response = c.get("/optional_resource", HTTP_AUTHORIZATION=header, HTTP_HOST="example.com")
    self.assertEqual(response.status_code, 200)
    self.assertEqual(response.content, "testuser")

<commit_msg>Write a test of sending the same nonce multiple times<commit_after>"""
This module tests the auth_mac package
"""

from django.test import TestCase
from django.test.client import Client
from django.contrib.auth.models import User
from auth_mac.models import Credentials
import datetime
import hmac, hashlib, base64
import unittest
from auth_mac.tools import Signature

class Test_NoAuthorisation(TestCase):
  urls = "auth_mac.tests.urls"
  def test_access_restricted(self):
    "Tests accessing restricted functions without authentication"
    c = Client()
    response = c.get("/unattainable_resource")
    self.assertEqual(response.status_code, 401)
    self.assertEqual(response['WWW-Authenticate'], "MAC")

    response = c.get("/protected_resource")
    self.assertEqual(response.status_code, 401)
    self.assertEqual(response['WWW-Authenticate'], "MAC")

class Test_Signatures(TestCase):
  urls = "auth_mac.tests.urls"

  def setUp(self):
    # Create a user to authorise with
    self.user = User.objects.create_user("testuser", "test@test.com")
    self.user.save()
    # And, create a MAC access credentials for this user
    self.rfc_credentials = Credentials(user=self.user, identifier="h480djs93hd8", key="489dks293j39")

  @unittest.expectedFailure
  def test_credential_object(self):
    """Test the credentials object using the IETF Draft values.
    See: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 """

    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.sign_request(uri="/resource/1?b=1&a=2", timestamp="1336363200", nonce="dj83hs9s")
    # Validate that we calculated the base string correctly
    example_bs = "1336363200\ndj83hs9s\nGET\n/resource/1?b=1&a=2\nexample.com\n80\n\n"
    self.assertEqual(ms.base_string, example_bs)
    self.assertEqual(ms.signature, "bhCQXTVyfj5cmA9uKkPFx1zeOXM=")

  def test_possible_erroneous_credentials(self):
    "Test that we don't stray from our self-calculated output"
    # Same as above test, but with a different signature
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.sign_request(uri="/resource/1?b=1&a=2", timestamp="1336363200", nonce="dj83hs9s")
    example_bs = "1336363200\ndj83hs9s\nGET\n/resource/1?b=1&a=2\nexample.com\n80\n\n"
    self.assertEqual(ms.base_string, example_bs)
    self.assertEqual(ms.signature, "6T3zZzy2Emppni6bzL7kdRxUWL4=")

  def test_creating_authheader(self):
    "Test the creation of the auth header"
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.update(uri="/resource/1?b=1&a=2", timestamp="1336363200", nonce="dj83hs9s")
    expected_authheader = 'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200"'
    header = ms.get_header()
    self.assertEqual(expected_authheader, header)

class TestRequest(TestCase):
  "Test the sending of requests and validation against credentials"
  urls = "auth_mac.tests.urls"

  def setUp(self):
    # Create a user to authorise with
    self.user = User.objects.create_user("testuser", "test@test.com")
    self.user.save()
    # And, create a MAC access credentials for this user
    self.rfc_credentials = Credentials(user=self.user, identifier="h480djs93hd8", key="489dks293j39")
    self.rfc_credentials.save()

  def test_workingcredentials(self):
    "Tests that we can read a resource with working credentials"
    c = Client()
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.update(uri="/protected_resource")
    c.get("/protected_resource", HTTP_AUTHORIZATION=ms.get_header())

  def test_nonmac_credentials(self):
    "Tests that sending a non-mac authentication fails"
    c = Client()
    ms = Signature(self.rfc_credentials, host="example.com", port=80, method="GET")
    ms.update(uri="/protected_resource")
    header = ms.get_header()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION="Basic " + header[4:])
    self.assertEqual(response.status_code, 401)
    # Make sure we don't have an error string
    self.assertEqual(response['WWW-Authenticate'], "MAC")

  def test_refuse_repeats(self):
    "Tests that repeating auth information fails auth"
    c = Client()
    validheader = 'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200", ext="fsf"'
    for key in ["nonce", "mac", "id", "ts", "ext"]:
      keystr = validheader + ', {0}="rextra"'.format(key)
      response = c.get("/protected_resource", HTTP_AUTHORIZATION=keystr)
      self.assertEqual(response.status_code, 401)
      self.assertIn("Duplicate", response["WWW-Authenticate"])

  def test_incomplete_information(self):
    "Test that giving incomplete mac information fails"
    c = Client()
    keystrs = [ 'MAC mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200"',
                'MAC nonce="dj83hs9s", id="h480djs93hd8", ts="1336363200"',
                'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", ts="1336363200"',
                'MAC nonce="dj83hs9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8"']
    for keystr in keystrs:
      response = c.get("/protected_resource", HTTP_AUTHORIZATION=keystr)
      self.assertEqual(response.status_code, 401)
      self.assertIn("Missing", response["WWW-Authenticate"])

  def test_invalid_credentials(self):
    "Test using credentials that are invalid, but signed correctly"
    c = Client()
    class CredShell(object):
      key = "NOTAVALIDKEY"
      identifier = "NOTANIDENTIFIER"
    bad = CredShell()
    # validheader = 'MAC nonce="dj83hss9s", mac="6T3zZzy2Emppni6bzL7kdRxUWL4=", id="h480djs93hd8", ts="1336363200", ext="fsf"'
    s = Signature(bad, method="GET", port=80, host="example.com", uri="protected_resource")
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=s.get_header())
    self.assertEqual(response.status_code, 401)
    self.assertIn("Invalid", response["WWW-Authenticate"])

  def test_expired_credentials(self):
    "Test using credentials that have expired"
    expired = Credentials(user=self.user, expiry=datetime.datetime.min, identifier="hdjs93hd8", key="489dks2939")
    expired.save()
    s = Signature(expired, method="GET", port=80, host="example.com", uri="protected_resource")
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=s.get_header())
    self.assertEqual(response.status_code, 401)
    self.assertIn("EXPIRED".upper(), response["WWW-Authenticate"].upper())

  def test_header_without_host(self):
    "Tests that signature does not proceed without a valid host value"
    validheader = 'MAC nonce="djd3hs9s", mac="INVALIDSIGNATURE=", id="h480djs93hd8", ts="1336363200"'
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=validheader)
    self.assertEqual(response.status_code, 401)
    self.assertIn("Host", response["WWW-Authenticate"])

  def test_invalid_signature(self):
    "Test using a valid credential with an invalid signature"
    validheader = 'MAC nonce="djd3hs9s", mac="INVALIDSIGNATURE=", id="h480djs93hd8", ts="1336363200"'
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=validheader, HTTP_HOST="example.com")
    self.assertEqual(response.status_code, 401)
    self.assertIn("SIGNATURE".upper(), response["WWW-Authenticate"].upper())

  def test_valid_signature(self):
    "Test using a valid credential with a valid signature"
    s = Signature(self.rfc_credentials, method="GET", port=80, host="example.com", uri="/protected_resource")
    header = s.get_header()
    c = Client()
    response = c.get("/protected_resource", HTTP_AUTHORIZATION=header, HTTP_HOST="example.com")
    self.assertEqual(response.status_code, 200)
    self.assertEqual(response.content, "testuser")

class TestUsers(TestCase):
  urls = "auth_mac.tests.urls"

  def setUp(self):
    # Create a user to authorise with
    self.user = User.objects.create_user("testuser", "test@test.com")
    self.user.save()
    # And, create a MAC access credentials for this user
    self.rfc_credentials = Credentials(user=self.user, identifier="h480djs93hd8", key="489dks293j39")
    self.rfc_credentials.save()

  def test_anonymousaccess(self):
    "Test the access of an optionally anonymous resource"
    c = Client()
    response = c.get("/optional_resource")
    self.assertEqual(response.status_code, 200)
    self.assertEqual(response.content, "AnonymousUser")

  def test_authaccess(self):
    "Test optional authorisation access with user credentials"
    s = Signature(self.rfc_credentials, method="GET", port=80, host="example.com", uri="/optional_resource")
    header = s.get_header()
    c = Client()
    response = c.get("/optional_resource", HTTP_AUTHORIZATION=header, HTTP_HOST="example.com")
    self.assertEqual(response.status_code, 200)
    self.assertEqual(response.content, "testuser")

class TestNonce(TestCase):
  "Tests the nonce-evasion procedures"
  urls = "auth_mac.tests.urls"

  def setUp(self):
    # Create a user to authorise with
    self.user = User.objects.create_user("testuser", "test@test.com")
    self.user.save()
    # And, create a MAC access credentials for this user
    self.rfc_credentials = Credentials(user=self.user, identifier="h480djs93hd8", key="489dks293j39")
    self.rfc_credentials.save()
    self.signature = Signature(self.rfc_credentials, method="GET", port=80, host="example.com", uri="/protected_resource")

  def test_sequential(self):
    "Test sending the same nonce and timestamp through"
    timestamp = datetime.datetime.utcnow()-datetime.datetime(1970,1,1)
    timestamp = timestamp.days * 24*3600 + timestamp.seconds

    c = Client()
    self.signature.update(nonce="A_NONCE", timestamp=timestamp)
    response = c.get("/protected_resource",
                    HTTP_AUTHORIZATION=self.signature.get_header(),
                    HTTP_HOST="example.com")

    self.assertEqual(response.status_code, 200)
    response = c.get("/protected_resource",
                    HTTP_AUTHORIZATION=self.signature.get_header(),
                    HTTP_HOST="example.com")
    self.assertEqual(response.status_code, 401)
    self.assertIn("NONCE".upper(), response["WWW-Authenticate"].upper())<|endoftext|>


<commit_before>from aux.protocol.connection import TLS_TCPConnection
from urlparse import urlparse, urlunparse

class HTTPSConnection(object):

    __is_persistent = False

    def __init__(self, https_url, timeout=60):
        self.url = urlparse(https_url)
        if not self.url.port:
            l = list(self.url)
            l[1] = l[1] + ":443"
            self.url = urlparse(urlunparse(l))
        self.__conn = TLS_TCPConnection(self.url.hostname, self.url.port, timeout=timeout)
        self.__conn.connect()

    def is_persistent(self):
        return self.__is_persistent

    def send_request(self, request):
        request.target = self.url.hostname
        self.__conn.send(str(request))
        return self.__conn.recv()
<commit_msg>removing https.py file cleanup<commit_after><|endoftext|>


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

"""
This simple script accepts 2 files outputted by the zakopane checksummer
and compares them, printing a list of files which have changed.

New files and deleted files are ignored.
"""

import sys

ZF_DB_HEADER_LINES = 3

def process_line(zf_line, dictified):
    """Dictify a single nonheader line from the zakopane db."""
    zf_kv = zf_line.strip()

    (checksum_, fname_) = zf_kv.split(maxsplit=1)
    (checksum, fname) = (checksum_.strip(), fname_.strip())
    dictified[fname] = checksum

def dictify_zf(fname):
    """Given path ``fname,'' dictify as zakopane db."""
    dictified = dict()
    in_header = ZF_DB_HEADER_LINES

    with open(fname, "r") as zf_fp:
        for line in zf_fp:
            if in_header:
                in_header -= 1
                continue
            process_line(line, dictified)

    return dictified

def print_diff(dba, dbb):
    """Given 2 dictified zakopane dbs, print their difference."""
    diff = [key for (key, val) in dba.items()
        if key in dbb and dbb[key] != val]

    diff.sort()
    for fname in diff:
        print(fname)

def main(*args):
    (fname_a, fname_b) = args[:2]
    zf_dba = dictify_zf(fname_a)
    zf_dbb = dictify_zf(fname_b)
    print_diff(zf_dba, zf_dbb)
    return 0

if __name__ == "__main__":
    sys.exit(main(*sys.argv[1:]))
<commit_msg>Erase cmp-zakopane.py<commit_after><|endoftext|>


<commit_before># -*- coding: utf-8 -*-

__version__ = '3.3.0.rc3'

default_app_config = 'cms.apps.CMSConfig'
<commit_msg>Bump to 3.3.0.rc4<commit_after># -*- coding: utf-8 -*-

__version__ = '3.3.0.rc4'

default_app_config = 'cms.apps.CMSConfig'
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
__version__ = '2.3.4'

# patch settings
try:
    from django.conf import settings
    if 'cms' in settings.INSTALLED_APPS:
        from conf import patch_settings
        patch_settings()
except ImportError: # pragma: no cover
    """
    This exception means that either the application is being built, or is
    otherwise installed improperly. Both make running patch_settings
    irrelevant.
    """
    pass

<commit_msg>2.3.5 release<commit_after># -*- coding: utf-8 -*-
__version__ = '2.3.5'

# patch settings
try:
    from django.conf import settings
    if 'cms' in settings.INSTALLED_APPS:
        from conf import patch_settings
        patch_settings()
except ImportError: # pragma: no cover
    """
    This exception means that either the application is being built, or is
    otherwise installed improperly. Both make running patch_settings
    irrelevant.
    """
    pass

<|endoftext|>


<commit_before>from axelrod import Player

class MetaPlayer(Player):
    """A generic player that has its own team of players."""

    team = []
    behaviour = {
        'memory_depth': float('inf')  # Long memory
    }

    def __init__(self):

        Player.__init__(self)

        # Make sure we don't use any meta players to avoid infinite recursion.
        self.team = [t for t in self.team if not issubclass(t, MetaPlayer)]
        self.nteam = len(self.team)

        # Initiate all the player in out team.
        self.team = [t() for t in self.team]

        # If the team will have stochastic players, this meta is also stochastic.
        self.stochastic = any([t.stochastic for t in self.team])

    def strategy(self, opponent):

        # Make sure the history of all hunters is current.
        for ih in range(len(self.team)):
            self.team[ih].history = self.history

        # Get the results of all our players.
        results = [player.strategy(opponent) for player in self.team]

        # A subclass should just define a way to choose the result based on team results.
        return self.meta_strategy(results, opponent)

    def meta_strategy(self, results, opponent):
        """Determine the meta result based on results of all players."""
        pass

class MetaMajority(MetaPlayer):
    """A player who goes by the majority vote of all other non-meta players."""

    name = "Meta Majority"

    def __init__(self):

        # We need to import the list of strategies at runtime, since
        # _strategies import also _this_ module before defining the list.
        from ._strategies import ordinary_strategies
        self.team = ordinary_strategies

        MetaPlayer.__init__(self)

    def meta_strategy(self, results, opponent):
        if results.count('D') > results.count('C'):
            return 'D'
        return 'C'

class MetaMinority(MetaPlayer):
    """A player who goes by the minority vote of all other non-meta players."""

    name = "Meta Minority"

    def __init__(self):

        # We need to import the list of strategies at runtime, since
        # _strategies import also _this_ module before defining the list.
        from ._strategies import ordinary_strategies
        self.team = ordinary_strategies

        MetaPlayer.__init__(self)

    def meta_strategy(self, results, opponent):
        if results.count('D') < results.count('C'):
            return 'D'
        return 'C'

class MetaWinner(MetaPlayer):
    """A player who goes by the strategy of the current winner."""

    name = "Meta Winner"

    def __init__(self, team=None):

        # The default is to use all strategies available, but we need to import the list
        # at runtime, since _strategies import also _this_ module before defining the list.
        if team:
            self.team = team
        else:
            from ._strategies import ordinary_strategies
            self.team = ordinary_strategies

        MetaPlayer.__init__(self)

        # For each player, we will keep the history of proposed moves and
        # a running score since the beginning of the game.
        for t in self.team:
            t.proposed_history = []
            t.score = 0

    def strategy(self, opponent):

        # Update the running score for each player, before determining the next move.
        if len(self.history):
            for player in self.team:
                pl_C = player.proposed_history[-1] == "C"
                opp_C = opponent.history[-1] == "C"
                s = 2 * (pl_C and opp_C) or 5 * (pl_C and not opp_C) or 4 * (not pl_C and not opp_C) or 0
                player.score += s

        return MetaPlayer.strategy(self, opponent)

    def meta_strategy(self, results, opponent):

        scores = [pl.score for pl in self.team]
        bestscore = min(scores)
        beststrategies = [i for i, pl in enumerate(self.team) if pl.score == bestscore]
        bestproposals = [results[i] for i in beststrategies]
        bestresult = "C" if "C" in bestproposals else "D"

        # Update each player's proposed history with his proposed result, but always after
        # the new result has been settled based on scores accumulated until now.
        for r, t in zip(results, self.team):
            t.proposed_history.append(r)

        return bestresult
<commit_msg>fixes MetaPlayer to use behaviour dictionary<commit_after>from axelrod import Player

class MetaPlayer(Player):
    """A generic player that has its own team of players."""

    team = []
    behaviour = {
        'memory_depth': float('inf')  # Long memory
    }

    def __init__(self):

        Player.__init__(self)

        # Make sure we don't use any meta players to avoid infinite recursion.
        self.team = [t for t in self.team if not issubclass(t, MetaPlayer)]
        self.nteam = len(self.team)

        # Initiate all the player in out team.
        self.team = [t() for t in self.team]

        # If the team will have stochastic players, this meta is also stochastic.
        self.stochastic = any([t.behaviour['stochastic'] for t in self.team])

    def strategy(self, opponent):

        # Make sure the history of all hunters is current.
        for ih in range(len(self.team)):
            self.team[ih].history = self.history

        # Get the results of all our players.
        results = [player.strategy(opponent) for player in self.team]

        # A subclass should just define a way to choose the result based on team results.
        return self.meta_strategy(results, opponent)

    def meta_strategy(self, results, opponent):
        """Determine the meta result based on results of all players."""
        pass

class MetaMajority(MetaPlayer):
    """A player who goes by the majority vote of all other non-meta players."""

    name = "Meta Majority"

    def __init__(self):

        # We need to import the list of strategies at runtime, since
        # _strategies import also _this_ module before defining the list.
        from ._strategies import ordinary_strategies
        self.team = ordinary_strategies

        MetaPlayer.__init__(self)

    def meta_strategy(self, results, opponent):
        if results.count('D') > results.count('C'):
            return 'D'
        return 'C'

class MetaMinority(MetaPlayer):
    """A player who goes by the minority vote of all other non-meta players."""

    name = "Meta Minority"

    def __init__(self):

        # We need to import the list of strategies at runtime, since
        # _strategies import also _this_ module before defining the list.
        from ._strategies import ordinary_strategies
        self.team = ordinary_strategies

        MetaPlayer.__init__(self)

    def meta_strategy(self, results, opponent):
        if results.count('D') < results.count('C'):
            return 'D'
        return 'C'

class MetaWinner(MetaPlayer):
    """A player who goes by the strategy of the current winner."""

    name = "Meta Winner"

    def __init__(self, team=None):

        # The default is to use all strategies available, but we need to import the list
        # at runtime, since _strategies import also _this_ module before defining the list.
        if team:
            self.team = team
        else:
            from ._strategies import ordinary_strategies
            self.team = ordinary_strategies

        MetaPlayer.__init__(self)

        # For each player, we will keep the history of proposed moves and
        # a running score since the beginning of the game.
        for t in self.team:
            t.proposed_history = []
            t.score = 0

    def strategy(self, opponent):

        # Update the running score for each player, before determining the next move.
        if len(self.history):
            for player in self.team:
                pl_C = player.proposed_history[-1] == "C"
                opp_C = opponent.history[-1] == "C"
                s = 2 * (pl_C and opp_C) or 5 * (pl_C and not opp_C) or 4 * (not pl_C and not opp_C) or 0
                player.score += s

        return MetaPlayer.strategy(self, opponent)

    def meta_strategy(self, results, opponent):

        scores = [pl.score for pl in self.team]
        bestscore = min(scores)
        beststrategies = [i for i, pl in enumerate(self.team) if pl.score == bestscore]
        bestproposals = [results[i] for i in beststrategies]
        bestresult = "C" if "C" in bestproposals else "D"

        # Update each player's proposed history with his proposed result, but always after
        # the new result has been settled based on scores accumulated until now.
        for r, t in zip(results, self.team):
            t.proposed_history.append(r)

        return bestresult
<|endoftext|>


<commit_before>import sys
import time
import pytest
import logging
import IPython
import websocket
import subprocess
import numpy as np

import azrael.clerk
import azrael.config as config
import azrael.clacks as clacks
import azrael.wscontroller as wscontroller
import azrael.controller as controller

from azrael.util import int2id, id2int

WSControllerBase = wscontroller.WSControllerBase

ipshell = IPython.embed

def killall():
    subprocess.call(['pkill', 'killme'])

def startAzrael(ctrl_type):
    killall()

    # Start Clerk and instantiate Controller.
    clerk = azrael.clerk.Clerk(reset=True)
    clerk.start()

    if ctrl_type == 'ZeroMQ':
        ctrl = ControllerBase()
        ctrl.setupZMQ()
        ctrl.connectToClerk()
        server = None
    elif ctrl_type == 'Websocket':
        server = clacks.ClacksServer()
        server.start()

        ctrl = WSControllerBase('ws://127.0.0.1:8080/websocket', 1)
        assert ctrl.ping()
    else:
        print('Unknown controller type <{}>'.format(ctrl_type))
        assert False
    return clerk, ctrl, server

def stopAzrael(clerk, server):
    # Terminate the Clerk.
    clerk.terminate()
    clerk.join(timeout=3)

    # Terminate the Server (if one was started).
    if server is not None:
        server.terminate()
        server.join(timeout=3)

    # Forcefully terminate everything.
    killall()

def test_ping_clacks():
    """
    Start services and send Ping to Clacks. Then terminate clacks and verify
    that the ping fails.
    """
    # Start the necessary services.
    clerk, ctrl, server = startAzrael('Websocket')

    # Ping the server.
    assert ctrl.ping()

    # Shutdown the services.
    stopAzrael(clerk, server)

    # Connection must now be impossible.
    with pytest.raises(ConnectionRefusedError):
        WSControllerBase('ws://127.0.0.1:8080/websocket', 1)

    print('Test passed')

def test_ping_clerk():
    """
    Ping the Clerk instance via Clacks.
    """
    # Start the necessary services.
    clerk, ctrl, server = startAzrael('Websocket')

    # And send 'PING' command.
    assert ctrl.pingClerk()

    # Shutdown the services.
    stopAzrael(clerk, server)

    print('Test passed')

def test_timeout():
    """
    WS connection must timeout if it is inactive for too long.
    """
    # Start the necessary services.
    clerk, ctrl, server = startAzrael('Websocket')

    # Read from the WS. Since the server is not writing to that socket the call
    # will block and must raise a timeout eventually.
    with pytest.raises(websocket.WebSocketTimeoutException):
        ctrl.sendToClacks(b'')

    # Shutdown the services.
    stopAzrael(clerk, server)

    print('Test passed')

def test_websocket_getID():
    """
    Query the controller ID associated with this WebSocket.
    """
    # Start the necessary services.
    clerk, ctrl, server = startAzrael('Websocket')

    # Make sure we are connected.
    assert ctrl.objID == int2id(1)

    # Shutdown the services.
    stopAzrael(clerk, server)

    print('Test passed')

if __name__ == '__main__':
    test_ping_clacks()
    test_ping_clerk()
    test_timeout()
    test_websocket_getID()
<commit_msg>Cleaned up 'test_clacks' module.<commit_after>import sys
import time
import pytest
import logging
import IPython
import websocket
import subprocess
import numpy as np

import azrael.clerk
import azrael.clacks
import azrael.config as config
import azrael.wscontroller as wscontroller
import azrael.controller as controller

from azrael.util import int2id, id2int

WSControllerBase = wscontroller.WSControllerBase

ipshell = IPython.embed

def killall():
    subprocess.call(['pkill', 'killme'])

def startAzrael(ctrl_type):
    """
    Start all Azrael services and return their handles.

    ``ctrl_type`` may be  either 'ZeroMQ' or 'Websocket'. The only difference
    this makes is that the 'Websocket' version will also start a Clacks server,
    whereas for 'ZeroMQ' the respective handle will be **None**.

    :param str ctrl_type: the controller type ('ZeroMQ' or 'Websocket').
    :return: handles to (clerk, ctrl, clacks)
    """
    killall()

    # Start Clerk and instantiate Controller.
    clerk = azrael.clerk.Clerk(reset=True)
    clerk.start()

    if ctrl_type == 'ZeroMQ':
        # Instantiate the ZeroMQ version of the Controller.
        ctrl = ControllerBase()
        ctrl.setupZMQ()
        ctrl.connectToClerk()

        # Do not start a Clacks process.
        clacks = None
    elif ctrl_type == 'Websocket':
        # Start a Clacks process.
        clacks = azrael.clacks.ClacksServer()
        clacks.start()

        # Instantiate the Websocket version of the Controller.
        ctrl = WSControllerBase('ws://127.0.0.1:8080/websocket', 1)
        assert ctrl.ping()
    else:
        print('Unknown controller type <{}>'.format(ctrl_type))
        assert False
    return clerk, ctrl, clacks

def stopAzrael(clerk, clacks):
    """
    Kill all processes related to Azrael.

    :param clerk: handle to Clerk process.
    :param clacks: handle to Clacks process.
    """
    # Terminate the Clerk.
    clerk.terminate()
    clerk.join(timeout=3)

    # Terminate Clacks (if one was started).
    if clacks is not None:
        clacks.terminate()
        clacks.join(timeout=3)

    # Forcefully terminate everything.
    killall()

def test_ping_clacks():
    """
    Start services and send Ping to Clacks. Then terminate clacks and verify
    that the ping fails.
    """
    # Start the necessary services.
    clerk, ctrl, clacks = startAzrael('Websocket')

    # Ping the Clacks.
    assert ctrl.ping()

    # Shutdown the services.
    stopAzrael(clerk, clacks)

    # Connection must now be impossible.
    with pytest.raises(ConnectionRefusedError):
        WSControllerBase('ws://127.0.0.1:8080/websocket', 1)

    print('Test passed')

def test_ping_clerk():
    """
    Ping the Clerk instance via Clacks.
    """
    # Start the necessary services.
    clerk, ctrl, clacks = startAzrael('Websocket')

    # And send 'PING' command.
    assert ctrl.pingClerk()

    # Shutdown the services.
    stopAzrael(clerk, clacks)

    print('Test passed')

def test_timeout():
    """
    WS connection must timeout if it is inactive for too long.
    """
    # Start the necessary services.
    clerk, ctrl, clacks = startAzrael('Websocket')

    # Read from the WS. Since Clacks is not writing to that socket the call
    # will block and must raise a timeout eventually.
    with pytest.raises(websocket.WebSocketTimeoutException):
        ctrl.sendToClacks(b'')

    # Shutdown the services.
    stopAzrael(clerk, clacks)

    print('Test passed')

def test_websocket_getID():
    """
    Query the controller ID associated with this WebSocket.
    """
    # Start the necessary services.
    clerk, ctrl, clacks = startAzrael('Websocket')

    # Make sure we are connected.
    assert ctrl.objID == int2id(1)

    # Shutdown the services.
    stopAzrael(clerk, clacks)

    print('Test passed')

if __name__ == '__main__':
    test_ping_clacks()
    test_ping_clerk()
    test_timeout()
    test_websocket_getID()
<|endoftext|>


<commit_before>#!/usr/bin/env python
from __future__ import print_function
import feedparser
import time
import hashlib
import os
import sys
from os.path import expanduser
import logging
import re
import requests
import argparse
import shutil # To get around "cross-device" rename error when moving to dest. dir.
from datetime import datetime as dt
from sqlobject import SQLObject, sqlite, DateTimeCol, UnicodeCol
from tqdm import tqdm

# python2 compat
try: input = raw_input
except NameError: pass

# TODO expanduser as action? https://gist.github.com/brantfaircloth/1252339
parser = argparse.ArgumentParser(description='Download podcasts via the command line.')
parser.add_argument('--no-download', action='store_true',
                   help="Don't download any files. Just mark as read.")
parser.add_argument('--podcastdir', '-p', default='~/Downloads/podcasts',
    help="Folder to download podcast files to.")
parser.add_argument('--basedir', '-b', default='~/.upodder',
    help="Folder to store subscriptions and seen database.")
parser.add_argument('--oldness', '-o', default=30, type=int,
    help="Skip entries older than X days.")
parser.add_argument('--mark-seen', action='store_true',
    help="Just mark all entries as seen and exit.")
parser.add_argument("--quiet", help="Only output errors.",
                    action="store_true")
args = parser.parse_args()

YES = [1,"1","on","yes","Yes","YES","y","Y","true","True","TRUE","t","T"]
CONFIGCOMMENT = ['#',';','$',':','"',"'"]
BADFNCHARS = re.compile(r'[^\w]+')
TEMPDIR = '/tmp/upodder'
FILENAME = '{entry_title}.{filename_extension}'

# Initializing logging
if args.quiet:
    l = logging.Logger('upodder', logging.ERROR)
else:
    l = logging.Logger('upodder', logging.DEBUG)
stderrHandler = logging.StreamHandler()
# stderrHandler.setFormatter(logging.Formatter('%(message)s'))
l.addHandler(stderrHandler)

# Dict of possible file types
FILE_TYPES = {
    'audio/mpeg': 'mp3',
    'video/x-m4v': 'm4v',
    'audio/x-opus': 'opus',
    'audio/x-ogg': 'ogg',
    'audio/aac': 'aac',
    'audio/mp4': 'm4a',
    'audio/mp3': 'mp3'
    }

class SeenEntry(SQLObject):
    "Represents a single feed item, seen before. Used to keep track of download status."
    hashed = UnicodeCol()
    pub_date = DateTimeCol()

class EntryProcessor(object):
    "Processes single feed entry"
    def __init__(self, entry, feed):
        self.hashed = hashlib.sha1(entry['title'].encode('ascii', 'ignore')).hexdigest()
        self.pub_date = dt.fromtimestamp(time.mktime(entry.published_parsed))

        if args.mark_seen:
            SeenEntry(pub_date=self.pub_date, hashed=self.hashed)
            l.debug("Marking as seen: %s"%(entry['title']))
            return

        # Let's check if we worked on this entry earlier...
        if SeenEntry.select(SeenEntry.q.hashed == self.hashed).count() > 0:
            l.debug("Already seen: %s"%(entry['title']))
            return

        # Let's check the entry's date
        if (dt.now() - self.pub_date).days > args.oldness:
            l.debug("Too old for us: %s"%entry['title'])
            return

        # Search for mpeg enclosures
        for enclosure in filter(lambda x: x.get('type') in FILE_TYPES.keys() ,entry.get('enclosures',[])):
            # Work only with first found audio/mpeg or video/x-m4v enclosure (Bad Thing? maybe :( )

            # copy enclosure.type to entry.type for generate_filename processing.
            entry['type'] = enclosure.get('type')

            if self._download_enclosure(enclosure, entry, feed, args.no_download):
                SeenEntry( pub_date=self.pub_date, hashed=self.hashed)
            break

    def _download_enclosure(self, enclosure, entry, feed, no_download=False):
        """Performs downloading of specified file. Returns True on success and False in other case"""

        downloadto = TEMPDIR + os.sep + self.hashed

        if no_download:
            l.debug("Would download %s from %s" % (entry['title'], enclosure['href']))
            return True

        try:
            """Downloads URL to file, returns file name of download (from URL or Content-Disposition)"""
            if not os.path.exists(os.path.dirname(downloadto)):
                os.makedirs(os.path.dirname(downloadto))

            l.debug("Downloading %s from %s" % (entry['title'], enclosure['href']))
            r = requests.get(enclosure['href'], stream=True, timeout=25)

            with open(downloadto, 'wb') as f:
                if 'content-length' in r.headers:
                    total_length = int(r.headers['content-length'])
                    with tqdm(total=total_length,
                              unit="B",
                              unit_scale=True,
                              ncols=90) as pbar:
                        for chunk in r.iter_content(1024):
                            f.write(chunk)
                            if chunk:
                                pbar.update(len(chunk))
                else:
                    for chunk in r.iter_content(1024):
                        if chunk:
                            f.write(chunk)
                            f.flush()

            # filename = cgi.parse_header(r.headers.get('content-disposition'))[1]['filename']
            # if not filename:
            #     filename = "Untitled.mp3"

        except KeyboardInterrupt:
            l.info("Download aborted by Ctrl+c")
            try:
                user_wish = input("Do you like to mark item as read? (y/n) or quit? (Ctrl+c): ")
                if user_wish in YES:
                    return True
                else:
                    return False
            except KeyboardInterrupt:
                print("\nQuitting")
                sys.exit()

        # Move downloaded file to its final destination
        moveto = expanduser(args.podcastdir) + os.sep + self._generate_filename(entry, feed)
        l.debug("Moving {%s} to {%s}"%(downloadto,moveto))
        if not os.path.exists(os.path.dirname(moveto)): os.makedirs(os.path.dirname(moveto))
        shutil.move(downloadto, moveto)
        return True

    def _generate_filename(self, entry, feed):
        """Generates file name for this enclosure based on config settins
           Added filename_extension dict mapping to handle different file types."""
        (year,month,day,hour,minute,second,weekday,yearday,leap) = time.localtime()
        subst = {
            'today': '%i-%02i-%02i'%(year,month,day),
            'entry_date': self.pub_date.date().isoformat(),
            'id': self.hashed,
            'entry_title': re.sub(BADFNCHARS,'_',entry.get('title')),
            'feed_href': re.sub(BADFNCHARS,'_',feed.href.split('://')[-1]),
            'feed_title': re.sub(BADFNCHARS,'_',feed.feed.get('title',feed.href)),
            'filename_extension': FILE_TYPES.get(entry.get('type')),
        }
        return FILENAME.format(**subst)

def process_feed(url):
    l.info('Downloading feed: %s' % url)
    feed = feedparser.parse(url)

    # Not all bozo errors cause total failure
    if feed.bozo and isinstance(feed.bozo_exception,
                                (type(feedparser.NonXMLContentType), type(feedparser.CharacterEncodingOverride))):
        l.error("Erroneous feed URL: %s (%s)"%(url, type(feed.bozo_exception)))
        return

    # When parsing a website or error message, title is missing.
    if 'title' not in feed.feed:
        l.error("Erroneous feed URL: %s" % url)
        return

    l.info("Parsing feed: %s"%feed.feed.title)

    feed.entries.reverse()
    for entry in feed.entries:
        EntryProcessor(entry, feed)

def init():
    if not os.path.exists(expanduser(args.basedir)):
        l.info("Creating base dir %s"%args.basedir)
        os.makedirs(expanduser(args.basedir))

    subscriptions = expanduser(args.basedir) + os.sep + 'subscriptions'
    if not os.path.exists(subscriptions):
        l.info("Creating empty subscriptions file %s"%subscriptions)
        open(subscriptions,'a').write("# Add your RSS/ATOM subscriptions here.\n\n")

    SeenEntry._connection = sqlite.builder()(expanduser(args.basedir + os.sep + 'seen.sqlite'), debug=False)
    SeenEntry.createTable(ifNotExists=True)

def main():
    init()

    for url in map(lambda x: x.strip(), open(expanduser(args.basedir) + os.sep + 'subscriptions')):
        if url and url[0] not in CONFIGCOMMENT:
            process_feed(url)

    l.info('Done updating feeds.')

if __name__ == '__main__':
    main()

<commit_msg>Fixed #22: Add m4a as accepted filetype.<commit_after>#!/usr/bin/env python
from __future__ import print_function
import feedparser
import time
import hashlib
import os
import sys
from os.path import expanduser
import logging
import re
import requests
import argparse
import shutil # To get around "cross-device" rename error when moving to dest. dir.
from datetime import datetime as dt
from sqlobject import SQLObject, sqlite, DateTimeCol, UnicodeCol
from tqdm import tqdm

# python2 compat
try: input = raw_input
except NameError: pass

# TODO expanduser as action? https://gist.github.com/brantfaircloth/1252339
parser = argparse.ArgumentParser(description='Download podcasts via the command line.')
parser.add_argument('--no-download', action='store_true',
                   help="Don't download any files. Just mark as read.")
parser.add_argument('--podcastdir', '-p', default='~/Downloads/podcasts',
    help="Folder to download podcast files to.")
parser.add_argument('--basedir', '-b', default='~/.upodder',
    help="Folder to store subscriptions and seen database.")
parser.add_argument('--oldness', '-o', default=30, type=int,
    help="Skip entries older than X days.")
parser.add_argument('--mark-seen', action='store_true',
    help="Just mark all entries as seen and exit.")
parser.add_argument("--quiet", help="Only output errors.",
                    action="store_true")
args = parser.parse_args()

YES = [1,"1","on","yes","Yes","YES","y","Y","true","True","TRUE","t","T"]
CONFIGCOMMENT = ['#',';','$',':','"',"'"]
BADFNCHARS = re.compile(r'[^\w]+')
TEMPDIR = '/tmp/upodder'
FILENAME = '{entry_title}.{filename_extension}'

# Initializing logging
if args.quiet:
    l = logging.Logger('upodder', logging.ERROR)
else:
    l = logging.Logger('upodder', logging.DEBUG)
stderrHandler = logging.StreamHandler()
# stderrHandler.setFormatter(logging.Formatter('%(message)s'))
l.addHandler(stderrHandler)

# Dict of possible file types
FILE_TYPES = {
    'audio/mpeg': 'mp3',
    'audio/x-m4a': 'm4a',
    'video/x-m4v': 'm4v',
    'audio/x-opus': 'opus',
    'audio/x-ogg': 'ogg',
    'audio/aac': 'aac',
    'audio/mp4': 'm4a',
    'audio/mp3': 'mp3'
    }

class SeenEntry(SQLObject):
    "Represents a single feed item, seen before. Used to keep track of download status."
    hashed = UnicodeCol()
    pub_date = DateTimeCol()

class EntryProcessor(object):
    "Processes single feed entry"
    def __init__(self, entry, feed):
        self.hashed = hashlib.sha1(entry['title'].encode('ascii', 'ignore')).hexdigest()
        self.pub_date = dt.fromtimestamp(time.mktime(entry.published_parsed))

        if args.mark_seen:
            SeenEntry(pub_date=self.pub_date, hashed=self.hashed)
            l.debug("Marking as seen: %s"%(entry['title']))
            return

        # Let's check if we worked on this entry earlier...
        if SeenEntry.select(SeenEntry.q.hashed == self.hashed).count() > 0:
            l.debug("Already seen: %s"%(entry['title']))
            return

        # Let's check the entry's date
        if (dt.now() - self.pub_date).days > args.oldness:
            l.debug("Too old for us: %s"%entry['title'])
            return

        # Search for mpeg enclosures
        for enclosure in filter(lambda x: x.get('type') in FILE_TYPES.keys() ,entry.get('enclosures',[])):
            # Work only with first found audio/mpeg or video/x-m4v enclosure (Bad Thing? maybe :( )

            # copy enclosure.type to entry.type for generate_filename processing.
            entry['type'] = enclosure.get('type')

            if self._download_enclosure(enclosure, entry, feed, args.no_download):
                SeenEntry( pub_date=self.pub_date, hashed=self.hashed)
            break

    def _download_enclosure(self, enclosure, entry, feed, no_download=False):
        """Performs downloading of specified file. Returns True on success and False in other case"""

        downloadto = TEMPDIR + os.sep + self.hashed

        if no_download:
            l.debug("Would download %s from %s" % (entry['title'], enclosure['href']))
            return True

        try:
            """Downloads URL to file, returns file name of download (from URL or Content-Disposition)"""
            if not os.path.exists(os.path.dirname(downloadto)):
                os.makedirs(os.path.dirname(downloadto))

            l.debug("Downloading %s from %s" % (entry['title'], enclosure['href']))
            r = requests.get(enclosure['href'], stream=True, timeout=25)

            with open(downloadto, 'wb') as f:
                if 'content-length' in r.headers:
                    total_length = int(r.headers['content-length'])
                    with tqdm(total=total_length,
                              unit="B",
                              unit_scale=True,
                              ncols=90) as pbar:
                        for chunk in r.iter_content(1024):
                            f.write(chunk)
                            if chunk:
                                pbar.update(len(chunk))
                else:
                    for chunk in r.iter_content(1024):
                        if chunk:
                            f.write(chunk)
                            f.flush()

            # filename = cgi.parse_header(r.headers.get('content-disposition'))[1]['filename']
            # if not filename:
            #     filename = "Untitled.mp3"

        except KeyboardInterrupt:
            l.info("Download aborted by Ctrl+c")
            try:
                user_wish = input("Do you like to mark item as read? (y/n) or quit? (Ctrl+c): ")
                if user_wish in YES:
                    return True
                else:
                    return False
            except KeyboardInterrupt:
                print("\nQuitting")
                sys.exit()

        # Move downloaded file to its final destination
        moveto = expanduser(args.podcastdir) + os.sep + self._generate_filename(entry, feed)
        l.debug("Moving {%s} to {%s}"%(downloadto,moveto))
        if not os.path.exists(os.path.dirname(moveto)): os.makedirs(os.path.dirname(moveto))
        shutil.move(downloadto, moveto)
        return True

    def _generate_filename(self, entry, feed):
        """Generates file name for this enclosure based on config settins
           Added filename_extension dict mapping to handle different file types."""
        (year,month,day,hour,minute,second,weekday,yearday,leap) = time.localtime()
        subst = {
            'today': '%i-%02i-%02i'%(year,month,day),
            'entry_date': self.pub_date.date().isoformat(),
            'id': self.hashed,
            'entry_title': re.sub(BADFNCHARS,'_',entry.get('title')),
            'feed_href': re.sub(BADFNCHARS,'_',feed.href.split('://')[-1]),
            'feed_title': re.sub(BADFNCHARS,'_',feed.feed.get('title',feed.href)),
            'filename_extension': FILE_TYPES.get(entry.get('type')),
        }
        return FILENAME.format(**subst)

def process_feed(url):
    l.info('Downloading feed: %s' % url)
    feed = feedparser.parse(url)

    # Not all bozo errors cause total failure
    if feed.bozo and isinstance(feed.bozo_exception,
                                (type(feedparser.NonXMLContentType), type(feedparser.CharacterEncodingOverride))):
        l.error("Erroneous feed URL: %s (%s)"%(url, type(feed.bozo_exception)))
        return

    # When parsing a website or error message, title is missing.
    if 'title' not in feed.feed:
        l.error("Erroneous feed URL: %s" % url)
        return

    l.info("Parsing feed: %s"%feed.feed.title)

    feed.entries.reverse()
    for entry in feed.entries:
        EntryProcessor(entry, feed)

def init():
    if not os.path.exists(expanduser(args.basedir)):
        l.info("Creating base dir %s"%args.basedir)
        os.makedirs(expanduser(args.basedir))

    subscriptions = expanduser(args.basedir) + os.sep + 'subscriptions'
    if not os.path.exists(subscriptions):
        l.info("Creating empty subscriptions file %s"%subscriptions)
        open(subscriptions,'a').write("# Add your RSS/ATOM subscriptions here.\n\n")

    SeenEntry._connection = sqlite.builder()(expanduser(args.basedir + os.sep + 'seen.sqlite'), debug=False)
    SeenEntry.createTable(ifNotExists=True)

def main():
    init()

    for url in map(lambda x: x.strip(), open(expanduser(args.basedir) + os.sep + 'subscriptions')):
        if url and url[0] not in CONFIGCOMMENT:
            process_feed(url)

    l.info('Done updating feeds.')

if __name__ == '__main__':
    main()

<|endoftext|>


<commit_before>import math
import pygame

pygame.init()

# Initializing some colors for cleaner looks throughout
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 80, 0)
RED = (255, 0, 0)
LIGHTBLUE = (0, 255, 255)

# I've tried to program this in it's entirety based on these variables so that they can be changed
# and still work at any time, will do more testing on this later
gameWidth = 1024
gameHeight = 850
boardWidth = 960
boardHeight = 720
boardX = 32
boardY = 100
gameSpeed = 100
blockWidth = 64
blockHeight = 48

# Some initialization stuff
font = pygame.font.Font(None, 36)
size = (gameWidth, gameHeight)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("PYTRON")
clock = pygame.time.Clock()
move = pygame.USEREVENT + 1
reset = pygame.USEREVENT + 2
pygame.time.set_timer(move, gameSpeed)

up, right, down, left = (False,)*4

board = [[0 for k in range(0, blockWidth)] for j in range(0, blockHeight)]
userTrail = []

def draw_board():
    # This just draws the grid lines that make up the board
    for k in range(0, blockWidth + 1):
        pygame.draw.line(screen, GREEN, (boardX - 1 + (k* 15), boardY - 1), (31 + (k* 15), boardHeight + boardY - 1), 2)

    for k in range(0, blockHeight + 1):
        pygame.draw.line(screen, GREEN, (boardX - 1, boardY - 1 + (k* 15)), (boardWidth + boardX - 1, boardY - 1 + (k* 15)), 2)

class Overseer(object):
    # Maintains score, reset, stuff like that

    def __init__(self):
        self.userScore = 0
        self.CPScore = 0
        self.reset = False

class Brick(object):
    # Brick class for both user and CP bricks
    def __init__(self, x, y, outlinecolor, image):
        self.image = pygame.image.load(image).convert()
        self.outlinecolor = outlinecolor
        self.rect = self.image.get_rect()
        self.rect.left = x
        self.rect.top = y
        self.top = False
        self.right = False
        self.bottom = False
        self.left = False

    def update_draw(self):
        # Determines if a line for an outline needs to be drawn and draws it
        screen.blit(self.image, self.rect)
        if self.top == False:
            pygame.draw.line(screen, self.outlinecolor, (self.rect.left, self.rect.top), (self.rect.left + 14, self.rect.top), 1)
        if self.right == False:
            pygame.draw.line(screen, self.outlinecolor, (self.rect.left + 14, self.rect.top), (self.rect.left + 14, self.rect.top + 14), 1)
        if self.bottom == False:
            pygame.draw.line(screen, self.outlinecolor, (self.rect.left, self.rect.top + 14), (self.rect.left + 14, self.rect.top + 14), 1)
        if self.left == False:
            pygame.draw.line(screen, self.outlinecolor, (self.rect.left, self.rect.top), (self.rect.left, self.rect.top + 14), 1)

class User(object):

    def __init__(self, x, y, direction):
        self.image = pygame.image.load('tron.png').convert()
        self.rect = self.image.get_rect()
        self.rotated = False
        self.rect.left = x
        self.rect.top = y
        self.dir = direction

    def update_draw(self):
        screen.blit(self.image, self.rect)

    # These will rotate the image to face the correct way and change the direction as well
    def up(self):
        if self.dir == 1:
            self.image = pygame.transform.rotate(self.image, 90)
            self.dir = 2
        elif self.dir == 3:
            self.image = pygame.transform.rotate(self.image, 270)
            self.dir = 2

    def right(self):
        if self.dir == 0:
            self.image = pygame.transform.rotate(self.image, 90)
            self.dir = 1
        elif self.dir == 2:
            self.image = pygame.transform.rotate(self.image, 270)
            self.dir = 1

    def down(self):
        if self.dir == 1:
            self.image = pygame.transform.rotate(self.image, 270)
            self.dir = 0
        elif self.dir == 3:
            self.image = pygame.transform.rotate(self.image, 90)
            self.dir = 0

    def left(self):
        if self.dir == 0:
            self.image = pygame.transform.rotate(self.image, 270)
            self.dir = 3
        elif self.dir == 2:
            self.image = pygame.transform.rotate(self.image, 90)
            self.dir = 3

    def move(self):
        if self.dir == 0:
            self.rect.top = self.rect.top + 15
        elif self.dir == 1:
            self.rect.left = self.rect.left + 15
        elif self.dir == 2:
            self.rect.top = self.rect.top - 15
        elif self.dir == 3:
            self.rect.left = self.rect.left - 15

def reset():
    global user, userTrail
    user = User(56*15 + boardX, 24 * 15 + boardY, 3)
    del userTrail[:]
    overseer.reset = False

    screen.fill(BLACK)
    draw_board()

    user.update_draw()
    pygame.display.flip()

def update_board():
    # This is where the magic happens so to speak
    # I wanted to find a way to draw an outline around the blocks in the most efficient way possible
    # Because I had to loop through all the bricks to print them at least once, I added the check code
    # to determine if it needed an outline or not. For my purposes, it is fast and efficient
    screen.fill(BLACK)
    draw_board()

    newUserBrick = Brick(user.rect.left, user.rect.top, LIGHTBLUE, 'brick.png')

    hasReset = False

    for ibrick in userTrail:
        if pygame.sprite.collide_rect(user, ibrick):
            overseer.reset = True
            hasReset = True
            reset()
            break

        ibrick.update_draw()

        if newUserBrick.rect.top == ibrick.rect.top:
            if newUserBrick.rect.left == ibrick.rect.left - 15:
                newUserBrick.right = True
                ibrick.left = True
            if newUserBrick.rect.left == ibrick.rect.left + 15:
                newUserBrick.left = True
                ibrick.right = True
        if newUserBrick.rect.left == ibrick.rect.left:
            if newUserBrick.rect.top == ibrick.rect.top - 15 :
                newUserBrick.bottom = True
                ibrick.top = True
            if newUserBrick.rect.top == ibrick.rect.top + 15:
                newUserBrick.top = True
                ibrick.bottom = True

    if not hasReset:
        userTrail.append(newUserBrick)

    user.update_draw()

    pygame.display.flip()

def keyCheck():

    # This checks if a key has been pressed
    # Extra checks have been put in place due to how pygame handles pressed
    # It will only register the moment it has been pressed and no more, even if it is held down
    global left, right, up, down

    if pygame.key.get_pressed()[pygame.K_UP] and not up:
        up = True
        user.up()
    else:
        up = False
    if pygame.key.get_pressed()[pygame.K_RIGHT] and not right:
        right = True
        user.right()
    else:
        right = False
    if pygame.key.get_pressed()[pygame.K_DOWN] and not down:
        down = True
        user.down()
    else:
        down = False
    if pygame.key.get_pressed()[pygame.K_LEFT] and not left:
        left = True
        user.left()
    else:
        left = False

# Initialize user and game
user = User(56*15 + boardX, 24 * 15 + boardY, 3)
gameOn = True
overseer = Overseer()

while gameOn:

    clock.tick(50)

    print overseer.reset

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameOn = False
        if event.type == pygame.KEYDOWN:
            keyCheck()
        if event.type == move:
            user.move()
            update_board()

pygame.quit()
<commit_msg>PEP8ifying my code<commit_after>import math
import pygame

pygame.init()

# Initializing some colors for cleaner looks throughout
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 80, 0)
RED = (255, 0, 0)
LIGHTBLUE = (0, 255, 255)

# I've tried to program this in it's entirety based
# on these variables so that they can be changed
# and still work at any time, will do more testing on this later
game_width = 1024
game_height = 850
board_width = 960
board_height = 720
board_x = 32
board_y = 100
game_speed = 100
block_width = 64
block_height = 48

# Some initialization stuff
font = pygame.font.Font(None, 36)
size = (game_width, game_height)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("PYTRON")
clock = pygame.time.Clock()
move = pygame.USEREVENT + 1
reset = pygame.USEREVENT + 2
pygame.time.set_timer(move, game_speed)

up, right, down, left = (False,)*4

board = [[0 for k in range(0, block_width)] for j in range(0, block_height)]

def draw_board():
    # This just draws the grid lines that make up the board
    for k in range(0, block_width + 1):
        pygame.draw.line(screen, GREEN, (board_x - 1 + (k * 15), board_y - 1),
                         (31 + (k * 15), board_height + board_y - 1), 2)

    for k in range(0, block_height + 1):
        pygame.draw.line(screen, GREEN, (board_x - 1, board_y - 1 + (k * 15)),
                         (board_width + board_x - 1, board_y - 1 + (k * 15)), 2)

class Overseer(object):
    # Maintains score, reset, stuff like that

    def __init__(self):
        self.user_score = 0
        self.cp_score = 0
        self.reset = False

class Brick(object):
    # Brick class for both user and CP bricks
    def __init__(self, x, y, outline_color, image):
        self.image = pygame.image.load(image).convert()
        self.outline_color = outline_color
        self.rect = self.image.get_rect()
        self.rect.left = x
        self.rect.top = y
        self.top = False
        self.right = False
        self.bottom = False
        self.left = False

    def update_draw(cls):
        # Determines if a line for an outline needs to be drawn and draws it
        screen.blit(cls.image, cls.rect)
        if cls.top is False:
            pygame.draw.line(screen, cls.outline_color, (cls.rect.left, cls.rect.top),
            (cls.rect.left + 14, cls.rect.top), 1)
        if cls.right is False:
            pygame.draw.line(screen, cls.outline_color, (cls.rect.left + 14, cls.rect.top),
            (cls.rect.left + 14, cls.rect.top + 14), 1)
        if cls.bottom is False:
            pygame.draw.line(screen, cls.outline_color, (cls.rect.left, cls.rect.top + 14),
            (cls.rect.left + 14, cls.rect.top + 14), 1)
        if cls.left is False:
            pygame.draw.line(screen, cls.outline_color, (cls.rect.left, cls.rect.top),
            (cls.rect.left, cls.rect.top + 14), 1)

class User(object):

    def __init__(self, x, y, direction):
        self.image = pygame.image.load('tron.png').convert()
        self.rect = self.image.get_rect()
        self.rotated = False
        self.rect.left = x
        self.rect.top = y
        self.dir = direction

    def update_draw(cls):
        screen.blit(cls.image, cls.rect)

    # These will rotate the image to face the correct way and change the direction as well
    def up(cls):
        if cls.dir == 1:
            cls.image = pygame.transform.rotate(cls.image, 90)
            cls.dir = 2
        elif cls.dir == 3:
            cls.image = pygame.transform.rotate(cls.image, 270)
            cls.dir = 2

    def right(cls):
        if cls.dir == 0:
            cls.image = pygame.transform.rotate(cls.image, 90)
            cls.dir = 1
        elif cls.dir == 2:
            cls.image = pygame.transform.rotate(cls.image, 270)
            cls.dir = 1

    def down(cls):
        if cls.dir == 1:
            cls.image = pygame.transform.rotate(cls.image, 270)
            cls.dir = 0
        elif cls.dir == 3:
            cls.image = pygame.transform.rotate(cls.image, 90)
            cls.dir = 0

    def left(cls):
        if cls.dir == 0:
            cls.image = pygame.transform.rotate(cls.image, 270)
            cls.dir = 3
        elif cls.dir == 2:
            cls.image = pygame.transform.rotate(cls.image, 90)
            cls.dir = 3

    def move(cls):
        if cls.dir == 0:
            cls.rect.top = cls.rect.top + 15
        elif cls.dir == 1:
            cls.rect.left = cls.rect.left + 15
        elif cls.dir == 2:
            cls.rect.top = cls.rect.top - 15
        elif cls.dir == 3:
            cls.rect.left = cls.rect.left - 15

def reset(overseer, user, user_trail):
    user.rect.left = 56*15 + board_x
    user.rect.top = 24 * 15 + board_y
    user.dir = 3
    user.image = pygame.image.load('tron.png').convert()
    del user_trail[:]
    overseer.reset = False

    screen.fill(BLACK)
    draw_board()

    user.update_draw()
    pygame.display.flip()

def update_board(user, overseer, user_trail):
    # This is where the magic happens so to speak
    # I wanted to find a way to draw an outline around the blocks in the most efficient way possible
    # Because I had to loop through all the bricks to print them at least once, I added the check code
    # to determine if it needed an outline or not. For my purposes, it is fast and efficient
    screen.fill(BLACK)
    draw_board()

    new_user_brick = Brick(user.rect.left, user.rect.top, LIGHTBLUE, 'brick.png')

    has_reset = False

    for ibrick in user_trail:
        if pygame.sprite.collide_rect(user, ibrick):
            overseer.reset = True
            has_reset = True
            reset(overseer, user, user_trail)
            break

        ibrick.update_draw()

        if new_user_brick.rect.top == ibrick.rect.top:
            if new_user_brick.rect.left == ibrick.rect.left - 15:
                new_user_brick.right = True
                ibrick.left = True
            if new_user_brick.rect.left == ibrick.rect.left + 15:
                new_user_brick.left = True
                ibrick.right = True
        if new_user_brick.rect.left == ibrick.rect.left:
            if new_user_brick.rect.top == ibrick.rect.top - 15:
                new_user_brick.bottom = True
                ibrick.top = True
            if new_user_brick.rect.top == ibrick.rect.top + 15:
                new_user_brick.top = True
                ibrick.bottom = True

    if not has_reset:
        user_trail.append(new_user_brick)

    user.update_draw()

    pygame.display.flip()

def keyCheck(user):

    # This checks if a key has been pressed
    # Extra checks have been put in place due to how pygame handles pressed
    # It will only register the moment it has been pressed and no more, even if it is held down
    global left, right, up, down

    if pygame.key.get_pressed()[pygame.K_UP] and not up:
        up = True
        user.up()
    else:
        up = False
    if pygame.key.get_pressed()[pygame.K_RIGHT] and not right:
        right = True
        user.right()
    else:
        right = False
    if pygame.key.get_pressed()[pygame.K_DOWN] and not down:
        down = True
        user.down()
    else:
        down = False
    if pygame.key.get_pressed()[pygame.K_LEFT] and not left:
        left = True
        user.left()
    else:
        left = False

def main():

    # Initialize user and game
    user = User(56*15 + board_x, 24 * 15 + board_y, 3)
    user_trail = []
    gameOn = True
    overseer = Overseer()

    while gameOn:
        clock.tick(50)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameOn = False
            if event.type == pygame.KEYDOWN:
                keyCheck(user)
            if event.type == move:
                user.move()
                update_board(user, overseer, user_trail)

    pygame.quit()

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


<commit_before>from collections import namedtuple
import numpy as np
import cv2
import cv2.cv as cv

showKeys = True

ControlRange = namedtuple('ControlRange', ['min', 'zero_min', 'zero_max', 'max'])
forward_range = ControlRange(-100, -20, 20, 100)
strafe_range = ControlRange(-100, -20, 20, 100)

class DesktopControlClient:
    """Desktop-based controller using mouse and/or keyboard input."""

    window_name = "Desktop Controller"
    window_width = 640
    window_height = 480
    loop_delay = 20

    axes_length = 360
    axes_color = (128, 0, 0)
    limit_color = (64, 0, 0)
    zero_color = (128, 128, 128)
    knob_radius = 15
    knob_color = (0, 0, 128)
    knob_fill_color = (0, 0, 255)
    help_color = (0, 128, 0)

    def __init__(self):
        self.forward = 0
        self.strafe = 0
        #self.turn = 0  # TODO add turning
        self.imageOut = np.zeros((self.window_height, self.window_width, 3), dtype=np.uint8) # numpy convention: (height, width, depth)
        self.imageCenter = (self.window_width / 2, self.window_height / 2)  # OpenCV convention: (x, y)

        # TODO Add mouse callback

    def run(self):
        cv2.namedWindow(self.window_name)
        while True:
            self.draw()
            key = cv2.waitKey(self.loop_delay)
            if key != -1:
                keyCode = key & 0x00007f  # key code is in the last 8 bits, pick 7 bits for correct ASCII interpretation (8th bit indicates
                keyChar = chr(keyCode) if not (key & 0x00ff00) else None # if keyCode is normal (SPECIAL bits are zero), convert to char (str)

                if showKeys: print "run(): key = {key:#06x}, keyCode = {keyCode}, keyChar = {keyChar}".format(key=key, keyCode=keyCode, keyChar=keyChar)  # [debug]

                if keyCode == 0x1b or keyChar == 'q' or keyChar == 'Q':  # quit
                    break
                elif keyChar == ' ':  # stop/zero out
                    self.forward = 0
                    self.strafe = 0
                elif keyChar == 'w' or keyChar == 'W':  # forward
                    self.forward -= 1
                    if self.forward < forward_range.min:
                        self.forward = forward_range.min
                elif keyChar == 's' or keyChar == 'S':  # backward
                    self.forward += 1
                    if self.forward > forward_range.max:
                        self.forward = forward_range.max
                elif keyChar == 'a' or keyChar == 'A':  # left
                    self.strafe -= 1
                    if self.strafe < strafe_range.min:
                        self.strafe = strafe_range.min
                elif keyChar == 'd' or keyChar == 'D':  # right
                    self.strafe += 1
                    if self.strafe > strafe_range.max:
                        self.strafe = strafe_range.max

                # TODO Send commands to server

    def draw(self):
        # Clear entire image
        self.imageOut.fill(255)

        # Draw axis lines
        cv2.line(self.imageOut, (self.imageCenter[0] - self.axes_length / 2, self.imageCenter[1]), (self.imageCenter[0] + self.axes_length / 2, self.imageCenter[1]), self.axes_color, 2)
        cv2.line(self.imageOut, (self.imageCenter[0], self.imageCenter[1] - self.axes_length / 2), (self.imageCenter[0], self.imageCenter[1] + self.axes_length / 2), self.axes_color, 2)

        # Draw limiting rectangle
        cv2.rectangle(self.imageOut, (self.imageCenter[0] + strafe_range.min, self.imageCenter[1] + forward_range.min), (self.imageCenter[0] + strafe_range.max, self.imageCenter[1] + forward_range.max), self.limit_color, 2)

        # Draw zero rectangle
        cv2.rectangle(self.imageOut, (self.imageCenter[0] + strafe_range.zero_min, self.imageCenter[1] + forward_range.zero_min), (self.imageCenter[0] + strafe_range.zero_max, self.imageCenter[1] + forward_range.zero_max), self.zero_color, 2)

        # Draw control knob
        cv2.circle(self.imageOut, (self.imageCenter[0] + self.strafe, self.imageCenter[1] + self.forward), self.knob_radius, self.knob_fill_color, cv.CV_FILLED)
        cv2.circle(self.imageOut, (self.imageCenter[0] + self.strafe, self.imageCenter[1] + self.forward), self.knob_radius, self.knob_color, 3)

        # Add help text
        cv2.putText(self.imageOut, "Move: W/S/A/D, Stop: SPACE, Quit: ESC", (12, self.window_height - 12), cv2.FONT_HERSHEY_SIMPLEX, 0.75, self.help_color, 2)

        # Show image
        cv2.imshow(self.window_name, self.imageOut)

if __name__ == "__main__":
    DesktopControlClient().run()
<commit_msg>Added mouse input to desktop control client<commit_after>from collections import namedtuple
import numpy as np
import cv2
import cv2.cv as cv

showKeys = True

ControlRange = namedtuple('ControlRange', ['min', 'zero_min', 'zero_max', 'max'])
forward_range = ControlRange(-100, -20, 20, 100)
strafe_range = ControlRange(-100, -20, 20, 100)

class DesktopControlClient:
    """Desktop-based controller using mouse and/or keyboard input."""

    window_name = "Desktop Controller"
    window_width = 640
    window_height = 480
    loop_delay = 20

    axes_length = 360
    axes_color = (128, 0, 0)
    limit_color = (64, 0, 0)
    zero_color = (128, 128, 128)
    knob_radius = 15
    knob_color = (0, 0, 128)
    knob_fill_color = (0, 0, 255)
    help_color = (0, 128, 0)

    def __init__(self):
        self.forward = 0
        self.strafe = 0
        #self.turn = 0  # TODO add turning
        self.imageOut = np.zeros((self.window_height, self.window_width, 3), dtype=np.uint8) # numpy convention: (height, width, depth)
        self.imageCenter = (self.window_width / 2, self.window_height / 2)  # OpenCV convention: (x, y)

    def run(self):
        cv2.namedWindow(self.window_name)
        cv.SetMouseCallback(self.window_name, self.onMouse, param=None)

        while True:
            self.draw()
            key = cv2.waitKey(self.loop_delay)
            if key != -1:
                keyCode = key & 0x00007f  # key code is in the last 8 bits, pick 7 bits for correct ASCII interpretation (8th bit indicates
                keyChar = chr(keyCode) if not (key & 0x00ff00) else None # if keyCode is normal (SPECIAL bits are zero), convert to char (str)

                if showKeys: print "run(): key = {key:#06x}, keyCode = {keyCode}, keyChar = {keyChar}".format(key=key, keyCode=keyCode, keyChar=keyChar)  # [debug]

                if keyCode == 0x1b or keyChar == 'q' or keyChar == 'Q':  # quit
                    break
                elif keyChar == ' ':  # stop/zero out
                    self.forward = 0
                    self.strafe = 0
                elif keyChar == 'w' or keyChar == 'W':  # forward
                    self.forward -= 1
                    if self.forward < forward_range.min:
                        self.forward = forward_range.min
                elif keyChar == 's' or keyChar == 'S':  # backward
                    self.forward += 1
                    if self.forward > forward_range.max:
                        self.forward = forward_range.max
                elif keyChar == 'a' or keyChar == 'A':  # left
                    self.strafe -= 1
                    if self.strafe < strafe_range.min:
                        self.strafe = strafe_range.min
                elif keyChar == 'd' or keyChar == 'D':  # right
                    self.strafe += 1
                    if self.strafe > strafe_range.max:
                        self.strafe = strafe_range.max

                # TODO Send commands to server

    def onMouse(self, event, x, y, flags, param=None):
        #print "DesktopControlClient.onMouse(): {} @ ({}, {}) [flags = {}]".format(event, x, y, flags)  # [debug]
        if event == cv.CV_EVENT_LBUTTONUP:  # stop when left button is released
            #print "stop"  # [debug]
            self.forward = 0
            self.strafe = 0
        elif event == cv.CV_EVENT_MOUSEMOVE and flags & cv.CV_EVENT_FLAG_LBUTTON:  # move when left button is held down
            #print "move ({}, {})".format(x, y)  # [debug]
            self.forward = y - self.imageCenter[1]
            if self.forward < forward_range.min:
                self.forward = forward_range.min
            elif self.forward > forward_range.max:
                self.forward = forward_range.max

            self.strafe = x - self.imageCenter[0]
            if self.strafe < strafe_range.min:
                self.strafe = strafe_range.min
            elif self.strafe > strafe_range.max:
                self.strafe = strafe_range.max

    def draw(self):
        # Clear entire image
        self.imageOut.fill(255)

        # Draw axis lines
        cv2.line(self.imageOut, (self.imageCenter[0] - self.axes_length / 2, self.imageCenter[1]), (self.imageCenter[0] + self.axes_length / 2, self.imageCenter[1]), self.axes_color, 2)
        cv2.line(self.imageOut, (self.imageCenter[0], self.imageCenter[1] - self.axes_length / 2), (self.imageCenter[0], self.imageCenter[1] + self.axes_length / 2), self.axes_color, 2)

        # Draw limiting rectangle
        cv2.rectangle(self.imageOut, (self.imageCenter[0] + strafe_range.min, self.imageCenter[1] + forward_range.min), (self.imageCenter[0] + strafe_range.max, self.imageCenter[1] + forward_range.max), self.limit_color, 2)

        # Draw zero rectangle
        cv2.rectangle(self.imageOut, (self.imageCenter[0] + strafe_range.zero_min, self.imageCenter[1] + forward_range.zero_min), (self.imageCenter[0] + strafe_range.zero_max, self.imageCenter[1] + forward_range.zero_max), self.zero_color, 2)

        # Draw control knob
        cv2.circle(self.imageOut, (self.imageCenter[0] + self.strafe, self.imageCenter[1] + self.forward), self.knob_radius, self.knob_fill_color, cv.CV_FILLED)
        cv2.circle(self.imageOut, (self.imageCenter[0] + self.strafe, self.imageCenter[1] + self.forward), self.knob_radius, self.knob_color, 3)

        # Add help text
        cv2.putText(self.imageOut, "Move: W/S/A/D, Stop: SPACE, Quit: ESC", (12, self.window_height - 12), cv2.FONT_HERSHEY_SIMPLEX, 0.75, self.help_color, 2)

        # Show image
        cv2.imshow(self.window_name, self.imageOut)

if __name__ == "__main__":
    DesktopControlClient().run()
<|endoftext|>