Esempio n. 1
0
    def __init__(self,
            prefix="", app=None, name=None,
            resources=None, parser_cache=None,
            compresser=True,
            http_cache=None, pagination=False,
            access_Control_Allow_Origin=None, access_Control_Allow_Methods=None,
            logger=None,
            auto_parse=True
        ):
        self.logger = None
        self.retriever = None
        self.setLogger(logger)

        if not resources:
            resources = list()

        # Set up endpoints with cache system
        if parser_cache:
            Text.CACHE_CLASS = parser_cache
            self.retriever = NautilusRetriever(resources, pagination=pagination, cache=parser_cache, logger=self.logger, auto_parse=auto_parse)
        else:
            self.retriever = NautilusRetriever(resources, pagination=pagination, auto_parse=auto_parse)
        self.retriever.resolver.TEXT_CLASS = Text

        self.app = app
        self.name = name
        self.prefix = prefix
        self.blueprint = None

        self.Access_Control_Allow_Methods = access_Control_Allow_Methods
        if not self.Access_Control_Allow_Methods:
            self.Access_Control_Allow_Methods = FlaskNautilus.Access_Control_Allow_Methods
        self.Access_Control_Allow_Origin = access_Control_Allow_Origin
        if not self.Access_Control_Allow_Origin:
            self.Access_Control_Allow_Origin = FlaskNautilus.Access_Control_Allow_Origin

        self.__http_cache = http_cache

        self.__compresser = False

        if self.name is None:
            self.name = __name__

        if self.app:
            self.init_app(app=app, compresser=compresser)
Esempio n. 2
0
 def setUp(self):
     self.endpoint = NautilusRetriever(["./tests/test_data/farsiLit"])
