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

import copy
import time

from dogpile.cache import proxy
import mock
from oslo_config import cfg
from oslo_config import fixture as config_fixture
from oslo_utils import uuidutils
from oslotest import base

from oslo_cache import _opts
from oslo_cache import core as cache
from oslo_cache import exception

NO_VALUE = cache.NO_VALUE
TEST_GROUP = uuidutils.generate_uuid(dashed=False)
TEST_GROUP2 = uuidutils.generate_uuid(dashed=False)

class BaseTestCase(base.BaseTestCase):
    def setUp(self):
        super(BaseTestCase, self).setUp()
        self.config_fixture = self.useFixture(config_fixture.Config())
        self.config_fixture.config(
            # TODO(morganfainberg): Make Cache Testing a separate test case
            # in tempest, and move it out of the base unit tests.
            group='cache',
            backend='dogpile.cache.memory',
            enabled=True,
            proxies=['oslo_cache.testing.CacheIsolatingProxy'])

def _copy_value(value):
    if value is not NO_VALUE:
        value = copy.deepcopy(value)
    return value

class TestProxy(proxy.ProxyBackend):
    def get(self, key):
        value = _copy_value(self.proxied.get(key))
        if value is not NO_VALUE:
            if isinstance(value[0], TestProxyValue):
                value[0].cached = True
        return value

class TestProxyValue(object):
    def __init__(self, value):
        self.value = value
        self.cached = False

class CacheRegionTest(BaseTestCase):

    def setUp(self):
        super(CacheRegionTest, self).setUp()
        self.region = cache.create_region()
        cache.configure_cache_region(self.config_fixture.conf, self.region)
        self.region.wrap(TestProxy)
        self.region_kwargs = cache.create_region(
            function=cache.kwarg_function_key_generator)
        cache.configure_cache_region(self.config_fixture.conf,
                                     self.region_kwargs)
        self.region_kwargs.wrap(TestProxy)
        self.test_value = TestProxyValue('Decorator Test')

    def _add_test_caching_option(self):
        self.config_fixture.register_opt(
            cfg.BoolOpt('caching', default=True), group='cache')

    def _add_dummy_config_group(self):
        self.config_fixture.register_opt(
            cfg.IntOpt('cache_time'), group=TEST_GROUP)
        self.config_fixture.register_opt(
            cfg.IntOpt('cache_time'), group=TEST_GROUP2)

    def _get_cacheable_function(self, region=None):
        region = region if region else self.region
        memoize = cache.get_memoization_decorator(
            self.config_fixture.conf, region, group='cache')

        @memoize
        def cacheable_function(value=0, **kw):
            return value

        return cacheable_function

    def test_region_built_with_proxy_direct_cache_test(self):
        # Verify cache regions are properly built with proxies.
        test_value = TestProxyValue('Direct Cache Test')
        self.region.set('cache_test', test_value)
        cached_value = self.region.get('cache_test')
        self.assertTrue(cached_value.cached)

    def test_cache_region_no_error_multiple_config(self):
        # Verify configuring the CacheRegion again doesn't error.
        cache.configure_cache_region(self.config_fixture.conf, self.region)
        cache.configure_cache_region(self.config_fixture.conf, self.region)

    def _get_cache_fallthrough_fn(self, cache_time):
        memoize = cache.get_memoization_decorator(
            self.config_fixture.conf,
            self.region,
            group='cache',
            expiration_group=TEST_GROUP2)

        class _test_obj(object):
            def __init__(self, value):
                self.test_value = value

            @memoize
            def get_test_value(self):
                return self.test_value

        def _do_test(value):

            test_obj = _test_obj(value)

            # Ensure the value has been cached
            test_obj.get_test_value()
            # Get the now cached value
            cached_value = test_obj.get_test_value()
            self.assertTrue(cached_value.cached)
            self.assertEqual(value.value, cached_value.value)
            self.assertEqual(cached_value.value, test_obj.test_value.value)
            # Change the underlying value on the test object.
            test_obj.test_value = TestProxyValue(
                uuidutils.generate_uuid(dashed=False))
            self.assertEqual(cached_value.value,
                             test_obj.get_test_value().value)
            # override the system time to ensure the non-cached new value
            # is returned
            new_time = time.time() + (cache_time * 2)
            with mock.patch.object(time, 'time',
                                   return_value=new_time):
                overriden_cache_value = test_obj.get_test_value()
                self.assertNotEqual(cached_value.value,
                                    overriden_cache_value.value)
                self.assertEqual(test_obj.test_value.value,
                                 overriden_cache_value.value)

        return _do_test

    def test_cache_no_fallthrough_expiration_time_fn(self):
        self._add_dummy_config_group()
        # Since we do not re-configure the cache region, for ease of testing
        # this value is set the same as the expiration_time default in the
        # [cache] group
        cache_time = 600
        expiration_time = cache._get_expiration_time_fn(
            self.config_fixture.conf, TEST_GROUP)
        do_test = self._get_cache_fallthrough_fn(cache_time)
        # Run the test with the dummy group cache_time value
        self.config_fixture.config(cache_time=cache_time,
                                   group=TEST_GROUP)
        test_value = TestProxyValue(uuidutils.generate_uuid(dashed=False))
        self.assertEqual(cache_time, expiration_time())
        do_test(value=test_value)

    def test_cache_fallthrough_expiration_time_fn(self):
        self._add_dummy_config_group()
        # Since we do not re-configure the cache region, for ease of testing
        # this value is set the same as the expiration_time default in the
        # [cache] group
        cache_time = 599
        expiration_time = cache._get_expiration_time_fn(
            self.config_fixture.conf, TEST_GROUP)
        do_test = self._get_cache_fallthrough_fn(cache_time)
        # Run the test with the dummy group cache_time value set to None and
        # the global value set.
        self.config_fixture.config(cache_time=None, group=TEST_GROUP)
        test_value = TestProxyValue(
            uuidutils.generate_uuid(dashed=False))
        self.assertIsNone(expiration_time())
        do_test(value=test_value)

    def test_should_cache_fn_global_cache_enabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally enabled.
        cacheable_function = self._get_cacheable_function()

        self.config_fixture.config(group='cache', enabled=True)
        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertTrue(cached_value.cached)

    def test_should_cache_fn_global_cache_disabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally disabled.
        cacheable_function = self._get_cacheable_function()

        self.config_fixture.config(group='cache', enabled=False)
        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertFalse(cached_value.cached)

    def test_should_cache_fn_global_cache_disabled_group_cache_enabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally disabled and the specific
        # group caching enabled.
        cacheable_function = self._get_cacheable_function()

        self._add_test_caching_option()
        self.config_fixture.config(group='cache', enabled=False)
        self.config_fixture.config(group='cache', caching=True)

        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertFalse(cached_value.cached)

    def test_should_cache_fn_global_cache_enabled_group_cache_disabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally enabled and the specific
        # group caching disabled.
        cacheable_function = self._get_cacheable_function()

        self._add_test_caching_option()
        self.config_fixture.config(group='cache', enabled=True)
        self.config_fixture.config(group='cache', caching=False)

        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertFalse(cached_value.cached)

    def test_should_cache_fn_global_cache_enabled_group_cache_enabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally enabled and the specific
        # group caching enabled.
        cacheable_function = self._get_cacheable_function()

        self._add_test_caching_option()
        self.config_fixture.config(group='cache', enabled=True)
        self.config_fixture.config(group='cache', caching=True)

        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertTrue(cached_value.cached)

    def test_cache_dictionary_config_builder(self):
        """Validate we build a sane dogpile.cache dictionary config."""
        self.config_fixture.config(group='cache',
                                   config_prefix='test_prefix',
                                   backend='oslo_cache.dict',
                                   expiration_time=86400,
                                   backend_argument=['arg1:test',
                                                     'arg2:test:test',
                                                     'arg3.invalid'])

        config_dict = cache._build_cache_config(self.config_fixture.conf)
        self.assertEqual(
            self.config_fixture.conf.cache.backend,
            config_dict['test_prefix.backend'])
        self.assertEqual(
            self.config_fixture.conf.cache.expiration_time,
            config_dict['test_prefix.expiration_time'])
        self.assertEqual('test', config_dict['test_prefix.arguments.arg1'])
        self.assertEqual('test:test',
                         config_dict['test_prefix.arguments.arg2'])
        self.assertNotIn('test_prefix.arguments.arg3', config_dict)

    def test_cache_dictionary_config_builder_global_disabled(self):
        """Validate the backend is reset to default if caching is disabled."""
        self.config_fixture.config(group='cache',
                                   enabled=False,
                                   config_prefix='test_prefix',
                                   backend='oslo_cache.dict')

        self.assertFalse(self.config_fixture.conf.cache.enabled)
        config_dict = cache._build_cache_config(self.config_fixture.conf)
        self.assertEqual(
            _opts._DEFAULT_BACKEND,
            config_dict['test_prefix.backend'])

    def test_cache_debug_proxy(self):
        single_value = 'Test Value'
        single_key = 'testkey'
        multi_values = {'key1': 1, 'key2': 2, 'key3': 3}

        self.region.set(single_key, single_value)
        self.assertEqual(single_value, self.region.get(single_key))

        self.region.delete(single_key)
        self.assertEqual(NO_VALUE, self.region.get(single_key))

        self.region.set_multi(multi_values)
        cached_values = self.region.get_multi(multi_values.keys())
        for value in multi_values.values():
            self.assertIn(value, cached_values)
        self.assertEqual(len(multi_values.values()), len(cached_values))

        self.region.delete_multi(multi_values.keys())
        for value in self.region.get_multi(multi_values.keys()):
            self.assertEqual(NO_VALUE, value)

    def test_configure_non_region_object_raises_error(self):
        self.assertRaises(exception.ConfigurationError,
                          cache.configure_cache_region,
                          self.config_fixture.conf,
                          "bogus")

    def test_function_key_generator_with_kwargs(self):
        cacheable_function = self._get_cacheable_function()

        self.config_fixture.config(group='cache', enabled=True)
        self.assertRaises(ValueError,
                          cacheable_function,
                          value=0, foo=self.test_value)

    def test_kwarg_function_key_generator_no_kwargs(self):
        cacheable_function = self._get_cacheable_function(
            region=self.region_kwargs)

        self.config_fixture.config(group='cache', enabled=True)
        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertTrue(cached_value.cached)

    def test_kwarg_function_key_generator_with_kwargs(self):
        cacheable_function = self._get_cacheable_function(
            region=self.region_kwargs)

        self.config_fixture.config(group='cache', enabled=True)
        cacheable_function(value=self.test_value)
        cached_value = cacheable_function(value=self.test_value)
        self.assertTrue(cached_value.cached)

