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

from urlparse import urlparse

import wtforms
import wtforms.fields.html5
from baseframe.forms import Form
from coaster import valid_username

from lastuser_core.models import Permission, Resource, getuser, Organization
from lastuser_core import resource_registry

class ConfirmDeleteForm(Form):
    """
    Confirm a delete operation
    """
    delete = wtforms.SubmitField('Delete')
    cancel = wtforms.SubmitField('Cancel')

class RegisterClientForm(Form):
    """
    Register a new OAuth client application
    """
    title = wtforms.TextField('Application title', validators=[wtforms.validators.Required()],
        description="The name of your application")
    description = wtforms.TextAreaField('Description', validators=[wtforms.validators.Required()],
        description="A description to help users recognize your application")
    client_owner = wtforms.RadioField('Owner', validators=[wtforms.validators.Required()],
        description="User or organization that owns this application. Changing the owner "
            "will revoke all currently assigned permissions for this app")
    website = wtforms.fields.html5.URLField('Application website', validators=[wtforms.validators.Required(), wtforms.validators.URL()],
        description="Website where users may access this application")
    redirect_uri = wtforms.fields.html5.URLField('Redirect URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="OAuth2 Redirect URL")
    notification_uri = wtforms.fields.html5.URLField('Notification URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="When the user's data changes, Lastuser will POST a notice to this URL. "
            "Other notices may be posted too")
    iframe_uri = wtforms.fields.html5.URLField('IFrame URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="Front-end notifications URL. This is loaded in a hidden iframe to notify the app that the "
            "user updated their profile in some way (not yet implemented)")
    resource_uri = wtforms.fields.html5.URLField('Resource URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="URL at which this application provides resources as per the Lastuser Resource API "
            "(not yet implemented)")
    namespace = wtforms.TextField('Client Namespace', validators=[wtforms.validators.Required()],
        description="A dot-based namespace that uniquely identifies your client application and provides external clients access to resources.")
    allow_any_login = wtforms.BooleanField('Allow anyone to login', default=True,
        description="If your application requires access to be restricted to specific users, uncheck this, "
            "and only users who have been assigned a permission to the app will be able to login")
    team_access = wtforms.BooleanField('Requires access to teams', default=False,
        description="If your application is capable of assigning access permissions to teams, check this. "
            "Organization owners will then able to grant access to teams in their organizations")

    def validate_client_owner(self, field):
        if field.data == self.edit_user.userid:
            self.user = self.edit_user
            self.org = None
        else:
            orgs = [org for org in self.edit_user.organizations_owned() if org.userid == field.data]
            if len(orgs) != 1:
                raise wtforms.ValidationError("Invalid owner")
            self.user = None
            self.org = orgs[0]

    def _urls_match(self, url1, url2):
        p1 = urlparse(url1)
        p2 = urlparse(url2)
        return (p1.netloc == p2.netloc) and (p1.scheme == p2.scheme) and (
            p1.username == p2.username) and (p1.password == p2.password)

    def validate_redirect_uri(self, field):
        if not self._urls_match(self.website.data, field.data):
            raise wtforms.ValidationError("The scheme, domain and port must match that of the website URL")

    def validate_notification_uri(self, field):
        if not self._urls_match(self.website.data, field.data):
            raise wtforms.ValidationError("The scheme, domain and port must match that of the website URL")

    def validate_resource_uri(self, field):
        if not self._urls_match(self.website.data, field.data):
            raise wtforms.ValidationError("The scheme, domain and port must match that of the website URL")

class PermissionForm(Form):
    """
    Create or edit a permission
    """
    name = wtforms.TextField('Permission name', validators=[wtforms.validators.Required()],
        description='Name of the permission as a single word in lower case. '
            'This is passed to the application when a user logs in. '
            'Changing the name will not automatically update it everywhere. '
            'You must reassign the permission to users who had it with the old name')
    title = wtforms.TextField('Title', validators=[wtforms.validators.Required()],
        description='Permission title that is displayed to users')
    description = wtforms.TextAreaField('Description',
        description='An optional description of what the permission is for')
    context = wtforms.RadioField('Context', validators=[wtforms.validators.Required()],
        description='Context where this permission is available')

    def validate(self):
        rv = super(PermissionForm, self).validate()
        if not rv:
            return False

        if not valid_username(self.name.data):
            self.name.errors.append("Name contains invalid characters")
            return False

        existing = Permission.get(name=self.name.data, allusers=True)
        if existing and existing.id != self.edit_id:
            self.name.errors.append("A global permission with that name already exists")
            return False

        if self.context.data == self.edit_user.userid:
            existing = Permission.get(name=self.name.data, user=self.edit_user)
        else:
            org = Organization.get(userid=self.context.data)
            if org:
                existing = Permission.get(name=self.name.data, org=org)
            else:
                existing = None
        if existing and existing.id != self.edit_id:
            self.name.errors.append("You have another permission with the same name")
            return False

        return True

    def validate_context(self, field):
        if field.data == self.edit_user.userid:
            self.user = self.edit_user
            self.org = None
        else:
            orgs = [org for org in self.edit_user.organizations_owned() if org.userid == field.data]
            if len(orgs) != 1:
                raise wtforms.ValidationError("Invalid context")
            self.user = None
            self.org = orgs[0]

class UserPermissionAssignForm(Form):
    """
    Assign permissions to a user
    """
    username = wtforms.TextField("User", validators=[wtforms.validators.Required()],
        description='Lookup a user by their username or email address')
    perms = wtforms.SelectMultipleField("Permissions", validators=[wtforms.validators.Required()])

    def validate_username(self, field):
        existing = getuser(field.data)
        if existing is None:
            raise wtforms.ValidationError("User does not exist")
        self.user = existing

class TeamPermissionAssignForm(Form):
    """
    Assign permissions to a team
    """
    team_id = wtforms.RadioField("Team", validators=[wtforms.validators.Required()],
        description='Select a team to assign permissions to')
    perms = wtforms.SelectMultipleField("Permissions", validators=[wtforms.validators.Required()])

    def validate_team_id(self, field):
        teams = [team for team in self.org.teams if team.userid == field.data]
        if len(teams) != 1:
            raise wtforms.ValidationError("Unknown team")
        self.team = teams[0]

class PermissionEditForm(Form):
    """
    Edit a user or team's permissions
    """
    perms = wtforms.SelectMultipleField("Permissions", validators=[wtforms.validators.Required()])

class ResourceForm(Form):
    """
    Edit a resource provided by an application
    """
    name = wtforms.TextField('Resource name', validators=[wtforms.validators.Required()],
        description="Name of the resource as a single word in lower case. "
            "This is provided by applications as part of the scope "
            "when requesting access to a user's resources.")
    title = wtforms.TextField('Title', validators=[wtforms.validators.Required()],
        description='Resource title that is displayed to users')
    description = wtforms.TextAreaField('Description',
        description='An optional description of what the resource is')
    siteresource = wtforms.BooleanField('Site resource',
        description='Enable if this resource is generic to the site and not owned by specific users')
    trusted = wtforms.BooleanField('Trusted applications only',
        description='Enable if access to the resource should be restricted to trusted '
            'applications. You may want to do this for sensitive information like billing data')

    def validate_name(self, field):
        if not valid_username(field.data):
            raise wtforms.ValidationError("Name contains invalid characters.")

        if field.data in resource_registry:
            raise wtforms.ValidationError("This name is reserved for internal use")

        existing = Resource.get(name=field.data)
        if existing and existing.id != self.edit_id:
            raise wtforms.ValidationError("A resource with that name already exists")

class ResourceActionForm(Form):
    """
    Edit an action associated with a resource
    """
    name = wtforms.TextField('Action name', validators=[wtforms.validators.Required()],
        description="Name of the action as a single word in lower case. "
            "This is provided by applications as part of the scope in the form "
            "'resource/action' when requesting access to a user's resources. "
            "Read actions are implicit when applications request just 'resource' "
            "in the scope and do not need to be specified as an explicit action.")
    title = wtforms.TextField('Title', validators=[wtforms.validators.Required()],
        description='Action title that is displayed to users')
    description = wtforms.TextAreaField('Description',
        description='An optional description of what the action is')

    def validate_name(self, field):
        if not valid_username(field.data):
            raise wtforms.ValidationError("Name contains invalid characters.")

        existing = self.edit_resource.get_action(field.data)
        if existing and existing.id != self.edit_id:
            raise wtforms.ValidationError("An action with that name already exists for this resource")

class ClientTeamAccessForm(Form):
    """
    Select organizations that the client has access to the teams of
    """
    organizations = wtforms.SelectMultipleField('Organizations')
<commit_msg>https://github.com/hasgeek/lastuser/pull/102/files#r9104754<commit_after># -*- coding: utf-8 -*-

from urlparse import urlparse

import wtforms
import wtforms.fields.html5
from baseframe.forms import Form
from coaster import valid_username

from lastuser_core.models import Permission, Resource, getuser, Organization
from lastuser_core import resource_registry

class ConfirmDeleteForm(Form):
    """
    Confirm a delete operation
    """
    delete = wtforms.SubmitField('Delete')
    cancel = wtforms.SubmitField('Cancel')

class RegisterClientForm(Form):
    """
    Register a new OAuth client application
    """
    title = wtforms.TextField('Application title', validators=[wtforms.validators.Required()],
        description="The name of your application")
    description = wtforms.TextAreaField('Description', validators=[wtforms.validators.Required()],
        description="A description to help users recognize your application")
    client_owner = wtforms.RadioField('Owner', validators=[wtforms.validators.Required()],
        description="User or organization that owns this application. Changing the owner "
            "will revoke all currently assigned permissions for this app")
    website = wtforms.fields.html5.URLField('Application website', validators=[wtforms.validators.Required(), wtforms.validators.URL()],
        description="Website where users may access this application")
    redirect_uri = wtforms.fields.html5.URLField('Redirect URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="OAuth2 Redirect URL")
    notification_uri = wtforms.fields.html5.URLField('Notification URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="When the user's data changes, Lastuser will POST a notice to this URL. "
            "Other notices may be posted too")
    iframe_uri = wtforms.fields.html5.URLField('IFrame URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="Front-end notifications URL. This is loaded in a hidden iframe to notify the app that the "
            "user updated their profile in some way (not yet implemented)")
    resource_uri = wtforms.fields.html5.URLField('Resource URL', validators=[wtforms.validators.Optional(), wtforms.validators.URL()],
        description="URL at which this application provides resources as per the Lastuser Resource API "
            "(not yet implemented)")
    namespace = wtforms.TextField('Client namespace', validators=[wtforms.validators.Required()],
        description="A dot-based namespace that uniquely identifies your client application and provides external clients access to resources. For example, if your client website is http://funnel.hasgeek.com, use 'com.hasgeek.funnel'.")
    allow_any_login = wtforms.BooleanField('Allow anyone to login', default=True,
        description="If your application requires access to be restricted to specific users, uncheck this, "
            "and only users who have been assigned a permission to the app will be able to login")
    team_access = wtforms.BooleanField('Requires access to teams', default=False,
        description="If your application is capable of assigning access permissions to teams, check this. "
            "Organization owners will then able to grant access to teams in their organizations")

    def validate_client_owner(self, field):
        if field.data == self.edit_user.userid:
            self.user = self.edit_user
            self.org = None
        else:
            orgs = [org for org in self.edit_user.organizations_owned() if org.userid == field.data]
            if len(orgs) != 1:
                raise wtforms.ValidationError("Invalid owner")
            self.user = None
            self.org = orgs[0]

    def _urls_match(self, url1, url2):
        p1 = urlparse(url1)
        p2 = urlparse(url2)
        return (p1.netloc == p2.netloc) and (p1.scheme == p2.scheme) and (
            p1.username == p2.username) and (p1.password == p2.password)

    def validate_redirect_uri(self, field):
        if not self._urls_match(self.website.data, field.data):
            raise wtforms.ValidationError("The scheme, domain and port must match that of the website URL")

    def validate_notification_uri(self, field):
        if not self._urls_match(self.website.data, field.data):
            raise wtforms.ValidationError("The scheme, domain and port must match that of the website URL")

    def validate_resource_uri(self, field):
        if not self._urls_match(self.website.data, field.data):
            raise wtforms.ValidationError("The scheme, domain and port must match that of the website URL")

class PermissionForm(Form):
    """
    Create or edit a permission
    """
    name = wtforms.TextField('Permission name', validators=[wtforms.validators.Required()],
        description='Name of the permission as a single word in lower case. '
            'This is passed to the application when a user logs in. '
            'Changing the name will not automatically update it everywhere. '
            'You must reassign the permission to users who had it with the old name')
    title = wtforms.TextField('Title', validators=[wtforms.validators.Required()],
        description='Permission title that is displayed to users')
    description = wtforms.TextAreaField('Description',
        description='An optional description of what the permission is for')
    context = wtforms.RadioField('Context', validators=[wtforms.validators.Required()],
        description='Context where this permission is available')

    def validate(self):
        rv = super(PermissionForm, self).validate()
        if not rv:
            return False

        if not valid_username(self.name.data):
            self.name.errors.append("Name contains invalid characters")
            return False

        existing = Permission.get(name=self.name.data, allusers=True)
        if existing and existing.id != self.edit_id:
            self.name.errors.append("A global permission with that name already exists")
            return False

        if self.context.data == self.edit_user.userid:
            existing = Permission.get(name=self.name.data, user=self.edit_user)
        else:
            org = Organization.get(userid=self.context.data)
            if org:
                existing = Permission.get(name=self.name.data, org=org)
            else:
                existing = None
        if existing and existing.id != self.edit_id:
            self.name.errors.append("You have another permission with the same name")
            return False

        return True

    def validate_context(self, field):
        if field.data == self.edit_user.userid:
            self.user = self.edit_user
            self.org = None
        else:
            orgs = [org for org in self.edit_user.organizations_owned() if org.userid == field.data]
            if len(orgs) != 1:
                raise wtforms.ValidationError("Invalid context")
            self.user = None
            self.org = orgs[0]

class UserPermissionAssignForm(Form):
    """
    Assign permissions to a user
    """
    username = wtforms.TextField("User", validators=[wtforms.validators.Required()],
        description='Lookup a user by their username or email address')
    perms = wtforms.SelectMultipleField("Permissions", validators=[wtforms.validators.Required()])

    def validate_username(self, field):
        existing = getuser(field.data)
        if existing is None:
            raise wtforms.ValidationError("User does not exist")
        self.user = existing

class TeamPermissionAssignForm(Form):
    """
    Assign permissions to a team
    """
    team_id = wtforms.RadioField("Team", validators=[wtforms.validators.Required()],
        description='Select a team to assign permissions to')
    perms = wtforms.SelectMultipleField("Permissions", validators=[wtforms.validators.Required()])

    def validate_team_id(self, field):
        teams = [team for team in self.org.teams if team.userid == field.data]
        if len(teams) != 1:
            raise wtforms.ValidationError("Unknown team")
        self.team = teams[0]

class PermissionEditForm(Form):
    """
    Edit a user or team's permissions
    """
    perms = wtforms.SelectMultipleField("Permissions", validators=[wtforms.validators.Required()])

class ResourceForm(Form):
    """
    Edit a resource provided by an application
    """
    name = wtforms.TextField('Resource name', validators=[wtforms.validators.Required()],
        description="Name of the resource as a single word in lower case. "
            "This is provided by applications as part of the scope "
            "when requesting access to a user's resources.")
    title = wtforms.TextField('Title', validators=[wtforms.validators.Required()],
        description='Resource title that is displayed to users')
    description = wtforms.TextAreaField('Description',
        description='An optional description of what the resource is')
    siteresource = wtforms.BooleanField('Site resource',
        description='Enable if this resource is generic to the site and not owned by specific users')
    trusted = wtforms.BooleanField('Trusted applications only',
        description='Enable if access to the resource should be restricted to trusted '
            'applications. You may want to do this for sensitive information like billing data')

    def validate_name(self, field):
        if not valid_username(field.data):
            raise wtforms.ValidationError("Name contains invalid characters.")

        if field.data in resource_registry:
            raise wtforms.ValidationError("This name is reserved for internal use")

        existing = Resource.get(name=field.data)
        if existing and existing.id != self.edit_id:
            raise wtforms.ValidationError("A resource with that name already exists")

class ResourceActionForm(Form):
    """
    Edit an action associated with a resource
    """
    name = wtforms.TextField('Action name', validators=[wtforms.validators.Required()],
        description="Name of the action as a single word in lower case. "
            "This is provided by applications as part of the scope in the form "
            "'resource/action' when requesting access to a user's resources. "
            "Read actions are implicit when applications request just 'resource' "
            "in the scope and do not need to be specified as an explicit action.")
    title = wtforms.TextField('Title', validators=[wtforms.validators.Required()],
        description='Action title that is displayed to users')
    description = wtforms.TextAreaField('Description',
        description='An optional description of what the action is')

    def validate_name(self, field):
        if not valid_username(field.data):
            raise wtforms.ValidationError("Name contains invalid characters.")

        existing = self.edit_resource.get_action(field.data)
        if existing and existing.id != self.edit_id:
            raise wtforms.ValidationError("An action with that name already exists for this resource")

class ClientTeamAccessForm(Form):
    """
    Select organizations that the client has access to the teams of
    """
    organizations = wtforms.SelectMultipleField('Organizations')
<|endoftext|>


<commit_before>import sys
from mock import Mock, patch
from py.test import raises
from remoto import backends
from remoto.tests import fake_module
from remoto.tests.conftest import Capture, Factory

class FakeSocket(object):

    def __init__(self, gethostname, getfqdn=None):
        self.gethostname = lambda: gethostname
        self.getfqdn = lambda: getfqdn or gethostname

class TestNeedsSsh(object):

    def test_short_hostname_matches(self):
        socket = FakeSocket('foo.example.org')
        assert backends.needs_ssh('foo', socket) is False

    def test_long_hostname_matches(self):
        socket = FakeSocket('foo.example.org')
        assert backends.needs_ssh('foo.example.org', socket) is False

    def test_hostname_does_not_match(self):
        socket = FakeSocket('foo')
        assert backends.needs_ssh('meh', socket) is True

    def test_fqdn_hostname_matches_short_hostname(self):
        socket = FakeSocket('foo', getfqdn='foo.example.org')
        assert backends.needs_ssh('foo.example.org', socket) is False

class FakeGateway(object):

    def remote_exec(self, module):
        pass

class TestLegacyRemoteModule(object):

    def setup(self):
        self.conn = backends.BaseConnection('localhost', sudo=True, eager=False)
        self.conn.gateway = FakeGateway()

    def test_importing_it_sets_it_as_remote_module(self):
        self.conn.import_module(fake_module)
        assert fake_module == self.conn.remote_module.module

    def test_importing_it_returns_the_module_too(self):
        remote_foo = self.conn.import_module(fake_module)
        assert remote_foo.module == fake_module

    def test_execute_the_remote_module_send(self):
        stub_channel = Factory(send=Capture(), receive=Capture())
        self.conn.gateway.channel = self.conn.gateway
        remote_foo = self.conn.import_module(fake_module)
        remote_foo.channel = stub_channel
        remote_foo.function('argument')
        assert stub_channel.send.calls[0]['args'][0] == "function('argument')"

    def test_execute_the_remote_module_receive(self):
        stub_channel = Factory(receive=Capture(return_values=[True]), send=Capture())
        self.conn.gateway.channel = self.conn.gateway
        remote_foo = self.conn.import_module(fake_module)
        remote_foo.channel = stub_channel
        assert remote_foo.function('argument') is True

class TestLegacyModuleExecuteArgs(object):

    def setup(self):
        self.remote_module = backends.LegacyModuleExecute(FakeGateway(), None)

    def test_single_argument(self):
        assert self.remote_module._convert_args(('foo',)) == "'foo'"

    def test_more_than_one_argument(self):
        args = ('foo', 'bar', 1)
        assert self.remote_module._convert_args(args) == "'foo', 'bar', 1"

    def test_dictionary_as_argument(self):
        args = ({'some key': 1},)
        assert self.remote_module._convert_args(args) == "{'some key': 1}"

class TestLegacyModuleExecuteGetAttr(object):

    def setup(self):
        self.remote_module = backends.LegacyModuleExecute(FakeGateway(), None)

    def test_raise_attribute_error(self):
        with raises(AttributeError) as err:
            self.remote_module.foo()
        assert err.value.args[0] == 'module None does not have attribute foo'

class TestMakeConnectionString(object):

    def test_makes_sudo_python_no_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: False)
        assert conn_string == 'popen//python=sudo python'

    def test_makes_sudo_python_with_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
        assert conn_string == 'ssh=localhost//python=sudo python'

    def test_makes_sudo_python_with_ssh_options(self):
        conn = backends.BaseConnection(
            'localhost', sudo=True, eager=False,
            interpreter='python', ssh_options='-F vagrant_ssh_config')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
        assert conn_string == 'ssh=-F vagrant_ssh_config localhost//python=sudo python'

    def test_makes_python_no_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=False, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: False)
        assert conn_string == 'popen//python=python'

    def test_makes_python_with_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=False, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
        assert conn_string == 'ssh=localhost//python=python'

    def test_makes_sudo_python_with_forced_sudo(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string(
            'localhost', _needs_ssh=lambda x: False, use_sudo=True
        )
        assert conn_string == 'popen//python=sudo python'

    def test_does_not_make_sudo_python_with_forced_sudo(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string(
            'localhost', _needs_ssh=lambda x: False, use_sudo=False
        )
        assert conn_string == 'popen//python=python'

    def test_detects_python3(self):
        with patch.object(sys, 'version_info', (3, 5, 1)):
            conn = backends.BaseConnection('localhost', sudo=True, eager=False)
            conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: False)
            assert conn_string == 'popen//python=sudo python3'

    def test_detects_python2(self):
        with patch.object(sys, 'version_info', (2, 7, 11)):
            conn = backends.BaseConnection('localhost', sudo=False, eager=False)
            conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
            assert conn_string == 'ssh=localhost//python=python2'

class TestDetectSudo(object):

    def setup(self):
        self.execnet = Mock()
        self.execnet.return_value = self.execnet
        self.execnet.makegateway.return_value = self.execnet
        self.execnet.remote_exec.return_value = self.execnet

    def test_does_not_need_sudo(self):
        self.execnet.receive.return_value = 'root'
        conn = backends.BaseConnection('localhost', sudo=True, eager=False)
        assert conn._detect_sudo(_execnet=self.execnet) is False

    def test_does_need_sudo(self):
        self.execnet.receive.return_value = 'alfredo'
        conn = backends.BaseConnection('localhost', sudo=True, eager=False)
        assert conn._detect_sudo(_execnet=self.execnet) is True
<commit_msg>tests: add tests for localhost needs_ssh behavior<commit_after>import sys
from mock import Mock, patch
import pytest
from remoto import backends
from remoto.tests import fake_module
from remoto.tests.conftest import Capture, Factory

class FakeSocket(object):

    def __init__(self, gethostname, getfqdn=None):
        self.gethostname = lambda: gethostname
        self.getfqdn = lambda: getfqdn or gethostname

class TestNeedsSsh(object):

    def test_short_hostname_matches(self):
        socket = FakeSocket('foo.example.org')
        assert backends.needs_ssh('foo', socket) is False

    def test_long_hostname_matches(self):
        socket = FakeSocket('foo.example.org')
        assert backends.needs_ssh('foo.example.org', socket) is False

    def test_hostname_does_not_match(self):
        socket = FakeSocket('foo')
        assert backends.needs_ssh('meh', socket) is True

    def test_fqdn_hostname_matches_short_hostname(self):
        socket = FakeSocket('foo', getfqdn='foo.example.org')
        assert backends.needs_ssh('foo.example.org', socket) is False

    @pytest.mark.parametrize('hostname', ['localhost', '127.0.0.1', '127.0.1.1'])
    def test_local_hostname(self, hostname):
        assert backends.needs_ssh(hostname) is False

class FakeGateway(object):

    def remote_exec(self, module):
        pass

class TestLegacyRemoteModule(object):

    def setup(self):
        self.conn = backends.BaseConnection('localhost', sudo=True, eager=False)
        self.conn.gateway = FakeGateway()

    def test_importing_it_sets_it_as_remote_module(self):
        self.conn.import_module(fake_module)
        assert fake_module == self.conn.remote_module.module

    def test_importing_it_returns_the_module_too(self):
        remote_foo = self.conn.import_module(fake_module)
        assert remote_foo.module == fake_module

    def test_execute_the_remote_module_send(self):
        stub_channel = Factory(send=Capture(), receive=Capture())
        self.conn.gateway.channel = self.conn.gateway
        remote_foo = self.conn.import_module(fake_module)
        remote_foo.channel = stub_channel
        remote_foo.function('argument')
        assert stub_channel.send.calls[0]['args'][0] == "function('argument')"

    def test_execute_the_remote_module_receive(self):
        stub_channel = Factory(receive=Capture(return_values=[True]), send=Capture())
        self.conn.gateway.channel = self.conn.gateway
        remote_foo = self.conn.import_module(fake_module)
        remote_foo.channel = stub_channel
        assert remote_foo.function('argument') is True

class TestLegacyModuleExecuteArgs(object):

    def setup(self):
        self.remote_module = backends.LegacyModuleExecute(FakeGateway(), None)

    def test_single_argument(self):
        assert self.remote_module._convert_args(('foo',)) == "'foo'"

    def test_more_than_one_argument(self):
        args = ('foo', 'bar', 1)
        assert self.remote_module._convert_args(args) == "'foo', 'bar', 1"

    def test_dictionary_as_argument(self):
        args = ({'some key': 1},)
        assert self.remote_module._convert_args(args) == "{'some key': 1}"

class TestLegacyModuleExecuteGetAttr(object):

    def setup(self):
        self.remote_module = backends.LegacyModuleExecute(FakeGateway(), None)

    def test_raise_attribute_error(self):
        with pytest.raises(AttributeError) as err:
            self.remote_module.foo()
        assert err.value.args[0] == 'module None does not have attribute foo'

class TestMakeConnectionString(object):

    def test_makes_sudo_python_no_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: False)
        assert conn_string == 'popen//python=sudo python'

    def test_makes_sudo_python_with_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
        assert conn_string == 'ssh=localhost//python=sudo python'

    def test_makes_sudo_python_with_ssh_options(self):
        conn = backends.BaseConnection(
            'localhost', sudo=True, eager=False,
            interpreter='python', ssh_options='-F vagrant_ssh_config')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
        assert conn_string == 'ssh=-F vagrant_ssh_config localhost//python=sudo python'

    def test_makes_python_no_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=False, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: False)
        assert conn_string == 'popen//python=python'

    def test_makes_python_with_ssh(self):
        conn = backends.BaseConnection('localhost', sudo=False, eager=False, interpreter='python')
        conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
        assert conn_string == 'ssh=localhost//python=python'

    def test_makes_sudo_python_with_forced_sudo(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string(
            'localhost', _needs_ssh=lambda x: False, use_sudo=True
        )
        assert conn_string == 'popen//python=sudo python'

    def test_does_not_make_sudo_python_with_forced_sudo(self):
        conn = backends.BaseConnection('localhost', sudo=True, eager=False, interpreter='python')
        conn_string = conn._make_connection_string(
            'localhost', _needs_ssh=lambda x: False, use_sudo=False
        )
        assert conn_string == 'popen//python=python'

    def test_detects_python3(self):
        with patch.object(sys, 'version_info', (3, 5, 1)):
            conn = backends.BaseConnection('localhost', sudo=True, eager=False)
            conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: False)
            assert conn_string == 'popen//python=sudo python3'

    def test_detects_python2(self):
        with patch.object(sys, 'version_info', (2, 7, 11)):
            conn = backends.BaseConnection('localhost', sudo=False, eager=False)
            conn_string = conn._make_connection_string('localhost', _needs_ssh=lambda x: True)
            assert conn_string == 'ssh=localhost//python=python2'

