[release] 0.6.21

This commit is contained in:
Maxime Alves LIRMM@home 2022-07-18 23:23:09 +02:00
parent 779dd2d519
commit c0bd6ddc43
11 changed files with 101 additions and 41 deletions

View File

@ -1,5 +1,13 @@
# HalfAPI # HalfAPI
## 0.6.21
- Store only domain's config in halfapi['config']
- Should run halfapi domain with config_file argument
- Testing : You can specify a "MODULE" attribute to point out the path to the Api's base module
- Environment : HALFAPI_DOMAIN_MODULE can be set to specify Api's base module
- Config : 'module' attribute can be set to specify Api's base module
## 0.6.20 ## 0.6.20
- Fix arguments handling - Fix arguments handling

View File

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM docker.io/python:3.8.12-slim-bullseye FROM docker.io/python:3.10.5-slim-bullseye
COPY . /halfapi COPY . /halfapi
WORKDIR /halfapi WORKDIR /halfapi
RUN apt-get update > /dev/null && apt-get -y install git > /dev/null RUN apt-get update > /dev/null && apt-get -y install git > /dev/null

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
__version__ = '0.6.20-rc0' __version__ = '0.6.21-rc0'
def version(): def version():
return f'HalfAPI version:{__version__}' return f'HalfAPI version:{__version__}'

View File

@ -8,6 +8,8 @@ import sys
import importlib import importlib
import subprocess import subprocess
import json
import click import click
import orjson import orjson
@ -120,9 +122,10 @@ def list_api_routes():
@click.option('--create',default=False, is_flag=True) @click.option('--create',default=False, is_flag=True)
@click.option('--update',default=False, is_flag=True) @click.option('--update',default=False, is_flag=True)
@click.option('--delete',default=False, is_flag=True) @click.option('--delete',default=False, is_flag=True)
@click.argument('config_file', type=click.File(mode='rb'), required=False)
@click.argument('domain',default=None, required=False) @click.argument('domain',default=None, required=False)
@cli.command() @cli.command()
def domain(domain, delete, update, create, read): #, domains, read, create, update, delete): def domain(domain, config_file, delete, update, create, read): #, domains, read, create, update, delete):
""" """
The "halfapi domain" command The "halfapi domain" command
@ -147,17 +150,14 @@ def domain(domain, delete, update, create, read): #, domains, read, create, upd
from ..conf import CONFIG from ..conf import CONFIG
from ..halfapi import HalfAPI from ..halfapi import HalfAPI
try: if config_file:
config_domain = CONFIG.pop('domain').get(domain, {}) CONFIG = json.loads(''.join(
except KeyError: [ line.decode() for line in config_file.readlines() ]
config_domain = {} ))
halfapi = HalfAPI(CONFIG) halfapi = HalfAPI(CONFIG)
half_domain = halfapi.add_domain(domain, config=config_domain)
click.echo(orjson.dumps( click.echo(orjson.dumps(
half_domain.schema(), halfapi.domains[domain].schema(),
option=orjson.OPT_NON_STR_KEYS, option=orjson.OPT_NON_STR_KEYS,
default=ORJSONResponse.default_cast) default=ORJSONResponse.default_cast)
) )

View File

@ -84,6 +84,8 @@ class HalfRoute(Route):
logger.debug( logger.debug(
'Args for current route (%s)', param.get('args')) 'Args for current route (%s)', param.get('args'))
if 'out' in param:
req.scope['out'] = param['out']
if 'out' in param: if 'out' in param:
req.scope['out'] = param['out'].copy() req.scope['out'] = param['out'].copy()

View File

@ -122,12 +122,12 @@ class HalfAPI(Starlette):
domain_key = domain.get('name', key) domain_key = domain.get('name', key)
self.add_domain( add_domain_args = {
domain_key, **domain,
domain.get('module'), 'path': path
domain.get('router'), }
domain.get('acl'),
path) self.add_domain(**add_domain_args)
schemas.append(self.__domains[domain_key].schema()) schemas.append(self.__domains[domain_key].schema())
@ -246,28 +246,26 @@ class HalfAPI(Starlette):
def domains(self): def domains(self):
return self.__domains return self.__domains
def add_domain(self, name, module=None, router=None, acl=None, path='/', config=None): def add_domain(self, **kwargs):
# logger.debug('HalfApi.add_domain %s %s %s %s %s', if not kwargs.get('enabled'):
# name, raise Exception(f'Domain not enabled ({kwargs})')
# module,
# router,
# acl,
# path,
# config)
if config: name = kwargs['name']
self.config['domain'][name] = config
if not module: self.config['domain'][name] = kwargs.get('config', {})
if not kwargs.get('module'):
module = name module = name
else:
module = kwargs.get('module')
try: try:
self.__domains[name] = HalfDomain( self.__domains[name] = HalfDomain(
name, name,
module=importlib.import_module(module), module=importlib.import_module(module),
router=router, router=kwargs.get('router'),
acl=acl, acl=kwargs.get('acl'),
app=self app=self
) )
@ -279,6 +277,6 @@ class HalfAPI(Starlette):
)) ))
raise exc raise exc
self.mount(path, self.__domains[name]) self.mount(kwargs.get('path', name), self.__domains[name])
return self.__domains[name] return self.__domains[name]

View File

@ -108,8 +108,9 @@ def args_check(fct):
kwargs['data'] = data kwargs['data'] = data
if req.scope.get('out'): out_s = req.scope.get('out')
kwargs['out'] = req.scope.get('out').copy() if out_s:
kwargs['out'] = list(out_s)
return await fct(req, *args, **kwargs) return await fct(req, *args, **kwargs)

