elg
Advanced tools
| import sys | ||
| import traceback | ||
| from argparse import ArgumentParser | ||
| from typing import Any, List | ||
| from loguru import logger | ||
| from . import BaseELGCommand | ||
| def local_installation_command_factory(args): | ||
| return LocalInstallationDockerCommand( | ||
| image=args.image, | ||
| execution_location=args.execution_location, | ||
| sidecar_image=args.sidecar_image, | ||
| name=args.name, | ||
| full_name=args.full_name, | ||
| gui=args.gui, | ||
| gui_image=args.gui_image, | ||
| gui_port=args.gui_port, | ||
| gui_path=args.gui_path, | ||
| folder=args.folder, | ||
| expose_port=args.expose_port, | ||
| ) | ||
| class LocalInstallationDockerCommand(BaseELGCommand): | ||
| @staticmethod | ||
| def register_subcommand(parser: ArgumentParser): | ||
| local_installation_parser = parser.add_parser( | ||
| "docker", | ||
| description="Create a Docker compose file to deploy an ELG compatible Docker image locally", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--image", | ||
| type=str, | ||
| required=True, | ||
| help="name of the Docker image", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--execution_location", | ||
| type=str, | ||
| required=True, | ||
| help="endpoint of the Docker image where the service can be executed", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--sidecar_image", | ||
| type=str, | ||
| default="", | ||
| required=False, | ||
| help="name of the sidecare Docker image", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--name", | ||
| type=str, | ||
| default=None, | ||
| required=False, | ||
| help="name of the service to use for the REST server", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--full_name", | ||
| type=str, | ||
| default=None, | ||
| required=False, | ||
| help="name of the service to display in the GUI", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--folder", | ||
| type=str, | ||
| default="./elg_local_installation/", | ||
| required=False, | ||
| help="path to the folder where to save the Docker compose file", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--gui", | ||
| default=False, | ||
| action="store_true", | ||
| required=False, | ||
| help="use to use the GUI", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--expose_port", | ||
| type=int, | ||
| default=8080, | ||
| required=False, | ||
| help="port used to publish to the host", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--gui_image", | ||
| type=str, | ||
| default="registry.gitlab.com/european-language-grid/usfd/gui-ie:latest", | ||
| required=False, | ||
| help="docker image of the GUI", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--gui_path", | ||
| type=str, | ||
| default="", | ||
| required=False, | ||
| help="path to the GUI", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--gui_port", | ||
| type=int, | ||
| default=80, | ||
| required=False, | ||
| help="port used by the GUI docker image", | ||
| ) | ||
| local_installation_parser.set_defaults(func=local_installation_command_factory) | ||
| def __init__( | ||
| self, | ||
| image: str, | ||
| execution_location: str, | ||
| folder: str = "./", | ||
| gui: bool = False, | ||
| expose_port: int = 8080, | ||
| sidecar_image: str = "", | ||
| name: str = None, | ||
| full_name: str = None, | ||
| gui_image: str = "registry.gitlab.com/european-language-grid/usfd/gui-ie:latest", | ||
| gui_port: int = 80, | ||
| gui_path: str = "", | ||
| record: Any = {}, | ||
| ): | ||
| self._folder = folder | ||
| self._gui = gui | ||
| self._expose_port = expose_port | ||
| self._image = image | ||
| self._execution_location = execution_location | ||
| self._sidecar_image = sidecar_image | ||
| self._name = name | ||
| self._full_name = full_name | ||
| self._gui_image = gui_image | ||
| self._gui_port = gui_port | ||
| self._gui_path = gui_path | ||
| self._record = record | ||
| def run(self): | ||
| from ..local_installation import (LocalInstallation, | ||
| LTServiceLocalInstallation) | ||
| try: | ||
| ltservice = LTServiceLocalInstallation.from_docker_image( | ||
| image=self._image, | ||
| execution_location=self._execution_location, | ||
| sidecar_image=self._sidecar_image, | ||
| name=self._name, | ||
| full_name=self._full_name, | ||
| gui=self._gui, | ||
| gui_image=self._gui_image, | ||
| gui_port=self._gui_port, | ||
| gui_path=self._gui_path, | ||
| record=self._record, | ||
| ) | ||
| LocalInstallation(ltservices=[ltservice]).create_docker_compose( | ||
| expose_port=self._expose_port, | ||
| path=self._folder, | ||
| ) | ||
| except Exception as e: | ||
| logger.error(f"Error during the creation of the Docker compose file - {e}") | ||
| traceback.print_exc() | ||
| sys.exit(1) |
| import sys | ||
| import traceback | ||
| from argparse import ArgumentParser | ||
| from typing import List | ||
| from loguru import logger | ||
| from . import BaseELGCommand | ||
| def local_installation_command_factory(args): | ||
| return LocalInstallationIdsCommand( | ||
| ids=args.ids, | ||
| folder=args.folder, | ||
| no_gui=args.no_gui, | ||
| domain=args.domain, | ||
| not_use_cache=args.not_use_cache, | ||
| cache_dir=args.cache_dir, | ||
| expose_port=args.expose_port, | ||
| gui_images=args.gui_images, | ||
| gui_ports=args.gui_ports, | ||
| ) | ||
| class LocalInstallationIdsCommand(BaseELGCommand): | ||
| @staticmethod | ||
| def register_subcommand(parser: ArgumentParser): | ||
| local_installation_parser = parser.add_parser( | ||
| "ids", | ||
| description="Create a Docker compose file to deploy a set of ELG services locally from their ids", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "ids", | ||
| type=int, | ||
| nargs="+", | ||
| help="ID of the service to deploy locally.", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--folder", | ||
| type=str, | ||
| default="./elg_local_installation/", | ||
| required=False, | ||
| help="path to the folder where to save the Docker compose file", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--no_gui", | ||
| default=False, | ||
| action="store_true", | ||
| required=False, | ||
| help="use to not use the GUI", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--domain", | ||
| type=str, | ||
| default="live", | ||
| required=False, | ||
| help="ELG domain you want to use", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--not_use_cache", | ||
| default=False, | ||
| action="store_true", | ||
| required=False, | ||
| help="use to not use cache", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--cache_dir", | ||
| type=str, | ||
| default="~/.cache/elg", | ||
| required=False, | ||
| help="path to the cache directory", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--expose_port", | ||
| type=int, | ||
| default=8080, | ||
| required=False, | ||
| help="port used to publish to the host", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--gui_images", | ||
| type=str, | ||
| nargs="+", | ||
| default="registry.gitlab.com/european-language-grid/usfd/gui-ie:latest", | ||
| required=False, | ||
| help="docker image of the GUI", | ||
| ) | ||
| local_installation_parser.add_argument( | ||
| "--gui_ports", | ||
| type=int, | ||
| nargs="+", | ||
| default=80, | ||
| required=False, | ||
| help="port used by the GUI docker image", | ||
| ) | ||
| local_installation_parser.set_defaults(func=local_installation_command_factory) | ||
| def __init__( | ||
| self, | ||
| ids: List[int] = None, | ||
| folder: str = "./", | ||
| no_gui: bool = False, | ||
| domain: str = "live", | ||
| not_use_cache: bool = False, | ||
| cache_dir: str = "~/.cache/elg", | ||
| expose_port: int = 8080, | ||
| gui_images: str = "registry.gitlab.com/european-language-grid/usfd/gui-ie:latest", | ||
| gui_ports: int = 80, | ||
| ): | ||
| self._ids = ids | ||
| self._folder = folder | ||
| self._gui = not no_gui | ||
| self._domain = domain | ||
| self._use_cache = not not_use_cache | ||
| self._cache_dir = cache_dir | ||
| self._expose_port = expose_port | ||
| self._gui_images = gui_images | ||
| self._gui_ports = gui_ports | ||
| def run(self): | ||
| from ..local_installation import LocalInstallation | ||
| try: | ||
| LocalInstallation.from_ids( | ||
| ids=self._ids, | ||
| gui=self._gui, | ||
| gui_images=self._gui_images, | ||
| gui_ports=self._gui_ports, | ||
| domain=self._domain, | ||
| use_cache=self._use_cache, | ||
| cache_dir=self._cache_dir, | ||
| ).create_docker_compose( | ||
| expose_port=self._expose_port, | ||
| path=self._folder, | ||
| ) | ||
| except Exception as e: | ||
| logger.error(f"Error during the creation of the Docker compose file - {e}") | ||
| traceback.print_exc() | ||
| sys.exit(1) |
| import sys | ||
| from argparse import ArgumentParser | ||
| from loguru import logger | ||
| from . import BaseELGCommand | ||
| from .local_installation_docker import LocalInstallationDockerCommand | ||
| from .local_installation_ids import LocalInstallationIdsCommand | ||
| class LocalInstallationCommand(BaseELGCommand): | ||
| @staticmethod | ||
| def register_subcommand(parser: ArgumentParser): | ||
| commands_parser = parser.add_parser("local-installation") | ||
| subparsers = commands_parser.add_subparsers( | ||
| title="ELG Local Installation CLI", | ||
| description="Create a Docker compose file to deploy a set of ELG services locally.", | ||
| help="For more information about a command, run: `elg local-installation <command> --help`", | ||
| ) | ||
| LocalInstallationIdsCommand.register_subcommand(subparsers) | ||
| LocalInstallationDockerCommand.register_subcommand(subparsers) |
| import json | ||
| import random | ||
| import re | ||
| import string | ||
| from pathlib import Path | ||
| from typing import Any, List, Union | ||
| from urllib.parse import urlparse | ||
| from loguru import logger | ||
| from .entity import Entity, MetadataRecordObj | ||
| from .utils import get_information | ||
| from .utils.local_installation import (DEFAULT_CONF_TEMPLATE, DOCKER_COMPOSE, | ||
| EXPOSE_PORT_CONFIG, FRONTEND, GUI, | ||
| GUI_CONF_TEMPLATE, | ||
| HTML_INDEX_HTML_TEMPLATE, | ||
| HTML_INDEX_IFRAME, HTML_INDEX_SCRIPT, | ||
| LTSERVICE, LTSERVICE_URL, | ||
| LTSERVICE_WITH_SIDECAR) | ||
| def name_from_image(image): | ||
| return re.sub("[^0-9a-zA-Z]+", "_", image)[-60:] | ||
| def random_name(length: int = 10): | ||
| return "".join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length)) | ||
| class LTServiceLocalInstallation: | ||
| def __init__( | ||
| self, | ||
| id: int, | ||
| image: str, | ||
| sidecar_image: str, | ||
| name: str, | ||
| full_name: str, | ||
| port: int, | ||
| path: str, | ||
| gui: bool, | ||
| gui_image: str, | ||
| gui_port: int, | ||
| gui_path: str, | ||
| record: Any, | ||
| ): | ||
| self.id = id | ||
| self.image = image | ||
| self.sidecar_image = sidecar_image | ||
| self.name = name | ||
| self.full_name = full_name | ||
| self.port = port | ||
| self.path = path | ||
| self.gui = gui | ||
| self.gui_image = gui_image | ||
| self.gui_port = gui_port | ||
| self.gui_path = gui_path | ||
| self.record = record | ||
| self.ltservice = ( | ||
| LTSERVICE.format(LTSERVICE_NAME=self.name, LTSERVICE_IMAGE=self.image) | ||
| if self.sidecar_image is None or self.sidecar_image == "" | ||
| else LTSERVICE_WITH_SIDECAR.format( | ||
| LTSERVICE_NAME=self.name, | ||
| LTSERVICE_IMAGE=self.image, | ||
| SIDECAR_IMAGE=self.sidecar_image, | ||
| ) | ||
| ) | ||
| self.url = LTSERVICE_URL.format( | ||
| LTSERVICE_NAME=self.name, | ||
| LTSERVICE_PORT=self.port, | ||
| LTSERVICE_PATH=self.path, | ||
| ) | ||
| if self.gui: | ||
| self.iframe = HTML_INDEX_IFRAME.format( | ||
| LTSERVICE_ID=self.id, | ||
| LTSERVICE_FULL_NAME=self.full_name, | ||
| LTSERVICE_NAME=self.name, | ||
| ) | ||
| self.script = HTML_INDEX_SCRIPT.format( | ||
| LTSERVICE_NAME=self.name, | ||
| GUI_NAME=name_from_image(self.gui_image), | ||
| GUI_PATH=self.gui_path, | ||
| ) | ||
| @classmethod | ||
| def from_id( | ||
| cls, | ||
| id: int, | ||
| gui: bool = True, | ||
| gui_image: str = "registry.gitlab.com/european-language-grid/usfd/gui-ie:latest", | ||
| gui_port: int = 80, | ||
| domain: str = "live", | ||
| use_cache: bool = True, | ||
| cache_dir: str = "~/.cache/elg", | ||
| ): | ||
| entity = Entity.from_id(id=id, domain=domain, use_cache=use_cache, cache_dir=cache_dir) | ||
| software_distribution = get_information( | ||
| id=entity.id, | ||
| obj=entity.record, | ||
| infos=["described_entity", "lr_subclass", "software_distribution"], | ||
| )[0] | ||
| if software_distribution.get("private_resource"): | ||
| logger.warning( | ||
| "Service [{id}] is private. It cannot be deployed locally.", | ||
| id=entity.id, | ||
| ) | ||
| # bypass for UDPipe English to make some tests | ||
| if entity.id != 423: | ||
| return None | ||
| sidecar_image = software_distribution.get("service_adapter_download_location") | ||
| image = software_distribution.get("docker_download_location") | ||
| execution_location = urlparse(software_distribution.get("execution_location")) | ||
| name = get_information( | ||
| id=entity.id, | ||
| obj=entity.record, | ||
| infos=["service_info", "elg_execution_location_sync"], | ||
| ).split("/")[-1] | ||
| full_name = entity.resource_name | ||
| port = execution_location.port | ||
| path = execution_location.path | ||
| gui_path = get_information(id=entity.id, obj=entity.record, infos=["service_info", "elg_gui_url"],).split( | ||
| "/" | ||
| )[-1] | ||
| record = entity.record | ||
| return cls( | ||
| id=id, | ||
| image=image, | ||
| sidecar_image=sidecar_image, | ||
| name=name, | ||
| full_name=full_name, | ||
| port=port, | ||
| path=path, | ||
| gui=gui, | ||
| gui_image=gui_image, | ||
| gui_port=gui_port, | ||
| gui_path=gui_path, | ||
| record=record, | ||
| ) | ||
| @classmethod | ||
| def from_docker_image( | ||
| cls, | ||
| image: str, | ||
| execution_location: str, | ||
| sidecar_image: str = "", | ||
| name: str = None, | ||
| full_name: str = None, | ||
| gui: bool = False, | ||
| gui_image: str = "registry.gitlab.com/european-language-grid/usfd/gui-ie:latest", | ||
| gui_port: int = 80, | ||
| gui_path: str = "", | ||
| record: Any = {}, | ||
| ): | ||
| name = name if name else random_name() | ||
| full_name = full_name if full_name else f"ELG Service from Docker {name}" | ||
| execution_location = urlparse(execution_location) | ||
| port = execution_location.port | ||
| port = int(port) if port is not None else 80 | ||
| path = execution_location.path | ||
| return cls( | ||
| id=-1, | ||
| image=image, | ||
| sidecar_image=sidecar_image, | ||
| name=name, | ||
| full_name=full_name, | ||
| port=port, | ||
| path=path, | ||
| gui=gui, | ||
| gui_image=gui_image, | ||
| gui_port=gui_port, | ||
| gui_path=gui_path, | ||
| record=MetadataRecordObj(record), | ||
| ) | ||
| class LocalInstallation: | ||
| def __init__(self, ltservices: List[LTServiceLocalInstallation]): | ||
| self.ltservices = ltservices | ||
| @classmethod | ||
| def from_ids( | ||
| cls, | ||
| ids: List[int], | ||
| gui: bool = True, | ||
| gui_images: Union[str, List[str]] = "registry.gitlab.com/european-language-grid/usfd/gui-ie:latest", | ||
| gui_ports: Union[int, List[int]] = 80, | ||
| domain: str = "live", | ||
| use_cache: bool = True, | ||
| cache_dir: str = "~/.cache/elg", | ||
| ): | ||
| if isinstance(gui_images, list) and len(gui_images) == 1: | ||
| gui_images = gui_images[0] | ||
| if isinstance(gui_images, str): | ||
| gui_images = [gui_images for _ in range(len(ids))] | ||
| elif isinstance(gui_images, list): | ||
| if len(gui_images) != len(ids): | ||
| raise ValueError( | ||
| f"You provided {len(gui_images)} GUI images and {len(ids)} service ids. These two numbers must be equal." | ||
| ) | ||
| else: | ||
| raise ValueError("gui_images must be a string or a list of strings.") | ||
| if isinstance(gui_ports, list) and len(gui_ports) == 1: | ||
| gui_ports = gui_ports[0] | ||
| if isinstance(gui_ports, int): | ||
| gui_ports = [gui_ports for _ in range(len(ids))] | ||
| elif isinstance(gui_ports, list): | ||
| if len(gui_ports) != len(ids): | ||
| raise ValueError( | ||
| f"You provided {len(gui_ports)} GUI ports and {len(ids)} service ids. These two numbers must be equal." | ||
| ) | ||
| else: | ||
| raise ValueError("gui_ports must be a int or a list of ints.") | ||
| assert len(ids) == len(gui_images) | ||
| assert len(ids) == len(gui_ports) | ||
| ltservices = [ | ||
| LTServiceLocalInstallation.from_id( | ||
| id=ltservice_id, | ||
| gui=gui, | ||
| gui_image=gui_image, | ||
| gui_port=gui_port, | ||
| domain=domain, | ||
| use_cache=use_cache, | ||
| cache_dir=cache_dir, | ||
| ) | ||
| for ltservice_id, gui_image, gui_port in zip(ids, gui_images, gui_ports) | ||
| ] | ||
| ltservices = [ltservice for ltservice in ltservices if ltservice] | ||
| return cls(ltservices=ltservices) | ||
| def create_docker_compose( | ||
| self, | ||
| expose_port: int = 8080, | ||
| path: str = "./elg_local_installation/", | ||
| ): | ||
| if self.ltservices == []: | ||
| logger.warning("None of the services can be deployed locally. Therefore, no files will be created.") | ||
| return | ||
| guis_image_port = list( | ||
| set([(ltservice.gui_image, ltservice.gui_port) for ltservice in self.ltservices if ltservice.gui]) | ||
| ) | ||
| gui = len(guis_image_port) > 0 | ||
| if gui: | ||
| guis = [ | ||
| GUI.format(GUI_NAME=name_from_image(gui_image), GUI_IMAGE=gui_image) | ||
| for gui_image, _ in guis_image_port | ||
| ] | ||
| frontend = FRONTEND.format(EXPOSE_PORT=expose_port) | ||
| gui_conf_templates = [ | ||
| GUI_CONF_TEMPLATE.format(GUI_NAME=name_from_image(gui_image), GUI_PORT=gui_port) | ||
| for gui_image, gui_port in guis_image_port | ||
| ] | ||
| default_conf_template = DEFAULT_CONF_TEMPLATE.format(GUIS="\n\n".join(gui_conf_templates)) | ||
| html_index_html_template = HTML_INDEX_HTML_TEMPLATE.format( | ||
| IFRAMES="\n".join([ltservice.iframe for ltservice in self.ltservices if ltservice.gui]), | ||
| SCRIPTS="\n".join([ltservice.script for ltservice in self.ltservices if ltservice.gui]), | ||
| ) | ||
| docker_compose = DOCKER_COMPOSE.format( | ||
| LTSERVICES="\n\n".join([ltservice.ltservice for ltservice in self.ltservices]), | ||
| LTSERVICES_URL="\n".join([ltservice.url for ltservice in self.ltservices]), | ||
| EXPOSE_PORT=expose_port, | ||
| EXPOSE_PORT_CONFIG=EXPOSE_PORT_CONFIG.format(EXPOSE_PORT=expose_port) if not gui else "", | ||
| EXECUTION_PATH="" if not gui else "/execution", | ||
| GUIS="\n".join(guis) if gui else "", | ||
| FRONTEND=frontend if gui else "", | ||
| ) | ||
| path = Path(path) | ||
| path.mkdir(parents=True, exist_ok=True) | ||
| with open(path / "docker-compose.yml", "w") as f: | ||
| f.write(docker_compose) | ||
| if gui: | ||
| nginx_conf_path = Path(path / "nginx-conf") | ||
| nginx_conf_path.mkdir(parents=True, exist_ok=True) | ||
| html_path = Path(nginx_conf_path / "html") | ||
| html_path.mkdir(parents=True, exist_ok=True) | ||
| with open(nginx_conf_path / "default.conf.template", "w") as f: | ||
| f.write(default_conf_template) | ||
| with open(html_path / "index.html.template", "w") as f: | ||
| f.write(html_index_html_template) | ||
| records_path = Path(nginx_conf_path / "records") | ||
| records_path.mkdir(parents=True, exist_ok=True) | ||
| for ltservice in self.ltservices: | ||
| if ltservice.gui: | ||
| with open(records_path / f"{ltservice.name}.json", "w") as f: | ||
| json.dump(ltservice.record, f, default=lambda o: o.__dict__, indent=4) | ||
| logger.info( | ||
| "The Docker compose file has been created [{path}]. Run `docker-compose up` from the folder of Docker compose file to start the ELG REST server and the service.s.", | ||
| path=path / "docker-compose.yml", | ||
| ) | ||
| return |
| DOCKER_COMPOSE = """\ | ||
| version: "3.7" | ||
| services: | ||
| {LTSERVICES} | ||
| restserver: | ||
| image: registry.gitlab.com/european-language-grid/ilsp/elg-lt-service-execution-all:production-reactive | ||
| command: | ||
| - "--logging.level.elg.ltserviceexecution.api=WARN" | ||
| {LTSERVICES_URL} | ||
| - "--elg.base.url=http://localhost:{EXPOSE_PORT}{EXECUTION_PATH}" | ||
| {EXPOSE_PORT_CONFIG} | ||
| restart: always | ||
| {GUIS} | ||
| {FRONTEND} | ||
| """ | ||
| EXPOSE_PORT_CONFIG = """\ | ||
| ports: | ||
| - "{EXPOSE_PORT}:8080" | ||
| """ | ||
| LTSERVICE = """\ | ||
| {LTSERVICE_NAME}: | ||
| image: "{LTSERVICE_IMAGE}" | ||
| restart: always\ | ||
| """ | ||
| LTSERVICE_WITH_SIDECAR = """\ | ||
| {LTSERVICE_NAME}: | ||
| image: "{LTSERVICE_IMAGE}" | ||
| restart: always | ||
| sidecar: | ||
| image: "{SIDECAR_IMAGE}" | ||
| network_mode: "service:{LTSERVICE_NAME}" | ||
| depends_on: | ||
| - {LTSERVICE_NAME} | ||
| """ | ||
| LTSERVICE_URL = ( | ||
| ' - "--elg.ltservices.staticServices.{LTSERVICE_NAME}=http://{LTSERVICE_NAME}:{LTSERVICE_PORT}{LTSERVICE_PATH}"' | ||
| ) | ||
| GUI = """\ | ||
| {GUI_NAME}: | ||
| image: "{GUI_IMAGE}" | ||
| restart: always | ||
| """ | ||
| FRONTEND = """\ | ||
| frontend: | ||
| image: "nginx:alpine" | ||
| ports: | ||
| - "{EXPOSE_PORT}:80" | ||
| volumes: | ||
| - type: bind | ||
| source: ./nginx-conf | ||
| target: /etc/nginx/templates | ||
| restart: always | ||
| """ | ||
| DEFAULT_CONF_TEMPLATE = """\ | ||
| log_format upstream_logging '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request upstream_response_time $upstream_response_time msec $msec request_time $request_time'; | ||
| server {{ | ||
| listen 80; | ||
| server_name localhost; | ||
| location / {{ | ||
| alias /etc/nginx/conf.d/html/; | ||
| index index.html index.htm; | ||
| }} | ||
| location ~ \.json {{ | ||
| root /etc/nginx/templates/records; | ||
| }} | ||
| location /i18n/ {{ | ||
| proxy_pass https://live.european-language-grid.eu/i18n/; | ||
| }} | ||
| location /execution/ {{ | ||
| access_log /dev/stdout upstream_logging; | ||
| proxy_pass http://restserver:8080/; | ||
| }} | ||
| {GUIS} | ||
| # redirect server error pages to the static page /50x.html | ||
| # | ||
| error_page 500 502 503 504 /50x.html; | ||
| location = /50x.html {{ | ||
| root /usr/share/nginx/html; | ||
| }} | ||
| }} | ||
| """ | ||
| GUI_CONF_TEMPLATE = """\ | ||
| location /{GUI_NAME}/ {{ | ||
| access_log /dev/stdout upstream_logging; | ||
| proxy_pass http://{GUI_NAME}:{GUI_PORT}/; | ||
| }} | ||
| """ | ||
| HTML_INDEX_HTML_TEMPLATE = """\ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <title>ELG Local Installation</title> | ||
| <link rel="preconnect" href="https://fonts.googleapis.com"> | ||
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | ||
| <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Display:wght@600&display=swap" rel="stylesheet"> | ||
| <style> | ||
| body {{ | ||
| font-family: 'Noto Sans Display', sans-serif; | ||
| background-color: #f8f4ed; | ||
| display: flex; | ||
| flex-direction: column; | ||
| }} | ||
| body > * {{ | ||
| margin-inline: auto; | ||
| }} | ||
| h1,h2 {{ | ||
| font-weight: 600; | ||
| width: 900px; | ||
| text-align: center; | ||
| }} | ||
| h1 {{ | ||
| font-size: 32px; | ||
| margin-bottom: 32px; | ||
| }} | ||
| h2 {{ | ||
| font-size: 24px; | ||
| }} | ||
| iframe {{ | ||
| margin-bottom: 32px; | ||
| background-color: white; | ||
| }} | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <h1>European Language Grid<br/>Local Installation</h1> | ||
| {IFRAMES} | ||
| <script> | ||
| {SCRIPTS} | ||
| </script> | ||
| </body> | ||
| </html> | ||
| """ | ||
| HTML_INDEX_IFRAME = """\ | ||
| <h2>[{LTSERVICE_ID}] {LTSERVICE_FULL_NAME}</h2> | ||
| <iframe width="900" height="500" id="{LTSERVICE_NAME}" src="about:blank"></iframe> | ||
| """ | ||
| HTML_INDEX_SCRIPT = """\ | ||
| window.addEventListener('message', function (e) {{ | ||
| document.getElementById('{LTSERVICE_NAME}').contentWindow.postMessage(JSON.stringify({{ | ||
| "StyleCss":" ", | ||
| "ServiceUrl":window.location.origin+"/execution/async/process/{LTSERVICE_NAME}", | ||
| "ApiRecordUrl":window.location.origin+"/{LTSERVICE_NAME}.json" | ||
| }}), window.location.origin); | ||
| }}, false); | ||
| document.getElementById('{LTSERVICE_NAME}').src = '/{GUI_NAME}/{GUI_PATH}'; | ||
| """ |
+21
| MIT License | ||
| Copyright (c) 2020 Malte | ||
| 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. |
| Metadata-Version: 2.1 | ||
| Name: elg | ||
| Version: 0.4.19 | ||
| Version: 0.4.20 | ||
| Summary: Use the European Language Grid in your Python projects | ||
@@ -13,3 +13,4 @@ Home-page: https://gitlab.com/european-language-grid/platform/python-client | ||
| To have more information about the Python SDK, please look at the documentation: [https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/PythonSDK.html](https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/PythonSDK.html). | ||
| To have more information about the Python SDK, please look at the documentation: [https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/GettingStarted.html](https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/GettingStarted.html). | ||
| Keywords: tools,sdk,language technology,europe,european,nlp | ||
@@ -16,0 +17,0 @@ Platform: UNKNOWN |
@@ -0,1 +1,2 @@ | ||
| LICENSE | ||
| README.md | ||
@@ -11,2 +12,3 @@ setup.cfg | ||
| elg/flask_service.py | ||
| elg/local_installation.py | ||
| elg/pipeline.py | ||
@@ -28,2 +30,5 @@ elg/provider.py | ||
| elg/cli/info.py | ||
| elg/cli/local_installation.py | ||
| elg/cli/local_installation_docker.py | ||
| elg/cli/local_installation_ids.py | ||
| elg/cli/run.py | ||
@@ -58,2 +63,3 @@ elg/cli/search.py | ||
| elg/utils/json_encoder.py | ||
| elg/utils/local_installation.py | ||
| elg/utils/utils.py |
+1
-1
@@ -1,2 +0,2 @@ | ||
| __version__ = "0.4.19" | ||
| __version__ = "0.4.20" | ||
@@ -3,0 +3,0 @@ import importlib.util |
@@ -12,3 +12,3 @@ import hashlib | ||
| from .utils import get_domain | ||
| from .utils.errors import (AuthenticationException, | ||
| from .utils.errors import (AuthenticationException, DomainException, | ||
| RefreshTokenExpirationException, | ||
@@ -203,3 +203,7 @@ catch_requests_error, ensure_response_ok) | ||
| raise AuthenticationException() | ||
| data = {"grant_type": "refresh_token", "client_id": self.client, "refresh_token": self.refresh_token} | ||
| data = { | ||
| "grant_type": "refresh_token", | ||
| "client_id": self.client, | ||
| "refresh_token": self.refresh_token, | ||
| } | ||
| self._requesting_oauth_token(data=data) | ||
@@ -267,3 +271,10 @@ | ||
| def _authenticate(self, auth_object: Authentication, auth_file: str, scope: str, use_cache: str, cache_dir: str): | ||
| def _authenticate( | ||
| self, | ||
| auth_object: Authentication, | ||
| auth_file: str, | ||
| scope: str, | ||
| use_cache: str, | ||
| cache_dir: str, | ||
| ): | ||
| """ | ||
@@ -270,0 +281,0 @@ Method to authenticate. |
+10
-3
| import concurrent.futures as cf | ||
| import time | ||
| from typing import Callable, List, Union | ||
| from typing import Callable, List, Tuple, Union | ||
@@ -227,3 +227,3 @@ import pandas as pd | ||
| @staticmethod | ||
| def _call_service(service: Service, **kwargs) -> (dict, float): | ||
| def _call_service(service: Service, **kwargs) -> Tuple[dict, float]: | ||
| """ | ||
@@ -262,3 +262,10 @@ Internal method to call a service | ||
| def _append_run(self, service: Service, request_input: str, run_idx: int, result: str, response_time: float): | ||
| def _append_run( | ||
| self, | ||
| service: Service, | ||
| request_input: str, | ||
| run_idx: int, | ||
| result: str, | ||
| response_time: float, | ||
| ): | ||
| """ | ||
@@ -265,0 +272,0 @@ Internal method to append the result of a run. Used by the Benchmark call function |
+26
-8
@@ -103,2 +103,4 @@ import urllib | ||
| page: int = 1, | ||
| elg_compatible_service: bool = None, | ||
| elg_hosted_data: bool = None, | ||
| ): | ||
@@ -112,4 +114,4 @@ """Internal method to send one search request to the API. | ||
| resource (str, optional): type of the language resource. Only used when the entity is set to | ||
| 'LanguageResource'. Can be 'Tool/Service', 'Lexical/Conceptual resource', 'Corpus', or | ||
| 'Language description'. Defaults to None. | ||
| 'LanguageResource'. Can be 'Tool/Service', 'Lexical/Conceptual resource', 'Corpus', 'Model', 'Grammar', or | ||
| 'Uncategorized Language Description'. Defaults to None. | ||
| function (str, optional): type of the function of the service. Only used when resource set to 'Tool/Service'. | ||
@@ -122,2 +124,4 @@ Defaults to None. | ||
| page (int, optional): page number. Defaults to 1. | ||
| elg_compatible_service (bool, optional): Filter ELG compatible services. Defaults to None. | ||
| elg_hosted_data (bool, optional): Filter ELG hosted data. Defaults to None. | ||
@@ -145,2 +149,6 @@ Returns: | ||
| queries.append(("licence__term", license)) | ||
| if elg_compatible_service: | ||
| queries.append(("elg_integrated_services_and_data__term", "ELG compatible services")) | ||
| if elg_hosted_data: | ||
| queries.append(("elg_integrated_services_and_data__term", "ELG hosted data")) | ||
| response = self._get(path=path, queries=queries, json=True) | ||
@@ -151,3 +159,3 @@ return [Entity.from_search_result(result=result, domain=self.domain) for result in response["results"]] | ||
| self, | ||
| entity: str = "LanguageResource", | ||
| entity: str = None, | ||
| search: str = None, | ||
@@ -159,2 +167,4 @@ resource: str = None, | ||
| limit: int = 100, | ||
| elg_compatible_service: bool = False, | ||
| elg_hosted_data: bool = False, | ||
| ): | ||
@@ -165,7 +175,7 @@ """Generator to iterate through search results via the API. | ||
| entity (str, optional): type of the entity to search. Can be 'LanguageResource', 'Organization', or | ||
| 'Project'. Defaults to "LanguageResource". | ||
| 'Project'. Defaults to None. | ||
| search (str, optional): terms to use for the search request. Defaults to None. | ||
| resource (str, optional): type of the language resource. Only used when the entity is set to | ||
| 'LanguageResource'. Can be 'Tool/Service', 'Lexical/Conceptual resource', 'Corpus', or | ||
| 'Language description'. Defaults to None. | ||
| 'LanguageResource'. Can be 'Tool/Service', 'Lexical/Conceptual resource', 'Corpus', 'Model', 'Grammar', or | ||
| 'Uncategorized Language Description'. Defaults to None. | ||
| function (str, optional): type of the function of the service. Only used when resource set to 'Tool/Service'. | ||
@@ -178,2 +188,4 @@ Defaults to None. | ||
| limit (int, optional): limit number of results. Defaults to 100. | ||
| elg_compatible_service (bool, optional): Filter ELG compatible services. Defaults to False. | ||
| elg_hosted_data (bool, optional): Filter ELG hosted data. Defaults to False. | ||
@@ -198,4 +210,4 @@ Yields: | ||
| """ | ||
| # results = [] | ||
| finished = False | ||
| if elg_compatible_service and elg_hosted_data: | ||
| raise ValueError("elg_compatible_service and elg_hosted_data cannot be both True.") | ||
| page = 1 | ||
@@ -214,2 +226,4 @@ attempts_remaining = 100 | ||
| page=page, | ||
| elg_compatible_service=elg_compatible_service, | ||
| elg_hosted_data=elg_hosted_data, | ||
| ) | ||
@@ -246,2 +260,4 @@ except ConnectException as e: | ||
| license: str = None, | ||
| elg_compatible_service: bool = None, | ||
| elg_hosted_data: bool = None, | ||
| ): | ||
@@ -261,2 +277,4 @@ """ | ||
| page=page, | ||
| elg_compatible_service=elg_compatible_service, | ||
| elg_hosted_data=elg_hosted_data, | ||
| ) | ||
@@ -263,0 +281,0 @@ self._display_entities(results) |
+2
-0
@@ -11,2 +11,3 @@ import argparse | ||
| from .info import InfoCommand | ||
| from .local_installation import LocalInstallationCommand | ||
| from .run import RunCommand | ||
@@ -31,2 +32,3 @@ from .search import SearchCommand | ||
| DockerCommand.register_subcommand(commands_parser) | ||
| LocalInstallationCommand.register_subcommand(commands_parser) | ||
@@ -33,0 +35,0 @@ args = parser.parse_args() |
+5
-3
@@ -168,5 +168,7 @@ from pathlib import Path | ||
| if not response.ok: | ||
| print(not_downloadable) | ||
| return None | ||
| print(f"Please, visit the licence of this corpus distribution by clicking: {elg_licence_url}\n") | ||
| # print(not_downloadable) | ||
| # return None | ||
| print(f"This corpus is distributed with the following licence: {self.licence.name}\n") | ||
| else: | ||
| print(f"Please, visit the licence of this corpus distribution by clicking: {elg_licence_url}\n") | ||
| accept = input("Do you accept the licence terms: (yes/[no]): ") | ||
@@ -173,0 +175,0 @@ if accept not in ["yes", "Yes", "y", "Y"]: |
+0
-2
@@ -84,3 +84,2 @@ from textwrap import TextWrapper | ||
| size: int = 0, | ||
| elg_compatible_service: bool = None, | ||
| **kwargs, | ||
@@ -113,3 +112,2 @@ ): | ||
| self.record = MetadataRecordObj(record) | ||
| self.elg_compatible_service = elg_compatible_service | ||
@@ -116,0 +114,0 @@ def __str__(self): |
+14
-9
@@ -21,3 +21,3 @@ import inspect | ||
| from .model import (AudioRequest, Failure, Progress, ResponseObject, | ||
| from .model import (AudioRequest, Failure, Progress, Request, ResponseObject, | ||
| StandardMessages, StructuredTextRequest, TextRequest) | ||
@@ -119,8 +119,15 @@ from .utils.docker import COPY_FOLDER, DOCKERFILE, ENTRYPOINT_FLASK, ENV_FLASK | ||
| if request_type in ["audio", "text", "structuredText"]: | ||
| if request_type == "audio": | ||
| request = AudioRequest(**data) | ||
| elif request_type == "text": | ||
| request = TextRequest(**data) | ||
| else: | ||
| request = StructuredTextRequest(**data) | ||
| try: | ||
| if request_type == "audio": | ||
| request = AudioRequest(**data) | ||
| elif request_type == "text": | ||
| request = TextRequest(**data) | ||
| else: | ||
| request = StructuredTextRequest(**data) | ||
| except Exception as e: | ||
| response = Failure(errors=[StandardMessages.generate_elg_request_invalid()]) | ||
| else: | ||
| response = Failure(errors=[StandardMessages.generate_elg_request_invalid()]) | ||
| if isinstance(request, Request): | ||
| logger.trace("Call with the input: {request}", request=request) | ||
@@ -134,4 +141,2 @@ try: | ||
| ) | ||
| else: | ||
| response = Failure(errors=[StandardMessages.generate_elg_request_invalid()]) | ||
@@ -138,0 +143,0 @@ if isinstance(response, Failure): |
@@ -1,2 +0,2 @@ | ||
| from typing import List | ||
| from typing import Any, List | ||
@@ -19,1 +19,6 @@ from pydantic import BaseModel | ||
| alias_generator = to_camel | ||
| def json(self, **kwargs: Any) -> str: | ||
| if "exclude_none" not in kwargs.keys(): | ||
| kwargs["exclude_none"] = True | ||
| return super().json(**kwargs) |
@@ -0,1 +1,3 @@ | ||
| from typing import Any | ||
| from pydantic import BaseModel | ||
@@ -20,1 +22,6 @@ | ||
| alias_generator = to_camel | ||
| def json(self, **kwargs: Any) -> str: | ||
| if "exclude_none" not in kwargs.keys(): | ||
| kwargs["exclude_none"] = True | ||
| return super().json(**kwargs) |
@@ -0,1 +1,3 @@ | ||
| from typing import Any | ||
| from pydantic import BaseModel | ||
@@ -29,1 +31,6 @@ | ||
| return " - ".join([f"{k}: {v}" for k, v in self.dict().items() if v is not None]) | ||
| def json(self, **kwargs: Any) -> str: | ||
| if "exclude_none" not in kwargs.keys(): | ||
| kwargs["exclude_none"] = True | ||
| return super().json(**kwargs) |
@@ -1,2 +0,2 @@ | ||
| from typing import List | ||
| from typing import Any, List | ||
@@ -30,1 +30,6 @@ from pydantic import BaseModel | ||
| alias_generator = to_camel | ||
| def json(self, **kwargs: Any) -> str: | ||
| if "exclude_none" not in kwargs.keys(): | ||
| kwargs["exclude_none"] = True | ||
| return super().json(**kwargs) |
@@ -17,132 +17,263 @@ from .StatusMessage import StatusMessage | ||
| @classmethod | ||
| def generate_elg_request_invalid(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_invalid(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.invalid""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.invalid" | ||
| text = {"en": "Invalid request message", "es": "Mensaje de petici\u00f3n inv\u00e1lido"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Invalid request message" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_missing(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_missing(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.missing""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.missing" | ||
| text = {"en": "No request provided in message", "es": "Ninguna petici\u00f3n provista en el mensaje"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "No request provided in message" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_type_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_type_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.type.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.type.unsupported" | ||
| text = { | ||
| "en": "Request type {0} not supported by this service", | ||
| "es": "Tipo de petici\u00f3n {0} no soportada por este servicio", | ||
| } | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Request type {0} not supported by this service" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_property_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_property_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.property.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.property.unsupported" | ||
| text = {"en": "Unsupported property {0} in request", "es": "Propiedad no soportada {0} en la petici\u00f3n"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Unsupported property {0} in request" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_too_large(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_too_large(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.too.large""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.too.large" | ||
| text = {"en": "Request size too large", "es": "Tama\u00f1o de petici\u00f3n demasiado grande"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Request size too large" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_text_mimetype_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_text_mimetype_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.text.mimeType.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.text.mimeType.unsupported" | ||
| text = { | ||
| "en": "MIME type {0} not supported by this service", | ||
| "es": "Tipo MIME {0} no soportado por este servicio", | ||
| } | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "MIME type {0} not supported by this service" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_audio_format_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_audio_format_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.audio.format.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.audio.format.unsupported" | ||
| text = { | ||
| "en": "Audio format {0} not supported by this service", | ||
| "es": "Formato de audio {0} no soportado por este servicio", | ||
| } | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Audio format {0} not supported by this service" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_audio_samplerate_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_audio_samplerate_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.audio.sampleRate.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.audio.sampleRate.unsupported" | ||
| text = { | ||
| "en": "Audio sample rate {0} not supported by this service", | ||
| "es": "Tasa de sampleo de audio {0} no soportado por este servicio", | ||
| } | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Audio sample rate {0} not supported by this service" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_structuredtext_property_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_request_image_format_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.image.format.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.image.format.unsupported" | ||
| text = "Image format {0} not supported by this service" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_request_structuredtext_property_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.request.structuredText.property.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.request.structuredText.property.unsupported" | ||
| text = { | ||
| "en": 'Unsupported property {0} in "texts" of structuredText request', | ||
| "es": 'Propiedad no soportada {0} en "texts" de la petici\u00f3n structuredText', | ||
| } | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = 'Unsupported property {0} in "texts" of structuredText request' | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_response_property_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_response_invalid(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.response.invalid""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.response.invalid" | ||
| text = "Invalid response message" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_response_type_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.response.type.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.response.type.unsupported" | ||
| text = "Response type {0} not supported" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_response_property_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.response.property.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.response.property.unsupported" | ||
| text = {"en": "Unsupported property {0} in response", "es": "Propiedad no soportada {0} en la respuesta"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Unsupported property {0} in response" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_response_texts_property_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_response_texts_property_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.response.texts.property.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.response.texts.property.unsupported" | ||
| text = { | ||
| "en": 'Unsupported property {0} in "texts" of texts response', | ||
| "es": 'Propiedad no soportada {0} en "texts" de la respuesta de textos', | ||
| } | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = 'Unsupported property {0} in "texts" of texts response' | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_response_classification_property_unsupported(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_response_classification_property_unsupported(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.response.classification.property.unsupported""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.response.classification.property.unsupported" | ||
| text = { | ||
| "en": 'Unsupported property {0} in "classes" of classification response', | ||
| "es": 'Propiedad no soportada {0} en "classes" de la respuesta de clasificaci\u00f3n', | ||
| } | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = 'Unsupported property {0} in "classes" of classification response' | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_response_invalid(cls, params=[], detail={}, lang="en"): | ||
| """Generate StatusMessage for code: elg.response.invalid""" | ||
| code = "elg.response.invalid" | ||
| text = {"en": "Invalid response message", "es": "Mensaje de respuesta inv\u00e1lido"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| def generate_elg_service_not_found(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.service.not.found""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.service.not.found" | ||
| text = "Service {0} not found" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_response_type_unsupported(cls, params=[], detail={}, lang="en"): | ||
| """Generate StatusMessage for code: elg.response.type.unsupported""" | ||
| code = "elg.response.type.unsupported" | ||
| text = {"en": "Response type {0} not supported", "es": "Tipo de respuesta {0} no soportada"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| def generate_elg_async_call_not_found(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.async.call.not.found""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.async.call.not.found" | ||
| text = "Async call {0} not found" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_service_not_found(cls, params=[], detail={}, lang="en"): | ||
| """Generate StatusMessage for code: elg.service.not.found""" | ||
| code = "elg.service.not.found" | ||
| text = {"en": "Service {0} not found", "es": "Servicio {0} no se encontr\u00f3"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| def generate_elg_permissions_quotaexceeded(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.permissions.quotaExceeded""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.permissions.quotaExceeded" | ||
| text = "Authorized quota exceeded" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_service_internalerror(cls, params=[], detail={}, lang="en"): | ||
| def generate_elg_permissions_accessdenied(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.permissions.accessDenied""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.permissions.accessDenied" | ||
| text = "Access denied" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_permissions_accessmanagererror(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.permissions.accessManagerError""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.permissions.accessManagerError" | ||
| text = "Error in access manager: {0}" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_file_not_found(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.file.not.found""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.file.not.found" | ||
| text = "File {0} not found" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_file_expired(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.file.expired""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.file.expired" | ||
| text = "Requested file {0} no longer available" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_upload_too_large(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.upload.too.large""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.upload.too.large" | ||
| text = "Upload too large" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) | ||
| @classmethod | ||
| def generate_elg_service_internalerror(cls, params=[], detail={}, **kwargs): | ||
| """Generate StatusMessage for code: elg.service.internalError""" | ||
| if "lang" in kwargs.keys(): | ||
| print( | ||
| "Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language." | ||
| ) | ||
| code = "elg.service.internalError" | ||
| text = {"en": "Internal error during processing: {0}", "es": "Error interno durante el procesamiento: {0}"} | ||
| return StatusMessage(code=code, text=text[lang], params=params, detail=detail) | ||
| text = "Internal error during processing: {0}" | ||
| return StatusMessage(code=code, text=text, params=params, detail=detail) |
@@ -1,2 +0,2 @@ | ||
| from typing import Dict, List | ||
| from typing import Any, Dict, List | ||
@@ -32,1 +32,6 @@ from pydantic import BaseModel | ||
| alias_generator = to_camel | ||
| def json(self, **kwargs: Any) -> str: | ||
| if "exclude_none" not in kwargs.keys(): | ||
| kwargs["exclude_none"] = True | ||
| return super().json(**kwargs) |
+22
-13
@@ -36,25 +36,25 @@ import inspect | ||
| @staticmethod | ||
| def InternalError(text): | ||
| return ProcessingError(500, StandardMessages.generate_elg_service_internalerror(params=[text])) | ||
| def InternalError(text, detail={}): | ||
| return ProcessingError(500, StandardMessages.generate_elg_service_internalerror(params=[text], detail=detail)) | ||
| @staticmethod | ||
| def InvalidRequest(): | ||
| return ProcessingError(400, StandardMessages.generate_elg_request_invalid()) | ||
| def InvalidRequest(detail={}): | ||
| return ProcessingError(400, StandardMessages.generate_elg_request_invalid(detail=detail)) | ||
| @staticmethod | ||
| def TooLarge(): | ||
| return ProcessingError(413, StandardMessages.generate_elg_request_too_large()) | ||
| def TooLarge(detail={}): | ||
| return ProcessingError(413, StandardMessages.generate_elg_request_too_large(detail=detail)) | ||
| @staticmethod | ||
| def UnsupportedMime(mime): | ||
| def UnsupportedMime(mime, detail={}): | ||
| return ProcessingError( | ||
| 400, | ||
| StandardMessages.generate_elg_request_text_mimetype_unsupported(params=[mime]), | ||
| StandardMessages.generate_elg_request_text_mimetype_unsupported(params=[mime], detail=detail), | ||
| ) | ||
| @staticmethod | ||
| def UnsupportedType(request_type): | ||
| def UnsupportedType(request_type, detail={}): | ||
| return ProcessingError( | ||
| 400, | ||
| StandardMessages.generate_elg_request_type_unsupported(params=[request_type]), | ||
| StandardMessages.generate_elg_request_type_unsupported(params=[request_type], detail=detail), | ||
| ) | ||
@@ -343,7 +343,16 @@ | ||
| if data.get("type") == "audio": | ||
| request = AudioRequest(**data) | ||
| try: | ||
| request = AudioRequest(**data) | ||
| except Exception as e: | ||
| raise ProcessingError.InvalidRequest() | ||
| elif data.get("type") == "text": | ||
| request = TextRequest(**data) | ||
| try: | ||
| request = TextRequest(**data) | ||
| except Exception as e: | ||
| raise ProcessingError.InvalidRequest() | ||
| elif data.get("type") == "structuredText": | ||
| request = StructuredTextRequest(**data) | ||
| try: | ||
| request = StructuredTextRequest(**data) | ||
| except Exception as e: | ||
| raise ProcessingError.InvalidRequest() | ||
| else: | ||
@@ -350,0 +359,0 @@ raise ProcessingError.InvalidRequest() |
+50
-38
@@ -19,3 +19,3 @@ import hashlib | ||
| NeedAuthentication, need_authentication) | ||
| from .entity import Entity | ||
| from .entity import Entity, MetadataRecordObj | ||
| from .model import (AudioRequest, Request, StructuredTextRequest, TextRequest, | ||
@@ -157,3 +157,12 @@ get_response) | ||
| ) | ||
| self._get_elg_execution_location() | ||
| self.elg_execution_location_sync = get_information( | ||
| id=self.id, | ||
| obj=self.record, | ||
| infos=["service_info", "elg_execution_location_sync"], | ||
| ) | ||
| self.elg_execution_location = get_information( | ||
| id=self.id, | ||
| obj=self.record, | ||
| infos=["service_info", "elg_execution_location"], | ||
| ) | ||
@@ -170,2 +179,4 @@ @classmethod | ||
| cache_dir: str = "~/.cache/elg", | ||
| local: bool = False, | ||
| local_domain: str = "http://localhost:8080/execution", | ||
| ): | ||
@@ -211,5 +222,31 @@ """ | ||
| domain = auth_domain | ||
| # Create a dummy Authentication object if local | ||
| if local: | ||
| auth_object = Authentication(domain=local_domain) | ||
| auth_object.expires_time = time.gmtime(time.time() + ONE_HUNDRED_YEARS_IN_SECONDS) | ||
| auth_object.refresh_expires_time = time.gmtime(time.time() + ONE_HUNDRED_YEARS_IN_SECONDS) | ||
| use_cache = False | ||
| cache_dir = None | ||
| # Use "live" domain by default | ||
| domain = get_domain(domain=domain if domain is not None else "live") | ||
| record = get_metadatarecord(id=id, domain=domain, use_cache=use_cache, cache_dir=cache_dir) | ||
| if local: | ||
| record["service_info"]["elg_execution_location_sync"] = ( | ||
| get_information( | ||
| id=id, | ||
| obj=record, | ||
| infos=["service_info", "elg_execution_location_sync"], | ||
| ) | ||
| .replace("/execution", "") | ||
| .replace(domain, local_domain) | ||
| ) | ||
| record["service_info"]["elg_execution_location"] = ( | ||
| get_information( | ||
| id=id, | ||
| obj=record, | ||
| infos=["service_info", "elg_execution_location"], | ||
| ) | ||
| .replace("/execution", "") | ||
| .replace(domain, local_domain) | ||
| ) | ||
| result = map_metadatarecord_to_result(id=id, record=record) | ||
@@ -219,3 +256,3 @@ result["auth_object"] = auth_object | ||
| result["scope"] = scope | ||
| result["domain"] = domain | ||
| result["domain"] = domain if not local else local_domain | ||
| result["use_cache"] = use_cache | ||
@@ -253,3 +290,3 @@ result["cache_dir"] = cache_dir | ||
| """ | ||
| if not entity.elg_compatible_service: | ||
| if not entity.functional_service: | ||
| raise NotElgServiceException(entity.id) | ||
@@ -272,7 +309,6 @@ if entity.record == None: | ||
| @classmethod | ||
| def from_docker_image( | ||
| def from_local_installation( | ||
| cls, | ||
| image: str, | ||
| execution_location: str, | ||
| port: int = 8000, | ||
| name: str, | ||
| local_domain: str = "http://localhost:8080/execution", | ||
| ): | ||
@@ -283,5 +319,4 @@ """ | ||
| Args: | ||
| image (str): name of the Docker image ELG compatible | ||
| execution_location (str): url of the ELG compatible endpoint, e.g., `http://localhost:8000/process`. | ||
| port (int, optional): port to use locally. Defaults to 8000. | ||
| name (str): name of the service. Corresponds to the name of the service in the docker-compose.yml file. | ||
| local_domain (str, optional): endpoint of the LT service execution server deployed locally. Defaults to "http://localhost:8080/execution". | ||
@@ -291,10 +326,2 @@ Returns: | ||
| """ | ||
| execution_location = urlparse(execution_location) | ||
| image_port = execution_location.port | ||
| image_port = int(image_port) if image_port is not None else 80 | ||
| print( | ||
| "To call the service locally, the docker image needs to be running. ", | ||
| f"Please run the following command: `docker run -p {port}:{image_port} {image}`.", | ||
| "When calling the service, you need to set the `sync_mode` parameter to True, otherwise an error will be raised.", | ||
| ) | ||
| auth_object = Authentication(domain="local") | ||
@@ -305,4 +332,4 @@ auth_object.expires_time = time.gmtime(time.time() + ONE_HUNDRED_YEARS_IN_SECONDS) | ||
| "service_info": { | ||
| "elg_execution_location_sync": f"http://127.0.0.1:{port}{execution_location.path}", | ||
| "elg_execution_location": "None", | ||
| "elg_execution_location_sync": f"{local_domain}/process/{name}", | ||
| "elg_execution_location": f"{local_domain}/async/process/{name}", | ||
| } | ||
@@ -312,4 +339,4 @@ } | ||
| "id": 0, | ||
| "resource_name": image, | ||
| "resource_short_name": image, | ||
| "resource_name": name, | ||
| "resource_short_name": name, | ||
| "resource_type": "ToolService", | ||
@@ -344,17 +371,2 @@ "entity_type": None, | ||
| def _get_elg_execution_location(self): | ||
| """ | ||
| Method to get the elg execution location information from the metadata record. | ||
| """ | ||
| self.elg_execution_location_sync = get_information( | ||
| id=self.id, | ||
| obj=self.record, | ||
| infos=["service_info", "elg_execution_location_sync"], | ||
| ) | ||
| self.elg_execution_location = get_information( | ||
| id=self.id, | ||
| obj=self.record, | ||
| infos=["service_info", "elg_execution_location"], | ||
| ) | ||
| @need_authentication() | ||
@@ -361,0 +373,0 @@ def __call__( |
@@ -1,28 +0,23 @@ | ||
| import configparser | ||
| import json | ||
| import requests | ||
| from jproperties import Properties | ||
| """ | ||
| Fairly basic script to generate elg/model/base/StandardMessages. | ||
| Fairly basic script to generate elg/model/base/StandardMessages from the standard messages.properties file in `elg-apis`. | ||
| Left simple to make maintenance/editing easy. | ||
| To run from the root directory of this project: `python elg/utils/generate_standard_messages.py`. | ||
| To run from the root directory of this project: `python elg/utils/_generate_standard_messages.py`. | ||
| Requires modules "requests" (to download the properties file) and "jproperties" (to parse it). | ||
| """ | ||
| config = configparser.RawConfigParser() | ||
| # Don't lower-case the keys | ||
| config.optionxform = lambda x: x | ||
| config.read("elg/model/messages/errors.ini") | ||
| details_dicts = {lang: dict(config.items(lang)) for lang in config.sections()} | ||
| properties_content = requests.get( | ||
| "https://gitlab.com/european-language-grid/platform/elg-apis/-/raw/master/java/src/main/resources/eu/elg/elg-messages.properties" | ||
| ).content | ||
| # Revert the dicts to pass from: | ||
| # "{'es': {1: 'q', 2: 'w'}, 'en': {1: 's', 2: 'r'}}" | ||
| # to | ||
| # "{1: {'es': 'q', 'en: 's'}, 2: {'es: 'w', 'en: 'r'}}" | ||
| keys = list(details_dicts.values())[0].keys() | ||
| details_dicts_reverted = {k: {} for k in keys} | ||
| for lang, d in details_dicts.items(): | ||
| # assert all the dict have the same keys | ||
| assert d.keys() == keys | ||
| for k in keys: | ||
| details_dicts_reverted[k][lang] = d[k] | ||
| props = Properties() | ||
| props.load(properties_content, "utf-8") | ||
| details = {k: v.replace("''", "'") for (k, (v, _)) in props.items()} | ||
| with open("elg/model/base/StandardMessages.py", "w+") as file: | ||
@@ -32,18 +27,22 @@ file.write("from .StatusMessage import StatusMessage\n\n") | ||
| file.write( | ||
| '\n\t"""\n' | ||
| + "\tThis class provides easy access to the standard set of ELG status messages that are provided by default by \n" | ||
| + "\tthe platform and should be fully translated in the ELG user interface. If you use codes other than these \n" | ||
| + "\tstandard ones in your services then you should also try to contribute translations of your messages into as \n" | ||
| + "\tmany languages as possible for the benefit of other ELG users.\n\n" | ||
| "\tImplementation note: This class is auto-generated from elg-messages.properties - to add new message codes you \n" | ||
| + "\tshould edit the property files, then run /utils/generate_standard_messages.py. Do not edit this class directly.\n" | ||
| + '\t"""\n' | ||
| '\n """\n' | ||
| + " This class provides easy access to the standard set of ELG status messages that are provided by default by \n" | ||
| + " the platform and should be fully translated in the ELG user interface. If you use codes other than these \n" | ||
| + " standard ones in your services then you should also try to contribute translations of your messages into as \n" | ||
| + " many languages as possible for the benefit of other ELG users.\n\n" | ||
| " Implementation note: This class is auto-generated from elg-messages.properties - to add new message codes you \n" | ||
| + " should edit the property files, then run /utils/generate_standard_messages.py. Do not edit this class directly.\n" | ||
| + ' """\n' | ||
| ) | ||
| for key in details_dicts_reverted: | ||
| file.write("\n\t@classmethod") | ||
| file.write("\n\tdef generate_" + key.replace(".", "_").lower() + '(cls, params=[], detail={}, lang="en"):') | ||
| file.write('\n\t\t"""Generate StatusMessage for code: ' + key + '"""') | ||
| file.write('\n\t\tcode="' + key + '"') | ||
| file.write("\n\t\ttext=" + json.dumps(details_dicts_reverted[key])) | ||
| file.write("\n\t\treturn StatusMessage(code=code,text=text[lang],params=params,detail=detail)") | ||
| for key in details: | ||
| file.write("\n @classmethod") | ||
| file.write("\n def generate_" + key.replace(".", "_").lower() + "(cls, params=[], detail={}, **kwargs):") | ||
| file.write('\n """Generate StatusMessage for code: ' + key + '"""') | ||
| file.write('\n if "lang" in kwargs.keys():') | ||
| file.write( | ||
| """\n print("Warning: lang is deprecated and will be ignored. The standard message 'text' will be in English, pass it to the i18n resolver to obtain it in another language.")""" | ||
| ) | ||
| file.write("\n code=" + repr(key)) | ||
| file.write("\n text=" + repr(details[key])) | ||
| file.write("\n return StatusMessage(code=code,text=text,params=params,detail=detail)") | ||
| file.write("\n") |
+12
-0
@@ -33,2 +33,14 @@ ENTRYPOINT_FLASK = """\ | ||
| # Many Python libraries used for LT such as nltk, transformers, etc. default to | ||
| # downloading their models from the internet the first time they are accessed. | ||
| # This is a problem for container images, as every run is the "first time" | ||
| # starting from a clean copy of the image. Therefore it is strongly | ||
| # recommended to pre-download any models that your code depends on during the | ||
| # build, so they are cached within the final image. For example: | ||
| # | ||
| # RUN venv/bin/python -m nltk.downloader -d venv/share/nltk_data punkt | ||
| # | ||
| # RUN venv/bin/python -c "from transformers import DistilBertTokenizer" \\ | ||
| # -c "DistilBertTokenizer.from_pretrained('bert-base-uncased')" | ||
| {env} | ||
@@ -35,0 +47,0 @@ |
+109
-93
@@ -121,99 +121,115 @@ import hashlib | ||
| detail = None | ||
| licences = [ | ||
| name | ||
| for terms in list( | ||
| map( | ||
| lambda x: list( | ||
| map( | ||
| lambda x: get_en_value( | ||
| try: | ||
| licences = [ | ||
| name | ||
| for terms in list( | ||
| map( | ||
| lambda x: list( | ||
| map( | ||
| lambda x: get_en_value( | ||
| get_information( | ||
| id, | ||
| x, | ||
| "licence_terms_name", | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| ), | ||
| get_information( | ||
| id, | ||
| x, | ||
| "licence_terms_name", | ||
| "licence_terms", | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| ), | ||
| get_information( | ||
| id, | ||
| x, | ||
| "licence_terms", | ||
| display_and_stat=display_and_stat, | ||
| ), | ||
| ) | ||
| ), | ||
| get_information( | ||
| id, | ||
| described_entity, | ||
| [ | ||
| "lr_subclass", | ||
| "software_distribution" if resource_type == "ToolService" else "dataset_distribution", | ||
| ], | ||
| display_and_stat=display_and_stat, | ||
| ), | ||
| ), | ||
| ) | ||
| ), | ||
| get_information( | ||
| id, | ||
| described_entity, | ||
| [ | ||
| "lr_subclass", | ||
| "software_distribution" if resource_type == "ToolService" else "dataset_distribution", | ||
| ], | ||
| display_and_stat=display_and_stat, | ||
| ), | ||
| ) | ||
| ) | ||
| ) | ||
| for name in terms | ||
| ] | ||
| if resource_type == "ToolService": | ||
| # input_content_resource | ||
| input_content_resource = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "input_content_resource"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| # output_resource | ||
| output_resource = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "output_resource"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| for name in terms | ||
| ] | ||
| except: | ||
| licences = [] | ||
| try: | ||
| if resource_type == "ToolService": | ||
| # input_content_resource | ||
| input_content_resource = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "input_content_resource"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| # output_resource | ||
| output_resource = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "output_resource"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| languages = [] | ||
| for resource in input_content_resource + output_resource: | ||
| try: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, resource, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| except: | ||
| continue | ||
| elif resource_type == "Corpus": | ||
| corpus_media_part = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "corpus_media_part"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| languages = [] | ||
| for media in corpus_media_part: | ||
| try: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, media, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| except: | ||
| continue | ||
| elif resource_type == "LanguageDescription": | ||
| language_description_media_part = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "language_description_media_part"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| languages = [] | ||
| for media in language_description_media_part: | ||
| try: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, media, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| except: | ||
| continue | ||
| elif resource_type == "LexicalConceptualResource": | ||
| lexical_conceptual_resource_media_part = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "lexical_conceptual_resource_media_part"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| languages = [] | ||
| for media in lexical_conceptual_resource_media_part: | ||
| try: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, media, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| except: | ||
| continue | ||
| except: | ||
| languages = [] | ||
| for resource in input_content_resource + output_resource: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, resource, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| elif resource_type == "Corpus": | ||
| corpus_media_part = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "corpus_media_part"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| languages = [] | ||
| for media in corpus_media_part: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, media, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| elif resource_type == "LanguageDescription": | ||
| language_description_media_part = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "language_description_media_part"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| languages = [] | ||
| for media in language_description_media_part: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, media, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| elif resource_type == "LexicalConceptualResource": | ||
| lexical_conceptual_resource_media_part = get_information( | ||
| id, | ||
| described_entity, | ||
| ["lr_subclass", "lexical_conceptual_resource_media_part"], | ||
| display_and_stat=display_and_stat, | ||
| ) | ||
| languages = [] | ||
| for media in lexical_conceptual_resource_media_part: | ||
| languages += [ | ||
| ISO639.LanguageName(l["language_id"]) | ||
| for l in get_information(id, media, "language", display_and_stat=display_and_stat) | ||
| ] | ||
| else: | ||
| raise ValueError(f"Resource type: {resource_type} not implemented yet.") | ||
| country_of_registration = None | ||
@@ -400,4 +416,4 @@ creation_date = get_information(id, record, "metadata_creation_date", display_and_stat=display_and_stat) | ||
| "detail": detail, | ||
| "licences": licences, | ||
| "languages": languages, | ||
| "licences": list(set(licences)), | ||
| "languages": list(set(languages)), | ||
| "country_of_registration": country_of_registration, | ||
@@ -404,0 +420,0 @@ "creation_date": creation_date, |
+3
-2
| Metadata-Version: 2.1 | ||
| Name: elg | ||
| Version: 0.4.19 | ||
| Version: 0.4.20 | ||
| Summary: Use the European Language Grid in your Python projects | ||
@@ -13,3 +13,4 @@ Home-page: https://gitlab.com/european-language-grid/platform/python-client | ||
| To have more information about the Python SDK, please look at the documentation: [https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/PythonSDK.html](https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/PythonSDK.html). | ||
| To have more information about the Python SDK, please look at the documentation: [https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/GettingStarted.html](https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/GettingStarted.html). | ||
| Keywords: tools,sdk,language technology,europe,european,nlp | ||
@@ -16,0 +17,0 @@ Platform: UNKNOWN |
+1
-1
@@ -5,2 +5,2 @@ # European Language Grid Python SDK | ||
| To have more information about the Python SDK, please look at the documentation: [https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/PythonSDK.html](https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/PythonSDK.html). | ||
| To have more information about the Python SDK, please look at the documentation: [https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/GettingStarted.html](https://european-language-grid.readthedocs.io/en/stable/all/A1_PythonSDK/GettingStarted.html). |
+1
-1
@@ -5,3 +5,3 @@ from setuptools import find_packages, setup | ||
| name="elg", | ||
| version="0.4.19", | ||
| version="0.4.20", | ||
| author="ELG Technical Team", | ||
@@ -8,0 +8,0 @@ url="https://gitlab.com/european-language-grid/platform/python-client", |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
299433
15.27%63
10.53%6825
16.25%