Skip to content

Commit

Permalink
Merge 3720ef4 into 185d79d
Browse files Browse the repository at this point in the history
  • Loading branch information
lrromero committed Oct 23, 2018
2 parents 185d79d + 3720ef4 commit 8c5224e
Show file tree
Hide file tree
Showing 5 changed files with 336 additions and 4 deletions.
13 changes: 13 additions & 0 deletions docs/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,19 @@ Toma los siguientes parámetros:
Retorna una lista de diccionarios con la información de las organizaciones. Recursivamente, dentro del campo `children`,
se encuentran las organizaciones dependientes en la jerarquía.

- **pydatajson.federation.push_organization_tree_to_ckan()**: Tomando un árbol de organizaciones como el creado por
`get_organizations_from_ckan()` crea en el portal de destino las organizaciones dentro de su jerarquía. Toma los siguientes
parámetros:
- **portal_url**: La URL del portal CKAN de destino.
- **apikey**: La apikey de un usuario con los permisos que le permitan crear las organizaciones.
- **org_tree**: lista de diccionarios con la data de organizaciones a crear.
- **parent** (opcional, default: None): Si se pasa, el árbol de organizaciones pasado en `org_tree` se
crea bajo la organización con `name` pasado en `parent`. Si no se pasa un parámetro, las organizaciones son creadas
como primer nivel.

Retorna el árbol de organizaciones creadas. Cada nodo tiene un campo `success` que indica si fue creado exitosamente o
no. En caso de que `success` sea False, los hijos de esa organización no son creados.

## Anexo I: Estructura de respuestas

### validate_catalog()
Expand Down
6 changes: 4 additions & 2 deletions pydatajson/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ def dataset_to_markdown(dataset):