View File

@ -35,7 +35,21 @@ class DomainMiddleware(BaseHTTPMiddleware):
request.scope['domain'] = self.domain['name'] request.scope['domain'] = self.domain['name']
if hasattr(request.app, 'config') \ if hasattr(request.app, 'config') \
and isinstance(request.app.config, dict): and isinstance(request.app.config, dict):
request.scope['config'] = { **request.app.config } # Set the config scope to the domain's config
request.scope['config'] = request.app.config.get(
'domain', {}
).get(
self.domain['name'], {}
).copy()
# TODO: Remove in 0.7.0
config = request.scope['config'].copy()
request.scope['config']['domain'] = {}
request.scope['config']['domain'][self.domain['name']] = {}
request.scope['config']['domain'][self.domain['name']]['config'] = config
else: else:
logger.debug('%s', request.app) logger.debug('%s', request.app)
logger.debug('%s', getattr(request.app, 'config', None)) logger.debug('%s', getattr(request.app, 'config', None))

View File

@ -11,11 +11,16 @@ from ..cli.cli import cli
from ..halfapi import HalfAPI from ..halfapi import HalfAPI
from ..half_domain import HalfDomain from ..half_domain import HalfDomain
from pprint import pprint from pprint import pprint
import tempfile
class TestDomain(TestCase): class TestDomain(TestCase):
@property
def module_name(self):
return getattr(self, 'MODULE', self.DOMAIN)
@property @property
def router_module(self): def router_module(self):
return '.'.join((self.DOMAIN, self.ROUTERS)) return '.'.join((self.module_name, self.ROUTERS))
def setUp(self): def setUp(self):
# CLI # CLI
@ -53,6 +58,7 @@ class TestDomain(TestCase):
'name': self.DOMAIN, 'name': self.DOMAIN,
'router': self.ROUTERS, 'router': self.ROUTERS,
'acl': self.ACL, 'acl': self.ACL,
'module': self.module_name,
'prefix': False, 'prefix': False,
'enabled': True, 'enabled': True,
'config': { 'config': {
@ -60,12 +66,16 @@ class TestDomain(TestCase):
} }
} }
_, self.config_file = tempfile.mkstemp()
with open(self.config_file, 'w') as fh:
fh.write(json.dumps(self.halfapi_conf))
self.halfapi = HalfAPI(self.halfapi_conf) self.halfapi = HalfAPI(self.halfapi_conf)
self.client = TestClient(self.halfapi.application) self.client = TestClient(self.halfapi.application)
self.module = importlib.import_module( self.module = importlib.import_module(
getattr(self, 'MODULE', self.DOMAIN) self.module_name
) )
@ -77,13 +87,13 @@ class TestDomain(TestCase):
try: try:
result = self.runner.invoke(cli, '--version') result = self.runner.invoke(cli, '--version')
self.assertEqual(result.exit_code, 0) self.assertEqual(result.exit_code, 0)
result = self.runner.invoke(cli, ['domain', self.DOMAIN]) result = self.runner.invoke(cli, ['domain', self.DOMAIN, self.config_file])
self.assertEqual(result.exit_code, 0) self.assertEqual(result.exit_code, 0)
result_d = json.loads(result.stdout) result_d = json.loads(result.stdout)
result = self.runner.invoke(cli, ['run', '--help']) result = self.runner.invoke(cli, ['run', '--help'])
self.assertEqual(result.exit_code, 0) self.assertEqual(result.exit_code, 0)
result = self.runner.invoke(cli, ['run', '--dryrun', self.DOMAIN]) # result = self.runner.invoke(cli, ['run', '--dryrun', self.DOMAIN])
self.assertEqual(result.exit_code, 0) # self.assertEqual(result.exit_code, 0)
except AssertionError as exc: except AssertionError as exc:
print(f'Result {result}') print(f'Result {result}')
print(f'Stdout {result.stdout}') print(f'Stdout {result.stdout}')

View File

@ -4,6 +4,7 @@ import subprocess
import importlib import importlib
import tempfile import tempfile
from unittest.mock import patch from unittest.mock import patch
import json
import pytest import pytest
from click.testing import CliRunner from click.testing import CliRunner
@ -25,7 +26,20 @@ class TestCliProj():
r = project_runner('domain') r = project_runner('domain')
print(r.stdout) print(r.stdout)
assert r.exit_code == 1 assert r.exit_code == 1
r = project_runner('domain dummy_domain') _, tmp_conf = tempfile.mkstemp()
with open(tmp_conf, 'w') as fh:
fh.write(
json.dumps({
'domain': {
'dummy_domain': {
'name': 'dummy_domain',
'enabled': True
}
}
})
)
r = project_runner(f'domain dummy_domain {tmp_conf}')
print(r.stdout) print(r.stdout)
assert r.exit_code == 0 assert r.exit_code == 0

View File

@ -14,4 +14,17 @@ def get(halfapi):
returns the configuration of the domain returns the configuration of the domain
""" """
logger.error('%s', halfapi) logger.error('%s', halfapi)
return halfapi['config']['domain']['dummy_domain']['config'] # TODO: Remove in 0.7.0
try:
assert 'test' in halfapi['config']['domain']['dummy_domain']['config']
except AssertionError as exc:
logger.error('No TEST in halfapi[config][domain][dummy_domain][config]')
raise exc
try:
assert 'test' in halfapi['config']
except AssertionError as exc:
logger.error('No TEST in halfapi[config]')
raise exc
return halfapi['config']