class TestDetectSudo(object):

    def setup(self):
        self.execnet = Mock()
        self.execnet.return_value = self.execnet
        self.execnet.makegateway.return_value = self.execnet
        self.execnet.remote_exec.return_value = self.execnet

    def test_does_not_need_sudo(self):
        self.execnet.receive.return_value = 'root'
        conn = backends.BaseConnection('localhost', sudo=True, eager=False)
        assert conn._detect_sudo(_execnet=self.execnet) is False

    def test_does_need_sudo(self):
        self.execnet.receive.return_value = 'alfredo'
        conn = backends.BaseConnection('localhost', sudo=True, eager=False)
        assert conn._detect_sudo(_execnet=self.execnet) is True
<|endoftext|>


<commit_before>"""Module provider for Glesys"""
import json

import requests

from lexicon.exceptions import AuthenticationError
from lexicon.providers.base import Provider as BaseProvider

NAMESERVER_DOMAINS = ["glesys.com"]

def provider_parser(subparser):
    """Generate a subparser for Glesys"""
    subparser.add_argument("--auth-username", help="specify username (CL12345)")
    subparser.add_argument("--auth-token", help="specify API key")

class Provider(BaseProvider):
    """Provider class for Glesys"""

    def __init__(self, config):
        super(Provider, self).__init__(config)
        self.domain_id = None
        self.api_endpoint = "https://api.glesys.com"

    def _authenticate(self):
        payload = self._get("/domain/list")
        domains = payload["response"]["domains"]
        for record in domains:
            if record["domainname"] == self.domain:
                # Domain records do not have any id.
                # Since domain_id cannot be None, use domain name as id instead.
                self.domain_id = record["domainname"]
                break
        else:
            raise AuthenticationError("No domain found")

    # Create record. If record already exists with the same content, do nothing.
    def _create_record(self, rtype, name, content):
        existing = self.list_records(rtype, name, content)
        if existing:
            # Already exists, do nothing.
            return True

        request_data = {
            "domainname": self.domain,
            "host": self._full_name(name),
            "type": rtype,
            "data": content,
        }
        self._addttl(request_data)

        self._post("/domain/addrecord", data=request_data)
        return True

    # List all records. Return an empty list if no records found
    # type, name and content are used to filter records.
    # If possible filter during the query, otherwise filter after response is received.
    def _list_records(self, rtype=None, name=None, content=None):
        request_data = {"domainname": self.domain}
        payload = self._post("/domain/listrecords", data=request_data)

        # Convert from Glesys record structure to Lexicon structure.
        processed_records = [
            self._glesysrecord2lexiconrecord(r) for r in payload["response"]["records"]
        ]

        if rtype:
            processed_records = [
                record for record in processed_records if record["type"] == rtype
            ]
        if name:
            processed_records = [
                record
                for record in processed_records
                if record["name"] == self._full_name(name)
            ]
        if content:
            processed_records = [
                record
                for record in processed_records
                if record["content"].lower() == content.lower()
            ]

        return processed_records

    # Update a record. Identifier must be specified.
    def _update_record(self, identifier, rtype=None, name=None, content=None):
        request_data = {"recordid": identifier}
        if name:
            request_data["host"] = name
        if rtype:
            request_data["type"] = rtype
        if content:
            request_data["data"] = content

        self._addttl(request_data)
        self._post("/domain/updaterecord", data=request_data)
        return True

    # Delete an existing record.
    # If record does not exist, do nothing.
    # If an identifier is specified, use it, otherwise do a lookup using type, name and content.
    def _delete_record(self, identifier=None, rtype=None, name=None, content=None):
        delete_record_id = []
        if not identifier:
            records = self._list_records(rtype, name, content)
            delete_record_id = [record["id"] for record in records]
        else:
            delete_record_id.append(identifier)

        for record_id in delete_record_id:
            request_data = {"recordid": record_id}
            self._post("/domain/deleterecord", data=request_data)

        return True

    # Helpers.
    def _request(self, action="GET", url="/", data=None, query_params=None):
        if data is None:
            data = {}
        if query_params is None:
            query_params = {}

        query_params["format"] = "json"
        default_headers = {
            "Accept": "application/json",
            "Content-Type": "application/json",
        }

        credentials = (
            self._get_provider_option("auth_username"),
            self._get_provider_option("auth_token"),
        )
        response = requests.request(
            action,
            self.api_endpoint + url,
            params=query_params,
            data=json.dumps(data),
            headers=default_headers,
            auth=credentials,
        )

        # if the request fails for any reason, throw an error.
        response.raise_for_status()
        return response.json()

    # Adds TTL parameter if passed as argument to lexicon.
    def _addttl(self, request_data):
        if self._get_lexicon_option("ttl"):
            request_data["ttl"] = self._get_lexicon_option("ttl")

    # From Glesys record structure: [u'domainname', u'recordid', u'type', u'host', u'ttl', u'data']
    def _glesysrecord2lexiconrecord(self, glesys_record):
        return {
            "id": glesys_record["recordid"],
            "type": glesys_record["type"],
            "name": glesys_record["host"],
            "ttl": glesys_record["ttl"],
            "content": glesys_record["data"],
        }
