Esempio n. 1
0
    def __init__(self, session=None, connection_factory=None, resource_factory=None, collection_factory=None):
        """
        Creates a ``Session`` instance.

        :param session: (Optional) Custom instantiated ``botocore`` instance.
            Useful if you have specific needs. If not present, a default
            ``Session`` will be created.
        :type session: <botocore.session.Session> instance

        :param connection_factory: (Optional) Specifies a custom
            ``ConnectionFactory`` to be used. Useful if you need to change how
            ``Connection`` objects are constructed by the session.
        :type connection_factory: <kotocore.connection.ConnectionFactory>
            instance

        :param resource_factory: (Optional) Specifies a custom
            ``ResourceFactory`` to be used. Useful if you need to change how
            ``Resource`` objects are constructed by the session.
        :type resource_factory: <kotocore.resources.ResourceFactory>
            instance

        :param collection_factory: (Optional) Specifies a custom
            ``CollectionFactory`` to be used. Useful if you need to change how
            ``Collection`` objects are constructed by the session.
        :type collection_factory: <kotocore.collections.CollectionFactory>
            instance
        """
        super(Session, self).__init__()
        self.core_session = session
        self.connection_factory = connection_factory
        self.resource_factory = resource_factory
        self.collection_factory = collection_factory

        self.cache = self.cache_class()

        if not self.core_session:
            self.core_session = botocore.session.get_session()

        self.core_session.user_agent_name = USER_AGENT_NAME
        self.core_session.user_agent_version = USER_AGENT_VERSION

        if not self.connection_factory:
            from kotocore.connection import ConnectionFactory

            self.connection_factory = ConnectionFactory(session=self)

        if not self.resource_factory:
            from kotocore.resources import ResourceFactory

            self.resource_factory = ResourceFactory(session=self)

        if not self.collection_factory:
            from kotocore.collections import CollectionFactory

            self.collection_factory = CollectionFactory(session=self)
Esempio n. 2
0
    def setUp(self):
        super(CollectionFactoryTestCase, self).setUp()
        self.session = Session(FakeSession(TestCoreService()))
        self.test_dirs = [
            os.path.join(os.path.dirname(__file__), 'test_data')
        ]
        self.test_loader = ResourceJSONLoader(self.test_dirs)
        self.cd = CollectionDetails(
            self.session,
            'test',
            'PipelineCollection',
            loader=self.test_loader
        )
        self.cf = CollectionFactory(
            session=self.session,
            loader=self.test_loader
        )

        # Fake in the class.
        self.session.cache.set_resource('test', 'Pipeline', FakePipeResource)
Esempio n. 3
0
class Session(object):
    """
    Stores all the state for a given ``kotocore`` session.

    Can dynamically create all the various ``Connection`` classes.

    Usage::

        >>> from kotocore.session import Session
        >>> session = Session()
        >>> sqs_conn = session.connect_to('sqs', region_name='us-west-2')

    """

    cache_class = ServiceCache

    def __init__(self, session=None, connection_factory=None, resource_factory=None, collection_factory=None):
        """
        Creates a ``Session`` instance.

        :param session: (Optional) Custom instantiated ``botocore`` instance.
            Useful if you have specific needs. If not present, a default
            ``Session`` will be created.
        :type session: <botocore.session.Session> instance

        :param connection_factory: (Optional) Specifies a custom
            ``ConnectionFactory`` to be used. Useful if you need to change how
            ``Connection`` objects are constructed by the session.
        :type connection_factory: <kotocore.connection.ConnectionFactory>
            instance

        :param resource_factory: (Optional) Specifies a custom
            ``ResourceFactory`` to be used. Useful if you need to change how
            ``Resource`` objects are constructed by the session.
        :type resource_factory: <kotocore.resources.ResourceFactory>
            instance

        :param collection_factory: (Optional) Specifies a custom
            ``CollectionFactory`` to be used. Useful if you need to change how
            ``Collection`` objects are constructed by the session.
        :type collection_factory: <kotocore.collections.CollectionFactory>
            instance
        """
        super(Session, self).__init__()
        self.core_session = session
        self.connection_factory = connection_factory
        self.resource_factory = resource_factory
        self.collection_factory = collection_factory

        self.cache = self.cache_class()

        if not self.core_session:
            self.core_session = botocore.session.get_session()

        self.core_session.user_agent_name = USER_AGENT_NAME
        self.core_session.user_agent_version = USER_AGENT_VERSION

        if not self.connection_factory:
            from kotocore.connection import ConnectionFactory

            self.connection_factory = ConnectionFactory(session=self)

        if not self.resource_factory:
            from kotocore.resources import ResourceFactory

            self.resource_factory = ResourceFactory(session=self)

        if not self.collection_factory:
            from kotocore.collections import CollectionFactory

            self.collection_factory = CollectionFactory(session=self)

    def get_connection(self, service_name):
        """
        Returns a ``Connection`` **class** for a given service.

        :param service_name: A string that specifies the name of the desired
            service. Ex. ``sqs``, ``sns``, ``dynamodb``, etc.
        :type service_name: string

        :rtype: <kotocore.connection.Connection subclass>
        """
        try:
            return self.cache.get_connection(service_name)
        except NotCached:
            pass

        # We didn't find it. Construct it.
        new_class = self.connection_factory.construct_for(service_name)
        self.cache.set_connection(service_name, new_class)
        return new_class

    def get_resource(self, service_name, resource_name, base_class=None):
        """
        Returns a ``Resource`` **class** for a given service.

        :param service_name: A string that specifies the name of the desired
            service. Ex. ``sqs``, ``sns``, ``dynamodb``, etc.
        :type service_name: string

        :param resource_name: A string that specifies the name of the desired
            class. Ex. ``Queue``, ``Notification``, ``Table``, etc.
        :type resource_name: string

        :param base_class: (Optional) The base class of the object. Prevents
            "magically" loading the wrong class (one with a different base).
        :type base_class: class

        :rtype: <kotocore.resources.Resource subclass>
        """
        try:
            return self.cache.get_resource(service_name, resource_name, base_class=base_class)
        except NotCached:
            pass

        # We didn't find it. Construct it.
        new_class = self.resource_factory.construct_for(service_name, resource_name, base_class=base_class)
        self.cache.set_resource(service_name, resource_name, new_class)
        return new_class

    def get_collection(self, service_name, collection_name, base_class=None):
        """
        Returns a ``Collection`` **class** for a given service.

        :param service_name: A string that specifies the name of the desired
            service. Ex. ``sqs``, ``sns``, ``dynamodb``, etc.
        :type service_name: string

        :param collection_name: A string that specifies the name of the desired
            class. Ex. ``QueueCollection``, ``NotificationCollection``,
            ``TableCollection``, etc.
        :type collection_name: string

        :param base_class: (Optional) The base class of the object. Prevents
            "magically" loading the wrong class (one with a different base).
        :type base_class: class

        :rtype: <kotocore.collections.Collection subclass>
        """
        try:
            return self.cache.get_collection(service_name, collection_name, base_class=base_class)
        except NotCached:
            pass

        # We didn't find it. Construct it.
        new_class = self.collection_factory.construct_for(service_name, collection_name, base_class=base_class)
        self.cache.set_collection(service_name, collection_name, new_class)
        return new_class

    def connect_to(self, service_name, **kwargs):
        """
        Shortcut method to make instantiating the ``Connection`` classes
        easier.

        Forwards ``**kwargs`` like region, keys, etc. on to the constructor.

        :param service_name: A string that specifies the name of the desired
            service. Ex. ``sqs``, ``sns``, ``dynamodb``, etc.
        :type service_name: string

        :rtype: <kotocore.connection.Connection> instance
        """
        service_class = self.get_connection(service_name)
        return service_class.connect_to(**kwargs)

    def get_core_service(self, service_name):
        """
        Returns a ``botocore.service.Service``.

        Mostly an abstraction for the ``*Connection`` objects to get what
        they need for introspection.

        :param service_name: A string that specifies the name of the desired
            service. Ex. ``sqs``, ``sns``, ``dynamodb``, etc.
        :type service_name: string

        :rtype: <botocore.service.Service subclass>
        """
        return self.core_session.get_service(service_name)
