<commit_before>from mock import patch, Mock
from unittest import TestCase
import noembed

class NoEmbedTests(TestCase):
    def setUp(self):
        self.example_url = 'http://example.com'
        self.noembed = noembed.NoEmbed()

    def test_endpoint_url_is_set_to_noembed_by_default(self):
        self.assertEqual(self.noembed.endpoint_url, noembed.NOEMBED_ENDPOINT_URL)

    def test_build_payload_returns_dict_with_supplied_url(self):
        payload = self.noembed.build_payload(self.example_url)
        self.assertEqual(payload['url'], self.example_url)

    def test_build_payload_does_not_include_maxwidth_or_maxheight_if_not_supplied(self):
        payload = self.noembed.build_payload(self.example_url)
        self.assertNotIn('maxwidth', payload.keys())
        self.assertNotIn('maxheight', payload.keys())

    def test_payload_includes_max_width_when_included(self):
        payload = self.noembed.build_payload(self.example_url, max_width=100)
        self.assertEqual(payload['maxwidth'], 100)

    def test_payload_includes_max_height_when_included(self):
        payload = self.noembed.build_payload(self.example_url, max_height=100)
        self.assertEqual(payload['maxheight'], 100)

    @patch('noembed.requests')
    def test_requests_get_is_called_with_endpoint_url_and_payload(self, mock_requests):
        mock_response = Mock()
        mock_response.json.return_value = {}
        mock_requests.get.return_value = mock_response
        self.noembed.embed(self.example_url, 100, 100)
        mock_requests.get.assert_called_once_with(
            noembed.NOEMBED_ENDPOINT_URL,
            params={'url': self.example_url, 'maxwidth':100, 'maxheight':100}
        )

    @patch('noembed.requests')
    def test_excption_raised_if_error_key_in_json(self, mock_requests):
        mock_response = Mock()
        mock_response.json.return_value = {
            'url': 'http://example.com',
            'error': 'This is an example error'
        }
        mock_requests.get.return_value = mock_response

        with self.assertRaises(noembed.NoEmbedException):
            self.noembed.embed(self.example_url)

    @patch('noembed.requests')
    def test_embed_returns_a_noembed_response(self, mock_requests):
        mock_response = Mock()
        mock_response.json.return_value = {}
        mock_requests.get.return_value = mock_response

        resp = self.noembed.embed(self.example_url)

        self.assertTrue(isinstance(resp, noembed.NoEmbedResponse))

    @patch('noembed.NoEmbedResponse')
    @patch('noembed.requests')
    def test_embed_passes_response_dict_to_noembed_response(self, mock_requests, mock_noembed_response):
        mock_response = Mock()
        mock_response.json.return_value = {'foo': 'bar'}
        mock_requests.get.return_value = mock_response

        noembed.embed(self.example_url)

        mock_noembed_response.assert_called_once_with({'foo': 'bar'})

class NoEmbedResponseTests(TestCase):
    def test_data_put_in_private_argument_on_init(self):
        data = {'a': 1, 'b': 2, 'c': 3}
        resp = noembed.NoEmbedResponse(data)
        self.assertEqual(data, resp._data)

    def test_data_items_set_as_attributes_on_init(self):
        data = {'a': 1, 'b': 2, 'c': 3}
        resp = noembed.NoEmbedResponse(data)
        for key, value in data.items():
            self.assertEqual(resp.__getattribute__(key), value)
<commit_msg>tests for embed function<commit_after>from mock import patch, Mock
from unittest import TestCase
import noembed

class NoEmbedTests(TestCase):
    def setUp(self):
        self.example_url = 'http://example.com'
        self.noembed = noembed.NoEmbed()

    def test_endpoint_url_is_set_to_noembed_by_default(self):
        self.assertEqual(self.noembed.endpoint_url, noembed.NOEMBED_ENDPOINT_URL)

    def test_build_payload_returns_dict_with_supplied_url(self):
        payload = self.noembed.build_payload(self.example_url)
        self.assertEqual(payload['url'], self.example_url)

    def test_build_payload_does_not_include_maxwidth_or_maxheight_if_not_supplied(self):
        payload = self.noembed.build_payload(self.example_url)
        self.assertNotIn('maxwidth', payload.keys())
        self.assertNotIn('maxheight', payload.keys())

    def test_payload_includes_max_width_when_included(self):
        payload = self.noembed.build_payload(self.example_url, max_width=100)
        self.assertEqual(payload['maxwidth'], 100)

    def test_payload_includes_max_height_when_included(self):
        payload = self.noembed.build_payload(self.example_url, max_height=100)
        self.assertEqual(payload['maxheight'], 100)

    @patch('noembed.requests')
    def test_requests_get_is_called_with_endpoint_url_and_payload(self, mock_requests):
        mock_response = Mock()
        mock_response.json.return_value = {}
        mock_requests.get.return_value = mock_response
        self.noembed.embed(self.example_url, 100, 100)
        mock_requests.get.assert_called_once_with(
            noembed.NOEMBED_ENDPOINT_URL,
            params={'url': self.example_url, 'maxwidth':100, 'maxheight':100}
        )

    @patch('noembed.requests')
    def test_excption_raised_if_error_key_in_json(self, mock_requests):
        mock_response = Mock()
        mock_response.json.return_value = {
            'url': 'http://example.com',
            'error': 'This is an example error'
        }
        mock_requests.get.return_value = mock_response

        with self.assertRaises(noembed.NoEmbedException):
            self.noembed.embed(self.example_url)

    @patch('noembed.requests')
    def test_embed_returns_a_noembed_response(self, mock_requests):
        mock_response = Mock()
        mock_response.json.return_value = {}
        mock_requests.get.return_value = mock_response

        resp = self.noembed.embed(self.example_url)

        self.assertTrue(isinstance(resp, noembed.NoEmbedResponse))

    @patch('noembed.NoEmbedResponse')
    @patch('noembed.requests')
    def test_embed_passes_response_dict_to_noembed_response(self, mock_requests, mock_noembed_response):
        mock_response = Mock()
        mock_response.json.return_value = {'foo': 'bar'}
        mock_requests.get.return_value = mock_response

        noembed.embed(self.example_url)

        mock_noembed_response.assert_called_once_with({'foo': 'bar'})

class NoEmbedResponseTests(TestCase):
    def test_data_put_in_private_argument_on_init(self):
        data = {'a': 1, 'b': 2, 'c': 3}
        resp = noembed.NoEmbedResponse(data)
        self.assertEqual(data, resp._data)

    def test_data_items_set_as_attributes_on_init(self):
        data = {'a': 1, 'b': 2, 'c': 3}
        resp = noembed.NoEmbedResponse(data)
        for key, value in data.items():
            self.assertEqual(resp.__getattribute__(key), value)

class EmbedTests(TestCase):
    @patch('noembed.NoEmbed.embed')
    def test_embed_function_passes_all_args_and_kwargs_to_a_noembed_instances_embed_method(self, mock_noembed):
        noembed.embed('http://example.com', max_width=100, ax_height=100)

        mock_noembed.assert_called_once_with('http://example.com', max_width=100, ax_height=100)
<|endoftext|>


<commit_before>import django.urls
from django import test, urls
from django.contrib import auth
from django.contrib.sites import models as sites_models
from django.core import mail

import logging

HTTP_GET = 'get'
HTTP_POST = 'post'

HTTP_FORBIDDEN_OR_LOGIN = 'forbidden_or_login'
HTTP_REDIRECTS = 'redirects'
HTTP_OK = 'ok'

def get_url(url, *args):
    return django.urls.reverse(url, args=args)

class Test(test.TestCase):
    def assertContainsLink(self, response=None, link_url=None, key=None, obj=None):
        if response is None:
            response = self.client.get(obj.get_absolute_url())
        self.assertContains(response, self.get_link(link_url, key))

    def assertNotContainsLink(self, response=None, link_url=None, key=None, obj=None):
        if response is None:
            response = self.client.get(obj.get_absolute_url())
        self.assertNotContains(response, self.get_link(link_url, key))

    def assertExists(self, model, **kwargs):
        qs = model.objects.filter(**kwargs)
        self.assertEqual(qs.count(), 1)
        return qs.first()

    def assertNotExists(self, model, **kwargs):
        self.assertFalse(model.objects.filter(**kwargs))

    def assertForbidden(self, url=None, method='get'):
        response = getattr(self.client, method)(url)
        self.assertEqual(response.status_code, 403)

    def assertLogin(self, url=None, url_name=None, url_args=[], method='get'):
        if url is None:
            url = django.urls.reverse(url_name, args=url_args)
        response = getattr(self.client, method)(url)
        self.assertRedirects(response, self.get_login_url(url))

    def assertForbiddenOrLogin(self, response, next_url):
        if auth.get_user(self.client).is_authenticated:
            self.assertEqual(response.status_code, 403)
        else:
            self.assertRedirects(response, self.get_login_url(next_url))

    def assertOk(self, url):
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def assertRedirect(self, url, method, data, other=None):
        response = getattr(self.client, method)(url, data)
        self.assertRedirects(response, other or url)

    def assertNotificationRecipient(self, gestalt):
        found = False
        for notification in mail.outbox:
            if notification.to[0].find(gestalt.user.email):
                found = True
        self.assertTrue(found)

    def assertNotificationSenderAnonymous(self):
        self.assertTrue(self.get_latest_notification().from_email.startswith(
            sites_models.Site.objects.get_current().name))

    def assertNotificationSenderName(self, gestalt):
        self.assertTrue(self.get_latest_notification().from_email.startswith(str(gestalt)))

    def assertNotificationHeaderContent(self, header, content):
        self.assertTrue(content in self.get_latest_notification().extra_headers[header])

    def assertNotificationContains(self, text):
        self.assertIn(text, self.get_latest_notification().body)

    def assertNoNotificationSent(self):
        self.assertEqual(len(mail.outbox), 0)

    def assertNotificationSent(self):
        self.assertGreater(len(mail.outbox), 0)

    def assertNotificationsSent(self, num):
        self.assertEqual(len(mail.outbox), num)

    def assertRequest(self, methods=[HTTP_GET], **kwargs):
        for method in methods:
            response = self.request(method, **kwargs)
            tests = kwargs['response']
            if HTTP_FORBIDDEN_OR_LOGIN in tests:
                self.assertForbiddenOrLogin(response, self.get_url(
                    kwargs['url'], kwargs.get('key')))
            if HTTP_REDIRECTS in tests:
                url = tests[HTTP_REDIRECTS]
                if isinstance(url, tuple):
                    url = self.get_url(*url)
                self.assertRedirects(response, url)
            if HTTP_OK in tests:
                self.assertEqual(response.status_code, 200)

    def get_link(self, url, key):
        return 'href="{}"'.format(url)

    def get_login_url(self, next_url):
        return '{}?next={}'.format(urls.reverse('account_login'), next_url)

    def get_response(self, method, url):
        return getattr(self.client, method)(url)

    def get_latest_notification(self):
        return mail.outbox[-1]

    def get_url(self, url, key=None):
        if key is None:
            args = []
        elif isinstance(key, (list, tuple)):
            args = key
        else:
            args = [key]
        return urls.reverse(
                '{}'.format(url), args=args)

    def request(self, method, **kwargs):
        url = self.get_url(kwargs['url'], kwargs.get('key'))
        return self.get_response(method, url)

    def setUp(self):
        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)
