Skip to content
This repository has been archived by the owner on Sep 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #44 from postatum/95473210_python3_support
Browse files Browse the repository at this point in the history
Add python3 support
  • Loading branch information
jstoiko committed Jun 13, 2015
2 parents 11ed179 + 733920a commit 094c38b
Show file tree
Hide file tree
Showing 13 changed files with 77 additions and 58 deletions.
10 changes: 5 additions & 5 deletions ramses/acl.py
@@ -1,12 +1,12 @@
import logging

import six
from pyramid.security import (
Allow, Deny,
Everyone, Authenticated,
ALL_PERMISSIONS)
from nefertari.acl import SelfParamMixin


from .views import collection_methods, item_methods
from . import registry

Expand Down Expand Up @@ -34,7 +34,7 @@ def methods_to_perms(perms, methods_map):
:methods_map: Map of HTTP methods to permission names (nefertari view
methods)
"""
if isinstance(perms, basestring):
if isinstance(perms, six.string_types):
perms = perms.split(',')
perms = [perm.strip().lower() for perm in perms]
if 'all' in perms:
Expand All @@ -45,7 +45,7 @@ def methods_to_perms(perms, methods_map):
except KeyError:
raise ValueError(
'Unknown method name in permissions: {}. Valid methods: '
'{}'.format(perms, methods_map.keys()))
'{}'.format(perms, list(methods_map.keys())))


def parse_acl(acl_string, methods_map):
Expand Down Expand Up @@ -78,7 +78,7 @@ def parse_acl(acl_string, methods_map):
action = actions.get(action_str)
if action is None:
raise ValueError('Unknown ACL action: {}. Valid actions: {}'.format(
action_str, actions.keys()))
action_str, list(actions.keys())))

# Process principal
princ_str = princ_str.strip().lower()
Expand Down Expand Up @@ -127,7 +127,7 @@ def _apply_callables(self, acl, methods_map, obj=None):
new_acl = []
for i, ace in enumerate(acl):
principal = ace[1]
if callable(principal):
if six.callable(principal):
ace = principal(ace=ace, request=self.request, obj=obj)
if not ace:
continue
Expand Down
3 changes: 2 additions & 1 deletion ramses/auth.py
Expand Up @@ -157,7 +157,8 @@ def setup_auth_policies(config, raml_data):
:raml_data: Instance of pyraml.parser.entities.RamlRoot.
"""
log.info('Configuring auth policies')
secured_by = filter(bool, (raml_data.securedBy or []))
secured_by_all = raml_data.securedBy or []
secured_by = [item for item in secured_by_all if item]
if not secured_by:
log.info('API is not secured. `securedBy` attribute value missing.')
return
Expand Down
2 changes: 0 additions & 2 deletions ramses/generators.py
@@ -1,5 +1,3 @@
from __future__ import print_function

import logging

