[release] 0.6.21
This commit is contained in:
parent
779dd2d519
commit
c0bd6ddc43
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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__}'
|
||||||
|
|
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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}')
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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']
|
||||||
|
|
Loading…
Reference in New Issue