<commit_msg>Fixing bug in glesys provider create action (#1356)<commit_after>"""Module provider for Glesys"""
import json

import requests

from lexicon.exceptions import AuthenticationError
from lexicon.providers.base import Provider as BaseProvider

NAMESERVER_DOMAINS = ["glesys.com"]

def provider_parser(subparser):
    """Generate a subparser for Glesys"""
    subparser.add_argument("--auth-username", help="specify username (CL12345)")
    subparser.add_argument("--auth-token", help="specify API key")

class Provider(BaseProvider):
    """Provider class for Glesys"""

    def __init__(self, config):
        super(Provider, self).__init__(config)
        self.domain_id = None
        self.api_endpoint = "https://api.glesys.com"

    def _authenticate(self):
        payload = self._get("/domain/list")
        domains = payload["response"]["domains"]
        for record in domains:
            if record["domainname"] == self.domain:
                # Domain records do not have any id.
                # Since domain_id cannot be None, use domain name as id instead.
                self.domain_id = record["domainname"]
                break
        else:
            raise AuthenticationError("No domain found")

    # Create record. If record already exists with the same content, do nothing.
    def _create_record(self, rtype, name, content):
        existing = self.list_records(rtype, name, content)
        if existing:
            # Already exists, do nothing.
            return True

        request_data = {
            "domainname": self.domain,
            "host": name,
            "type": rtype,
            "data": content,
        }
        self._addttl(request_data)

        self._post("/domain/addrecord", data=request_data)
        return True

    # List all records. Return an empty list if no records found
    # type, name and content are used to filter records.
    # If possible filter during the query, otherwise filter after response is received.
    def _list_records(self, rtype=None, name=None, content=None):
        request_data = {"domainname": self.domain}
        payload = self._post("/domain/listrecords", data=request_data)

        # Convert from Glesys record structure to Lexicon structure.
        processed_records = [
            self._glesysrecord2lexiconrecord(r) for r in payload["response"]["records"]
        ]

        if rtype:
            processed_records = [
                record for record in processed_records if record["type"] == rtype
            ]
        if name:
            processed_records = [
                record
                for record in processed_records
                if record["name"] == self._full_name(name)
            ]
        if content:
            processed_records = [
                record
                for record in processed_records
                if record["content"].lower() == content.lower()
            ]

        return processed_records

    # Update a record. Identifier must be specified.
    def _update_record(self, identifier, rtype=None, name=None, content=None):
        request_data = {"recordid": identifier}
        if name:
            request_data["host"] = name
        if rtype:
            request_data["type"] = rtype
        if content:
            request_data["data"] = content

        self._addttl(request_data)
        self._post("/domain/updaterecord", data=request_data)
        return True

    # Delete an existing record.
    # If record does not exist, do nothing.
    # If an identifier is specified, use it, otherwise do a lookup using type, name and content.
    def _delete_record(self, identifier=None, rtype=None, name=None, content=None):
        delete_record_id = []
        if not identifier:
            records = self._list_records(rtype, name, content)
            delete_record_id = [record["id"] for record in records]
        else:
            delete_record_id.append(identifier)

        for record_id in delete_record_id:
            request_data = {"recordid": record_id}
            self._post("/domain/deleterecord", data=request_data)

        return True

    # Helpers.
    def _request(self, action="GET", url="/", data=None, query_params=None):
        if data is None:
            data = {}
        if query_params is None:
            query_params = {}

        query_params["format"] = "json"
        default_headers = {
            "Accept": "application/json",
            "Content-Type": "application/json",
        }

        credentials = (
            self._get_provider_option("auth_username"),
            self._get_provider_option("auth_token"),
        )
        response = requests.request(
            action,
            self.api_endpoint + url,
            params=query_params,
            data=json.dumps(data),
            headers=default_headers,
            auth=credentials,
        )

        # if the request fails for any reason, throw an error.
        response.raise_for_status()
        return response.json()

    # Adds TTL parameter if passed as argument to lexicon.
    def _addttl(self, request_data):
        if self._get_lexicon_option("ttl"):
            request_data["ttl"] = self._get_lexicon_option("ttl")

    # From Glesys record structure: [u'domainname', u'recordid', u'type', u'host', u'ttl', u'data']
    def _glesysrecord2lexiconrecord(self, glesys_record):
        return {
            "id": glesys_record["recordid"],
            "type": glesys_record["type"],
            "name": glesys_record["host"],
            "ttl": glesys_record["ttl"],
            "content": glesys_record["data"],
        }
<|endoftext|>


<commit_before>from django.conf import settings
from django.contrib import admin
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models.query import QuerySet
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect

from order import managers
from order import models as order_models

csrf_protect_m = method_decorator(csrf_protect)

def create_order_classes(related_class, order_field_names):
    """
    Create order model and admin class.
    Add order model to order.models module and register admin class.
    Connect ordered_objects manager to related model.
    """
    # Resolve labels for related class.
    labels = resolve_labels(related_class)

    # Dynamic Classes
    class OrderItemBase(models.Model):
        """
        Dynamic order class base.
        """
        item = models.ForeignKey(related_class)
        timestamp = models.DateTimeField(auto_now=True)

        class Meta:
            abstract = True
            app_label = 'order'

    class Admin(admin.ModelAdmin):
        """
        Dynamic order admin class.
        """
        list_display = ('item_link',) + tuple(order_field_names)
        list_editable = order_field_names

        def get_model_perms(self, request):
            """
            Return empty perms dict thus hiding the model from admin index.
            """
            return {}

        @csrf_protect_m
        def changelist_view(self, request, extra_context=None):
            list_url = reverse('admin:%s_%s_changelist' % (labels['app'], labels['model'].lower()))
            add_url = reverse('admin:%s_%s_add' % (labels['app'], labels['model'].lower()))

            result = super(Admin, self).changelist_view(request, extra_context={
                'add_url': add_url,
                'list_url': list_url,
                'related_opts': related_class._meta,
            })

            # XXX: Sanitize order on list save.
            #if (request.method == "POST" and self.list_editable and '_save' in request.POST):
            #    sanitize_order(self.model)
            return result

        def item_link(self, obj):
            url = reverse('admin:%s_%s_change' % (labels['app'], labels['model'].lower()), args=(obj.item.id,))
            return '%s' % (url, obj.item.title)
        item_link.allow_tags = True
        item_link.short_description = 'Item'

    # Set up a dictionary to simulate declarations within a class.
    attrs = {
        '__module__': 'order.models',
    }

    # Create provided order fields and add to attrs.
    fields = {}
    for field in order_field_names:
        fields[field] = models.IntegerField()
    attrs.update(fields)

    # Create the class which automatically triggers Django model processing.
    order_item_class_name = resolve_order_item_class_name(related_class)
    model = type(order_item_class_name, (OrderItemBase, ), attrs)

    # Set the model as part of the order.models module.
    setattr(order_models, order_item_class_name, model)

    # Register admin model.
    admin.site.register(model, Admin)

    # Add user_order_by method to base QuerySet.
    setattr(QuerySet, 'user_order_by', managers.user_order_by)

    # Return created model class.
    return model

def is_orderable(cls):
    """
    Checks if the provided class is specified as an orderable in settings.ORDERABLE_MODELS.
    If it is return its settings.
    """
    labels = resolve_labels(cls)
    if settings.ORDERABLE_MODELS.has_key(labels['app_model']):
        return settings.ORDERABLE_MODELS[labels['app_model']]
    if settings.ORDERABLE_MODELS.has_key(labels['module_app_model']):
        return settings.ORDERABLE_MODELS[labels['module_app_model']]
    return False

def resolve_labels(cls):
    """
    Returns app, model, app_model, module_app and module_app_model labels for provided class.
    XXX: There has to be a better way to do this.
    """
    labels = {}

    # Resolve module.app label.
    labels['module_app'] = cls.__module__.replace('.models', '')

    # Resolve app label.
    labels['app'] = '.'.join(labels['module_app'].split('.')[1:])

    # Resolve model label
    labels['model'] = cls._meta.object_name

    # Resolve module_app_model label.
    labels['app_model'] = '%s.%s' % (labels['app'], labels['model'])

    # Resolve module_app_model label.
    labels['module_app_model'] = '%s.%s' % (labels['module_app'], labels['model'])

    return labels

def resolve_order_item_class_name(cls):
    """
    Returns an OrderItem class name for provided class.
    """
    return '%sOrderItem' % cls._meta.object_name

def resolve_order_item_related_set_name(cls):
    """
    Returns a reverse relation manager name to order items for class.
    """
    return ('%s_set' % resolve_order_item_class_name(cls)).lower()

def sanitize_order(model):
    """
    Sanitize order values so eliminate conflicts and gaps.
    XXX: Early start, very ugly, needs work.
    """
    to_order_dict = {}

    order_field_names = []
    for field in model._meta.fields:
        if isinstance(field, models.IntegerField):
            order_field_names.append(field.name)

    for field_name in order_field_names:
        to_order_dict[field_name] = list(model.objects.all().order_by(field_name, '-timestamp'))

    updates = {}
    for field_name, object_list in to_order_dict.items():
        for i, obj in enumerate(object_list):
            position = i + 1
            if getattr(obj, field_name) != position:
                if updates.has_key(obj):
                    updates[obj][field_name] = position
                else:
                    updates[obj] = {field_name: position}

    for obj, fields in updates.items():
        for field, value in fields.items():
            setattr(obj, field, value)
        obj.save()
<commit_msg>correctly resolve app label<commit_after>from django.conf import settings
from django.contrib import admin
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models.query import QuerySet
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect

from order import managers
from order import models as order_models

csrf_protect_m = method_decorator(csrf_protect)

def create_order_classes(related_class, order_field_names):
    """
    Create order model and admin class.
    Add order model to order.models module and register admin class.
    Connect ordered_objects manager to related model.
    """
    # Resolve labels for related class.
    labels = resolve_labels(related_class)

    # Dynamic Classes
    class OrderItemBase(models.Model):
        """
        Dynamic order class base.
        """
        item = models.ForeignKey(related_class)
        timestamp = models.DateTimeField(auto_now=True)

        class Meta:
            abstract = True
            app_label = 'order'

    class Admin(admin.ModelAdmin):
        """
        Dynamic order admin class.
        """
        list_display = ('item_link',) + tuple(order_field_names)
        list_editable = order_field_names

        def get_model_perms(self, request):
            """
            Return empty perms dict thus hiding the model from admin index.
            """
            return {}

        @csrf_protect_m
        def changelist_view(self, request, extra_context=None):
            list_url = reverse('admin:%s_%s_changelist' % (labels['app'], labels['model'].lower()))
            add_url = reverse('admin:%s_%s_add' % (labels['app'], labels['model'].lower()))

            result = super(Admin, self).changelist_view(request, extra_context={
                'add_url': add_url,
                'list_url': list_url,
                'related_opts': related_class._meta,
            })

            # XXX: Sanitize order on list save.
            #if (request.method == "POST" and self.list_editable and '_save' in request.POST):
            #    sanitize_order(self.model)
            return result

        def item_link(self, obj):
            url = reverse('admin:%s_%s_change' % (labels['app'], labels['model'].lower()), args=(obj.item.id,))
            return '%s' % (url, str(obj.item))
        item_link.allow_tags = True
        item_link.short_description = 'Item'

    # Set up a dictionary to simulate declarations within a class.
    attrs = {
        '__module__': 'order.models',
    }

    # Create provided order fields and add to attrs.
    fields = {}
    for field in order_field_names:
        fields[field] = models.IntegerField()
    attrs.update(fields)

    # Create the class which automatically triggers Django model processing.
    order_item_class_name = resolve_order_item_class_name(related_class)
    model = type(order_item_class_name, (OrderItemBase, ), attrs)

    # Set the model as part of the order.models module.
    setattr(order_models, order_item_class_name, model)

    # Register admin model.
    admin.site.register(model, Admin)

    # Add user_order_by method to base QuerySet.
    setattr(QuerySet, 'user_order_by', managers.user_order_by)

    # Return created model class.
    return model

def is_orderable(cls):
    """
    Checks if the provided class is specified as an orderable in settings.ORDERABLE_MODELS.
    If it is return its settings.
    """
    labels = resolve_labels(cls)
    if settings.ORDERABLE_MODELS.has_key(labels['app_model']):
        return settings.ORDERABLE_MODELS[labels['app_model']]
    if settings.ORDERABLE_MODELS.has_key(labels['module_app_model']):
        return settings.ORDERABLE_MODELS[labels['module_app_model']]
    return False

def resolve_labels(cls):
    """
    Returns app, model, app_model, module_app and module_app_model labels for provided class.
    XXX: There has to be a better way to do this.
    """
    labels = {}

    # Resolve module.app label.
    labels['module_app'] = cls.__module__.replace('.models', '')

    # Resolve app label.
    labels['app'] = labels['module_app'].split('.')[-1]

    # Resolve model label
    labels['model'] = cls._meta.object_name

    # Resolve module_app_model label.
    labels['app_model'] = '%s.%s' % (labels['app'], labels['model'])

    # Resolve module_app_model label.
    labels['module_app_model'] = '%s.%s' % (labels['module_app'], labels['model'])

    return labels

def resolve_order_item_class_name(cls):
    """
    Returns an OrderItem class name for provided class.
    """
    return '%sOrderItem' % cls._meta.object_name

def resolve_order_item_related_set_name(cls):
    """
    Returns a reverse relation manager name to order items for class.
    """
    return ('%s_set' % resolve_order_item_class_name(cls)).lower()

def sanitize_order(model):
    """
    Sanitize order values so eliminate conflicts and gaps.
    XXX: Early start, very ugly, needs work.
    """
    to_order_dict = {}

    order_field_names = []
    for field in model._meta.fields:
        if isinstance(field, models.IntegerField):
            order_field_names.append(field.name)

    for field_name in order_field_names:
        to_order_dict[field_name] = list(model.objects.all().order_by(field_name, '-timestamp'))

    updates = {}
    for field_name, object_list in to_order_dict.items():
        for i, obj in enumerate(object_list):
            position = i + 1
            if getattr(obj, field_name) != position:
                if updates.has_key(obj):
                    updates[obj][field_name] = position
                else:
                    updates[obj] = {field_name: position}

    for obj, fields in updates.items():
        for field, value in fields.items():
            setattr(obj, field, value)
        obj.save()
<|endoftext|>


<commit_before># Copyright (c) 2009 Raymond Hettinger
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
#     The above copyright notice and this permission notice shall be
#     included in all copies or substantial portions of the Software.
#
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#     OTHER DEALINGS IN THE SOFTWARE.

from UserDict import DictMixin

class OrderedDict(dict, DictMixin):

    def __init__(self, *args, **kwds):
        if len(args) > 1:
            raise TypeError('expected at most 1 arguments, got %d' % len(args))
        try:
            self.__end
        except AttributeError:
            self.clear()
        self.update(*args, **kwds)

    def clear(self):
        self.__end = end = []
        end += [None, end, end]         # sentinel node for doubly linked list
        self.__map = {}                 # key --> [key, prev, next]
        dict.clear(self)

    def __setitem__(self, key, value):
        if key not in self:
            end = self.__end
            curr = end[1]
            curr[2] = end[1] = self.__map[key] = [key, curr, end]
        dict.__setitem__(self, key, value)

    def __delitem__(self, key):
        dict.__delitem__(self, key)
        key, prev, next = self.__map.pop(key)
        prev[2] = next
        next[1] = prev

    def __iter__(self):
        end = self.__end
        curr = end[2]
        while curr is not end:
            yield curr[0]
            curr = curr[2]

    def __reversed__(self):
        end = self.__end
        curr = end[1]
        while curr is not end:
            yield curr[0]
            curr = curr[1]

    def popitem(self, last=True):
        if not self:
            raise KeyError('dictionary is empty')
        if last:
            key = reversed(self).next()
        else:
            key = iter(self).next()
        value = self.pop(key)
        return key, value

    def __reduce__(self):
        items = [[k, self[k]] for k in self]
        tmp = self.__map, self.__end
        del self.__map, self.__end
        inst_dict = vars(self).copy()
        self.__map, self.__end = tmp
        if inst_dict:
            return (self.__class__, (items,), inst_dict)
        return self.__class__, (items,)

    def keys(self):
        return list(self)

    setdefault = DictMixin.setdefault
    update = DictMixin.update
    pop = DictMixin.pop
    values = DictMixin.values
    items = DictMixin.items
    iterkeys = DictMixin.iterkeys
    itervalues = DictMixin.itervalues
    iteritems = DictMixin.iteritems

    def __repr__(self):
        if not self:
            return '%s()' % (self.__class__.__name__,)
        return '%s(%r)' % (self.__class__.__name__, self.items())

    def copy(self):
        return self.__class__(self)

    @classmethod
    def fromkeys(cls, iterable, value=None):
        d = cls()
        for key in iterable:
            d[key] = value
        return d

    def __eq__(self, other):
        if isinstance(other, OrderedDict):
            if len(self) != len(other):
                return False
            for p, q in  zip(self.items(), other.items()):
                if p != q:
                    return False
            return True
        return dict.__eq__(self, other)

    def __ne__(self, other):
        return not self == other
<commit_msg>Fixed ordereddict to not error when ChannelRepositoryTools is installed in ST3<commit_after># Copyright (c) 2009 Raymond Hettinger
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
#     The above copyright notice and this permission notice shall be
#     included in all copies or substantial portions of the Software.
#
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#     OTHER DEALINGS IN THE SOFTWARE.

import sys
if sys.version_info < (3,):
    from UserDict import DictMixin

    class OrderedDict(dict, DictMixin):

        def __init__(self, *args, **kwds):
            if len(args) > 1:
                raise TypeError('expected at most 1 arguments, got %d' % len(args))
            try:
                self.__end
            except AttributeError:
                self.clear()
            self.update(*args, **kwds)

        def clear(self):
            self.__end = end = []
            end += [None, end, end]         # sentinel node for doubly linked list
            self.__map = {}                 # key --> [key, prev, next]
            dict.clear(self)

        def __setitem__(self, key, value):
            if key not in self:
                end = self.__end
                curr = end[1]
                curr[2] = end[1] = self.__map[key] = [key, curr, end]
            dict.__setitem__(self, key, value)

        def __delitem__(self, key):
            dict.__delitem__(self, key)
            key, prev, next = self.__map.pop(key)
            prev[2] = next
            next[1] = prev

        def __iter__(self):
            end = self.__end
            curr = end[2]
            while curr is not end:
                yield curr[0]
                curr = curr[2]

        def __reversed__(self):
            end = self.__end
            curr = end[1]
            while curr is not end:
                yield curr[0]
                curr = curr[1]

        def popitem(self, last=True):
            if not self:
                raise KeyError('dictionary is empty')
            if last:
                key = reversed(self).next()
            else:
                key = iter(self).next()
            value = self.pop(key)
            return key, value

        def __reduce__(self):
            items = [[k, self[k]] for k in self]
            tmp = self.__map, self.__end
            del self.__map, self.__end
            inst_dict = vars(self).copy()
            self.__map, self.__end = tmp
            if inst_dict:
                return (self.__class__, (items,), inst_dict)
            return self.__class__, (items,)

        def keys(self):
            return list(self)

        setdefault = DictMixin.setdefault
        update = DictMixin.update
        pop = DictMixin.pop
        values = DictMixin.values
        items = DictMixin.items
        iterkeys = DictMixin.iterkeys
        itervalues = DictMixin.itervalues
        iteritems = DictMixin.iteritems

        def __repr__(self):
            if not self:
                return '%s()' % (self.__class__.__name__,)
            return '%s(%r)' % (self.__class__.__name__, self.items())

        def copy(self):
            return self.__class__(self)

        @classmethod
        def fromkeys(cls, iterable, value=None):
            d = cls()
            for key in iterable:
                d[key] = value
            return d

        def __eq__(self, other):
            if isinstance(other, OrderedDict):
                if len(self) != len(other):
                    return False
                for p, q in  zip(self.items(), other.items()):
                    if p != q:
                        return False
                return True
            return dict.__eq__(self, other)

        def __ne__(self, other):
            return not self == other
<|endoftext|>


<commit_before>##by: Shevaun Lewis
##date updated: 3/11/11
##updated by: Shayne Sloggett
## revised 5/2014 by Ilia Kurenkov

# IK: for now importing repeat fxn from itertools, may want to revise this
from itertools import repeat
# import functionality from utility module
from util import *

###############################################################################
## processing unsorted DA1 files
###############################################################################

def classify_line(line):
    '''Given a line (as a list of strings), determines what type of trial
    this line is: whether it is a question, a sentence or a rejected trial.
    '''
    trial_types = {
    '2' : 's',
    '6' : 'q',
    '7' : 'q',
    }
    item_type = line[4]
    if item_type in trial_types:
        return trial_types[item_type]
    return 'reject'

def parse_da1_file(file_name):
    '''Given a file name extracts the subject number from it as well as all the
    sentence, question and rejected items for this subject.
    Returns a tuple of the form:
    (subject_number, sentence_list, question_list, rejected_list)
    '''
    # using function imported from util module
    subj_number = get_subj_num(file_name)
    with open(file_name) as da1file:
        # we start by filtering out all empty lines
        non_empty = [line.strip().split() for line in da1file if line]
        # we then collect the sentence, question and rejected lists
        sentences = [line for line in non_empty if classify_line(line) is 's']
        questions = [line for line in non_empty if classify_line(line) is 'q']
        rejects = [line for line in non_empty if classify_line(line) is 'reject']
    return (subj_number, sentences, questions, rejects)

def sort_da1_data(data_dir):
    '''Sorts a folder with DA1 files.
    Given a folder name, loops over all DA1 files in it and for each file
    creates a tuple with the subject number tied to the corresponding sentence,
    question and rejected trials.
    '''
    # generate the paths to files using function from util module
    file_list = gen_file_paths(data_dir, filter_func=is_DA1_file)
    # we then run parse_da1_file function on every member of file_list
    return list(map(parse_da1_file, file_list))

###############################################################################
## writing sorted DA1s to folders
###############################################################################

def create_folder(root_path, study_exp_name, suffix, data):
    '''Given a root path as well as a study or experiment name, a suffix
    (e.g. -s or -q) and data to write, creates an output folder under the root_path
    directory with the passed suffix.
    Then creates files for all the subjects that have non-empty data for
    this folder.
    '''
    # we start by setting up the output folder
    output_root = os.path.join(root_path, study_exp_name + suffix)
    os.makedirs(output_root, exist_ok=True)
    # we then make sure we're not writing empty lists to files
    existing_data = (item for item in data if len(item[1]) > 0)
    # for all subjects that have data associated with them...
    for subj_n, trials in existing_data:
        # create the name for the subject's file and turn it into a path
        subj_file_name = subj_n + '-' + study_exp_name + suffix + '.da1'
        subj_file_path = os.path.join(output_root, subj_file_name)
        write_to_table(subj_file_path, trials, delimiter=' ')

def write_da1(study_exp_name, data, nest_under=''):
    '''Given a study or experiment name as well as the data for writing,
    creates a folder corresponding to the experiment/study name and writes
    data to subfolders inside it, one for every suffix in the "suffixes" list.
    The suffixes stand for be basic trial types: sentences, questions, rejections.
    The optional nest_under argument can specify that the whole output folder
    should be created inside the folder passed as "nest_under".
    '''
    suffixes = [
    ('-s', 1),
    ('-q', 2),
    ('-reject', 3)
    ]
    # set the root path to different things based on whether nest_under is provided
    if nest_under:
        root_path = os.path.join(nest_under, study_exp_name + '-sorted')
    else:
        root_path = study_exp_name + '-sorted'
    for suff, index in suffixes:
        # use the index variable to select only data relevant for this suffix
        relevant = [(item[0], item[index]) for item in data]
        create_folder(root_path, study_exp_name, suff, relevant)

###############################################################################
## loading sorted DA1s
###############################################################################

def get_study_name(dir_name):
    normed_dir = os.path.normpath(dir_name)
    return os.path.basename(normed_dir).split('-')[0]

def load_da1_file(file_path, index):
    subj_number = get_subj_num(file_path)
    starter = (subj_number, [], [], [])
    with open(file_path) as da1file:
        subj_items = [line.strip().split() for line in da1file]
    return starter[:index] + (subj_items,) + starter[index + 1:]

def load_sorted_da1(sorted_dir):
    # consider passing this around as an argument to change program's overall behavior
    suffixes = [
    ('-s', 1),
    ('-q', 2),
    ('-reject', 3)
    ]
    # think about making following line a bit simpler or clearer as to its purpose
    study_name = get_study_name(sorted_dir)
    sorted_da1 = []
    for suffix, index in suffixes:
        suff_root = os.path.join(sorted_dir, study_name + suffix)
        subj_files = gen_file_paths(suff_root)
        sorted_da1 += [load_da1_file(f, index) for f in subj_files]
    return sorted_da1

###############################################################################
## Selecting items for only one experiment
###############################################################################

def condition_filter(ranges):
    start, total = int(ranges[0]), int(ranges[1])
    return [str(n) for n in range(start, start + total)]

def get_exp_items(item, cond_range):
    # print(item)
    s_number, sents, questions, rejects = item
    exp_sents = [s for s in sents if s[1] in cond_range]
    exp_qs =  [q for q in questions if q[1] in cond_range]
    exp_rej =  [r for r in rejects if r[1] in cond_range]
    return (s_number, exp_sents, exp_qs, exp_rej)

###############################################################################
## Running the code
###############################################################################

SPLIT_WHOLE_STUDY = '''
Do you need to split the DA1s into -s, -q, and -reject files?
(Answer *no* if you already have the data split.)
'''
START_EXP_SPLIT = '''
Do you want to split the data by experiment?
'''
MORE_EXP_SPLIT = '''
Do you want to split the data by more experiments?
'''

def main():
    split_study = ask_single_question(SPLIT_WHOLE_STUDY)
    if is_yes(split_study):
        questions = [
        'folder with unsorted DA1 files',
        'name of your study',
        ]
        [da1_folder, study_name] = ask_user_questions(questions, return_list=True)
        sorted_da1s = sort_da1_data(da1_folder)
        write_da1(study_name, sorted_da1s)
        study_root = study_name + '-sorted'
    else:
        sorted_folder = ask_single_question('Enter sorted files folder:\n')
        sorted_da1s = load_sorted_da1(sorted_folder)
        study_root = sorted_folder

    experiment_meta_qs = [
    'experiment name',
    'first condition number',
    'total number of conditions'
    ]

    experiment_split_decision = ask_single_question(START_EXP_SPLIT)
    splitting_by_experiment = is_yes(experiment_split_decision)

    while splitting_by_experiment:
        exp_meta_data = ask_user_questions(experiment_meta_qs, return_list=True)
        exp_filter = condition_filter(exp_meta_data[1:])
        exp_data = [get_exp_items(item, exp_filter) for item in sorted_da1s]
        exp_name = exp_meta_data[0]
        write_da1(exp_name, exp_data, nest_under=study_root)
        continue_decision = ask_single_question(MORE_EXP_SPLIT)
        splitting_by_experiment = is_yes(continue_decision)

if __name__ == '__main__':
    main()<commit_msg>cleaned up section on loading sorted da1 data<commit_after>##by: Shevaun Lewis
##date updated: 3/11/11
##updated by: Shayne Sloggett
## revised 5/2014 by Ilia Kurenkov

# IK: for now importing repeat fxn from itertools, may want to revise this
from itertools import repeat
# import functionality from utility module
from util import *

###############################################################################
## processing unsorted DA1 files
###############################################################################

def classify_line(line):
    '''Given a line (as a list of strings), determines what type of trial
    this line is: whether it is a question, a sentence or a rejected trial.
    '''
    trial_types = {
    '2' : 's',
    '6' : 'q',
    '7' : 'q',
    }
    item_type = line[4]
    if item_type in trial_types:
        return trial_types[item_type]
    return 'reject'

def parse_da1_file(file_name):
    '''Given a file name extracts the subject number from it as well as all the
    sentence, question and rejected items for this subject.
    Returns a tuple of the form:
    (subject_number, sentence_list, question_list, rejected_list)
    '''
    # using function imported from util module
    subj_number = get_subj_num(file_name)
    with open(file_name) as da1file:
        # we start by filtering out all empty lines
        non_empty = [line.strip().split() for line in da1file if line]
        # we then collect the sentence, question and rejected lists
        sentences = [line for line in non_empty if classify_line(line) is 's']
        questions = [line for line in non_empty if classify_line(line) is 'q']
        rejects = [line for line in non_empty if classify_line(line) is 'reject']
    return (subj_number, sentences, questions, rejects)

def sort_da1_data(data_dir):
    '''Sorts a folder with DA1 files.
    Given a folder name, loops over all DA1 files in it and for each file
    creates a tuple with the subject number tied to the corresponding sentence,
    question and rejected trials.
    '''
    # generate the paths to files using function from util module
    file_list = gen_file_paths(data_dir, filter_func=is_DA1_file)
    # we then run parse_da1_file function on every member of file_list
    return list(map(parse_da1_file, file_list))

###############################################################################
## writing sorted DA1s to folders
###############################################################################

def create_folder(root_path, study_exp_name, suffix, data):
    '''Given a root path as well as a study or experiment name, a suffix
    (e.g. -s or -q) and data to write, creates an output folder under the root_path
    directory with the passed suffix.
    Then creates files for all the subjects that have non-empty data for
    this folder.
    '''
    # we start by setting up the output folder
    output_root = os.path.join(root_path, study_exp_name + suffix)
    os.makedirs(output_root, exist_ok=True)
    # we then make sure we're not writing empty lists to files
    existing_data = (item for item in data if len(item[1]) > 0)
    # for all subjects that have data associated with them...
    for subj_n, trials in existing_data:
        # create the name for the subject's file and turn it into a path
        subj_file_name = subj_n + '-' + study_exp_name + suffix + '.da1'
        subj_file_path = os.path.join(output_root, subj_file_name)
        write_to_table(subj_file_path, trials, delimiter=' ')

def write_da1(study_exp_name, data, nest_under=''):
    '''Given a study or experiment name as well as the data for writing,
    creates a folder corresponding to the experiment/study name and writes
    data to subfolders inside it, one for every suffix in the "suffixes" list.
    The suffixes stand for be basic trial types: sentences, questions, rejections.
    The optional nest_under argument can specify that the whole output folder
    should be created inside the folder passed as "nest_under".
    '''
    suffixes = [
    ('-s', 1),
    ('-q', 2),
    ('-reject', 3)
    ]
    # set the root path to different things based on whether nest_under is provided
    if nest_under:
        root_path = os.path.join(nest_under, study_exp_name + '-sorted')
    else:
        root_path = study_exp_name + '-sorted'
    for suff, index in suffixes:
        # use the index variable to select only data relevant for this suffix
        relevant = [(item[0], item[index]) for item in data]
        create_folder(root_path, study_exp_name, suff, relevant)

###############################################################################
## loading sorted DA1s
###############################################################################

def get_study_name(dir_name):
    '''Given a folder name extracts the study name from it, assuming the following
    folder name format:
    STUDY_NAME-sorted
    '''
    normed_dir = os.path.normpath(dir_name)
    return os.path.basename(normed_dir).split('-')[0]

def load_da1_file(file_path, index):
    '''This function loads only sentence or question or rejection items
    for a subject from a da1 file and returns them in the same format as if we
    read in an unsorted da1 file:
    (subject#, sentences, questions, rejects)
    However, in this case two of the lists will be empty, as we are loading a
    sorted file.
    The "index" argument deterimines which one of the three lists gets populated
    with the items extracted from the file.
    '''
    subj_number = get_subj_num(file_path)
    subj_frame = [subj_number, [], [], []]
    with open(file_path) as da1file:
        subj_frame[index] = [line.strip().split() for line in da1file]
    return tuple(subj_frame)

def load_sorted_da1(sorted_dir):
    '''Given path to a folder with the sorted DA1 files, reads in said files
    and returns the same data structure as sort_da1_data, namely a list of
    tuples where subject numbers are bound to lists of sentence, question, rejected
    items.
    '''
    suffixes = [
    ('-s', 1),
    ('-q', 2),
    ('-reject', 3)
    ]
    study_name = get_study_name(sorted_dir)
    sorted_da1 = []
    for suffix, index in suffixes:
        type_root = os.path.join(sorted_dir, study_name + suffix)
        subj_files = gen_file_paths(type_root)
        sorted_da1 += [load_da1_file(f, index) for f in subj_files]
    return sorted_da1

###############################################################################
## Selecting items for only one experiment
###############################################################################

def condition_filter(ranges):
    start, total = int(ranges[0]), int(ranges[1])
    return [str(n) for n in range(start, start + total)]

def get_exp_items(item, cond_range):
    # print(item)
    s_number, sents, questions, rejects = item
    exp_sents = [s for s in sents if s[1] in cond_range]
    exp_qs =  [q for q in questions if q[1] in cond_range]
    exp_rej =  [r for r in rejects if r[1] in cond_range]
    return (s_number, exp_sents, exp_qs, exp_rej)

###############################################################################
## Running the code
###############################################################################

SPLIT_WHOLE_STUDY = '''
Do you need to split the DA1s into -s, -q, and -reject files?
(Answer *no* if you already have the data split.)
'''
START_EXP_SPLIT = '''
Do you want to split the data by experiment?
'''
MORE_EXP_SPLIT = '''
Do you want to split the data by more experiments?
'''

def main():
    split_study = ask_single_question(SPLIT_WHOLE_STUDY)
    if is_yes(split_study):
        questions = [
        'folder with unsorted DA1 files',
        'name of your study',
        ]
        [da1_folder, study_name] = ask_user_questions(questions, return_list=True)
        sorted_da1s = sort_da1_data(da1_folder)
        write_da1(study_name, sorted_da1s)
        study_root = study_name + '-sorted'
    else:
        sorted_folder = ask_single_question('Enter sorted files folder:\n')
        sorted_da1s = load_sorted_da1(sorted_folder)
        study_root = sorted_folder

    experiment_meta_qs = [
    'experiment name',
    'first condition number',
    'total number of conditions'
    ]

    experiment_split_decision = ask_single_question(START_EXP_SPLIT)
    splitting_by_experiment = is_yes(experiment_split_decision)

    while splitting_by_experiment:
        exp_meta_data = ask_user_questions(experiment_meta_qs, return_list=True)
        exp_filter = condition_filter(exp_meta_data[1:])
        exp_data = [get_exp_items(item, exp_filter) for item in sorted_da1s]
        exp_name = exp_meta_data[0]
        write_da1(exp_name, exp_data, nest_under=study_root)
        continue_decision = ask_single_question(MORE_EXP_SPLIT)
        splitting_by_experiment = is_yes(continue_decision)

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


<commit_before>import sublime
import sublime_plugin

import glob
import os

DEBUG = 1
THIS_PACKAGE = "PackageDev"
# if DEBUG: THIS_PACKAGE = "XXX" + THIS_PACKAGE

status = sublime.status_message
error = sublime.error_message
join_path = os.path.join
path_exists = os.path.exists
root_at_packages_path = lambda *leafs: join_path(sublime.packages_path(), *leafs)

DEFAULT_DIRS = (
            "Snippets",
            "Support",
            "Docs",
            "Macros"
            )

# name, default template
DEFAULT_FILES = (
            ("LICENSE.txt", None),
            ("README.rst", root_at_packages_path(THIS_PACKAGE, "Support/README.rst")),
)

class NewPackageCommand(sublime_plugin.WindowCommand):

    def on_done(self, pkg_name):
        pam = PackageManager()
        if pam.exists(pkg_name):
            error("  NewPackage -- Error\n\n"
                  "  Package '" + pkg_name + "' already exists.\n"
                  "  You cannot overwrite an existing package."
            )
            return

        pam.create_new(pkg_name)

    def on_cancel(self):
        status('on_cancel')

    def on_changed(self):
        status('on_changed')

    def run(self):
        self.window.show_input_panel(
                            "New Package Name", '', self.on_done, None, None)

class DeletePackageCommand(sublime_plugin.WindowCommand):
    def run(self):
        pam = PackageManager()
        pam.browse()

class PackageManager(object):

    def is_installed(self, name):
        raise NotImplemented

    def exists(self, name):
        return path_exists(root_at_packages_path(name))

    def browse(self):
        # Let user choose.
        sublime.active_window().run_command("open_dir",
                                            {"dir": sublime.packages_path()})

    def create_new(self, name):
        print "[NewPackage] Creating new package...",
        print root_at_packages_path(name)

        if self.dry_run:
            msg = "[NewPackage] ** Nothing done. This was a test. **"
            print msg
            status(msg)
            return

        # Create top folder, default folders, default files.
        map(os.makedirs, [root_at_packages_path(name, d) for d in DEFAULT_DIRS])

        for f, template in [(root_at_packages_path(name, fname), template)
                                        for fname, template in DEFAULT_FILES]:
            with open(f, 'w') as fh:
                if template:
                    content = "".join(open(template, 'r').readlines()) % \
                                                        {"package_name": name}
                    fh.write(content)

        msg = "[NewPackage] Created new package '%s'." % name
        print msg
        status(msg)

    def __init__(self, dry_run=False):
        self.dry_run = dry_run<commit_msg>Make sublime_lib available for all packages.<commit_after>import sublime
import sublime_plugin

import glob
import os
import sys

# Makes sublime_lib package available for all packages.
if not os.path.join(root_at_packages_path("PackageDev/Lib")) in sys.path:
    sys.path.append(os.path.join(root_at_packages_path("PackageDev/Lib")))

DEBUG = 1
THIS_PACKAGE = "PackageDev"
# if DEBUG: THIS_PACKAGE = "XXX" + THIS_PACKAGE

status = sublime.status_message
error = sublime.error_message
join_path = os.path.join
path_exists = os.path.exists
root_at_packages_path = lambda *leafs: join_path(sublime.packages_path(), *leafs)

DEFAULT_DIRS = (
            "Snippets",
            "Support",
            "Docs",
            "Macros"
            )

# name, default template
DEFAULT_FILES = (
            ("LICENSE.txt", None),
            ("README.rst", root_at_packages_path(THIS_PACKAGE, "Support/README.rst")),
)

class NewPackageCommand(sublime_plugin.WindowCommand):

    def on_done(self, pkg_name):
        pam = PackageManager()
        if pam.exists(pkg_name):
            error("  NewPackage -- Error\n\n"
                  "  Package '" + pkg_name + "' already exists.\n"
                  "  You cannot overwrite an existing package."
            )
            return

        pam.create_new(pkg_name)

    def on_cancel(self):
        status('on_cancel')

    def on_changed(self):
        status('on_changed')

    def run(self):
        self.window.show_input_panel(
                            "New Package Name", '', self.on_done, None, None)

class DeletePackageCommand(sublime_plugin.WindowCommand):
    def run(self):
        pam = PackageManager()
        pam.browse()

class PackageManager(object):

    def is_installed(self, name):
        raise NotImplemented

    def exists(self, name):
        return path_exists(root_at_packages_path(name))

    def browse(self):
        # Let user choose.
        sublime.active_window().run_command("open_dir",
                                            {"dir": sublime.packages_path()})

    def create_new(self, name):
        print "[NewPackage] Creating new package...",
        print root_at_packages_path(name)

        if self.dry_run:
            msg = "[NewPackage] ** Nothing done. This was a test. **"
            print msg
            status(msg)
            return

        # Create top folder, default folders, default files.
        map(os.makedirs, [root_at_packages_path(name, d) for d in DEFAULT_DIRS])

        for f, template in [(root_at_packages_path(name, fname), template)
                                        for fname, template in DEFAULT_FILES]:
            with open(f, 'w') as fh:
                if template:
                    content = "".join(open(template, 'r').readlines()) % \
                                                        {"package_name": name}
                    fh.write(content)

        msg = "[NewPackage] Created new package '%s'." % name
        print msg
        status(msg)

    def __init__(self, dry_run=False):
        self.dry_run = dry_run<|endoftext|>


<commit_before>from django.db.models import get_model
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
from django.utils.module_loading import module_has_submodule

from sitetree import settings

def generate_id_for(obj):
    """Generates and returns a unique identifier for the given object."""
    return id(obj)

def tree(alias, title='', items=None):
    """Dynamically creates and returns a sitetree.
    `items` - dynamic sitetree items objects created by `item` function.

    """
    tree_obj = get_tree_model()(alias=alias, title=title)
    tree_obj.id = generate_id_for(tree_obj)
    tree_obj.is_dynamic = True

    if items is not None:
        tree_obj.dynamic_items = []
        def traverse(items):
            for item in items:
                item.tree = tree_obj
                tree_obj.dynamic_items.append(item)
                if hasattr(item, 'dynamic_children'):
                    traverse(item.dynamic_children)

        traverse(items)
    return tree_obj

def item(title, url, children=None, url_as_pattern=True, hint='', alias='', description='', in_menu=True, in_breadcrumbs=True, in_sitetree=True, access_loggedin=False, access_guest=False):
    """Dynamically creates and returns a sitetree item object.
    `children` - a list of children for tree item. Children should also be created by `item` function.

    """
    item_obj = get_tree_item_model()(title=title, url=url, urlaspattern=url_as_pattern,
                                   hint=hint, alias=alias, description=description, inmenu=in_menu,
                                   insitetree=in_sitetree, inbreadcrumbs=in_breadcrumbs,
                                   access_loggedin=access_loggedin, access_guest=access_guest)
    item_obj.id = generate_id_for(item_obj)
    item_obj.is_dynamic = True
    item_obj.dynamic_children = []

    if children is not None:
        for child in children:
            child.parent = item_obj
            item_obj.dynamic_children.append(child)
    return item_obj

def import_app_sitetree_module(app):
    """Imports sitetree module from a given app."""
    module_name = settings.APP_MODULE_NAME
    module = import_module(app)
    try:
        sub_module = import_module('%s.%s' % (app, module_name))
        return sub_module
    except:
        if module_has_submodule(module, module_name):
            raise
        return None

def import_project_sitetree_modules():
    """Imports sitetrees modules from packages (apps)."""
    from django.conf import settings as django_settings
    submodules = []
    for app in django_settings.INSTALLED_APPS:
        module = import_app_sitetree_module(app)
        if module is not None:
            submodules.append(module)
    return submodules

def get_app_n_model(settings_entry_name):
    """Returns tuple with application and tree[item] model class names."""
    try:
        app_name, model_name = getattr(settings, settings_entry_name).split('.')
    except ValueError:
        raise ImproperlyConfigured('`SITETREE_%s` must have the following format: `app_name.model_name`.' % settings_entry_name)
    return app_name, model_name

def get_model_class(settings_entry_name):
    """Returns a certain sitetree model as defined in the project settings."""
    app_name, model_name = get_app_n_model(settings_entry_name)
    model = get_model(app_name, model_name)

    if model is None:
        raise ImproperlyConfigured('`SITETREE_%s` refers to model `%s` that has not been installed.' % (settings_entry_name, model_name))

    return model

def get_tree_model():
    """Returns the Tree model, set for the project."""
    return get_model_class('MODEL_TREE')

def get_tree_item_model():
    """Returns the TreeItem model, set for the project."""
    return get_model_class('MODEL_TREE_ITEM')
<commit_msg>Satisfied Django 1.7 warning.<commit_after>from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
from django.utils.module_loading import module_has_submodule

try:
    from django.apps import apps
    apps_get_model = apps.get_model
except ImportError:  # Django < 1.7
    from django.db.models import get_model
    apps_get_model = None

from sitetree import settings

def generate_id_for(obj):
    """Generates and returns a unique identifier for the given object."""
    return id(obj)

def tree(alias, title='', items=None):
    """Dynamically creates and returns a sitetree.
    `items` - dynamic sitetree items objects created by `item` function.

    """
    tree_obj = get_tree_model()(alias=alias, title=title)
    tree_obj.id = generate_id_for(tree_obj)
    tree_obj.is_dynamic = True

    if items is not None:
        tree_obj.dynamic_items = []
        def traverse(items):
            for item in items:
                item.tree = tree_obj
                tree_obj.dynamic_items.append(item)
                if hasattr(item, 'dynamic_children'):
                    traverse(item.dynamic_children)

        traverse(items)
    return tree_obj

def item(title, url, children=None, url_as_pattern=True, hint='', alias='', description='', in_menu=True, in_breadcrumbs=True, in_sitetree=True, access_loggedin=False, access_guest=False):
    """Dynamically creates and returns a sitetree item object.
    `children` - a list of children for tree item. Children should also be created by `item` function.

    """
    item_obj = get_tree_item_model()(title=title, url=url, urlaspattern=url_as_pattern,
                                   hint=hint, alias=alias, description=description, inmenu=in_menu,
                                   insitetree=in_sitetree, inbreadcrumbs=in_breadcrumbs,
                                   access_loggedin=access_loggedin, access_guest=access_guest)
    item_obj.id = generate_id_for(item_obj)
    item_obj.is_dynamic = True
    item_obj.dynamic_children = []

    if children is not None:
        for child in children:
            child.parent = item_obj
            item_obj.dynamic_children.append(child)
    return item_obj

def import_app_sitetree_module(app):
    """Imports sitetree module from a given app."""
    module_name = settings.APP_MODULE_NAME
    module = import_module(app)
    try:
        sub_module = import_module('%s.%s' % (app, module_name))
        return sub_module
    except:
        if module_has_submodule(module, module_name):
            raise
        return None

def import_project_sitetree_modules():
    """Imports sitetrees modules from packages (apps)."""
    from django.conf import settings as django_settings
    submodules = []
    for app in django_settings.INSTALLED_APPS:
        module = import_app_sitetree_module(app)
        if module is not None:
            submodules.append(module)
    return submodules

def get_app_n_model(settings_entry_name):
    """Returns tuple with application and tree[item] model class names."""
    try:
        app_name, model_name = getattr(settings, settings_entry_name).split('.')
    except ValueError:
        raise ImproperlyConfigured('`SITETREE_%s` must have the following format: `app_name.model_name`.' % settings_entry_name)
    return app_name, model_name

def get_model_class(settings_entry_name):
    """Returns a certain sitetree model as defined in the project settings."""
    app_name, model_name = get_app_n_model(settings_entry_name)
    if apps_get_model is None:
        model = get_model(app_name, model_name)
    else:
        try:
            model = apps_get_model(app_name, model_name)
        except (LookupError, ValueError):
            model = None

    if model is None:
        raise ImproperlyConfigured('`SITETREE_%s` refers to model `%s` that has not been installed.' % (settings_entry_name, model_name))

    return model

def get_tree_model():
    """Returns the Tree model, set for the project."""
    return get_model_class('MODEL_TREE')

def get_tree_item_model():
    """Returns the TreeItem model, set for the project."""
    return get_model_class('MODEL_TREE_ITEM')
<|endoftext|>