from inflection import pluralize, singularize
Expand Down
5 changes: 3 additions & 2 deletions ramses/registry.py
Expand Up @@ -50,6 +50,7 @@ def foo():
assert registry.mget('Foo') == {'my_stored_var': myvar}
"""
import six


class Registry(dict):
Expand All @@ -64,9 +65,9 @@ def decorator(function):
registry[name] = function
return function

if len(args) == 1 and callable(args[0]):
if len(args) == 1 and six.callable(args[0]):
function = args[0]
name = function.func_name
name = function.__name__
return decorator(function)
elif len(args) == 2:
registry[args[0]] = args[1]
Expand Down
15 changes: 8 additions & 7 deletions ramses/scaffolds/__init__.py
@@ -1,19 +1,20 @@
from pyramid.scaffolds import PyramidTemplate
import binascii
import os
from os import urandom, chdir
import subprocess

from six import moves
from pyramid.scaffolds import PyramidTemplate


class RamsesStarterTemplate(PyramidTemplate):
_template_dir = 'ramses_starter'
summary = 'Ramses starter'

def pre(self, command, output_dir, vars):
dbengine_choices = {'1':'sqla', '2':'mongodb'}
vars['engine'] = dbengine_choices[raw_input("""
dbengine_choices = {'1': 'sqla', '2': 'mongodb'}
vars['engine'] = dbengine_choices[moves.input("""
Which database backend would you like to use:
(1) for SQLAlchemy/PostgreSQL, or
(2) for MongoEngine/MongoDB?
Expand All @@ -27,7 +28,7 @@ def pre(self, command, output_dir, vars):
def post(self, command, output_dir, vars):
os.chdir(str(output_dir))
subprocess.call('pip install -r requirements.txt', shell=True)
subprocess.call('pip install nefertari-{}'.format(vars['engine']), shell=True)
subprocess.call('pip install nefertari-{}'.format(vars['engine']),
shell=True)
msg = """Goodbye boilerplate! Welcome to Ramses."""
self.out(msg)

17 changes: 9 additions & 8 deletions ramses/utils.py
Expand Up @@ -111,19 +111,20 @@ def find_dynamic_resource(raml_resource):
def dynamic_part_name(raml_resource, clean_uri, pk_field):
""" Generate a dynamic part for a resource :raml_resource:.
A dynamic part is generated using 2 parts: :clean_uri: of the resource and
the dynamic part of any dymanic subresources. If :raml_resource: has no dynamic
subresources, 'id' is used as the 2nd part.
E.g. if your dynamic part on route 'stories' is named 'superId' then dynamic
part will be 'stories_superId'.
A dynamic part is generated using 2 parts: :clean_uri: of the resource
and the dynamic part of any dymanic subresources. If :raml_resource:
has no dynamic subresources, 'id' is used as the 2nd part.
E.g. if your dynamic part on route 'stories' is named 'superId' then
dynamic part will be 'stories_superId'.
Arguments:
:raml_resource: Instance of pyraml.entities.RamlResource for which
dynamic part name is being generated.
:clean_uri: Cleaned URI of :raml_resource:
"""
subresources = raml_resource.resources or {}
dynamic_uris = [uri for uri in subresources.keys() if is_dynamic_uri(uri)]
dynamic_uris = [uri for uri in subresources.keys()
if is_dynamic_uri(uri)]
if dynamic_uris:
dynamic_part = clean_dynamic_uri(dynamic_uris[0])
else:
Expand Down Expand Up @@ -153,7 +154,7 @@ def resource_view_attrs(raml_resource, singular=False):
if singular:
collection_methods = item_methods

http_methods = (raml_resource.methods or {}).keys()
http_methods = list((raml_resource.methods or {}).keys())
attrs = [collection_methods.get(m.lower()) for m in http_methods]

# Check if resource has dynamic subresource like collection/{id}
Expand All @@ -164,7 +165,7 @@ def resource_view_attrs(raml_resource, singular=False):
# If dynamic subresource exists, add its methods to attrs, as both
# resources are handled by a single view
if dynamic_res and dynamic_res[0].methods:
http_submethods = (dynamic_res[0].methods or {}).keys()
http_submethods = list((dynamic_res[0].methods or {}).keys())
attrs += [item_methods.get(m.lower()) for m in http_submethods]

return set(filter(bool, attrs))
Expand Down
26 changes: 15 additions & 11 deletions ramses/views.py
@@ -1,5 +1,6 @@
import logging

import six
from nefertari.view import BaseView as NefertariBaseView, ESAggregationMixin
from nefertari.json_httpexceptions import (
JHTTPCreated, JHTTPOk, JHTTPNotFound)
Expand Down Expand Up @@ -115,7 +116,7 @@ def get_item(self, **kwargs):
Returns an object from the applicable ACL. If ACL wasn't applied, it is
applied explicitly.
"""
if callable(self.context):
if six.callable(self.context):
self.reload_context(es_based=False, **kwargs)

objects = self._parent_queryset()
Expand Down Expand Up @@ -290,7 +291,7 @@ def get_item_es(self, **kwargs):
if objects_ids is not None:
objects_ids = self.get_es_object_ids(objects_ids)

if callable(self.context):
if six.callable(self.context):
self.reload_context(es_based=True, **kwargs)

if (objects_ids is not None) and (item_id not in objects_ids):
Expand Down Expand Up @@ -373,12 +374,14 @@ class ItemSubresourceBaseView(BaseView):
""" Base class for all subresources of collection item resources which
don't represent a collection of their own.
E.g. /users/{id}/profile, where 'profile' is a singular resource or
/users/{id}/some_action, where the 'some_action' action may be performed
when requesting this route.
/users/{id}/some_action, where the 'some_action' action may be
performed when requesting this route.
Subclass ItemSubresourceBaseView in your project when you want to define
a subroute and view of an item route defined in RAML and generated by ramses.
Use `self.get_item` to get an object on which actions are being performed.
Subclass ItemSubresourceBaseView in your project when you want to
define a subroute and view of an item route defined in RAML and
generated by ramses.
Use `self.get_item` to get an object on which actions are being
performed.
Moved into a separate class so all item subresources have a common
base class, thus making checks like `isinstance(view, baseClass)` easier.
Expand All @@ -401,9 +404,9 @@ class ItemAttributeView(ItemSubresourceBaseView):
Attribute resources represent field: ListField, DictField.
You may subclass ItemAttributeView in your project when you want to define
custom attribute subroute and view of a item route defined in RAML and
generated by ramses.
You may subclass ItemAttributeView in your project when you want to
define custom attribute subroute and view of a item route defined in
RAML and generated by ramses.
"""
def __init__(self, *args, **kw):
super(ItemAttributeView, self).__init__(*args, **kw)
Expand Down Expand Up @@ -501,7 +504,8 @@ def generate_rest_view(model_cls, attrs=None, es_based=True,
:singular: Boolean indicating if ItemSingularView should be used as a
base class for generated view.
"""
valid_attrs = collection_methods.values() + item_methods.values()
valid_attrs = (list(collection_methods.values()) +
list(item_methods.values()))
missing_attrs = set(valid_attrs) - set(attrs)

if singular:
Expand Down
7 changes: 6 additions & 1 deletion setup.py
Expand Up @@ -12,6 +12,7 @@
'inflection',
'nefertari>=0.3.3',
'transaction',
'six',
]

setup(name='ramses',
Expand All @@ -20,6 +21,10 @@
long_description=README,
classifiers=[
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Framework :: Pyramid",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
Expand All @@ -34,7 +39,7 @@
install_requires=requires,
tests_require=requires,
test_suite="ramses",
entry_points = """\
entry_points="""\
[pyramid.scaffold]
ramses_starter=ramses.scaffolds:RamsesStarterTemplate
""")
6 changes: 3 additions & 3 deletions tests/test_acl.py
Expand Up @@ -26,7 +26,7 @@ def test_methods_to_perms(self):
perms = acl.methods_to_perms('get', self.methods_map)
assert perms == ['index']
perms = acl.methods_to_perms('get,post', self.methods_map)
assert perms == ['index', 'create']
assert sorted(perms) == ['create', 'index']

def test_parse_acl_no_string(self):
perms = acl.parse_acl('', self.methods_map)
Expand All @@ -47,10 +47,10 @@ def test_parse_acl_multiple_values(self, mock_perms):
call(['read', 'write'], self.methods_map),
call(['all'], self.methods_map),
])
assert perms == [
assert sorted(perms) == sorted([
(Allow, Everyone, 'Foo'),
(Allow, Authenticated, 'Foo'),
]
])