class UTF8KeyManglerTests(BaseTestCase):

    def test_key_is_utf8_encoded(self):
        key = u'fäké1'
        encoded = cache._sha1_mangle_key(key)
        self.assertIsNotNone(encoded)

    def test_key_is_bytestring(self):
        key = b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'
        encoded = cache._sha1_mangle_key(key)
        self.assertIsNotNone(encoded)

    def test_key_is_string(self):
        key = 'fake'
        encoded = cache._sha1_mangle_key(key)
        self.assertIsNotNone(encoded)
<commit_msg>Remove dogpile kwarg test<commit_after># -*- coding: utf-8 -*-
# Copyright 2013 Metacloud
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import copy
import time

from dogpile.cache import proxy
import mock
from oslo_config import cfg
from oslo_config import fixture as config_fixture
from oslo_utils import uuidutils
from oslotest import base

from oslo_cache import _opts
from oslo_cache import core as cache
from oslo_cache import exception

NO_VALUE = cache.NO_VALUE
TEST_GROUP = uuidutils.generate_uuid(dashed=False)
TEST_GROUP2 = uuidutils.generate_uuid(dashed=False)

class BaseTestCase(base.BaseTestCase):
    def setUp(self):
        super(BaseTestCase, self).setUp()
        self.config_fixture = self.useFixture(config_fixture.Config())
        self.config_fixture.config(
            # TODO(morganfainberg): Make Cache Testing a separate test case
            # in tempest, and move it out of the base unit tests.
            group='cache',
            backend='dogpile.cache.memory',
            enabled=True,
            proxies=['oslo_cache.testing.CacheIsolatingProxy'])

def _copy_value(value):
    if value is not NO_VALUE:
        value = copy.deepcopy(value)
    return value

class TestProxy(proxy.ProxyBackend):
    def get(self, key):
        value = _copy_value(self.proxied.get(key))
        if value is not NO_VALUE:
            if isinstance(value[0], TestProxyValue):
                value[0].cached = True
        return value

class TestProxyValue(object):
    def __init__(self, value):
        self.value = value
        self.cached = False

class CacheRegionTest(BaseTestCase):

    def setUp(self):
        super(CacheRegionTest, self).setUp()
        self.region = cache.create_region()
        cache.configure_cache_region(self.config_fixture.conf, self.region)
        self.region.wrap(TestProxy)
        self.region_kwargs = cache.create_region(
            function=cache.kwarg_function_key_generator)
        cache.configure_cache_region(self.config_fixture.conf,
                                     self.region_kwargs)
        self.region_kwargs.wrap(TestProxy)
        self.test_value = TestProxyValue('Decorator Test')

    def _add_test_caching_option(self):
        self.config_fixture.register_opt(
            cfg.BoolOpt('caching', default=True), group='cache')

    def _add_dummy_config_group(self):
        self.config_fixture.register_opt(
            cfg.IntOpt('cache_time'), group=TEST_GROUP)
        self.config_fixture.register_opt(
            cfg.IntOpt('cache_time'), group=TEST_GROUP2)

    def _get_cacheable_function(self, region=None):
        region = region if region else self.region
        memoize = cache.get_memoization_decorator(
            self.config_fixture.conf, region, group='cache')

        @memoize
        def cacheable_function(value=0, **kw):
            return value

        return cacheable_function

    def test_region_built_with_proxy_direct_cache_test(self):
        # Verify cache regions are properly built with proxies.
        test_value = TestProxyValue('Direct Cache Test')
        self.region.set('cache_test', test_value)
        cached_value = self.region.get('cache_test')
        self.assertTrue(cached_value.cached)

    def test_cache_region_no_error_multiple_config(self):
        # Verify configuring the CacheRegion again doesn't error.
        cache.configure_cache_region(self.config_fixture.conf, self.region)
        cache.configure_cache_region(self.config_fixture.conf, self.region)

    def _get_cache_fallthrough_fn(self, cache_time):
        memoize = cache.get_memoization_decorator(
            self.config_fixture.conf,
            self.region,
            group='cache',
            expiration_group=TEST_GROUP2)

        class _test_obj(object):
            def __init__(self, value):
                self.test_value = value

            @memoize
            def get_test_value(self):
                return self.test_value

        def _do_test(value):

            test_obj = _test_obj(value)

            # Ensure the value has been cached
            test_obj.get_test_value()
            # Get the now cached value
            cached_value = test_obj.get_test_value()
            self.assertTrue(cached_value.cached)
            self.assertEqual(value.value, cached_value.value)
            self.assertEqual(cached_value.value, test_obj.test_value.value)
            # Change the underlying value on the test object.
            test_obj.test_value = TestProxyValue(
                uuidutils.generate_uuid(dashed=False))
            self.assertEqual(cached_value.value,
                             test_obj.get_test_value().value)
            # override the system time to ensure the non-cached new value
            # is returned
            new_time = time.time() + (cache_time * 2)
            with mock.patch.object(time, 'time',
                                   return_value=new_time):
                overriden_cache_value = test_obj.get_test_value()
                self.assertNotEqual(cached_value.value,
                                    overriden_cache_value.value)
                self.assertEqual(test_obj.test_value.value,
                                 overriden_cache_value.value)

        return _do_test

    def test_cache_no_fallthrough_expiration_time_fn(self):
        self._add_dummy_config_group()
        # Since we do not re-configure the cache region, for ease of testing
        # this value is set the same as the expiration_time default in the
        # [cache] group
        cache_time = 600
        expiration_time = cache._get_expiration_time_fn(
            self.config_fixture.conf, TEST_GROUP)
        do_test = self._get_cache_fallthrough_fn(cache_time)
        # Run the test with the dummy group cache_time value
        self.config_fixture.config(cache_time=cache_time,
                                   group=TEST_GROUP)
        test_value = TestProxyValue(uuidutils.generate_uuid(dashed=False))
        self.assertEqual(cache_time, expiration_time())
        do_test(value=test_value)

    def test_cache_fallthrough_expiration_time_fn(self):
        self._add_dummy_config_group()
        # Since we do not re-configure the cache region, for ease of testing
        # this value is set the same as the expiration_time default in the
        # [cache] group
        cache_time = 599
        expiration_time = cache._get_expiration_time_fn(
            self.config_fixture.conf, TEST_GROUP)
        do_test = self._get_cache_fallthrough_fn(cache_time)
        # Run the test with the dummy group cache_time value set to None and
        # the global value set.
        self.config_fixture.config(cache_time=None, group=TEST_GROUP)
        test_value = TestProxyValue(
            uuidutils.generate_uuid(dashed=False))
        self.assertIsNone(expiration_time())
        do_test(value=test_value)

    def test_should_cache_fn_global_cache_enabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally enabled.
        cacheable_function = self._get_cacheable_function()

        self.config_fixture.config(group='cache', enabled=True)
        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertTrue(cached_value.cached)

    def test_should_cache_fn_global_cache_disabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally disabled.
        cacheable_function = self._get_cacheable_function()

        self.config_fixture.config(group='cache', enabled=False)
        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertFalse(cached_value.cached)

    def test_should_cache_fn_global_cache_disabled_group_cache_enabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally disabled and the specific
        # group caching enabled.
        cacheable_function = self._get_cacheable_function()

        self._add_test_caching_option()
        self.config_fixture.config(group='cache', enabled=False)
        self.config_fixture.config(group='cache', caching=True)

        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertFalse(cached_value.cached)

    def test_should_cache_fn_global_cache_enabled_group_cache_disabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally enabled and the specific
        # group caching disabled.
        cacheable_function = self._get_cacheable_function()

        self._add_test_caching_option()
        self.config_fixture.config(group='cache', enabled=True)
        self.config_fixture.config(group='cache', caching=False)

        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertFalse(cached_value.cached)

    def test_should_cache_fn_global_cache_enabled_group_cache_enabled(self):
        # Verify should_cache_fn generates a sane function for subsystem and
        # functions as expected with caching globally enabled and the specific
        # group caching enabled.
        cacheable_function = self._get_cacheable_function()

        self._add_test_caching_option()
        self.config_fixture.config(group='cache', enabled=True)
        self.config_fixture.config(group='cache', caching=True)

        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertTrue(cached_value.cached)

    def test_cache_dictionary_config_builder(self):
        """Validate we build a sane dogpile.cache dictionary config."""
        self.config_fixture.config(group='cache',
                                   config_prefix='test_prefix',
                                   backend='oslo_cache.dict',
                                   expiration_time=86400,
                                   backend_argument=['arg1:test',
                                                     'arg2:test:test',
                                                     'arg3.invalid'])

        config_dict = cache._build_cache_config(self.config_fixture.conf)
        self.assertEqual(
            self.config_fixture.conf.cache.backend,
            config_dict['test_prefix.backend'])
        self.assertEqual(
            self.config_fixture.conf.cache.expiration_time,
            config_dict['test_prefix.expiration_time'])
        self.assertEqual('test', config_dict['test_prefix.arguments.arg1'])
        self.assertEqual('test:test',
                         config_dict['test_prefix.arguments.arg2'])
        self.assertNotIn('test_prefix.arguments.arg3', config_dict)

    def test_cache_dictionary_config_builder_global_disabled(self):
        """Validate the backend is reset to default if caching is disabled."""
        self.config_fixture.config(group='cache',
                                   enabled=False,
                                   config_prefix='test_prefix',
                                   backend='oslo_cache.dict')

        self.assertFalse(self.config_fixture.conf.cache.enabled)
        config_dict = cache._build_cache_config(self.config_fixture.conf)
        self.assertEqual(
            _opts._DEFAULT_BACKEND,
            config_dict['test_prefix.backend'])

    def test_cache_debug_proxy(self):
        single_value = 'Test Value'
        single_key = 'testkey'
        multi_values = {'key1': 1, 'key2': 2, 'key3': 3}

        self.region.set(single_key, single_value)
        self.assertEqual(single_value, self.region.get(single_key))

        self.region.delete(single_key)
        self.assertEqual(NO_VALUE, self.region.get(single_key))

        self.region.set_multi(multi_values)
        cached_values = self.region.get_multi(multi_values.keys())
        for value in multi_values.values():
            self.assertIn(value, cached_values)
        self.assertEqual(len(multi_values.values()), len(cached_values))

        self.region.delete_multi(multi_values.keys())
        for value in self.region.get_multi(multi_values.keys()):
            self.assertEqual(NO_VALUE, value)

    def test_configure_non_region_object_raises_error(self):
        self.assertRaises(exception.ConfigurationError,
                          cache.configure_cache_region,
                          self.config_fixture.conf,
                          "bogus")

    def test_kwarg_function_key_generator_no_kwargs(self):
        cacheable_function = self._get_cacheable_function(
            region=self.region_kwargs)

        self.config_fixture.config(group='cache', enabled=True)
        cacheable_function(self.test_value)
        cached_value = cacheable_function(self.test_value)
        self.assertTrue(cached_value.cached)

    def test_kwarg_function_key_generator_with_kwargs(self):
        cacheable_function = self._get_cacheable_function(
            region=self.region_kwargs)

        self.config_fixture.config(group='cache', enabled=True)
        cacheable_function(value=self.test_value)
        cached_value = cacheable_function(value=self.test_value)
        self.assertTrue(cached_value.cached)