def distribution_to_markdown(distribution):
"""Genera texto en markdown a partir de los metadatos de una `distribution`.
"""Genera texto en markdown a partir de los metadatos de una
`distribution`.
Args:
distribution (dict): Diccionario con metadatos de una `distribution`.
distribution (dict): Diccionario con metadatos de una
`distribution`.
Returns:
str: Texto que describe una `distribution`.
Expand Down
41 changes: 40 additions & 1 deletion pydatajson/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def push_new_themes(catalog, portal_url, apikey):
taxonomía.
portal_url (str): La URL del portal CKAN de destino.
apikey (str): La apikey de un usuario con los permisos que le
permitan crear o actualizar el dataset.
permitan crear o actualizar los temas.
Returns:
str: Los ids de los temas creados.
"""
Expand Down Expand Up @@ -314,3 +314,42 @@ def get_organizations_from_ckan(portal_url):
ckan_portal = RemoteCKAN(portal_url)
return ckan_portal.call_action('group_tree',
data_dict={'type': 'organization'})


def push_organization_tree_to_ckan(portal_url, apikey, org_tree, parent=None):
"""Toma un árbol de organizaciones y lo replica en el portal de
destino.
Args:
portal_url (str): La URL del portal CKAN de destino.
apikey (str): La apikey de un usuario con los permisos que le
permitan crear las organizaciones.
org_tree(list): lista de diccionarios con la data de las
organizaciones a crear.
parent(str): campo name de la organizacion padre.
Returns:
(list): Devuelve el arbol de organizaciones recorridas,
junto con el status detallando si la creación fue
exitosa o no.
"""
portal = RemoteCKAN(portal_url, apikey=apikey)
created = []
for node in org_tree:
if parent:
node['groups'] = [{'name': parent}]
try:
pushed_org = portal.call_action('organization_create',
data_dict=node)
pushed_org['success'] = True
except Exception as e:
logger.exception('Ocurrió un error creando la organización {}: {}'
.format(node['title'], str(e)))
pushed_org = {'name': node, 'success': False}

if pushed_org['success']:
pushed_org['children'] = push_organization_tree_to_ckan(
portal_url, apikey, node['children'], parent=node['name'])

created.append(pushed_org)
return created
235 changes: 235 additions & 0 deletions tests/samples/organization_tree.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
[
{
"highlighted": false,
"title": " Jefatura de Gabinete de Ministros",
"children": [
{
"highlighted": false,
"title": "Agencia de Acceso a la Informaci\u00f3n P\u00fablica",
"children": [],
"name": "aaip",
"id": "daa8b40c-fa37-478c-a7ef-081305aeadd8"
},
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Ambiente y Desarrollo Sustentable",
"children": [
{
"highlighted": false,
"title": "Autoridad de Cuenca Matanza Riachuelo",
"children": [],
"name": "acumar",
"id": "1b6b28cd-098f-41d7-b43f-d5a01ffa8759"
}
],
"name": "ambiente",
"id": "0e5aa328-825e-4509-851d-5421e866635e"
},
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Modernizaci\u00f3n",
"children": [
{
"highlighted": false,
"title": "Empresa Argentina de Soluciones Satelitales",
"children": [],
"name": "arsat",
"id": "b2509ac0-3af6-4f66-9ffa-8c6fb4206791"
},
{
"highlighted": false,
"title": "Ente Nacional de Comunicaciones",
"children": [],
"name": "enacom",
"id": "6eb7d19b-2d42-494f-8e57-d67c501d23eb"
}
],
"name": "modernizacion",
"id": "4c7a6f6b-5caf-42a1-aae5-0a07e609a235"
},
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Turismo",
"children": [],
"name": "turismo",
"id": "3a751de6-128e-4f9a-a479-4672ef79a0e8"
}
],
"name": "jgm",
"id": "f917ad65-28ea-42a9-81ae-61a2bb8f58d0"
},
{
"highlighted": false,
"title": " Ministerio de Defensa",
"children": [
{
"highlighted": false,
"title": "Instituto Geogr\u00e1fico Nacional",
"children": [],
"name": "ign",
"id": "9b47c8eb-bb5c-40df-bbaa-589374d14da8"
},
{
"highlighted": false,
"title": "Servicio Meteorol\u00f3gico Nacional",
"children": [],
"name": "smn",
"id": "dba2a17e-e2ea-4e0b-b0ef-bf4ffe9f9ad9"
}
],
"name": "defensa",
"id": "5e80ed4f-8bfb-4451-8240-e8f39e695ee1"
},
{
"highlighted": false,
"title": "Ministerio de Educaci\u00f3n, Cultura, Ciencia y Tecnolog\u00eda",
"children": [
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Ciencia y Tecnolog\u00eda",
"children": [],
"name": "mincyt",
"id": "772ab9b7-056d-4ae4-b7a2-a1329e979690"
},
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Cultura",
"children": [],
"name": "cultura",
"id": "9fcc8ffc-3dcc-4437-acc8-72c5b08d8d51"
}
],
"name": "educacion",
"id": "27d39ff7-7110-4c6d-b7e8-1b8eba392d7e"
},
{
"highlighted": false,
"title": " Ministerio de Hacienda",
"children": [
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Energ\u00eda",
"children": [
{
"highlighted": false,
"title": "Ente Nacional Regulador del Gas",
"children": [],
"name": "enargas",
"id": "dddda9d3-644d-4e3d-974b-302fd8945a86"
}
],
"name": "energia",
"id": "cd1b32a2-2d3a-44ac-8c98-a425a7b62d42"
},
{
"highlighted": false,
"title": "Subsecretar\u00eda de Presupuesto",
"children": [],
"name": "sspre",
"id": "a753aeb8-52eb-4cfc-a6ee-6d930094b0f2"
},
{
"highlighted": false,
"title": "Subsecretar\u00eda de Programaci\u00f3n Macroecon\u00f3mica",
"children": [],
"name": "sspm",
"id": "68f9ee22-5ec3-44cf-a32b-b87d9db46b93"
},
{
"highlighted": false,
"title": "Subsecretar\u00eda de Programaci\u00f3n Microecon\u00f3mica",
"children": [],
"name": "sspmi",
"id": "b4baa84a-16a7-4db0-af9c-bd925971d26a"
}
],
"name": "hacienda",
"id": "b2a6e77e-a3c8-4e1a-bcba-7134a9436051"
},
{
"highlighted": false,
"title": " Ministerio de Justicia y Derechos Humanos",
"children": [],
"name": "justicia",
"id": "06b380f8-888f-43c0-8367-16a7ddf47d4f"
},
{
"highlighted": false,
"title": " Ministerio del Interior, Obras P\u00fablicas y Vivienda ",
"children": [],
"name": "interior",
"id": "c88b1ad1-f78d-4cf9-848d-d73ccae6cd8e"
},
{
"highlighted": false,
"title": "Ministerio de Producci\u00f3n y Trabajo",
"children": [
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Agroindustria",
"children": [],
"name": "agroindustria",
"id": "b10c94e2-ade1-4a97-8c4c-b1ada7878d60"
},
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Trabajo y Empleo",
"children": [],
"name": "trabajo",
"id": "f31cb5dc-79ab-442b-ac7f-87ef6ad7749d"
},
{
"highlighted": false,
"title": "Secretar\u00eda de Transformaci\u00f3n Productiva",
"children": [],
"name": "siep",
"id": "83a04686-747a-4ba3-a0b1-2f05c3196bc4"
}
],
"name": "produccion",
"id": "1ca8d15b-31fc-4f09-ba09-53edd3d4cce6"
},
{
"highlighted": false,
"title": "Ministerio de Relaciones Exteriores y Culto",
"children": [],
"name": "exterior",
"id": "89cd05f2-11c1-4f1a-875f-b4faf97eb4d4"
},
{
"highlighted": false,
"title": "Ministerio de Salud y Desarrollo Social",
"children": [
{
"highlighted": false,
"title": "Secretar\u00eda de Gobierno de Salud",
"children": [],
"name": "salud",
"id": "dd1f2018-587f-43af-9b07-fc32f5ab588b"
}
],
"name": "desarrollo-social",
"id": "ef25c735-2abb-4165-94a6-a6798a103603"
},
{
"highlighted": false,
"title": " Ministerio de Seguridad",
"children": [],
"name": "seguridad",
"id": "908fd413-5a22-40e7-9204-38ef380ae232"
},
{
"highlighted": false,
"title": " Ministerio de Transporte",
"children": [],
"name": "transporte",
"id": "71418928-10c4-4625-aeaf-69a4d73d00ed"
},
{
"highlighted": false,
"title": "Sin organizaci\u00f3n asignada",
"children": [],
"name": "otros",
"id": "109d53ef-3ed3-498e-97d0-a456698969f7"
}
]
45 changes: 44 additions & 1 deletion tests/test_federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import unittest
import os
import re
import json

try:
from mock import patch, MagicMock
Expand Down Expand Up @@ -481,7 +482,49 @@ def mock_call_action(action, data_dict=None):
@patch('pydatajson.federation.RemoteCKAN', autospec=True)
class OrganizationsTestCase(FederationSuite):

def setUp(self):
self.portal_url = 'portal_url'
self.apikey = 'apikey'
self.org_tree = json.load(open(
self.get_sample('organization_tree.json')))

def check_hierarchy(self, node, parent=None):
if not node['success']:
self.assertTrue('children' not in node)
return
if parent is None:
self.assertTrue('groups' not in node)
else:
self.assertDictEqual(node['groups'][0],
{'name': parent})

for child in node['children']:
self.check_hierarchy(child, parent=node['name'])

def test_get_organization_calls_api_correctly(self, mock_portal):
get_organizations_from_ckan('portal_url')
get_organizations_from_ckan(self.portal_url)
mock_portal.return_value.call_action.assert_called_with(
'group_tree', data_dict={'type': 'organization'})

def test_push_organizations_sends_correct_hierarchy(self, mock_portal):
mock_portal.return_value.call_action = (lambda _, data_dict: data_dict)
pushed_tree = push_organization_tree_to_ckan(self.portal_url,
self.apikey,
self.org_tree)
for node in pushed_tree:
self.check_hierarchy(node)

def test_push_organizations_cuts_trees_on_failures(self, mock_portal):
def mock_org_create(_action, data_dict):
broken_orgs = ('acumar', 'modernizacion', 'hacienda')
if data_dict['name'] in broken_orgs:
raise Exception('broken org on each level')
else:
return data_dict

mock_portal.return_value.call_action = mock_org_create
pushed_tree = push_organization_tree_to_ckan(self.portal_url,
self.apikey,
self.org_tree)
for node in pushed_tree:
self.check_hierarchy(node)

0 comments on commit 8c5224e

Please sign in to comment.