@patch.object(acl, 'methods_to_perms')
def test_parse_acl_special_principal(self, mock_perms):
Expand Down
24 changes: 12 additions & 12 deletions tests/test_auth.py
Expand Up @@ -67,21 +67,21 @@ def test_routes_views_added(self, mock_policy):
])
login, logout, register = config.add_view.call_args_list
login_kwargs = login[1]
assert login_kwargs.keys() == [
'request_method', 'view', 'route_name', 'attr']
assert sorted(login_kwargs.keys()) == sorted([
'request_method', 'view', 'route_name', 'attr'])
assert login_kwargs['route_name'] == 'login'
assert login_kwargs['attr'] == 'login'
assert login_kwargs['request_method'] == 'POST'

logout_kwargs = logout[1]
assert logout_kwargs.keys() == [
'view', 'route_name', 'attr']
assert sorted(logout_kwargs.keys()) == sorted([
'view', 'route_name', 'attr'])
assert logout_kwargs['route_name'] == 'logout'
assert logout_kwargs['attr'] == 'logout'

register_kwargs = register[1]
assert register_kwargs.keys() == [
'request_method', 'view', 'route_name', 'attr']
assert sorted(register_kwargs.keys()) == sorted([
'request_method', 'view', 'route_name', 'attr'])
assert register_kwargs['route_name'] == 'register'
assert register_kwargs['attr'] == 'register'
assert register_kwargs['request_method'] == 'POST'
Expand Down Expand Up @@ -133,22 +133,22 @@ def test_routes_views_added(self, mock_policy):