<commit_msg>Fix evaluation of "assertNotificationRecipient"<commit_after>import django.urls
from django import test, urls
from django.contrib import auth
from django.contrib.sites import models as sites_models
from django.core import mail

import logging

HTTP_GET = 'get'
HTTP_POST = 'post'

HTTP_FORBIDDEN_OR_LOGIN = 'forbidden_or_login'
HTTP_REDIRECTS = 'redirects'
HTTP_OK = 'ok'

def get_url(url, *args):
    return django.urls.reverse(url, args=args)

class Test(test.TestCase):
    def assertContainsLink(self, response=None, link_url=None, key=None, obj=None):
        if response is None:
            response = self.client.get(obj.get_absolute_url())
        self.assertContains(response, self.get_link(link_url, key))

    def assertNotContainsLink(self, response=None, link_url=None, key=None, obj=None):
        if response is None:
            response = self.client.get(obj.get_absolute_url())
        self.assertNotContains(response, self.get_link(link_url, key))

    def assertExists(self, model, **kwargs):
        qs = model.objects.filter(**kwargs)
        self.assertEqual(qs.count(), 1)
        return qs.first()

    def assertNotExists(self, model, **kwargs):
        self.assertFalse(model.objects.filter(**kwargs))

    def assertForbidden(self, url=None, method='get'):
        response = getattr(self.client, method)(url)
        self.assertEqual(response.status_code, 403)

    def assertLogin(self, url=None, url_name=None, url_args=[], method='get'):
        if url is None:
            url = django.urls.reverse(url_name, args=url_args)
        response = getattr(self.client, method)(url)
        self.assertRedirects(response, self.get_login_url(url))

    def assertForbiddenOrLogin(self, response, next_url):
        if auth.get_user(self.client).is_authenticated:
            self.assertEqual(response.status_code, 403)
        else:
            self.assertRedirects(response, self.get_login_url(next_url))

    def assertOk(self, url):
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

    def assertRedirect(self, url, method, data, other=None):
        response = getattr(self.client, method)(url, data)
        self.assertRedirects(response, other or url)

    def _count_notifications_for_recipient(self, gestalt):
        count = 0
        for notification in mail.outbox:
            if gestalt.user.email in notification.to[0]:
                count += 1
        return count

    def assertNotificationRecipient(self, gestalt):
        self.assertGreater(self._count_notifications_for_recipient(gestalt), 0)

    def assertNotificationSenderAnonymous(self):
        self.assertTrue(self.get_latest_notification().from_email.startswith(
            sites_models.Site.objects.get_current().name))

    def assertNotificationSenderName(self, gestalt):
        self.assertTrue(self.get_latest_notification().from_email.startswith(str(gestalt)))

    def assertNotificationHeaderContent(self, header, content):
        self.assertTrue(content in self.get_latest_notification().extra_headers[header])

    def assertNotificationContains(self, text):
        self.assertIn(text, self.get_latest_notification().body)

    def assertNoNotificationSent(self):
        self.assertEqual(len(mail.outbox), 0)

    def assertNotificationSent(self):
        self.assertGreater(len(mail.outbox), 0)

    def assertNotificationsSent(self, num):
        self.assertEqual(len(mail.outbox), num)

    def assertRequest(self, methods=[HTTP_GET], **kwargs):
        for method in methods:
            response = self.request(method, **kwargs)
            tests = kwargs['response']
            if HTTP_FORBIDDEN_OR_LOGIN in tests:
                self.assertForbiddenOrLogin(response, self.get_url(
                    kwargs['url'], kwargs.get('key')))
            if HTTP_REDIRECTS in tests:
                url = tests[HTTP_REDIRECTS]
                if isinstance(url, tuple):
                    url = self.get_url(*url)
                self.assertRedirects(response, url)
            if HTTP_OK in tests:
                self.assertEqual(response.status_code, 200)

    def get_link(self, url, key):
        return 'href="{}"'.format(url)

    def get_login_url(self, next_url):
        return '{}?next={}'.format(urls.reverse('account_login'), next_url)

    def get_response(self, method, url):
        return getattr(self.client, method)(url)

    def get_latest_notification(self):
        return mail.outbox[-1]

    def get_url(self, url, key=None):
        if key is None:
            args = []
        elif isinstance(key, (list, tuple)):
            args = key
        else:
            args = [key]
        return urls.reverse(
                '{}'.format(url), args=args)

    def request(self, method, **kwargs):
        url = self.get_url(kwargs['url'], kwargs.get('key'))
        return self.get_response(method, url)

    def setUp(self):
        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)
<|endoftext|>


<commit_before>import unittest
from grasshopper import Framework

def i(**kwargs): pass

def a(**kwargs): pass

def b(**kwargs): pass

def c(**kwargs): pass

def d(**kwargs): pass

def e(**kwargs): pass

def f(**kwargs): pass

def g(**kwargs): pass

def h(**kwargs): pass