class UTF8KeyManglerTests(BaseTestCase):

    def test_key_is_utf8_encoded(self):
        key = u'fäké1'
        encoded = cache._sha1_mangle_key(key)
        self.assertIsNotNone(encoded)

    def test_key_is_bytestring(self):
        key = b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'
        encoded = cache._sha1_mangle_key(key)
        self.assertIsNotNone(encoded)

    def test_key_is_string(self):
        key = 'fake'
        encoded = cache._sha1_mangle_key(key)
        self.assertIsNotNone(encoded)
<|endoftext|>


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

import ujson as json
import pandas as pd
import numpy as np
import re
from wand.image import Image

from agri_med_backend.constants import *
from agri_med_backend import cfg
from agri_med_backend import util

def upload_img_handler(params, files):
    cfg.logger.warning('params: %s files: %s', params, files)

    the_file = files.get('file', None)
    if not the_file:
        return {'success': False, 'errorMsg': 'no file'}

    basename = ''
    the_timestamp = util.get_timestamp()
    while True:
        basename = str(the_timestamp) + util.gen_random_string()
        if basename[0] != '-':
            break

    filename = cfg.config.get('img_dir', '/data/agri_med/img') + '/' + basename

    cfg.logger.warning('to write file: the_file: %s name: %s basename: %s filename: %s', the_file, the_file.name, basename, filename)
    try:
        content = the_file.file.read()
        with Image(blob=content) as original:
            width, height = original.size
            if width >= 600:
                new_height = int(height * 600 / width)
                original = original.resize(width=600, height=new_height)
            converted = original.convert(format='png')
            with open(filename, 'w') as f:
                converted.save(f)
    except Exception as e:
        cfg.logger.error('unable to save: filename: %s e: %s', filename, e)

    path = '/get/img?name=%s' % (basename)

    return {'success': True, 'path': path}
<commit_msg>resize<commit_after># -*- coding: utf-8 -*-

import ujson as json
import pandas as pd
import numpy as np
import re
from wand.image import Image

from agri_med_backend.constants import *
from agri_med_backend import cfg
from agri_med_backend import util

def upload_img_handler(params, files):
    cfg.logger.warning('params: %s files: %s', params, files)

    the_file = files.get('file', None)
    if not the_file:
        return {'success': False, 'errorMsg': 'no file'}

    basename = ''
    the_timestamp = util.get_timestamp()
    while True:
        basename = str(the_timestamp) + util.gen_random_string()
        if basename[0] != '-':
            break

    filename = cfg.config.get('img_dir', '/data/agri_med/img') + '/' + basename

    cfg.logger.warning('to write file: the_file: %s name: %s basename: %s filename: %s', the_file, the_file.name, basename, filename)
    try:
        content = the_file.file.read()
        with Image(blob=content) as original:
            width, height = original.size
            if width >= 600:
                new_height = int(height * 600 / width)
                original.resize(width=600, height=new_height)
            converted = original.convert(format='png')
            with open(filename, 'w') as f:
                converted.save(f)
    except Exception as e:
        cfg.logger.error('unable to save: filename: %s e: %s', filename, e)

    path = '/get/img?name=%s' % (basename)

    return {'success': True, 'path': path}
<|endoftext|>


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

from base import *
from objecttree import ObjectTree
from memoryfs import MemoryFS

class DirMount(object):
    def __init__(self, path, fs):
        self.path = path
        self.fs = fs

    def __str__(self):
        return "Mount point: %s"%self.path

class FileMount(object):
    def __init__(self, path, open_callable, info_callable=None):
        self.open_callable = open_callable
        def no_info_callable(path):
            return {}
        self.info_callable = info_callable or no_info_callable

class MountFS(FS):
    """A filesystem that delegates to other filesystems."""

    DirMount = DirMount
    FileMount = FileMount

    def __init__(self, thread_synchronize=True):
        FS.__init__(self, thread_synchronize=thread_synchronize)
        self.mount_tree = ObjectTree()

    def __str__(self):
        return "<MountFS>"

    __repr__ = __str__

    def __unicode__(self):
        return unicode(self.__str__())

    def _delegate(self, path):
        path = normpath(path)
        head_path, object, tail_path = self.mount_tree.partialget(path)

        if type(object) is MountFS.DirMount:
            dirmount = object
            return dirmount.fs, head_path, tail_path

        if object is None:
            return None, None, None

        return self, head_path, tail_path

    def desc(self, path):
        self._lock.acquire()
        try:
            fs, mount_path, delegate_path = self._delegate(path)
            if fs is self:
                if fs.isdir(path):
                    return "Mount dir"
                else:
                    return "Mounted file"
            return "Mounted dir, maps to path %s on %s" % (delegate_path, str(fs))
        finally:
            self._lock.release()

    def isdir(self, path):
        self._lock.acquire()
        try:
            fs, mount_path, delegate_path = self._delegate(path)
            if fs is None:
                raise ResourceNotFoundError(path)

            if fs is self:
                object = self.mount_tree.get(path, None)
                return isinstance(object, dict)
            else:
                return fs.isdir(delegate_path)
        finally:
            self._lock.release()

    def isfile(self, path):

        self._lock.acquire()
        try:
            fs, mount_path, delegate_path = self._delegate(path)
            if fs is None:
                return ResourceNotFoundError(path)

            if fs is self:
                object = self.mount_tree.get(path, None)
                return type(object) is MountFS.FileMount
            else:
                return fs.isfile(delegate_path)
        finally:
            self._lock.release()

    def listdir(self, path="/", wildcard=None, full=False, absolute=False, dirs_only=False, files_only=False):

        self._lock.acquire()
        try:
            path = normpath(path)
            fs, mount_path, delegate_path = self._delegate(path)

            if fs is None:
                raise ResourceNotFoundError(path)

            if fs is self:
                if files_only:
                    return []

                paths = self.mount_tree[path].keys()
                return self._listdir_helper(path,
                                            paths,
                                            wildcard,
                                            full,
                                            absolute,
                                            dirs_only,
                                            files_only)
            else:
                paths = fs.listdir(delegate_path,
                                   wildcard=wildcard,
                                   full=False,
                                   absolute=False,
                                   dirs_only=dirs_only,
                                   files_only=files_only)
                if full or absolute:
                    if full:
                        path = abspath(normpath(path))
                    else:
                        path = relpath(normpath(path))
                    paths = [pathjoin(path, p) for p in paths]

                return paths
        finally:
            self._lock.release()

    def makedir(self, path, recursive=False, allow_recreate=False):
        path = normpath(path)
        self._lock.acquire()
        try:
            fs, mount_path, delegate_path = self._delegate(path)
            if fs is self:
                raise UnsupportedError("make directory", msg="Can only makedir for mounted paths" )
            return fs.makedir(delegate_path, recursive=recursive, allow_recreate=allow_recreate)
        finally:
            self._lock.release()

    def open(self, path, mode="r", **kwargs):

        self._lock.acquire()
        try:
            path = normpath(path)
            object = self.mount_tree.get(path, None)
            if type(object) is MountFS.FileMount:
                callable = object.open_callable
                return callable(path, mode, **kwargs)

            fs, mount_path, delegate_path = self._delegate(path)

            if fs is None:
                raise ResourceNotFoundError(path)

            return fs.open(delegate_path, mode, **kwargs)

        finally:
            self._lock.release()

    def exists(self, path):

        self._lock.acquire()
        try:

            path = normpath(path)
            fs, mount_path, delegate_path = self._delegate(path)

            if fs is None:
                return False

            if fs is self:
                return path in self.mount_tree

            return fs.exists(delegate_path)

        finally:
            self._lock.release()

    def remove(self, path):
        self._lock.acquire()
        try:
            path = normpath(path)
            fs, mount_path, delegate_path = self._delegate(path)
            if fs is None:
                raise ResourceNotFoundError(path)
            if fs is self:
                raise UnsupportedError("remove file", msg="Can only remove paths within a mounted dir")
            return fs.remove(delegate_path)

        finally:
            self._lock.release()

    def removedir(self, path, recursive=False, force=False):

        self._lock.acquire()
        try:

            path = normpath(path)
            fs, mount_path, delegate_path = self._delegate(path)

            if fs is None or fs is self:
                raise ResourceInvalidError(path, msg="Can not removedir for an un-mounted path")

            if not force and not fs.isdirempty(delegate_path):
                raise DirectoryNotEmptyError("Directory is not empty: %(path)s")

            return fs.removedir(delegate_path, recursive, force)

        finally:
            self._lock.release()

    def rename(self, src, dst):

        if not issamedir(src, dst):
            raise ValueError("Destination path must the same directory (use the move method for moving to a different directory)")

        self._lock.acquire()
        try:
            fs1, mount_path1, delegate_path1 = self._delegate(src)
            fs2, mount_path2, delegate_path2 = self._delegate(dst)

            if fs1 is not fs2:
                raise OperationFailedError("rename resource", path=src)

            if fs1 is not self:
                return fs1.rename(delegate_path1, delegate_path2)

            path_src = normpath(src)
            path_dst = normpath(dst)

            object = self.mount_tree.get(path_src, None)
            object2 = self.mount_tree.get(path_dst, None)

            if object1 is None:
                raise ResourceNotFoundError(src)

            # TODO!

            raise UnsupportedError("rename resource", path=src)
        finally:
            self._lock.release()

    def mountdir(self, path, fs):
        """Mounts a directory on a given path.

        path -- A path within the MountFS
        fs -- A filesystem object to mount

        """
        self._lock.acquire()
        try:
            path = normpath(path)
            self.mount_tree[path] = MountFS.DirMount(path, fs)
        finally:
            self._lock.release()
    mount = mountdir

    def mountfile(self, path, open_callable=None, info_callable=None):
        self._lock.acquire()
        try:
            path = normpath(path)
            self.mount_tree[path] = MountFS.FileMount(path, callable, info_callable)
        finally:
            self._lock.release()

    def getinfo(self, path):

        self._lock.acquire()
        try:
            path = normpath(path)

            fs, mount_path, delegate_path = self._delegate(path)

            if fs is None:
                raise ResourceNotFoundError(path)

            if fs is self:
                if self.isfile(path):
                    return self.mount_tree[path].info_callable(path)
                return {}
            return fs.getinfo(delegate_path)
        finally:
            self._lock.release()

    def getsize(self, path):
        self._lock.acquire()
        try:
            path = normpath(path)
            fs, mount_path, delegate_path = self._delegate(path)

            if fs is None:
                raise ResourceNotFoundError(path)

            if fs is self:
                object = self.mount_tree.get(path, None)

                if object is None or isinstance(object, dict):
                    raise ResourceNotFoundError(path)

                size = self.mount_tree[path].info_callable(path).get("size", None)
                return size

            return fs.getinfo(delegate_path).get("size", None)
        except:
            self._lock.release()