token, reset_token, register = config.add_view.call_args_list
token_kwargs = token[1]
assert token_kwargs.keys() == [
'request_method', 'view', 'route_name', 'attr']
assert sorted(token_kwargs.keys()) == sorted([
'request_method', 'view', 'route_name', 'attr'])
assert token_kwargs['route_name'] == 'token'
assert token_kwargs['attr'] == 'claim_token'
assert token_kwargs['request_method'] == 'POST'

reset_token_kwargs = reset_token[1]
assert reset_token_kwargs.keys() == [
'request_method', 'view', 'route_name', 'attr']
assert sorted(reset_token_kwargs.keys()) == sorted([
'request_method', 'view', 'route_name', 'attr'])
assert reset_token_kwargs['route_name'] == 'reset_token'
assert reset_token_kwargs['attr'] == 'reset_token'
assert reset_token_kwargs['request_method'] == 'POST'

register_kwargs = register[1]
assert register_kwargs.keys() == [
'request_method', 'view', 'route_name', 'attr']
assert sorted(register_kwargs.keys()) == sorted([
'request_method', 'view', 'route_name', 'attr'])
assert register_kwargs['route_name'] == 'register'
assert register_kwargs['attr'] == 'register'
assert register_kwargs['request_method'] == 'POST'
Expand Down
8 changes: 4 additions & 4 deletions tests/test_registry.py
Expand Up @@ -13,30 +13,30 @@ def foo(*args, **kwargs):
return args, kwargs

assert registry.registry['foo'] is foo
assert registry.registry.keys() == ['foo']
assert list(registry.registry.keys()) == ['foo']

def test_add_decorator_with_name(self):
@registry.add('bar')
def foo(*args, **kwargs):
return args, kwargs

assert registry.registry['bar'] is foo
assert registry.registry.keys() == ['bar']
assert list(registry.registry.keys()) == ['bar']

def test_add_arbitrary_object(self):
registry.add('foo', 1)
registry.add('bar', 2)

assert registry.registry['foo'] == 1
assert registry.registry['bar'] == 2
assert registry.registry.keys() == ['foo', 'bar']
assert sorted(registry.registry.keys()) == ['bar', 'foo']

def test_get(self):
registry.registry['foo'] = 1
assert registry.get('foo') == 1

def test_get_error(self):
assert not registry.registry.keys()
assert not list(registry.registry.keys())
with pytest.raises(KeyError) as ex:
registry.get('foo')
assert 'is not registered in ramses registry' in str(ex.value)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_views.py
Expand Up @@ -309,7 +309,7 @@ def test_get_es_object_ids(self):
view = self._test_view()
view._resource = Mock(id_name='foobar')
objects = [Mock(foobar=4), Mock(foobar=7)]
assert view.get_es_object_ids(objects) == ['4', '7']
assert sorted(view.get_es_object_ids(objects)) == ['4', '7']

@patch('nefertari.elasticsearch.ES')
def test_get_collection_es_no_parent(self, mock_es):
Expand Down

0 comments on commit 094c38b

Please sign in to comment.