class TestLookup(unittest.TestCase):

    def setUp(self):
        app = Framework()
        app.get('/', i)
        app.get('/a/', a)
        app.get('/b', b)
        app.post('/b', b)
        app.get('/b/*', b)
        app.get('/b/*/d', d)
        app.get('/b/*/e', e)
        app.get('/b/f/g', g)
        app.get('/c', c)
        app.get('/c/f', f)
        app.get('/c/f/*', h)
        app.post('/c/f/*/a/*', a)
        app.delete('/c/f/*/a/*/b', b)
        self.app = app

    def test_basic(self):
        self.assertEqual(self.app.lookup('a', 'GET')[0], a)
        self.assertEqual(self.app.lookup('/a', 'GET')[0], a)
        self.assertEqual(self.app.lookup('a/', 'GET')[0], a)
        self.assertEqual(self.app.lookup('/a/', 'GET')[0], a)

        self.assertEqual(self.app.lookup('b', 'GET')[0], b)
        self.assertEqual(self.app.lookup('/b', 'GET')[0], b)
        self.assertEqual(self.app.lookup('b/', 'GET')[0], b)
        self.assertEqual(self.app.lookup('/b/', 'GET')[0], b)

    def test_nested(self):
        self.assertEqual(self.app.lookup('b/f/g', 'GET')[0], g)
        self.assertEqual(self.app.lookup('/b/f/g', 'GET')[0], g)
        self.assertEqual(self.app.lookup('b/f/g/', 'GET')[0], g)
        self.assertEqual(self.app.lookup('/b/f/g/', 'GET')[0], g)

    def test_wildcards(self):
        self.assertEqual(self.app.lookup('b/*/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('b/x/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('b/abc/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('/b/abc/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('/b/abc/e/', 'GET')[0], e)
        self.assertEqual(self.app.lookup('/b/abc', 'GET')[0], b)
        self.assertEqual(self.app.lookup('/c/f', 'GET')[0], f)
        self.assertEqual(self.app.lookup('/c/f/', 'GET')[0], f)
        self.assertEqual(self.app.lookup('/c/f/abc', 'GET')[0], h)

    def test_slash_agnostic(self):
        self.assertEqual(
            self.app.lookup('a', 'GET')[0],
            self.app.lookup('/a/', 'GET')[0])
        self.assertEqual(
            self.app.lookup('a/', 'GET')[0],
            self.app.lookup('/a/', 'GET')[0])
        self.assertEqual(
            self.app.lookup('/a', 'GET')[0],
            self.app.lookup('/a/', 'GET')[0])

        self.assertEqual(
            self.app.lookup('a', 'GET')[0],
            self.app.lookup('/a', 'GET')[0])
        self.assertEqual(
            self.app.lookup('a/', 'GET')[0],
            self.app.lookup('/a', 'GET')[0])

        self.assertEqual(
            self.app.lookup('a', 'GET')[0],
            self.app.lookup('a/', 'GET')[0])
        self.assertEqual(
            self.app.lookup('/a', 'GET')[0],
            self.app.lookup('a/', 'GET')[0])

    def test_wildcard_passing_arguments(self):
        self.assertEqual(
            self.app.lookup('b/abc/e', 'GET')[1],
            ['abc'])
        self.assertEqual(
            self.app.lookup('c/f/77e/a/something', 'POST')[1],
            ['77e', 'something'])
        self.assertEqual(
            self.app.lookup('c/f/77e/a/something/b', 'DELETE')[1],
            ['77e', 'something'])

class TestRouting(unittest.TestCase):
    def setUp(self):
        self.app = Framework()

    def test_order_doesnt_matter(self):
        from itertools import permutations
        routes = [
            ('/a', a),
            ('/a/*', b),
            ('/a/c', c),
        ]
        routes_permutations = permutations(routes, len(routes))
        for i, routes in enumerate(routes_permutations):
            app = Framework({'app': i})
            for route in routes:
                app.get(*route)
            self.assertEqual(app.lookup('/a', 'GET')[0], a, i)
            self.assertEqual(app.lookup('/a/x', 'GET')[0], b, i)
            self.assertEqual(app.lookup('/a/c', 'GET')[0], c, i)

if __name__ == "__main__":
    unittest.main()
<commit_msg>Add unit tests for non matching lookups<commit_after>import unittest
from grasshopper import Framework

def i(**kwargs): pass

def a(**kwargs): pass

def b(**kwargs): pass

def c(**kwargs): pass

def d(**kwargs): pass

def e(**kwargs): pass

def f(**kwargs): pass

def g(**kwargs): pass

def h(**kwargs): pass

class TestLookup(unittest.TestCase):

    def setUp(self):
        app = Framework()
        app.get('/', i)
        app.get('/a/', a)
        app.get('/b', b)
        app.post('/b', b)
        app.get('/b/*', b)
        app.get('/b/*/d', d)
        app.get('/b/*/e', e)
        app.get('/b/f/g', g)
        app.get('/c', c)
        app.get('/c/f', f)
        app.get('/c/f/*', h)
        app.post('/c/f/*/a/*', a)
        app.delete('/c/f/*/a/*/b', b)
        self.app = app

    def test_basic(self):
        self.assertEqual(self.app.lookup('a', 'GET')[0], a)
        self.assertEqual(self.app.lookup('/a', 'GET')[0], a)
        self.assertEqual(self.app.lookup('a/', 'GET')[0], a)
        self.assertEqual(self.app.lookup('/a/', 'GET')[0], a)

        self.assertEqual(self.app.lookup('b', 'GET')[0], b)
        self.assertEqual(self.app.lookup('/b', 'GET')[0], b)
        self.assertEqual(self.app.lookup('b/', 'GET')[0], b)
        self.assertEqual(self.app.lookup('/b/', 'GET')[0], b)

    def test_nested(self):
        self.assertEqual(self.app.lookup('b/f/g', 'GET')[0], g)
        self.assertEqual(self.app.lookup('/b/f/g', 'GET')[0], g)
        self.assertEqual(self.app.lookup('b/f/g/', 'GET')[0], g)
        self.assertEqual(self.app.lookup('/b/f/g/', 'GET')[0], g)

    def test_wildcards(self):
        self.assertEqual(self.app.lookup('b/*/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('b/x/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('b/abc/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('/b/abc/e', 'GET')[0], e)
        self.assertEqual(self.app.lookup('/b/abc/e/', 'GET')[0], e)
        self.assertEqual(self.app.lookup('/b/abc', 'GET')[0], b)
        self.assertEqual(self.app.lookup('/c/f', 'GET')[0], f)
        self.assertEqual(self.app.lookup('/c/f/', 'GET')[0], f)
        self.assertEqual(self.app.lookup('/c/f/abc', 'GET')[0], h)

    def test_slash_agnostic(self):
        self.assertEqual(
            self.app.lookup('a', 'GET')[0],
            self.app.lookup('/a/', 'GET')[0])
        self.assertEqual(
            self.app.lookup('a/', 'GET')[0],
            self.app.lookup('/a/', 'GET')[0])
        self.assertEqual(
            self.app.lookup('/a', 'GET')[0],
            self.app.lookup('/a/', 'GET')[0])

        self.assertEqual(
            self.app.lookup('a', 'GET')[0],
            self.app.lookup('/a', 'GET')[0])
        self.assertEqual(
            self.app.lookup('a/', 'GET')[0],
            self.app.lookup('/a', 'GET')[0])

        self.assertEqual(
            self.app.lookup('a', 'GET')[0],
            self.app.lookup('a/', 'GET')[0])
        self.assertEqual(
            self.app.lookup('/a', 'GET')[0],
            self.app.lookup('a/', 'GET')[0])

    def test_wildcard_passing_arguments(self):
        self.assertEqual(
            self.app.lookup('b/abc/e', 'GET')[1],
            ['abc'])
        self.assertEqual(
            self.app.lookup('c/f/77e/a/something', 'POST')[1],
            ['77e', 'something'])
        self.assertEqual(
            self.app.lookup('c/f/77e/a/something/b', 'DELETE')[1],
            ['77e', 'something'])

class Test404s(unittest.TestCase):
    def setUp(self):
        self.app = Framework()
        self.app.get('a/*', a)
        self.app.post('/c/f/*/a/*', a)
        self.app.put('/a/b/c', c)
        self.app.delete('/a/*/c', c)

    def test_wildcard_termination(self):
        self.assertEqual(self.app.lookup('/a', 'GET'), (None, []))
        self.assertEqual(self.app.lookup('c/f/x/a', 'POST'), (None, []))
        self.assertEqual(self.app.lookup('a/c/', 'DELETE'), (None, []))

    def test_wrong_url(self):
        self.assertEqual(self.app.lookup('/a/b', 'PUT'), (None, []))
        self.assertEqual(self.app.lookup('/a/b/c/d', 'PUT'), (None, []))
        self.assertEqual(self.app.lookup('/b/c', 'PUT'), (None, []))

class TestRouting(unittest.TestCase):
    def setUp(self):
        self.app = Framework()

    def test_order_doesnt_matter(self):
        from itertools import permutations
        routes = [
            ('/a', a),
            ('/a/*', b),
            ('/a/c', c),
        ]
        routes_permutations = permutations(routes, len(routes))
        for i, routes in enumerate(routes_permutations):
            app = Framework({'app': i})
            for route in routes:
                app.get(*route)
            self.assertEqual(app.lookup('/a', 'GET')[0], a, i)
            self.assertEqual(app.lookup('/a/x', 'GET')[0], b, i)
            self.assertEqual(app.lookup('/a/c', 'GET')[0], c, i)

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


<commit_before>#!/usr/bin/python3

# =============================================================================
# ================================================================== PARAMETERS

PathTests     = "refs"     # can be overrided by arg1 from the cmd line
PathResults   = "results"  # can be overrided by arg2 from the cmd line
PathBuild     = "../build"
Sensibility   = 1.0
Nthreads      = 0          # if 0 then AFF3CT takes all the available threads
RecursiveScan = True
MaxFE         = 100        # 0 takes fe from the original simulation
WeakRate      = 0.8        # 0 < WeakRate < 1
MaxTimeSNR    = 1        # max time to spend per SNR (in sec), 0 = illimited

# ================================================================== PARAMETERS
# =============================================================================

# =============================================================================
# ==================================================================== PACKAGES

import os
import sys
import math
import pathlib
import subprocess

# ==================================================================== PACKAGES
# =============================================================================

# =============================================================================
# =================================================================== FUNCTIONS

def recursivelyGetFilenames(currentPath, fileNames):
	if not os.path.exists(currentPath.replace(PathTests, PathResults)):
		os.makedirs(currentPath.replace(PathTests, PathResults))

	files = os.listdir(currentPath)
	for f in files:
		if ".empty" in f:
			continue
		if "~" in f:
			continue
		if os.path.isdir(currentPath + "/" + f):
			newCurrentPath = currentPath + "/" + f
			recursivelyGetFilenames(newCurrentPath, fileNames)
		else:
			fileNames.append(currentPath.replace(PathTests + "/", "") + "/" + f)

# -----

# =================================================================== FUNCTIONS
# =============================================================================

# =============================================================================
# ======================================================================== MAIN

if len(sys.argv) >= 2:
	PathTests = sys.argv[1]

if len(sys.argv) >= 3:
	PathResults = sys.argv[2]

PathOrigin = os.getcwd()

# get the filenames to test
fileNames = []
fileNamesTmp = os.listdir(PathTests)
for f in fileNamesTmp:
	if not os.path.isdir(PathTests + "/" + f):
		fileNames.append(f)
	else:
		if RecursiveScan:
			recursivelyGetFilenames(PathTests + "/" + f, fileNames)

print("Starting the test script...")

testId = 0
for fn in fileNames:

	if pathlib.Path(fn).suffix != ".txt" and pathlib.Path(fn).suffix != ".perf" and pathlib.Path(fn).suffix != ".data" and pathlib.Path(fn).suffix != ".dat":
		continue

	print("Test n°" + str(testId) + " - " + fn, end="", flush=True);

	# open the file in read mode (from the fileName "fn" and the path)
	f = open(PathTests + "/" + fn, 'r')

	# read all the lines from the current file f
	lines = []
	for line in f:
		lines.append(line)

	# get the main infos from the lines
	runCommand = lines[1].strip()

	currentSection = ""
	idx = 0
	simuRef = []
	for l in lines:
		# avoid the first lines and the comments
		if idx > 6 and l.replace(" ", "") != "" and l.replace(" ", "") != "\n" and l[0] != '#':
			simuRef.append(l.strip().replace("||", "|").replace(" ", "").split("|"))
		idx = idx +1

	f.close()

	# split the run command
	argsAFFECT = [""]
	idx = 0

	new = 0
	found_dashes = 0
	for s in runCommand:
		if found_dashes == 0:
			if s == ' ':
				if new == 0:
					argsAFFECT.append("")
					idx = idx + 1
					new = 1

			elif s == '\"':
				if new == 0:
					argsAFFECT.append("")
					idx = idx + 1
					new = 1
				found_dashes = 1

			else:
				argsAFFECT[idx] += s
				new = 0

		else: # between dashes
			if s == '\"':
				argsAFFECT.append("")
				idx = idx + 1
				found_dashes = 0

			else:
				argsAFFECT[idx] += s

	del argsAFFECT[idx]

	argsAFFECT.append("--ter-freq")
	argsAFFECT.append("0")
	if MaxFE:
		argsAFFECT.append("-e")
		argsAFFECT.append(str(MaxFE))
	argsAFFECT.append("-t")
	argsAFFECT.append(str(Nthreads))
	argsAFFECT.append("--sim-no-colors")
	if MaxTimeSNR:
		argsAFFECT.append("--sim-stop-time")
		argsAFFECT.append(str(MaxTimeSNR))

	os.chdir(PathBuild)
	processAFFECT = subprocess.Popen(argsAFFECT, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	(stdoutAFFECT, stderrAFFECT) = processAFFECT.communicate()

	err = stderrAFFECT.decode(encoding='UTF-8')
	if err:
		print(" - ABORTED.", end="\n");
		print("Error message:", end="\n");
		print(err)
	else:
		# begin to write the results into a file
		os.chdir(PathOrigin)

		fRes = open(PathResults + "/" + fn, 'w+')

		# parse the results
		stdOutput = stdoutAFFECT.decode(encoding='UTF-8').split("\n")
		outputAFFECTLines = []
		simuCur = []
		for l in stdOutput:
			if l != "" and l[0] != '#' and l[0] != "(": # avoid the first lines and the comments
				array = l.strip().replace("||", "|").replace(" ", "").split("|")
				if (len(array) == 12 or len(array) == 9):
					outputAFFECTLines.append(l)
					simuCur.append(array)
				else:
					fRes.write(l + "\n")
			elif l != "" and l[0] == '#' and "# End of the simulation." not in l:
				fRes.write(l + "\n")

		fRes.flush()

		# validate (or not) the BER/FER performance
		valid = 0;
		idx = 0
		for ref in simuRef:
			numRef = float(ref[6][0:4])
			powerRef = int(ref[6][6:8])
			try:
				numCur = float(simuCur[idx][6][0:4])
				powerCur = int(simuCur[idx][6][6:8])
			except IndexError: # no such line
				break

			if powerRef - powerCur != 0:
				if powerRef > powerCur:
					numCur = numCur * 10**(math.fabs(powerRef - powerCur))
				else:
					numRef = numRef * 10**(math.fabs(powerRef - powerCur))

			absoluteNumDiff = math.fabs(numRef - numCur)
			if absoluteNumDiff > Sensibility:
				fRes.write(outputAFFECTLines[idx] + "WRONG! FER=" + ref[6][0:8] + "\n")
			else:
				valid = valid + 1
				fRes.write(outputAFFECTLines[idx] + "\n")

			cur_fe = int(simuCur[idx][4])

			idx = idx + 1

			if cur_fe < MaxFE:
				break

		if valid == idx:
			print(" - STRONG PASSED.", end="\n");
		elif idx != 0 and float(valid) / float(idx) >= WeakRate:
			print(" - WEAK PASSED.", end="\n");
		else:
			print(" - FAILED.", end="\n");

		fRes.write("# End of the simulation.\n")
		fRes.close();

	testId = testId + 1

# ======================================================================== MAIN
# =============================================================================
<commit_msg>Modify test time per SNR<commit_after>#!/usr/bin/python3

# =============================================================================
# ================================================================== PARAMETERS

PathTests     = "refs"     # can be overrided by arg1 from the cmd line
PathResults   = "results"  # can be overrided by arg2 from the cmd line
PathBuild     = "../build"
Sensibility   = 1.0
Nthreads      = 0          # if 0 then AFF3CT takes all the available threads
RecursiveScan = True
MaxFE         = 100        # 0 takes fe from the original simulation
WeakRate      = 0.8        # 0 < WeakRate < 1
MaxTimeSNR    = 600        # max time to spend per SNR (in sec), 0 = illimited

# ================================================================== PARAMETERS
# =============================================================================

# =============================================================================
# ==================================================================== PACKAGES

import os
import sys
import math
import pathlib
import subprocess

# ==================================================================== PACKAGES
# =============================================================================

# =============================================================================
# =================================================================== FUNCTIONS

def recursivelyGetFilenames(currentPath, fileNames):
	if not os.path.exists(currentPath.replace(PathTests, PathResults)):
		os.makedirs(currentPath.replace(PathTests, PathResults))

	files = os.listdir(currentPath)
	for f in files:
		if ".empty" in f:
			continue
		if "~" in f:
			continue
		if os.path.isdir(currentPath + "/" + f):
			newCurrentPath = currentPath + "/" + f
			recursivelyGetFilenames(newCurrentPath, fileNames)
		else:
			fileNames.append(currentPath.replace(PathTests + "/", "") + "/" + f)

# -----

# =================================================================== FUNCTIONS
# =============================================================================

# =============================================================================
# ======================================================================== MAIN

if len(sys.argv) >= 2:
	PathTests = sys.argv[1]

if len(sys.argv) >= 3:
	PathResults = sys.argv[2]

PathOrigin = os.getcwd()

# get the filenames to test
fileNames = []
fileNamesTmp = os.listdir(PathTests)
for f in fileNamesTmp:
	if not os.path.isdir(PathTests + "/" + f):
		fileNames.append(f)
	else:
		if RecursiveScan:
			recursivelyGetFilenames(PathTests + "/" + f, fileNames)

print("Starting the test script...")

testId = 0
for fn in fileNames:

	if pathlib.Path(fn).suffix != ".txt" and pathlib.Path(fn).suffix != ".perf" and pathlib.Path(fn).suffix != ".data" and pathlib.Path(fn).suffix != ".dat":
		continue

	print("Test n°" + str(testId) + " - " + fn, end="", flush=True);

	# open the file in read mode (from the fileName "fn" and the path)
	f = open(PathTests + "/" + fn, 'r')

	# read all the lines from the current file f
	lines = []
	for line in f:
		lines.append(line)

	# get the main infos from the lines
	runCommand = lines[1].strip()

	currentSection = ""
	idx = 0
	simuRef = []
	for l in lines:
		# avoid the first lines and the comments
		if idx > 6 and l.replace(" ", "") != "" and l.replace(" ", "") != "\n" and l[0] != '#':
			simuRef.append(l.strip().replace("||", "|").replace(" ", "").split("|"))
		idx = idx +1

	f.close()

	# split the run command
	argsAFFECT = [""]
	idx = 0

	new = 0
	found_dashes = 0
	for s in runCommand:
		if found_dashes == 0:
			if s == ' ':
				if new == 0:
					argsAFFECT.append("")
					idx = idx + 1
					new = 1

			elif s == '\"':
				if new == 0:
					argsAFFECT.append("")
					idx = idx + 1
					new = 1
				found_dashes = 1

			else:
				argsAFFECT[idx] += s
				new = 0

		else: # between dashes
			if s == '\"':
				argsAFFECT.append("")
				idx = idx + 1
				found_dashes = 0

			else:
				argsAFFECT[idx] += s

	del argsAFFECT[idx]

	argsAFFECT.append("--ter-freq")
	argsAFFECT.append("0")
	if MaxFE:
		argsAFFECT.append("-e")
		argsAFFECT.append(str(MaxFE))
	argsAFFECT.append("-t")
	argsAFFECT.append(str(Nthreads))
	argsAFFECT.append("--sim-no-colors")
	if MaxTimeSNR:
		argsAFFECT.append("--sim-stop-time")
		argsAFFECT.append(str(MaxTimeSNR))

	os.chdir(PathBuild)
	processAFFECT = subprocess.Popen(argsAFFECT, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	(stdoutAFFECT, stderrAFFECT) = processAFFECT.communicate()

	err = stderrAFFECT.decode(encoding='UTF-8')
	if err:
		print(" - ABORTED.", end="\n");
		print("Error message:", end="\n");
		print(err)
	else:
		# begin to write the results into a file
		os.chdir(PathOrigin)

		fRes = open(PathResults + "/" + fn, 'w+')

		# parse the results
		stdOutput = stdoutAFFECT.decode(encoding='UTF-8').split("\n")
		outputAFFECTLines = []
		simuCur = []
		for l in stdOutput:
			if l != "" and l[0] != '#' and l[0] != "(": # avoid the first lines and the comments
				array = l.strip().replace("||", "|").replace(" ", "").split("|")
				if (len(array) == 12 or len(array) == 9):
					outputAFFECTLines.append(l)
					simuCur.append(array)
				else:
					fRes.write(l + "\n")
			elif l != "" and l[0] == '#' and "# End of the simulation." not in l:
				fRes.write(l + "\n")

		fRes.flush()

		# validate (or not) the BER/FER performance
		valid = 0;
		idx = 0
		for ref in simuRef:
			numRef = float(ref[6][0:4])
			powerRef = int(ref[6][6:8])
			try:
				numCur = float(simuCur[idx][6][0:4])
				powerCur = int(simuCur[idx][6][6:8])
			except IndexError: # no such line
				break

			if powerRef - powerCur != 0:
				if powerRef > powerCur:
					numCur = numCur * 10**(math.fabs(powerRef - powerCur))
				else:
					numRef = numRef * 10**(math.fabs(powerRef - powerCur))

			absoluteNumDiff = math.fabs(numRef - numCur)
			if absoluteNumDiff > Sensibility:
				fRes.write(outputAFFECTLines[idx] + "WRONG! FER=" + ref[6][0:8] + "\n")
			else:
				valid = valid + 1
				fRes.write(outputAFFECTLines[idx] + "\n")

			cur_fe = int(simuCur[idx][4])

			idx = idx + 1

			if cur_fe < MaxFE:
				break

		if valid == idx:
			print(" - STRONG PASSED.", end="\n");
		elif idx != 0 and float(valid) / float(idx) >= WeakRate:
			print(" - WEAK PASSED.", end="\n");
		else:
			print(" - FAILED.", end="\n");

		fRes.write("# End of the simulation.\n")
		fRes.close();

	testId = testId + 1

# ======================================================================== MAIN
# =============================================================================
<|endoftext|>


<commit_before># coding=utf-8

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import sys
import os
from datetime import datetime

try:
    from ansible.utils.color import colorize, hostcolor
    from ansible.plugins.callback import CallbackBase
except ImportError:
    class CallbackBase:
        # pylint: disable=I0011,R0903
        pass

import unittest

# Fields we would like to see before the others, in this order, please...
PREFERED_FIELDS = ['stdout', 'rc', 'stderr', 'start', 'end', 'msg']
# Fields we will delete from the result
DELETABLE_FIELDS = [
    'stdout', 'stdout_lines', 'rc', 'stderr', 'start', 'end', 'msg',
    '_ansible_verbose_always', '_ansible_no_log', 'invocation', '_ansible_parsed',
    '_ansible_item_result', '_ansible_ignore_errors', '_ansible_item_label']

CHANGED = 'yellow'
UNCHANGED = 'green'

def deep_serialize(data, indent=0):
    # pylint: disable=I0011,E0602,R0912,W0631

    padding = " " * indent * 2
    if isinstance(data, list):
        if data == []:
            return "[]"
        output = "[ "
        if len(data) == 1:
            output = output + \
                ("\n" +
                 padding).join(deep_serialize(data[0], 0).splitlines()) + " ]"
        else:
            list_padding = " " * (indent + 1) * 2

            for item in data:
                output = output + "\n" + list_padding + "- " + \
                    deep_serialize(item, indent)
            output = output + "\n" + padding + " ]"
    elif isinstance(data, dict):
        if "_ansible_no_log" in data and data["_ansible_no_log"]:
            data = {"censored":
                    "the output has been hidden due to the fact that"
                    " 'no_log: true' was specified for this result"}
        list_padding = " " * (indent + 1) * 2
        output = "{\n"

        for key in PREFERED_FIELDS:
            if key in data.keys():
                value = data[key]
                prefix = list_padding + "- %s: " % key
                output = output + prefix + "%s\n" % \
                    "\n".join([" " * len(prefix) + line
                               for line in deep_serialize(value, indent)
                               .splitlines()]).strip()

        for key in DELETABLE_FIELDS:
            if key in data.keys():
                del data[key]

        for key, value in data.items():
            output = output + list_padding + \
                "- %s: %s\n" % (key, deep_serialize(value, indent + 1))

        output = output + padding + "}"
    else:
        string_form = str(data)
        if len(string_form) == 0:
            return "\"\""

        return string_form
    return output

class TestStringMethods(unittest.TestCase):

    test_structure = {
        u'cmd': [u'false'], u'end': u'2016-12-29 16:46:04.151591',
        '_ansible_no_log': False, u'stdout': u'', u'changed': True, 'failed': True,
        u'delta': u'0:00:00.005046', u'stderr': u'', u'rc': 1, 'invocation':
            {'module_name': u'command',
             u'module_args': {
                 u'creates': None, u'executable': None, u'chdir': None,
                 u'_raw_params': u'false', u'removes': None,
                 u'warn': True, u'_uses_shell': False}},
        'stdout_lines': [], u'start': u'2016-12-29 16:46:04.146545', u'warnings': []}

    def test_single_item_array(self):
        self.assertEqual(
            deep_serialize(self.test_structure['cmd']),
            "[ false ]")

    def test_single_empty_item_array(self):
        self.assertEqual(
            deep_serialize([""]),
            "[ \"\" ]")

    def test_issue_4(self):
        self.assertEqual(
            deep_serialize(["ÉLÉGANT"]),
            "[ ÉLÉGANT ]")

    def test_empty_array(self):
        self.assertEqual(
            deep_serialize(self.test_structure['stdout_lines']),
            "[]")

    def test_simple_hash(self):
        hs = {"cmd": "toto", "ret": 12}
        expected_result = "{\n  - cmd: toto\n  - ret: 12\n}"
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_hash_array(self):
        hs = {u'cmd': [u'false']}
        expected_result = "{\n  - cmd: [ false ]\n}"
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_hash_array2(self):
        hs = {u'cmd': ['one', 'two']}
        expected_result = """{
  - cmd: [
    - one
    - two
   ]
}"""
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_favorite_hash(self):
        hs = {"cmd": "toto", "rc": 12}
        expected_result = "{\n  - rc: 12\n  - cmd: toto\n}"
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_nested(self):
        hs = {u'cmd': {'bar': ['one', 'two']}}
        expected_result = """{
  - cmd: {
    - bar: [
      - one
      - two
     ]
  }
}"""
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_multiline_single(self):
        # pylint: disable=I0011,C0303
        hs = [["foo", "bar"]]
        expected_result = """[ [
  - foo
  - bar
 ] ]"""
        # print(deep_serialize(hs))
        # print(expected_result)
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_empty_array_no_padding(self):
        hs = [[{"foo": []}]]
        expected_result = """[ [ {
  - foo: []
} ] ]"""
        # print(deep_serialize(hs))
        # print(expected_result)
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_hidden_fields(self):
        hs = {"_ansible_verbose_always": True}
        expected_result = """{
}"""
        # print(deep_serialize(hs))
        # print(expected_result)
        self.assertEqual(deep_serialize(hs), expected_result)

class CallbackModule(CallbackBase):

    '''
    This is the default callback interface, which simply prints messages
    to stdout when new callback events are received.
    '''

    CALLBACK_VERSION = 2.0
    CALLBACK_TYPE = 'stdout'
    CALLBACK_NAME = 'anstomlog'

    def _get_duration(self):
        end = datetime.now()
        total_duration = (end - self.task_started)
        seconds = total_duration.total_seconds()
        if seconds >= 60:
            seconds_remaining = seconds % 60
            minutes = (seconds - seconds_remaining) / 60
            duration = "{0:.0f}m{1:.0f}s".format(minutes, seconds_remaining)
        elif seconds >= 1:
            duration = "{0:.2f}s".format(seconds)
        else:
            duration = "{0:.0f}ms".format(seconds * 1000)
        return duration

    def _command_generic_msg(self, hostname, result, caption):
        duration = self._get_duration()

        stdout = result.get('stdout', '')
        if self._display.verbosity > 0:
            if 'stderr' in result and result['stderr']:
                stderr = result.get('stderr', '')
                return "%s | %s | %s | rc=%s | stdout: \n%s\n\n\t\t\t\tstderr: %s" % \
                    (hostname, caption, duration,
                     result.get('rc', 0), stdout, stderr)

            if len(stdout) > 0:
                return "%s | %s | %s | rc=%s | stdout: \n%s\n" % \
                    (hostname, caption, duration, result.get('rc', 0), stdout)

            return "%s | %s | %s | rc=%s | no stdout" % \
                (hostname, caption, duration, result.get('rc', 0))

        return "%s | %s | %s | rc=%s" % (hostname, caption, duration, result.get('rc', 0))

    def v2_playbook_on_task_start(self, task, is_conditional):
        parentTask = task.get_first_parent_include()
        if parentTask is not None:
            sectionName = task._role.get_name()
            if parentTask.action.endswith('tasks'):
                sectionName = os.path.splitext(os.path.basename(task.get_path()))[0]
            self._open_section("  ↳ {} : {}".format(sectionName, task.name))
        else:
            self._open_section(task.get_name(), task.get_path())

    def _open_section(self, section_name, path=None):
        self.task_started = datetime.now()

        prefix = ''
        ts = self.task_started.strftime("%H:%M:%S")

        if self._display.verbosity > 1:
            if path:
                self._emit_line("[{}]: {}".format(ts, path))
        self.task_start_preamble = "[{}]{} {} ...".format(ts, prefix, section_name)
        sys.stdout.write(self.task_start_preamble)

    def v2_playbook_on_handler_task_start(self, task):
        self._emit_line("triggering handler | %s " % task.get_name().strip())

    def v2_runner_on_failed(self, result, ignore_errors=False):
        duration = self._get_duration()
        host_string = self._host_string(result)

        if 'exception' in result._result:
            exception_message = "An exception occurred during task execution."
            if self._display.verbosity < 3:
                # extract just the actual error message from the exception text
                error = result._result['exception'].strip().split('\n')[-1]
                msg = exception_message + \
                    "To see the full traceback, use -vvv. The error was: %s" % error
            else:
                msg = exception_message + \
                    "The full traceback is:\n" + \
                    result._result['exception'].replace('\n', '')

                self._emit_line(msg, color='red')

        self._emit_line("%s | FAILED | %s" %
                        (host_string,
                         duration), color='red')
        self._emit_line(deep_serialize(result._result), color='red')

    def v2_on_file_diff(self, result):

        if result._task.loop and 'results' in result._result:
            for res in result._result['results']:
                if 'diff' in res and res['diff'] and res.get('changed', False):
                    diff = self._get_diff(res['diff'])
                    if diff:
                        self._emit_line(diff)

        elif 'diff' in result._result and \
                result._result['diff'] and \
                result._result.get('changed', False):
            diff = self._get_diff(result._result['diff'])
            if diff:
                self._emit_line(diff)

    @staticmethod
    def _host_string(result):
        delegated_vars = result._result.get('_ansible_delegated_vars', None)

        if delegated_vars:
            host_string = "%s -> %s" % (
                result._host.get_name(), delegated_vars['ansible_host'])
        else:
            host_string = result._host.get_name()

        return host_string

    def v2_runner_on_ok(self, result):
        duration = self._get_duration()

        self._clean_results(result._result, result._task.action)

        host_string = self._host_string(result)

        self._clean_results(result._result, result._task.action)

        if result._task.action in ('include', 'include_role', 'include_tasks'):
            sys.stdout.write("\b\b\b\b ")
            if result._task.action in ('include', 'include_role'):
                sys.stdout.write("    \n")
            return

        msg, color = self._changed_or_not(result._result, host_string)

        if result._task.loop and self._display.verbosity > 0 and 'results' in result._result:
            for item in result._result['results']:
                msg, color = self._changed_or_not(item, host_string)
                item_msg = "%s - item=%s" % (msg, self._get_item(item))
                self._emit_line("%s | %s" %
                                (item_msg, duration), color=color)
        else:
            self._emit_line("%s | %s" %
                            (msg, duration), color=color)
        self._handle_warnings(result._result)

        if ((self._display.verbosity > 0 or '_ansible_verbose_always' in result._result)
                and not '_ansible_verbose_override' in result._result):
            self._emit_line(deep_serialize(result._result), color=color)

        result._preamble = self.task_start_preamble

    @staticmethod
    def _changed_or_not(result, host_string):
        if result.get('changed', False):
            msg = "%s | CHANGED" % host_string
            color = CHANGED
        else:
            msg = "%s | SUCCESS" % host_string
            color = UNCHANGED

        return [msg, color]

    def _emit_line(self, lines, color='green'):

        if self.task_start_preamble is None:
            self._open_section("system")

        if self.task_start_preamble.endswith(" ..."):
            sys.stdout.write("\b\b\b\b | ")
            self.task_start_preamble = " "

        for line in lines.splitlines():
            self._display.display(line, color=color)

    def v2_runner_on_unreachable(self, result):
        self._emit_line("%s | UNREACHABLE!: %s" %
                        (self._host_string(result), result._result.get('msg', '')), color=CHANGED)

    def v2_runner_on_skipped(self, result):
        duration = self._get_duration()

        self._emit_line("%s | SKIPPED | %s" %
                        (self._host_string(result), duration), color='cyan')

    def v2_playbook_on_include(self, included_file):
        if self.task_start_preamble.endswith(" ..."):
            self.task_start_preamble = " "
            msg = '| {} | {} | {}'.format(
                ", ".join([h.name for h in included_file._hosts]),
                'INCLUDED',
                os.path.basename(included_file._filename))
            self._display.display(msg, color='cyan')

    def v2_playbook_on_stats(self, stats):
        self._open_section("system")
        self._emit_line("-- Play recap --")

        hosts = sorted(stats.processed.keys())
        for h in hosts:
            t = stats.summarize(h)

            self._emit_line(u"%s : %s %s %s %s" % (
                hostcolor(h, t),
                colorize(u'ok', t['ok'], UNCHANGED),
                colorize(u'changed', t['changed'], CHANGED),
                colorize(u'unreachable', t['unreachable'], CHANGED),
                colorize(u'failed', t['failures'], 'red')))

    def __init__(self, *args, **kwargs):
        super(CallbackModule, self).__init__(*args, **kwargs)
        self.task_started = datetime.now()
        self.task_start_preamble = None
        # python2 only
        try:
            reload(sys).setdefaultencoding('utf8')
        # pylint: disable=W0702
        except:
            pass

if __name__ == '__main__':
    unittest.main()
<commit_msg>chore(callback): Use ansible color<commit_after># coding=utf-8

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import sys
import os
from datetime import datetime

try:
    from ansible.utils.color import colorize, hostcolor
    from ansible.plugins.callback import CallbackBase
    from ansible import constants as C
except ImportError:
    class CallbackBase:
        # pylint: disable=I0011,R0903
        pass
    class C:
        COLOR_OK = 'green'

import unittest

# Fields we would like to see before the others, in this order, please...
PREFERED_FIELDS = ['stdout', 'rc', 'stderr', 'start', 'end', 'msg']
# Fields we will delete from the result
DELETABLE_FIELDS = [
    'stdout', 'stdout_lines', 'rc', 'stderr', 'start', 'end', 'msg',
    '_ansible_verbose_always', '_ansible_no_log', 'invocation', '_ansible_parsed',
    '_ansible_item_result', '_ansible_ignore_errors', '_ansible_item_label']

def deep_serialize(data, indent=0):
    # pylint: disable=I0011,E0602,R0912,W0631

    padding = " " * indent * 2
    if isinstance(data, list):
        if data == []:
            return "[]"
        output = "[ "
        if len(data) == 1:
            output = output + \
                ("\n" +
                 padding).join(deep_serialize(data[0], 0).splitlines()) + " ]"
        else:
            list_padding = " " * (indent + 1) * 2

            for item in data:
                output = output + "\n" + list_padding + "- " + \
                    deep_serialize(item, indent)
            output = output + "\n" + padding + " ]"
    elif isinstance(data, dict):
        if "_ansible_no_log" in data and data["_ansible_no_log"]:
            data = {"censored":
                    "the output has been hidden due to the fact that"
                    " 'no_log: true' was specified for this result"}
        list_padding = " " * (indent + 1) * 2
        output = "{\n"

        for key in PREFERED_FIELDS:
            if key in data.keys():
                value = data[key]
                prefix = list_padding + "- %s: " % key
                output = output + prefix + "%s\n" % \
                    "\n".join([" " * len(prefix) + line
                               for line in deep_serialize(value, indent)
                               .splitlines()]).strip()

        for key in DELETABLE_FIELDS:
            if key in data.keys():
                del data[key]

        for key, value in data.items():
            output = output + list_padding + \
                "- %s: %s\n" % (key, deep_serialize(value, indent + 1))

        output = output + padding + "}"
    else:
        string_form = str(data)
        if len(string_form) == 0:
            return "\"\""

        return string_form
    return output

class TestStringMethods(unittest.TestCase):

    test_structure = {
        u'cmd': [u'false'], u'end': u'2016-12-29 16:46:04.151591',
        '_ansible_no_log': False, u'stdout': u'', u'changed': True, 'failed': True,
        u'delta': u'0:00:00.005046', u'stderr': u'', u'rc': 1, 'invocation':
            {'module_name': u'command',
             u'module_args': {
                 u'creates': None, u'executable': None, u'chdir': None,
                 u'_raw_params': u'false', u'removes': None,
                 u'warn': True, u'_uses_shell': False}},
        'stdout_lines': [], u'start': u'2016-12-29 16:46:04.146545', u'warnings': []}

    def test_single_item_array(self):
        self.assertEqual(
            deep_serialize(self.test_structure['cmd']),
            "[ false ]")

    def test_single_empty_item_array(self):
        self.assertEqual(
            deep_serialize([""]),
            "[ \"\" ]")

    def test_issue_4(self):
        self.assertEqual(
            deep_serialize(["ÉLÉGANT"]),
            "[ ÉLÉGANT ]")

    def test_empty_array(self):
        self.assertEqual(
            deep_serialize(self.test_structure['stdout_lines']),
            "[]")

    def test_simple_hash(self):
        hs = {"cmd": "toto", "ret": 12}
        expected_result = "{\n  - cmd: toto\n  - ret: 12\n}"
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_hash_array(self):
        hs = {u'cmd': [u'false']}
        expected_result = "{\n  - cmd: [ false ]\n}"
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_hash_array2(self):
        hs = {u'cmd': ['one', 'two']}
        expected_result = """{
  - cmd: [
    - one
    - two
   ]
}"""
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_favorite_hash(self):
        hs = {"cmd": "toto", "rc": 12}
        expected_result = "{\n  - rc: 12\n  - cmd: toto\n}"
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_nested(self):
        hs = {u'cmd': {'bar': ['one', 'two']}}
        expected_result = """{
  - cmd: {
    - bar: [
      - one
      - two
     ]
  }
}"""
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_multiline_single(self):
        # pylint: disable=I0011,C0303
        hs = [["foo", "bar"]]
        expected_result = """[ [
  - foo
  - bar
 ] ]"""
        # print(deep_serialize(hs))
        # print(expected_result)
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_empty_array_no_padding(self):
        hs = [[{"foo": []}]]
        expected_result = """[ [ {
  - foo: []
} ] ]"""
        # print(deep_serialize(hs))
        # print(expected_result)
        self.assertEqual(deep_serialize(hs), expected_result)

    def test_hidden_fields(self):
        hs = {"_ansible_verbose_always": True}
        expected_result = """{
}"""
        # print(deep_serialize(hs))
        # print(expected_result)
        self.assertEqual(deep_serialize(hs), expected_result)

class CallbackModule(CallbackBase):

    '''
    This is the default callback interface, which simply prints messages
    to stdout when new callback events are received.
    '''

    CALLBACK_VERSION = 2.0
    CALLBACK_TYPE = 'stdout'
    CALLBACK_NAME = 'anstomlog'

    def _get_duration(self):
        end = datetime.now()
        total_duration = (end - self.task_started)
        seconds = total_duration.total_seconds()
        if seconds >= 60:
            seconds_remaining = seconds % 60
            minutes = (seconds - seconds_remaining) / 60
            duration = "{0:.0f}m{1:.0f}s".format(minutes, seconds_remaining)
        elif seconds >= 1:
            duration = "{0:.2f}s".format(seconds)
        else:
            duration = "{0:.0f}ms".format(seconds * 1000)
        return duration

    def _command_generic_msg(self, hostname, result, caption):
        duration = self._get_duration()

        stdout = result.get('stdout', '')
        if self._display.verbosity > 0:
            if 'stderr' in result and result['stderr']:
                stderr = result.get('stderr', '')
                return "%s | %s | %s | rc=%s | stdout: \n%s\n\n\t\t\t\tstderr: %s" % \
                    (hostname, caption, duration,
                     result.get('rc', 0), stdout, stderr)

            if len(stdout) > 0:
                return "%s | %s | %s | rc=%s | stdout: \n%s\n" % \
                    (hostname, caption, duration, result.get('rc', 0), stdout)

            return "%s | %s | %s | rc=%s | no stdout" % \
                (hostname, caption, duration, result.get('rc', 0))

        return "%s | %s | %s | rc=%s" % (hostname, caption, duration, result.get('rc', 0))

    def v2_playbook_on_task_start(self, task, is_conditional):
        parentTask = task.get_first_parent_include()
        if parentTask is not None:
            sectionName = task._role.get_name()
            if parentTask.action.endswith('tasks'):
                sectionName = os.path.splitext(os.path.basename(task.get_path()))[0]
            self._open_section("  ↳ {} : {}".format(sectionName, task.name))
        else:
            self._open_section(task.get_name(), task.get_path())

    def _open_section(self, section_name, path=None):
        self.task_started = datetime.now()

        prefix = ''
        ts = self.task_started.strftime("%H:%M:%S")

        if self._display.verbosity > 1:
            if path:
                self._emit_line("[{}]: {}".format(ts, path))
        self.task_start_preamble = "[{}]{} {} ...".format(ts, prefix, section_name)
        sys.stdout.write(self.task_start_preamble)

    def v2_playbook_on_handler_task_start(self, task):
        self._emit_line("triggering handler | %s " % task.get_name().strip())

    def v2_runner_on_failed(self, result, ignore_errors=False):
        duration = self._get_duration()
        host_string = self._host_string(result)

        if 'exception' in result._result:
            exception_message = "An exception occurred during task execution."
            if self._display.verbosity < 3:
                # extract just the actual error message from the exception text
                error = result._result['exception'].strip().split('\n')[-1]
                msg = exception_message + \
                    "To see the full traceback, use -vvv. The error was: %s" % error
            else:
                msg = exception_message + \
                    "The full traceback is:\n" + \
                    result._result['exception'].replace('\n', '')

                self._emit_line(msg, color=C.COLOR_ERROR)

        self._emit_line("%s | FAILED | %s" %
                        (host_string,
                         duration), color=C.COLOR_ERROR)
        self._emit_line(deep_serialize(result._result), color=C.COLOR_ERROR)

    def v2_on_file_diff(self, result):

        if result._task.loop and 'results' in result._result:
            for res in result._result['results']:
                if 'diff' in res and res['diff'] and res.get('changed', False):
                    diff = self._get_diff(res['diff'])
                    if diff:
                        self._emit_line(diff)

        elif 'diff' in result._result and \
                result._result['diff'] and \
                result._result.get('changed', False):
            diff = self._get_diff(result._result['diff'])
            if diff:
                self._emit_line(diff)

    @staticmethod
    def _host_string(result):
        delegated_vars = result._result.get('_ansible_delegated_vars', None)

        if delegated_vars:
            host_string = "%s -> %s" % (
                result._host.get_name(), delegated_vars['ansible_host'])
        else:
            host_string = result._host.get_name()

        return host_string

    def v2_runner_on_ok(self, result):
        duration = self._get_duration()

        self._clean_results(result._result, result._task.action)

        host_string = self._host_string(result)

        self._clean_results(result._result, result._task.action)

        if result._task.action in ('include', 'include_role', 'include_tasks'):
            sys.stdout.write("\b\b\b\b ")
            if result._task.action in ('include', 'include_role'):
                sys.stdout.write("    \n")
            return

        msg, color = self._changed_or_not(result._result, host_string)

        if result._task.loop and self._display.verbosity > 0 and 'results' in result._result:
            for item in result._result['results']:
                msg, color = self._changed_or_not(item, host_string)
                item_msg = "%s - item=%s" % (msg, self._get_item(item))
                self._emit_line("%s | %s" %
                                (item_msg, duration), color=color)
        else:
            self._emit_line("%s | %s" %
                            (msg, duration), color=color)
        self._handle_warnings(result._result)

        if ((self._display.verbosity > 0 or '_ansible_verbose_always' in result._result)
                and not '_ansible_verbose_override' in result._result):
            self._emit_line(deep_serialize(result._result), color=color)

        result._preamble = self.task_start_preamble

    @staticmethod
    def _changed_or_not(result, host_string):
        if result.get('changed', False):
            msg = "%s | CHANGED" % host_string
            color = C.COLOR_CHANGED
        else:
            msg = "%s | SUCCESS" % host_string
            color = C.COLOR_OK

        return [msg, color]

    def _emit_line(self, lines, color=C.COLOR_OK):

        if self.task_start_preamble is None:
            self._open_section("system")

        if self.task_start_preamble.endswith(" ..."):
            sys.stdout.write("\b\b\b\b | ")
            self.task_start_preamble = " "

        for line in lines.splitlines():
            self._display.display(line, color=color)

    def v2_runner_on_unreachable(self, result):
        self._emit_line('{} | UNREACHABLE!: {}'.format(
            self._host_string(result), result._result.get('msg', '')), color=C.COLOR_CHANGED)

    def v2_runner_on_skipped(self, result):
        duration = self._get_duration()

        self._emit_line("%s | SKIPPED | %s" %
                        (self._host_string(result), duration), color=C.COLOR_SKIP)

    def v2_playbook_on_include(self, included_file):
        if self.task_start_preamble.endswith(" ..."):
            self.task_start_preamble = " "
            msg = '| {} | {} | {}'.format(
                ", ".join([h.name for h in included_file._hosts]),
                'INCLUDED',
                os.path.basename(included_file._filename))
            self._display.display(msg, color=C.COLOR_SKIP)

    def v2_playbook_on_stats(self, stats):
        self._open_section("system")
        self._emit_line("-- Play recap --")

        hosts = sorted(stats.processed.keys())
        for h in hosts:
            t = stats.summarize(h)

            self._emit_line(u"%s : %s %s %s %s" % (
                hostcolor(h, t),
                colorize(u'ok', t['ok'], C.COLOR_OK),
                colorize(u'changed', t['changed'], C.COLOR_CHANGED),
                colorize(u'unreachable', t['unreachable'], C.COLOR_UNREACHABLE),
                colorize(u'failed', t['failures'], C.COLOR_ERROR)))

    def __init__(self, *args, **kwargs):
        super(CallbackModule, self).__init__(*args, **kwargs)
        self.task_started = datetime.now()
        self.task_start_preamble = None
        # python2 only
        try:
            reload(sys).setdefaultencoding('utf8')
        # pylint: disable=W0702
        except:
            pass

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


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

progname = "cam-track.py"
ver = "version 0.85"

"""
cam-track written by Claude Pageau pageauc@gmail.com
Raspberry (Pi) - python opencv2 camera pan/tilt tracking using picamera module

This is a raspberry pi python opencv2 camera tracking demonstration program.
It takes a sample search rectangle from center of video stream image
and tracks its position based on a percent accuracy at maxLoc.
As the camera pans and tilts.  The cumulative position is displayed.

I will work on converting position based on 360 degree camera movement.
This is still very much a work in progress but I thought it would be
useful for others who might want a simple way to track camera movement.
Note the program can get confused by plain surroundings or some
other movements in the frame although this can be tuned out somewhat
using cam_move_x and cam_move_y global variables

This runs under python2 and openCV2

installation
-------------
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install -y python-opencv python-picamera
mkdir ~/cam-track
cd ~/cam-track
wget https://raw.github.com/pageauc/motion-track/master/cam-track/cam-track.py
chmod +x cam-track.py
./cam-track.py       # defaults to run from RPI desktop terminal session

Good Luck  Claude ...

"""
print("%s %s using python2 and OpenCV2" % (progname, ver))
print("Camera movement (pan/tilt) Tracker using openCV2 image searching")
print("Loading Please Wait ....")

# import the necessary packages
import time
import cv2

from picamera.array import PiRGBArray
from picamera import PiCamera
from threading import Thread
from operator import itemgetter
import numpy as np

#-----------------------------------------------------------------------------------------------
# Global Variable Settings
debug = True      # Set to False for no data display
window_on = True  # Set to True displays opencv windows (GUI desktop reqd)
fps_on = False    # Display fps (not implemented)

# Sets the maximum x y pixels that are allowed to reduce effect of objects moving in frame
cam_move_x = 12    # Max number of x pixels in one move
cam_move_y = 8    # Max number of y pixels in one move

# Camera Settings
CAMERA_WIDTH = 320
CAMERA_HEIGHT = 240
CAMERA_HFLIP = False
CAMERA_VFLIP = True
CAMERA_ROTATION=0
CAMERA_FRAMERATE = 35  # framerate of video stream.  Can be 100+ with new R2 RPI camera module
FRAME_COUNTER = 1000   # used by fps

# OpenCV Settings
show_search_rect = True # show outline of current search box on main window
show_search_wind = False # show rectangle search_rect_1 window
show_circle = True      # show a circle otherwise show bounding rectangle on window
CIRCLE_SIZE = 3         # diameter of circle to show motion location in window
WINDOW_BIGGER = 2.0     # increase the display window size
MAX_SEARCH_THRESHOLD = .96 # default=.97 Accuracy for best search result of search_rect in stream images
LINE_THICKNESS = 1      # thickness of bounding line in pixels
CV_FONT_SIZE = .25      # size of font on opencv window default .5
red = (0,0,255)         # opencv line colours
green = (0,255,0)
blue = (255,0,0)

# search rectangle variables
image_cx = int(CAMERA_WIDTH/2)   # x center of image
image_cy = int(CAMERA_HEIGHT/2)  # y center of image
sw_w = int(CAMERA_WIDTH/4)    # search window width
sw_h = int(CAMERA_HEIGHT/4)   # search window height
sw_buf_x = int(sw_w/4)        # buffer to left/right of image
sw_buf_y = int(sw_h/4)        # buffer to top/bot of image
sw_x = (image_cx - sw_w/2)    # top x corner of search rect
sw_y = (image_cy - sw_h/2)    # top y corner of search rect
sw_xy = (sw_x,sw_y)          # initialize cam position tracker

#-----------------------------------------------------------------------------------------------
# Create a Video Stream Tread
class PiVideoStream:
    def __init__(self, resolution=(CAMERA_WIDTH, CAMERA_HEIGHT), framerate=CAMERA_FRAMERATE, rotation=0, hflip=False, vflip=False):
        # initialize the camera and stream
        self.camera = PiCamera()
        self.camera.resolution = resolution
        self.camera.rotation = rotation
        self.camera.framerate = framerate
        self.camera.hflip = hflip
        self.camera.vflip = vflip
        self.rawCapture = PiRGBArray(self.camera, size=resolution)
        self.stream = self.camera.capture_continuous(self.rawCapture,
            format="bgr", use_video_port=True)

        # initialize the frame and the variable used to indicate
        # if the thread should be stopped
        self.frame = None
        self.stopped = False

    def start(self):
        # start the thread to read frames from the video stream
        t = Thread(target=self.update, args=())
        t.daemon = True
        t.start()
        return self

    def update(self):
        # keep looping infinitely until the thread is stopped
        for f in self.stream:
            # grab the frame from the stream and clear the stream in
            # preparation for the next frame
            self.frame = f.array
            self.rawCapture.truncate(0)
            # if the thread indicator variable is set, stop the thread
            # and resource camera resources
            if self.stopped:
                self.stream.close()
                self.rawCapture.close()
                self.camera.close()
                return

    def read(self):
        # return the frame most recently read
        return self.frame

    def stop(self):
        # indicate that the thread should be stopped
        self.stopped = True

#-----------------------------------------------------------------------------------------------
# Currently not used but included in case you want to check speed
def show_FPS(start_time,frame_count):
    if debug:
        if frame_count >= FRAME_COUNTER:
            duration = float(time.time() - start_time)
            FPS = float(frame_count / duration)
            print("Processing at %.2f fps last %i frames" %( FPS, frame_count))
            frame_count = 0
            start_time = time.time()
        else:
            frame_count += 1
    return start_time, frame_count

#-----------------------------------------------------------------------------------------------
def check_image_match(full_image, small_image):
    # Look for small_image in full_image and return best and worst results
    result = cv2.matchTemplate( full_image, small_image, cv2.TM_CCORR_NORMED)
    # Process result to return probabilities and Location of best and worst image match
    minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(result)  # find search rect match in new image
    return maxLoc, maxVal

#-----------------------------------------------------------------------------------------------
def xy_at_edge(xy_loc):  # check if search rect is near edge plus buffer space
    near_edge = False
    if ( xy_loc[0] < sw_buf_x
      or xy_loc[0] > CAMERA_WIDTH - (sw_buf_x + sw_w)
      or xy_loc[1] < sw_buf_y
      or xy_loc[1] > CAMERA_HEIGHT - (sw_buf_y + sw_h)):
        near_edge = True
        if debug:
            print("xy_at_edge - xy(%i, %i) xyBuf(%i,%i)" %( xy_loc[0], xy_loc[1], sw_buf_x, sw_buf_y))
    return near_edge

#-----------------------------------------------------------------------------------------------
def xy_low_val(cur_val, val_setting):
    # Check if maxVal is below MAX_SEARCH_THRESHOLD value
    bad_match = False
    if cur_val < val_setting:
        bad_match = True
        if debug:
            print("xy_low_val - maxVal=%0.5f  threshold=%0.4f" % (cur_val, val_setting))
    return bad_match

#-----------------------------------------------------------------------------------------------
def xy_moved(xy_prev, xy_loc):
    # Check if x or y location has changed
    moved = False
    if (xy_loc[0] <> xy_prev[0] or
        xy_loc[1] <> xy_prev[1]):
        moved = True
        if debug:
            print("xy_moved   - dx=%i dy=%i "
                         %( xy_loc[0] - xy_prev[0], xy_loc[1] - xy_prev[1]))
    return moved

#-----------------------------------------------------------------------------------------------
def xy_big_move(xy_prev, xy_new):
    big_move = False
    if (abs( xy_new[0] - xy_prev[0] ) > cam_move_x or
        abs( xy_new[1] - xy_prev[1] ) > cam_move_y):
            big_move = True
            if debug:
                print("xy_big-move- xy(%i,%i) move exceeded %i or %i"
                              % ( xy_new[0], xy_new[1], cam_move_x, cam_move_y))
    return big_move

def xy_update(xy_cam, xy_prev, xy_new):
    dx = 0
    dy = 0
    if abs(xy_prev[0] - xy_new[0]) > 0:
        dx = xy_prev[0] - xy_new[0]
    if abs(xy_prev[1] - xy_new[1]) > 0:
        dy = xy_prev[1] - xy_new[1]
    xy_cam = ((xy_cam[0] + dx, xy_cam[1] + dy))
    if debug:
        print("xy-update  - cam xy (%i,%i) dxy(%i,%i)"
                         % (xy_cam[0], xy_cam[1], dx, dy))
    return xy_cam

#-----------------------------------------------------------------------------------------------
def cam_track():
    # Process steam images to find camera movement
    # using an extracted search rectangle in the middle of one frame
    # and find location in subsequent images.  Grap a new search rect
    # as needed based on nearness to edge of image or percent probability
    # of image search result Etc.

    # Setup Video Stream Thread
    vs = PiVideoStream().start()
    vs.camera.rotation = CAMERA_ROTATION
    vs.camera.hflip = CAMERA_HFLIP
    vs.camera.vflip = CAMERA_VFLIP
    time.sleep(2.0)    # Let camera warm up

    if WINDOW_BIGGER > 1:  # Note setting a bigger window will slow the FPS
        big_w = int(CAMERA_WIDTH * WINDOW_BIGGER)
        big_h = int(CAMERA_HEIGHT * WINDOW_BIGGER)

    sw_maxVal = MAX_SEARCH_THRESHOLD  # Threshold Accuracy of search in image
    xy_cam = (0,0)    # xy of Cam Overall Position
    xy_new = sw_xy    # xy of current search_rect
    xy_prev = xy_new  # xy of prev search_rect
    search_reset = False  # Reset search window back to center
    image1 = vs.read()    # Grab a Video Steam
    search_rect = image1[sw_y:sw_y+sw_h, sw_x:sw_x+sw_w]  # Init centre search rectangle
    while True:
        image1 = vs.read()  # capture a new image1 from video stream thread
        # Check location of search rect in image1
        xy_new, xy_val = check_image_match(image1, search_rect)
        # Analyse new xy for issues
        if xy_moved(xy_prev, xy_new):
            if (xy_big_move(xy_prev, xy_new) or
                xy_at_edge(xy_new) or
                xy_low_val(xy_val, sw_maxVal)):
               search_reset = True  # Reset search to center
            else:
                # update new cam position
                xy_cam = xy_update(xy_cam, xy_prev, xy_new)
                xy_prev = xy_new

        if search_reset:   # Reset search_rect back to center
            if debug:
                print("cam-track  - Reset search_rect img_xy(%i,%i) CamPos(%i,%i)"
                                           % (xy_new[0], xy_new[1], xy_cam[0], xy_cam[1]))
            search_rect = image1[sw_y:sw_y+sw_h, sw_x:sw_x+sw_w]
            xy_new = sw_xy
            xy_prev = xy_new
            search_reset = False

        if debug:
            print("cam-track  - Cam Pos(%i,%i) %0.5f  img_xy(%i,%i)"
                     % ( xy_cam[0], xy_cam[1], xy_val, xy_new[0], xy_new[1] ))

        if window_on:
            image2 = image1
            # Display openCV window information on RPI desktop if required
            if show_circle:
               cv2.circle(image2,(image_cx, image_cy), CIRCLE_SIZE, red, 1)
            if show_search_rect:
                cv2.rectangle(image2,( xy_new[0], xy_new[1] ),
                                     ( xy_new[0] + sw_w, xy_new[1] + sw_h ),
                                     green, LINE_THICKNESS)     # show search rect
            # Show Cam Position text on bottom of opencv window
            m_text = ("CAM POS( %i %i )   " % (xy_cam[0], xy_cam[1]))
            cv2.putText(image2, m_text,
                       (image_cx - len(m_text) * 3, CAMERA_HEIGHT - 15 ),
                        cv2.FONT_HERSHEY_SIMPLEX, CV_FONT_SIZE, green, 1)
            if WINDOW_BIGGER > 1:
                image2 = cv2.resize( image2,( big_w, big_h ))
            cv2.imshow('Cam-Track  (q in window to quit)',image2)

            if show_search_wind:
                cv2.imshow( 'search rectangle', search_rect )

            if cv2.waitKey(1) & 0xFF == ord('q'):
                vs.stop()    # Stop video stream thread
                cv2.destroyAllWindows()
                print("End Cam Tracking")
                break

#-----------------------------------------------------------------------------------------------
if __name__ == '__main__':
    try:
        cam_track()
    finally:
        print("")
        print("+++++++++++++++++++++++++++++++++++")
        print("%s %s - Exiting" % (progname, ver))
        print("+++++++++++++++++++++++++++++++++++")
        print("")

<commit_msg>ver 0.86 Release<commit_after>#!/usr/bin/env python

progname = "cam-track.py"
ver = "version 0.85"

"""
cam-track written by Claude Pageau pageauc@gmail.com
Raspberry (Pi) - python opencv2 camera pan/tilt tracking using picamera module

This is a raspberry pi python opencv2 camera tracking demonstration program.
It takes a sample search rectangle from center of video stream image
and tracks its position based on a percent accuracy at maxLoc.
As the camera pans and tilts.  The cumulative position is displayed.

I will work on converting position based on 360 degree camera movement.
This is still very much a work in progress but I thought it would be
useful for others who might want a simple way to track camera movement.
Note the program can get confused by plain surroundings or some
other movements in the frame although this can be tuned out somewhat
using cam_move_x and cam_move_y global variables

This runs under python2 and openCV2

installation
-------------
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install -y python-opencv python-picamera
mkdir ~/cam-track
cd ~/cam-track
wget https://raw.github.com/pageauc/motion-track/master/cam-track/cam-track.py
chmod +x cam-track.py
./cam-track.py       # defaults to run from RPI desktop terminal session

Good Luck  Claude ...

"""
print("%s %s using python2 and OpenCV2" % (progname, ver))
print("Camera movement (pan/tilt) Tracker using openCV2 image searching")
print("Loading Please Wait ....")

# import the necessary packages
import time
import cv2

from picamera.array import PiRGBArray
from picamera import PiCamera
from threading import Thread
from operator import itemgetter
import numpy as np

#-----------------------------------------------------------------------------------------------
# Global Variable Settings
debug = True      # Set to False for no data display
window_on = True  # Set to True displays opencv windows (GUI desktop reqd)
fps_on = False    # Display fps (not implemented)

# Sets the maximum x y pixels that are allowed to reduce effect of objects moving in frame
cam_move_x = 12    # Max number of x pixels in one move
cam_move_y = 8    # Max number of y pixels in one move

# Camera Settings
CAMERA_WIDTH = 320
CAMERA_HEIGHT = 240
CAMERA_HFLIP = False
CAMERA_VFLIP = True
CAMERA_ROTATION=0
CAMERA_FRAMERATE = 35  # framerate of video stream.  Can be 100+ with new R2 RPI camera module
FRAME_COUNTER = 1000   # used by fps

# OpenCV Settings
show_search_rect = True # show outline of current search box on main window
show_search_wind = False # show rectangle search_rect_1 window
show_circle = True      # show a circle otherwise show bounding rectangle on window
CIRCLE_SIZE = 3         # diameter of circle to show motion location in window
WINDOW_BIGGER = 2.0     # increase the display window size
MAX_SEARCH_THRESHOLD = .96 # default=.97 Accuracy for best search result of search_rect in stream images
LINE_THICKNESS = 1      # thickness of bounding line in pixels
CV_FONT_SIZE = .25      # size of font on opencv window default .5
red = (0,0,255)         # opencv line colours
green = (0,255,0)
blue = (255,0,0)

# search rectangle variables
image_cx = int(CAMERA_WIDTH/2)   # x center of image
image_cy = int(CAMERA_HEIGHT/2)  # y center of image
sw_w = int(CAMERA_WIDTH/4)    # search window width
sw_h = int(CAMERA_HEIGHT/4)   # search window height
sw_buf_x = int(sw_w/4)        # buffer to left/right of image
sw_buf_y = int(sw_h/4)        # buffer to top/bot of image
sw_x = (image_cx - sw_w/2)    # top x corner of search rect
sw_y = (image_cy - sw_h/2)    # top y corner of search rect
sw_xy = (sw_x,sw_y)          # initialize cam position tracker

#-----------------------------------------------------------------------------------------------
# Create a Video Stream Tread
class PiVideoStream:
    def __init__(self, resolution=(CAMERA_WIDTH, CAMERA_HEIGHT), framerate=CAMERA_FRAMERATE, rotation=0, hflip=False, vflip=False):
        # initialize the camera and stream
        self.camera = PiCamera()
        self.camera.resolution = resolution
        self.camera.rotation = rotation
        self.camera.framerate = framerate
        self.camera.hflip = hflip
        self.camera.vflip = vflip
        self.rawCapture = PiRGBArray(self.camera, size=resolution)
        self.stream = self.camera.capture_continuous(self.rawCapture,
            format="bgr", use_video_port=True)

        # initialize the frame and the variable used to indicate
        # if the thread should be stopped
        self.frame = None
        self.stopped = False

    def start(self):
        # start the thread to read frames from the video stream
        t = Thread(target=self.update, args=())
        t.daemon = True
        t.start()
        return self

    def update(self):
        # keep looping infinitely until the thread is stopped
        for f in self.stream:
            # grab the frame from the stream and clear the stream in
            # preparation for the next frame
            self.frame = f.array
            self.rawCapture.truncate(0)
            # if the thread indicator variable is set, stop the thread
            # and resource camera resources
            if self.stopped:
                self.stream.close()
                self.rawCapture.close()
                self.camera.close()
                return

    def read(self):
        # return the frame most recently read
        return self.frame

    def stop(self):
        # indicate that the thread should be stopped
        self.stopped = True

#-----------------------------------------------------------------------------------------------
# Currently not used but included in case you want to check speed
def show_FPS(start_time,frame_count):
    if debug:
        if frame_count >= FRAME_COUNTER:
            duration = float(time.time() - start_time)
            FPS = float(frame_count / duration)
            print("Processing at %.2f fps last %i frames" %( FPS, frame_count))
            frame_count = 0
            start_time = time.time()
        else:
            frame_count += 1
    return start_time, frame_count

#-----------------------------------------------------------------------------------------------
def check_image_match(full_image, small_image):
    # Look for small_image in full_image and return best and worst results
    result = cv2.matchTemplate( full_image, small_image, cv2.TM_CCORR_NORMED)
    # Process result to return probabilities and Location of best and worst image match
    minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(result)  # find search rect match in new image
    return maxLoc, maxVal

#-----------------------------------------------------------------------------------------------
def xy_at_edge(xy_loc):  # check if search rect is near edge plus buffer space
    near_edge = False
    if ( xy_loc[0] < sw_buf_x
      or xy_loc[0] > CAMERA_WIDTH - (sw_buf_x + sw_w)
      or xy_loc[1] < sw_buf_y
      or xy_loc[1] > CAMERA_HEIGHT - (sw_buf_y + sw_h)):
        near_edge = True
        if debug:
            print("xy_at_edge - xy(%i, %i) xyBuf(%i,%i)" %( xy_loc[0], xy_loc[1], sw_buf_x, sw_buf_y))
    return near_edge

#-----------------------------------------------------------------------------------------------
def xy_low_val(cur_val, val_setting):
    # Check if maxVal is below MAX_SEARCH_THRESHOLD value
    bad_match = False
    if cur_val < val_setting:
        bad_match = True
        if debug:
            print("xy_low_val - maxVal=%0.5f  threshold=%0.4f" % (cur_val, val_setting))
    return bad_match

#-----------------------------------------------------------------------------------------------
def xy_moved(xy_prev, xy_loc):
    # Check if x or y location has changed
    moved = False
    if (xy_loc[0] <> xy_prev[0] or
        xy_loc[1] <> xy_prev[1]):
        moved = True
        if debug:
            print("xy_moved   - dx=%i dy=%i "
                         %( xy_loc[0] - xy_prev[0], xy_loc[1] - xy_prev[1]))
    return moved

#-----------------------------------------------------------------------------------------------
def xy_big_move(xy_prev, xy_new):
    big_move = False
    if (abs( xy_new[0] - xy_prev[0] ) > cam_move_x or
        abs( xy_new[1] - xy_prev[1] ) > cam_move_y):
            big_move = True
            if debug:
                print("xy_big-move- xy(%i,%i) move exceeded %i or %i"
                              % ( xy_new[0], xy_new[1], cam_move_x, cam_move_y))
    return big_move

def xy_update(xy_cam, xy_prev, xy_new):
    dx = 0
    dy = 0
    if abs(xy_prev[0] - xy_new[0]) > 0:
        dx = xy_prev[0] - xy_new[0]
    if abs(xy_prev[1] - xy_new[1]) > 0:
        dy = xy_prev[1] - xy_new[1]
    xy_cam = ((xy_cam[0] + dx, xy_cam[1] + dy))
    if debug:
        print("xy-update  - cam xy (%i,%i) dxy(%i,%i)"
                         % (xy_cam[0], xy_cam[1], dx, dy))
    return xy_cam

#-----------------------------------------------------------------------------------------------
def cam_track():
    # Process steam images to find camera movement
    # using an extracted search rectangle in the middle of one frame
    # and find location in subsequent images.  Grab a new search rect
    # as needed based on nearness to edge of image or percent probability
    # of image search result Etc.

    # Setup Video Stream Thread
    vs = PiVideoStream().start()
    vs.camera.rotation = CAMERA_ROTATION
    vs.camera.hflip = CAMERA_HFLIP
    vs.camera.vflip = CAMERA_VFLIP
    time.sleep(2.0)    # Let camera warm up

    if WINDOW_BIGGER > 1:  # Note setting a bigger window will slow the FPS
        big_w = int(CAMERA_WIDTH * WINDOW_BIGGER)
        big_h = int(CAMERA_HEIGHT * WINDOW_BIGGER)

    sw_maxVal = MAX_SEARCH_THRESHOLD  # Threshold Accuracy of search in image
    xy_cam = (0,0)    # xy of Cam Overall Position
    xy_new = sw_xy    # xy of current search_rect
    xy_prev = xy_new  # xy of prev search_rect
    search_reset = False  # Reset search window back to center
    image1 = vs.read()    # Grab image from video stream thread
    search_rect = image1[sw_y:sw_y+sw_h, sw_x:sw_x+sw_w]  # Init centre search rectangle
    while True:
        image1 = vs.read()  # Grab a new image1 from video stream thread
        # Check location of search rect in image1
        xy_new, xy_val = check_image_match(image1, search_rect)
        # Analyse new xy for issues
        if xy_moved(xy_prev, xy_new):
            if (xy_big_move(xy_prev, xy_new) or
                xy_at_edge(xy_new) or
                xy_low_val(xy_val, sw_maxVal)):
               search_reset = True  # Reset search to center
            else:
                # update new cam position
                xy_cam = xy_update(xy_cam, xy_prev, xy_new)
                xy_prev = xy_new

        if search_reset:   # Reset search_rect back to center
            if debug:
                print("cam-track  - Reset search_rect img_xy(%i,%i) CamPos(%i,%i)"
                                           % (xy_new[0], xy_new[1], xy_cam[0], xy_cam[1]))
            search_rect = image1[sw_y:sw_y+sw_h, sw_x:sw_x+sw_w]
            xy_new = sw_xy
            xy_prev = xy_new
            search_reset = False

        if debug:
            print("cam-track  - Cam Pos(%i,%i) %0.5f  img_xy(%i,%i)"
                     % ( xy_cam[0], xy_cam[1], xy_val, xy_new[0], xy_new[1] ))

        if window_on:
            image2 = image1
            # Display openCV window information on RPI desktop if required
            if show_circle:
               cv2.circle(image2,(image_cx, image_cy), CIRCLE_SIZE, red, 1)
            if show_search_rect:
                cv2.rectangle(image2,( xy_new[0], xy_new[1] ),
                                     ( xy_new[0] + sw_w, xy_new[1] + sw_h ),
                                     green, LINE_THICKNESS)     # show search rect
            # Show Cam Position text on bottom of opencv window
            m_text = ("CAM POS( %i %i )   " % (xy_cam[0], xy_cam[1]))
            cv2.putText(image2, m_text,
                       (image_cx - len(m_text) * 3, CAMERA_HEIGHT - 15 ),
                        cv2.FONT_HERSHEY_SIMPLEX, CV_FONT_SIZE, green, 1)
            if WINDOW_BIGGER > 1:
                image2 = cv2.resize( image2,( big_w, big_h ))
            cv2.imshow('Cam-Track  (q in window to quit)',image2)

            if show_search_wind:
                cv2.imshow( 'search rectangle', search_rect )

            if cv2.waitKey(1) & 0xFF == ord('q'):
                vs.stop()    # Stop video stream thread
                cv2.destroyAllWindows()
                print("End Cam Tracking")
                break

#-----------------------------------------------------------------------------------------------
if __name__ == '__main__':
    try:
        cam_track()
    finally:
        print("")
        print("+++++++++++++++++++++++++++++++++++")
        print("%s %s - Exiting" % (progname, ver))
        print("+++++++++++++++++++++++++++++++++++")
        print("")

<|endoftext|>