Skip to content

Commit 5320cef

Browse files
author
Pedro Crespo
committed
Merge remote-tracking branch 'upstream/master'
2 parents cf6c63a + 062f221 commit 5320cef

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1875
-501
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ run_test:
100100
pytest -v services/apihub/tests
101101
pytest --cov=pytest_docker -v packages/pytest_docker/tests
102102
pytest --cov=s3wrapper -v packages/s3wrapper/tests
103-
pytest --cov=simcore_sdk -v packages/simcore-sdk/tests
103+
pytest --cov=servicelib -v packages/service-library/tests
104104
pytest --cov=simcore_service_webserver -v services/web/server/tests/unit
105105
pytest --cov=simcore_service_webserver -v services/web/server/tests/login
106106
pytest --cov=simcore_service_director -v services/director/tests

api/specs/webserver/v0/openapi.yaml

+38-6
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,25 @@ info:
1111
url: https://github.com/ITISFoundation/osparc-simcore/blob/master/LICENSE
1212
servers:
1313
- description: Development server
14-
url: http://{host}:{port}/v0
14+
url: http://{host}:{port}/{basePath}
1515
variables:
1616
host:
1717
default: 'localhost'
1818
port:
1919
default: '8001'
20+
basePath:
21+
enum:
22+
- v0
23+
default: v0
2024
- description: Production server
21-
url: https://webserver:{port}/v0
25+
url: '{publicUrl}/{basePath}'
2226
variables:
23-
port:
24-
default: '9081'
27+
publicUrl:
28+
default: 'https://osparc.io'
29+
basePath:
30+
enum:
31+
- v0
32+
default: v0
2533
tags:
2634
- name: admins
2735
description: Secured Admin-only calls
@@ -98,6 +106,8 @@ paths:
98106
application/json:
99107
schema:
100108
$ref: './components/schemas/log_message.yaml#/LogMessageEnveloped'
109+
'400':
110+
$ref: '#/components/responses/DataError_BadRequest_400'
101111
'409':
102112
$ref: '#/components/responses/DataError_Conflict_409'
103113
'422':
@@ -127,6 +137,7 @@ paths:
127137
$ref: '#/components/responses/DefaultErrorResponse'
128138
/auth/logout:
129139
get:
140+
operationId: auth_logout
130141
responses:
131142
'200':
132143
description: Succesfully logged out
@@ -137,7 +148,28 @@ paths:
137148
default:
138149
$ref: '#/components/responses/DefaultErrorResponse'
139150
#/auth/reset-password:
140-
#/auth/change-email:
151+
/auth/change-email:
152+
post:
153+
operationId: auth_change_email
154+
requestBody:
155+
content:
156+
application/json:
157+
schema:
158+
type: object
159+
properties:
160+
new_email:
161+
type: string
162+
#format: email
163+
responses:
164+
'200':
165+
description: User has been succesfully registered.
166+
content:
167+
application/json:
168+
schema:
169+
$ref: './components/schemas/log_message.yaml#/LogMessageEnveloped'
170+
default:
171+
$ref: '#/components/responses/DefaultErrorResponse'
172+
141173
#/auth/change-password:
142174
/auth/confirmation/{code}:
143175
get:
@@ -148,7 +180,7 @@ paths:
148180
required: true
149181
schema:
150182
type: string
151-
format: uuid
183+
#format: uuid
152184
responses:
153185
default:
154186
$ref: '#/components/responses/OK_NoContent_204'

packages/service-library/Makefile

+4-3
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ docs: ## generate Sphinx HTML documentation, including API docs
7676
servedocs: docs ## compile the docs watching for changes
7777
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
7878

