Skip to content
This repository has been archived by the owner on Apr 22, 2024. It is now read-only.

Parallel extraction #386

Merged
merged 39 commits into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
909a137
feat: add mapping sets to kernel (#337)
lordmallam Sep 5, 2018
fd40779
Merge branch 'develop' into parallel-extraction
obdulia-losantos Sep 6, 2018
2e4d2a7
chore: merge develop into parallel-extraction
obdulia-losantos Sep 6, 2018
431b11b
Merge branch 'develop' into parallel-develop
obdulia-losantos Sep 11, 2018
1d1eda0
chore: merge develop into parallel-extraction
obdulia-losantos Sep 11, 2018
ef912d6
chore: merge branch 'develop' into 'parallel-extraction'
obdulia-losantos Sep 13, 2018
ed4b803
feat: (ui) mappingsets to pipelines (#361)
lordmallam Sep 18, 2018
8462983
fix: artefacts generation with mapping sets (#350)
obdulia-losantos Sep 20, 2018
34f92e4
chore: merge develop into parallel-extraction
obdulia-losantos Sep 20, 2018
7345540
Merge branch 'develop' into parallel-extraction
obdulia-losantos Sep 24, 2018
13b045d
fix(couchdb): adapt to mapping set model
obdulia-losantos Sep 24, 2018
22358ac
chore: merge branch 'develop' into parallel-extraction
obdulia-losantos Sep 24, 2018
9b25d70
fix: reactivate UI tests in travis (#371)
obdulia-losantos Sep 25, 2018
7037edf
fix mappingset migration (#379)
sabeen Sep 27, 2018
08b4033
Merge branch 'develop' into parallel-extraction
obdulia-losantos Oct 2, 2018
2deaa8b
chore: add mappingset to client test_fixtures
Oct 2, 2018
7bb16e5
chore: swap mapping.id for mappingset.id in submission generation
Oct 2, 2018
fa2338a
fix: use model from swagger for submissions in integration tests
Oct 2, 2018
51dac72
fix: remove useless test and change scope of entity generation
Oct 2, 2018
30f0bae
chore: Merge branch 'develop' into parallel-extraction
obdulia-losantos Oct 2, 2018
679579f
feat (ui): pipeline fetch/publish using mapping set (#373)
lordmallam Oct 3, 2018
f002b4a
Merge branch 'develop' into parallel-extraction
obdulia-losantos Oct 3, 2018
b737147
Merge pull request #385 from eHealthAfrica/parallel-develop
obdulia-losantos Oct 3, 2018
ca3e926
fix (ui): check pipelines lenght
lordmallam Oct 4, 2018
3875051
fix (ui): migration fix
lordmallam Oct 4, 2018
37e3ebe
fix(ui): contract migration
lordmallam Oct 5, 2018
8ca57ad
fix: artefacts names (#387)
obdulia-losantos Oct 5, 2018
73bee2a
Merge branch 'develop' into parallel-extraction
obdulia-losantos Oct 5, 2018
93db101
fix(ui): filter piplines - redux
lordmallam Oct 5, 2018
d548dbe
Merge branch 'parallel-extraction' of https://github.com/eHealthAfric…
lordmallam Oct 5, 2018
6cbfad8
Merge pull request #388 from eHealthAfrica/parallel-develop
obdulia-losantos Oct 5, 2018
c7e5a77
feat(kernel): create an empty mapping along with the passthrough one …
obdulia-losantos Oct 8, 2018
b9dc074
Merge branch 'develop' into parallel-extraction
shawnsarwar Oct 8, 2018
19990e1
fixed css grid and added word break for long titles without breaking …
sabeen Oct 8, 2018
3f33ff9
docs(ui): fix model comments (#401)
obdulia-losantos Oct 9, 2018
7217511
Merge branch 'develop' into parallel-extraction
shawnsarwar Oct 9, 2018
6bfc2ec
Merge branch 'develop' into parallel-extraction
shawnsarwar Oct 9, 2018
144ae1c
feat(kernel): include a random input in the generated mapping (#402)
obdulia-losantos Oct 10, 2018
bbc50ac
fix(ui): the derived data must have an id field with UUID content (#400)
obdulia-losantos Oct 10, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions aether-common-module/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ Possible responses:
- `Always Look on the Bright Side of Life!!!` ✘
- `Brought to you by eHealth Africa - good tech for hard places` ✔

#### To make submissions linked to an existing project artefact (mapping).
#### To push submissions linked to an existing project artefact (mapping set).

```python
aether.common.kernel.utils.submit_to_kernel(submission, mapping_id, submission_id=None)
aether.common.kernel.utils.submit_to_kernel(submission, mappingset_id, submission_id=None)
```

### Conf section
Expand Down
12 changes: 6 additions & 6 deletions aether-common-module/aether/common/kernel/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,12 @@ def test__test_connection_get_fail(self, mock_get, mock_head):
)

@mock.patch.dict('os.environ', AETHER_ENV_MOCK)
def test_submit_to_kernel__without_mapping_id(self):
def test_submit_to_kernel__without_mappingset_id(self):
self.assertRaises(
Exception,
utils.submit_to_kernel,
submission={'a': 1},
mapping_id=None,
submission={},
mappingset_id=None,
)

@mock.patch.dict('os.environ', AETHER_ENV_MOCK)
Expand All @@ -154,22 +154,22 @@ def test_submit_to_kernel__without_submission(self):
Exception,
utils.submit_to_kernel,
submission=None,
mapping_id=1,
mappingset_id=1,
)

@mock.patch('requests.put')
@mock.patch('requests.post')
@mock.patch.dict('os.environ', AETHER_ENV_MOCK)
def test_submit_to_kernel__without_submission_id(self, mock_post, mock_put):
utils.submit_to_kernel(submission={'_id': 'a'}, mapping_id=1, submission_id=None)
utils.submit_to_kernel(submission={'_id': 'a'}, mappingset_id=1, submission_id=None)
mock_put.assert_not_called()
mock_post.assert_called()

@mock.patch('requests.put')
@mock.patch('requests.post')
@mock.patch.dict('os.environ', AETHER_ENV_MOCK)
def test_submit_to_kernel__with_submission_id(self, mock_post, mock_put):
utils.submit_to_kernel(submission={'_id': 'a'}, mapping_id=1, submission_id=1)
utils.submit_to_kernel(submission={'_id': 'a'}, mappingset_id=1, submission_id=1)
mock_put.assert_called()
mock_post.assert_not_called()

Expand Down
8 changes: 4 additions & 4 deletions aether-common-module/aether/common/kernel/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,16 @@ def get_data(url):
return results


def submit_to_kernel(submission, mapping_id, submission_id=None):
def submit_to_kernel(submission, mappingset_id, submission_id=None):
'''
Push the submission to Aether Kernel
'''

if submission is None:
raise errors.SubmissionError(_('Cannot make submission without content!'))

if mapping_id is None:
raise errors.SubmissionError(_('Cannot make submission without mapping!'))
if mappingset_id is None:
raise errors.SubmissionError(_('Cannot make submission without mapping set!'))

if submission_id:
# update existing doc
Expand All @@ -164,7 +164,7 @@ def submit_to_kernel(submission, mapping_id, submission_id=None):
url,
json={
'payload': submission,
'mapping': mapping_id,
'mappingset': mappingset_id,
},
headers=get_auth_header(),
)
2 changes: 1 addition & 1 deletion aether-couchdb-sync-module/aether/sync/api/couchdb_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,5 +194,5 @@ def post_to_aether(document, aether_id=False):
)

return kernel_utils.submit_to_kernel(submission=document,
mapping_id=str(schema.kernel_id),
mappingset_id=str(schema.kernel_id),
submission_id=aether_id)
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from . import clean_couch


SUBMISSION_FK = 'mapping'
SUBMISSION_FK = 'mappingset'
headers_testing = kernel_utils.get_auth_header()
device_id = 'test_import-from-couch'

Expand Down
8 changes: 7 additions & 1 deletion aether-kernel/aether/kernel/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,18 @@ class ProjectAdmin(CompareVersionAdmin):

class MappingAdmin(CompareVersionAdmin):
form = forms.MappingForm
list_display = ('id', 'name', 'revision',)
readonly_fields = ('id',)


class MappingSetAdmin(CompareVersionAdmin):
list_display = ('id', 'name', 'revision', 'project',)
readonly_fields = ('id',)


class SubmissionAdmin(CompareVersionAdmin):
form = forms.SubmissionForm
list_display = ('id', 'revision', 'mapping', 'map_revision',)
list_display = ('id', 'revision', 'mappingset',)
readonly_fields = ('id',)


Expand All @@ -57,6 +62,7 @@ class EntityAdmin(CompareVersionAdmin):


admin.site.register(models.Project, ProjectAdmin)
admin.site.register(models.MappingSet, MappingSetAdmin)
admin.site.register(models.Mapping, MappingAdmin)
admin.site.register(models.Submission, SubmissionAdmin)
admin.site.register(models.Schema, SchemaAdmin)
Expand Down
110 changes: 103 additions & 7 deletions aether-kernel/aether/kernel/api/avro_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,14 @@
for details.
'''

import collections
import copy
import uuid
import random

from collections import namedtuple
from copy import deepcopy
from os import urandom
from string import ascii_letters
from uuid import uuid4


# Constants used by AvroValidator to distinguish between avro types
# ``int`` and ``long``.
Expand Down Expand Up @@ -55,6 +60,87 @@
NAMESPACE = 'org.ehealthafrica.aether'


def random_string():
return ''.join(random.choice(ascii_letters) for i in range(random.randint(1, 30)))


def random_avro(schema):
'''
Generates a random value based on the given AVRO schema.
'''

name = schema.get('name')
avro_type = schema['type']
if isinstance(avro_type, list): # UNION or NULLABLE
# ["null", "int", "string", {"type: "record", ...}]
avro_type = [t for t in avro_type if t != NULL] # ignore NULL
if len(avro_type) == 1: # it was NULLABLE
avro_type = avro_type[0]

if __has_type(avro_type): # {"type": {"type": "zzz", ...}}
schema = avro_type
avro_type = avro_type.get('type')

if avro_type == NULL:
return None

if avro_type == BOOLEAN:
return True if random.random() > 0.5 else False

if avro_type in [BYTES, FIXED]:
return urandom(schema.get('size', 8))

if avro_type == INT:
return random.randint(INT_MIN_VALUE, INT_MAX_VALUE)

if avro_type == LONG:
return random.randint(LONG_MIN_VALUE, LONG_MAX_VALUE)

if avro_type in [FLOAT, DOUBLE]:
return random.random() + random.randint(INT_MIN_VALUE, INT_MAX_VALUE)

if avro_type == STRING:
if name == 'id':
return str(uuid4()) # "id" fields contain an UUID
return random_string()

if avro_type == ENUM:
return random.choice(schema['symbols'])

if avro_type == RECORD:
return {
f['name']: random_avro(f)
for f in schema.get('fields', [])
}

if avro_type == MAP:
values = schema.get('values')
map_type = values if __has_type(values) else {'type': values}
return {
random_string(): random_avro(map_type)
for i in range(random.randint(1, 5))
}

if avro_type == ARRAY:
items = schema.get('items')
array_type = items if __has_type(items) else {'type': items}
return [
random_avro(array_type)
for i in range(random.randint(1, 5))
]

if isinstance(avro_type, list): # UNION
# choose one random type and generate value
# ["int", "string", {"type: "record", ...}]
ut = avro_type[random.randint(0, len(avro_type) - 1)]
ut = ut if __has_type(ut) else {'type': ut}
return random_avro(ut)

# TODO: named types ¯\_(ツ)_/¯

return None


class AvroValidationException(Exception):
pass

Expand All @@ -70,7 +156,7 @@ class AvroValidationException(Exception):
#
# indicates that the expected type at path "$.a.b" was a union of
# 'null' and 'string'. The actual value was 1.
AvroValidationError = collections.namedtuple(
AvroValidationError = namedtuple(
'AvroValidationError',
['expected', 'datum', 'path'],
)
Expand Down Expand Up @@ -333,9 +419,11 @@ def avro_schema_to_passthrough_artefacts(item_id, avro_schema):
'''

if not item_id:
item_id = str(uuid.uuid4())
item_id = str(uuid4())

definition = deepcopy(avro_schema)
sample = random_avro(definition)

definition = copy.deepcopy(avro_schema)
# assign default namespace
if not definition.get('namespace'):
definition['namespace'] = NAMESPACE
Expand Down Expand Up @@ -377,7 +465,15 @@ def avro_schema_to_passthrough_artefacts(item_id, avro_schema):
'definition': {
'entities': {name: item_id},
'mapping': rules,
}
},
# this is an auto-generated mapping that shouldn't be modified manually
'is_read_only': True,
'is_active': True,
'input': sample, # include a data sample
}

return schema, mapping


def __has_type(avro_type):
return isinstance(avro_type, dict) and avro_type.get('type')
54 changes: 54 additions & 0 deletions aether-kernel/aether/kernel/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,71 @@ class Meta:


class MappingFilter(filters.FilterSet):
mappingset = filters.CharFilter(
method='mappingset_filter',
)
projectschema = filters.CharFilter(
method='projectschema_filter',
)

def mappingset_filter(self, queryset, name, value):
if is_uuid(value):
return queryset.filter(mappingset__pk=value)
else:
return queryset.filter(mappingset__name=value)

def projectschema_filter(self, queryset, name, value):
if is_uuid(value):
return queryset.filter(projectschemas__in=[value])
else:
return queryset.filter(projectschemas__name__in=[value])

class Meta:
fields = '__all__'
exclude = ('definition',)
model = models.Mapping


class MappingSetFilter(filters.FilterSet):
project = filters.CharFilter(
method='project_filter',
)

def project_filter(self, queryset, name, value):
if is_uuid(value):
return queryset.filter(project__pk=value)
else:
return queryset.filter(project__name=value)

class Meta:
fields = '__all__'
exclude = ('input',)
model = models.MappingSet


class SubmissionFilter(filters.FilterSet):
instanceID = filters.CharFilter(
field_name='payload__meta__instanceID',
)
project = filters.CharFilter(
method='project_filter',
)
mappingset = filters.CharFilter(
method='mappingset_filter',
)

def project_filter(self, queryset, name, value):
if is_uuid(value):
return queryset.filter(project__pk=value)
else:
return queryset.filter(project__name=value)

def mappingset_filter(self, queryset, name, value):
if is_uuid(value):
return queryset.filter(mappingset__pk=value)
else:
return queryset.filter(mappingset__name=value)

class Meta:
fields = '__all__'
exclude = ('payload',)
Expand Down Expand Up @@ -100,6 +145,9 @@ class EntityFilter(filters.FilterSet):
project = filters.CharFilter(
method='project_filter',
)
mapping = filters.CharFilter(
method='mapping_filter',
)

def project_filter(self, queryset, name, value):
if is_uuid(value):
Expand All @@ -113,6 +161,12 @@ def schema_filter(self, queryset, name, value):
else:
return queryset.filter(projectschema__schema__name=value)

def mapping_filter(self, queryset, name, value):
if is_uuid(value):
return queryset.filter(mapping__pk=value)
else:
return queryset.filter(mapping__name=value)

class Meta:
fields = '__all__'
exclude = ('payload',)
Expand Down
Loading