<commit_msg>fix a locking bug in MountFS.getsize<commit_after>#!/usr/bin/env python

from fs.base import *
from fs.objecttree import ObjectTree

class DirMount(object):
    def __init__(self, path, fs):
        self.path = path
        self.fs = fs

    def __str__(self):
        return "Mount point: %s"%self.path

class FileMount(object):
    def __init__(self, path, open_callable, info_callable=None):
        self.open_callable = open_callable
        def no_info_callable(path):
            return {}
        self.info_callable = info_callable or no_info_callable

class MountFS(FS):
    """A filesystem that delegates to other filesystems."""

    DirMount = DirMount
    FileMount = FileMount

    def __init__(self, thread_synchronize=True):
        FS.__init__(self, thread_synchronize=thread_synchronize)
        self.mount_tree = ObjectTree()

    def __str__(self):
        return "<MountFS>"

    __repr__ = __str__

    def __unicode__(self):
        return unicode(self.__str__())

    def _delegate(self, path):
        path = normpath(path)
        head_path, object, tail_path = self.mount_tree.partialget(path)

        if type(object) is MountFS.DirMount:
            dirmount = object
            return dirmount.fs, head_path, tail_path

        if object is None:
            return None, None, None

        return self, head_path, tail_path

    @synchronize
    def desc(self, path):
        fs, mount_path, delegate_path = self._delegate(path)
        if fs is self:
            if fs.isdir(path):
                return "Mount dir"
            else:
                return "Mounted file"
        return "Mounted dir, maps to path %s on %s" % (delegate_path, str(fs))

    @synchronize
    def isdir(self, path):
        fs, mount_path, delegate_path = self._delegate(path)
        if fs is None:
            raise ResourceNotFoundError(path)

        if fs is self:
            object = self.mount_tree.get(path, None)
            return isinstance(object, dict)
        else:
            return fs.isdir(delegate_path)

    @synchronize
    def isfile(self, path):
        fs, mount_path, delegate_path = self._delegate(path)
        if fs is None:
            return ResourceNotFoundError(path)

        if fs is self:
            object = self.mount_tree.get(path, None)
            return type(object) is MountFS.FileMount
        else:
            return fs.isfile(delegate_path)

    @synchronize
    def listdir(self, path="/", wildcard=None, full=False, absolute=False, dirs_only=False, files_only=False):
        path = normpath(path)
        fs, mount_path, delegate_path = self._delegate(path)

        if fs is None:
            raise ResourceNotFoundError(path)

        if fs is self:
            if files_only:
                return []

            paths = self.mount_tree[path].keys()
            return self._listdir_helper(path,
                                        paths,
                                        wildcard,
                                        full,
                                        absolute,
                                        dirs_only,
                                        files_only)
        else:
            paths = fs.listdir(delegate_path,
                               wildcard=wildcard,
                               full=False,
                               absolute=False,
                               dirs_only=dirs_only,
                               files_only=files_only)
            if full or absolute:
                if full:
                    path = abspath(normpath(path))
                else:
                    path = relpath(normpath(path))
                paths = [pathjoin(path, p) for p in paths]

            return paths

    @synchronize
    def makedir(self, path, recursive=False, allow_recreate=False):
        path = normpath(path)
        fs, mount_path, delegate_path = self._delegate(path)
        if fs is self:
            raise UnsupportedError("make directory", msg="Can only makedir for mounted paths" )
        return fs.makedir(delegate_path, recursive=recursive, allow_recreate=allow_recreate)

    @synchronize
    def open(self, path, mode="r", **kwargs):
        path = normpath(path)
        object = self.mount_tree.get(path, None)
        if type(object) is MountFS.FileMount:
            callable = object.open_callable
            return callable(path, mode, **kwargs)

        fs, mount_path, delegate_path = self._delegate(path)

        if fs is None:
            raise ResourceNotFoundError(path)

        return fs.open(delegate_path, mode, **kwargs)

    @synchronize
    def exists(self, path):
        path = normpath(path)
        fs, mount_path, delegate_path = self._delegate(path)
        if fs is None:
            return False
        if fs is self:
            return path in self.mount_tree
        return fs.exists(delegate_path)

    @synchronize
    def remove(self, path):
        path = normpath(path)
        fs, mount_path, delegate_path = self._delegate(path)
        if fs is None:
            raise ResourceNotFoundError(path)
        if fs is self:
            raise UnsupportedError("remove file", msg="Can only remove paths within a mounted dir")
        return fs.remove(delegate_path)

    @synchronize
    def removedir(self, path, recursive=False, force=False):
        path = normpath(path)
        fs, mount_path, delegate_path = self._delegate(path)

        if fs is None or fs is self:
            raise ResourceInvalidError(path, msg="Can not removedir for an un-mounted path")

        if not force and not fs.isdirempty(delegate_path):
            raise DirectoryNotEmptyError("Directory is not empty: %(path)s")

        return fs.removedir(delegate_path, recursive, force)

    @synchronize
    def rename(self, src, dst):
        if not issamedir(src, dst):
            raise ValueError("Destination path must the same directory (use the move method for moving to a different directory)")
        fs1, mount_path1, delegate_path1 = self._delegate(src)
        fs2, mount_path2, delegate_path2 = self._delegate(dst)

        if fs1 is not fs2:
            raise OperationFailedError("rename resource", path=src)

        if fs1 is not self:
            return fs1.rename(delegate_path1, delegate_path2)

        path_src = normpath(src)
        path_dst = normpath(dst)

        object = self.mount_tree.get(path_src, None)
        object2 = self.mount_tree.get(path_dst, None)

        if object1 is None:
            raise ResourceNotFoundError(src)

        # TODO!
        raise UnsupportedError("rename resource", path=src)

    @synchronize
    def mountdir(self, path, fs):
        """Mounts a directory on a given path.

        path -- A path within the MountFS
        fs -- A filesystem object to mount

        """
        path = normpath(path)
        self.mount_tree[path] = MountFS.DirMount(path, fs)
    mount = mountdir

    @synchronize
    def mountfile(self, path, open_callable=None, info_callable=None):
        path = normpath(path)
        self.mount_tree[path] = MountFS.FileMount(path, callable, info_callable)

    @synchronize
    def getinfo(self, path):
        path = normpath(path)

        fs, mount_path, delegate_path = self._delegate(path)

        if fs is None:
            raise ResourceNotFoundError(path)

        if fs is self:
            if self.isfile(path):
                return self.mount_tree[path].info_callable(path)
            return {}
        return fs.getinfo(delegate_path)

    @synchronize
    def getsize(self, path):
        path = normpath(path)
        fs, mount_path, delegate_path = self._delegate(path)

        if fs is None:
            raise ResourceNotFoundError(path)

        if fs is self:
            object = self.mount_tree.get(path, None)

            if object is None or isinstance(object, dict):
                raise ResourceNotFoundError(path)

            size = self.mount_tree[path].info_callable(path).get("size", None)
            return size

        return fs.getinfo(delegate_path).get("size", None)

<|endoftext|>


<commit_before>from ott.utils import json_utils
from ott.utils import html_utils
from ott.otp_client  import otp_to_ott
from ott.utils.parse import TripParamParser
from ott.geocoder.geosolr import GeoSolr

import sys
import simplejson as json
import urllib
import contextlib
import logging
log = logging.getLogger(__file__)

class TripPlanner(object):
    def __init__(self, otp_url="http://localhost/prod", solr='http://localhost/solr', adverts=None, fares=None, cancelled_routes=None):
        self.otp_url = otp_url

        self.geo = solr
        if isinstance(solr, str):
            self.geo = GeoSolr(solr)

        self.adverts = adverts
        self.fares = fares
        self.cancelled_routes = cancelled_routes

        # optionally create Adverts and Fares objects
        # note: requires change to this buildout to include the ott.data project
        try:
            from ott.data.content import Adverts
            from ott.data.content import Fares
            from ott.data.content import CancelledRoutes

            if isinstance(adverts, str):
                self.adverts = Adverts(adverts)

            if isinstance(fares, str):
                self.fares = Fares(fares)
        except Exception, e:
            log.warn(e)

    def plan_trip(self, request=None, pretty=False):
        """ "powell%20blvd::45.49063653,-122.4822897"  "45.433507,-122.559709"
        """
        #import pdb; pdb.set_trace()

        # step 1: parse params
        param = TripParamParser(request)

        # step 2: handle any geocoding needing to be done -- note, changes param object implicitly in the call
        msg = self.geocode(param)
        if msg:
            # TODO -- trip error or plan?
            pass

        # step 3: call the trip planner...
        otp_params = param
        if otp_params.is_latest():
            # step 3b: if we have Arr=L (latest trip), we need to increase the date by 1 day, since LATEST
            # trip is essentially an ArriveBy 1:30am trip
            otp_params = param.clone()
            otp_params.date_offset(day_offset=1)
        url = "{0}?{1}".format(self.otp_url, otp_params.otp_url_params())
        f = self.call_otp(url)
        j = json.loads(f)

        # step 4: process any planner errors
        if j is None:
            pass
            # TODO -- trip error or plan?

        # step 5: parse the OTP trip plan into OTT format
        ret_val = {}
        try:
            plan = otp_to_ott.Plan(jsn=j['plan'], params=param, fares=self.fares)
            ret_val['plan'] = plan

            if self.adverts:
                m = plan.dominant_transit_mode()
                l = html_utils.get_lang(request)
                ret_val['adverts'] = self.adverts.query(m, l)
        except Exception, e:
            try:
                ret_val['error'] = otp_to_ott.Error(j['error'], param)
            except:
                log.warn("I think we had a problem parsing the JSON from OTP ... see exception below:")
                log.warn(e)

        ret_val = json_utils.json_repr(ret_val, pretty or param.pretty_output())
        return ret_val

    @classmethod
    def call_otp(cls, url):
        ret_val = None
        try:
            log.info(url)
            with contextlib.closing(urllib.urlopen(url)) as f:
                ret_val = f.read()
        except Exception as e:
            log.warn(e)
        return ret_val

    def geocode(self, param):
        """ TODO ... rethink this whole thing
            1) should geocoding be in param_parser
            2) we're going to need other parsers ... like for stops, etc... (where we only need to geocode 1 param, etc...)
            3) ....
        """
        ret_val = None

        # step 2: get your origin
        f = param.get_from()
        if not param.has_valid_coord(f):
            # step 2b: geocode the origin if you don't have a valid ::LatLon
            f = param.strip_coord(f)
            f = self.geo.geostr(f)
            param.frm = f

        # step 3: get your destination
        t = param.get_to()
        if not param.has_valid_coord(t):
            # step 3b: geocode the destination if you don't have a valid ::LatLon
            t = param.strip_coord(t)
            t = self.geo.geostr(t)
            param.to = t

        return ret_val