79-
release: dist ## package and upload a release
80-
twine upload dist/*
81-
8279
dist: clean ## builds source and wheel package
8380
python setup.py sdist
8481
python setup.py bdist_wheel
8582
ls -l dist
8683

8784
install: clean ## install the package to the active Python's site-packages
8885
python setup.py install
86+
87+
dev: clean
88+
pip install -r requirements/dev.txt
89+
pip list

packages/service-library/requirements/dev.txt

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@
33
bumpversion
44
coverage
55

6-
pytest==3.4.2
7-
pytest-runner==2.11.1
6+
-r ../tests/requirements.txt

packages/service-library/setup.py

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ def list_packages(*parts):
4242
'License :: OSI Approved :: MIT License',
4343
'Natural Language :: English',
4444
'Programming Language :: Python :: 3.6',
45-
'Programming Language :: Python :: 3.7',
4645
],
4746
long_description=readme + '\n\n' + history,
4847
license="MIT license",

packages/service-library/src/servicelib/aiopg_utils.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
import logging
1313
import warnings
1414

15-
log = logging.getLogger(__name__)
15+
logger = logging.getLogger(__name__)
1616

17-
warnings.warn("DO NOT USER, STILL UNDER DEVELOPMENT")
17+
warnings.warn("DO NOT USE IN PRODUCTION, STILL UNDER DEVELOPMENT")
1818

1919
@attr.s(auto_attribs=True)
2020
class AiopgExecutor:
@@ -42,9 +42,7 @@ def _compile(self, sql, *multiparams, **params):
4242

4343
async def execute(self):
4444
async with self.engine.acquire() as conn:
45-
log.debug(self.statement)
46-
import pdb; pdb.set_trace()
47-
45+
logger.debug(self.statement)
4846
resp = await conn.execute(self.statement)
4947
return resp
5048

packages/service-library/src/servicelib/openapi.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@
1212
OAI_VERSION = '3.0.1'
1313
OAI_VERSION_URL = 'https://github.com/OAI/OpenAPI-Specification/blob/master/versions/%s.md'%OAI_VERSION
1414

15+
# alias
16+
OpenApiSpec = Spec
17+
18+
1519
# TODO: ensure openapi_core.__version__ is up-to-date with OAI_VERSION
1620

17-
def create_specs(openapi_path: Path) -> Spec:
21+
def create_specs(openapi_path: Path) -> OpenApiSpec:
22+
# TODO: spec_from_file and spec_from_url
1823
with openapi_path.open() as f:
1924
spec_dict = yaml.safe_load(f)
2025

packages/service-library/src/servicelib/openapi_validation.py

+25-3
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
from openapi_core import shortcuts
1010
from openapi_core.schema.specs.models import Spec as OpenApiSpec
1111
from openapi_core.validation.request.validators import RequestValidator
12+
from openapi_core.validation.response.validators import ResponseValidator
1213

1314
from .openapi_wrappers import (PARAMETERS_KEYS, AiohttpOpenAPIRequest,
1415
AiohttpOpenAPIResponse)
1516

16-
log = logging.getLogger(__name__)
17+
logger = logging.getLogger(__name__)
1718

1819
#from openapi_core.wrappers.mock import MockRequest
1920

@@ -32,7 +33,6 @@ async def validate_request(request: web.Request, spec: OpenApiSpec):
3233

3334
return result.parameters, result.body, result.errors
3435

35-
3636
async def validate_parameters(spec: OpenApiSpec, request: web.Request):
3737
req = await AiohttpOpenAPIRequest.create(request)
3838
return shortcuts.validate_parameters(spec, req)
@@ -41,6 +41,9 @@ async def validate_body(spec: OpenApiSpec, request: web.Request):
4141
req = await AiohttpOpenAPIRequest.create(request)
4242
return shortcuts.validate_body(spec, req)
4343

44+
45+
46+
4447
async def validate_data(spec: OpenApiSpec, request, response: web.Response):
4548

4649
if isinstance(request, web.Request):
@@ -58,7 +61,26 @@ async def validate_data(spec: OpenApiSpec, request, response: web.Response):
5861
req = request
5962

6063
res = await AiohttpOpenAPIResponse.create(response)
61-
return shortcuts.validate_data(spec, req, res)
64+
65+
validator = ResponseValidator(spec)
66+
result = validator.validate(req, res)
67+
68+
result.raise_for_errors()
69+
70+
return result.data
71+
72+
async def validate_response(spec: OpenApiSpec, request: web.Request, response: web.Response):
73+
"""
74+
Validates server response against openapi specs
75+
76+
Raises exceptions OpenAPIError, OpenAPIMappingError
77+
"""
78+
validator = ResponseValidator(spec)
79+
80+
req = await AiohttpOpenAPIRequest.create(request)
81+
res = AiohttpOpenAPIResponse(response, response.text) # FIXME:ONLY IN SERVER side. Async in client!
82+
result = validator.validate(req, res)
83+
result.raise_for_errors()
6284

6385

6486
__all__ = (

packages/service-library/src/servicelib/openapi_wrappers.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
CAPTURES = re.compile(r'\(\?P<([_a-zA-Z][_a-zA-Z0-9]+)>(.[^)]+)\)')
1414
PARAMETERS_KEYS = ('path', 'query', 'header', 'cookie')
15+
PATH_KEY, QUERY_KEY, HEADER_KEY, COOKIE_KEY = PARAMETERS_KEYS
1516

1617
class AiohttpOpenAPIRequest(BaseOpenAPIRequest):
1718
wrappedcls = web.Request
@@ -109,16 +110,19 @@ class AiohttpOpenAPIResponse(BaseOpenAPIResponse):
109110

110111
def __init__(self, response: web.Response, data: str):
111112
self._response = response
112-
self._data = data
113+
self._text = data
113114

114115
@staticmethod
115116
async def create(response: web.Response):
116-
data = await response.text()
117-
return AiohttpOpenAPIResponse(response, data)
117+
text = await response.text()
118+
return AiohttpOpenAPIResponse(response, text)
118119

119120
@property
120-
def data(self) -> str:
121-
return self._data
121+
def body(self) -> str:
122+
return self._text
123+
124+
# BUG: not part of BaseOpenAPIResponse but used in openapi-core
125+
data = body
122126

123127
@property
124128
def status_code(self) -> int:

packages/service-library/src/servicelib/resources.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import pathlib
66
import pkg_resources
77
from pathlib import Path
8-
#import typing
8+
from typing import TextIO
99
import attr
1010

1111

@@ -21,16 +21,17 @@ class ResourcesFacade:
2121
distribution_name: str
2222
config_folder: str
2323

24-
def exists(self, resource_name: str):
24+
def exists(self, resource_name: str) -> bool:
2525
return pkg_resources.resource_exists(self.package_name, resource_name)
2626

27-
def stream(self, resource_name: str):
27+
def stream(self, resource_name: str) -> TextIO:
28+
# TODO: check if read-only and if so, rename
2829
return pkg_resources.resource_stream(self.package_name, resource_name)
2930

30-
def listdir(self, resource_name: str):
31+
def listdir(self, resource_name: str) -> str:
3132
return pkg_resources.resource_listdir(self.package_name, resource_name)
3233

33-
def isdir(self, resource_name: str):
34+
def isdir(self, resource_name: str) -> str:
3435
return pkg_resources.resource_isdir(self.package_name, resource_name)
3536

3637
def get_path(self, resource_name: str) -> Path:

packages/service-library/src/servicelib/response_utils.py

-44
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
""" rest - json data encoders/decodes
2+
3+
"""
4+
import attr
5+
import json
6+
7+
8+
class DataEncoder(json.JSONEncoder):
9+
"""
10+
Customized json encoder for rest data models
11+
12+
Extra encoding of:
13+
- attr.s-like classes
14+
15+
TODO: extend to more types like apiset
16+
"""
17+
def default(self, o): #pylint: disable=E0202
18+
if attr.has(o.__class__):
19+
return attr.asdict(o)
20+
return json.JSONEncoder.default(self, o)
21+
22+
23+
def jsonify(payload):
24+
return json.dumps(payload, cls=DataEncoder)

0 commit comments

Comments
 (0)