Esempio n. 3
0
class ResponseTest(TestCase):
    def setUp(self):
        self.endpoint = NautilusRetriever(["./tests/test_data/farsiLit"])

    def test_with_get_capabilities(self):
        response = self.endpoint.getCapabilities(category="translation", output=MY_CAPYTAIN)
        ti = TextInventory(resource=response)
        self.assertEqual(
            len(ti["urn:cts:farsiLit:hafez.divan"].texts), 2,
            "Asserts that only two texts have been added to the TI"
        )
        self.assertEqual(
            ti["urn:cts:farsiLit:hafez.divan.perseus-eng1"].lang, "eng",
            "Asserts that text have lang"
        )
        response = self.endpoint.getCapabilities(category="edition", output=MY_CAPYTAIN)
        ti = TextInventory(resource=response)
        self.assertEqual(
            len(ti["urn:cts:farsiLit:hafez.divan"].texts), 1,
            "Asserts that only one text has been added to the TI"
        )
        self.assertEqual(
            ti["urn:cts:farsiLit:hafez.divan.perseus-far1"].lang, "fa",
            "Asserts that text have lang"
        )

    def test_with_get_capabilities_cts_response(self):
        response = self.endpoint.getCapabilities(category="translation", output=XML)
        self.assertIn(
            "<requestFilters>category=translation</requestFilters>", response,
            "Filters should be listed"
        )
        ti = TextInventory(resource=response)
        self.assertEqual(
            len(ti["urn:cts:farsiLit:hafez.divan"].texts), 2,
            "Asserts that only two texts has been added to the TI"
        )

    def test_get_passage_complete_urn(self):
        """ Test Get Passage """
        response, metadata = self.endpoint.getPassage("urn:cts:farsiLit:hafez.divan.perseus-eng1:1.1.1.1", output=MY_CAPYTAIN)
        self.assertEqual(
            response.text(),
            "Ho ! Saki, pass around and offer the bowl (of love for God) : ### ",
            "It should be possible to retrieve text"
        )

    def test_get_passage_partial_urn(self):
        """ Test Get Passage """
        response, metadata = self.endpoint.getPassage("urn:cts:farsiLit:hafez.divan:1.1.1.1", output=MY_CAPYTAIN)
        self.assertEqual(
            response.text(),
            "الا یا ایها الساقی ادر کاسا و ناولها ### ",
            "It should be possible to retrieve text from edition without version"
        )

    def test_get_passage_formatted(self):
        response = self.endpoint.getPassage("urn:cts:farsiLit:hafez.divan:1.1.1.1", output=XML)
        p = Passage(resource=xmlparser(response), urn="urn:cts:farsiLit:hafez.divan:1.1.1.1")
        """
        self.assertEqual(
            p.text(),
            "الا یا ایها الساقی ادر کاسا و ناولها ###",
            "API Response should be parsable by MyCapytain Library"
        )
        """

    def test_get_passage_plus_formatted(self):
        response = self.endpoint.getPassagePlus("urn:cts:farsiLit:hafez.divan:1.1.1.2", output=XML)
        parsed_response = Passage(resource=xmlparser(response), urn="urn:cts:farsiLit:hafez.divan:1.1.1.2")
        self.assertEqual(
            parsed_response.text().strip(),
            "که عشق آسان نمود اول ولی افتاد مشکل‌ها ***",
            "API Response should be parsable by MyCapytain Library"
        )
        self.assertIn(
            "<prev><urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.1.1</urn></prev>", response,
            "Previous URN should be found"
        )
        self.assertIn(
            "<next><urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.2.1</urn></next>", response,
            "Next URN should be found"
        )

    def test_get_valid_reff(self):
        """ With reference """
        response = self.endpoint.getValidReff("urn:cts:farsiLit:hafez.divan:1.1", output=XML)
        self.assertIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.1</urn>", response,
            "First URN should be found"
        )
        self.assertNotIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.2.1</urn>", response,
            "First URN should be found"
        )

    def test_get_valid_reff_simple(self):
        """ Without reference """
        response = self.endpoint.getValidReff("urn:cts:farsiLit:hafez.divan", output=XML)
        self.assertIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1</urn>", response,
            "First URN should be found"
        )
        self.assertNotIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1</urn>", response,
            "First URN should be found"
        )

        response = self.endpoint.getValidReff("urn:cts:farsiLit:hafez.divan", level=4, output=XML)
        self.assertIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.1.2</urn>", response,
            "First URN should be found"
        )
        self.assertNotIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1</urn>", response,
            "First URN should be found"
        )

        response = self.endpoint.getValidReff(
            "urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.1.1-1.1.2.1",
            level=4,
            output=XML
        )
        self.assertIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.1.1</urn>", response,
            "First URN should be found"
        )
        self.assertIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.1.2</urn>", response,
            "First URN should be found"
        )
        self.assertIn(
            "<urn>urn:cts:farsiLit:hafez.divan.perseus-far1:1.1.2.1</urn>", response,
            "First URN should be found"
        )
    """
Esempio n. 4
0
class FlaskNautilus(object):
    """ Initiate the class

    :param prefix: Prefix on which to install the extension
    :param app: Application on which to register
    :param name: Name to use for the blueprint
    :param resources: List of directory to feed the inventory
    :type resources: list(str)
    :param logger: Logging handler.
    :type logger: logging
    :param parser_cache: Cache object
    :type parser_cache: BaseCache
    :param http_cache: HTTP Cache should be a FlaskCache object
    :param auto_parse: Parses on first execution the resources given to build inventory. Not recommended for production

    :cvar ROUTES: List of triple length tuples
    :cvar Access_Control_Allow_Methods: Dictionary with route name and allowed methods over CORS
    :cvar Access_Control_Allow_Origin: Dictionary with route name and allowed host over CORS or "*"
    :cvar LoggingHandler: Logging handler to be set for the blueprint
    :ivar logger: Logging handler
    :type logger: logging
    :ivar retriever: CapiTainS Retriever
    """
    ROUTES = [
        ('/', "r_dispatcher", ["GET"])
    ]
    Access_Control_Allow_Methods = {
        "r_dispatcher": "OPTIONS, GET"
    }
    Access_Control_Allow_Origin = "*"
    LoggingHandler = logging.StreamHandler

    def __init__(self,
            prefix="", app=None, name=None,
            resources=None, parser_cache=None,
            compresser=True,
            http_cache=None, pagination=False,
            access_Control_Allow_Origin=None, access_Control_Allow_Methods=None,
            logger=None,
            auto_parse=True
        ):
        self.logger = None
        self.retriever = None
        self.setLogger(logger)

        if not resources:
            resources = list()

        # Set up endpoints with cache system
        if parser_cache:
            Text.CACHE_CLASS = parser_cache
            self.retriever = NautilusRetriever(resources, pagination=pagination, cache=parser_cache, logger=self.logger, auto_parse=auto_parse)
        else:
            self.retriever = NautilusRetriever(resources, pagination=pagination, auto_parse=auto_parse)
        self.retriever.resolver.TEXT_CLASS = Text

        self.app = app
        self.name = name
        self.prefix = prefix
        self.blueprint = None

        self.Access_Control_Allow_Methods = access_Control_Allow_Methods
        if not self.Access_Control_Allow_Methods:
            self.Access_Control_Allow_Methods = FlaskNautilus.Access_Control_Allow_Methods
        self.Access_Control_Allow_Origin = access_Control_Allow_Origin
        if not self.Access_Control_Allow_Origin:
            self.Access_Control_Allow_Origin = FlaskNautilus.Access_Control_Allow_Origin

        self.__http_cache = http_cache

        self.__compresser = False

        if self.name is None:
            self.name = __name__

        if self.app:
            self.init_app(app=app, compresser=compresser)

    def setLogger(self, logger):
        """ Set up the Logger for the application

        :param logger: logging.Logger object
        :return: Logger instance
        """
        self.logger = logger
        if not logger:
            self.logger = logging.getLogger("capitains_nautilus")
        else:
            self.logger = self.logger.getLogger("capitains_nautilus")
        formatter = logging.Formatter("[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s")
        stream = FlaskNautilus.LoggingHandler()
        stream.setLevel(logging.INFO)
        stream.setFormatter(formatter)
        self.logger.addHandler(stream)

        if self.retriever:
            self.retriever.logger = self.logger
            self.retriever.resolver.logger = self.logger

        return self.logger

    def init_app(self, app, compresser=False):
        """ Initiate the extension on the application

        :param app: Flask Application
        :return: Blueprint for Flask Nautilus registered in app
        :rtype: Blueprint
        """

        if not self.app:
            self.app = app

        if not self.__http_cache:
            self.__http_cache = Cache(config={'CACHE_TYPE': 'simple'})

        self.init_blueprint()

        if compresser:
            self.__compresser = Compress(app)

        return self.blueprint

    def init_blueprint(self):
        """ Properly generates the blueprint, registering routes and filters and connecting the app and the blueprint

        :return: Blueprint of the extension
        :rtype: Blueprint
        """
        self.blueprint = Blueprint(
            self.name,
            self.name,
            url_prefix=self.prefix
        )

        # Register routes
        for url, name, methods in FlaskNautilus.ROUTES:
            self.blueprint.add_url_rule(
                url,
                view_func=self.view(name),
                endpoint=name[2:],
                methods=methods
            )

        self.app.register_blueprint(self.blueprint)
        return self.blueprint

    def view(self, function_name):
        """ Builds response according to a function name

        :param function_name: Route name / function name
        :return: Function
        """
        if isinstance(self.Access_Control_Allow_Origin, dict):
            d = {
                "Access-Control-Allow-Origin": self.Access_Control_Allow_Origin[function_name],
                "Access-Control-Allow-Methods": self.Access_Control_Allow_Methods[function_name]
            }
        else:
            d = {
                "Access-Control-Allow-Origin": self.Access_Control_Allow_Origin,
                "Access-Control-Allow-Methods": self.Access_Control_Allow_Methods[function_name]
            }

        def r(*x, **y):
            val = list(getattr(self, function_name)(*x, **y))
            val[2].update(d)
            return tuple(val)
        return r

    def r_dispatcher(self):
        """ Actual main route of CTS APIs. Transfer typical requests through the ?request=REQUESTNAME route

        :return: Response
        """
        _request = request.args.get("request", None)
        if not _request:
            return "This request does not exist", 404, dict()  # Should maybe return documentation on top of 404 ?
        elif _request.lower() == "getcapabilities":
            return self._r_GetCapabilities(
                urn=request.args.get("urn", None),
                inv=request.args.get("inv", None)
            )
        elif _request.lower() == "getpassage":
            return self._r_GetPassage(
                urn=request.args.get("urn", None),
                inv=request.args.get("inv", None)
            )
        elif _request.lower() == "getpassageplus":
            return self._r_GetPassagePlus(
                urn=request.args.get("urn", None),
                inv=request.args.get("inv", None)
            )
        elif _request.lower() == "getlabel":
            return self._r_GetLabel(
                urn=request.args.get("urn", None),
                inv=request.args.get("inv", None)
            )
        elif _request.lower() == "getfirsturn":
            return self._r_GetFirstUrn(
                urn=request.args.get("urn", None),
                inv=request.args.get("inv", None)
            )
        elif _request.lower() == "getprevnexturn":
            return self._r_GetPrevNext(
                urn=request.args.get("urn", None),
                inv=request.args.get("inv", None)
            )
        elif _request.lower() == "getvalidreff":
            return self._r_GetValidReff(
                urn=request.args.get("urn", None),
                inv=request.args.get("inv", None),
                level=request.args.get("level", 1, type=int)
            )
        return "This request does not exist", 404, ""  # Should maybe return documentation on top of 404 ?

    def _r_GetCapabilities(self, urn=None, inv=None):
        """ Provisional route for GetCapabilities request

        :param urn: URN to filter the resource
        :param inv: Inventory Identifier
        :return: GetCapabilities response
        """
        return self.retriever.getCapabilities(inventory=inv, urn=urn).strip(), 200, {"content-type": "application/xml"}

    def _r_GetPassage(self, urn, inv):
        """ Provisional route for GetPassage request

        :param urn: URN to filter the resource
        :param inv: Inventory Identifier
        :return: GetPassage response
        """
        return self.retriever.getPassage(inventory=inv, urn=urn).strip(), 200, {"content-type": "application/xml"}

    def _r_GetPassagePlus(self, urn, inv):
        """ Provisional route for GetPassagePlus request

        :param urn: URN to filter the resource
        :param inv: Inventory Identifier
        :return: GetPassagePlus response
        """
        return self.retriever.getPassagePlus(inventory=inv, urn=urn).strip(), 200, {"content-type": "application/xml"}

    def _r_GetValidReff(self, urn, inv, level):
        """ Provisional route for GetValidReff request

        :param urn: URN to filter the resource
        :param inv: Inventory Identifier
        :return: GetValidReff response
        """
        return self.retriever.getValidReff(inventory=inv, urn=urn, level=level).strip(), 200, {"content-type": "application/xml"}

    def _r_GetPrevNext(self, urn, inv):
        """ Provisional route for GetPrevNext request

        :param urn: URN to filter the resource
        :param inv: Inventory Identifier
        :return: GetPrevNext response
        """
        return self.retriever.getPrevNextUrn(inventory=inv, urn=urn).strip(), 200, {"content-type": "application/xml"}

    def _r_GetFirstUrn(self, urn, inv):
        """ Provisional route for GetFirstUrn request

        :param urn: URN to filter the resource
        :param inv: Inventory Identifier
        :return: GetFirstUrn response
        """
        return self.retriever.getFirstUrn(inventory=inv, urn=urn).strip(), 200, {"content-type": "application/xml"}

    def _r_GetLabel(self, urn, inv):
        """ Provisional route for GetLabel request

        :param urn: URN to filter the resource
        :param inv: Inventory Identifier
        :return: GetLabel response
        """
        return self.retriever.getLabel(inventory=inv, urn=urn).strip(), 200, {"content-type": "application/xml"}