def main():
    argv = sys.argv
    pretty = 'pretty' in argv or 'p' in argv
    trimet = 'trimet' in argv or 'tm' in argv
    if trimet:
        tp = TripPlanner(otp_url="http://maps.trimet.org/prod", solr='http://maps.trimet.org/solr')
    else:
        tp = TripPlanner()

    plan = tp.plan_trip(argv[1], pretty)
    print plan

if __name__ == '__main__':
    main()
<commit_msg>add cancelled / banned routes<commit_after>from ott.utils import json_utils
from ott.utils import html_utils
from ott.otp_client  import otp_to_ott
from ott.utils.parse import TripParamParser
from ott.geocoder.geosolr import GeoSolr

import sys
import simplejson as json
import urllib
import contextlib
import logging
log = logging.getLogger(__file__)

class TripPlanner(object):
    def __init__(self, otp_url="http://localhost/prod", solr='http://localhost/solr', adverts=None, fares=None, cancelled_routes=None):
        self.otp_url = otp_url

        self.geo = solr
        if isinstance(solr, str):
            self.geo = GeoSolr(solr)

        self.adverts = adverts
        self.fares = fares
        self.cancelled_routes = cancelled_routes

        # optionally create Adverts and Fares objects
        # note: requires change to this buildout to include the ott.data project
        try:
            from ott.data.content import Adverts
            from ott.data.content import Fares
            from ott.data.content import CancelledRoutes

            if isinstance(adverts, str):
                self.adverts = Adverts(adverts)

            if isinstance(fares, str):
                self.fares = Fares(fares)
        except Exception, e:
            log.warn(e)

    def plan_trip(self, request=None, pretty=False):
        """ "powell%20blvd::45.49063653,-122.4822897"  "45.433507,-122.559709"
        """
        #import pdb; pdb.set_trace()

        # step 1: parse params
        param = TripParamParser(request)

        # step 2: handle any geocoding needing to be done -- note, changes param object implicitly in the call
        msg = self.geocode(param)
        if msg:
            # TODO -- trip error or plan?
            pass

        # step 3: call the trip planner...
        otp_params = param
        otp_params.banned_routes = self.cancelled_routes
        if otp_params.is_latest():
            # step 3b: if we have Arr=L (latest trip), we need to increase the date by 1 day, since LATEST
            # trip is essentially an ArriveBy 1:30am trip
            otp_params = param.clone()
            otp_params.date_offset(day_offset=1)

        url = "{0}?{1}".format(self.otp_url, otp_params.otp_url_params())
        f = self.call_otp(url)
        j = json.loads(f)

        # step 4: process any planner errors
        if j is None:
            pass
            # TODO -- trip error or plan?

        # step 5: parse the OTP trip plan into OTT format
        ret_val = {}
        try:
            plan = otp_to_ott.Plan(jsn=j['plan'], params=param, fares=self.fares)
            ret_val['plan'] = plan

            if self.adverts:
                m = plan.dominant_transit_mode()
                l = html_utils.get_lang(request)
                ret_val['adverts'] = self.adverts.query(m, l)
        except Exception, e:
            try:
                ret_val['error'] = otp_to_ott.Error(j['error'], param)
            except:
                log.warn("I think we had a problem parsing the JSON from OTP ... see exception below:")
                log.warn(e)

        ret_val = json_utils.json_repr(ret_val, pretty or param.pretty_output())
        return ret_val

    @classmethod
    def call_otp(cls, url):
        ret_val = None
        try:
            log.info(url)
            with contextlib.closing(urllib.urlopen(url)) as f:
                ret_val = f.read()
        except Exception as e:
            log.warn(e)
        return ret_val

    def geocode(self, param):
        """ TODO ... rethink this whole thing
            1) should geocoding be in param_parser
            2) we're going to need other parsers ... like for stops, etc... (where we only need to geocode 1 param, etc...)
            3) ....
        """
        ret_val = None

        # step 2: get your origin
        f = param.get_from()
        if not param.has_valid_coord(f):
            # step 2b: geocode the origin if you don't have a valid ::LatLon
            f = param.strip_coord(f)
            f = self.geo.geostr(f)
            param.frm = f

        # step 3: get your destination
        t = param.get_to()
        if not param.has_valid_coord(t):
            # step 3b: geocode the destination if you don't have a valid ::LatLon
            t = param.strip_coord(t)
            t = self.geo.geostr(t)
            param.to = t

        return ret_val

def main():
    argv = sys.argv
    pretty = 'pretty' in argv or 'p' in argv
    trimet = 'trimet' in argv or 'tm' in argv
    if trimet:
        tp = TripPlanner(otp_url="http://maps.trimet.org/prod", solr='http://maps.trimet.org/solr')
    else:
        tp = TripPlanner()

    plan = tp.plan_trip(argv[1], pretty)
    print plan

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


<commit_before># -*- coding: utf-8 -*-
from __future__ import print_function

import os
import codecs
import logging

from exhibitionist.toolbox import (getLogger, http_handler, JSONRequestHandler,
                                   CORSMixin, StaticFileHandler,
                                   utf8, HTTPError, xhtml_escape)

context = None # get rid of "symbol missing" squiggles in rope

logger = getLogger(__name__)

# you can use your favorite template engine instead
# tornado engine uses "{{context}}" style placeholders,
# tmpl=Template(str) to construct templates,
# and tmpl.generate(**kwds), to render.
from tornado.template import Template

PROJECT_NAME = "myAwesomeProject"

# This endpoint will be  at http://{server_addr}/myAwesomeProject/{objid}
# JSONRequestHandler is a subclass of tornado's RequestHandler
# with the addition of JSONMixin, providing the write_json()
# method.
@http_handler(r'/%s/{{objid}}' % PROJECT_NAME,foo='bar')
class MainViewHandler(JSONRequestHandler):

    # any custom kwds argument specified via @http_handler
    # will be available in kwds
    def initialize(self,**kwds):
        kwds.get('foo') == 'bar'

    # prepare is called after __init__ is run
    def prepare(self):
        pass

    # get is invoked when the user issues an HTTP GET request, the
    # common case. You can also implement put, post, delete and others
    # similarly. see http://www.tornadoweb.org/documentation/web.html
    # whenever the special marker {{objid}} is included in the route
    # objid is passed as an argument to get, and the associated object
    # itself is available at 'context.object'. if an unrecognized
    # objid is provided, a 404 will be raised automatically.
    def get(self, objid):

        # Instantiate a template object using Template engine
        # This can be moved to prepare() when index.html is stabilized
        # Done like this, changes to the template are reflected
        # on (no-cache) refresh

        tmpl_file = os.path.join(self.get_template_path(),"index.html")
        if not(os.path.isdir(self.get_template_path())):
            # logger.fatal(self.transforms)
            logger.fatal(self._transforms)
            self.set_status(500)
            return self.finish("Template path does not exist")

        with codecs.open(tmpl_file) as f:
            self.tmpl = Template(f.read())

        # validate the object's type to avoid mysterious errors later on
        if not isinstance(context.object, list):
            self.set_status(500)
            return self.finish("bad object type")

        # Tornado makes query parameters available via `get_argument`.
        # Here we handle requests for "/myAwesomeProject/{objid}?format=json".
        # These are usually the AJAX requests issued by the client *after*
        # grabbing the HTML page, below.
        if self.get_argument("format", "").lower() == "json":
            # For this example, the payload for the json data returned
            # is just the string representation of the object.
            payload = unicode(context.object).encode('utf-8', 'replace')

            # write_json will encode the payload as json, and send it
            # to the client.
            #
            # IMPORTANT: the payload must be JSON-Encodable.
            #
            # JSONP is automatically used if a query parameter called "callback"
            # was given, jQuery's default name for jsnop.
            # See CORSMixin if you prefer avoiding JSONP.
            self.write_json(dict(payload=payload))

        # if the client requested "/myAwesomeProject/{objid}"
        # we render the HTMl and send it back to the client
        # this is usually the first request.
        else:
            # The object associated with {objid} is available here
            obj = context.object

            # Get back the url of this view. We embed this in the HTML returned
            # to the client, which uses it to issue AJAX requests back to us.
            # e.g '$.getJSON(api_url + "?format=json")' (javascript)
            # See templates/index.html for the javascript side of things
            api_url = context.get_view_url("MainViewHandler", obj)
            api_url += "?format=json"  # add query parameter to url

            # get the websocket connection url ("ws://server_addr/ws")
            # Also embedded int he client HTML, the client opens a websocket
            # on load, and subscribes to notification on the "channel= {objid}"
            ws_url = context.get_ws_url()
            logger.info(self.static_url("."))
            # render the template , see /templates/index.html

            static_base=self.static_url("")[:-1] # strip trailing slash

            body = self.tmpl.generate(
                                      objid=objid,
                                      api_url=api_url,
                                      ws_url=ws_url,
                                      static_url=self.static_url)

            self.write(body) # send the HTML to client

# This handler demonstrates a different style of doing things
# with unique paths, rather then query parameters as seen above.
# CORSMixin can be used to allow cross-origin requests from FriendlyDomain.com

# Uncomment the decorator to activate this endpoint
#@http_handler(r'/%s/{{objid}}/(?P<parity>odd|even)'% PROJECT_NAME)
class AlternativeHandler(CORSMixin('FriendlyDomain.com'), JSONRequestHandler):
    def __init__(self, *args, **kwds):
        super(AlternativeHandler, self).__init__(*args, **kwds)

    # note the 'parity' arg, corresponding to route regex named capture group
    def get(self, objid, parity):

        # validate the object's type to avoid mysterious errors later on
        if not isinstance(context.object, list):
            raise HTTPError(500, # Server Error status code
                            log_message="bad object type") # to the client

        parity = parity.lower()
        base = 0
        if parity == 'odd':
            base = 1 # just the odd elements
        elif parity == 'even':
            base = 0 # just the even elements
        else:
            raise HTTPError(500, # Server Error status code
                            log_message="bad parity")

        # For this example, the payload for the json data returned
        # is just the string representation of the object.
        payload = context.object[base::2]

        # ensure payload is JSON-Encodable by converting everything to it's utf8 repr
        payload = map(utf8, payload)

        # always escape data which might end up as HTML.
        payload = map(xhtml_escape,
                      map(utf8, payload)) # ensure JSON-Encodable
        self.write_json(dict(payload=payload))

<commit_msg>ENH: tweak boilerplate example , better error message, accept list/tuple<commit_after># -*- coding: utf-8 -*-
from __future__ import print_function

import os
import codecs
import logging

from exhibitionist.toolbox import (getLogger, http_handler, JSONRequestHandler,
                                   CORSMixin, StaticFileHandler,
                                   utf8, HTTPError, xhtml_escape)

context = None # get rid of "symbol missing" squiggles in rope

logger = getLogger(__name__)

