├── .gitignore ├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── jsongraph ├── __init__.py ├── binding.py ├── common.py ├── config.py ├── context.py ├── graph.py ├── metadata.py ├── query.py ├── reflect.py ├── schemas │ └── config.json ├── triplify.py ├── util.py └── vocab.py ├── setup.py └── tests ├── __init__.py ├── fixtures ├── countries │ ├── countries.csv │ └── mapping.json ├── everypol │ ├── mapping.json │ └── term-26.csv ├── rdfconv │ └── bt_partial.json ├── schemas │ ├── area.json │ ├── contact_detail.json │ ├── count.json │ ├── event.json │ ├── group_result.json │ ├── identifier.json │ ├── link.json │ ├── membership.json │ ├── motion.json │ ├── organization.json │ ├── other_name.json │ ├── person.json │ ├── post.json │ ├── speech.json │ ├── vote.json │ └── vote_event.json └── test.json ├── test_context.py ├── test_graph.py ├── test_metadata.py ├── test_query.py ├── test_reflect.py └── util.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | pyenv/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | 47 | # Translations 48 | *.mo 49 | *.pot 50 | 51 | # Django stuff: 52 | *.log 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | # PyBuilder 58 | target/ 59 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.3" 5 | before_install: 6 | - virtualenv ./pyenv --distribute 7 | - source ./pyenv/bin/activate 8 | install: 9 | - pip install --upgrade pip 10 | - pip install -e . 11 | - pip install nose coverage unicodecsv python-dateutil 12 | before_script: 13 | - nosetests --version 14 | script: 15 | - nosetests --with-coverage --cover-package=jsongraph 16 | after_success: 17 | - coveralls 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Friedrich Lindenberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | recursive-include jsongraph/schemas * 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: install 3 | @rm -rf **/*.pyc 4 | @pyenv/bin/nosetests --with-coverage --cover-package=jsongraph --cover-erase -x 5 | 6 | install: pyenv/bin/python 7 | 8 | pyenv/bin/python: 9 | virtualenv pyenv 10 | pyenv/bin/pip install --upgrade pip 11 | pyenv/bin/pip install wheel nose coverage unicodecsv python-dateutil 12 | pyenv/bin/pip install -e . 13 | 14 | upload: test 15 | pyenv/bin/python setup.py sdist bdist_wheel upload 16 | 17 | clean: 18 | rm -rf pyenv jsongraph.egg-info dist build 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jsongraph [![Build Status](https://travis-ci.org/pudo/jsongraph.svg?branch=master)](https://travis-ci.org/pudo/jsongraph) 2 | 3 | This library provides tools to integrate data from multiple sources into a 4 | coherent data model. Given a heterogeneous set of source records, it will 5 | generate a set of composite entities with merged information from all 6 | available sources. Further, it allows querying the resulting graph using a 7 | simple, JSON-based graph query language. 8 | 9 | The intent of this tool is to make a graph-based data integration system 10 | (based on RDF) seamlessly available through simple JSON objects. 11 | 12 | ## Usage 13 | 14 | This is what using the library looks like in a simplified scenario: 15 | 16 | ```python 17 | from jsongraph import Graph 18 | 19 | # Create a graph for all project information. This can be backed by a 20 | # triple store or an in-memory construct. 21 | graph = Graph(base_uri='file:///path/to/schema/files') 22 | graph.register('person', 'person_schema.json') 23 | 24 | # Load data about a person. 25 | context = graph.context() 26 | context.add('person', data) 27 | context.save() 28 | # Repeat data loading for a variety of source files. 29 | 30 | # This will integrate data from all source files into a single representation 31 | # of the data. 32 | context = graph.consolidate('urn:prod') 33 | 34 | # Metaweb-style queries: 35 | for item in context.query([{"name": None, "limit": 5}]): 36 | print item['name'] 37 | ``` 38 | 39 | ## Design 40 | 41 | A ``jsongraph`` application is focussed on a ``Graph``, which stores a set of 42 | data. A ``Graph`` can either exist only in memory, or be stored in a backend 43 | database. 44 | 45 | All data in a ``Graph`` is structured as collections of JSON objects (i.e. 46 | nested dictionaries, lists and values). The structure of all stored objects 47 | must be defined using a [JSON Schema](http://json-schema.org/). Some limits 48 | apply to such schema, e.g. they may not allow additional or pattern properties. 49 | 50 | ### Contexts and Metadata 51 | 52 | The objects in each ``Graph`` are grouped into a set of ``Contexts``. Those 53 | also include metadata, such as the source of the data, and the level of trust 54 | that the system shall have in those data. A ``Context`` will usually correspond 55 | to a source data file, or a user interaction. 56 | 57 | ### Consolidated Contexts 58 | 59 | When working with ``jsongraph``, a user will first load data into a variety of 60 | ``Contexts``. They can then generate a consolidated version of the data, in a 61 | separate ``Context``. 62 | 63 | This consolidated version applies entity de-duplication. For object properties 64 | with multiple available values across several ``Contexts``, the information 65 | from the most trustworthy ``Context`` will be chosen. 66 | 67 | ### Queries 68 | 69 | ``jsongraph`` includes a query language implementation, which is heavily 70 | inspired by Google's [Metaweb Query Language](http://mql.freebaseapps.com/ch03.html). 71 | Queries are written as JSON, and search proceeds by example. Searches can also 72 | be deeply nested, traversing the links between objects stored in the ``Graph`` 73 | at an arbitrary complexity. 74 | 75 | Queries on the data can be run either against any of the source ``Contexts``, 76 | or against the consolidated context. Queries against the consolidated 77 | ``Context`` will produce responses which reflect the best available information 78 | based on data from a variety of sources. 79 | 80 | ### De-duplication 81 | 82 | One key part of the functions of this library will be the application of 83 | de-duplication rules. This will take place in three steps: 84 | 85 | * Generating a set of de-duplicating candidates for all entities in a given 86 | ``Graph``. These will be simplified representations of objects which can be 87 | fed into a comparison tool (either automated or interactive with the user). 88 | 89 | * Once the candidates have been decided, they are transformed into a mapping of 90 | the type (``original_fingerprint`` -> ``same_as_fingerprint``). Such mappings 91 | are applied to a context. 92 | 93 | * Upon graph consolidation (see above), the entities which have been mapped to 94 | another are not included. All their properties are inherited by the 95 | destination entity. 96 | 97 | A data comparison candidate may look like this: 98 | 99 | ```json 100 | { 101 | "fingerprint": "...", 102 | "entity": "...", 103 | "data": { 104 | 105 | }, 106 | "source": { 107 | "label": "...", 108 | "url": "http://..." 109 | } 110 | } 111 | ``` 112 | 113 | ## Tests 114 | 115 | The test suite will usually be executed in it's own ``virtualenv`` and perform a 116 | coverage check as well as the tests. To execute on a system with ``virtualenv`` 117 | and ``make`` installed, type: 118 | 119 | ```bash 120 | $ make test 121 | ``` 122 | -------------------------------------------------------------------------------- /jsongraph/__init__.py: -------------------------------------------------------------------------------- 1 | from jsongraph.graph import Graph 2 | from jsongraph.util import sparql_store, GraphException 3 | 4 | __all__ = [Graph, GraphException, sparql_store] 5 | 6 | import warnings 7 | warnings.filterwarnings( 8 | 'ignore', 9 | "urlgrabber not installed in the system. The execution of this method has no effect." # noqa 10 | ) 11 | -------------------------------------------------------------------------------- /jsongraph/binding.py: -------------------------------------------------------------------------------- 1 | from rdflib import Literal, URIRef 2 | # from rdflib.term import Identifier 3 | # from rdflib.namespace import RDF 4 | 5 | from jsonmapping import SchemaVisitor 6 | 7 | from jsongraph.util import is_url, safe_uriref 8 | from jsongraph.vocab import BNode, PRED, ID 9 | 10 | 11 | class Binding(SchemaVisitor): 12 | 13 | @property 14 | def uri(self): 15 | val = self.path 16 | return None if val is None else URIRef(val) 17 | 18 | @property 19 | def subject(self): 20 | if not hasattr(self, '_rdf_subject'): 21 | self._rdf_subject = None 22 | subject = self.schema.get('rdfSubject', 'id') 23 | for prop in self.properties: 24 | if prop.match(subject): 25 | obj = prop.object 26 | if obj is not None and not isinstance(obj, URIRef): 27 | obj = ID[obj] 28 | self._rdf_subject = obj 29 | break 30 | if self._rdf_subject is None: 31 | self._rdf_subject = BNode() 32 | return self._rdf_subject 33 | 34 | @property 35 | def predicate(self): 36 | return PRED[self.schema.get('rdfName', self.name)] 37 | 38 | @property 39 | def reverse(self): 40 | name = self.schema.get('rdfReverse') 41 | if name is not None: 42 | return PRED[name] 43 | if self.parent is not None and self.parent.is_array: 44 | return self.parent.reverse 45 | 46 | def get_property(self, predicate): 47 | for prop in self.properties: 48 | if predicate == PRED[prop.name]: 49 | return prop 50 | 51 | @property 52 | def object(self): 53 | if self.data is None: 54 | return self.data 55 | if self.schema.get('format') == 'uri' or \ 56 | self.schema.get('rdfType') == 'uri': 57 | try: 58 | return safe_uriref(self.data) 59 | except: 60 | pass 61 | if self.schema.get('rdfType') == 'id': 62 | if is_url(self.data): 63 | try: 64 | return safe_uriref(self.data) 65 | except: 66 | pass 67 | return ID[self.data] 68 | return Literal(self.data) 69 | -------------------------------------------------------------------------------- /jsongraph/common.py: -------------------------------------------------------------------------------- 1 | from rdflib import URIRef, RDF 2 | from sparqlquery import Select, v, desc 3 | 4 | from jsongraph.query import Query, QueryNode 5 | from jsongraph.binding import Binding 6 | 7 | 8 | class GraphOperations(object): 9 | """ Common operations for both the context graphs and the main store. """ 10 | 11 | def get_binding(self, schema, data): 12 | """ For a given schema, get a binding mediator providing links to the 13 | RDF terms matching that schema. """ 14 | schema = self.parent.get_schema(schema) 15 | return Binding(schema, self.parent.resolver, data=data) 16 | 17 | def get(self, id, depth=3, schema=None): 18 | """ Construct a single object based on its ID. """ 19 | uri = URIRef(id) 20 | if schema is None: 21 | for o in self.graph.objects(subject=uri, predicate=RDF.type): 22 | schema = self.parent.get_schema(str(o)) 23 | if schema is not None: 24 | break 25 | else: 26 | schema = self.parent.get_schema(schema) 27 | binding = self.get_binding(schema, None) 28 | return self._objectify(uri, binding, depth=depth, path=set()) 29 | 30 | def all(self, schema_name, depth=3): 31 | schema_uri = self.parent.get_uri(schema_name) 32 | uri = URIRef(schema_uri) 33 | var = v['uri'] 34 | q = Select([var]).where((var, RDF.type, uri)) 35 | q = q.order_by(desc(var)) 36 | for data in q.execute(self.graph): 37 | yield self.get(data['uri'], depth=depth, schema=schema_uri) 38 | 39 | def _objectify(self, node, binding, depth, path): 40 | """ Given an RDF node URI (and it's associated schema), return an 41 | object from the ``graph`` that represents the information available 42 | about this node. """ 43 | if binding.is_object: 44 | obj = {'$schema': binding.path} 45 | for (s, p, o) in self.graph.triples((node, None, None)): 46 | prop = binding.get_property(p) 47 | if prop is None or depth <= 1 or o in path: 48 | continue 49 | # This is slightly odd but yield purty objects: 50 | if depth <= 2 and (prop.is_array or prop.is_object): 51 | continue 52 | sub_path = path.union([node]) 53 | value = self._objectify(o, prop, depth - 1, sub_path) 54 | if prop.is_array and prop.name in obj: 55 | obj[prop.name].extend(value) 56 | else: 57 | obj[prop.name] = value 58 | return obj 59 | elif binding.is_array: 60 | for item in binding.items: 61 | return [self._objectify(node, item, depth, path)] 62 | else: 63 | return node.toPython() 64 | 65 | def query(self, q): 66 | """ Run a query using the jsongraph query dialect. This expects an 67 | input query, which can either be a dict or a list. """ 68 | return Query(self, None, QueryNode(None, None, q)) 69 | -------------------------------------------------------------------------------- /jsongraph/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | from jsonschema import Draft4Validator, ValidationError 5 | 6 | config_schema = os.path.dirname(__file__) 7 | config_schema = os.path.join(config_schema, 'schemas', 'config.json') 8 | 9 | with open(config_schema, 'rb') as fh: 10 | config_schema = json.load(fh) 11 | config_validator = Draft4Validator(config_schema) 12 | -------------------------------------------------------------------------------- /jsongraph/context.py: -------------------------------------------------------------------------------- 1 | from rdflib import Graph, URIRef 2 | # from jsonschema import validate 3 | 4 | from jsongraph.vocab import BNode 5 | from jsongraph.metadata import MetaData 6 | from jsongraph.common import GraphOperations 7 | from jsongraph.triplify import triplify 8 | 9 | 10 | class Context(GraphOperations): 11 | 12 | def __init__(self, parent, identifier=None, meta=None): 13 | self.parent = parent 14 | if identifier is None: 15 | identifier = BNode() 16 | self.identifier = URIRef(identifier) 17 | self.meta = MetaData(self, meta) 18 | self.meta.generate() 19 | 20 | @property 21 | def graph(self): 22 | if not hasattr(self, '_graph') or self._graph is None: 23 | if self.parent.buffered: 24 | self._graph = Graph(identifier=self.identifier) 25 | else: 26 | self._graph = self.parent.graph.get_context(self.identifier) 27 | return self._graph 28 | 29 | def add(self, schema, data): 30 | """ Stage ``data`` as a set of statements, based on the given 31 | ``schema`` definition. """ 32 | binding = self.get_binding(schema, data) 33 | uri, triples = triplify(binding) 34 | for triple in triples: 35 | self.graph.add(triple) 36 | return uri 37 | 38 | def save(self): 39 | """ Transfer the statements in this context over to the main store. """ 40 | if self.parent.buffered: 41 | query = """ 42 | INSERT DATA { GRAPH %s { %s } } 43 | """ 44 | query = query % (self.identifier.n3(), 45 | self.graph.serialize(format='nt')) 46 | self.parent.graph.update(query) 47 | self.flush() 48 | else: 49 | self.meta.generate() 50 | 51 | def delete(self): 52 | """ Delete all statements matching the current context identifier 53 | from the main store. """ 54 | if self.parent.buffered: 55 | query = 'CLEAR SILENT GRAPH %s ;' % self.identifier.n3() 56 | self.parent.graph.update(query) 57 | self.flush() 58 | else: 59 | self.graph.remove((None, None, None)) 60 | 61 | def flush(self): 62 | """ Clear all the pending statements in the local context, without 63 | transferring them to the main store. """ 64 | self._graph = None 65 | 66 | def __str__(self): 67 | return self.identifier 68 | 69 | def __repr__(self): 70 | return '' % self.identifier 71 | -------------------------------------------------------------------------------- /jsongraph/graph.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from rdflib import URIRef, plugin, ConjunctiveGraph 4 | from rdflib.store import Store 5 | from rdflib.plugins.memory import Memory, IOMemory 6 | from jsonschema import RefResolver, ValidationError 7 | 8 | from jsongraph.context import Context 9 | from jsongraph.config import config_validator 10 | from jsongraph.common import GraphOperations 11 | from jsongraph.util import sparql_store, GraphException 12 | 13 | log = logging.getLogger(__name__) 14 | 15 | 16 | class Graph(GraphOperations): 17 | """ Registry for assigning names aliases to certain schemata. """ 18 | 19 | def __init__(self, base_uri=None, resolver=None, config=None, graph=None): 20 | self.config = config or {} 21 | try: 22 | config_validator.validate(self.config) 23 | except ValidationError as ve: 24 | raise GraphException("Invalid config: %r" % ve) 25 | self._resolver = resolver 26 | self._base_uri = base_uri 27 | self._store = None 28 | self._graph = graph 29 | self._buffered = None 30 | self.aliases = {} 31 | for alias, schema in self.config.get('schemas', {}).items(): 32 | self.register(alias, schema) 33 | 34 | @property 35 | def parent(self): 36 | return self 37 | 38 | @property 39 | def base_uri(self): 40 | """ Resolution base for JSON schema. Also used as the default 41 | graph ID for RDF. """ 42 | if self._base_uri is None: 43 | if self._resolver is not None: 44 | self._base_uri = self.resolver.resolution_scope 45 | else: 46 | self._base_uri = 'http://pudo.github.io/jsongraph' 47 | return URIRef(self._base_uri) 48 | 49 | @property 50 | def resolver(self): 51 | """ Resolver for JSON Schema references. This can be based around a 52 | file or HTTP-based resolution base URI. """ 53 | if self._resolver is None: 54 | self._resolver = RefResolver(self.base_uri, {}) 55 | # if self.base_uri not in self._resolver.store: 56 | # self._resolver.store[self.base_uri] = self.config 57 | return self._resolver 58 | 59 | @property 60 | def store(self): 61 | """ Backend storage for RDF data. Either an in-memory store, or an 62 | external triple store controlled via SPARQL. """ 63 | if self._store is None: 64 | config = self.config.get('store', {}) 65 | if 'query' in config and 'update' in config: 66 | self._store = sparql_store(config.get('query'), 67 | config.get('update')) 68 | else: 69 | self._store = plugin.get('IOMemory', Store)() 70 | log.debug('Created store: %r', self._store) 71 | return self._store 72 | 73 | @property 74 | def graph(self): 75 | """ A conjunctive graph of all statements in the current instance. """ 76 | if not hasattr(self, '_graph') or self._graph is None: 77 | self._graph = ConjunctiveGraph(store=self.store, 78 | identifier=self.base_uri) 79 | return self._graph 80 | 81 | @property 82 | def buffered(self): 83 | """ Whether write operations should be buffered, i.e. run against a 84 | local graph before being stored to the main data store. """ 85 | if 'buffered' not in self.config: 86 | return not isinstance(self.store, (Memory, IOMemory)) 87 | return self.config.get('buffered') 88 | 89 | def context(self, identifier=None, meta=None): 90 | """ Get or create a context, with the given identifier and/or 91 | provenance meta data. A context can be used to add, update or delete 92 | objects in the store. """ 93 | return Context(self, identifier=identifier, meta=meta) 94 | 95 | def register(self, alias, uri): 96 | """ Register a new schema URI under a given name. """ 97 | # TODO: do we want to constrain the valid alias names. 98 | if isinstance(uri, dict): 99 | id = uri.get('id', alias) 100 | self.resolver.store[id] = uri 101 | uri = id 102 | self.aliases[alias] = uri 103 | 104 | def get_uri(self, alias): 105 | """ Get the URI for a given alias. A registered URI will return itself, 106 | otherwise ``None`` is returned. """ 107 | if alias in self.aliases.keys(): 108 | return self.aliases[alias] 109 | if alias in self.aliases.values(): 110 | return alias 111 | raise GraphException('No such schema: %r' % alias) 112 | 113 | def get_schema(self, alias): 114 | """ Actually resolve the schema for the given alias/URI. """ 115 | if isinstance(alias, dict): 116 | return alias 117 | uri = self.get_uri(alias) 118 | if uri is None: 119 | raise GraphException('No such schema: %r' % alias) 120 | uri, schema = self.resolver.resolve(uri) 121 | return schema 122 | 123 | def clear(self, context=None): 124 | """ Delete all data from the graph. """ 125 | context = URIRef(context).n3() if context is not None else '?g' 126 | query = """ 127 | DELETE { GRAPH %s { ?s ?p ?o } } WHERE { GRAPH %s { ?s ?p ?o } } 128 | """ % (context, context) 129 | self.parent.graph.update(query) 130 | 131 | def __str__(self): 132 | return self.base_uri 133 | 134 | def __repr__(self): 135 | return '' % self.base_uri 136 | -------------------------------------------------------------------------------- /jsongraph/metadata.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from collections import MutableMapping 3 | 4 | from rdflib import Literal 5 | from rdflib.namespace import RDF 6 | 7 | from jsongraph.vocab import META 8 | 9 | 10 | class MetaData(MutableMapping): 11 | """ This object retains information on the origin and trustworthiness of 12 | a particular subset of the data. """ 13 | 14 | def __init__(self, context, data=None): 15 | self.context = context 16 | self.data = self._load() 17 | self.data.update(data or {}) 18 | if 'created_at' not in self.data: 19 | self.data['created_at'] = datetime.utcnow() 20 | self.saved = False 21 | 22 | def _load(self): 23 | """ Load provenance info from the main store. """ 24 | graph = self.context.parent.graph.get_context(self.context.identifier) 25 | data = {} 26 | for (_, p, o) in graph.triples((self.context.identifier, None, None)): 27 | if not p.startswith(META): 28 | continue 29 | name = p[len(META):] 30 | data[name] = o.toPython() 31 | return data 32 | 33 | def generate(self): 34 | """ Add provenance info to the context graph. """ 35 | t = (self.context.identifier, RDF.type, META.Provenance) 36 | if t not in self.context.graph: 37 | self.context.graph.add(t) 38 | for name, value in self.data.items(): 39 | pat = (self.context.identifier, META[name], None) 40 | if pat in self.context.graph: 41 | self.context.graph.remove(pat) 42 | self.context.graph.add((pat[0], META[name], Literal(value))) 43 | 44 | def __delitem__(self, item): 45 | del self.data[item] 46 | 47 | def __getitem__(self, item): 48 | return self.data[item] 49 | 50 | def __iter__(self): 51 | return iter(self.data) 52 | 53 | def __len__(self): 54 | return len(self.data) 55 | 56 | def __setitem__(self, item, value): 57 | self.data[item] = value 58 | -------------------------------------------------------------------------------- /jsongraph/query.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from uuid import uuid4 3 | from time import time 4 | from collections import OrderedDict 5 | 6 | from normality import slugify 7 | from rdflib import RDF, Literal, URIRef 8 | from sparqlquery import Select, v, func, desc 9 | from mqlparser import OP_EQ, OP_NOT, OP_IN, OP_NIN, OP_LIKE 10 | from mqlparser import QueryNode # noqa 11 | 12 | from jsongraph.vocab import PRED 13 | 14 | log = logging.getLogger(__name__) 15 | 16 | 17 | class Query(object): 18 | """ A query against a fully constructed JSON graph. The query language is 19 | based on Freebase's Metaweb Query Language, a JSON-based query-by-example 20 | method of interrogating graphs. """ 21 | 22 | def __init__(self, context, parent, node): 23 | self.context = context 24 | self.parent = parent 25 | self.node = node 26 | self._results = [] 27 | if node.name is None: 28 | self.id = 'root' 29 | else: 30 | prefix = '_any' if node.name == '*' else node.name 31 | id = '%s_%s' % (prefix, uuid4().hex[:5]) 32 | self.id = slugify(id, '_') 33 | self.var = v[self.id] 34 | 35 | @property 36 | def children(self): 37 | if not hasattr(self, '_children'): 38 | self._children = [] 39 | for child_node in self.node.children: 40 | qb = Query(self.context, self, child_node) 41 | self._children.append(qb) 42 | return self._children 43 | 44 | @property 45 | def predicate_var(self): 46 | return 'pred_' + self.id 47 | 48 | @property 49 | def predicate(self): 50 | if self.node.name == '$schema': 51 | return RDF.type 52 | if self.node.specific_attribute: 53 | return PRED[self.node.name] 54 | return v[self.predicate_var] 55 | 56 | def get_name(self, data): 57 | """ For non-specific queries, this will return the actual name in the 58 | result. """ 59 | if self.node.specific_attribute: 60 | return self.node.name 61 | name = data.get(self.predicate_var) 62 | if str(RDF.type) in [self.node.name, name]: 63 | return '$schema' 64 | if name.startswith(PRED): 65 | name = name[len(PRED):] 66 | return name 67 | 68 | def project(self, q, parent=False): 69 | """ Figure out which attributes should be returned for the current 70 | level of the query. """ 71 | if self.parent: 72 | print (self.parent.var, self.predicate, self.var) 73 | q = q.project(self.var, append=True) 74 | if parent and self.parent: 75 | q = q.project(self.parent.var, append=True) 76 | if not self.node.specific_attribute: 77 | q = q.project(self.predicate, append=True) 78 | for child in self.children: 79 | if child.node.leaf: 80 | q = child.project(q) 81 | return q 82 | 83 | def convert(self, val): 84 | # deref $schema: 85 | if self.node.name == '$schema': 86 | return URIRef(self.context.parent.get_uri(val)) 87 | return Literal(val) 88 | 89 | def filter_value(self, q, var): 90 | if self.node.op == OP_EQ: 91 | q = q.filter(var == self.convert(self.node.value)) 92 | elif self.node.op == OP_NOT: 93 | q = q.filter(var != self.convert(self.node.value)) 94 | elif self.node.op == OP_IN: 95 | q = q.filter(var.in_(*[self.convert(d) for d in self.node.data])) 96 | elif self.node.op == OP_NIN: 97 | exp = var.not_in(*[self.convert(d) for d in self.node.data]) 98 | q = q.filter(exp) 99 | elif self.node.op == OP_LIKE: 100 | regex = '.*%s.*' % self.node.value 101 | q = q.filter(func.regex(var, regex, 'i')) 102 | return q 103 | 104 | def filter(self, q, parents=None): 105 | """ Apply any filters to the query. """ 106 | if self.node.leaf and self.node.filtered: 107 | # TODO: subject filters? 108 | q = q.where((self.parent.var, 109 | self.predicate, 110 | self.var)) 111 | # TODO: inverted nodes 112 | q = self.filter_value(q, self.var) 113 | elif self.parent is not None: 114 | q = q.where((self.parent.var, self.predicate, self.var)) 115 | 116 | if parents is not None: 117 | parents = [URIRef(p) for p in parents] 118 | q = q.filter(self.parent.var.in_(*parents)) 119 | 120 | # TODO: forbidden nodes. 121 | for child in self.children: 122 | q = child.filter(q) 123 | return q 124 | 125 | def nested(self): 126 | """ A list of all sub-entities for which separate queries will 127 | be conducted. """ 128 | for child in self.children: 129 | if child.node.nested: 130 | yield child 131 | 132 | def query(self, parents=None): 133 | """ Compose the query and generate SPARQL. """ 134 | # TODO: benchmark single-query strategy 135 | q = Select([]) 136 | q = self.project(q, parent=True) 137 | q = self.filter(q, parents=parents) 138 | 139 | if self.parent is None: 140 | subq = Select([self.var]) 141 | subq = self.filter(subq, parents=parents) 142 | subq = subq.offset(self.node.offset) 143 | subq = subq.limit(self.node.limit) 144 | subq = subq.distinct() 145 | # TODO: sorting. 146 | subq = subq.order_by(desc(self.var)) 147 | q = q.where(subq) 148 | 149 | # if hasattr(self.context, 'identifier'): 150 | # q._where = graph(self.context.identifier, q._where) 151 | log.debug("Compiled query: %r", q.compile()) 152 | return q 153 | 154 | def base_object(self, data): 155 | """ Make sure to return all the existing filter fields 156 | for query results. """ 157 | obj = {'id': data.get(self.id)} 158 | if self.parent is not None: 159 | obj['$parent'] = data.get(self.parent.id) 160 | return obj 161 | 162 | def execute(self, parents=None): 163 | """ Run the data query and construct entities from it's results. """ 164 | results = OrderedDict() 165 | for row in self.query(parents=parents).execute(self.context.graph): 166 | data = {k: v.toPython() for (k, v) in row.asdict().items()} 167 | id = data.get(self.id) 168 | if id not in results: 169 | results[id] = self.base_object(data) 170 | 171 | for child in self.children: 172 | if child.id in data: 173 | name = child.get_name(data) 174 | value = data.get(child.id) 175 | if child.node.many and \ 176 | child.node.op not in [OP_IN, OP_NIN]: 177 | if name not in results[id]: 178 | results[id][name] = [value] 179 | else: 180 | results[id][name].append(value) 181 | else: 182 | results[id][name] = value 183 | return results 184 | 185 | def collect(self, parents=None): 186 | """ Given re-constructed entities, conduct queries for child 187 | entities and merge them into the current level's object graph. """ 188 | results = self.execute(parents=parents) 189 | ids = results.keys() 190 | for child in self.nested(): 191 | name = child.node.name 192 | for child_data in child.collect(parents=ids).values(): 193 | parent_id = child_data.pop('$parent', None) 194 | if child.node.many: 195 | if name not in results[parent_id]: 196 | results[parent_id][name] = [] 197 | results[parent_id][name].append(child_data) 198 | else: 199 | results[parent_id][name] = child_data 200 | return results 201 | 202 | def run(self): 203 | results = [] 204 | for result in self.collect().values(): 205 | if not self.node.many: 206 | return result 207 | results.append(result) 208 | return results 209 | 210 | def results(self): 211 | t = time() 212 | result = self.run() 213 | t = (time() - t) * 1000 214 | log.debug("Completed: %sms", t) 215 | return { 216 | 'status': 'ok', 217 | 'query': self.node.to_dict(), 218 | 'result': result, 219 | 'time': t 220 | } 221 | -------------------------------------------------------------------------------- /jsongraph/reflect.py: -------------------------------------------------------------------------------- 1 | 2 | def predicates(graph): 3 | """ Return a listing of all known predicates in the registered schemata, 4 | including the schema path they associate with, their name and allowed 5 | types. """ 6 | seen = set() 7 | 8 | def _traverse(binding): 9 | if binding.path in seen: 10 | return 11 | seen.add(binding.path) 12 | 13 | if binding.is_object: 14 | for prop in binding.properties: 15 | yield (binding.path, prop.name, tuple(prop.types)) 16 | for pred in _traverse(prop): 17 | yield pred 18 | elif binding.is_array: 19 | for item in binding.items: 20 | for pred in _traverse(item): 21 | yield pred 22 | 23 | schemas = graph.aliases.values() 24 | schemas.extend(graph.resolver.store) 25 | for schema_uri in graph.aliases.values(): 26 | binding = graph.get_binding(schema_uri, None) 27 | for pred in _traverse(binding): 28 | if pred not in seen: 29 | yield pred 30 | seen.add(pred) 31 | -------------------------------------------------------------------------------- /jsongraph/schemas/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "http://pudo.github.io/graphkit/config.yaml", 3 | "$schema": "http://json-schema.org/draft-04/schema#", 4 | "title": "GraphKit Configuration", 5 | "properties": { 6 | "store": { 7 | "type": "object", 8 | "properties": { 9 | "query": { 10 | "type": "string", 11 | "format": "uri" 12 | }, 13 | "update": { 14 | "type": "string", 15 | "format": "uri" 16 | } 17 | }, 18 | "required": ["query", "update"] 19 | }, 20 | "schemas": { 21 | "type": "object", 22 | "patternProperties": { 23 | "[A-Za-z][A-Za-z0-9_]*[A-Za-z0-9]": { 24 | "oneOf": [ 25 | { 26 | "type": "string", 27 | "format": "uri" 28 | }, 29 | { 30 | "$ref": "http://json-schema.org/draft-04/schema#" 31 | } 32 | ] 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /jsongraph/triplify.py: -------------------------------------------------------------------------------- 1 | from rdflib import RDF 2 | 3 | 4 | def triplify_object(binding): 5 | """ Create bi-directional bindings for object relationships. """ 6 | triples = [] 7 | if binding.uri: 8 | triples.append((binding.subject, RDF.type, binding.uri)) 9 | 10 | if binding.parent is not None: 11 | parent = binding.parent.subject 12 | if binding.parent.is_array: 13 | parent = binding.parent.parent.subject 14 | triples.append((parent, binding.predicate, binding.subject)) 15 | if binding.reverse is not None: 16 | triples.append((binding.subject, binding.reverse, parent)) 17 | 18 | for prop in binding.properties: 19 | _, prop_triples = triplify(prop) 20 | triples.extend(prop_triples) 21 | 22 | return binding.subject, triples 23 | 24 | 25 | def triplify(binding): 26 | """ Recursively generate RDF statement triples from the data and 27 | schema supplied to the application. """ 28 | triples = [] 29 | if binding.data is None: 30 | return None, triples 31 | 32 | if binding.is_object: 33 | return triplify_object(binding) 34 | elif binding.is_array: 35 | for item in binding.items: 36 | _, item_triples = triplify(item) 37 | triples.extend(item_triples) 38 | return None, triples 39 | else: 40 | subject = binding.parent.subject 41 | triples.append((subject, binding.predicate, binding.object)) 42 | if binding.reverse is not None: 43 | triples.append((binding.object, binding.reverse, subject)) 44 | return subject, triples 45 | -------------------------------------------------------------------------------- /jsongraph/util.py: -------------------------------------------------------------------------------- 1 | import url 2 | from rdflib import ConjunctiveGraph, URIRef 3 | 4 | 5 | def is_url(text): 6 | """ Check if the given text looks like a URL. """ 7 | if text is None: 8 | return False 9 | text = text.lower() 10 | return text.startswith('http://') or text.startswith('https://') or \ 11 | text.startswith('urn:') or text.startswith('file://') 12 | 13 | 14 | def safe_uriref(text): 15 | """ Escape a URL properly. """ 16 | url_ = url.parse(text).sanitize().deuserinfo().canonical() 17 | return URIRef(url_.punycode().unicode()) 18 | 19 | 20 | def sparql_store(query_url, update_url): 21 | gs = ConjunctiveGraph('SPARQLUpdateStore') 22 | gs.open((query_url, update_url)) 23 | return gs.store 24 | 25 | 26 | class GraphException(Exception): 27 | pass 28 | -------------------------------------------------------------------------------- /jsongraph/vocab.py: -------------------------------------------------------------------------------- 1 | from uuid import uuid4 2 | 3 | from rdflib import URIRef, Namespace 4 | 5 | PRED = Namespace('urn:p:') 6 | META = Namespace('urn:meta:') 7 | ID = Namespace('urn:id:') 8 | 9 | 10 | def BNode(): 11 | return URIRef(uuid4().urn) 12 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | setup( 5 | name='jsongraph', 6 | version='0.2.2', 7 | description="Library for data integration using a JSON/RDF object graph.", 8 | long_description="", 9 | classifiers=[ 10 | "Development Status :: 3 - Alpha", 11 | "Intended Audience :: Developers", 12 | "License :: OSI Approved :: MIT License", 13 | "Operating System :: OS Independent", 14 | 'Programming Language :: Python :: 2.6', 15 | 'Programming Language :: Python :: 2.7', 16 | 'Programming Language :: Python :: 3.3', 17 | 'Programming Language :: Python :: 3.4' 18 | ], 19 | keywords='schema jsonschema json rdf graph sna networks', 20 | author='Friedrich Lindenberg', 21 | author_email='friedrich@pudo.org', 22 | url='http://github.com/pudo/jsongraph', 23 | license='MIT', 24 | packages=find_packages(exclude=['ez_setup', 'examples', 'test']), 25 | namespace_packages=[], 26 | package_data={ 27 | '': ['jsongraph/schemas/*.json'] 28 | }, 29 | include_package_data=True, 30 | zip_safe=False, 31 | test_suite='nose.collector', 32 | install_requires=[ 33 | 'jsonmapping', 34 | 'mqlparser', 35 | 'url', 36 | 'jsonschema', 37 | 'rdflib', 38 | 'sparqlquery', 39 | 'requests>=2.0', 40 | 'normality', 41 | 'pyyaml', 42 | 'six' 43 | ], 44 | tests_require=[ 45 | 'nose', 46 | 'coverage', 47 | 'wheel', 48 | 'unicodecsv' 49 | ] 50 | ) 51 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pudo/jsongraph/35e4f397dbe69cd5553cf9cb9ab98859c3620f03/tests/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/countries/countries.csv: -------------------------------------------------------------------------------- 1 | euname,modified,linked_country,iso3,iso2,grc,isonum,country,imperitive 2 | ,,Georgia,,,ABK,,Abkhazia,De Facto; Currency 3 | AFGHANISTAN,,,AFG,AF,AFG,004,Afganistan, 4 | ,Added 26th October 2010,Finland,ALA,AX,ALA,248,Åland Islands,Postal 5 | Albania,,,ALB,AL,ALB,008,Albania, 6 | ALGERIA,,,DZA,DZ,ALG,012,Algeria, 7 | ,,United States of America,ASM,AS,AMS,016,American Samoa,Geographical 8 | ANDORRA,,,AND,AD,AND,020,Andorra, 9 | ANGOLA,,,AGO,AO,ANG,024,Angola, 10 | ,,United Kingdom,AIA,AI,ANU,660,Anguilla,Geographical; Postal; Currency; Telephone 11 | ANTIGUA AND BARBUDA,,,ATG,AG,ANT,028,Antigua & Barbuda, 12 | Argentina,,,ARG,AR,ARG,032,Argentina, 13 | Armenia,,,ARM,AM,ARM,051,Armenia, 14 | ARUBA,,Netherlands,ABW,AW,ARU,533,Aruba,Geographical; Postal; Currency; Telephone 15 | Australia,,,AUS,AU,AST,036,Australia, 16 | Austria,,,AUT,AT,AUS,040,Austria, 17 | AZERBAIJAN,,,AZE,AZ,AZE,031,Azerbaijan, 18 | BAHAMAS,,,BHS,BS,BAH,044,Bahamas, 19 | BAHRAIN,,,BHR,BH,BAR,048,Bahrain, 20 | BANGLADESH,,,BGD,BD,BAN,050,Bangladesh, 21 | Barbados,,,BRB,BB,BAB,052,Barbados, 22 | BELARUS,,,BLR,BY,BEO,112,Belarus, 23 | Belgium,,,BEL,BE,BEL,056,Belgium, 24 | BELIZE,,,BLZ,BZ,BEI,084,Belize, 25 | Benin,,,BEN,BJ,BEN,204,Benin, 26 | BERMUDA,,United Kingdom,BMU,BM,BER,060,Bermuda,Geographical; Postal; Currency; Telephone 27 | BHUTAN,,,BTN,BT,BHU,064,Bhutan, 28 | BOLIVIA,,,BOL,BO,BOL,068,Bolivia, 29 | ,ISO codes added 28th Dec. 2010,Netherlands,BES,BQ,BON,535,Bonaire,Geographical; Postal; Currency; Telephone 30 | Bosnia-Herzegovina,,,BIH,BA,BOS,070,Bosnia-Herzegovina, 31 | BOTSWANA,,,BWA,BW,BOT,072,Botswana, 32 | Brazil,,,BRA,BR,BRA,076,Brazil, 33 | ,,"United Kingdom, United States of America",IOT,IO,BIO,086,British Indian Ocean Territory,Geographical; Postal; Telephone 34 | British Virgin Islands,,United Kingdom,VGB,VG,BVI,092,British Virgin Islands,Geographical; Postal; Currency; Telephone 35 | BRUNEI,,,BRN,BN,BRU,096,Brunei Darussalam, 36 | Bulgaria,,,BGR,BG,BUL,100,Bulgaria, 37 | BURKINA FASO,,,BFA,BF,BUK,854,Burkina Faso, 38 | BURUNDI,,,BDI,BI,BUU,108,Burundi, 39 | Cambodia,,,KHM,KH,CAM,116,Cambodia, 40 | Cameroon,,,CMR,CM,CAE,120,Cameroon, 41 | Canada,,,CAN,CA,CAN,124,Canada, 42 | CAPE VERDE,,,CPV,CV,CAP,132,Cape Verde Islands, 43 | ,,United Kingdom,CYM,KY,CAY,136,Cayman Islands,Geographical; Postal; Currency; Telephone 44 | "CENTRAL AFRICAN, REPUBLIC",,,CAF,CF,CEN,140,Central African Republic, 45 | Chad,,,TCD,TD,CHA,148,Chad, 46 | CHILE,,,CHL,CL,CHI,152,Chile, 47 | CHINA,,,CHN,CN,CHN,156,China, 48 | ,,Australia,CXR,CX,CHR,162,Christmas Island,Geographical 49 | ,,Australia,CCK,CC,COC,166,Cocos (Keeling) Islands,Geographical 50 | Colombia,,,COL,CO,CLO,170,Colombia, 51 | COMOROS,,,COM,KM,COM,174,Comoros, 52 | CONGO,,,COG,CG,CNG,178,Congo (Brazzaville), 53 | "CONGO, DEMOCRATIC REPUBLIC OF",,,ZAR,CD,ZAI,180,Congo (Kinshasa), 54 | COOK ISLANDS,,New Zealand,COK,CK,COO,184,Cook Islands,Geographical; Postal; Telephone 55 | Costa Rica,,,CRI,CR,COS,188,Costa Rica, 56 | Croatia,,,HRV,HR,CRO,191,Croatia, 57 | CUBA,,,CUB,CU,CUB,192,Cuba, 58 | ,ISO codes added 28th Dec. 2010,Netherlands,CUW,CW,CUR,531,Curaçao,Geographical; Postal; Currency; Telephone 59 | Cyprus,,,CYP,CY,CYP,196,Cyprus, 60 | Czech Republic,,,CZE,CZ,CZE,203,Czech Republic, 61 | Denmark,,,DNK,DK,DEN,208,Denmark, 62 | DJIBOUTI,,,DJI,DJ,DJI,262,Djibouti, 63 | DOMINIQUE,,,DMA,DM,DOI,212,Dominica, 64 | Dominican Republic,,,DOM,DO,DOM,214,Dominican Republic, 65 | EAST TIMOR,,,TLS,TL,ETI,626,East Timor, 66 | Ecuador,,,ECU,EC,ECU,218,Ecuador, 67 | EGYPT,,,EGY,EG,EGY,818,Egypt, 68 | El Salvador,,,SLV,SV,ELS,222,El Salvador, 69 | EQUATORIAL GUINEA,,,GNQ,GQ,EQA,226,Equatorial Guinea, 70 | ERITREA,,,ERI,ER,ERI,232,Eritrea, 71 | Estonia,,,EST,EE,EST,233,Estonia, 72 | ETHIOPIA,,,ETH,ET,ETH,231,Ethiopia, 73 | FAROE ISLANDS,,,FRO,FO,FAE,234,Faeroe Islands, 74 | ,,United Kingdom,FLK,FK,FAL,238,Falkland Islands,Geographical; Postal; Currency; Telephone 75 | FIJI,,,FJI,FJ,FIJ,242,Fiji, 76 | Finland,,,FIN,FI,FIN,246,Finland, 77 | France,,,FRA,FR,FRA,250,France, 78 | FRENCH GUYANA,,France,GUF,GF,FGU,254,French Guiana,Geographical; Telephone 79 | FRENCH POLYNESIA,Corrected 13th November 2010,France,PYF,PF,FPO,258,French Polynesia,Geographical; Currency; Telephone 80 | ,,France,ATF,TF,FST,260,French Southern Territories,Geographical; Postal; Telephone 81 | GABON,,,GAB,GA,GAB,266,Gabon, 82 | GAMBIA,,,GMB,GM,GAM,270,Gambia, 83 | GEORGIA,,,GEO,GE,GEO,268,Georgia, 84 | Germany,,,DEU,DE,GER,276,Germany, 85 | Ghana,,,GHA,GH,GHA,288,Ghana, 86 | GIBRALTAR,,United Kingdom,GIB,GI,GIB,292,Gibralter,Geographical; Postal; Currency; Telephone 87 | Greece,,,GRC,GR,GRE,300,Greece, 88 | GREENLAND,,Denmark,GRL,GL,GRN,304,Greenland,Geographical; Postal; Telephone 89 | GRENADA,,,GRD,GD,GRA,308,Grenada, 90 | GUADELOUPE,,France,GLP,GP,GUD,312,Guadeloupe,Geographical; Postal; Telephone 91 | ,,United States of America,GUM,GU,GUM,316,Guam,Geographical 92 | Guatemala,,,GTM,GT,GUA,320,Guatemala, 93 | ,,United Kingdom,GGY,GG,GUE,831,Guernsey,Postal 94 | Guinea,,,GIN,GN,GUI,324,Guinea, 95 | GUINEA BISSAU,,,GNB,GW,GUB,624,Guinea-Bissau, 96 | GUYANA,,,GUY,GY,GUY,328,Guyana, 97 | HAITI,,,HTI,HT,HAI,332,Haiti, 98 | HOLY SEE (VATICAN CITY STATE),,,VAT,VA,VAT,336,Holy See, 99 | Honduras,,,HND,HN,HON,340,Honduras, 100 | Hong Kong,,China,HKG,HK,HOK,344,Hong Kong,Postal; Currency; Telephone 101 | Hungary,,,HUN,HU,HUN,348,Hungary, 102 | Iceland,,,ISL,IS,ICE,352,Iceland, 103 | India,,,IND,IN,IND,356,India, 104 | INDONESIA,,,IDN,ID,INO,360,Indonesia, 105 | "IRAN, ISLAMIC REPUBLIC OF",,,IRN,IR,IRA,364,Iran, 106 | IRAQ,,,IRQ,IQ,IRQ,368,Iraq, 107 | Ireland,,,IRL,IE,IRE,372,Ireland, 108 | ISLE OF MAN,,United Kingdom,IMN,IM,ISL,833,Isle of Man,Postal 109 | Israel,,,ISR,IL,ISR,376,Israel, 110 | Italy,,,ITA,IT,ITA,380,Italy, 111 | COTE D'IVOIRE,,,CIV,CI,IVO,384,Ivory Coast, 112 | Jamaica,,,JAM,JM,JAM,388,Jamaica, 113 | Japan,,,JPN,JP,JAP,392,Japan, 114 | JERSEY,,United Kingdom,JEY,JE,JER,832,Jersey,Postal 115 | JORDAN,,,JOR,JO,JOR,400,Jordan, 116 | KAZAKHSTAN,,,KAZ,KZ,KAZ,398,Kazakhstan, 117 | Kenya,,,KEN,KE,KEN,404,Kenya, 118 | KIRIBATI,,,KIR,KI,KII,296,Kiribati, 119 | ,,Serbia,,,KOS,,Kosovo,Postal; Currency; Telephone 120 | KUWAIT,,,KWT,KW,KUW,414,Kuwait, 121 | KYRGYZSTAN,,,KGZ,KG,KIR,417,Kyrgyzstan, 122 | "LAOS, PEOPLE'S DEMOCRATIC REPUBLIC",,,LAO,LA,LAO,418,Laos, 123 | Latvia,,,LVA,LV,LAT,428,Latvia, 124 | LEBANON,,,LBN,LB,LEB,422,Lebanon, 125 | LESOTHO,,,LSO,LS,LES,426,Lesotho, 126 | LIBERIA,,,LBR,LR,LIR,430,Liberia, 127 | LIBYA,,,LBY,LY,LIB,434,Libya, 128 | LIECHTENSTEIN,,,LIE,LI,LIE,438,Liechtenstein, 129 | LITUANIA,,,LTU,LT,LIT,440,Lithuania, 130 | Luxembourg,,,LUX,LU,LUX,442,Luxembourg, 131 | MACAO,,China,MAC,MO,MCA,446,Macau,Postal; Currency; Telephone 132 | "MACEDONIA, FORMER YUGOSLAV REPUBLIC OF",,,MKD,MK,MCE,807,Macedonia, 133 | MADAGASCAR,,,MDG,MG,MAD,450,Madagascar, 134 | MALAWI,,,MWI,MW,MAW,454,Malawi, 135 | Malaysia,,,MYS,MY,MAA,458,Malaysia, 136 | MALDIVES,,,MDV,MV,MAV,462,Maldives, 137 | MALI,,,MLI,ML,MAI,466,Mali, 138 | Malta,,,MLT,MT,MAL,470,Malta, 139 | MARSHALL ISLANDS,,,MHL,MH,MAR,584,Marshall Islands, 140 | MARTINIQUE,,France,MTQ,MQ,MAN,474,Martinique,Geographical; Postal; Telephone 141 | Mauritania,,,MRT,MR,MAU,478,Mauritania, 142 | MAURITIUS,,,MUS,MU,MAT,480,Mauritius, 143 | MAYOTTE,,France,MYT,YT,MAY,175,Mayotte,Geographical; Postal; Telephone 144 | Mexico,,,MEX,MX,MEX,484,Mexico, 145 | "MICRONESIA, FEDERATED STATES OF",,,FSM,FM,MIC,583,Micronesia, 146 | "MOLDOVA, REPUBLIC OF",,,MDA,MD,MOL,498,Moldova, 147 | Monaco,,,MCO,MC,MON,492,Monaco, 148 | MONGOLIA,,,MNG,MN,MOG,496,Mongolia, 149 | Montenegro,,,MNE,ME,MOE,499,Montenegro, 150 | ,,United Kingdom,MSR,MS,MOT,500,Montserrat,Geographical; Postal; Currency; Telephone 151 | Morocco,,,MAR,MA,MOR,504,Morocco, 152 | Mozambique,,,MOZ,MZ,MOZ,508,Mozambique, 153 | Myanmar,,,MMR,MM,BUR,104,Myanmar, 154 | ,,Azerbaijan,,,NAG,,Nagorno-Karabakh,De Facto 155 | NAMIBIA,,,NAM,NA,NAM,516,Namibia, 156 | NAURU,,,NRU,NR,NAU,520,Nauru, 157 | NEPAL,,,NPL,NP,NEP,524,Nepal, 158 | Netherlands Antilles,,,ANT,AN,NAN,530,Netherlands Antilles,Legacy 159 | Netherlands,,,NLD,NL,NET,528,Netherlands, 160 | NEW CALEDONIA,,France,NCL,NC,NCA,540,New Caledonia,Geographical; Postal; Currency; Telephone 161 | NEW ZEALAND,,,NZL,NZ,NEW,554,New Zealand, 162 | Nicaragua,,,NIC,NI,NIC,558,Nicaragua, 163 | Niger,,,NER,NE,NIE,562,Niger, 164 | Nigeria,,,NGA,NG,NIG,566,Nigeria, 165 | NIUE,,,NIU,NU,NIU,570,Niue, 166 | ,,Australia,NFK,NF,NOF,574,Norfolk Island,Geographical; Telephone 167 | "KOREA, PEOPLE'S DEMOCRATIC REPUBLIC OF",,,PRK,KP,NKO,408,North Korea, 168 | ,,Cyprus,,,NCY,,Northern Cyprus,De Facto; Postal; Currency; Telephone 169 | ,,United States of America,MNP,MP,NMI,580,Northern Mariana Islands,Geographical 170 | Norway,,,NOR,NO,NOR,578,Norway, 171 | OMAN,,,OMN,OM,OMA,512,Oman, 172 | Pakistan,,,PAK,PK,PAK,586,Pakistan, 173 | PALAU,,,PLW,PW,PAL,585,Palau, 174 | PALESTINIAN OCCUPIED TERRITORY,,Israel,PSE,PS,PLA,275,Palestinian Territories, 175 | PANAMA,,,PAN,PA,PAN,591,Panama, 176 | PAPUA NEW GUINEA,,,PNG,PG,PAP,598,Papua New Guinea, 177 | PARAGUAY,,,PRY,PY,PAR,600,Paraguay, 178 | PERU,,,PER,PE,PER,604,Peru, 179 | Philippines,,,PHL,PH,PHI,608,Philippines, 180 | ,,United Kingdom,PCN,PN,PIT,612,Pitcairn Islands,Geographical; Postal; Currency; Telephone 181 | Poland,,,POL,PL,POL,616,Poland, 182 | Portugal,,,PRT,PT,POR,620,Portugal, 183 | PUERTO RICO,,United States,PRI,PR,PUE,630,Puerto Rico,Geographical 184 | ,,Somalia,,,PUN,,Puntland,De Facto 185 | QATAR,,,QAT,QA,QAT,634,Qatar, 186 | Romania,,,ROU,RO,ROM,642,Romania, 187 | "RUSSIA, FEDERATION OF",,,RUS,RU,RUS,643,Russia, 188 | RUANDA,,,RWA,RW,RWA,646,Rwanda, 189 | REUNION,,France,REU,RE,REU,638,Réunion,Geographical; Postal; Currency; Telephone 190 | ,ISO codes added 28th Dec. 2010,The Netherlands,BES,BQ,SAB,535,Saba,Geographical; Postal; Currency; Telephone 191 | ,,France,BLM,BL,STB,652,Saint Barthélemy,Geographical; Postal; Currency; Telephone 192 | SAINT KITTS AND NEVIS,,,KNA,KN,STC,659,Saint Christopher & Nevis, 193 | ,,United Kingdom,SHN,SH,STH,654,Saint Helena,Geographical; Postal; Currency; Telephone 194 | SAINT LUCIA,,,LCA,LC,STL,662,Saint Lucia, 195 | ,,France,MAF,MF,STM,663,Saint Martin,Geographical; Postal; Currency; Telephone 196 | ,,France,SPM,PM,SPM,666,Saint Pierre & Miquelon,Geographical; Postal; Currency; Telephone 197 | SAINT VINCENT AND THE GRENADINES,,,VCT,VC,STV,670,Saint Vincent & The Grenadines, 198 | SAMOA,,,WSM,WS,WSM,882,Samoa, 199 | SAINT MARINO,,,SMR,SM,SAN,674,San Marino, 200 | SAO TOME AND PRINCIPE,,,STP,ST,SAO,678,Sao Tome & Principe, 201 | SUADI ARABIA,,,SAU,SA,SAU,682,Saudi Arabia, 202 | Senegal,,,SEN,SN,SEN,686,Senegal, 203 | Serbia,,,SRB,RS,YUG,688,Serbia, 204 | SEYCHELLES,,,SYC,SC,SEY,690,Seychelles, 205 | SIERRA LEONE,,,SLE,SL,SIE,694,Sierra Leone, 206 | SINGAPORE,,,SGP,SG,SIN,702,Singapore, 207 | ,ISO codes added 28th Dec. 2010,The Netherlands,BES,BQ,STE,535,Sint Eustatius,Geographical; Postal; Currency; Telephone 208 | ,ISO codes added 28th Dec. 2010,The Netherlands,SXM,SX,SMA,534,Sint Maarten,Geographical; Postal; Currency; Telephone 209 | Slovakia,,,SVK,SK,SLO,703,Slovakia, 210 | Slovenia,,,SVN,SI,SLV,705,Slovenia, 211 | SOLOMON ISLANDS,,,SLB,SB,SOL,090,Solomon Islands, 212 | SOMALIA,,,SOM,SO,SOM,706,Somalia, 213 | ,,Somalia,SOM,SO,SOA,706,Somaliland,De Facto 214 | South Africa,,,ZAF,ZA,SAF,710,South Africa, 215 | ,,United Kingdom,SGS,GS,SGE,239,South Georgia & The South Sandwish Islands,Geographical; Postal; Currency; Telephone 216 | "KOREA, REPUBLIC OF",,,KOR,KR,SKO,418,South Korea, 217 | ,,Georgia,,,SOS,,South Ossetia,De Facto; Currency 218 | SOUTH SUDAN,Added 22nd February 2011. ISO codes added 18th August 2011.,,SSD,SS,SSU,,South Sudan, 219 | Spain,,,ESP,ES,SPA,724,Spain, 220 | SRI LANKA,,,LKA,LK,SRI,144,Sri Lanka, 221 | Sudan,,,SDN,SD,SUD,736,Sudan, 222 | SURINAM,,,SUR,SR,SUR,740,Suriname, 223 | SWAZILAND,,,SWZ,SZ,SWA,748,Swaziland, 224 | Sweden,,,SWE,SE,SWE,752,Sweden, 225 | Switzerland,,,CHE,CH,SWI,756,Switzerland, 226 | "SYRIA, ARAB REPUBLIC",,,SYR,SY,SYR,760,Syria, 227 | TAIWAN,,China,TWN,TW,TAI,158,Taiwan, 228 | TAJIKISTAN,,,TJK,TJ,TAJ,762,Tajikistan, 229 | "TANZANIA, UNITED RE UBLIC OF",,,TZA,TZ,TAN,834,Tanzania, 230 | THAILAND,,,THA,TH,THA,764,Thailand, 231 | TOGO,,,TGO,TG,TOG,768,Togo, 232 | ,,New Zealand,TKL,TK,TOK,772,Tokelau,Geographical; Postal; Telephone 233 | TONGA,,,TON,TO,TON,776,Tonga, 234 | ,,Moldova,,,TRA,,Transdniestria,De Facto 235 | TRINIDAD AND TOBAGO,,,TTO,TT,TRI,780,Trinidad & Tobago, 236 | Tunisia,,,TUN,TN,TUN,788,Tunisia, 237 | Turkey,,,TUR,TR,TUR,792,Turkey, 238 | TURKMENISTAN,,,TKM,TM,TUK,795,Turkmenistan, 239 | ,,United Kingdom,TCA,TC,TUC,796,Turks & Caicos Islands,Geographical; Postal; Currency; Telephone 240 | TUVALU,,,TUV,TV,TUV,798,Tuvalu, 241 | Uganda,,,UGA,UG,UGA,800,Uganda, 242 | Ukraine,,,UKR,UA,UKR,804,Ukraine, 243 | United Arab Emirates,,,ARE,AE,UAE,784,United Arab Emirates, 244 | United Kingdom,,,GBR,GB,UNI,826,United Kingdom, 245 | United States,,,USA,US,USA,840,United States, 246 | US VIRGIN ISLANDS,,United States of America,VIR,VI,VIR,850,United States Virgin Islands,Geographical 247 | URUGUAY,,,URY,UY,URU,858,Uruguay, 248 | UZBEKISTAN,,,UZB,UZ,UZB,860,Uzbekistan, 249 | VANUATU,,,VUT,VU,VAN,548,Vanuatu, 250 | VENEZUELA,,,VEN,VE,VEN,862,Venezuela, 251 | VIETNAM,,,VNM,VN,VIE,704,Vietnam, 252 | ,,France,WLF,WF,WAL,876,Wallis & Futuna,Geographical; Postal; Currency; Telephone 253 | WESTERN SAHARA,,Morocco,ESH,EH,WSA,732,Western Sahara,Political 254 | Yemen,,,YEM,YE,YEM,887,Yemen, 255 | ZAMBIA,,,ZMB,ZM,ZAM,894,Zambia, 256 | ZIMBABWE,,,ZWE,ZW,ZIM,716,Zimbabwe, 257 | -------------------------------------------------------------------------------- /tests/fixtures/countries/mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "$ref": "#/definitions/country" 4 | }, 5 | "mapping": { 6 | "name": { 7 | "column": "country" 8 | }, 9 | "iso2": { 10 | "column": "iso2" 11 | }, 12 | "iso3": { 13 | "column": "iso3" 14 | } 15 | }, 16 | "definitions": { 17 | "country": { 18 | "title": "Country", 19 | "type": "object", 20 | "properties": { 21 | "name": { 22 | "type": "string", 23 | "minLength": 2, 24 | "maxLength": 500 25 | }, 26 | "iso2": { 27 | "type": "string", 28 | "minLength": 2, 29 | "maxLength": 2 30 | }, 31 | "iso3": { 32 | "type": "string", 33 | "minLength": 3, 34 | "maxLength": 3 35 | } 36 | }, 37 | "required": ["name"] 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/fixtures/everypol/mapping.json: -------------------------------------------------------------------------------- 1 | { 2 | "schema": { 3 | "$ref": "http://www.popoloproject.com/schemas/person.json#" 4 | }, 5 | "mapping": { 6 | "id": { 7 | "column": "id" 8 | }, 9 | "name": { 10 | "column": "name" 11 | }, 12 | "image": { 13 | "column": "image" 14 | }, 15 | "contact_details": [ 16 | { 17 | "optional": true, 18 | "mapping": { 19 | "value": { 20 | "column": "email" 21 | }, 22 | "type": { 23 | "default": "email" 24 | } 25 | } 26 | }, 27 | { 28 | "optional": true, 29 | "mapping": { 30 | "value": { 31 | "column": "twitter" 32 | }, 33 | "type": { 34 | "default": "twitter" 35 | } 36 | } 37 | } 38 | ], 39 | "memberships": [ 40 | { 41 | "mapping": { 42 | "person_id": { 43 | "column": "id" 44 | }, 45 | "role": { 46 | "default": "Member of Parliament" 47 | }, 48 | "id": { 49 | "columns": ["id", "group_id"], 50 | "transforms": ["strip", "join", "hash"] 51 | }, 52 | "organization": { 53 | "mapping": { 54 | "id": { 55 | "column": "group_id", 56 | "default": "no-party", 57 | "transforms": ["coalesce", "slugify"] 58 | }, 59 | "name": { 60 | "column": "group", 61 | "default": "No Party" 62 | } 63 | } 64 | } 65 | } 66 | } 67 | ] 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/fixtures/everypol/term-26.csv: -------------------------------------------------------------------------------- 1 | id,name,email,twitter,group,group_id,area,chamber,term,start_date,end_date,image,gender 2 | anton-de-waal-alberts,Adv Anton De Waal Alberts,aalberts@parliament.gov.za,,Freedom Front +,"Vryheidsfront Plus, FF+",Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/60/84/6084e931d6b15446833c08c2bf56c7eb.jpg, 3 | tshililo-michael-masutha,Adv Michael Masutha,mmasutha@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0e/d4/0ed49074a8b2683c06ad1b7bb4ac2d90.jpg, 4 | amy-tuck,Amy Tuck,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6b/f0/6bf0e4af017b427cdbfda695524db809.jpg, 5 | pakishe-aaron-motsoaledi,Dr Aaron Motsoaledi,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/67/54/67549411c6e6d373516775b3159de1b8.jpg, 6 | annelie-lotriet,Dr Annelie Lotriet,Whippery.Secretary@da.org.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9c/d5/9cd5d2029bfe1e462776fab98e20d066.jpg, 7 | bantubonke-harrington-holomisa,Dr Bantu Holomisa,bholomisa@parliament.gov.za,,United Democratic Movement,UDM,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d6/0e/d60e5628af2db50c92853803a8b0302a.jpg, 8 | celiwe-qhamkile-madlopha,Dr Celiwe Qhamkile Madlopha,cmadlopha@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/05/77/05774e333174cc7b6d21b7668f98acc2.jpg, 9 | cornelius-petrus-mulder,Dr Cornelius Petrus Mulder,cmulder@parliament.gov.za,,Freedom Front +,"Vryheidsfront Plus, FF+",,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bc/4a/bc4aceadea367554338b22ee74f255f5.jpg, 10 | dion-travers-george,Dr Dion George,dtg@wol.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6a/2d/6a2d7da9220358649416da7d5ce86b62.jpg, 11 | gerhardus-willem-koornhof,Dr Gerhardus Willem Koornhof,gkoornhof@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/50/a0/50a02d36bc056e07bc9033d4d2b9e5ef.jpg, 12 | heinrich-cyril-volmink,Dr Heinrich Cyril Volmink,hvolmink@gmail.com,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4a/a8/4aa8c9eeea1835a0c7259b7ca532da80.jpg, 13 | mathume-joseph-phaahla,Dr Joseph Phaahla,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/13/81/13817022f16910bff2391d35ae945afe.jpg, 14 | makhosi-busisiwe-khoza,Dr Makhosi Busisiwe Khoza,,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4f/ad/4fad51024529ed6f09047aa8c38a0634.jpg, 15 | mathole-serofo-motshekga,Dr Mathole Serofo Motshekga,mmotshekga@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4d/19/4d191d136d45b8636042bb041d57d6e6.jpg, 16 | michael-john-cardo,Dr Michael John Cardo,mikecardo@yahoo.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e6/42/e642a0291e704d08fc8b0a2428004c35.jpg, 17 | monwabisi-bevan-goqwana,Dr Monwabisi Bevan Goqwana,mgoqwana@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a1/0d/a10d3389d08b20eaa45db8746c7909fb.jpg, 18 | patrick-maesela,Dr Patrick Maesela,pmaesela@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/65/5a/655a8cfaf9a1e03c4bd4d5154209efb4.jpg, 19 | petrus-johannes-groenewald,Dr Petrus Johannes Groenewald,pjgr@vodamail.co.za,,Freedom Front +,"Vryheidsfront Plus, FF+",,National Assembly,26,,,http://www.pa.org.za/media_root/cache/36/93/3693f19826fc1455fc77851d733a503e.jpg, 20 | pieter-willem-adriaan-mulder,Dr Pieter Willem Adriaan Mulder,pmulder@parliament.gov.za,,Freedom Front +,"Vryheidsfront Plus, FF+",,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e1/79/e1799c31cc784748bf9fa88440ce9ecc.jpg, 21 | wilmot-godfrey-james,Dr Wilmot Godfrey James,wjames@parliament.gov.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0a/21/0a2100eba6e11fb0ed20b47ef878fa4b.jpg, 22 | zukile-luyenge,Dr Zukile Luyenge,zluyenge@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d6/b7/d6b7ae33352f65f5c598ec36a6348ef9.jpg, 23 | hildah-vangile-nyambi,Hildah Vangile Nyambi,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 24 | hlayiseka-crucief-chewane,Hlayiseka Crucief Chewane,,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 25 | sango-patekile-holomisa,Inkosi Patekile Holomisa,sholomisa@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/87/b1/87b1698af27d1bbeecd20390bf22b6e9.jpg, 26 | johannes-mothibeli-koekoe-mahumapelo,Johannes Mothibeli Koekoe Mahumapelo,,,Agang South Africa,AGANG SA,,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 27 | loyiso-khanyisa-bunye-mpumlwana,Loyiso Khanyisa Bunye Mpumlwana,lmpumlwana@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d6/7d/d67d2b414682e93e366973b602f7f2a9.jpg, 28 | luthando-richmond-mbinda,Luthando Richmond Mbinda,,,Pan Africanist Congress of Azania,PAC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/96/3f/963f6b919f022c20dde885f5e94c9e27.jpg, 29 | martha-phindile-mmola,Martha Phindile Mmola,mmmola@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/75/b7/75b744ab61bd673a414db3aa82069c6c.jpg, 30 | mkhacani-joseph-maswanganyi,Mkhacani Joseph Maswanganyi,,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 31 | abinaar-modikela-matlhoko,Mr Abinaar Modikela Matlhoko,amatlhoko@parliament.gov.za,,Economic Freedom Fighters,EFF,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2e/bf/2ebf6a7915ff7f7a785a0227a23a5f02.jpg, 32 | abram-molefe-mudau,Mr Abram Molefe Mudau,amudau@parliament.gov.za,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/3d/5c/3d5cdd382a4913f5dea4f14705b97437.jpg, 33 | ahmed-munzoor-shaik-emam,Mr Ahmed Munzoor Shaik Emam,mshaik-emam@parliament.gov.za,,National Freedom Party,NFP,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e7/25/e7258005fce15fa91fb6d85d3adbc74c.jpg, 34 | alan-ross-mcloughlin,Mr Alan Ross Mcloughlin,alanmcloughlin250@gmail.com,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fc/fb/fcfb05f4d65c1c15cb5411e2e4072b19.jpg, 35 | alfred-mkhipheni-mpontshane,Mr Alfred Mkhipheni Mpontshane,ampontshane@parliament.gov.za,,Inkatha Freedom Party,IFP,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4a/cd/4acd830170ecc32ef95ff71fc4f3771c.jpg, 36 | amos-fish-mahlalela,Mr Amos Fish Mahlalela,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/55/66/556620404ec6b3d25332ee8a230b1584.jpg, 37 | andrew-frans-madella,Mr Andrew Frans Madella,,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d9/8a/d98a555a17905b702e7bc3104404eac6.jpg, 38 | andrew-grant-whitfield,Mr Andrew Grant Whitfield,whitfield.andrew@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ef/77/ef777c59e8a52d4b6b71b77cdbfc7995.jpg, 39 | andricus-pieter-van-der-westhuizen,Mr Andricus Pieter Van der Westhuizen,anvanderwesthuizen@parliament.gov.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/80/be/80beab2ad609b18983eac70cde90fd14.jpg, 40 | andries-carl-nel,Mr Andries Nel,Andries.Nel@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f0/d0/f0d0c88e85fca0d620faf0c4d7b6f3ba.jpg, 41 | a-m-figlan,Mr Archibold Mzuvukile Figlan,afiglan@wcpp.gov.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4d/20/4d20122bb4ed3559e291635bfd55e0c5.jpg, 42 | benedict-anthony-duke-martins,Mr Benedict Anthony Duke Martins,bmartins@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/61/59/6159d61694e5b5e62dd126f64acd6fc5.jpg, 43 | bennet-mzwenqaba-bhanga,Mr Bennet Mzwenqaba Bhanga,nbhanga@gmail.com,,Democratic Alliance,DA,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5f/2c/5f2c73bc580af39b2a0239cd8dad47af.jpg, 44 | bhekokwakhe-hamilton-cele,Mr Bheki Cele,,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c1/2c/c12c07198463c38fa884e3d00c084019.jpg, 45 | bhekiziswe-abram-radebe,Mr Bhekizizwe Abram Radebe,bradebe@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f8/b1/f8b148bfd476b1346037faad3a945aef.jpg, 46 | bongani-michael-mkongi,Mr Bongani Michael Mkongi,,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/cb/11/cb1127e742d7f61e3e6b8d5a8b3486ae.jpg, 47 | bongani-thomas-bongo,Mr Bongani Thomas Bongo,bbongo@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e8/84/e8843e48b4b45852f4af78ff8d718804.jpg, 48 | bonginkosi-emmanuel-nzimande,Mr Bonginkosi “Blade” Nzimande,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/df/5c/df5c5e701ecfe10e4d307a1001a58a85.jpg, 49 | bonisile-nesi,Mr Bonisile Alfred Nesi,bnesi@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b4/78/b478bc6a3f4804fe9f7e361d42eb5348.jpg, 50 | buoang-lemias-mashile,Mr Buoang Lemias Mashile,bmashile@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ae/b0/aeb025a277f3119fd93ea9bbb7e5d7b5.jpg, 51 | kgwaridi-buti-manamela,Mr Buti Manamela,kmanamela@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/04/4d/044dd491101dc8c20d4a01725b555db7.jpg, 52 | cameron-mackenzie,Mr Cameron Mackenzie,cameron@sentinel360.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/10/32/1032dc076a98df79a34c05761f7d789f.jpg, 53 | cassel-charlie-mathale,Mr Cassel Charlie Mathale,cmathale@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/aa/c7/aac7798d0a6ac253ef45a75032b6e97b.jpg, 54 | cedric-thomas-frolick,Mr Cedric Thomas Frolick,cfrolick@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a4/74/a47479f30bb209c35082072820140e93.jpg, 55 | charles-danny-kekana,Mr Charles Danny Kekana,dkekana@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/50/13/50137268b6a67de560e19c1769afb631.jpg, 56 | choloane-david-matsepe,Mr Choloane David Matsepe,dmatsepe@parliament.gov.za,,Democratic Alliance,DA,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f7/05/f705fc5b364a38dc50c27aa63fd9daea.jpg, 57 | christian-hans-heinrich-hunsinger,Mr Christian Hans Heinrich Hunsinger,chunsinger33@gmail.com,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/62/de/62deb7f08a44ac518fe76d7717caf5b7.jpg, 58 | humphrey-maxegwana,Mr Comely Humphrey Maqocwa Maxegwana,hmaxhegwana@ecleg.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c7/2c/c72c698af94a29cc965a93788be10d2c.jpg, 59 | matamela-cyril-ramaphosa,Mr Cyril Ramaphosa,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/43/7e/437e8e6c02846d67ad9340fcbe9ff935.jpg, 60 | dalton-hlamalani-khosa,Mr Dalton Hlamalani Khosa,hkhosa@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e0/0f/e00f26cb013ac21d2bf5ac140c239f08.jpg, 61 | darren-bergman,Mr Darren Bergman,bergman.darren@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a7/53/a75377fdc1dd704a50650d7659f25a0c.jpg, 62 | david-christie-ross,Mr David Christie Ross,dross@parliament.gov.za,,Democratic Alliance,DA,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/11/d4/11d4133c653264b8a97ef3fb70759f4b.jpg, 63 | david-douglas-van-rooyen,Mr David Douglas Des Van Rooyen,dvanrooyen@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/38/b9/38b9fe3aa58fe84bef2bf3965bbec4e1.jpg, 64 | david-john-maynier,Mr David John Maynier,david@da-mp.org.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/49/1d/491d1af6744823a7456e32428ecc6925.jpg, 65 | mbangiseni-david-mahlobo,Mr David Mahlobo,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4c/57/4c572ecadedaca80a3c357a3f7544a88.jpg, 66 | dean-william-macpherson,Mr Dean William Macpherson,dean@eduform.co.za,,Democratic Alliance,DA,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/55/b3/55b368694512884ee9cf66d204e758a4.jpg, 67 | dumisani-dennis-gamede,Mr Dennis Dumisani Gamede,dgamede@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b9/58/b958ebdd098c1dec87302ca1affa21a9.jpg, 68 | derek-andre-hanekom,Mr Derek Hanekom,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/18/a3/18a348edfd13409c12a57ccf9c1a9979.jpg, 69 | derick-mnguni,Mr Derick Mnguni,dmnguni@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4a/d0/4ad04914092ff84d343117ba46e113e2.jpg, 70 | derrick-america,Mr Derrick America,damerica@telkomsa.net,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c8/05/c805ef22553e159e6a541869d654c0b4.jpg, 71 | diliza-lucky-twala,Mr Diliza Lucky Twala,,,Economic Freedom Fighters,EFF,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a3/6b/a36b6ea7a9854d6eaffbc51d2ff4db74.jpg, 72 | dirk-jan-stubbe,Mr Dirk Jan Stubbe,stubbedj@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a1/81/a18194a729eafae0aba1fa0b2ebcf020.jpg, 73 | donald-mlindwa-gumede,Mr Donald Mlindwa Gumede,dgumede@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/99/b7/99b7a4ec95c2c6ae38f799efebc787e8.jpg, 74 | ebrahim-ismail-ebrahim,Mr Ebrahim Ismail Ebrahim,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/43/a2/43a2f4d605b77f04bf1edcea063835d8.jpg, 75 | ebrahim-patel,Mr Ebrahim Patel,epatel@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5c/a3/5ca32844bdcc63f365f49d1856d2c15f.jpg, 76 | elvis-kholwana-siwela,Mr Elvis Kholwana Siwela,esiwela@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7a/5c/7a5c0897b44855ccd046d815d2ec8911.jpg, 77 | enock-muzi-mthethwa,Mr Enock Muzi Mthethwa,emthethwa@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fe/ab/feabb8722ea85eea80cd149d20ca7103.jpg, 78 | mohamed-enver-surty,Mr Enver Surty,esurty@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f3/bb/f3bb7900c084253853ec31429886fbd9.jpg, 79 | erik-johannes-marais,Mr Erik Johannes Marais,emarais@parliament.gov.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/25/d7/25d7328c33011ed2e9865f31e9181930.jpg, 80 | ezekiel-kekana,Mr Ezekiel Kekana,,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/10/ce/10ce1f7424c6b00ab127b515bfa6a444.jpg, 81 | fezile-bhengu,Mr Fezile Bhengu,,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/90/e1/90e19c2ca0c219e4c04dede9f9681371.jpg, 82 | fikile-april-mbalula,Mr Fikile Mbalula,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4c/4c/4c4c7dd173e05a3ed8a5f474a9ecf6b3.jpg, 83 | fikile-zachariah-majola,Mr Fikile Zachariah Majola,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/79/11/7911b0226913f219be1d276ebc379024.jpg, 84 | francois-beukman,Mr Francois Beukman,fbeukman@parliament.gov.za,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7e/53/7e538c03d73dfc1d758bb0cf8e29470c.jpg, 85 | freddie-adams,Mr Freddie Adams,fadams@parliament.gov.za,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/db/f1/dbf17fc7cc8f6042db6c911e29ab894f.jpg, 86 | gavin-richard-davis,Mr Gavin Richard Davis,gavdavis@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/86/65/86651463da68679881f770d831d2996f.jpg, 87 | geordin-gwyn-hill-lewis,Mr Geordin Gwyn Hill-Lewis,Geordinh@da.org.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/87/c8/87c876c046e5aa82f9db19e1da15bdc2.jpg, 88 | gerhardus-cornelius-oosthuizen,Mr Gerhardus Oosthuizen,goosthuizen@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e1/e0/e1e0ad63321b1b1e19af8201e62d2941.jpg, 89 | gaolatlhe-godfrey-oliphant,Mr Godfrey Oliphant,goliphant@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bc/82/bc82d8a99a048c0eaf8a652822941317.jpg, 90 | godrich-ahmed-gardee,Mr Godrich Ahmed Gardee,ggardee@effighters.org.za,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b2/2a/b22a7da690df3ace6d6a4aedfd1a35c4.jpg, 91 | goodwill-sbusiso-radebe,Mr Goodwill Sbusiso Radebe,gradebe@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/45/bf/45bfd09808766141a60a06cade4de0c2.jpg, 92 | gordon-mackay,Mr Gordon Mackay,gordon_mackay@outlook.com,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ad/cd/adcd9b3578a5706a285a98912050e766.jpg, 93 | gratitude-magwanishe,Mr Gratitude Magwanishe,gmagwanishe@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9b/fb/9bfbf1cfa6c36470cad09bc3e67dd0f7.jpg, 94 | gregory-allen-grootboom,Mr Gregory Allen Grootboom,advisor.da@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0d/e7/0de70d125c04ab884e524245d7b8ae7d.jpg, 95 | gregory-rudy-krumbock,Mr Gregory Rudy Krumbock,gkrumbock@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/05/43/05437890cee9f675cc4a78ecd62c95a0.jpg, 96 | gugile-ernest-nkwinti,Mr Gugile Nkwinti,ministry@ruraldevelopment.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a5/7a/a57aa1119f36ccad4c76d5f40145bafc.jpg, 97 | hendrik-christiaan-crafford-kruger,Mr Hendrik Christiaan Crafford Krüger,smme@mweb.co.za,,Democratic Alliance,DA,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c4/1a/c41aa551e05312fec2c46620caf17267.jpg, 98 | hendrik-cornelius-schmidt,Mr Hendrik Cornelus Schmidt,hschmidt@parliament.gov.za,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bc/9a/bc9a96784a0dbc1300b279a174beed9f.jpg, 99 | hlengiwe-buhle-mkhize,Mr Hlengiwe Mkhize,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/86/80/8680a629020d37d502c1d8a9da624ab3.jpg, 100 | humphrey-mmemezi,Mr Humphrey Mdumzeli Zondelele Mmemezi,hmmemezi@gpl.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0d/0f/0d0fb3ac5141f54987756be642406dda.jpg, 101 | ian-michael-ollis,Mr Ian Michael Ollis,iollis@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e2/dc/e2dcec30bb0d674bda2c9842e91ed55c.jpg, 102 | imamile-aubin-pikinini,Mr Imamile Aubin Pikinini,ipikinini@ecleg.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/26/12/261266be203b21f616f5172da090c226.jpg, 103 | itumeleng-mosala,Mr Itumeleng Mosala,,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/03/f4/03f4d49d757e3f2f2d6c031936d4e9d1.jpg, 104 | jabulani-lukas-mahlangu,Mr Jabulani Lukas Mahlangu,jmahlangu@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/da/7c/da7c5a60cc53c10b4ebd9ef1705c273c.jpg, 105 | jackson-mphikwa-mthembu,Mr Jackson Mphikwa Mthembu,jmthembu@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ef/b2/efb274940cf7f1c72b0b4f16dd82612c.jpg, 106 | james-jim-skosana,Mr James Jim Skosana,jskosana@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ce/c9/cec969958ad0cd535a254507a46c1c3e.jpg, 107 | james-robert-bourne-lorimer,Mr James Robert Bourne Lorimer,jlorimer@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bc/5c/bc5ca080eea01d05b83930827b33e097.jpg, 108 | james-selfe,Mr James Selfe,fedexchair@da.org.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ca/b2/cab277dcd7ab1c4017e618cdf39d9b90.jpg, 109 | james-vos,Mr James Vos,capevos@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/07/ea/07eae79ea32edd998fa42215962f66ca.jpg, 110 | jan-adriaan-esterhuizen,Mr Jan Adriaan Esterhuizen,jesterhuizen@parliament.gov.za,,Inkatha Freedom Party,IFP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ea/1d/ea1d5c38c20874185647b9de2f0f3614.jpg, 111 | jeffrey-thamsanqa-radebe,Mr Jeff Radebe,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/45/bd/45bd995d2e0efd1d7dc4b9e96d305ceb.jpg, 112 | jeremy-patrick-cronin,Mr Jeremy Cronin,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/21/62/2162bb3d7ee51d99cd8e7343012a6493.jpg, 113 | jerome-joseph-maake,Mr Jerome Joseph Maake,jmaake@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/61/02/610212376a8bfdca4585b0e8ef40ab6e.jpg, 114 | john-henry-steenhuisen,Mr John Henry Steenhuisen,unicity@iafrica.com,,Democratic Alliance,DA,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/1e/2b/1e2b9dd7b501b5665b317b20f8a7806d.jpg, 115 | john-harold-jeffery,Mr John Jeffery,jjeffery@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/29/db/29dbae53a53cdafe7d0733c5d7cb98e2.jpg, 116 | joseph-job-mc-gluwa,Mr Joseph Job Mc Gluwa,,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 117 | julius-sello-malema,Mr Julius Sello Malema,jmalema@parliament.gov.za,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/56/03/56031cfadf4535ea07b0c4abb6714504.jpg, 118 | emmanuel-ramaotoana-kebby-maphatsoe,Mr Kebby Maphatsoe,kmaphatsoe@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7f/19/7f19d046af4b6786f76e694eceec2f33.jpg, 119 | kenneth-sililo-mubu,Mr Kenneth Sililo Mubu,ksmubu@yahoo.com,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/48/78/4878c0f10efbde9f28cc0b6944a3a4c9.jpg, 120 | kevin-john-mileham,Mr Kevin John Mileham,kevin@forwardmomentum.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/47/ce/47ce6ced19f263d23fa01ada7124791f.jpg, 121 | kgotso-zachariah-morapela,Mr Kgotso Zachariah Morapela,kmorapela@parliament.gov.za,,Economic Freedom Fighters,EFF,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/93/74/93744c7a361d11661604ecc48ce88718.jpg, 122 | khethamabala-petros-sithole,Mr Khethamabala Petros Sithole,ksithole@parliament.gov.za,,Inkatha Freedom Party,IFP,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ba/9e/ba9efc756d5a3429545adc4d5112c419.jpg, 123 | lefu-peter-khoarai,Mr Lefu Peter Khoarai,lkhoarai@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6f/7b/6f7b7b511a827e64e75615a89704b4ca.jpg, 124 | leonard-jones-basson,Mr Leonard Jones Basson,basson@danw.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/07/b4/07b4e349c9a1512518e443181bc56d83.jpg, 125 | lulama-maxwell-ntshayisa,Mr Lulama Maxwell Ntshayisa,lntshayisa@parliament.gov.za,,unknown,unknown,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/3b/f2/3bf2fc19b56e8966331aa51a9287e8ab.jpg, 126 | mlungisi-johnson,Mr Lulu Johnson,mjohnson@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5b/2a/5b2ac000c0fd84b185653beabe4c4d06.jpg, 127 | luwellyn-tyrone-landers,Mr Luwellyn Tyrone Landers,llanders@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4f/2d/4f2db997c57abbfecc2b48ade54749f4.jpg, 128 | madala-louis-david-ntombela,Mr Madala Louis David Ntombela,mntombela@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a9/d3/a9d3e981797ae0bdb0d8145264d5b7e5.jpg, 129 | madala-backson-masuku,Mr Madala Masuku,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/3b/91/3b91cc05e4666cd6b47395eed8647f3a.jpg, 130 | maesela-david-kekana,Mr Maesela David Kekana,makekana@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/56/6c/566ccc309ab9bb9611c92e87846643bb.jpg, 131 | makashule-gana,Mr Makashule Gana,gana@vodamail.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d4/a5/d4a50b03aa53e455d9b654bfe7c3a37d.jpg, 132 | malcolm-john-figg,Mr Malcolm John Figg,malcolmf@aerosat.co.za,,Democratic Alliance,DA,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/16/5e/165e12c307986d200af881faf84ea97a.jpg, 133 | maliyakhe-lymon-shelembe,Mr Maliyakhe Lymon Shelembe,mshelembe@parliament.gov.za,,National Freedom Party,NFP,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/db/3a/db3a6e892debdcd5823beda9ede8eec8.jpg, 134 | knowledge-malusi-nkanyezi-gigaba,Mr Malusi Gigaba,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/54/5b/545b4b4ae8cfe0519d0a3d3678320cd3.jpg, 135 | malusi-stanley-motimele,Mr Malusi Stanley Motimele,mmotimele@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/91/0f/910f62494ab503f69450a27453266215.jpg, 136 | mamagase-elleck-nchabeleng,Mr Mamagase Elleck Nchabeleng,mnchabeleng@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2f/b0/2fb098ca6111c17b8e035d12326c3206.jpg, 137 | mandlenkosi-phillip-galo,Mr Mandlenkosi Phillip Galo,mandlagalo@aic.org.za,,unknown,unknown,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f5/9a/f59af2d9527a11c825857a4952dbc3f6.jpg, 138 | mandlenkosi-sicelo-mabika,Mr Mandlenkosi Sicelo Mabika,mmabika@parliament.gov.za,,National Freedom Party,NFP,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b0/f0/b0f0d663bec8cc825bacbe2f3859dd21.jpg, 139 | mangaqa-albert-mncwango,Mr Mangaqa Albert Mncwango,mmncwango@parliament.gov.za,,Inkatha Freedom Party,IFP,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bc/e3/bce373aca4935e6b02d1d8701b192e8a.jpg, 140 | manuel-simao-franca-de-freitas,Mr Manuel Simão Franca De Freitas,manny@democratic-alliance.co.za,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ea/2d/ea2d15a472567e02eef845f9a3482ef7.jpg, 141 | marius-helenis-redelinghuys,Mr Marius Redelinghuys,mredelinghuys@parliament.gov.za,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c3/2f/c32f9021bf41f5bade0f06e53f3975ce.jpg, 142 | marthinus-christoffel-johannes-van-schalkwyk,Mr Marthinus Christoffel Johannes Van Schalkwyk,,,Independent,IND,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d9/49/d949ed9b5b65b1595a8b8d28de7ac882.jpg, 143 | mbuyiseni-quintin-ndlozi,Mr Mbuyiseni Quintin Ndlozi,mndlozi@parliament.gov.za,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/22/d2/22d21a3a63d569642add59598927bb64.jpg, 144 | mcebisi-jonas,Mr Mcebisi Jonas,andiswa.kamba@deaet.ecape.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ec/01/ec019d2fad1b488ab602f24b20de8a61.jpg, 145 | mcebisi-skwatsha,Mr Mcebisi Skwatsha,mskwatsha@wcpp.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bb/19/bb19324785257ef4ae549f5abc350c85.jpg, 146 | mduduzi-comfort-manana,Mr Mduduzi Manana,mdmanana@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6f/6b/6f6b48308e00b12e9cb76a70c8e54d1a.jpg, 147 | mervyn-alexander-dirks,Mr Mervyn Alexander Dirks,mdirks@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e0/84/e084a7c06ccacc32647042902c0847d4.jpg, 148 | michael-bagraim,Mr Michael Bagraim,bagm@iafrica.com,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ef/ba/efba59572c190259f23dfa2216794d19.jpg, 149 | michael-waters,Mr Michael Waters,mwaters@democratic-alliance.co.za,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/13/41/1341d643eba684220e829ce25f6c4ea5.jpg, 150 | mkhuleko-hlengwa,Mr Mkhuleko Hlengwa,mhlengwa@parliament.gov.za,,Inkatha Freedom Party,IFP,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2a/c2/2ac2cbea8a166f7a084273f2a666f3ac.jpg, 151 | mmusi-aloysias-maimane,Mr Mmusi Aloysias Maimane,parliamentaryleader@da.org.za,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c8/05/c805e261a48cfacecf5d3e2331c2378f.jpg, 152 | mncedisi-lutando-wellington-filtane,Mr Mncedisi Lutando Wellington Filtane,mvelasco@parliament.gov.za,,United Democratic Movement,UDM,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/da/6f/da6fbc369482015be9e946d0f3149555.jpg, 153 | mnyamezeli-shedrack-booi,Mr Mnyamezeli Shedrack Booi,mbooi@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ed/4a/ed4adc3f9dfc095b3986765c50c01c58.jpg, 154 | mogamad-nazier-paulsen,Mr Mogamad Nazier Paulsen,nazierpaulsen@ivleague.co.za,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d4/21/d421b79152517f1b798e0bc81812a0e0.jpg, 155 | mohammed-haniff-hoosen,Mr Mohammed Haniff Hoosen,mhoosen@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/54/61/54613add7d952c6df3ca849c5d991b60.jpg, 156 | mohlopi-phillemon-mapulane,Mr Mohlopi Philemon Mapulane,pmapulane@parliament.gov.za,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f4/d4/f4d418d051918124281f9c9580cf869e.jpg, 157 | molapi-andries-plouamma,Mr Molapi Andries Plouamma,mplouamma@parliament.gov.za,,Agang South Africa,AGANG SA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2e/0a/2e0a6548a008a47086e8e23a91edde10.jpg, 158 | moloko-stanford-armour-maila,Mr Moloko Stanford Armour Maila,mmaila@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0e/ae/0eaef3e1600e6f6915563babb2d53a64.jpg, 159 | moses-sipho-mbatha,Mr Moses Sipho Mbatha,mmbatha@parliament.gov.za,,Economic Freedom Fighters,EFF,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6a/e1/6ae1749166e3ba60b05f978cc039c4e8.jpg, 160 | moses-siphosezwe-amos-masango,Mr Moses Siphosezwe Amos Masango,msamasango@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/64/03/64038c11a615944b0545463c6a25f09c.jpg, 161 | mosie-antony-cele,Mr Mosie Antony Cele,mcele@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/37/c4/37c4b3958bfbc7698b7b07544cef7655.jpg, 162 | mosiuoa-gerard-patrick-lekota,Mr Mosiuoa Lekota,mlekota@parliament.gov.za,,Congress of the People,COPE,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/3a/ef/3aef2f5f4f4de3f4aa9c40ea1538af07.jpg, 163 | motswaledi-hezekiel-matlala,Mr Motswaledi Hezekiel Matlala,mmatlala@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5c/68/5c683781c9d34376c0909553d741523a.jpg, 164 | mponeng-winston-rabotapi,Mr Mponeng Winston Rabotapi,mrabotapi@parliament.gov.za,,Democratic Alliance,DA,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5e/a3/5ea3f2d0f76707a4aedea9fe76d771fe.jpg, 165 | mtikeni-patrick-sibande,Mr Mtikeni Patrick Sibande,psibande@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/10/4a/104add0f21af3b17c19813fbf7327444.jpg, 166 | mzameni-richard-mdakane,Mr Mzameni Richard Mdakane,mmdakane@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b4/a8/b4a8f9ad2a4a6fc8c63c60e1a659cd14.jpg, 167 | mzingisi-marshall-dlamini,Mr Mzingisi Marshall Dlamini,,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a9/16/a91655683d89d2a79757fd706dd0b54e.jpg, 168 | mziwamadoda-uppington-kalako,Mr Mziwamadoda Uppington Kalako,,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/cb/e0/cbe0b769556676ce1d533c52377a1ca9.jpg, 169 | mzwandile-collen-masina,Mr Mzwandile Masina,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b4/37/b437836ec0ef3ab8eb6aaa188e3bbf45.jpg, 170 | narend-singh,Mr Narend Singh,nsingh@parliament.gov.za,,Inkatha Freedom Party,IFP,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/24/55/24557dea33f618c9f580d6df50e30734.jpg, 171 | emmanuel-nkosinathi-mthethwa,Mr Nathi Mthethwa,ministersoffice@dac.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5d/d3/5dd3fa4a25418e486b430f4e03cb0403.jpg, 172 | ndabakayise-erasmus-gcwabaza,Mr Ndabakayise Erasmus Gcwabaza,ngcwabaza@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/00/60/0060d00d3c4caff0e6c84b05242459ca.jpg, 173 | ndumiso-capa,Mr Ndumiso Capa,ncapa@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/62/60/626004ce9aba0fbfb835aebcc3d4145e.jpg, 174 | nelson-themba-godi,Mr Nelson Themba Godi,ngodi@parliament.gov.za,,African People's Convention,APC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/1e/6b/1e6b5a4673c80bbd0f803a3c9bb358cd.jpg, 175 | ngoako-abel-ramatlhodi,Mr Ngoako Abel Ramatlhodi,nramatlhodi@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5f/46/5f46287cb882e91b6425e6cf6f0d90a5.jpg, 176 | nhlanhla-musa-nene,Mr Nhlanhla Nene,,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/cb/46/cb46a3de17d769fe4bcde00530c38e71.jpg, 177 | nhlanhlakayise-moses-khubisa,Mr Nhlanhlakayise Moses Khubisa,nkhubisa@parliament.gov.za,,National Freedom Party,NFP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/44/d7/44d7e6cfd274cee6807488ad447559a1.jpg, 178 | nicholous-pro-khoza,Mr Nicholous Pro Khoza,pkhoza@parliament.gov.za,,Economic Freedom Fighters,EFF,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b8/ad/b8ad5b3e44add42ecb57f55f5d89ace4.jpg, 179 | nkosiyakhe-amos-masondo,Mr Nkosiyakhe Amos Masondo,nmasondo@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/55/d7/55d745d8e59f60c40a899fa7a74c4cb5.jpg, 180 | nqabayomzi-lawrence-kwankwa,Mr Nqabayomzi Lawrence Saziso Kwankwa,nkwankwa@parliament.gov.za,,United Democratic Movement,UDM,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fa/9f/fa9f7237d6bb1f466beb6cda4047c6cb.jpg, 181 | nthako-sam-matiase,Mr Nthako Sam Matiase,nmatiase@parliament.gov.za,,Economic Freedom Fighters,EFF,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2b/e0/2be044ed4c3f5956b9f246ebf709450a.jpg, 182 | nyiko-floyd-shivambu,Mr Nyiko Floyd Shivambu,,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a4/29/a429f1512f51b7575c071ddfbe31f8eb.jpg, 183 | kopeng-obed-bapela,Mr Obed Bapela,obapela@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b6/62/b6629ff19ba1b7b6e8ec0a158bdd77ab.jpg, 184 | patrick-george-atkinson,Mr Patrick George Atkinson,peegee@icon.co.za,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/75/5a/755abfd9f645bbcbc771817173d733d2.jpg, 185 | pebane-george-moteka,Mr Pebane George Moteka,pmoteka@parliament.gov.za,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/3a/02/3a0253ea73aa1fa9caf024d4e39a05b1.jpg, 186 | phumelele-stone-sizani,Mr Phumelele Stone Sizani,psizani@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fb/e0/fbe0798da4eaab0a13ea21b7993e1d59.jpg, 187 | pieter-van-dalen,Mr Pieter Van Dalen,Pietervandalen@hotmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/10/18/10188d2226fb51e25adc2c22f0888c61.jpg, 188 | pravin-gordhan,Mr Pravin Gordhan,minreg@treasury.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/05/64/056464dfc2a159466a7f1a134ee52a80.jpg, 189 | puleng-peter-mabe,Mr Puleng Peter Mabe,pmabe@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4a/22/4a2210c641b88903d9688901e2734ed0.jpg, 190 | phumzile-justice-mnguni,Mr Pumzile Justice Mnguni,pjmnguni@ecleg.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0c/d0/0cd09ebe744bca63ef207e22db43d6a2.jpg, 191 | rembuluwani-moses-tseli,Mr Rembuluwani Moses Tseli,mtseli@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/28/8e/288ede34add9d91dfd2c786739fdfc55.jpg, 192 | risimati-thompson-mavunda,Mr Risimati Thompson Mavunda,rmavunda@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/47/97/4797b847ff086c8e2166ec31374b49ae.jpg, 193 | robert-haydn-davies,Mr Rob Davies,rdavies@thedti.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/70/f3/70f34372e4310ed49cb9d48795e85a62.jpg, 194 | robert-alfred-lees,Mr Robert Alfred Lees,alf@leeskzn.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e6/1b/e61b3e05a7533216245cc26cd69a3f03.jpg, 195 | roger-william-tobias-chance,Mr Roger William Tobias Chance,toby@tobychance.com,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ba/e8/bae82deb73cf08abaea75d92b3cb6a1a.jpg, 196 | sahlulele-luzipo,Mr Sahlulele Luzipho,sluzipo@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a6/93/a6931c4cb95a1230803f8a023dedc891.jpg, 197 | samuel-gaaesi-mmusi,Mr Samuel Gaaesi Mmusi,smmusi@parliament.gov.za,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e8/53/e8536960f3d15b8ddc23dbb4adec64a8.jpg, 198 | sarel-jacobus-francois-marais,Mr Sarel Jacobus Francois Marais,befco@mweb.co.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/67/84/6784ce6064f5ffb86b97fbcc2a8e7be7.jpg, 199 | sejamotopo-charles-motau,Mr Sejamotopo Charles Motau,sejmotau@mweb.co.za,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/34/8d/348d4d720d9409cc0fb98c526cb24001.jpg, 200 | sello-albert-tleane,Mr Sello Albert Tleane,,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/74/44/7444ef39e054e62514d5e10bb4074426.jpg, 201 | senzeni-zokwana,Mr Senzeni Zokwana,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/44/80/44808755df697e6c0081539c45596d72.jpg, 202 | seropane-senyane-alton-mphethi,Mr Seropane Senyane Alton Mphethi,amphethi@parliament.gov.za,,Pan Africanist Congress of Azania,PAC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/97/32/9732fe7e73011a5ba55ca9f7eeb6e50c.jpg, 203 | shahid-esau,Mr Shahid Esau,snabs@mweb.co.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4f/38/4f38b74eda348f2a9d65a79da9d29948.jpg, 204 | shipokasa-paulus-mashatile,Mr Shipokosa Paulus Mashatile,pmashatile@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d1/8d/d18d66b17356744c2718cdc2eede6825.jpg, 205 | sibusiso-christopher-mncwabe,Mr Sibusiso Christopher Mncwabe,smncwabe@parliament.gov.za,,National Freedom Party,NFP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/78/91/78918bc05557e7649337bb602f7b353b.jpg, 206 | simphiwe-donatus-bekwa,Mr Simphiwe Donatus Bekwa,,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d4/ab/d4ab9fd07a9b12eb1baccd2f2d51318d.jpg, 207 | siyabonga-cyprian-cwele,Mr Siyabonga Cwele,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9c/0a/9c0a8408ca5bdec13ddca65854867265.jpg, 208 | mmoba-solomon-seshoka,Mr Solly Malatsi,mmalatsi@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/20/2b/202b3f04db1877d7b32e26a244079ef1.jpg, 209 | solomon-lechesa-tsenoli,Mr Solomon Lechesa Tsenoli,lechesa@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/59/b5/59b5c7981a9a6d3f335a6d5cad9b20e1.jpg, 210 | solomon-patrick-mabilo,Mr Solomon Patrick Mabilo,,,African National Congress,ANC,Northern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/83/6f/836f001f7cce841488d63a77baa9f3ce.jpg, 211 | steven-nicholas-swart,Mr Steve Swart,sswart@parliament.gov.za,,African Christian Democratic Party,ACDP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/68/a6/68a6579a909613cfc1bbbb21914a5550.jpg, 212 | steven-mahlubanzima-jafta,Mr Steven Mahlubanzima Jafta,sjafta@parliament.gov.za,,unknown,unknown,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/49/6c/496c1366ad7e91fa2db7588a3e9755ac.jpg, 213 | stevens-mokgalapa,Mr Stevens Mokgalapa,mokgalapa@polka.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/08/29/082958001fe5dfc2e05490ea1ef77269.jpg, 214 | strike-michael-ralegoma,Mr Strike Michael Ralegoma,,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5e/82/5e82edd014cb7b636da8931d5ca115e1.jpg, 215 | s-j-masango,Mr Suhla James Masango,jamesm@jantar.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/65/ec/65ec908fefc88fa17841362c93d25420.jpg, 216 | tandeka-gqada,Mr Tandeka Gqada,gqadatandeka@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c2/44/c244b2b13aa145ba8cabce0e3935812d.jpg, 217 | tete-ramalie-jonas-ezekiel-ramokhoase,Mr Tete Ramalie Jonas Ezekiel Ramokhoase,jramokhoase@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/83/01/8301d17a91f3433b24b8ec0d69db2d73.jpg, 218 | sampson-phathakge-makwetla,Mr Thabang Sampson Phathakge Makwetla,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7c/b0/7cb0651be5e37cff76d64d9cdb8b674b.jpg, 219 | richard-majola,Mr Thembekile Richard Majola,richardmajola1@gmail.com,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/89/b6/89b64bad8738ff82d74b3c7c9d590f23.jpg, 220 | thilivhali-elphus-mulaudzi,Mr Thilivhali Elphus Mulaudzi,,,Economic Freedom Fighters,EFF,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/da/a2/daa2ef49aa946e24bbf6f419bd8b4006.jpg, 221 | thomas-walters,Mr Thomas Charles Ravenscroft Walters,tcrwalters@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d3/a8/d3a834cbad936f425c171bd855315b37.jpg, 222 | thomas-makondo,Mr Thomas Makondo,tmakondo@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7e/1f/7e1fb9c039a8267a494079b16cffd991.jpg, 223 | thomas-zwelakhe-hadebe,Mr Thomas Zwelakhe Hadebe,thomas.hadebe@gmail.com,,Democratic Alliance,DA,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/8f/9e/8f9ec08277bdeb06f3adca2f37048b6b.jpg, 224 | thembelani-waltermade-nxesi,Mr Thulas Nxesi,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/1b/40/1b40c30f9f0b4ea6c89a2e5d308168fc.jpg, 225 | timothy-james-brauteseth,Mr Timothy James Brauteseth,dsa@saol.com,,Democratic Alliance,DA,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9e/40/9e409a2f0995977aa831e91d7a2baad5.jpg, 226 | timothy-zanoxolo-matsebane-khoza,Mr Timothy Zanoxolo Matsebane Khoza,tkhoza@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ec/93/ec93b4bbb09148dd79b69a6a4ba34a36.jpg, 227 | trevor-bonhomme,Mr Trevor John Bonhomme,,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0c/3b/0c3b9b693dd7b059e51fd64019ed38e3.jpg, 228 | tsepo-winston-mhlongo,Mr Tsepo Winston Mhlongo,tsepomhlongo@yahoo.com,,Democratic Alliance,DA,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/44/ec/44ec73ac4e3ac818a6b2922314b3900c.jpg, 229 | vincent-george-smith,Mr Vincent George Smith,vsmith@anc.org.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/10/c3/10c3335b2de5a9930459f912f8901686.jpg, 230 | werner-horn,Mr Werner Horn,werner@hvrprok.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bf/25/bf2528fdb2dbe805acfce8b0cdbe6834.jpg, 231 | william-mothipa-madisha,Mr William Mothipa Madisha,wmadisha@parliament.gov.za,,Congress of the People,COPE,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f1/45/f145fccda757c4f145b907270f876ebc.jpg, 232 | xitlhangoma-mabasa,Mr Xitlhangoma Mabasa,xmabaso@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5d/b5/5db54e7976df2d80874cc34738e3cdd5.jpg, 233 | yunus-ismail-carrim,Mr Yunus Ismail Carrim,ycarrim@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e8/9e/e89e30fb81001d02710d111e5da55969.jpg, 234 | yusuf-cassim,Mr Yusuf Cassim,ycassim@parliament.gov.za,,Democratic Alliance,DA,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6a/45/6a45f8c5379f455f8b8538b04f91cfec.jpg, 235 | zakhele-njabulo-mbhele,Mr Zakhele Njabulo Mbhele,voxprimus@gmail.com,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/95/8a/958a39bb186e6ce3c3302db38f94a0cf.jpg, 236 | zondi-silence-makhubele,Mr Zondi Silence Makhubele,zmakhubele@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/14/b6/14b6bfb494e051c10d82ba04041232d3.jpg, 237 | zwelivelile-mandlesizwe-dalibhunga-mandela,Mr Zwelivelile Mandlesizwe Dalibhunga Mandela,zmandela@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b2/d5/b2d5d82a8dd292f8ab6abb4cb5d3fc0b.jpg, 238 | anchen-margaretha-dreyer,Mrs Anchen Margaretha Dreyer,anchend@absamail.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c3/30/c3308260d5a62b6807d3a1983432ef4a.jpg, 239 | matsie-angelina-motshekga,Mrs Angie Motshekga,mabua.s@dbe.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e3/b1/e3b1a3060e7283227eeec34158a3a896.jpg, 240 | beverley-lynette-abrahams,Mrs Beverley Lynnette Abrahams,babrahams@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6f/7f/6f7fc3fddd427f0f6c5a6d863b5f43e9.jpg, 241 | cheryllyn-dudley,Mrs Cheryllyn Dudley,cdudley@parliament.gov.za,,African Christian Democratic Party,ACDP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/94/9e/949eb9c8fa1e3463b423c4cc0164f4d1.jpg, 242 | denise-robinson,Mrs Denise Robinson,DeniseR@wol.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/14/52/14529c8511487321aeebdd0d0aa8e207.jpg, 243 | glynnis-breytenbach,Mrs Glynnis Breytenbach,glynis.breytenbach@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/81/fc/81fc42efe1c96bf39c9b3cf5eef8be5d.jpg, 244 | joyce-vuyiswa-basson,Mrs Joyce Vuyiswa Basson,jbasson@parliament.gov.za,,African National Congress,ANC,Northern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/69/63/69630ae1ed1db2814aaeb63d28cd94d5.jpg, 245 | juliana-danielle-kilian,Mrs Juliana Danielle Kilian,jkilian@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/99/e0/99e00b3eba1123b12189d486fe36bb30.jpg, 246 | madipoane-refiloe-moremadi-mothapo,Mrs Madipoane Refiloe Moremadi Mothapo,mmothapo@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bb/f8/bbf8699d2a04dabf71d58f0f0da6b194.jpg, 247 | marian-robin-shinn,Mrs Marian Robin Shinn,mshinn@parliament.gov.za,,Democratic Alliance,DA,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7e/1f/7e1f1bc55c3f337c298b6999fdee26d0.jpg, 248 | nokukhanya-mthembu,Mrs Nokukhanya Mthembu,nmthembu@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6e/6a/6e6a1527b7c87d19d5d12da1da682114.jpg, 249 | nosilivere-winnifred-magadla,Mrs Nosilivere Winifred Magadla,nmagadla@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0b/0d/0b0de4332dd3ca718702b3f5abf0c2e8.jpg, 250 | tshoganetso-mpho-adolphina-gasebonwe-tongwane,Mrs Tshoganetso Mpho Adolphina Gasebonwe-Tongwane,tgasebonwe@parliament.gov.za,,African National Congress,ANC,Northern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/23/d1/23d13844ee20c6c188f61104d2092f2a.jpg, 251 | vatiswa-bam-mugwanya,Mrs Vatiswa Bam-Mugwanya,vbam-mugwanya@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/43/9a/439a14de7c7ce311e6ff4b4b81daa2d7.jpg, 252 | yvonne-nkwenkwezi-phosa,Mrs Yvonne Nkwenkwezi Phosa,yphosa@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/86/45/86450ffcaaf9c08159724ce9fee0c971.jpg, 253 | zisiwe-beauty-nosimo-balindlela,Mrs Zisiwe Beauty Nosimo Balindlela,khayamnandi@webmail.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ef/9f/ef9ff8e3c2ef3db130d52d971508572c.jpg, 254 | agnes-noluthando-daphne-qikani,Ms Agnes Daphne Noluthando Qikani,aqikani@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0b/05/0b05e9d7272086152f54199a9289cbbe.jpg, 255 | angela-thokozile-didiza,Ms Angela Thokozile Didiza,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/19/48/194830d8d8fc5e9d28e77fcfed71df07.jpg, 256 | maapi-angelina-molebatsi,Ms Angelina Molebatsi,mmolebatsi@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/78/78/7878aac82d651e6a8f63abd4a92ff907.jpg, 257 | annette-steyn,Ms Annette Steyn,ansteyn@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/bd/27/bd275142a47cff845e82262efc869af7.jpg, 258 | annette-theresa-lovemore,Ms Annette Theresa Lovemore,alovemore@parliament.gov.za,,Democratic Alliance,DA,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/75/ee/75ee5000764becd4bf457c4e7abb7b81.jpg, 259 | asanda-matshobeni,Ms Asanda Matshobeni,pmogotsi@parliament.gov.za,,Economic Freedom Fighters,EFF,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/47/c9/47c94b40a76318a27630a1d65fa94be9.jpg, 260 | ayanda-dlodlo,Ms Ayanda Dlodlo,adlodlo@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e7/89/e789cad2127ab761fdc91eee24f9a895.jpg, 261 | baleka-mbete,Ms Baleka Mbete,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9e/c6/9ec6de05a01470f2e498f0e168ca93a8.jpg, 262 | barbara-thomson,Ms Barbara Thomson,bthomson@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/8a/40/8a40a5c9f3400f60e5f8700fc3b7ac3d.jpg, 263 | bathabile-olive-dlamini,Ms Bathabile Dlamini,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/12/33/123383a01709b25c47fb8005559f05f3.jpg, 264 | beatrice-thembekile-ngcobo,Ms Beatrice Thembekile Ngcobo,bngcobo@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6e/1d/6e1d38bdf73c6d0d82e85e60ade8f92c.jpg, 265 | beauty-nomvuzo-dlulane,Ms Beauty Nomvuzo Dlulane,bdlulane@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7d/c8/7dc873c053702a07f194b0753cced568.jpg, 266 | bertha-peace-mabe,Ms Bertha Peace Mabe,bmabe@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/54/9d/549df4b9411d0160f099c875f9fa28c7.jpg, 267 | bongekile-jabulile-dlomo,Ms Bongekile Jabulile Dlomo,,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9d/87/9d8769c9c5cedcaa0212d396d6983767.jpg, 268 | kwati-candith-mashego-dlamini,Ms Candith Mashego-Dlamini,NMashigo@ruraldevelopment.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/1d/2e/1d2eaed1abe545b0d9d74c6ed8fa7050.jpg, 269 | cathrine-matsimbi,Ms Cathrine Matsimbi,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/79/42/7942af0956cc4061a0e5354f6f0d4972.jpg, 270 | ndaba-nonhlanhla,Ms Claudia Nonhlanhla Ndaba,nndaba@gpl.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ca/fd/cafd6741ec04abce0ccc507754ba3658.jpg, 271 | cornelia-carol-september,Ms Cornelia Carol September,cseptember@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f0/ec/f0ec96e09c66ca50ff99562abc2fcfda.jpg, 272 | cynthia-nocollege-majeke,Ms Cynthia Nocollege Majeke,cmajeke@parliament.gov.za,,United Democratic Movement,UDM,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f2/bc/f2bc5eeca88106c2de1c088d468885ac.jpg, 273 | daphne-zukiswa-rantho,Ms Daphne Zukiswa Rantho,zrantho@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4b/53/4b5306cb76cd81e343f56c2b54008dc0.jpg, 274 | deborah-dineo-raphuti,Ms Deborah Dineo Raphuti,draphuti@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6e/07/6e07223e49d16584f8d9e16fd5e07954.jpg, 275 | deidre-carter,Ms Deidre Carter,dcarter@parliament.gov.za,,Congress of the People,COPE,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7a/62/7a624773f1fc5918988a0f4fe38fdcec.jpg, 276 | dianne-kohler-barnard,Ms Dianne Kohler Barnard,dk55@ananzi.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0f/ca/0fca8b2c2bebe6ef0652887ef470d6bf.jpg, 277 | dikeledi-gladys-mahlangu,Ms Dikeledi Gladys Mahlangu,dimahlangu@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/07/c0/07c0557bfb0a6c55e0e394e766399321.jpg, 278 | dikeledi-phillistus-magadzi,Ms Dikeledi Phillistus Magadzi,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/85/a3/85a324337761071e3c6530a6a01e87c4.jpg, 279 | dikeledi-rebecca-tsotetsi,Ms Dikeledi Rebecca Tsotetsi,dtsotetsi@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/69/ca/69ca4b95559196ff634ad2dba43bfbeb.jpg, 280 | ms-letsatsi-duba-db,Ms Dipuo Bertha Letsatsi-Duba,dletsatsi-duba@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5c/7b/5c7b9dc9727756eb2e2d5ea306cc1ec0.jpg, 281 | elizabeth-dipuo-peters,Ms Dipuo Peters,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5c/02/5c02c96d56fb7058c2a7242a1627c840.jpg, 282 | dorries-eunice-dlakude,Ms Dorries Eunice Dlakude,ddlakude@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/39/bb/39bbeed59171010eb272a9533a1626b8.jpg, 283 | dudu-hellen-mathebe,Ms Dudu Hellen Mathebe,dmathebe@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/26/b9/26b92ed146b4a5d43d50b87b53bbc021.jpg, 284 | duduzile-promise-manana,Ms Duduzile Promise Manana,,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/be/88/be8854ab57eb5a9b32410b417b07ac53.jpg, 285 | d-van-der-walt,Ms Désirée Van Der Walt,desiree@dalimpopo.co.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/cb/4f/cb4f256c9d0e6b5de8136a83e2b921e3.jpg, 286 | bomo-edna-edith-molewa,Ms Edna Molewa,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a0/8e/a08eaa6a725383f48e677edb0f38d279.jpg, 287 | elizabeth-koena-mmanoko-masehela,Ms Elizabeth Koena Mmanoko Masehela,emasehela@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/57/bb/57bb16c14f91c3fcc43cb7ee8edf1025.jpg, 288 | elizabeth-thabethe,Ms Elizabeth Thabethe,,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/26/af/26af7f08a28461e4ca9253947356601e.jpg, 289 | elsabe-natasha-louw,Ms Elsabe Natasha Louw,elouw@parliament.gov.za,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/84/bc/84bcaec14e20491314d56adc75817322.jpg, 290 | elsie-mmathulare-coleman,Ms Elsie Mmathulare Coleman,ecoleman@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/01/3e/013e4dc90ed2c9ff7d2ff051dfaf4c15.jpg, 291 | evelyn-rayne-wilson,Ms Evelyn Rayne Wilson,wilsonworx@webmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e1/03/e10361d21228e3ec0dd524208e748fe1.jpg, 292 | azwihangwisi-faith-muthambi,Ms Faith Muthambi,amuthambi@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b0/02/b0020624c49d5f48ed5dfd7b27ed4944.jpg, 293 | fatima-ismail-chohan,Ms Fatima Chohan,fchohan@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e1/b4/e1b4c9404b0b441d2d2d7ba671247427.jpg, 294 | fezeka-sister-loliwe,Ms Fezeka Sister Loliwe,floliwe@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fd/cd/fdcd54716426658d96ecf9d0ef2264fe.jpg, 295 | girly-namhla-nobanda,Ms Girly Namhla Nobanda,gnobanda@parliament.gov.za,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/38/51/385158c0b1d63914b03d98a0037d7894.jpg, 296 | grace-kekulu-tseke,Ms Grace Kekulu Tseke,gtseke@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/07/b5/07b529bd0ec1be649e20b31d58e0a904.jpg, 297 | hellen-boikhutso-kekana,Ms Hellen Boikhutso Kekana,,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/39/06/39066e245e32d6df8f9ccf1c34990556.jpg, 298 | hendrietta-ipeleng-bogopane-zulu,Ms Henrietta Bogopane-Zulu,hbogopane@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d9/e3/d9e301036adfb25d4ce6d1c116140218.jpg, 299 | hildegard-sonja-boshoff,Ms Hildegard Sonja Boshoff,sonja2@vodamail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/59/46/5946ae057b9d40951356c36163dca65a.jpg, 300 | hlengiwe-octavia-maxon,Ms Hlengiwe Octavia Maxon,,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5b/95/5b95223796f180f1135e5f7a1f503dda.jpg, 301 | hope-helene-malgas,Ms Hope Helene Malgas,hmalgas@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/74/69/746909f4bb1f4544da4eb7de0a3b4d93.jpg, 302 | joanmariae-louise-fubbs,Ms Joanmariae Louise Fubbs,jfubbs@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/e7/e6/e7e655de02b72978ccce1d71a3c17c9c.jpg, 303 | johanna-fredrika-juanita-terblanche,Ms Johanna Fredrika Terblanche,jterblanche@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/1d/06/1d066b8d78c4fda317e94908f91ca65a.jpg, 304 | johanna-mmule-maluleke,Ms Johanna Mmule Maluleke,jmaluleke@parliament.gov.za,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/be/1b/be1b76a1278f710e6838bce68efd9c96.jpg, 305 | johanna-steenkamp,Ms Johanna Steenkamp,steenkampjni@gmail.com,,Democratic Alliance,DA,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ce/0c/ce0c7078c7dab546cdbc629f24e5cdfb.jpg, 306 | joyce-clementine-moloi-moropa,Ms Joyce Clementine Moloi-Moropa,jmoropa@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/73/8c/738c1705630d80d6d799ede3c1c227ef.jpg, 307 | karen-de-kock,Ms Karen De Kock,kaidekock@gmail.com,,Democratic Alliance,DA,Northern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/48/59/48592f99ffb743cfbec4bfe4bf6f8b9c.jpg, 308 | liezl-linda-van-der-merwe,Ms Liezl Linda van der Merwe,,,Inkatha Freedom Party,IFP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/22/66/2266a5064c5f613cc2bf5f508b6035c2.jpg, 309 | maseko-lindiwe,Ms Lindiwe Michelle Maseko,lmaseko@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/41/3c/413c9926a90d2238445cad81e840ad54.jpg, 310 | lindiwe-ntombikayise-mjobo,Ms Lindiwe Ntombikayise Mjobo,lmjobo@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/1f/4c/1f4c6d8bfb01216e4c6b6068c0eef336.jpg, 311 | lindiwe-nonceba-sisulu,Ms Lindiwe Sisulu,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ac/ef/acefaa8cd3e5eca30df02bc2f8679585.jpg, 312 | l-d-zulu,Ms Lindiwe Zulu,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/34/31/3431b6e565c294e5536cd99fd731de7e.jpg, 313 | lindy-wilson,Ms Lindy Wilson,wilsonworx@webmail.com,,Democratic Alliance,DA,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b5/b1/b5b1edc92b70ee380764c94186b74f67.jpg, 314 | livhuhani-mabija,Ms Livhuhani Mabija,lmabija@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ba/3c/ba3c4bc4c6f6c1bc823d2daea6a9c70a.jpg, 315 | lumka-elizabeth-yengeni,Ms Lumka Elizabeth Yengeni,lyengeni@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5f/ff/5fff24d52e2e04e24f99f1e9027b63b4.jpg, 316 | lungi-annette-mnganga-gcabashe,Ms Lungi Annette Mnganga - Gcabashe,lmnganga-gcabashe@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/b0/26/b0261e6ae94172af0f94162bf01e6447.jpg, 317 | lungiswa-veronica-james,Ms Lungiswa Veronica James,Lungiswa.James@capetown.gov.za,,Democratic Alliance,DA,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f5/2f/f52fe8226771c68e607d1fc7ecfdb0d5.jpg, 318 | lusizo-sharon-makhubela-mashele,Ms Lusizo Sharon Makhubela-Mashele,lmakhubela-mashele@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ab/b8/abb8a0b4b208d204d05511cf0e6dbe0f.jpg, 319 | lynette-brown,Ms Lynne Brown,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ff/43/ff4362fa5b58b8f224ec5afc0d528b2e.jpg, 320 | ms-semenya-machwene-rosinah,Ms Machwene Rosina Semenya,MALEKAK@limpopoleg.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/37/f0/37f0fc912220440d763e2596dbaa28d1.jpg, 321 | makhotso-magdeline-sotyu,Ms Maggie Sotyu,msotyu@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/28/84/2884c9cec438440dc757c06ef0294ef9.jpg, 322 | maite-emily-nkoana-mashabane,Ms Maite Nkoana-Mashabane,minister@dirco.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/33/e9/33e90a68a26b17a9b4ebae04a216d079.jpg, 323 | makgathatso-charlotte-chana-pilane-majake,Ms Makgathatso Charlotte Chana Pilane-Majake,cpilane-majake@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7c/01/7c01afac81975d5b79551e70f2fc8739.jpg, 324 | makoti-sibongile-khawula,Ms Makoti Sibongile Khawula,,,Economic Freedom Fighters,EFF,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2a/df/2adf2b5d6d56caee56b61beb685b20cc.jpg, 325 | chueu-patricia,Ms Mamonare Patricia Chueu,pchueu@gpl.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fa/71/fa712fdcef96452d80e6a7f587bcdd0e.jpg, 326 | mandisa-octovia-matshoba,Ms Mandisa Octovia Matshoba,mmatshoba@parliament.gov.za,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f9/6a/f96af76b47e9a83294ffc8cce29c51e9.jpg, 327 | mapule-veronica-mafolo,Ms Mapule Veronica Mafolo,mmafolo@parliament.gov.za,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/dd/72/dd7262f8c40dc98f54cacfa3be4080e5.jpg, 328 | mary-ann-lindelwa-dunjwa,Ms Mary-Ann Lindelwa Dunjwa,mdunjwa@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0b/c5/0bc59af85e675d9f226a9e8f2aeb389f.jpg, 329 | masefele-rosalia-morutoa,Ms Masefele Rosalia Morutoa,rmorutoa@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/01/07/0107c30f02df2b49a528d726689e7473.jpg, 330 | m-scheepers,Ms Maureen Angela Scheepers,mscheepers@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/47/67/47677c775c609245d4842421ebe7efc8.jpg, 331 | mildred-nelisiwe-oliphant,Ms Mildred Oliphant,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/62/9c/629c27e7a8b8dbcc96b1c789d270ddb5.jpg, 332 | millicent-ntombizodwa-sibongile-manana,Ms Millicent Ntombizodwa Sibongile Manana,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2f/73/2f731975d5d057d75608d1bfb6dd6664.jpg, 333 | mmamoloko-tryphosa-kubayi,Ms Mmamoloko Tryphosa Kubayi,mmkubayi@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/12/1c/121c12a86f16cb7f21500c0c1a9e3a7d.jpg, 334 | mmatlala-grace-boroto,Ms Mmatlala Grace Boroto,mboroto@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/d3/9c/d39c3abc5c08cd9c6fc5be0ec7ffa2b0.jpg, 335 | mogotle-friddah-nkadimeng,Ms Mogotle Friddah Nkadimeng,mnkadimeng@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/f6/b2/f6b27d5559abc633fe595e190e570949.jpg, 336 | grace-naledi-mandisa-pandor,Ms Naledi Pandor,gpandor@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/24/82/2482ed73fea4367e2107b62f21447da1.jpg, 337 | natasha-wendy-anita-michael,Ms Natasha Wendy Anita Mazzone,natasha.michael@yahoo.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/76/6c/766c6d2f827185f9e1536762ec8466ca.jpg, 338 | ngwanamakwetle-reneiloe-mashabela,Ms Ngwanamakwetle Reneiloe Mashabela,nmashabela@parliament.gov.za,,Economic Freedom Fighters,EFF,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/1a/b0/1ab0e291fb1f085a8765f364b8d73c68.jpg, 339 | nkhensani-kate-bilankulu,Ms Nkhensani Kate Bilankulu,kbilankulu@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/93/c2/93c2b291162d6b63212f23cfc26463ff.jpg, 340 | nocawe-noncedo-mafu,Ms Nocawe Noncedo Mafu,nmafu@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c3/f7/c3f71ba6f8e31ce7231e76faf46ab737.jpg, 341 | nokhaya-adelaide-mnisi,Ms Nokhaya Adelaide Mnisi,nmnisi@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ed/8b/ed8bfc7bb7b2fc0300ca19db0d8c48a0.jpg, 342 | nokulunga-primrose-sonti,Ms Nokulunga Primrose Sonti,nsonti@parliament.gov.za,,Economic Freedom Fighters,EFF,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/7c/a4/7ca4a1198ef330588c71127269df0160.jpg, 343 | nokuzola-ndongeni,Ms Nokuzola Ndongeni,,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/cb/85/cb85c8f4638476826ff55019ad6cf6e5.jpg, 344 | nomaindiya-cathleen-mfeketho,Ms Noma-India Mfeketho,speaker@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9b/02/9b024ac3afbbea6237ef81575e904394.jpg, 345 | nomalungelo-gina,Ms Nomalungelo Gina,ngina@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/02/cf/02cf715b46ff94a7b4915502e5d40103.jpg, 346 | nomsa-innocencia-tarabella-marchesi,Ms Nomsa Innocencia Tarabella Marchesi,nomsa_marchesi@hotmail.com,,Democratic Alliance,DA,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fe/26/fe26252e0e32e9ea16606e89d9fd7c09.jpg, 347 | nomzamo-winfred-madikizela-mandela,Ms Nomzamo Winfred Madikizela-Mandela,nmadikizela-mandela@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/98/cc/98cc7f6e4647bfa479e03823aab43fbf.jpg, 348 | nosiviwe-noluthando-mapisa-nqakula,Ms Nosiviwe Mapisa-Nqakula,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/60/4b/604bb4d3e47a0330caa315961adc5b11.jpg, 349 | nozabelo-ruth-bhengu,Ms Nozabelo Ruth Bhengu,nbhengu@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4d/71/4d71590f47a20e8abbc743f1cd064143.jpg, 350 | nthabiseng-pauline-khunou,Ms Nthabiseng Pauline Khunou,nkhunou@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/32/45/32458bf7bad6aeff9c162e215b01d1c4.jpg, 351 | nthibane-rebecca-mokoto,Ms Nthibane Rebecca Mokoto,,,African National Congress,ANC,North West,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6f/4f/6f4fc2588094b0eccda23733f94323ce.jpg, 352 | ntombovuyo-veronica-nqweniso,Ms Ntombovuyo Veronica Mente-Nqweniso,vmente-nqweniso@parliament.gov.za,,Economic Freedom Fighters,EFF,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ab/ff/abff697fb89bb5f3498c3484863ef561.jpg, 353 | pamela-tshwete,Ms Pam Tshwete,ptshwete@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/8b/d9/8bd977c42a0e660a52402dd6077b0e3b.jpg, 354 | patricia-emily-adams,Ms Patricia Emily Adams,padams@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/33/e6/33e670f0a29b540a67acd60aa2231b64.jpg, 355 | phumuzile-catherine-ngwenya-mabila,Ms Phumuzile Catherine Ngwenya-Mabila,pngwenya-mabila@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/76/c6/76c67e75ddd29346b6e6088a7cda0ebc.jpg, 356 | phumzile-bhengu,Ms Phumzile Bhengu,pbhengu@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/de/87/de87f0afc9c615887108fb8866160c6b.jpg, 357 | phumzile-thelma-van-damme,Ms Phumzile Thelma Van Damme,phumzile7@gmail.com,,Democratic Alliance,DA,Unknown sub-area of Western Cape known as DA Constituency Area: Mitchells Plain 2,National Assembly,26,,,http://www.pa.org.za/media_root/cache/67/77/6777f571230e1a0c7b0e58dfa18f71dc.jpg, 358 | pinky-sharon-kekana,Ms Pinky Sharon Kekana,,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/49/f9/49f97a846b6a88c3cd65c3d98e87f93b.jpg, 359 | priscilla-tozama-mantashe,Ms Priscilla Tozama Mantashe,,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/17/f6/17f63b7f9d74f2f9abce8b5935078d24.jpg, 360 | pumza-ntobongwana,Ms Pumza Ntobongwana,pntobongwana@parliament.gov.za,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/99/bc/99bc89f47e31befc2acb6c01926fcfa1.jpg, 361 | raesibe-eunice-nyalungu,Ms Raesibe Eunice Nyalungu,rnyalungu@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/19/78/19788483e087add17a39bd9d77c36c6b.jpg, 362 | regina-mina-mpontseng-lesoma,Ms Regina Mina Mpontseng Lesoma,mlesoma@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/be/53/be538e13d60ee54f5f18661211717529.jpg, 363 | thizwilondi-rejoyce-mabudafhasi,Ms Rejoice Mabudafhasi,tmabudafhasi@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4b/6a/4b6a8ff4b6d049b5c37d186c48d1aac9.jpg, 364 | rosemary-nokuzola-capa,Ms Rosemary Nokuzola Capa,tmirubelela@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/87/da/87dad0bee899d4ba1e2d81d076b0d228.jpg, 365 | santosh-vinita-kalyan,Ms Santosh Vinita Kalyan,Whippery.Secretary@da.org.za,,Democratic Alliance,DA,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/2a/8d/2a8d9d9fdc8ec038d8c3ede099a71fb5.jpg, 366 | semakaleng-patricia-kopane,Ms Semakaleng Patricia Kopane,skopane@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/17/47/17476f7faf529dd9fb9dd14080bf7d62.jpg, 367 | sharome-renay-van-schalkwyk,Ms Sharome Renay Van Schalkwyk,svanschalkwyk@parliament.gov.za,,African National Congress,ANC,Northern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4a/9f/4a9fa03ebeac6a20bac6974d1165dbd0.jpg, 368 | sheila-coleen-nkhensani-shope-sithole,Ms Sheila Coleen Nkhensani Shope-Sithole,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/6f/cb/6fcbc5b13c5177fa2299d6531a679dd0.jpg, 369 | sheilla-tembalam-xego-sovita,Ms Sheilla Tembalam Xego,,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ae/74/ae7460b57ee2ec69d143aefaa66bdacd.jpg, 370 | shela-paulina-boshielo,Ms Shela Paulina Boshielo,sboshielo@parliament.gov.za,,African National Congress,ANC,Limpopo,National Assembly,26,,,http://www.pa.org.za/media_root/cache/5c/c9/5cc92b6f0b292009b91618173baad63b.jpg, 371 | sibongile-judith-nkomo,Ms Sibongile Judith Nkomo,snkomo@parliament.gov.za,,Inkatha Freedom Party,IFP,,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 372 | sibongile-mchunu,Ms Sibongile Mchunu,smchunu@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/31/41/3141b9c8bbdc3b3c815ad530abb89bbb.jpg, 373 | sibongile-pearm-tsoleli,Ms Sibongile Pearm Tsoleli,stsoleli@parliament.gov.za,,African National Congress,ANC,Free State,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ea/8c/ea8c9f751656b4052058da96c988c42f.jpg, 374 | lydia-sindisiwe-chikunga,Ms Sindi Chikunga,lchikunga@parliament.gov.za,,African National Congress,ANC,Mpumalanga,National Assembly,26,,,http://www.pa.org.za/media_root/cache/3b/c2/3bc2a97ac409995bdb4bc2cdce911804.jpg, 375 | stella-tembisa-ndabeni-abrahams,Ms Stella Ndabeni-Abrahams,sndabeni-abrahams@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fb/89/fb89e2b60ecf80e7f257ae9fd2e6ad58.jpg, 376 | susan-shabangu,Ms Susan Shabangu,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/fb/10/fb10eb1993effb909119cebcda86d977.jpg, 377 | tandi-mahambehlala,Ms Tandi Mahambehlala,,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/81/eb/81ebd8708189cc415bfa2078efafe9f2.jpg, 378 | tandiwe-elizabeth-kenye,Ms Tandiwe Elizabeth Kenye,tkenye@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/4d/cc/4dcc5756cadaa2a6a19a2b8271b0a83e.jpg, 379 | tarnia-elena-baker,Ms Tarnia Elena Baker,tarniabaker@gmail.com,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/89/92/8992dc28ed7fcd40936382fc3c532fbf.jpg, 380 | terri-stander,Ms Terri Stander,tstander@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ba/5a/ba5a7504c546fe007e44818a498fbe06.jpg, 381 | thandi-cecilia-memela,Ms Thandi Cecilia Memela,tmashamaite@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/59/93/5993867afda81aceca541ca6cbfd3dd5.jpg, 382 | thandi-vivian-tobias,Ms Thandi Vivian Tobias,ttobias-pokolo@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/3a/73/3a73686cdd240c0d385dce1e643e2adb.jpg, 383 | thapelo-dorothy-chiloane,Ms Thapelo Dorothy Chiloane,tchiloane@parliament.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 384 | tokozile-xasa,Ms Thokozile Xasa,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/8f/f1/8ff1487fad782e857121c7b22e0e821d.jpg, 385 | tina-monica-joemat-pettersson,Ms Tina Joemat-Petterssen,Caroline.Nobevu@energy.gov.za,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/a6/9c/a69c18e02e9bb472910d1125a6140a40.jpg, 386 | velhelmina-pulani-mogotsi,Ms Velhelmina Pulani Mogotsi,pmogotsi@parliament.gov.za,,African National Congress,ANC,Gauteng,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ff/65/ff651115d5afd796d2c589a6e3f6854d.jpg, 387 | veronica-van-dyk,Ms Veronica Van Dyk,houthoop@telkomsa.net,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c7/28/c72839936de5720bdbc747a6b41cd0b5.jpg, 388 | xoliswa-tom,Ms Xoliswa Sandra Tom,xtom@parliament.gov.za,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/c6/ca/c6cac7480d0bba5e3b2513fd14e7b947.jpg, 389 | veronica-zanele-msibi,Ms Zanele kaMagwaza-Msibi,,,National Freedom Party,NFP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/0e/c8/0ec8ae9eed3b24a72efca00d2ba795a7.jpg, 390 | zelda-jongbloed,Ms Zelda Jongbloed,zjongbloed@parliament.gov.za,,Democratic Alliance,DA,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/9f/aa/9faa1855da2e61c436ac7887b3b74a25.jpg, 391 | zephroma-sizani-dlamini-dubazana,Ms Zephroma Sizani Dlamini-Dubazana,sdlamini-dubazana@parliament.gov.za,,African National Congress,ANC,KwaZulu-Natal,National Assembly,26,,,http://www.pa.org.za/media_root/cache/cb/b1/cbb18cec45cc89563efb7e219be8d355.jpg, 392 | zoliswa-albertina-kota-fredericks,Ms Zoe Kota-Fredericks,zkota@parliament.gov.za,,African National Congress,ANC,Western Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/be/05/be057e404536e791528ffcbc9a88f487.jpg, 393 | zukisa-cheryl-faku,Ms Zukisa Cheryl Faku,,,African National Congress,ANC,Eastern Cape,National Assembly,26,,,http://www.pa.org.za/media_root/cache/71/74/717405538df703da9734cdf6ddb7abeb.jpg, 394 | mangosuthu-gatsha-buthelezi,Prince Mangosuthu Gatsha Buthelezi,mbuthelezi@parliament.gov.za,,Inkatha Freedom Party,IFP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/ab/af/abafe6eb053bf370f55ea1b94547d42c.jpg, 395 | belinda-bozzoli,Professor Belinda Bozzoli,bbozzoli@global.co.za,,Democratic Alliance,DA,Unknown sub-area of Gauteng known as DA Constituency Area: Boksburg,National Assembly,26,,,http://www.pa.org.za/media_root/cache/13/2a/132afa848f97d69e0d94ad9913edf50f.jpg, 396 | kenneth-raselabe-joseph-meshoe,Rev Kenneth Raselabe Joseph Meshoe,president@acdp.org.za,,African Christian Democratic Party,ACDP,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/17/41/17417dd782895de0dc667d32a81ed56d.jpg, 397 | tshoganetso-mpho-adolphina-tongwane,Tshoganetso Mpho Adolphina Tongwane,,,African National Congress,ANC,,National Assembly,26,,,http://www.pa.org.za/media_root/cache/8c/a9/8ca98a9848cede4bf96bc6f29ff00ca4.jpg, 398 | vuyokazi-ketabahle,Vuyokazi Ketabahle,Vuyo860@ovi.com,,Economic Freedom Fighters,EFF,,National Assembly,26,,,http://www.pa.org.za/static/images/person-210x210.jpg, 399 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/area.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/area.json#", 4 | "title": "Area", 5 | "description": "A geographic area whose geometry may change over time", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The area's unique identifier", 10 | "type": ["string", "null"], 11 | "rdfType": "id" 12 | }, 13 | "name": { 14 | "description": "A primary name", 15 | "type": ["string", "null"] 16 | }, 17 | "identifier": { 18 | "description": "An issued identifier", 19 | "type": ["string", "null"] 20 | }, 21 | "classification": { 22 | "description": "An area category, e.g. city", 23 | "type": ["string", "null"] 24 | }, 25 | "parent_id": { 26 | "description": "The ID of the area that contains this area", 27 | "type": ["string", "null"], 28 | "rdfName": "parent", 29 | "rdfType": "id", 30 | "rdfReverseName": "children" 31 | }, 32 | "parent": { 33 | "description": "The area that contains this area", 34 | "$ref": "http://www.popoloproject.com/schemas/area.json#", 35 | "rdfReverseName": "children" 36 | }, 37 | "geometry": { 38 | "description": "A geometry", 39 | "type": ["object", "null"] 40 | }, 41 | "memberships": { 42 | "description": "The memberships to which this area is related", 43 | "type": "array", 44 | "items": { 45 | "$ref": "http://www.popoloproject.com/schemas/membership.json#" 46 | } 47 | }, 48 | "organizations": { 49 | "description": "The organizations to which this area is related", 50 | "type": "array", 51 | "items": { 52 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 53 | } 54 | }, 55 | "posts": { 56 | "description": "The posts to which this area is related", 57 | "type": "array", 58 | "items": { 59 | "$ref": "http://www.popoloproject.com/schemas/post.json#" 60 | } 61 | }, 62 | "children": { 63 | "description": "The sub-areas of the area", 64 | "type": "array", 65 | "items": { 66 | "$ref": "http://www.popoloproject.com/schemas/area.json#" 67 | } 68 | }, 69 | "created_at": { 70 | "description": "The time at which the resource was created", 71 | "type": ["string", "null"], 72 | "format": "date-time" 73 | }, 74 | "updated_at": { 75 | "description": "The time at which the resource was last modified", 76 | "type": ["string", "null"], 77 | "format": "date-time" 78 | }, 79 | "sources": { 80 | "description": "URLs to documents from which the resource is derived", 81 | "type": "array", 82 | "items": { 83 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/contact_detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/contact_detail.json#", 4 | "title": "Contact detail", 5 | "description": "A means of contacting an entity", 6 | "type": "object", 7 | "properties": { 8 | "label": { 9 | "description": "A human-readable label for the contact detail", 10 | "type": ["string", "null"] 11 | }, 12 | "type": { 13 | "description": "A type of medium, e.g. 'fax' or 'email'", 14 | "type": "string", 15 | "required": true 16 | }, 17 | "value": { 18 | "description": "A value, e.g. a phone number or email address", 19 | "type": "string", 20 | "required": true 21 | }, 22 | "note": { 23 | "description": "A note, e.g. for grouping contact details by physical location", 24 | "type": ["string", "null"] 25 | }, 26 | "valid_from": { 27 | "description": "The date from which the contact detail is valid", 28 | "type": ["string", "null"], 29 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 30 | }, 31 | "valid_until": { 32 | "description": "The date from which the contact detail is no longer valid", 33 | "type": ["string", "null"], 34 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 35 | }, 36 | "created_at": { 37 | "description": "The time at which the resource was created", 38 | "type": ["string", "null"], 39 | "format": "date-time" 40 | }, 41 | "updated_at": { 42 | "description": "The time at which the resource was last modified", 43 | "type": ["string", "null"], 44 | "format": "date-time" 45 | }, 46 | "sources": { 47 | "description": "URLs to documents from which the resource is derived", 48 | "type": "array", 49 | "items": { 50 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/count.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/count.json#", 4 | "title": "Count", 5 | "description": "The number of votes for an option in a vote event", 6 | "type": "object", 7 | "properties": { 8 | "option": { 9 | "description": "An option in a vote event", 10 | "type": "string", 11 | "required": true 12 | }, 13 | "value": { 14 | "description": "The number of votes for an option", 15 | "type": "integer", 16 | "required": true 17 | }, 18 | "group_id": { 19 | "description": "The ID of a group of voters", 20 | "type": ["string", "null"] 21 | }, 22 | "group": { 23 | "description": "A group of voters", 24 | "type": ["object", "null"] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/event.json#", 4 | "title": "Event", 5 | "description": "An occurrence that people may attend", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The event's unique identifier", 10 | "type": ["string", "null"], 11 | "rdfType": "id" 12 | }, 13 | "name": { 14 | "description": "The event's name", 15 | "type": ["string", "null"] 16 | }, 17 | "description": { 18 | "description": "The event's description", 19 | "type": ["string", "null"] 20 | }, 21 | "start_date": { 22 | "description": "The time at which the event starts", 23 | "type": ["string", "null"], 24 | "pattern": "^[0-9]{4}((-[0-9]{2}){0,2}|(-[0-9]{2}){2}(T[0-9]{2}(:[0-9]{2}(:[0-9]{2})?)?Z)?)$" 25 | }, 26 | "end_date": { 27 | "description": "The time at which the event ends", 28 | "type": ["string", "null"], 29 | "pattern": "^[0-9]{4}((-[0-9]{2}){0,2}|(-[0-9]{2}){2}(T[0-9]{2}(:[0-9]{2}(:[0-9]{2})?)?Z)?)$" 30 | }, 31 | "location": { 32 | "description": "The event's location", 33 | "type": ["string", "null"] 34 | }, 35 | "status": { 36 | "description": "The event's status", 37 | "type": ["string", "null"] 38 | }, 39 | "identifiers": { 40 | "description": "Issued identifiers", 41 | "type": "array", 42 | "items": { 43 | "$ref": "http://www.popoloproject.com/schemas/identifier.json#" 44 | } 45 | }, 46 | "classification": { 47 | "description": "The event's category", 48 | "type": ["string", "null"] 49 | }, 50 | "organization_id": { 51 | "description": "The ID of the organization organizing the event", 52 | "type": ["string", "null"] 53 | }, 54 | "organization": { 55 | "description": "The organization organizing the event", 56 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 57 | }, 58 | "attendees": { 59 | "description": "People attending the event", 60 | "type": "array", 61 | "items": { 62 | "$ref": "http://www.popoloproject.com/schemas/person.json#" 63 | } 64 | }, 65 | "parent_id": { 66 | "description": "The ID of an event that this event is a part of", 67 | "type": ["string", "null"] 68 | }, 69 | "parent": { 70 | "description": "An event that this event is a part of", 71 | "$ref": "http://www.popoloproject.com/schemas/event.json#" 72 | }, 73 | "children": { 74 | "description": "The sub-events of the event", 75 | "type": "array", 76 | "items": { 77 | "$ref": "http://www.popoloproject.com/schemas/event.json#" 78 | } 79 | }, 80 | "created_at": { 81 | "description": "The time at which the resource was created", 82 | "type": ["string", "null"], 83 | "format": "date-time" 84 | }, 85 | "updated_at": { 86 | "description": "The time at which the resource was last modified", 87 | "type": ["string", "null"], 88 | "format": "date-time" 89 | }, 90 | "sources": { 91 | "description": "URLs to documents from which the resource is derived", 92 | "type": "array", 93 | "items": { 94 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/group_result.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/group_result.json#", 4 | "title": "Group result", 5 | "description": "A result of a vote event within a group of voters", 6 | "type": "object", 7 | "properties": { 8 | "group_id": { 9 | "description": "The ID of a group of voters", 10 | "type": ["string", "null"] 11 | }, 12 | "group": { 13 | "description": "A group of voters", 14 | "type": ["object", "null"] 15 | }, 16 | "result": { 17 | "description": "The result of the vote event within a group of voters", 18 | "type": "string", 19 | "required": true 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/identifier.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/identifier.json#", 4 | "title": "Identifier", 5 | "description": "An issued identifier", 6 | "type": "object", 7 | "properties": { 8 | "identifier": { 9 | "description": "An issued identifier, e.g. a DUNS number", 10 | "type": "string", 11 | "required": true 12 | }, 13 | "scheme": { 14 | "description": "An identifier scheme, e.g. DUNS", 15 | "type": ["string", "null"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/link.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/link.json#", 4 | "title": "Link", 5 | "description": "A URL", 6 | "type": "object", 7 | "rdfSubject": "url", 8 | "properties": { 9 | "url": { 10 | "description": "A URL", 11 | "type": "string", 12 | "format": "uri", 13 | "required": true 14 | }, 15 | "note": { 16 | "description": "A note, e.g. 'Wikipedia page'", 17 | "type": ["string", "null"] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/membership.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/membership.json#", 4 | "title": "Membership", 5 | "description": "A relationship between a member and an organization", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The membership's unique identifier", 10 | "type": ["string", "null"], 11 | "rdfType": "id" 12 | }, 13 | "label": { 14 | "description": "A label describing the membership", 15 | "type": ["string", "null"] 16 | }, 17 | "role": { 18 | "description": "The role that the member fulfills in the organization", 19 | "type": ["string", "null"] 20 | }, 21 | "member": { 22 | "description": "The person or organization that is a member of the organization", 23 | "type": ["object", "null"] 24 | }, 25 | "person_id": { 26 | "description": "The ID of the person who is a member of the organization", 27 | "type": ["string", "null"], 28 | "rdfName": "person", 29 | "rdfType": "id", 30 | "rdfReverse": "memberships" 31 | }, 32 | "person": { 33 | "description": "The person who is a member of the organization", 34 | "$ref": "http://www.popoloproject.com/schemas/person.json#", 35 | "rdfReverse": "memberships" 36 | }, 37 | "organization_id": { 38 | "description": "The ID of the organization in which the person or organization is a member", 39 | "type": ["string", "null"], 40 | "rdfName": "organization", 41 | "rdfType": "id", 42 | "rdfReverse": "memberships" 43 | }, 44 | "organization": { 45 | "description": "The organization in which the person or organization is a member", 46 | "$ref": "http://www.popoloproject.com/schemas/organization.json#", 47 | "rdfReverse": "memberships" 48 | }, 49 | "post_id": { 50 | "description": "The ID of the post held by the member in the organization through this membership", 51 | "type": ["string", "null"] 52 | }, 53 | "post": { 54 | "description": "The post held by the member in the organization through this membership", 55 | "$ref": "http://www.popoloproject.com/schemas/post.json#" 56 | }, 57 | "on_behalf_of_id": { 58 | "description": "The ID of the organization on whose behalf the person is a member of the organization", 59 | "type": ["string", "null"] 60 | }, 61 | "on_behalf_of": { 62 | "description": "The organization on whose behalf the person is a member of the organization", 63 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 64 | }, 65 | "area_id": { 66 | "description": "The ID of the geographic area to which this membership is related", 67 | "type": ["string", "null"] 68 | }, 69 | "area": { 70 | "description": "The geographic area to which this membership is related", 71 | "$ref": "http://www.popoloproject.com/schemas/area.json#" 72 | }, 73 | "start_date": { 74 | "description": "The date on which the relationship began", 75 | "type": ["string", "null"], 76 | "pattern": "^[0-9]{4}((-[0-9]{2}){0,2}|(-[0-9]{2}){2}(T[0-9]{2}(:[0-9]{2}(:[0-9]{2})?)?Z)?)$" 77 | }, 78 | "end_date": { 79 | "description": "The date on which the relationship ended", 80 | "type": ["string", "null"], 81 | "pattern": "^[0-9]{4}((-[0-9]{2}){0,2}|(-[0-9]{2}){2}(T[0-9]{2}(:[0-9]{2}(:[0-9]{2})?)?Z)?)$" 82 | }, 83 | "contact_details": { 84 | "description": "Means of contacting the member of the organization", 85 | "type": "array", 86 | "items": { 87 | "$ref": "http://www.popoloproject.com/schemas/contact_detail.json#" 88 | } 89 | }, 90 | "links": { 91 | "description": "URLs to documents about the membership", 92 | "type": "array", 93 | "items": { 94 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 95 | } 96 | }, 97 | "created_at": { 98 | "description": "The time at which the resource was created", 99 | "type": ["string", "null"], 100 | "format": "date-time" 101 | }, 102 | "updated_at": { 103 | "description": "The time at which the resource was last modified", 104 | "type": ["string", "null"], 105 | "format": "date-time" 106 | }, 107 | "sources": { 108 | "description": "URLs to documents from which the resource is derived", 109 | "type": "array", 110 | "items": { 111 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/motion.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/motion.json#", 4 | "title": "Motion", 5 | "description": "A formal step to introduce a matter for consideration by an organization", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The motion's unique identifier", 10 | "type": ["string", "null"] 11 | }, 12 | "organization_id": { 13 | "description": "The ID of the organization in which the motion is proposed", 14 | "type": ["string", "null"] 15 | }, 16 | "organization": { 17 | "description": "The organization in which the motion is proposed", 18 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 19 | }, 20 | "legislative_session_id": { 21 | "description": "The ID of the legislative session in which the motion is proposed", 22 | "type": ["string", "null"] 23 | }, 24 | "legislative_session": { 25 | "description": "The legislative session in which the motion is proposed", 26 | "$ref": "http://www.popoloproject.com/schemas/event.json#" 27 | }, 28 | "creator_id": { 29 | "description": "The ID of the person who proposed the motion", 30 | "type": ["string", "null"] 31 | }, 32 | "creator": { 33 | "description": "The person who proposed the motion", 34 | "$ref": "http://www.popoloproject.com/schemas/person.json#" 35 | }, 36 | "text": { 37 | "description": "The transcript or text of the motion", 38 | "type": ["string", "null"] 39 | }, 40 | "identifier": { 41 | "description": "An issued identifier", 42 | "type": ["string", "null"] 43 | }, 44 | "classification": { 45 | "description": "A motion category, e.g. adjournment", 46 | "type": ["string", "null"] 47 | }, 48 | "date": { 49 | "description": "The date on which the motion was proposed", 50 | "type": ["string", "null"], 51 | "format": "date-time" 52 | }, 53 | "requirement": { 54 | "description": "The requirement for the motion to be adopted", 55 | "type": ["string", "null"] 56 | }, 57 | "result": { 58 | "description": "The result of the motion", 59 | "type": ["string", "null"] 60 | }, 61 | "vote_events": { 62 | "description": "Events at which people vote on the motion", 63 | "type": "array", 64 | "items": { 65 | "$ref": "http://www.popoloproject.com/schemas/vote_event.json#" 66 | } 67 | }, 68 | "created_at": { 69 | "description": "The time at which the resource was created", 70 | "type": ["string", "null"], 71 | "format": "date-time" 72 | }, 73 | "updated_at": { 74 | "description": "The time at which the resource was last modified", 75 | "type": ["string", "null"], 76 | "format": "date-time" 77 | }, 78 | "sources": { 79 | "description": "URLs to documents from which the resource is derived", 80 | "type": "array", 81 | "items": { 82 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/organization.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/organization.json#", 4 | "title": "Organization", 5 | "description": "A group with a common purpose or reason for existence that goes beyond the set of people belonging to it", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The organization's unique identifier", 10 | "type": ["string", "null"], 11 | "rdfType": "id" 12 | }, 13 | "name": { 14 | "description": "A primary name, e.g. a legally recognized name", 15 | "type": ["string", "null"] 16 | }, 17 | "other_names": { 18 | "description": "Alternate or former names", 19 | "type": "array", 20 | "items": { 21 | "$ref": "http://www.popoloproject.com/schemas/other_name.json#" 22 | } 23 | }, 24 | "identifiers": { 25 | "description": "Issued identifiers", 26 | "type": "array", 27 | "items": { 28 | "$ref": "http://www.popoloproject.com/schemas/identifier.json#" 29 | } 30 | }, 31 | "classification": { 32 | "description": "An organization category, e.g. committee", 33 | "type": ["string", "null"] 34 | }, 35 | "parent_id": { 36 | "description": "The ID of the organization that contains this organization", 37 | "type": ["string", "null"] 38 | }, 39 | "parent": { 40 | "description": "The organization that contains this organization", 41 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 42 | }, 43 | "area_id": { 44 | "description": "The ID of the geographic area to which this organization is related", 45 | "type": ["string", "null"] 46 | }, 47 | "area": { 48 | "description": "The geographic area to which this organization is related", 49 | "$ref": "http://www.popoloproject.com/schemas/area.json#" 50 | }, 51 | "abstract": { 52 | "description": "A one-line description of an organization", 53 | "type": ["string", "null"] 54 | }, 55 | "description": { 56 | "description": "An extended description of an organization", 57 | "type": ["string", "null"] 58 | }, 59 | "founding_date": { 60 | "description": "A date of founding", 61 | "type": ["string", "null"], 62 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 63 | }, 64 | "dissolution_date": { 65 | "description": "A date of dissolution", 66 | "type": ["string", "null"], 67 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 68 | }, 69 | "image": { 70 | "description": "A URL of an image", 71 | "type": ["string", "null"], 72 | "format": "uri" 73 | }, 74 | "contact_details": { 75 | "description": "Means of contacting the organization", 76 | "type": "array", 77 | "items": { 78 | "$ref": "http://www.popoloproject.com/schemas/contact_detail.json#" 79 | } 80 | }, 81 | "links": { 82 | "description": "URLs to documents about the organization", 83 | "type": "array", 84 | "items": { 85 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 86 | } 87 | }, 88 | "memberships": { 89 | "description": "The memberships of the members of the organization and of the organization itself", 90 | "type": "array", 91 | "items": { 92 | "$ref": "http://www.popoloproject.com/schemas/membership.json#" 93 | } 94 | }, 95 | "posts": { 96 | "description": "Posts within the organization", 97 | "type": "array", 98 | "items": { 99 | "$ref": "http://www.popoloproject.com/schemas/post.json#" 100 | } 101 | }, 102 | "motions": { 103 | "description": "Motions within the organization", 104 | "type": "array", 105 | "items": { 106 | "$ref": "http://www.popoloproject.com/schemas/motion.json#" 107 | } 108 | }, 109 | "vote_events": { 110 | "description": "Vote events in which members of the organization are voting", 111 | "type": "array", 112 | "items": { 113 | "$ref": "http://www.popoloproject.com/schemas/vote_event.json#" 114 | } 115 | }, 116 | "votes": { 117 | "description": "Votes cast by the organization", 118 | "type": "array", 119 | "items": { 120 | "$ref": "http://www.popoloproject.com/schemas/vote.json#" 121 | } 122 | }, 123 | "children": { 124 | "description": "The sub-organizations of the organization", 125 | "type": "array", 126 | "items": { 127 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 128 | } 129 | }, 130 | "created_at": { 131 | "description": "The time at which the resource was created", 132 | "type": ["string", "null"], 133 | "format": "date-time" 134 | }, 135 | "updated_at": { 136 | "description": "The time at which the resource was last modified", 137 | "type": ["string", "null"], 138 | "format": "date-time" 139 | }, 140 | "sources": { 141 | "description": "URLs to documents from which the resource is derived", 142 | "type": "array", 143 | "items": { 144 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/other_name.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/other_name.json#", 4 | "title": "Other name", 5 | "description": "An alternate or former name", 6 | "type": "object", 7 | "properties": { 8 | "name": { 9 | "description": "An alternate or former name", 10 | "type": "string" 11 | }, 12 | "family_name": { 13 | "description": "One or more family names", 14 | "type": ["string", "null"] 15 | }, 16 | "given_name": { 17 | "description": "One or more primary given names", 18 | "type": ["string", "null"] 19 | }, 20 | "additional_name": { 21 | "description": "One or more secondary given names", 22 | "type": ["string", "null"] 23 | }, 24 | "honorific_prefix": { 25 | "description": "One or more honorifics preceding a person's name", 26 | "type": ["string", "null"] 27 | }, 28 | "honorific_suffix": { 29 | "description": "One or more honorifics following a person's name", 30 | "type": ["string", "null"] 31 | }, 32 | "patronymic_name": { 33 | "description": "One or more patronymic names", 34 | "type": ["string", "null"] 35 | }, 36 | "start_date": { 37 | "description": "The date on which the name was adopted", 38 | "type": ["string", "null"], 39 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 40 | }, 41 | "end_date": { 42 | "description": "The date on which the name was abandoned", 43 | "type": ["string", "null"], 44 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 45 | }, 46 | "note": { 47 | "description": "A note, e.g. 'Birth name'", 48 | "type": ["string", "null"] 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/person.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/person.json#", 4 | "title": "Person", 5 | "description": "A real person, alive or dead", 6 | "type": "object", 7 | "rdfSubject": "id", 8 | "properties": { 9 | "id": { 10 | "description": "The person's unique identifier", 11 | "type": ["string", "null"], 12 | "rdfType": "id" 13 | }, 14 | "name": { 15 | "description": "A person's preferred full name", 16 | "type": ["string", "null"] 17 | }, 18 | "other_names": { 19 | "description": "Alternate or former names", 20 | "type": "array", 21 | "items": { 22 | "$ref": "http://www.popoloproject.com/schemas/other_name.json#" 23 | } 24 | }, 25 | "identifiers": { 26 | "description": "Issued identifiers", 27 | "type": "array", 28 | "items": { 29 | "$ref": "http://www.popoloproject.com/schemas/identifier.json#" 30 | } 31 | }, 32 | "family_name": { 33 | "description": "One or more family names", 34 | "type": ["string", "null"] 35 | }, 36 | "given_name": { 37 | "description": "One or more primary given names", 38 | "type": ["string", "null"] 39 | }, 40 | "additional_name": { 41 | "description": "One or more secondary given names", 42 | "type": ["string", "null"] 43 | }, 44 | "honorific_prefix": { 45 | "description": "One or more honorifics preceding a person's name", 46 | "type": ["string", "null"] 47 | }, 48 | "honorific_suffix": { 49 | "description": "One or more honorifics following a person's name", 50 | "type": ["string", "null"] 51 | }, 52 | "patronymic_name": { 53 | "description": "One or more patronymic names", 54 | "type": ["string", "null"] 55 | }, 56 | "sort_name": { 57 | "description": "A name to use in a lexicographically ordered list", 58 | "type": ["string", "null"] 59 | }, 60 | "email": { 61 | "description": "A preferred email address", 62 | "type": ["string", "null"], 63 | "format": "email" 64 | }, 65 | "gender": { 66 | "description": "A gender", 67 | "type": ["string", "null"] 68 | }, 69 | "birth_date": { 70 | "description": "A date of birth", 71 | "type": ["string", "null"], 72 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 73 | }, 74 | "death_date": { 75 | "description": "A date of death", 76 | "type": ["string", "null"], 77 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 78 | }, 79 | "image": { 80 | "description": "A URL of a head shot", 81 | "type": ["string", "null"], 82 | "format": "uri" 83 | }, 84 | "summary": { 85 | "description": "A one-line account of a person's life", 86 | "type": ["string", "null"] 87 | }, 88 | "biography": { 89 | "description": "An extended account of a person's life", 90 | "type": ["string", "null"] 91 | }, 92 | "national_identity": { 93 | "description": "A national identity", 94 | "type": ["string", "null"] 95 | }, 96 | "contact_details": { 97 | "description": "Means of contacting the person", 98 | "type": "array", 99 | "items": { 100 | "$ref": "http://www.popoloproject.com/schemas/contact_detail.json#" 101 | } 102 | }, 103 | "links": { 104 | "description": "URLs to documents about the person", 105 | "type": "array", 106 | "items": { 107 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 108 | } 109 | }, 110 | "memberships": { 111 | "description": "The person's memberships", 112 | "type": "array", 113 | "items": { 114 | "$ref": "http://www.popoloproject.com/schemas/membership.json#" 115 | } 116 | }, 117 | "motions": { 118 | "description": "The person's motions", 119 | "type": "array", 120 | "items": { 121 | "$ref": "http://www.popoloproject.com/schemas/motion.json#" 122 | } 123 | }, 124 | "speeches": { 125 | "description": "The person's speeches", 126 | "type": "array", 127 | "items": { 128 | "$ref": "http://www.popoloproject.com/schemas/speech.json#" 129 | } 130 | }, 131 | "votes": { 132 | "description": "Votes cast by the person", 133 | "type": "array", 134 | "items": { 135 | "$ref": "http://www.popoloproject.com/schemas/vote.json#" 136 | } 137 | }, 138 | "created_at": { 139 | "description": "The time at which the resource was created", 140 | "type": ["string", "null"], 141 | "format": "date-time" 142 | }, 143 | "updated_at": { 144 | "description": "The time at which the resource was last modified", 145 | "type": ["string", "null"], 146 | "format": "date-time" 147 | }, 148 | "sources": { 149 | "description": "URLs to documents from which the resource is derived", 150 | "type": "array", 151 | "items": { 152 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 153 | } 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/post.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/post.json#", 4 | "title": "Post", 5 | "description": "A position that exists independent of the person holding it", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The post's unique identifier", 10 | "type": ["string", "null"] 11 | }, 12 | "label": { 13 | "description": "A label describing the post", 14 | "type": ["string", "null"] 15 | }, 16 | "other_label": { 17 | "description": "An alternate label", 18 | "type": "array", 19 | "items": { 20 | "type": "string" 21 | } 22 | }, 23 | "role": { 24 | "description": "The function that the holder of the post fulfills", 25 | "type": ["string", "null"] 26 | }, 27 | "organization_id": { 28 | "description": "The ID of the organization in which the post is held", 29 | "type": ["string", "null"] 30 | }, 31 | "organization": { 32 | "description": "The organization in which the post is held", 33 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 34 | }, 35 | "area_id": { 36 | "description": "The ID of the geographic area to which this post is related", 37 | "type": ["string", "null"] 38 | }, 39 | "area": { 40 | "description": "The geographic area to which this post is related", 41 | "$ref": "http://www.popoloproject.com/schemas/area.json#" 42 | }, 43 | "start_date": { 44 | "description": "The date on which the post was created", 45 | "type": ["string", "null"], 46 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 47 | }, 48 | "end_date": { 49 | "description": "The date on which the post was eliminated", 50 | "type": ["string", "null"], 51 | "pattern": "^[0-9]{4}(-[0-9]{2}){0,2}$" 52 | }, 53 | "contact_details": { 54 | "description": "Means of contacting the holder of the post", 55 | "type": "array", 56 | "items": { 57 | "$ref": "http://www.popoloproject.com/schemas/contact_detail.json#" 58 | } 59 | }, 60 | "links": { 61 | "description": "URLs to documents about the post", 62 | "type": "array", 63 | "items": { 64 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 65 | } 66 | }, 67 | "memberships": { 68 | "description": "The memberships through which people hold the post in the organization", 69 | "type": "array", 70 | "items": { 71 | "$ref": "http://www.popoloproject.com/schemas/membership.json#" 72 | } 73 | }, 74 | "created_at": { 75 | "description": "The time at which the resource was created", 76 | "type": ["string", "null"], 77 | "format": "date-time" 78 | }, 79 | "updated_at": { 80 | "description": "The time at which the resource was last modified", 81 | "type": ["string", "null"], 82 | "format": "date-time" 83 | }, 84 | "sources": { 85 | "description": "URLs to documents from which the resource is derived", 86 | "type": "array", 87 | "items": { 88 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/speech.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/speech.json#", 4 | "title": "Speech", 5 | "description": "A speech, a scene, a narrative, or another part of a transcript", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The speech's unique identifier", 10 | "type": ["string", "null"] 11 | }, 12 | "creator_id": { 13 | "description": "The ID of the person who is speaking", 14 | "type": ["string", "null"] 15 | }, 16 | "creator": { 17 | "description": "The person who is speaking", 18 | "$ref": "http://www.popoloproject.com/schemas/person.json#" 19 | }, 20 | "role": { 21 | "description": "The speaker's role while speaking", 22 | "type": ["string", "null"] 23 | }, 24 | "attribution_text": { 25 | "description": "The text identifying the speaker", 26 | "type": ["string", "null"] 27 | }, 28 | "audience_id": { 29 | "description": "The ID of the person to whom the speaker is speaking", 30 | "type": ["string", "null"] 31 | }, 32 | "audience": { 33 | "description": "The person to whom the speaker is speaking", 34 | "$ref": "http://www.popoloproject.com/schemas/person.json#" 35 | }, 36 | "text": { 37 | "description": "The transcript or text of the speech", 38 | "type": ["string", "null"] 39 | }, 40 | "audio": { 41 | "description": "The audio recording of the speech", 42 | "type": ["string", "null"], 43 | "format": "uri" 44 | }, 45 | "video": { 46 | "description": "The video recording of the speech", 47 | "type": ["string", "null"], 48 | "format": "uri" 49 | }, 50 | "date": { 51 | "description": "The time at which the speech is spoken", 52 | "type": ["string", "null"], 53 | "format": "date-time" 54 | }, 55 | "title": { 56 | "description": "A name given to the speech", 57 | "type": ["string", "null"] 58 | }, 59 | "type": { 60 | "description": "The type of the part of the transcript", 61 | "type": ["string", "null"] 62 | }, 63 | "position": { 64 | "description": "The position of the speech within a transcript", 65 | "type": ["integer", "null"] 66 | }, 67 | "event_id": { 68 | "description": "The ID of the event at which the speech is spoken", 69 | "type": ["string", "null"] 70 | }, 71 | "event": { 72 | "description": "The event at which the speech is spoken", 73 | "$ref": "http://www.popoloproject.com/schemas/event.json#" 74 | }, 75 | "created_at": { 76 | "description": "The time at which the resource was created", 77 | "type": ["string", "null"], 78 | "format": "date-time" 79 | }, 80 | "updated_at": { 81 | "description": "The time at which the resource was last modified", 82 | "type": ["string", "null"], 83 | "format": "date-time" 84 | }, 85 | "sources": { 86 | "description": "URLs to documents from which the resource is derived", 87 | "type": "array", 88 | "items": { 89 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/vote.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/vote.json#", 4 | "title": "Vote", 5 | "description": "A voter's vote in a vote event", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The vote's unique identifier", 10 | "type": ["string", "null"] 11 | }, 12 | "vote_event_id": { 13 | "description": "The ID of a vote event", 14 | "type": ["string", "null"] 15 | }, 16 | "vote_event": { 17 | "description": "A vote event", 18 | "$ref": "http://www.popoloproject.com/schemas/vote_event.json#" 19 | }, 20 | "voter_id": { 21 | "description": "The ID of the person or organization that is voting", 22 | "type": ["string", "null"] 23 | }, 24 | "voter": { 25 | "description": "The person or organization that is voting", 26 | "type": ["object", "null"] 27 | }, 28 | "option": { 29 | "description": "The option chosen by the voter, whether actively or passively", 30 | "type": ["string", "null"] 31 | }, 32 | "group_id": { 33 | "description": "The ID of the voter's primary political group", 34 | "type": ["string", "null"] 35 | }, 36 | "group": { 37 | "description": "The voter's primary political group", 38 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 39 | }, 40 | "role": { 41 | "description": "The voter's role in the event", 42 | "type": ["string", "null"] 43 | }, 44 | "weight": { 45 | "description": "The weight of the voter's vote", 46 | "type": ["number", "null"] 47 | }, 48 | "pair_id": { 49 | "description": "The ID of the person with whom the voter is paired", 50 | "type": ["string", "null"] 51 | }, 52 | "pair": { 53 | "description": "The person with whom the voter is paired", 54 | "$ref": "http://www.popoloproject.com/schemas/person.json#" 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/fixtures/schemas/vote_event.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-03/schema#", 3 | "id": "http://www.popoloproject.com/schemas/vote_event.json#", 4 | "title": "Vote event", 5 | "description": "An event at which people's votes are recorded", 6 | "type": "object", 7 | "properties": { 8 | "id": { 9 | "description": "The vote event's unique identifier", 10 | "type": ["string", "null"] 11 | }, 12 | "organization_id": { 13 | "description": "The ID of the organization whose members are voting", 14 | "type": ["string", "null"] 15 | }, 16 | "organization": { 17 | "description": "The organization whose members are voting", 18 | "$ref": "http://www.popoloproject.com/schemas/organization.json#" 19 | }, 20 | "legislative_session_id": { 21 | "description": "The ID of the legislative session in which the vote occurs", 22 | "type": ["string", "null"] 23 | }, 24 | "legislative_session": { 25 | "description": "The legislative session in which the vote occurs", 26 | "$ref": "http://www.popoloproject.com/schemas/event.json#" 27 | }, 28 | "identifier": { 29 | "description": "An issued identifier", 30 | "type": ["string", "null"] 31 | }, 32 | "motion_id": { 33 | "description": "The ID of the motion being decided", 34 | "type": ["string", "null"] 35 | }, 36 | "motion": { 37 | "description": "The motion being decided", 38 | "$ref": "http://www.popoloproject.com/schemas/motion.json#" 39 | }, 40 | "start_date": { 41 | "description": "The time at which the event begins", 42 | "type": ["string", "null"], 43 | "format": "date-time" 44 | }, 45 | "end_date": { 46 | "description": "The time at which the event ends", 47 | "type": ["string", "null"], 48 | "format": "date-time" 49 | }, 50 | "result": { 51 | "description": "The result of the vote event", 52 | "type": ["string", "null"] 53 | }, 54 | "group_results": { 55 | "description": "The result of the vote event within groups of voters", 56 | "type": "array", 57 | "items": { 58 | "$ref": "http://www.popoloproject.com/schemas/group_result.json#" 59 | } 60 | }, 61 | "counts": { 62 | "description": "The number of votes for options", 63 | "type": "array", 64 | "items": { 65 | "$ref": "http://www.popoloproject.com/schemas/count.json#" 66 | } 67 | }, 68 | "votes": { 69 | "description": "Voters' votes", 70 | "type": "array", 71 | "items": { 72 | "$ref": "http://www.popoloproject.com/schemas/vote.json#" 73 | } 74 | }, 75 | "created_at": { 76 | "description": "The time at which the resource was created", 77 | "type": ["string", "null"], 78 | "format": "date-time" 79 | }, 80 | "updated_at": { 81 | "description": "The time at which the resource was last modified", 82 | "type": ["string", "null"], 83 | "format": "date-time" 84 | }, 85 | "sources": { 86 | "description": "URLs to documents from which the resource is derived", 87 | "type": "array", 88 | "items": { 89 | "$ref": "http://www.popoloproject.com/schemas/link.json#" 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/fixtures/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "test.json" 3 | } 4 | -------------------------------------------------------------------------------- /tests/test_context.py: -------------------------------------------------------------------------------- 1 | import json 2 | import copy 3 | from nose.tools import raises 4 | from unittest import TestCase 5 | 6 | from jsongraph.util import GraphException 7 | 8 | from .util import make_test_graph, fixture_file 9 | 10 | DATA = json.load(fixture_file('rdfconv/bt_partial.json')) 11 | 12 | 13 | class ContextTestCase(TestCase): 14 | 15 | def setUp(self): 16 | super(ContextTestCase, self).setUp() 17 | self.data = copy.deepcopy(DATA) 18 | 19 | def test_basic_load_data(self): 20 | graph = make_test_graph() 21 | ctx = graph.context() 22 | assert 'urn' in repr(ctx), repr(ctx) 23 | assert str(ctx) in repr(ctx), repr(ctx) 24 | sc = lambda: len(list(graph.graph.triples((None, None, None)))) 25 | 26 | for org in sorted(self.data['organizations']): 27 | org_id = ctx.add('organizations', org) 28 | assert org_id is not None 29 | 30 | obj = ctx.get(org_id, schema='organizations') 31 | assert obj['name'] == org['name'], obj 32 | obj = ctx.get(org_id) 33 | assert obj['name'] == org['name'], obj 34 | 35 | ctx.delete() 36 | assert sc() == 0, sc() 37 | 38 | @raises(GraphException) 39 | def test_basic_get_invalid_schema(self): 40 | graph = make_test_graph() 41 | ctx = graph.context() 42 | for org in sorted(self.data['organizations']): 43 | uri = ctx.add('organizations', org) 44 | ctx.get(uri, schema='foo') 45 | 46 | def test_read_all(self): 47 | graph = make_test_graph() 48 | ctx = graph.context() 49 | 50 | for org in sorted(self.data['organizations']): 51 | ctx.add('organizations', org) 52 | 53 | ctx.save() 54 | loaded = list(ctx.all('organizations')) 55 | assert len(loaded) == len(self.data['organizations']), loaded 56 | assert len(loaded) > 0, loaded 57 | assert 'organization' in loaded[0]['$schema'], loaded[0] 58 | 59 | loaded2 = list(graph.all('organizations')) 60 | assert len(loaded2) == len(self.data['organizations']), loaded2 61 | assert len(loaded2) > 0, loaded2 62 | 63 | @raises(GraphException) 64 | def test_basic_all_invalid_schema(self): 65 | graph = make_test_graph() 66 | list(graph.all('foo')) 67 | 68 | def test_buffered_load_data(self): 69 | graph = make_test_graph(buffered=True) 70 | ctx = graph.context() 71 | assert 'urn' in repr(ctx), repr(ctx) 72 | assert str(ctx) in repr(ctx), repr(ctx) 73 | sc = lambda: len(list(graph.graph.triples((None, None, None)))) 74 | 75 | for org in sorted(self.data['organizations']): 76 | org_id = ctx.add('organizations', org) 77 | assert org_id is not None 78 | assert sc() == 0, sc() 79 | ctx.save() 80 | assert sc() != 0, sc() 81 | ctx.delete() 82 | assert sc() == 0, sc() 83 | break 84 | 85 | def test_restore_context(self): 86 | graph = make_test_graph() 87 | ctx = graph.context(meta={'source': 'blah'}) 88 | for org in sorted(self.data['organizations']): 89 | ctx.add('organizations', org) 90 | break 91 | 92 | ctx.save() 93 | ctx2 = graph.context(identifier=ctx.identifier) 94 | assert ctx is not ctx2, (ctx, ctx2) 95 | assert ctx.meta['created_at'] == ctx2.meta['created_at'], \ 96 | (ctx.meta, ctx2.meta) 97 | 98 | def test_delete_all_data(self): 99 | graph = make_test_graph() 100 | ctx = graph.context(meta={'source': 'blah'}) 101 | for org in sorted(self.data['organizations']): 102 | ctx.add('organizations', org) 103 | break 104 | sc = lambda: len(list(graph.graph.triples((None, None, None)))) 105 | assert sc() != 0, sc() 106 | graph.clear(context='foo') 107 | assert sc() != 0, sc() 108 | graph.clear() 109 | assert sc() == 0, sc() 110 | -------------------------------------------------------------------------------- /tests/test_graph.py: -------------------------------------------------------------------------------- 1 | from nose.tools import raises 2 | from unittest import TestCase 3 | 4 | from jsongraph.graph import Graph 5 | from jsongraph.util import GraphException 6 | 7 | from .util import make_test_graph, resolver 8 | from .util import PERSON_URI, MEM_URI 9 | 10 | 11 | class GraphTestCase(TestCase): 12 | 13 | def setUp(self): 14 | super(GraphTestCase, self).setUp() 15 | self.graph = make_test_graph() 16 | 17 | @raises(GraphException) 18 | def test_missing_schema(self): 19 | graph = Graph() 20 | graph.get_schema('foo') 21 | 22 | def test_graph(self): 23 | graph = Graph() 24 | assert 'github.io' in graph.base_uri, graph.base_uri 25 | assert graph.get_schema({}) == {}, graph.get_schema({}) 26 | assert 'github.io' in repr(graph), repr(graph) 27 | assert str(graph) in repr(graph), repr(graph) 28 | 29 | def test_graph_unconfigured(self): 30 | graph = Graph() 31 | assert graph.base_uri is not None 32 | assert graph.resolver is not None 33 | 34 | @raises(GraphException) 35 | def test_invalid_schema_config(self): 36 | Graph(config={'schemas': 5}) 37 | 38 | @raises(GraphException) 39 | def test_invalid_store_config(self): 40 | Graph(config={'store': {'update': 6, 'query': 'huhu'}}) 41 | 42 | def test_graph_sparql(self): 43 | config = { 44 | 'store': { 45 | 'query': 'http://localhost:3030/gk-test/query', 46 | 'update': 'http://localhost:3030/gk-test/update' 47 | } 48 | } 49 | graph = Graph(config=config) 50 | assert graph.store is not None, graph.store 51 | assert 'SPARQLUpdateStore' in repr(graph.store), graph.store 52 | assert graph.buffered is True, graph.buffered 53 | 54 | def test_register(self): 55 | assert self.graph.resolver == resolver, self.graph 56 | assert 'memberships' not in self.graph.aliases 57 | self.graph.register('memberships', MEM_URI) 58 | assert 'memberships' in self.graph.aliases 59 | 60 | data = {"id": 'http://foo.bar'} 61 | self.graph.register('bar', data) 62 | assert self.graph.get_uri('bar') == data['id'], \ 63 | self.graph.get_uri('bar') 64 | assert self.graph.get_schema('bar') == data, \ 65 | self.graph.get_schema('bar') 66 | 67 | def test_get_uri(self): 68 | assert self.graph.resolver == resolver, self.graph 69 | assert 'persons' in self.graph.aliases 70 | assert self.graph.get_uri('persons') == PERSON_URI, \ 71 | self.graph.get_uri('persons') 72 | 73 | def test_get_schema(self): 74 | schema1 = self.graph.get_schema('persons') 75 | schema2 = self.graph.get_schema(PERSON_URI) 76 | assert schema1 == schema2 77 | assert 'id' in schema1 78 | assert schema1['id'] == PERSON_URI, schema1['id'] 79 | 80 | def test_resolver(self): 81 | assert self.graph.resolver.resolution_scope in self.graph.base_uri 82 | 83 | def test_graph_store(self): 84 | g = self.graph.graph 85 | assert g.store == self.graph.store, g.store 86 | assert g.identifier == self.graph.base_uri, g.identifier 87 | -------------------------------------------------------------------------------- /tests/test_metadata.py: -------------------------------------------------------------------------------- 1 | # from rdflib import ConjunctiveGraph 2 | from unittest import TestCase 3 | 4 | # from jsongraph.metadata import MetaData 5 | 6 | from .util import make_test_graph 7 | 8 | 9 | class MetaDataTestCase(TestCase): 10 | 11 | def setUp(self): 12 | super(MetaDataTestCase, self).setUp() 13 | self.graph = make_test_graph() 14 | 15 | def test_basic_context(self): 16 | data = {'source_url': 'http://pudo.org'} 17 | ctx = self.graph.context(meta=data) 18 | assert 'pudo.org' in ctx.meta.get('source_url') 19 | ctx.meta['label'] = 'Banana' 20 | assert 'label' in ctx.meta 21 | -------------------------------------------------------------------------------- /tests/test_query.py: -------------------------------------------------------------------------------- 1 | import json 2 | from unittest import TestCase 3 | 4 | from .util import make_test_graph, fixture_file 5 | 6 | CTX = {} 7 | 8 | 9 | def get_context(): 10 | if 'ctx' not in CTX: 11 | data = json.load(fixture_file('rdfconv/bt_partial.json')) 12 | graph = make_test_graph() 13 | context = graph.context() 14 | for org in sorted(data['organizations']): 15 | context.add('organizations', org) 16 | for per in sorted(data['persons']): 17 | context.add('persons', per) 18 | CTX['ctx'] = context 19 | return CTX['ctx'] 20 | 21 | 22 | class ContextTestCase(TestCase): 23 | 24 | def setUp(self): 25 | super(ContextTestCase, self).setUp() 26 | 27 | def test_basic_query(self): 28 | context = get_context() 29 | res = context.query({'limit': 100, 'name': None}).results() 30 | assert res['status'] == 'ok', res 31 | assert res['query']['limit'] == 1, res 32 | assert res['result']['name'] is not None, res 33 | 34 | def test_list_query(self): 35 | context = get_context() 36 | res = context.query([{'id': None, 'name': None}]).results() 37 | assert res['status'] == 'ok' 38 | assert len(res['result']) == 15 39 | fst = res['result'][0] 40 | assert 'id' in fst, fst 41 | assert 'name' in fst, fst 42 | 43 | def test_nested_query(self): 44 | context = get_context() 45 | res = context.query({ 46 | 'memberships': [{ 47 | 'organization': {'name': "CSU", "id": None} 48 | }], 49 | 'contact_details': [] 50 | }).results() 51 | assert res['status'] == 'ok' 52 | # from pprint import pprint 53 | # pprint(res) 54 | assert len(res['result']) > 0 55 | 56 | def test_query_multiple(self): 57 | context = get_context() 58 | q = [{'id': None, 'limit': 2, 'memberships': [ 59 | {'id': None, 'organization': {'name': None}} 60 | ]}] 61 | res = context.query(q).results() 62 | assert res['status'] == 'ok' 63 | assert len(res['result']) == 2, res 64 | res = res['result'][0] 65 | assert 'id' in res, res 66 | assert 'memberships' in res, res 67 | assert isinstance(res['memberships'], list), res 68 | assert 'id' in res['memberships'][0], res 69 | # from pprint import pprint 70 | # pprint(res) 71 | # assert False 72 | 73 | def test_query_simple_filter(self): 74 | context = get_context() 75 | q = [{'id': None, 'limit': 10, 'name': 'CSU'}] 76 | res = context.query(q).results() 77 | assert res['status'] == 'ok' 78 | assert len(res['result']) == 1, res 79 | res0 = res['result'][0] 80 | assert res0['name'] == 'CSU', res 81 | assert 'csu' in res0['id'], res 82 | 83 | def test_query_negative_filter(self): 84 | context = get_context() 85 | q = [{'id': None, 'limit': 10, 'name!=': 'CSU'}] 86 | res = context.query(q).results() 87 | assert res['status'] == 'ok' 88 | assert len(res['result']) > 1, res 89 | for rec in res['result']: 90 | assert rec['name'] != 'CSU', res 91 | assert 'csu' not in rec['id'], res 92 | 93 | def test_query_regex_filter(self): 94 | context = get_context() 95 | q = [{'id': None, 'limit': 10, 'name~=': '90'}] 96 | res = context.query(q).results() 97 | assert res['status'] == 'ok' 98 | assert len(res['result']) == 1, res 99 | for rec in res['result']: 100 | assert '90' in rec['name'], rec 101 | 102 | def test_query_list_filter(self): 103 | context = get_context() 104 | items = ['SPD', 'CSU'] 105 | q = [{'id': None, 'limit': 10, 'name|=': items}] 106 | res = context.query(q).results() 107 | assert res['status'] == 'ok' 108 | assert len(res['result']) == 2, res 109 | for rec in res['result']: 110 | assert rec['name'] in items, rec 111 | 112 | def test_query_negative_list_filter(self): 113 | context = get_context() 114 | items = ['SPD', 'CSU'] 115 | q = [{'id': None, 'limit': 1000, 'name|!=': items}] 116 | res = context.query(q).results() 117 | assert res['status'] == 'ok' 118 | assert len(res['result']) > 2, res 119 | for rec in res['result']: 120 | assert rec['name'] not in items, rec 121 | 122 | def test_query_wildcard_fields(self): 123 | context = get_context() 124 | q = [{'*': None, '$schema': 'persons', 'limit': 10}] 125 | res = context.query(q).results() 126 | assert res['status'] == 'ok' 127 | assert len(res['result']) == 10, res 128 | for rec in res['result']: 129 | assert 'id' in rec, rec 130 | assert 'name' in rec, rec 131 | assert '$schema' in rec, rec 132 | assert 'limit' not in rec, rec 133 | # from pprint import pprint 134 | # pprint(res) 135 | # assert False 136 | 137 | q = [{'*': None, 'limit': 10}] 138 | res = context.query(q).results() 139 | for rec in res['result']: 140 | assert '$schema' in rec, rec 141 | assert 'limit' not in rec, rec 142 | -------------------------------------------------------------------------------- /tests/test_reflect.py: -------------------------------------------------------------------------------- 1 | # from rdflib import ConjunctiveGraph 2 | from unittest import TestCase 3 | 4 | from jsongraph import reflect 5 | 6 | from .util import make_test_graph, ORG_URI 7 | 8 | 9 | class ReflectTestCase(TestCase): 10 | 11 | def setUp(self): 12 | super(ReflectTestCase, self).setUp() 13 | self.graph = make_test_graph() 14 | 15 | def test_predicates(self): 16 | preds = list(reflect.predicates(self.graph)) 17 | t = ('string', 'null') 18 | assert (ORG_URI, 'name', t) in preds, preds 19 | t = ('array',) 20 | assert (ORG_URI, 'memberships', t) in preds, preds 21 | -------------------------------------------------------------------------------- /tests/util.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import urllib 4 | 5 | from jsonschema import RefResolver # noqa 6 | 7 | fixtures_dir = os.path.join(os.path.dirname(__file__), 'fixtures') 8 | BASE_URI = 'http://www.popoloproject.com/schemas' 9 | PERSON_URI = BASE_URI + '/person.json#' 10 | ORG_URI = BASE_URI + '/organization.json#' 11 | MEM_URI = BASE_URI + '/membership.json#' 12 | 13 | 14 | def fixture_file(path): 15 | file_name = os.path.join(fixtures_dir, path) 16 | return open(file_name, 'rb') 17 | 18 | 19 | def fixture_uri(path): 20 | base = os.path.join(fixtures_dir, path) 21 | base_uri = 'file://' + urllib.pathname2url(base) 22 | with open(base, 'rb') as fh: 23 | return json.load(fh), base_uri 24 | 25 | 26 | def create_resolver(): 27 | resolver = RefResolver(BASE_URI, BASE_URI) 28 | schemas = os.path.join(fixtures_dir, 'schemas') 29 | for fn in os.listdir(schemas): 30 | path = os.path.join(schemas, fn) 31 | with open(path, 'rb') as fh: 32 | data = json.load(fh) 33 | resolver.store[data.get('id')] = data 34 | return resolver 35 | 36 | 37 | resolver = create_resolver() 38 | 39 | 40 | def make_test_graph(buffered=False): 41 | from jsongraph.graph import Graph 42 | config = { 43 | 'buffered': buffered, 44 | 'schemas': { 45 | 'persons': PERSON_URI, 46 | 'organizations': ORG_URI 47 | } 48 | } 49 | if 'JSONGRAPH_TEST_SPARQL_QUERY' in os.environ: 50 | config['store'] = { 51 | 'query': os.environ.get('JSONGRAPH_TEST_SPARQL_QUERY'), 52 | 'update': os.environ.get('JSONGRAPH_TEST_SPARQL_UPDATE') 53 | } 54 | return Graph(config=config, resolver=resolver) 55 | --------------------------------------------------------------------------------