Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

elg

Package Overview
Dependencies
Maintainers
2
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

elg - npm Package Compare versions

Comparing version
0.4.19
to
0.4.20
+164
elg/cli/local_installation_docker.py
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}';
"""
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.
+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

@@ -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.

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

@@ -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)

@@ -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()

@@ -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"]:

@@ -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):

@@ -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)

@@ -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()

@@ -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")

@@ -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 @@

@@ -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,

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

@@ -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).

@@ -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",