# you can use your favorite template engine instead
# tornado engine uses "{{context}}" style placeholders,
# tmpl=Template(str) to construct templates,
# and tmpl.generate(**kwds), to render.
from tornado.template import Template

PROJECT_NAME = "myAwesomeProject"

# This endpoint will be  at http://{server_addr}/myAwesomeProject/{objid}
# JSONRequestHandler is a subclass of tornado's RequestHandler
# with the addition of JSONMixin, providing the write_json()
# method.
@http_handler(r'/%s/{{objid}}' % PROJECT_NAME,foo='bar')
class MainViewHandler(JSONRequestHandler):

    # any custom kwds argument specified via @http_handler
    # will be available in kwds
    def initialize(self,**kwds):
        kwds.get('foo') == 'bar'

    # prepare is called after __init__ is run
    def prepare(self):
        pass

    # get is invoked when the user issues an HTTP GET request, the
    # common case. You can also implement put, post, delete and others
    # similarly. see http://www.tornadoweb.org/documentation/web.html
    # whenever the special marker {{objid}} is included in the route
    # objid is passed as an argument to get, and the associated object
    # itself is available at 'context.object'. if an unrecognized
    # objid is provided, a 404 will be raised automatically.
    def get(self, objid):

        # Instantiate a template object using Template engine
        # This can be moved to prepare() when index.html is stabilized
        # Done like this, changes to the template are reflected
        # on (no-cache) refresh

        tmpl_file = os.path.join(self.get_template_path(),"index.html")
        if not(os.path.isdir(self.get_template_path())):
            # logger.fatal(self.transforms)
            logger.fatal(self._transforms)
            self.set_status(500)
            return self.finish("Template path does not exist")

        with codecs.open(tmpl_file) as f:
            self.tmpl = Template(f.read())

        # validate the object's type to avoid mysterious errors later on
        if not isinstance(context.object, (list,tuple)):
            self.set_status(500)
            return self.finish("Bad object type, expected list or tuple")

        # Tornado makes query parameters available via `get_argument`.
        # Here we handle requests for "/myAwesomeProject/{objid}?format=json".
        # These are usually the AJAX requests issued by the client *after*
        # grabbing the HTML page, below.
        if self.get_argument("format", "").lower() == "json":
            # For this example, the payload for the json data returned
            # is just the string representation of the object.
            payload = unicode(context.object).encode('utf-8', 'replace')

            # write_json will encode the payload as json, and send it
            # to the client.
            #
            # IMPORTANT: the payload must be JSON-Encodable.
            #
            # JSONP is automatically used if a query parameter called "callback"
            # was given, jQuery's default name for jsnop.
            # See CORSMixin if you prefer avoiding JSONP.
            self.write_json(dict(payload=payload))

        # if the client requested "/myAwesomeProject/{objid}"
        # we render the HTMl and send it back to the client
        # this is usually the first request.
        else:
            # The object associated with {objid} is available here
            obj = context.object

            # Get back the url of this view. We embed this in the HTML returned
            # to the client, which uses it to issue AJAX requests back to us.
            # e.g '$.getJSON(api_url + "?format=json")' (javascript)
            # See templates/index.html for the javascript side of things
            api_url = context.get_view_url("MainViewHandler", obj)
            api_url += "?format=json"  # add query parameter to url

            # get the websocket connection url ("ws://server_addr/ws")
            # Also embedded int he client HTML, the client opens a websocket
            # on load, and subscribes to notification on the "channel= {objid}"
            ws_url = context.get_ws_url()
            logger.info(self.static_url("."))
            # render the template , see /templates/index.html

            static_base=self.static_url("")[:-1] # strip trailing slash

            body = self.tmpl.generate(
                                      objid=objid,
                                      api_url=api_url,
                                      ws_url=ws_url,
                                      static_url=self.static_url)

            self.write(body) # send the HTML to client

# This handler demonstrates a different style of doing things
# with unique paths, rather then query parameters as seen above.
# CORSMixin can be used to allow cross-origin requests from FriendlyDomain.com

# Uncomment the decorator to activate this endpoint
#@http_handler(r'/%s/{{objid}}/(?P<parity>odd|even)'% PROJECT_NAME)
class AlternativeHandler(CORSMixin('FriendlyDomain.com'), JSONRequestHandler):
    def __init__(self, *args, **kwds):
        super(AlternativeHandler, self).__init__(*args, **kwds)

    # note the 'parity' arg, corresponding to route regex named capture group
    def get(self, objid, parity):

        # validate the object's type to avoid mysterious errors later on
        if not isinstance(context.object, list):
            raise HTTPError(500, # Server Error status code
                            log_message="bad object type") # to the client

        parity = parity.lower()
        base = 0
        if parity == 'odd':
            base = 1 # just the odd elements
        elif parity == 'even':
            base = 0 # just the even elements
        else:
            raise HTTPError(500, # Server Error status code
                            log_message="bad parity")

        # For this example, the payload for the json data returned
        # is just the string representation of the object.
        payload = context.object[base::2]

        # ensure payload is JSON-Encodable by converting everything to it's utf8 repr
        payload = map(utf8, payload)

        # always escape data which might end up as HTML.
        payload = map(xhtml_escape,
                      map(utf8, payload)) # ensure JSON-Encodable
        self.write_json(dict(payload=payload))

<|endoftext|>