Esempio n. 4
0
class CollectionFactoryTestCase(unittest.TestCase):
    def setUp(self):
        super(CollectionFactoryTestCase, self).setUp()
        self.session = Session(FakeSession(TestCoreService()))
        self.test_dirs = [
            os.path.join(os.path.dirname(__file__), 'test_data')
        ]
        self.test_loader = ResourceJSONLoader(self.test_dirs)
        self.cd = CollectionDetails(
            self.session,
            'test',
            'PipelineCollection',
            loader=self.test_loader
        )
        self.cf = CollectionFactory(
            session=self.session,
            loader=self.test_loader
        )

        # Fake in the class.
        self.session.cache.set_resource('test', 'Pipeline', FakePipeResource)

    def test_init(self):
        self.assertEqual(self.cf.session, self.session)
        self.assertTrue(isinstance(self.cf.loader, ResourceJSONLoader))
        self.assertEqual(self.cf.base_collection_class, Collection)
        self.assertEqual(self.cf.details_class, CollectionDetails)

        # Test overrides (invalid for actual usage).
        import kotocore
        cf = CollectionFactory(
            loader=False,
            base_collection_class=PipeCollection,
            details_class=True
        )
        self.assertEqual(cf.session, kotocore.session)
        self.assertEqual(cf.loader, False)
        self.assertEqual(cf.base_collection_class, PipeCollection)
        self.assertEqual(cf.details_class, True)

    def test_build_class_name(self):
        self.assertEqual(
            self.cf._build_class_name('PipelineCollection'),
            'PipelineCollection'
        )
        self.assertEqual(
            self.cf._build_class_name('TestName'),
            'TestName'
        )

    def test_build_methods(self):
        attrs = self.cf._build_methods(self.cd)
        self.assertEqual(len(attrs), 3)
        self.assertTrue('create' in attrs)
        self.assertTrue('each' in attrs)
        self.assertTrue('test_role' in attrs)

    def test_create_operation_method(self):
        class StubbyCollection(Collection):
            pass

        class StubbyResource(Resource):
            _details = ResourceDetails(
                self.session,
                'test',
                'Pipeline',
                loader=self.test_loader
            )

        op_method = self.cf._create_operation_method('create', {
            "api_name": "CreatePipeline"
        })
        self.assertEqual(op_method.__name__, 'create')
        self.assertEqual(op_method.__doc__, DEFAULT_DOCSTRING)

        # Assign it & call it.
        StubbyCollection._details = self.cd
        StubbyCollection.create = op_method
        StubbyCollection.change_resource(StubbyResource)
        sr = StubbyCollection(connection=FakeConn())
        fake_pipe = sr.create()
        self.assertEqual(fake_pipe.id, '1872baf45')
        self.assertEqual(fake_pipe.title, 'A pipe')

        # Make sure an exception is raised when the underlying connection
        # doesn't have an analogous method.
        sr = StubbyCollection(connection=OopsConn())

        with self.assertRaises(NoSuchMethod):
            fake_pipe = sr.create()

    def test_construct_for(self):
        col_class = self.cf.construct_for('test', 'PipelineCollection')