<commit_before># coding: utf-8
#from redbaron import RedBaron
#from redbaron import IntNode, FloatNode, ComplexNode,StringNode
#from redbaron import NameNode
#from redbaron import AssignmentNode
#from redbaron import CommentNode, EndlNode
#from redbaron import ComparisonNode
#from redbaron import ComparisonOperatorNode
#from redbaron import UnitaryOperatorNode
#from redbaron import BinaryOperatorNode, BooleanOperatorNode
#from redbaron import AssociativeParenthesisNode
#<<<<<<< HEAD
#from redbaron import DefNode
#from redbaron import TupleNode, ListNode
#from redbaron import CommaProxyList
#from redbaron import LineProxyList
#from redbaron import NodeList
#from redbaron import DotProxyList
#=======
#from redbaron import DefNode,ClassNode
#from redbaron import ListNode,TupleNode
#from redbaron import CommaProxyList,CommaNode
#from redbaron import LineProxyList,DotProxyList,NodeList
#>>>>>>> f18b96666364581a3855b76976d2bc1ec78982d1
#from redbaron import ReturnNode
#from redbaron import DefArgumentNode,CallNode,CallArgumentNode
#from redbaron import ForNode,IfelseblockNode,WhileNode,IfNode,ElseNode,ElifNode
#from redbaron import DotNode,AtomtrailersNode,PrintNode
#from redbaron import ComparisonNode,ComparisonOperatorNode
#from redbaron import DelNode
#from redbaron import DictNode, DictitemNode
#from redbaron import ForNode, WhileNode
#from redbaron import IfelseblockNode, IfNode, ElseNode, ElifNode
#from redbaron import DotNode, AtomtrailersNode
#from redbaron import CallNode
#
#
#
#
#from pyccel.ast import NativeInteger, NativeFloat, NativeDouble, NativeComplex
#from pyccel.ast import Nil,Len,Del
#from pyccel.ast import Variable,DottedName
#from pyccel.ast import Assign
#<<<<<<< HEAD
#from pyccel.ast import Return
#from pyccel.ast import FunctionDef
#from pyccel.ast import For
#from pyccel.ast import If
#from pyccel.ast import While
#from pyccel.ast import Print
#from pyccel.ast import Del
#from pyccel.ast import Comment, EmptyLine
#=======
#from pyccel.ast import FunctionDef,FunctionCall,ClassDef
#from pyccel.ast import For,Range,If,While
#from pyccel.ast import Comment, EmptyLine,Print
#from pyccel import fcode
#from pyccel.ast.core import Return
#from pyccel.parser import PyccelParser
#
#>>>>>>> f18b96666364581a3855b76976d2bc1ec78982d1
#
#
#from sympy import Symbol
#from sympy import Tuple
#from sympy import Add, Mul, Pow
#from sympy.logic.boolalg import And, Or
#from sympy.logic.boolalg import true, false
#from sympy.logic.boolalg import Not
##from sympy.logic.boolalg import Boolean,
#from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge
#from sympy import Integer, Float
#<<<<<<< HEAD
#from sympy.core.containers import Dict
#from sympy.core.function import Function
#
## ... TODO should be moved to pyccel.ast
#=======
#from sympy import sympify
#from sympy import And,Or
#from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge
## ... TODO should be moved to pyccel.ast
#>>>>>>> f18b96666364581a3855b76976d2bc1ec78982d1
#from sympy.core.basic import Basic
#from sympy.functions import *
#from sympy import Sum
#Built_in_Functions={'abs':Abs,'dict':'','help':'','min':Min,
#'setattr':'','all':'','dir':'',
#'hex':'','next':'','slice':'','any':'',
#'divmod':'','id':'','object':'','sorted':'',
#'ascii':'','enumerate':'','input':'','oct':'',
#'staticmethod':'','bin':'','eval':'','int':Integer,
#'open':'','str':'','bool':'','exec':'',
#'isinstance':'','ord':'','sum':Sum,'bytearray':'',
#'filter':'','issubclass':'','pow':'','super':'',
#'bytes':'','float':Float,'iter':'','tuple':'','callable':'',
#'format':'','len':Len,'property':'','type':'',
#'chr':'','frozenset':'','list':'','range':Range,
#'vars':'','classmethod':'','getattr':'','locals':'',
#'repr':'','zip':'','compile':'','globals':'',
#'map':'','reversed':'','__import__':'','complex':'',
#'hasattr':'','max':Max,'round':'','delattr':'','hash':'',
#'memoryview':'','set':''}
#
#class Argument(Symbol):
#    """An abstract Argument data structure."""
#    pass
#
#class ValuedArgument(Basic):
#    """Represents a valued argument in the code."""
#
#    def __new__(cls, expr, value):
#        if not isinstance(expr, Argument):
#            raise TypeError('Expecting an argument')
#        return Basic.__new__(cls, expr, value)
#
#    @property
#    def argument(self):
#        return self._args[0]
#
#    @property
#    def value(self):
#        return self._args[1]
#
#    def _sympystr(self, printer):
#        sstr = printer.doprint
#
#        argument = sstr(self.argument)
#        value    = sstr(self.value)
#        return '{0}={1}'.format(argument, value)
## ...
#
## ... utilities
#from sympy import srepr
#from sympy.printing.dot import dotprint
#
#import os
#
#def view_tree(expr):
#    """Views a sympy expression tree."""
#
#    print srepr(expr)
#
#def export_ast(expr, filename):
#    """Exports sympy AST using graphviz then convert it to an image."""
#
#    graph_str = dotprint(expr)
#
#    f = file(filename, 'w')
#    f.write(graph_str)
#    f.close()
#
#    # name without path
#    name = os.path.basename(filename)
#    # name without extension
#    name = os.path.splitext(name)[0]
#    cmd = "dot -Tps {name}.gv -o {name}.ps".format(name=name)
#    os.system(cmd)
## ...
#
#
## TODO use Double instead of Float? or add precision
#def datatype_from_redbaron(node):
#    """Returns the pyccel datatype of a RedBaron Node."""
#    if isinstance(node, IntNode):
#        return NativeInteger()
#    elif isinstance(node, FloatNode):
#        return NativeFloat()
#    elif isinstance(node, ComplexNode):
#        return NativeComplex()
#    else:
#        raise NotImplementedError('TODO')
#
#def fst_to_ast(stmt):
#    """Creates AST from FST."""
#<<<<<<< HEAD
#    if isinstance(stmt, (RedBaron,
#                         CommaProxyList, LineProxyList, NodeList,
#                         TupleNode, ListNode)):
#=======
#    if isinstance(stmt, (RedBaron, CommaProxyList, LineProxyList, ListNode,TupleNode,NodeList)):
#>>>>>>> f18b96666364581a3855b76976d2bc1ec78982d1
#        ls = [fst_to_ast(i) for i in stmt]
#        return Tuple(*ls)
#    elif isinstance(stmt, DictNode):
#        d = {}
#        for i in stmt.value:
#            if not isinstance(i, DictitemNode):
#                raise TypeError('Expecting a DictitemNode')
#            key   = fst_to_ast(i.key)
#            value = fst_to_ast(i.value)
#            # sympy does not allow keys to be strings
#            if isinstance(key, str):
#                raise TypeError('sympy does not allow keys to be strings')
#            d[key] = value
#        return Dict(d)
#    elif stmt is None:
#        return Nil()
#    elif isinstance(stmt, str):
#        return repr(stmt)
#    elif isinstance(stmt, StringNode):
#        return repr(stmt.value)
#    elif isinstance(stmt,ComparisonOperatorNode):
#        return str(stmt)
#    elif isinstance(stmt, IntNode):
#        return Integer(stmt.value)
#    elif isinstance(stmt, FloatNode):
#        return Float(stmt.value)
#    elif isinstance(stmt, ComplexNode):
#        raise NotImplementedError('ComplexNode not yet available')
#    elif isinstance(stmt, DelNode):
#        arg = fst_to_ast(stmt.value)
#        return Del(arg)
#    elif isinstance(stmt, UnitaryOperatorNode):
#        target = fst_to_ast(stmt.target)
#        if stmt.value == 'not':
#            return Not(target)
#        elif stmt.value == '+':
#            return target
#        elif stmt.value == '-':
#            return -target
#        elif stmt.value == '~':
#            raise ValueError('Invert unary operator is not covered by Pyccel.')
#        else:
#            raise ValueError('unknown/unavailable unary operator '
#                             '{node}'.format(node=type(stmt.value)))
#    elif isinstance(stmt, AssignmentNode):
#        lhs = fst_to_ast(stmt.target)
#        rhs = fst_to_ast(stmt.value)
#        return Assign(lhs, rhs)
#    elif isinstance(stmt, NameNode):
#        if stmt.previous and not isinstance(stmt.previous,CommaNode):
#            return fst_to_ast(stmt.previous)
#        if stmt.value == 'None':
#            return Nil()
#        else:
#            return Symbol(stmt.value)
#    elif isinstance(stmt,PrintNode):
#         ls=fst_to_ast(stmt.value)
#         return Print(ls)
#    elif isinstance(stmt,AtomtrailersNode):
#         return fst_to_ast(stmt.value)
#    elif isinstance(stmt,(IntNode, FloatNode, ComplexNode)):
#        return sympify(stmt.value)
#    elif isinstance(stmt, AssociativeParenthesisNode):
#        return fst_to_ast(stmt.value)
#    elif isinstance(stmt,(BooleanOperatorNode,BinaryOperatorNode,ComparisonNode)) :
#            return op(fst_to_ast(stmt.first),fst_to_ast(stmt.second),str(stmt.value))
#    elif isinstance(stmt, DefArgumentNode):
#        arg = Argument(str(stmt.target))
#        if stmt.value is None:
#            return arg
#        else:
#            value = fst_to_ast(stmt.value)
#            return ValuedArgument(arg, value)
#    elif isinstance(stmt,DotProxyList):
#        node=fst_to_ast(stmt[-1])
#        if len(stmt)>1:
#            stmt.pop()
#            stmt.pop()
#        return node
#    elif isinstance(stmt,DotNode):
#        pre=fst_to_ast(stmt.previous)
#        suf=stmt.next
#        stmt.parent.value.remove(stmt.previous)
#        return DottedName(str(pre),str(fst_to_ast(suf)))
#    elif isinstance(stmt,CallNode):
#        name=stmt.previous.name.value
#        if  name in Built_in_Functions and not Built_in_Functions[name]=='':
#            return Built_in_Functions[name](*fst_to_ast(stmt.value))
#        else:
#            return FunctionCall(str(fst_to_ast(stmt.previous.name)),fst_to_ast(stmt.value))
#    elif isinstance(stmt,CallArgumentNode):
#        return fst_to_ast(stmt.value)
#    elif isinstance(stmt, ReturnNode):
#        return Return(fst_to_ast(stmt.value))
#    elif isinstance(stmt, DefNode):
#        # TODO results must be computed at the decoration stage
#        name        = fst_to_ast(stmt.name)
#        arguments   = fst_to_ast(stmt.arguments)
#        results     = []
#        body        = fst_to_ast(stmt.value)
#        local_vars  = []
#        global_vars = []
#        cls_name    = None
#        hide        = False
#        kind        = 'function'
#        imports     = []
#        return FunctionDef(name, arguments, results, body,
#                           local_vars=local_vars, global_vars=global_vars,
#                           cls_name=cls_name, hide=hide,
#                           kind=kind, imports=imports)
#<<<<<<< HEAD
#    elif isinstance(stmt, AtomtrailersNode):
#         return fst_to_ast(stmt.value)
#    elif isinstance(stmt, DotProxyList):
#        # we first get the index of the call node
#        call = None
#        for i, s in enumerate(stmt):
#            if isinstance(s, CallNode):
#                call = stmt[i]
#                break
#            i += 1
#        if call is None:
#            raise ValueError('Can not find the call node')
#
#        # the function name (without trailer) is the previous node to the call
#        name = call.previous
#        name = fst_to_ast(name)
#        # TODO handle dot trailers
#
#=======
#    elif isinstance(stmt,ClassNode):
#        name=fst_to_ast(stmt.name)
#        methods=fst_to_ast(stmt.value)
#        attributes=methods[0].arguments
#        return ClassDef(name,attributes,methods)
#>>>>>>> f18b96666364581a3855b76976d2bc1ec78982d1
#    elif isinstance(stmt, ForNode):
#        target = fst_to_ast(stmt.iterator)
#        iter   = fst_to_ast(stmt.target)
#        body   = fst_to_ast(stmt.value)
#        strict = True
#        return For(target, iter, body, strict=strict)
#<<<<<<< HEAD
#    elif isinstance(stmt, IfelseblockNode):
#        args = fst_to_ast(stmt.value)
#        return If(*args)
#    elif isinstance(stmt,(IfNode, ElifNode)):
#        test = fst_to_ast(stmt.test)
#        body = fst_to_ast(stmt.value)
#        return Tuple(test, body)
#    elif isinstance(stmt, ElseNode):
#        test = True
#        body = fst_to_ast(stmt.value)
#        return Tuple(test, body)
#    elif isinstance(stmt, WhileNode):
#        test = fst_to_ast(stmt.test)
#        body = fst_to_ast(stmt.value)
#        return While(test, body)
#=======
#    elif isinstance(stmt,IfelseblockNode):
#        return If(*fst_to_ast(stmt.value))
#    elif isinstance(stmt,(IfNode,ElifNode)):
#        return Tuple(fst_to_ast(stmt.test),list(fst_to_ast(stmt.value)))
#    elif isinstance(stmt,ElseNode):
#        return Tuple(True,list(fst_to_ast(stmt.value)))
#    elif isinstance(stmt,WhileNode):
#        return While(fst_to_ast(stmt.test),fst_to_ast(stmt.value))
#>>>>>>> f18b96666364581a3855b76976d2bc1ec78982d1
#    elif isinstance(stmt, EndlNode):
#        return EmptyLine()
#    elif isinstance(stmt, CommentNode):
#        pyccel = PyccelParser()
#        comment=str(stmt.value).encode()
#        comment = pyccel.parse(comment)
#        comment=comment.statements[0]
#        return comment.expr
#    else:
#        raise NotImplementedError('{node} not yet available'.format(node=type(stmt)))
#
#
#def op(x,y,operator):
#    if operator=='*':
#        return Mul(x,y)
#    if operator=='/':
#        y = Pow(y, -1)
#        return Mul(x,y)
#    elif operator=='+':
#        return Add(x,y)
#    elif operator=='-':
#        return Add(x,-y)
#    elif operator=='and':
#        return And(x,y)
#    elif operator=='or':
#        return Or(x,y)
#    elif operator=='**':
#        return Pow(x,y)
#    elif operator=='==':
#        return Eq(x,y)
#    elif operator=='!=' or operator=='<>':
#        return Ne(x,y)
#    elif operator=='>':
#        return Gt(x,y)
#    elif operator=='>=':
#        return Ge(x,y)
#    elif operator=='<':
#        return Lt(x,y)
#    elif operator=='<=':
#        return Le(x,y)
#    else:
#        print(operator,type(operator))
#        raise ValueError('unknown/unavailable operator {node}'.format())
#
#
#def read_file(filename):
#    """Returns the source code from a filename."""
#    f = open(filename)
#    code = f.read()
#    f.close()
#    return code
#
#filename = 'scripts/expressions.py'
##filename = 'scripts/functions.py'
##filename = 'scripts/loops.py'
##filename = 'scripts/dels.py'
#code = read_file(filename)
#red  = RedBaron(code)
#
#print('----- FST -----')
#for stmt in red:
#    print stmt
##    print type(stmt)
#print('---------------')
#
## converts redbaron fst to sympy ast
#ast = fst_to_ast(red)
#
#print('----- AST -----')
#for expr in ast:
#    print expr
##    print '\t', type(expr.rhs)
#print('---------------')
#
##view_tree(ast)
#
#export_ast(ast, filename='ast.gv')
<commit_msg>fix merge<commit_after># coding: utf-8
from redbaron import RedBaron
from redbaron import StringNode, IntNode, FloatNode, ComplexNode
from redbaron import NameNode
from redbaron import AssignmentNode
from redbaron import CommentNode, EndlNode
from redbaron import ComparisonNode
from redbaron import ComparisonOperatorNode
from redbaron import UnitaryOperatorNode
from redbaron import BinaryOperatorNode, BooleanOperatorNode
from redbaron import AssociativeParenthesisNode
from redbaron import DefNode
from redbaron import TupleNode, ListNode
from redbaron import CommaProxyList
from redbaron import LineProxyList
from redbaron import NodeList
from redbaron import DotProxyList
from redbaron import ReturnNode
from redbaron import DefArgumentNode
from redbaron import ForNode
from redbaron import PrintNode
from redbaron import DelNode
from redbaron import DictNode, DictitemNode
from redbaron import ForNode, WhileNode
from redbaron import IfelseblockNode, IfNode, ElseNode, ElifNode
from redbaron import DotNode, AtomtrailersNode
from redbaron import CallNode
from redbaron import CallArgumentNode

from pyccel.ast import NativeInteger, NativeFloat, NativeDouble, NativeComplex
from pyccel.ast import Nil
from pyccel.ast import Variable
from pyccel.ast import Assign
from pyccel.ast import Return
from pyccel.ast import FunctionDef
from pyccel.ast import For
from pyccel.ast import If
from pyccel.ast import While
from pyccel.ast import Print
from pyccel.ast import Del
from pyccel.ast import Comment, EmptyLine

from sympy import Symbol
from sympy import Tuple
from sympy import Add, Mul, Pow
from sympy.logic.boolalg import And, Or
from sympy.logic.boolalg import true, false
from sympy.logic.boolalg import Not
#from sympy.logic.boolalg import Boolean,
from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge
from sympy import Integer, Float
from sympy.core.containers import Dict
from sympy.core.function import Function

# ... TODO should be moved to pyccel.ast
from sympy.core.basic import Basic

class Argument(Symbol):
    """An abstract Argument data structure."""
    pass

class ValuedArgument(Basic):
    """Represents a valued argument in the code."""

    def __new__(cls, expr, value):
        if not isinstance(expr, Argument):
            raise TypeError('Expecting an argument')
        return Basic.__new__(cls, expr, value)

    @property
    def argument(self):
        return self._args[0]

    @property
    def value(self):
        return self._args[1]

    def _sympystr(self, printer):
        sstr = printer.doprint

        argument = sstr(self.argument)
        value    = sstr(self.value)
        return '{0}={1}'.format(argument, value)
# ...

# ... utilities
from sympy import srepr
from sympy.printing.dot import dotprint

import os

def view_tree(expr):
    """Views a sympy expression tree."""

    print srepr(expr)

def export_ast(expr, filename):
    """Exports sympy AST using graphviz then convert it to an image."""

    graph_str = dotprint(expr)

    f = file(filename, 'w')
    f.write(graph_str)
    f.close()

    # name without path
    name = os.path.basename(filename)
    # name without extension
    name = os.path.splitext(name)[0]
    cmd = "dot -Tps {name}.gv -o {name}.ps".format(name=name)
    os.system(cmd)
# ...

# TODO use Double instead of Float? or add precision
def datatype_from_redbaron(node):
    """Returns the pyccel datatype of a RedBaron Node."""
    if isinstance(node, IntNode):
        return NativeInteger()
    elif isinstance(node, FloatNode):
        return NativeFloat()
    elif isinstance(node, ComplexNode):
        return NativeComplex()
    else:
        raise NotImplementedError('TODO')

def fst_to_ast(stmt):
    """Creates AST from FST."""
    if isinstance(stmt, (RedBaron,
                         CommaProxyList, LineProxyList, NodeList,
                         TupleNode, ListNode)):
        ls = [fst_to_ast(i) for i in stmt]
        return Tuple(*ls)
    elif isinstance(stmt, DictNode):
        d = {}
        for i in stmt.value:
            if not isinstance(i, DictitemNode):
                raise TypeError('Expecting a DictitemNode')
            key   = fst_to_ast(i.key)
            value = fst_to_ast(i.value)
            # sympy does not allow keys to be strings
            if isinstance(key, str):
                raise TypeError('sympy does not allow keys to be strings')
            d[key] = value
        return Dict(d)
    elif stmt is None:
        return Nil()
    elif isinstance(stmt, str):
        return repr(stmt)
    elif isinstance(stmt, StringNode):
        return repr(stmt.value)
    elif isinstance(stmt, IntNode):
        return Integer(stmt.value)
    elif isinstance(stmt, FloatNode):
        return Float(stmt.value)
    elif isinstance(stmt, ComplexNode):
        raise NotImplementedError('ComplexNode not yet available')
    elif isinstance(stmt, AssignmentNode):
        lhs = fst_to_ast(stmt.target)
        rhs = fst_to_ast(stmt.value)
        return Assign(lhs, rhs)
    elif isinstance(stmt, NameNode):
        if stmt.value == 'None':
            return Nil()
        elif stmt.value == 'True':
            return true
        elif stmt.value == 'False':
            return false
        else:
            return Symbol(stmt.value)
    elif isinstance(stmt, DelNode):
        arg = fst_to_ast(stmt.value)
        return Del(arg)
    elif isinstance(stmt, UnitaryOperatorNode):
        target = fst_to_ast(stmt.target)
        if stmt.value == 'not':
            return Not(target)
        elif stmt.value == '+':
            return target
        elif stmt.value == '-':
            return -target
        elif stmt.value == '~':
            raise ValueError('Invert unary operator is not covered by Pyccel.')
        else:
            raise ValueError('unknown/unavailable unary operator '
                             '{node}'.format(node=type(stmt.value)))
    elif isinstance(stmt, (BinaryOperatorNode, BooleanOperatorNode)):
        first  = fst_to_ast(stmt.first)
        second = fst_to_ast(stmt.second)
        if stmt.value == '+':
            return Add(first, second)
        elif stmt.value == '*':
            return Mul(first, second)
        elif stmt.value == '-':
            second = Mul(-1, second)
            return Add(first, second)
        elif stmt.value == '/':
            second = Pow(second, -1)
            return Mul(first, second)
        elif stmt.value == 'and':
            return And(first, second)
        elif stmt.value == 'or':
            return Or(first, second)
        else:
            raise ValueError('unknown/unavailable binary operator '
                             '{node}'.format(node=type(stmt.value)))
    elif isinstance(stmt, ComparisonOperatorNode):
        if stmt.first == '==':
            return '=='
        elif stmt.first == '!=':
            return '!='
        elif stmt.first == '<':
            return '<'
        elif stmt.first == '>':
            return '>'
        elif stmt.first == '<=':
            return '<='
        elif stmt.first == '>=':
            return '>='
        else:
            raise ValueError('unknown comparison operator {}'.format(stmt.first))
    elif isinstance(stmt, ComparisonNode):
        first  = fst_to_ast(stmt.first)
        second = fst_to_ast(stmt.second)
        op     = fst_to_ast(stmt.value)
        if op == '==':
            return Eq(first, second)
        elif op == '!=':
            return Ne(first, second)
        elif op == '<':
            return Lt(first, second)
        elif op == '>':
            return Gt(first, second)
        elif op == '<=':
            return Le(first, second)
        elif op == '>=':
            return Ge(first, second)
        else:
            raise ValueError('unknown/unavailable binary operator '
                             '{node}'.format(node=type(op)))
    elif isinstance(stmt, PrintNode):
        expr = fst_to_ast(stmt.value)
        return Print(expr)
    elif isinstance(stmt, AssociativeParenthesisNode):
        return fst_to_ast(stmt.value)
    elif isinstance(stmt, DefArgumentNode):
        arg = Argument(str(stmt.target))
        if stmt.value is None:
            return arg
        else:
            value = fst_to_ast(stmt.value)
            return ValuedArgument(arg, value)
    elif isinstance(stmt, ReturnNode):
        return Return(fst_to_ast(stmt.value))
    elif isinstance(stmt, DefNode):
        # TODO results must be computed at the decoration stage
        name        = fst_to_ast(stmt.name)
        arguments   = fst_to_ast(stmt.arguments)
        results     = []
        body        = fst_to_ast(stmt.value)
        local_vars  = []
        global_vars = []
        cls_name    = None
        hide        = False
        kind        = 'function'
        imports     = []
        return FunctionDef(name, arguments, results, body,
                           local_vars=local_vars, global_vars=global_vars,
                           cls_name=cls_name, hide=hide,
                           kind=kind, imports=imports)
    elif isinstance(stmt, AtomtrailersNode):
         return fst_to_ast(stmt.value)
    elif isinstance(stmt, DotProxyList):
        # TODO handle dot trailers
        # we first get the index of the call node
        call = None
        for i, s in enumerate(stmt):
            if isinstance(s, CallNode):
                call = stmt[i]
                break
            i += 1
        if call is None:
            raise ValueError('Can not find the call node')

        # the function name (without trailer) is the previous node to the call
        name = call.previous

        if isinstance(call, CallNode):
            # in this case, name must be a string
            args   = fst_to_ast(call)
            f_name = str(name)
            return Function(f_name)(*args)
        else:
            name = fst_to_ast(name)
            raise NotImplementedError('TODO')
    elif isinstance(stmt, CallNode):
        args = fst_to_ast(stmt.value)
        return args
    elif isinstance(stmt, CallArgumentNode):
        return fst_to_ast(stmt.value)
    elif isinstance(stmt, ForNode):
        target = fst_to_ast(stmt.iterator)
        iter   = fst_to_ast(stmt.target)
        body   = fst_to_ast(stmt.value)
        strict = True
        return For(target, iter, body, strict=strict)
    elif isinstance(stmt, IfelseblockNode):
        args = fst_to_ast(stmt.value)
        return If(*args)
    elif isinstance(stmt,(IfNode, ElifNode)):
        test = fst_to_ast(stmt.test)
        body = fst_to_ast(stmt.value)
        return Tuple(test, body)
    elif isinstance(stmt, ElseNode):
        test = True
        body = fst_to_ast(stmt.value)
        return Tuple(test, body)
    elif isinstance(stmt, WhileNode):
        test = fst_to_ast(stmt.test)
        body = fst_to_ast(stmt.value)
        return While(test, body)
    elif isinstance(stmt, EndlNode):
        return EmptyLine()
    elif isinstance(stmt, CommentNode):
        # TODO must check if it is a header or not
        return Comment(stmt.value)
    else:
        raise NotImplementedError('{node} not yet available'.format(node=type(stmt)))

def read_file(filename):
    """Returns the source code from a filename."""
    f = open(filename)
    code = f.read()
    f.close()
    return code

######################################################
if __name__ == '__main__':
    import sys

    try:
        filename = sys.argv[1]
    except:
        raise ValueError('Expecting an argument for filename')

    code = read_file(filename)
    red  = RedBaron(code)

    print('----- FST -----')
    for stmt in red:
        print stmt
    #    print type(stmt)
    print('---------------')

    # converts redbaron fst to sympy ast
    ast = fst_to_ast(red)

    print('----- AST -----')
    for expr in ast:
        print expr
    #    print '\t', type(expr.rhs)
    print('---------------')

    #view_tree(ast)

    export_ast(ast, filename='ast.gv')
<|endoftext|>