You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2020/12/12 00:21:08 UTC

[atlas] branch master updated: ATLAS-4077: updated Python client to support Python 2.7

This is an automated email from the ASF dual-hosted git repository.

madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git


The following commit(s) were added to refs/heads/master by this push:
     new 77943a9  ATLAS-4077: updated Python client to support Python 2.7
77943a9 is described below

commit 77943a9489bd49e53b1e8572fa9ea32ae02e5b04
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Tue Dec 8 17:44:28 2020 -0800

    ATLAS-4077: updated Python client to support Python 2.7
---
 .../src/main/python/discovery_example.py           |   1 +
 .../sample-app/src/main/python/entity_example.py   | 178 ++++-----
 .../sample-app/src/main/python/glossary_example.py |  13 +-
 .../sample-app/src/main/python/lineage_example.py  |  12 +-
 .../main/python/request_json/entity_create_db.json |  26 +-
 .../python/request_json/entity_create_process.json |  44 +--
 .../request_json/entity_create_table_canada.json   | 165 +++------
 .../request_json/entity_create_table_us.json       | 163 +++-----
 .../main/python/request_json/typedef_create.json   | 410 +++++----------------
 .../sample-app/src/main/python/sample_client.py    | 117 +++---
 .../sample-app/src/main/python/typedef_example.py  |  92 ++---
 atlas-examples/sample-app/src/main/python/utils.py |  27 +-
 intg/src/main/python/README.md                     | 153 +++++++-
 .../apache_atlas/{ => client}/base_client.py       |  40 +-
 .../main/python/apache_atlas/client/discovery.py   |  12 +-
 intg/src/main/python/apache_atlas/client/entity.py |   9 +-
 .../main/python/apache_atlas/client/glossary.py    |   8 +-
 .../src/main/python/apache_atlas/client/lineage.py |   6 +-
 .../python/apache_atlas/client/relationship.py     |   6 +-
 .../src/main/python/apache_atlas/client/typedef.py |   7 +-
 intg/src/main/python/apache_atlas/exceptions.py    |   9 +-
 .../main/python/apache_atlas/model/discovery.py    | 281 +++++++-------
 intg/src/main/python/apache_atlas/model/entity.py  | 167 ---------
 intg/src/main/python/apache_atlas/model/enums.py   | 149 ++++++++
 .../src/main/python/apache_atlas/model/glossary.py | 286 +++++++-------
 .../src/main/python/apache_atlas/model/instance.py | 299 +++++++++++++++
 intg/src/main/python/apache_atlas/model/lineage.py |  37 +-
 .../src/main/python/apache_atlas/model/metrics.py  |  21 +-
 intg/src/main/python/apache_atlas/model/misc.py    |  90 +++++
 intg/src/main/python/apache_atlas/model/profile.py |  37 ++
 .../main/python/apache_atlas/model/relationship.py |  75 ++--
 intg/src/main/python/apache_atlas/model/typedef.py | 260 +++++++------
 intg/src/main/python/apache_atlas/utils.py         |  76 +++-
 intg/src/main/python/setup.py                      |  13 +-
 34 files changed, 1753 insertions(+), 1536 deletions(-)

diff --git a/atlas-examples/sample-app/src/main/python/discovery_example.py b/atlas-examples/sample-app/src/main/python/discovery_example.py
index 93aae1d..a62de3f 100644
--- a/atlas-examples/sample-app/src/main/python/discovery_example.py
+++ b/atlas-examples/sample-app/src/main/python/discovery_example.py
@@ -16,6 +16,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
 import logging
 
 from utils import TABLE_TYPE
diff --git a/atlas-examples/sample-app/src/main/python/entity_example.py b/atlas-examples/sample-app/src/main/python/entity_example.py
index 2cd5da1..b08b675 100644
--- a/atlas-examples/sample-app/src/main/python/entity_example.py
+++ b/atlas-examples/sample-app/src/main/python/entity_example.py
@@ -20,7 +20,10 @@
 import json
 import logging
 
-from apache_atlas.model.entity import AtlasEntityWithExtInfo, EntityMutations
+from apache_atlas.model.enums    import EntityOperation
+from apache_atlas.model.instance import AtlasEntityWithExtInfo, EntityMutations, AtlasRelatedObjectId
+from apache_atlas.utils          import type_coerce
+
 
 LOG = logging.getLogger('entity-example')
 
@@ -41,10 +44,10 @@ class EntityExample:
 
     def __init__(self, client):
         self.client              = client
-        self.db_entity           = None
+        self.entity_db           = None
         self.entity_table_us     = None
         self.entity_table_canada = None
-        self.load_process        = None
+        self.entity_process      = None
 
     def create_entities(self):
         self.__create_db()
@@ -58,132 +61,129 @@ class EntityExample:
 
         return None
 
-    def get_entity_by_guid(self, entity_guid):
-        entity_with_ext_info = self.client.entity.get_entity_by_guid(entity_guid)
+    def get_entity_by_guid(self, guid):
+        entity = self.client.entity.get_entity_by_guid(guid)
 
-        if entity_with_ext_info:
-            LOG.info("Entity info is : %s", entity_with_ext_info)
+        LOG.info("Entity(guid=%s): typeName=%s, attr.name=%s", guid, entity.entity.typeName, entity.entity.attributes['name'])
 
     def remove_entities(self):
-        delete_entity_list = [self.load_process['guid'], self.entity_table_us['guid'], self.entity_table_canada['guid'], self.db_entity['guid']]
-        response           = self.client.entity.purge_entities_by_guids(delete_entity_list)
-
-        if not response:
-            LOG.info("There is no entity to delete!")
+        entity_list = [ self.entity_process.guid, self.entity_table_us.guid, self.entity_table_canada.guid, self.entity_db.guid ]
 
-        LOG.info("Deletion complete for DB entity: %s, US entity: %s, Canada entity: %s and Process entity: %s",
-                 self.db_entity['typeName'],
-                 self.entity_table_us['typeName'],
-                 self.entity_table_canada['typeName'],
-                 self.load_process['typeName'])
+        self.client.entity.delete_entities_by_guids(entity_list)
 
-    def __create_db(self):
-        if not self.db_entity:
-            with open('request_json/entity_create_db.json') as f:
-                entity_db      = json.load(f)
-                self.db_entity = self.__create_db_helper(entity_db)
+        response = self.client.entity.purge_entities_by_guids(entity_list)
 
-        if self.db_entity:
-            LOG.info("Created database entity: %s", self.db_entity['typeName'])
+        if response is not None:
+            LOG.info("Purged entities")
         else:
-            LOG.info("Database entity not created")
+            LOG.info("Purge failed!")
 
-    def __create_db_helper(self, ext_info):
-        instance_entity = ext_info['entity']
-        entity          = self.__create_entity(ext_info)
+    def __create_db(self):
+        if not self.entity_db:
+            with open('request_json/entity_create_db.json') as f:
+                entity = type_coerce(json.load(f), AtlasEntityWithExtInfo)
 
-        if entity and entity['guid']:
-            instance_entity['guid'] = entity['guid']
+                self.entity_db = self.__create_db_helper(entity)
 
-        return instance_entity
+        if self.entity_db:
+            LOG.info("Created database entity: guid=%s, attr.name=%s", self.entity_db.guid, self.entity_db.attributes['name'])
+        else:
+            LOG.info("Failed to create database entity")
 
     def __create_us_table(self):
         if not self.entity_table_us:
             with open('request_json/entity_create_table_us.json') as f:
-                entity_table_us      = json.load(f)
-                self.entity_table_us = self.__create_table_helper(entity_table_us)
+                entity = type_coerce(json.load(f), AtlasEntityWithExtInfo)
 
-        if self.entity_table_us:
-            LOG.info("Created table entity for US: %s", self.entity_table_us['typeName'])
-        else:
-            LOG.info("Table entity for US not created")
+                self.entity_table_us = self.__create_table_helper(entity)
+
+            if self.entity_table_us:
+                LOG.info("Created US table entity: guid=%s, attr.name=%s", self.entity_table_us.guid, self.entity_table_us.attributes['name'])
+            else:
+                LOG.info("Failed to create US table entity")
 
     def __create_canada_table(self):
         if not self.entity_table_canada:
             with open('request_json/entity_create_table_canada.json') as f:
-                entity_table_canada      = json.load(f)
-                self.entity_table_canada = self.__create_table_helper(entity_table_canada)
+                entity = type_coerce(json.load(f), AtlasEntityWithExtInfo)
 
-        if self.entity_table_canada:
-            LOG.info("Created table entity for Canada: %s", self.entity_table_canada['typeName'])
-        else:
-            LOG.info("Table entity for Canada not created")
+                self.entity_table_canada = self.__create_table_helper(entity)
 
-    def __create_table_helper(self, ext_info):
-        instance_entity = ext_info['entity']
+            if self.entity_table_canada:
+                LOG.info("Created Canada table entity: guid=%s, attr.name=%s", self.entity_table_canada.guid, self.entity_table_canada.attributes['name'])
+            else:
+                LOG.info("Failed to create Canada table entity")
 
-        if self.db_entity:
-            instance_entity['relationshipAttributes']['db']['guid']     = self.db_entity['guid']
-            instance_entity['relationshipAttributes']['db']['typeName'] = self.db_entity['typeName']
+    def __create_process(self):
+        if not self.entity_process:
+            with open('request_json/entity_create_process.json') as f:
+                entity = type_coerce(json.load(f), AtlasEntityWithExtInfo)
 
-        ext_info['entity'] = instance_entity
+                self.entity_process = self.__create_process_helper(entity)
 
-        entity = self.__create_entity(ext_info)
+        if self.entity_process:
+            LOG.info("Created process entity: guid=%s, attr.name=%s", self.entity_process.guid, self.entity_process.attributes['name'])
+        else:
+            LOG.info("Failed to createa process entity")
 
-        if entity and entity['guid']:
-            instance_entity['guid'] = entity['guid']
+    def __create_db_helper(self, entity):
+        self.__create_entity(entity)
 
-        return instance_entity
+        return entity.entity
 
-    def __create_process(self):
-        if not self.load_process:
-            with open('request_json/entity_create_process.json') as f:
-                entity_process    = json.load(f)
-                self.load_process = self.__create_process_helper(entity_process)
+    def __create_table_helper(self, entity):
+        table = entity.entity
 
-        if self.load_process:
-            LOG.info("Created process Entity: %s", self.load_process['typeName'])
-        else:
-            LOG.info("Process Entity not created")
+        if self.entity_db:
+            dbId = AtlasRelatedObjectId({ 'guid': self.entity_db.guid })
 
-    def __create_process_helper(self, ext_info):
-        instance_entity = ext_info['entity']
+            LOG.info("setting: table(%s).db=%s", table.guid, dbId)
 
-        if self.entity_table_us:
-            input_list = []
-            input_data = {'guid': self.entity_table_us['guid'],
-                          'typeName': self.entity_table_us['typeName']
-                          }
+            table.relationshipAttributes['db'] = dbId
 
-            input_list.append(input_data)
+        self.__create_entity(entity)
 
-            instance_entity['relationshipAttributes']['inputs'] = input_list
+        return table
 
-        if self.entity_table_canada:
-            output_list = []
-            output_data = {'guid': self.entity_table_canada['guid'],
-                           'typeName': self.entity_table_canada['typeName']
-                           }
+    def __create_process_helper(self, entity):
+        process = entity.entity
 
-            output_list.append(output_data)
+        process.relationshipAttributes = {}
 
-            instance_entity['relationshipAttributes']['outputs'] = output_list
+        if self.entity_table_us:
+            process.relationshipAttributes['inputs'] = [ AtlasRelatedObjectId({ 'guid': self.entity_table_us.guid }) ]
 
-        ext_info['entity'] = instance_entity
+        if self.entity_table_canada:
+            process.relationshipAttributes['outputs'] = [ AtlasRelatedObjectId({'guid': self.entity_table_canada.guid }) ]
 
-        return self.__create_entity(ext_info)
+        return self.__create_entity(entity)
 
-    def __create_entity(self, ext_info):
+    def __create_entity(self, entity):
         try:
-            entity      = self.client.entity.create_entity(ext_info)
-            create_enum = EntityMutations.entity_operation_enum.CREATE.name
+            response = self.client.entity.create_entity(entity)
+
+            guid = None
+
+            if response and response.mutatedEntities:
+                if EntityOperation.CREATE.name in response.mutatedEntities:
+                    header_list = response.mutatedEntities[EntityOperation.CREATE.name]
+                elif EntityOperation.UPDATE.name in response.mutatedEntities:
+                    header_list = response.mutatedEntities[EntityOperation.UPDATE.name]
+
+                if header_list and len(header_list) > 0:
+                    guid = header_list[0].guid
+            elif response and response.guidAssignments:
+                if entity.entity is not None and entity.entity.guid is not None:
+                    in_guid = entity.entity.guid
+                else:
+                    in_guid = None
 
-            if entity and entity.mutatedEntities and entity.mutatedEntities[create_enum]:
-                header_list = entity.mutatedEntities[create_enum]
+                if in_guid and response.guidAssignments[in_guid]:
+                    guid = response.guidAssignments[in_guid]
 
-                if len(header_list) > 0:
-                    return header_list[0]
+            if guid:
+                entity.entity.guid = guid
         except Exception as e:
-            LOG.exception("failed to create entity %s", ext_info['entity'])
+            LOG.exception("failed to create entity %s. error=%s", entity, e)
 
-        return None
\ No newline at end of file
+        return entity.entity if entity and entity.entity else None
diff --git a/atlas-examples/sample-app/src/main/python/glossary_example.py b/atlas-examples/sample-app/src/main/python/glossary_example.py
index ab5e201..449c2bc 100644
--- a/atlas-examples/sample-app/src/main/python/glossary_example.py
+++ b/atlas-examples/sample-app/src/main/python/glossary_example.py
@@ -18,6 +18,7 @@
 # limitations under the License.
 
 import logging
+
 from apache_atlas.model.glossary import AtlasGlossary, AtlasGlossaryCategory, AtlasGlossaryTerm, AtlasGlossaryHeader
 
 LOG = logging.getLogger('glossary-example')
@@ -33,7 +34,7 @@ class GlossaryExample:
         self.emp_company_category = None
 
     def create_glossary(self):
-        glossary          = AtlasGlossary(None, None, GlossaryExample.glossaryName, "This is a test Glossary")
+        glossary          = AtlasGlossary({ 'name': GlossaryExample.glossaryName, 'shortDescription': 'This is a test Glossary' })
         self.emp_glossary = self.client.glossary.create_glossary(glossary)
 
         LOG.info("Created glossary with name: %s and guid: %s", self.emp_glossary.name, self.emp_glossary.guid)
@@ -47,16 +48,18 @@ class GlossaryExample:
             LOG.info("Glossary extended info: %s; name: %s; language: %s", ext_info.guid, ext_info.name, ext_info.language)
 
     def create_glossary_term(self):
-        header               = AtlasGlossaryHeader(self.emp_glossary.guid, None, self.emp_glossary.name)
-        term                 = AtlasGlossaryTerm(None, None, "EmpSalaryTerm", None, None, None, None, None, None, None, header)
+        header = AtlasGlossaryHeader({ 'glossaryGuid': self.emp_glossary.guid, 'displayText': self.emp_glossary.name })
+        term   = AtlasGlossaryTerm({ 'name': 'EmpSalaryTerm', 'anchor': header })
+
         self.emp_salary_term = self.client.glossary.create_glossary_term(term)
 
         if self.emp_salary_term:
             LOG.info("Created Term for Employee Salary: %s with guid: %s", self.emp_salary_term.name, self.emp_salary_term.guid)
 
     def create_glossary_category(self):
-        header                    = AtlasGlossaryHeader(self.emp_glossary.guid, None, self.emp_glossary.name)
-        category                  = AtlasGlossaryCategory(None, None, "EmpSalaryCategory", None, None, None, None, header)
+        header   = AtlasGlossaryHeader({ 'glossaryGuid': self.emp_glossary.guid, 'displayText': self.emp_glossary.name })
+        category = AtlasGlossaryCategory({ 'name': 'EmpSalaryCategory', 'anchor': header })
+
         self.emp_company_category = self.client.glossary.create_glossary_category(category)
 
         if self.emp_company_category:
diff --git a/atlas-examples/sample-app/src/main/python/lineage_example.py b/atlas-examples/sample-app/src/main/python/lineage_example.py
index 42e2398..5341eda 100644
--- a/atlas-examples/sample-app/src/main/python/lineage_example.py
+++ b/atlas-examples/sample-app/src/main/python/lineage_example.py
@@ -16,20 +16,20 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
 import logging
 
-from apache_atlas.model.lineage import AtlasLineageInfo
+from apache_atlas.model.enums import LineageDirection
 
 LOG = logging.getLogger('lineage-example')
 
 
 class LineageExample:
-
     def __init__(self, client):
         self.client = client
 
     def lineage(self, guid):
-        direction    = AtlasLineageInfo.lineageDirection_enum.BOTH.name
+        direction    = LineageDirection.BOTH.name
         lineage_info = self.client.lineage.get_lineage_info(guid, direction, 0)
 
         if not lineage_info:
@@ -40,7 +40,7 @@ class LineageExample:
         guid_entity_map = lineage_info.guidEntityMap
 
         for relation in relations:
-            from_entity = guid_entity_map[relation['fromEntityId']]
-            to_entity   = guid_entity_map[relation['toEntityId']]
+            from_entity = guid_entity_map[relation.fromEntityId]
+            to_entity   = guid_entity_map[relation.toEntityId]
 
-            LOG.info("%s (%s) -> %s (%s)", from_entity['displayText'], from_entity['typeName'], to_entity['displayText'], to_entity['typeName'])
\ No newline at end of file
+            LOG.info("%s (%s) -> %s (%s)", from_entity.displayText, from_entity.typeName, to_entity.displayText, to_entity.typeName)
\ No newline at end of file
diff --git a/atlas-examples/sample-app/src/main/python/request_json/entity_create_db.json b/atlas-examples/sample-app/src/main/python/request_json/entity_create_db.json
index c6f8a87..f7dc525 100644
--- a/atlas-examples/sample-app/src/main/python/request_json/entity_create_db.json
+++ b/atlas-examples/sample-app/src/main/python/request_json/entity_create_db.json
@@ -1,19 +1,15 @@
 {
   "entity": {
-    "typeName": "sample_db_type",
+    "guid":       "-1",
+    "typeName":   "sample_db",
     "attributes": {
-      "owner": "user",
-      "createTime": 1000,
-      "@cl1": "employeeCluster",
-      "qualifiedName": "employee_db_entity@cl1",
-      "name": "employee_db_entity",
-      "description": "employee database",
-      "locationUri": "/tmp"
-    },
-    "guid": "-222736766326565",
-    "isIncomplete": false,
-    "provenanceType": 0,
-    "version": 0,
-    "proxy": false
+      "name":          "employee_db",
+      "qualifiedName": "employee_db@cl1",
+      "description":   "employee database",
+      "owner":         "user",
+      "clusterName":   "cl1",
+      "locationUri":   "/hive/database/employee_db",
+      "createTime":    1607476058882
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/atlas-examples/sample-app/src/main/python/request_json/entity_create_process.json b/atlas-examples/sample-app/src/main/python/request_json/entity_create_process.json
index f59ec48..26addbb 100644
--- a/atlas-examples/sample-app/src/main/python/request_json/entity_create_process.json
+++ b/atlas-examples/sample-app/src/main/python/request_json/entity_create_process.json
@@ -1,37 +1,19 @@
 {
   "entity": {
-    "typeName": "sample_process_type",
+    "typeName":   "sample_process",
     "attributes": {
-      "queryGraph": "graph",
-      "qualifiedName": "employee_process_entity@cl1",
-      "name": "employee_process_entity",
-      "queryText": "create table as select ",
-      "description": "hive query for monthly avg salary",
-      "startTime": 1596855233685,
-      "queryPlan": "plan",
-      "operationType": "testOperation",
-      "endTime": 1596855243685,
-      "userName": "user ETL",
-      "queryId": "id"
+      "name":          "employee_process",
+      "description":   "hive query for monthly avg salary",
+      "qualifiedName": "employee_process@cl1",
+      "userName":      "user ETL",
+      "startTime":     1607476549507,
+      "endTime":       1607476552529,
+      "queryText":     "create table as select ",
+      "queryId":       "<query-id>"
     },
-    "guid": "-222736766326574",
-    "isIncomplete": false,
-    "provenanceType": 0,
-    "version": 0,
     "relationshipAttributes": {
-      "outputs": [{
-        "guid": "b0619fb9-b025-4348-8b8a-79e8faa0e789",
-        "typeName": "sample_table_type"
-      }],
-      "inputs": [{
-        "guid": "b49bb0fe-4714-4122-901a-9ac433a89ccd",
-        "typeName": "sample_table_type"
-      }]
-    },
-    "classifications": [{
-      "typeName": "classification",
-      "entityStatus": "ACTIVE"
-    }],
-    "proxy": false
+      "inputs":  [ { "typeName": "sample_table", "uniqueAttributes": { "qualifiedName": "employee_db.employees_us@cl1"     } } ],
+      "outputs": [ { "typeName": "sample_table", "uniqueAttributes": { "qualifiedName": "employee_db.employees_canada@cl1" } } ]
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_canada.json b/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_canada.json
index 8838841..25a114d 100644
--- a/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_canada.json
+++ b/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_canada.json
@@ -1,124 +1,59 @@
 {
+  "entity": {
+    "guid":       "-1",
+    "typeName":   "sample_table",
+    "attributes": {
+      "name":          "employees_canada",
+      "description":   "Canada employees",
+      "qualifiedName": "employee_db.employees_canada@cl1",
+      "tableType":     "Managed",
+      "serde1":        { "typeName": "sample_serdeType", "attributes": { "name": "serde1", "serde": "serde1" } },
+      "serde2":        { "typeName": "sample_serdeType", "attributes": { "name": "serde2", "serde": "serde2" } }
+    },
+
+    "relationshipAttributes": {
+      "db":      { "typeName": "sample_db", "uniqueAttributes": { "qualifiedName": "employee_db@cl1" } },
+      "columns": [
+	    { "guid": "-2" },
+		{ "guid": "-3" },
+		{ "guid": "-4" }
+	  ]
+    }
+  },
+
   "referredEntities": {
-    "-222736766326566": {
-      "typeName": "sample_column_type",
+    "-2": {
+      "guid":       "-2",
+      "typeName":   "sample_column",
       "attributes": {
-        "qualifiedName": "time_id@cl1",
-        "dataType": "int",
-        "name": "time_id",
-        "comment": "time id"
-      },
-      "guid": "-222736766326566",
-      "isIncomplete": false,
-      "provenanceType": 0,
-      "version": 0,
-      "relationshipAttributes": {
-        "table": {
-          "guid": "-222736766326569",
-          "typeName": "sample_table_type"
-        }
-      },
-      "classifications": [],
-      "proxy": false
+        "table":         { "guid": "-1" },
+        "name":          "time_id",
+        "dataType":      "int",
+        "comment":       "time id",
+        "qualifiedName": "employee_db.employees_canada.time_id@cl1"
+	  }
     },
-    "-222736766326567": {
-      "typeName": "sample_column_type",
+    "-3": {
+      "guid":       "-3",
+      "typeName":   "sample_column",
       "attributes": {
-        "qualifiedName": "customer_id@cl1",
-        "dataType": "int",
-        "name": "customer_id",
-        "comment": "customer id"
-      },
-      "guid": "-222736766326567",
-      "isIncomplete": false,
-      "provenanceType": 0,
-      "version": 0,
-      "relationshipAttributes": {
-        "table": {
-          "guid": "-222736766326569",
-          "typeName": "sample_table_type"
-        }
-      },
-      "classifications": [{
-        "typeName": "sample_pii_Tag",
-        "entityStatus": "ACTIVE"
-      }],
-      "proxy": false
+        "table":         { "guid": "-1" },
+        "name":          "customer_id",
+        "dataType":      "int",
+        "comment":       "customer id",
+        "qualifiedName": "employee_db.employees_canada.customer_id@cl1"
+      }
     },
-    "-222736766326568": {
-      "typeName": "sample_column_type",
+    "-4": {
+      "guid":       "-4",
+      "typeName":   "sample_column",
       "attributes": {
-        "qualifiedName": "company_id@cl1",
-        "dataType": "double",
-        "name": "company_id",
-        "comment": "company id"
-      },
-      "guid": "-222736766326568",
-      "isIncomplete": false,
-      "provenanceType": 0,
-      "version": 0,
-      "relationshipAttributes": {
-        "table": {
-          "guid": "-222736766326569",
-          "typeName": "sample_table_type"
-        }
-      },
-      "classifications": [{
-        "typeName": "sample_finance_Tag",
-        "entityStatus": "ACTIVE"
-      }],
-      "proxy": false
-    }
-  },
-  "entity": {
-    "typeName": "sample_table_type",
-    "attributes": {
-      "serde2": {
-        "typeName": "serdeType",
-        "attributes": {
-          "serde": "serde2",
-          "name": "serde2"
-        }
-      },
-      "tableType": "Managed",
-      "serde1": {
-        "typeName": "serdeType",
-        "attributes": {
-          "serde": "serde1",
-          "name": "serde1"
-        }
-      },
-      "lastAccessTime": "2014-07-11T08:00:00.000Z",
-      "level": 2,
-      "qualifiedName": "employee_table_entity_CANADA@cl1",
-      "name": "employee_table_entity_CANADA",
-      "description": "emp table",
-      "compressed": false
-    },
-    "guid": "-222736766326569",
-    "isIncomplete": false,
-    "provenanceType": 0,
-    "version": 0,
-    "relationshipAttributes": {
-      "columns": [{
-        "guid": "-222736766326566",
-        "typeName": "sample_column_type"
-      }, {
-        "guid": "-222736766326567",
-        "typeName": "sample_column_type"
-      }, {
-        "guid": "-222736766326568",
-        "typeName": "sample_column_type"
-      }],
-      "db": {
-        "guid": "c1e152c4-e40a-4bc9-a8a1-3c09d8d85f17",
-        "typeName": "sample_db_type"
+        "table":         { "guid": "-1" },
+        "name":          "company_id",
+        "dataType":      "double",
+        "comment":       "company id",
+        "qualifiedName": "employee_db.employees_canada.company_id@cl1"
       }
-    },
-    "classifications": [{
-      "typeName": "Metric",
-      "entityStatus": "ACTIVE"
-    }],
-    "proxy": false
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_us.json b/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_us.json
index 9685e8d..56ca736 100644
--- a/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_us.json
+++ b/atlas-examples/sample-app/src/main/python/request_json/entity_create_table_us.json
@@ -1,124 +1,59 @@
 {
+  "entity": {
+    "guid":       "-1",
+    "typeName":   "sample_table",
+    "attributes": {
+      "name":          "employees_us",
+      "description":   "US employees",
+      "qualifiedName": "employee_db.employees_us@cl1",
+      "tableType":     "Managed",
+      "serde1":        { "typeName": "sample_serdeType", "attributes": { "name": "serde1", "serde": "serde1" } },
+      "serde2":        { "typeName": "sample_serdeType", "attributes": { "name": "serde2", "serde": "serde2" } }
+    },
+
+    "relationshipAttributes": {
+      "db":      { "typeName": "sample_db", "uniqueAttributes": { "qualifiedName": "employee_db@cl1" } },
+      "columns": [
+	    { "guid": "-2" },
+		{ "guid": "-3" },
+		{ "guid": "-4" }
+	  ]
+    }
+  },
+
   "referredEntities": {
-    "-222736766326570": {
-      "typeName": "sample_column_type",
+    "-2": {
+      "guid":       "-2",
+      "typeName":   "sample_column",
       "attributes": {
-        "qualifiedName": "time_id@cl1",
-        "dataType": "int",
-        "name": "time_id",
-        "comment": "time id"
-      },
-      "guid": "-222736766326570",
-      "isIncomplete": false,
-      "provenanceType": 0,
-      "version": 0,
-      "relationshipAttributes": {
-        "table": {
-          "guid": "-222736766326573",
-          "typeName": "sample_table_type"
-        }
-      },
-      "classifications": [],
-      "proxy": false
+        "name":          "time_id",
+        "dataType":      "int",
+        "comment":       "time id",
+        "qualifiedName": "employee_db.employees_us.time_id@cl1",
+        "table": { "guid": "-1" }
+      }
     },
-    "-222736766326571": {
-      "typeName": "sample_column_type",
+    "-3": {
+      "guid":       "-3",
+      "typeName":   "sample_column",
       "attributes": {
-        "qualifiedName": "customer_id@cl1",
-        "dataType": "int",
         "name": "customer_id",
-        "comment": "customer id"
-      },
-      "guid": "-222736766326571",
-      "isIncomplete": false,
-      "provenanceType": 0,
-      "version": 0,
-      "relationshipAttributes": {
-        "table": {
-          "guid": "-222736766326573",
-          "typeName": "sample_table_type"
-        }
-      },
-      "classifications": [{
-        "typeName": "sample_pii_Tag",
-        "entityStatus": "ACTIVE"
-      }],
-      "proxy": false
+        "dataType": "int",
+        "comment": "customer id",
+        "qualifiedName": "employee_db.employees_us.customer_id@cl1",
+        "table": { "guid": "-1" }
+      }
     },
-    "-222736766326572": {
-      "typeName": "sample_column_type",
+    "-4": {
+      "guid":       "-4",
+      "typeName":   "sample_column",
       "attributes": {
-        "qualifiedName": "company_id@cl1",
-        "dataType": "double",
-        "name": "company_id",
-        "comment": "company id"
-      },
-      "guid": "-222736766326572",
-      "isIncomplete": false,
-      "provenanceType": 0,
-      "version": 0,
-      "relationshipAttributes": {
-        "table": {
-          "guid": "-222736766326573",
-          "typeName": "sample_table_type"
-        }
-      },
-      "classifications": [{
-        "typeName": "sample_finance_Tag",
-        "entityStatus": "ACTIVE"
-      }],
-      "proxy": false
-    }
-  },
-  "entity": {
-    "typeName": "sample_table_type",
-    "attributes": {
-      "serde2": {
-        "typeName": "serdeType",
-        "attributes": {
-          "serde": "serde2",
-          "name": "serde2"
-        }
-      },
-      "tableType": "Managed",
-      "serde1": {
-        "typeName": "serdeType",
-        "attributes": {
-          "serde": "serde1",
-          "name": "serde1"
-        }
-      },
-      "lastAccessTime": "2014-07-11T08:00:00.000Z",
-      "level": 2,
-      "qualifiedName": "employee_table_entity_US@cl1",
-      "name": "employee_table_entity_US",
-      "description": "emp table",
-      "compressed": false
-    },
-    "guid": "-222736766326573",
-    "isIncomplete": false,
-    "provenanceType": 0,
-    "version": 0,
-    "relationshipAttributes": {
-      "columns": [{
-        "guid": "-222736766326570",
-        "typeName": "sample_column_type"
-      }, {
-        "guid": "-222736766326571",
-        "typeName": "sample_column_type"
-      }, {
-        "guid": "-222736766326572",
-        "typeName": "sample_column_type"
-      }],
-      "db": {
-        "guid": "c1e152c4-e40a-4bc9-a8a1-3c09d8d85f17",
-        "typeName": "sample_db_type"
+        "name":          "company_id",
+        "dataType":      "double",
+        "comment":       "company id",
+        "qualifiedName": "employee_db.employees_us.company_id@cl1",
+        "table": { "guid": "-1" }
       }
-    },
-    "classifications": [{
-      "typeName": "Metric",
-      "entityStatus": "ACTIVE"
-    }],
-    "proxy": false
+    }
   }
-}
\ No newline at end of file
+}
diff --git a/atlas-examples/sample-app/src/main/python/request_json/typedef_create.json b/atlas-examples/sample-app/src/main/python/request_json/typedef_create.json
index b42781a..5ebfc83 100644
--- a/atlas-examples/sample-app/src/main/python/request_json/typedef_create.json
+++ b/atlas-examples/sample-app/src/main/python/request_json/typedef_create.json
@@ -1,419 +1,177 @@
 {
   "enumDefs": [
     {
-      "category": "ENUM",
-      "name": "tableType",
-      "description": "tableType",
+      "name":        "sample_tableType",
+      "description": "sample_tableType",
+      "typeVersion": "1.0",
       "elementDefs": [
-        {
-          "value": "MANAGED",
-          "ordinal": 1
-        },
-        {
-          "value": "EXTERNAL",
-          "ordinal": 2
-        }
+        { "value": "MANAGED",  "ordinal": 1 },
+        { "value": "EXTERNAL", "ordinal": 2 }
       ]
     }
   ],
   "structDefs": [
     {
-      "category": "STRUCT",
-      "name": "serdeType",
+      "name":        "sample_serdeType",
       "typeVersion": "1.0",
       "attributeDefs": [
-        {
-          "name": "name",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": false,
-          "isUnique": false,
-          "isIndexable": true
-        },
-        {
-          "name": "serde",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": false,
-          "isUnique": false,
-          "isIndexable": true
-        }
+        { "name": "name",  "typeName": "string", "cardinality": "SINGLE", "isOptional": false, "isUnique": false, "isIndexable": true },
+        { "name": "serde", "typeName": "string", "cardinality": "SINGLE", "isOptional": false, "isUnique": false, "isIndexable": true }
       ]
     }
   ],
   "classificationDefs": [
     {
-      "category": "CLASSIFICATION",
-      "name": "classification",
-      "typeVersion": "1.0",
-      "attributeDefs": [
-        {
-          "name": "tag",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": false,
-          "isUnique": false,
-          "isIndexable": true
-        }
-      ]
-    },
-    {
-      "category": "CLASSIFICATION",
-      "name": "sample_pii_Tag",
+      "name": "sample_pii",
       "typeVersion": "1.0"
     },
     {
-      "category": "CLASSIFICATION",
-      "name": "sample_finance_Tag",
+      "name": "sample_finance",
       "typeVersion": "1.0"
     },
     {
-      "category": "CLASSIFICATION",
-      "name": "Metric",
+      "name": "sample_metric",
       "typeVersion": "1.0"
     }
   ],
   "entityDefs": [
     {
-      "category": "ENTITY",
-      "name": "sample_db_type",
+      "name":        "sample_db",
+      "superTypes":  [ "DataSet" ],
       "typeVersion": "1.0",
       "attributeDefs": [
-        {
-          "name": "locationUri",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "createTime",
-          "typeName": "long",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "randomTable",
-          "typeName": "array<sample_table_type>",
-          "cardinality": "SET",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        }
-      ],
-      "superTypes": [
-        "DataSet"
+        { "name": "locationUri", "typeName": "string", "cardinality": "SINGLE", "isOptional": false, "isUnique": false, "isIndexable": true },
+        { "name": "createTime",  "typeName": "date",   "cardinality": "SINGLE", "isOptional": false, "isUnique": false, "isIndexable": true }
       ]
     },
     {
-      "category": "ENTITY",
-      "name": "sample_table_type",
+      "name":        "sample_table",
       "typeVersion": "1.0",
+      "superTypes":  [ "DataSet" ],
       "attributeDefs": [
-        {
-          "name": "createTime",
-          "typeName": "long",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "lastAccessTime",
-          "typeName": "date",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "temporary",
-          "typeName": "boolean",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "db",
-          "typeName": "sample_db_type",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "columns",
-          "typeName": "array<sample_column_type>",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "tableType",
-          "typeName": "tableType",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "serde1",
-          "typeName": "serdeType",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "serde2",
-          "typeName": "serdeType",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        }
-      ],
-      "superTypes": [
-        "DataSet"
+        { "name": "createTime",     "typeName": "date",                 "cardinality": "SINGLE", "isOptional": true, "isUnique": false, "isIndexable": true },
+        { "name": "tableType",      "typeName": "sample_tableType",     "cardinality": "SINGLE", "isOptional": true, "isUnique": false, "isIndexable": true },
+        { "name": "temporary",      "typeName": "boolean",              "cardinality": "SINGLE", "isOptional": true, "isUnique": false, "isIndexable": false },
+        { "name": "serde1",         "typeName": "sample_serdeType",     "cardinality": "SINGLE", "isOptional": true, "isUnique": false, "isIndexable": false },
+        { "name": "serde2",         "typeName": "sample_serdeType",     "cardinality": "SINGLE", "isOptional": true, "isUnique": false, "isIndexable": false }
       ]
     },
     {
-      "category": "ENTITY",
-      "name": "sample_column_type",
+      "name":        "sample_column",
       "typeVersion": "1.0",
+      "superTypes":  [ "DataSet" ],
       "attributeDefs": [
-        {
-          "name": "dataType",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "comment",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        }
-      ],
-      "superTypes": [
-        "DataSet"
+        { "name": "dataType", "typeName": "string", "cardinality": "SINGLE", "isOptional": true, "isUnique": false, "isIndexable": true },
+        { "name": "comment",  "typeName": "string", "cardinality": "SINGLE", "isOptional": true, "isUnique": false, "isIndexable": true }
       ]
     },
     {
-      "category": "ENTITY",
-      "name": "sample_process_type",
+      "name":        "sample_process",
       "typeVersion": "1.0",
+      "superTypes":  [ "Process" ],
       "attributeDefs": [
-        {
-          "name": "userName",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "startTime",
-          "typeName": "long",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "endTime",
-          "typeName": "long",
-          "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false
-        },
-        {
-          "name": "queryText",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": false,
-          "isUnique": false,
-          "isIndexable": true
-        },
-        {
-          "name": "queryPlan",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": false,
-          "isUnique": false,
-          "isIndexable": true
-        },
-        {
-          "name": "queryId",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": false,
-          "isUnique": false,
-          "isIndexable": true
-        },
-        {
-          "name": "queryGraph",
-          "typeName": "string",
-          "cardinality": "SINGLE",
-          "isOptional": false,
-          "isUnique": false,
-          "isIndexable": true
-        }
-      ],
-      "superTypes": [
-        "Process"
+        { "name": "userName",   "typeName": "string", "cardinality": "SINGLE", "isOptional": true,  "isUnique": false, "isIndexable": true },
+        { "name": "startTime",  "typeName": "long",   "cardinality": "SINGLE", "isOptional": true,  "isUnique": false, "isIndexable": true },
+        { "name": "endTime",    "typeName": "long",   "cardinality": "SINGLE", "isOptional": true,  "isUnique": false, "isIndexable": true },
+        { "name": "queryText",  "typeName": "string", "cardinality": "SINGLE", "isOptional": false, "isUnique": false, "isIndexable": true },
+        { "name": "queryId",    "typeName": "string", "cardinality": "SINGLE", "isOptional": false, "isUnique": false, "isIndexable": true }
       ]
     }
   ],
   "relationshipDefs": [
     {
-      "category": "RELATIONSHIP",
-      "name": "sample_Table_DB",
-      "description": "sample_Table_DB",
-      "typeVersion": "1.0",
+      "name":                 "sample_db_tables",
+      "description":          "Tables of a db",
+      "typeVersion":          "1.0",
       "relationshipCategory": "AGGREGATION",
-      "propagateTags": "NONE",
-      "endDef1": {
-        "type": "sample_table_type",
-        "name": "db",
-        "cardinality": "SINGLE",
-        "isContainer": false,
-        "isLegacyAttribute": false
-      },
-      "endDef2": {
-        "type": "sample_db_type",
-        "name": "tables",
-        "cardinality": "SET",
-        "isContainer": true,
-        "isLegacyAttribute": false
-      }
+      "propagateTags":        "NONE",
+      "endDef1":              { "name": "db",     "type": "sample_table", "cardinality": "SINGLE", "isContainer": false, "isLegacyAttribute": false },
+      "endDef2":              { "name": "tables", "type": "sample_db",    "cardinality": "SET",    "isContainer": true,  "isLegacyAttribute": false }
     },
     {
-      "category": "RELATIONSHIP",
-      "name": "sample_Table_Columns",
-      "description": "sample_Table_Columns",
-      "typeVersion": "1.0",
+      "name":                 "sample_table_columns",
+      "description":          "Columns of a table",
+      "typeVersion":          "1.0",
       "relationshipCategory": "COMPOSITION",
-      "propagateTags": "NONE",
-      "endDef1": {
-        "type": "sample_table_type",
-        "name": "columns",
-        "cardinality": "SET",
-        "isContainer": true,
-        "isLegacyAttribute": false
-      },
-      "endDef2": {
-        "type": "sample_column_type",
-        "name": "table",
-        "cardinality": "SINGLE",
-        "isContainer": false,
-        "isLegacyAttribute": false
-      }
+      "propagateTags":        "NONE",
+      "endDef1":              { "name": "table",   "type": "sample_column", "cardinality": "SINGLE", "isContainer": false, "isLegacyAttribute": false },
+      "endDef2":              { "name": "columns", "type": "sample_table",  "cardinality": "SET",    "isContainer": true,  "isLegacyAttribute": false }
     }
   ],
   "businessMetadataDefs": [
     {
-      "category": "BUSINESS_METADATA",
-      "name": "bmWithAllTypes",
-      "description": "description",
+      "name":        "sample_bm",
+      "description": "Sample business metadata",
       "typeVersion": "1.0",
       "attributeDefs": [
         {
-          "name": "attr1",
-          "typeName": "boolean",
+		  "name":        "attr1",
+          "typeName":    "boolean",
+          "description": "Boolean attribute",
           "cardinality": "SINGLE",
-          "isOptional": true,
-          "isIndexable": false,
-          "includeInNotification": false,
-          "defaultValue": "",
-          "description": "description",
-          "searchWeight": 0,
+          "isOptional":  true,
           "options": {
-            "applicableEntityTypes": "[\"sample_db_type\",\"sample_table_type\"]",
-            "maxStrLength": "20"
+            "applicableEntityTypes": "[ \"sample_db\", \"sample_table\" ]",
+            "maxStrLength":          50
           }
         },
         {
-          "name": "attr2",
-          "typeName": "byte",
+          "name":        "attr2",
+          "typeName":    "byte",
+          "description": "Byte attribute",
           "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false,
-          "includeInNotification": false,
-          "defaultValue": "",
-          "description": "description",
-          "searchWeight": 0,
+          "isOptional":  true,
+          "isUnique":    false,
+          "isIndexable": true,
           "options": {
-            "applicableEntityTypes": "[\"sample_db_type\",\"sample_table_type\"]",
-            "maxStrLength": "20"
+            "applicableEntityTypes": "[ \"sample_db\", \"sample_table\" ]",
+            "maxStrLength":          50
           }
         },
         {
-          "name": "attr8",
-          "typeName": "string",
+          "name":        "attr3",
+          "typeName":    "string",
+          "description": "String attribute",
           "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false,
-          "includeInNotification": false,
-          "defaultValue": "",
-          "description": "description",
+          "isOptional":  true,
+          "isUnique":    false,
+          "isIndexable": true,
           "searchWeight": 0,
           "options": {
-            "applicableEntityTypes": "[\"sample_db_type\",\"sample_table_type\"]",
-            "maxStrLength": "20"
+            "applicableEntityTypes": "[ \"sample_db\", \"sample_table\" ]",
+            "maxStrLength":          50
           }
         }
       ]
     },
     {
-      "category": "BUSINESS_METADATA",
-      "name": "bmWithAllTypesMV",
-      "description": "description",
+      "name":        "sample_bm_mv",
+      "description": "Sample business metadata with multi-value attributes",
       "typeVersion": "1.0",
       "attributeDefs": [
         {
-          "name": "attr11",
-          "typeName": "array<boolean>",
+          "name":        "mv_attr1",
+          "typeName":    "array<boolean>",
+          "description": "Array of booleans",
           "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false,
-          "defaultValue": "",
-          "description": "description",
-          "searchWeight": 0,
+          "isOptional":  true,
           "options": {
-            "applicableEntityTypes": "[\"sample_db_type\",\"sample_table_type\"]",
-            "maxStrLength": "20"
+            "applicableEntityTypes": "[\"sample_db\",\"sample_table\"]",
+            "maxStrLength":          50
           }
         },
         {
-          "name": "attr18",
-          "typeName": "array<string>",
+          "name":        "mv_attr2",
+          "typeName":    "array<string>",
+          "description": "Array of strings",
           "cardinality": "SINGLE",
-          "isOptional": true,
-          "isUnique": false,
-          "isIndexable": false,
-          "defaultValue": "",
-          "description": "description",
-          "searchWeight": 0,
+          "isOptional":  true,
           "options": {
-            "applicableEntityTypes": "[\"sample_db_type\",\"sample_table_type\"]",
-            "maxStrLength": "20"
+            "applicableEntityTypes": "[ \"sample_db\", \"sample_table\" ]",
+            "maxStrLength":          50
           }
         }
       ]
     }
   ]
-}
\ No newline at end of file
+}
diff --git a/atlas-examples/sample-app/src/main/python/sample_client.py b/atlas-examples/sample-app/src/main/python/sample_client.py
index 54720d9..732b280 100644
--- a/atlas-examples/sample-app/src/main/python/sample_client.py
+++ b/atlas-examples/sample-app/src/main/python/sample_client.py
@@ -16,17 +16,18 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
 import logging
+import getpass
 
-from apache_atlas.base_client import AtlasClient
+from apache_atlas.client.base_client import AtlasClient
+from typedef_example                 import TypeDefExample
+from entity_example                  import EntityExample
+from lineage_example                 import LineageExample
+from glossary_example                import GlossaryExample
+from discovery_example               import DiscoveryExample
+from utils                           import METRIC_CLASSIFICATION, NAME
 
-from typedef_example import TypeDefExample
-from entity_example import EntityExample
-from lineage_example import LineageExample
-from glossary_example import GlossaryExample
-from discovery_example import DiscoveryExample
-from utils import METRIC_CLASSIFICATION, NAME
-import getpass
 
 LOG = logging.getLogger('sample-example')
 
@@ -36,70 +37,62 @@ class SampleApp:
         self.created_entity = None
 
     def main(self):
-        url      = input("Enter Atlas URL: ")
-        username = input("Enter username: ")
-        password = getpass.getpass('Enter password: ')
-        client   = AtlasClient(url, username, password)
+        # Python3
+        global input
+        try: input = raw_input
+        except NameError: pass
 
-        # Typedef examples
-        LOG.info("\n")
-        LOG.info("---------- Creating Sample Types -----------")
-        typedef = TypeDefExample(client)
-        typedef.create_type_def()
-        typedef.print_typedefs()
+        url      = input('Enter Atlas URL: ')
+        username = input('Enter username: ')
+        password = getpass.getpass('Enter password: ')
 
-        # Entity example
-        LOG.info("\n")
-        LOG.info("---------- Creating Sample Entities -----------")
-        entity = EntityExample(client)
-        entity.create_entities()
+        client = AtlasClient(url, (username, password))
 
-        self.created_entity = entity.get_table_entity()
+        self.__entity_example(client)
 
-        if self.created_entity and self.created_entity['guid']:
-            entity.get_entity_by_guid(self.created_entity['guid'])
+        self.__typedef_example(client)
 
-        # Lineage Examples
-        LOG.info("\n")
-        LOG.info("---------- Lineage example -----------")
         self.__lineage_example(client)
 
-        # Discovery Example
-        LOG.info("\n")
-        LOG.info("---------- Search example -----------")
         self.__discovery_example(client)
 
-        # Glossary Examples
-        LOG.info("\n")
-        LOG.info("---------- Glossary Example -----------")
         self.__glossary_example(client)
 
-        LOG.info("\n")
-        LOG.info("---------- Deleting Entities -----------")
-        entity.remove_entities()
+        self.__entity_cleanup()
 
-    def __glossary_example(self, client):
-        glossary     = GlossaryExample(client)
-        glossary_obj = glossary.create_glossary()
 
-        if not glossary_obj:
-            LOG.info("Create glossary first")
-            return
+    def __typedef_example(self, client):
+        LOG.info("\n---------- Creating Sample Types -----------")
 
-        glossary.create_glossary_term()
-        glossary.get_glossary_detail()
-        glossary.create_glossary_category()
-        glossary.delete_glossary()
+        typedefExample = TypeDefExample(client)
+
+        typedefExample.create_type_def()
+
+    def __entity_example(self, client):
+        LOG.info("\n---------- Creating Sample Entities -----------")
+
+        self.entityExample = EntityExample(client)
+
+        self.entityExample.create_entities()
+
+        self.created_entity = self.entityExample.get_table_entity()
+
+        if self.created_entity and self.created_entity.guid:
+            self.entityExample.get_entity_by_guid(self.created_entity.guid)
 
     def __lineage_example(self, client):
+        LOG.info("\n---------- Lineage example -----------")
+
         lineage = LineageExample(client)
 
         if self.created_entity:
-            lineage.lineage(self.created_entity['guid'])
+            lineage.lineage(self.created_entity.guid)
         else:
             LOG.info("Create entity first to get lineage info")
 
     def __discovery_example(self, client):
+        LOG.info("\n---------- Search example -----------")
+
         discovery = DiscoveryExample(client)
 
         discovery.dsl_search()
@@ -108,10 +101,30 @@ class SampleApp:
             LOG.info("Create entity first to get search info")
             return
 
-        discovery.quick_search(self.created_entity['typeName'])
+        discovery.quick_search(self.created_entity.typeName)
+
+        discovery.basic_search(self.created_entity.typeName, METRIC_CLASSIFICATION, self.created_entity.attributes[NAME])
+
+    def __glossary_example(self, client):
+        LOG.info("\n---------- Glossary Example -----------")
+
+        glossary     = GlossaryExample(client)
+        glossary_obj = glossary.create_glossary()
+
+        if not glossary_obj:
+            LOG.info("Create glossary first")
+            return
+
+        glossary.create_glossary_term()
+        glossary.get_glossary_detail()
+        glossary.create_glossary_category()
+        glossary.delete_glossary()
+
+    def __entity_cleanup(self):
+        LOG.info("\n---------- Deleting Entities -----------")
 
-        discovery.basic_search(self.created_entity['typeName'], METRIC_CLASSIFICATION, self.created_entity['attributes'][NAME])
+        self.entityExample.remove_entities()
 
 
 if __name__ == "__main__":
-    SampleApp().main()
\ No newline at end of file
+    SampleApp().main()
diff --git a/atlas-examples/sample-app/src/main/python/typedef_example.py b/atlas-examples/sample-app/src/main/python/typedef_example.py
index 8431d70..aa1f94e 100644
--- a/atlas-examples/sample-app/src/main/python/typedef_example.py
+++ b/atlas-examples/sample-app/src/main/python/typedef_example.py
@@ -17,26 +17,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 import logging
 import utils
+
+from apache_atlas.utils           import type_coerce
 from apache_atlas.model.discovery import SearchFilter
-from apache_atlas.model.typedef import AtlasTypesDef
+from apache_atlas.model.typedef   import AtlasTypesDef
 
-import json
 
 LOG = logging.getLogger('sample-example')
 
 
 class TypeDefExample:
-    SAMPLE_APP_TYPES = {
-        utils.PROCESS_TYPE,
-        utils.COLUMN_TYPE,
-        utils.TABLE_TYPE,
+    SAMPLE_APP_TYPES = [
         utils.DATABASE_TYPE,
+        utils.TABLE_TYPE,
+        utils.COLUMN_TYPE,
+        utils.PROCESS_TYPE,
         utils.PII_TAG,
-        utils.CLASSIFICATION,
         utils.FINANCE_TAG,
-        utils.METRIC_CLASSIFICATION}
+        utils.METRIC_CLASSIFICATION
+    ]
 
     def __init__(self, client):
         self.typesDef = None
@@ -46,10 +48,10 @@ class TypeDefExample:
         try:
             if not self.typesDef:
                 with open('request_json/typedef_create.json') as f:
-                    typedef       = json.load(f)
+                    typedef       = type_coerce(json.load(f), AtlasTypesDef)
                     self.typesDef = self.__create(typedef)
         except Exception as e:
-            LOG.exception("Error in creating typeDef.")
+            LOG.exception("Error in creating typeDef", exc_info=e)
 
     def print_typedefs(self):
         for type_name in TypeDefExample.SAMPLE_APP_TYPES:
@@ -63,52 +65,58 @@ class TypeDefExample:
     def remove_typedefs(self):
         if not self.typesDef:
             LOG.info("There is no typeDef to delete.")
-            return
-
-        for type_name in TypeDefExample.SAMPLE_APP_TYPES:
-            self.client.typedef.delete_type_by_name(type_name)
+        else:
+            for type_name in TypeDefExample.SAMPLE_APP_TYPES:
+                self.client.typedef.delete_type_by_name(type_name)
 
-        self.typesDef = None
+            self.typesDef = None
 
         LOG.info("Deleted typeDef successfully!")
 
     def __create(self, type_def):
-        types_to_create = AtlasTypesDef().__dict__
-
-        for enum_def in type_def['enumDefs']:
-            if self.client.typedef.type_with_name_exists(enum_def['name']):
-                LOG.info("Type with name %s already exists. Skipping.", enum_def['name'])
+        types_to_create = AtlasTypesDef()
+
+        types_to_create.enumDefs             = []
+        types_to_create.structDefs           = []
+        types_to_create.classificationDefs   = []
+        types_to_create.entityDefs           = []
+        types_to_create.relationshipDefs     = []
+        types_to_create.businessMetadataDefs = []
+
+        for enum_def in type_def.enumDefs:
+            if self.client.typedef.type_with_name_exists(enum_def.name):
+                LOG.info("Type with name %s already exists. Skipping.", enum_def.name)
             else:
-                types_to_create['enumDefs'].append(enum_def)
+                types_to_create.enumDefs.append(enum_def)
 
-        for struct_def in type_def['structDefs']:
-            if self.client.typedef.type_with_name_exists(struct_def['name']):
-                LOG.info("Type with name %s already exists. Skipping.", struct_def['name'])
+        for struct_def in type_def.structDefs:
+            if self.client.typedef.type_with_name_exists(struct_def.name):
+                LOG.info("Type with name %s already exists. Skipping.", struct_def.name)
             else:
-                types_to_create['structDefs'].append(struct_def)
+                types_to_create.structDefs.append(struct_def)
 
-        for classification_def in type_def['classificationDefs']:
-            if self.client.typedef.type_with_name_exists(classification_def['name']):
-                LOG.info("Type with name %s already exists. Skipping.", classification_def['name'])
+        for classification_def in type_def.classificationDefs:
+            if self.client.typedef.type_with_name_exists(classification_def.name):
+                LOG.info("Type with name %s already exists. Skipping.", classification_def.name)
             else:
-                types_to_create['classificationDefs'].append(classification_def)
+                types_to_create.classificationDefs.append(classification_def)
 
-        for entity_def in type_def['entityDefs']:
-            if self.client.typedef.type_with_name_exists(entity_def['name']):
-                LOG.info("Type with name %s already exists. Skipping.", entity_def['name'])
+        for entity_def in type_def.entityDefs:
+            if self.client.typedef.type_with_name_exists(entity_def.name):
+                LOG.info("Type with name %s already exists. Skipping.", entity_def.name)
             else:
-                types_to_create['entityDefs'].append(entity_def)
+                types_to_create.entityDefs.append(entity_def)
 
-        for relationship_def in type_def['relationshipDefs']:
-            if self.client.typedef.type_with_name_exists(relationship_def['name']):
-                LOG.info("Type with name %s already exists. Skipping.", relationship_def['name'])
+        for relationship_def in type_def.relationshipDefs:
+            if self.client.typedef.type_with_name_exists(relationship_def.name):
+                LOG.info("Type with name %s already exists. Skipping.", relationship_def.name)
             else:
-                types_to_create['relationshipDefs'].append(relationship_def)
+                types_to_create.relationshipDefs.append(relationship_def)
 
-        for business_metadata_def in type_def['businessMetadataDefs']:
-            if self.client.typedef.type_with_name_exists(business_metadata_def['name']):
-                LOG.info("Type with name %s already exists. Skipping.", business_metadata_def['name'])
+        for business_metadata_def in type_def.businessMetadataDefs:
+            if self.client.typedef.type_with_name_exists(business_metadata_def.name):
+                LOG.info("Type with name %s already exists. Skipping.", business_metadata_def.name)
             else:
-                types_to_create['businessMetadataDefs'].append(business_metadata_def)
+                types_to_create.businessMetadataDefs.append(business_metadata_def)
 
-        return self.client.typedef.create_atlas_typedefs(types_to_create)
\ No newline at end of file
+        return self.client.typedef.create_atlas_typedefs(types_to_create)
diff --git a/atlas-examples/sample-app/src/main/python/utils.py b/atlas-examples/sample-app/src/main/python/utils.py
index c19382f..c83472d 100644
--- a/atlas-examples/sample-app/src/main/python/utils.py
+++ b/atlas-examples/sample-app/src/main/python/utils.py
@@ -20,19 +20,18 @@
 NAME        = "name"
 DESCRIPTION = "description"
 
-PII_TAG               = "sample_pii_Tag"
-FINANCE_TAG           = "sample_finance_Tag"
-CLASSIFICATION        = "classification"
-METRIC_CLASSIFICATION = "Metric"
+PII_TAG               = "sample_pii"
+FINANCE_TAG           = "sample_finance"
+METRIC_CLASSIFICATION = "sample_metric"
 
-DATABASE_TYPE = "sample_db_type"
-PROCESS_TYPE  = "sample_process_type"
-TABLE_TYPE    = "sample_table_type"
-COLUMN_TYPE   = "sample_column_type"
+DATABASE_TYPE = "sample_db"
+PROCESS_TYPE  = "sample_process"
+TABLE_TYPE    = "sample_table"
+COLUMN_TYPE   = "sample_column"
 
-TABLE_DATABASE_TYPE       = "sample_Table_DB"
-TABLE_COLUMNS_TYPE        = "sample_Table_Columns"
-ENUM_TABLE_TYPE           = "tableType"
-BUSINESS_METADATA_TYPE    = "bmWithAllTypes"
-BUSINESS_METADATA_TYPE_MV = "bmWithAllTypesMV"
-STRUCT_TYPE_SERDE         = "serdeType"
\ No newline at end of file
+TABLE_DATABASE_TYPE       = "sample_db_tables"
+TABLE_COLUMNS_TYPE        = "sample_table_columns"
+ENUM_TABLE_TYPE           = "sample_tableType"
+BUSINESS_METADATA_TYPE    = "sample_bm"
+BUSINESS_METADATA_TYPE_MV = "sample_bm_mv"
+STRUCT_TYPE_SERDE         = "sample_serdeType"
diff --git a/intg/src/main/python/README.md b/intg/src/main/python/README.md
index 086d777..9d80a68 100644
--- a/intg/src/main/python/README.md
+++ b/intg/src/main/python/README.md
@@ -1,15 +1,12 @@
-# Atlas Python Client
+# Apache Atlas Python Client
 
-This is a python library for Atlas. Users can integrate with Atlas using the python client.
-Currently, compatible with Python 3.5+
+Python library for Apache Atlas.
 
 ## Installation
 
-Use the package manager [pip](https://pip.pypa.io/en/stable/) to install python client for Atlas.
+Use the package manager [pip](https://pip.pypa.io/en/stable/) to install Python client for Apache Atlas.
 
 ```bash
-# After publishing apache-atlas use
-
 > pip install apache-atlas
 ```
 
@@ -19,22 +16,146 @@ Verify if apache-atlas client is installed:
 
 Package      Version
 ------------ ---------
-apache-atlas 0.0.1
+apache-atlas 0.0.2
 ```
 
 ## Usage
 
-```python create_glossary.py```
+```python atlas_example.py```
 ```python
-# create_glossary.py
+# atlas_example.py
+
+import time
+
+from apache_atlas.client.base_client import AtlasClient
+from apache_atlas.model.instance     import *
+
+
+## Step 1: create a client to connect to Apache Atlas server
+client = AtlasClient('http://localhost:21000', ('admin', 'atlasR0cks!'))
+
+# For Kerberos authentication, use HTTPKerberosAuth as shown below
+#
+# from requests_kerberos import HTTPKerberosAuth
+#
+# client = AtlasClient('http://localhost:21000', HTTPKerberosAuth())
+
+# to disable SSL certificate validation (not recommended for production use!)
+#
+# client.session.verify = False
+
+
+## Step 2: Let's create a database entity
+test_db            = AtlasEntity({ 'typeName': 'hive_db' })
+test_db.attributes = { 'name': 'test_db', 'clusterName': 'prod', 'qualifiedName': 'test_db@prod' }
+
+entity_info        = AtlasEntityWithExtInfo()
+entity_info.entity = test_db
+
+print('Creating test_db')
+
+resp = client.entity.create_entity(entity_info)
+
+guid_db = resp.get_assigned_guid(test_db.guid)
+
+print('    created test_db: guid=' + guid_db)
+
+
+## Step 3: Let's create a table entity, and two column entities - in one call
+test_tbl                        = AtlasEntity({ 'typeName': 'hive_table' })
+test_tbl.attributes             = { 'name': 'test_tbl', 'qualifiedName': 'test_db.test_tbl@prod' }
+test_tbl.relationshipAttributes = { 'db': AtlasRelatedObjectId({ 'guid': guid_db }) }
+
+test_col1                        = AtlasEntity({ 'typeName': 'hive_column' })
+test_col1.attributes             = { 'name': 'test_col1', 'type': 'string', 'qualifiedName': 'test_db.test_tbl.test_col1@prod' }
+test_col1.relationshipAttributes = { 'table': AtlasRelatedObjectId({ 'guid': test_tbl.guid }) }
+
+test_col2                        = AtlasEntity({ 'typeName': 'hive_column' })
+test_col2.attributes             = { 'name': 'test_col2', 'type': 'string', 'qualifiedName': 'test_db.test_tbl.test_col2@prod' }
+test_col2.relationshipAttributes = { 'table': AtlasRelatedObjectId({ 'guid': test_tbl.guid }) }
+
+entities_info          = AtlasEntitiesWithExtInfo()
+entities_info.entities = [ test_tbl, test_col1, test_col2 ]
+
+print('Creating test_tbl')
+
+resp = client.entity.create_entities(entities_info)
+
+guid_tbl  = resp.get_assigned_guid(test_tbl.guid)
+guid_col1 = resp.get_assigned_guid(test_col1.guid)
+guid_col2 = resp.get_assigned_guid(test_col2.guid)
+
+print('    created test_tbl:           guid=' + guid_tbl)
+print('    created test_tbl.test_col1: guid=' + guid_col1)
+print('    created test_tbl.test_col2: guid=' + guid_col2)
+
+
+## Step 4: Let's create a view entity that feeds from the table created earlier
+#          Also create a lineage between the table and the view, and lineages between their columns as well
+test_view                        = AtlasEntity({ 'typeName': 'hive_table' })
+test_view.attributes             = { 'name': 'test_view', 'qualifiedName': 'test_db.test_view@prod' }
+test_view.relationshipAttributes = { 'db': AtlasRelatedObjectId({ 'guid': guid_db }) }
+
+test_view_col1                        = AtlasEntity({ 'typeName': 'hive_column' })
+test_view_col1.attributes             = { 'name': 'test_col1', 'type': 'string', 'qualifiedName': 'test_db.test_view.test_col1@prod' }
+test_view_col1.relationshipAttributes = { 'table': AtlasRelatedObjectId({ 'guid': test_view.guid }) }
+
+test_view_col2                        = AtlasEntity({ 'typeName': 'hive_column' })
+test_view_col2.attributes             = { 'name': 'test_col2', 'type': 'string', 'qualifiedName': 'test_db.test_view.test_col2@prod' }
+test_view_col2.relationshipAttributes = { 'table': AtlasRelatedObjectId({ 'guid': test_view.guid }) }
+
+test_process                         = AtlasEntity({ 'typeName': 'hive_process' })
+test_process.attributes              = { 'name': 'create_test_view', 'userName': 'admin', 'operationType': 'CREATE', 'qualifiedName': 'create_test_view@prod' }
+test_process.attributes['queryText'] = 'create view test_view as select * from test_tbl'
+test_process.attributes['queryPlan'] = '<queryPlan>'
+test_process.attributes['queryId']   = '<queryId>'
+test_process.attributes['startTime'] = int(time.time() * 1000)
+test_process.attributes['endTime']   = int(time.time() * 1000)
+test_process.relationshipAttributes  = { 'inputs': [ AtlasRelatedObjectId({ 'guid': guid_tbl }) ], 'outputs': [ AtlasRelatedObjectId({ 'guid': test_view.guid }) ] }
+
+test_col1_lineage                        = AtlasEntity({ 'typeName': 'hive_column_lineage' })
+test_col1_lineage.attributes             = { 'name': 'test_view.test_col1 lineage', 'depenendencyType': 'read', 'qualifiedName': 'test_db.test_view.test_col1@prod' }
+test_col1_lineage.attributes['query']    = { 'guid': test_process.guid }
+test_col1_lineage.relationshipAttributes = { 'inputs': [ AtlasRelatedObjectId({ 'guid': guid_col1 }) ], 'outputs': [ AtlasRelatedObjectId({ 'guid': test_view_col1.guid }) ] }
+
+test_col2_lineage                        = AtlasEntity({ 'typeName': 'hive_column_lineage' })
+test_col2_lineage.attributes             = { 'name': 'test_view.test_col2 lineage', 'depenendencyType': 'read', 'qualifiedName': 'test_db.test_view.test_col2@prod' }
+test_col2_lineage.attributes['query']    = { 'guid': test_process.guid }
+test_col2_lineage.relationshipAttributes = { 'inputs': [ AtlasRelatedObjectId({ 'guid': guid_col2 }) ], 'outputs': [ AtlasRelatedObjectId({ 'guid': test_view_col2.guid }) ] }
+
+entities_info          = AtlasEntitiesWithExtInfo()
+entities_info.entities = [ test_process, test_col1_lineage, test_col2_lineage ]
+
+entities_info.add_referenced_entity(test_view)
+entities_info.add_referenced_entity(test_view_col1)
+entities_info.add_referenced_entity(test_view_col2)
+
+print('Creating test_view')
+
+resp = client.entity.create_entities(entities_info)
+
+guid_view         = resp.get_assigned_guid(test_view.guid)
+guid_view_col1    = resp.get_assigned_guid(test_view_col1.guid)
+guid_view_col2    = resp.get_assigned_guid(test_view_col2.guid)
+guid_process      = resp.get_assigned_guid(test_process.guid)
+guid_col1_lineage = resp.get_assigned_guid(test_col1_lineage.guid)
+guid_col2_lineage = resp.get_assigned_guid(test_col2_lineage.guid)
+
+print('    created test_view:           guid=' + guid_view)
+print('    created test_view.test_col1: guid=' + guid_view_col1)
+print('    created test_view.test_col2: guid=' + guid_view_col1)
+print('    created test_view lineage:   guid=' + guid_process)
+print('    created test_col1 lineage:   guid=' + guid_col1_lineage)
+print('    created test_col2 lineage:   guid=' + guid_col2_lineage)
+
+
+## Step 5: Finally, cleanup by deleting entities created above
+print('Deleting entities')
 
-from apache_atlas.base_client import AtlasClient
-from apache_atlas.model.glossary import AtlasGlossary
+resp = client.entity.delete_entities_by_guids([ guid_col1_lineage, guid_col2_lineage, guid_process, guid_view, guid_tbl, guid_db ])
 
-client        = AtlasClient("http://localhost:31000", "admin", "admin123")
-glossary      = AtlasGlossary(None, None, "Glossary_Test", "This is a test Glossary")
-test_glossary = client.glossary.create_glossary(glossary)
+deleted_count = len(resp.mutatedEntities[EntityOperation.DELETE.name]) if resp and resp.mutatedEntities and EntityOperation.DELETE.name in resp.mutatedEntities else 0
 
-print('Created Test Glossary with guid: ' + test_glossary.guid)
+print('    ' + str(deleted_count) + ' entities deleted')
 ```
-For more examples, checkout `sample-app` python  project in atlas-examples module.
\ No newline at end of file
+For more examples, checkout `sample-app` python project in [atlas-examples](https://github.com/apache/atlas/blob/master/atlas-examples/sample-app/src/main/python/sample_client.py) module.
diff --git a/intg/src/main/python/apache_atlas/base_client.py b/intg/src/main/python/apache_atlas/client/base_client.py
similarity index 82%
rename from intg/src/main/python/apache_atlas/base_client.py
rename to intg/src/main/python/apache_atlas/client/base_client.py
index ba85018..3e6002d 100644
--- a/intg/src/main/python/apache_atlas/base_client.py
+++ b/intg/src/main/python/apache_atlas/client/base_client.py
@@ -19,31 +19,27 @@
 
 import copy
 import os
-from http import HTTPStatus
-
-from requests import Session
 import json
 import logging
-import logging.config
-
-from apache_atlas.utils import CustomEncoder, HttpMethod
-from apache_atlas.client.typedef import TypeDefClient
-from apache_atlas.client.discovery import DiscoveryClient
-from apache_atlas.client.entity import EntityClient
-from apache_atlas.client.glossary import GlossaryClient
-from apache_atlas.client.lineage import LineageClient
+
+from requests                         import Session
+from apache_atlas.client.discovery    import DiscoveryClient
+from apache_atlas.client.entity       import EntityClient
+from apache_atlas.client.glossary     import GlossaryClient
+from apache_atlas.client.lineage      import LineageClient
 from apache_atlas.client.relationship import RelationshipClient
+from apache_atlas.client.typedef      import TypeDefClient
+from apache_atlas.exceptions          import AtlasServiceException
+from apache_atlas.utils               import HttpMethod, HTTPStatus, type_coerce
 
-from apache_atlas.exceptions import AtlasServiceException
 
 LOG = logging.getLogger('apache_atlas')
 
 
 class AtlasClient:
-
-    def __init__(self, host, username, password):
+    def __init__(self, host, auth):
         session      = Session()
-        session.auth = (username, password)
+        session.auth = auth
 
         self.host           = host
         self.session        = session
@@ -55,6 +51,9 @@ class AtlasClient:
         self.glossary       = GlossaryClient(self)
         self.relationship   = RelationshipClient(self)
 
+        logging.getLogger("requests").setLevel(logging.WARNING)
+
+
     def call_api(self, api, response_type=None, query_params=None, request_obj=None):
         params = copy.deepcopy(self.request_params)
         path   = os.path.join(self.host, api.path)
@@ -62,13 +61,11 @@ class AtlasClient:
         params['headers']['Accept']       = api.consumes
         params['headers']['Content-type'] = api.produces
 
-        print(path)
-
         if query_params:
             params['params'] = query_params
 
         if request_obj:
-            params['data'] = json.dumps(request_obj, indent=4, cls=CustomEncoder)
+            params['data'] = json.dumps(request_obj)
 
         if LOG.isEnabledFor(logging.DEBUG):
             LOG.debug("------------------------------------------------------")
@@ -92,7 +89,6 @@ class AtlasClient:
 
         if response is None:
             return None
-
         elif response.status_code == api.expected_status:
             if not response_type:
                 return None
@@ -106,7 +102,7 @@ class AtlasClient:
                     if response_type == str:
                         return json.dumps(response.json())
 
-                    return response_type(**response.json())
+                    return type_coerce(response.json(), response_type)
                 else:
                     return None
             except Exception as e:
@@ -115,11 +111,9 @@ class AtlasClient:
                 LOG.exception("Exception occurred while parsing response with msg: %s", e)
 
                 raise AtlasServiceException(api, response)
-
         elif response.status_code == HTTPStatus.SERVICE_UNAVAILABLE:
             LOG.error("Atlas Service unavailable. HTTP Status: %s", HTTPStatus.SERVICE_UNAVAILABLE)
 
             return None
-
         else:
-            raise AtlasServiceException(api, response)
\ No newline at end of file
+            raise AtlasServiceException(api, response)
diff --git a/intg/src/main/python/apache_atlas/client/discovery.py b/intg/src/main/python/apache_atlas/client/discovery.py
index b1cdcc6..5bead22 100644
--- a/intg/src/main/python/apache_atlas/client/discovery.py
+++ b/intg/src/main/python/apache_atlas/client/discovery.py
@@ -17,10 +17,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from http import HTTPStatus
-
-from apache_atlas.model.discovery import AtlasSearchResult, AtlasUserSavedSearch, AtlasSuggestionsResult, AtlasQuickSearchResult
-from apache_atlas.utils import API, HttpMethod, BASE_URI
+from apache_atlas.model.discovery import *
+from apache_atlas.utils           import API, HttpMethod, HTTPStatus
 
 
 class DiscoveryClient:
@@ -145,14 +143,14 @@ class DiscoveryClient:
         return self.client.call_api(DiscoveryClient.UPDATE_SAVED_SEARCH, AtlasUserSavedSearch, None, saved_search)
 
     def delete_saved_search(self, guid):
-        return self.client.call_api(DiscoveryClient.DELETE_SAVED_SEARCH.format_map({'guid': guid}))
+        return self.client.call_api(DiscoveryClient.DELETE_SAVED_SEARCH.format_path({'guid': guid}))
 
     def execute_saved_search(self, user_name, search_name):
         query_params = {"user", user_name}
 
-        return self.client.call_api(DiscoveryClient.EXECUTE_SAVED_SEARCH_BY_NAME.format_map({'search_name': search_name}),
+        return self.client.call_api(DiscoveryClient.EXECUTE_SAVED_SEARCH_BY_NAME.format_path({'search_name': search_name}),
                                     AtlasSearchResult, query_params)
 
     def execute_saved_search(self, search_guid):
-        return self.client.call_api(DiscoveryClient.EXECUTE_SAVED_SEARCH_BY_GUID.format_map({'search_guid': search_guid}),
+        return self.client.call_api(DiscoveryClient.EXECUTE_SAVED_SEARCH_BY_GUID.format_path({'search_guid': search_guid}),
                                     AtlasSearchResult)
\ No newline at end of file
diff --git a/intg/src/main/python/apache_atlas/client/entity.py b/intg/src/main/python/apache_atlas/client/entity.py
index d43408e..ebfe27f 100644
--- a/intg/src/main/python/apache_atlas/client/entity.py
+++ b/intg/src/main/python/apache_atlas/client/entity.py
@@ -17,13 +17,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from http import HTTPStatus
-
-from apache_atlas.model.entity import AtlasEntityWithExtInfo, AtlasEntitiesWithExtInfo, AtlasEntityHeader, \
-    AtlasClassifications, AtlasEntityHeaders, EntityMutationResponse
-
-from apache_atlas.utils import API, HttpMethod, BASE_URI, APPLICATION_OCTET_STREAM, APPLICATION_JSON, \
-    MULTIPART_FORM_DATA, attributes_to_params, list_attributes_to_params
+from apache_atlas.model.instance import *
+from apache_atlas.utils          import *
 
 
 class EntityClient:
diff --git a/intg/src/main/python/apache_atlas/client/glossary.py b/intg/src/main/python/apache_atlas/client/glossary.py
index 41b977e..ed7acdf 100644
--- a/intg/src/main/python/apache_atlas/client/glossary.py
+++ b/intg/src/main/python/apache_atlas/client/glossary.py
@@ -17,10 +17,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from http import HTTPStatus
-
-from apache_atlas.model.glossary import AtlasGlossaryCategory, AtlasGlossaryTerm, AtlasGlossary, AtlasGlossaryExtInfo
-from apache_atlas.utils import BASE_URI, API, HttpMethod, APPLICATION_JSON, APPLICATION_OCTET_STREAM, MULTIPART_FORM_DATA
+from apache_atlas.model.glossary import *
+from apache_atlas.utils          import *
 
 
 class GlossaryClient:
@@ -142,7 +140,7 @@ class GlossaryClient:
     def get_related_categories(self, category_guid, sort_by_attribute, limit, offset):
         query_params = {GlossaryClient.LIMIT: limit, GlossaryClient.OFFSET: offset, "sort": sort_by_attribute}
 
-        return self.client.call_api(GlossaryClient.GET_RELATED_CATEGORIES.format_map({'category_guid': category_guid}),
+        return self.client.call_api(GlossaryClient.GET_RELATED_CATEGORIES.format_path({'category_guid': category_guid}),
                                     dict, query_params)
 
     def create_glossary(self, glossary):
diff --git a/intg/src/main/python/apache_atlas/client/lineage.py b/intg/src/main/python/apache_atlas/client/lineage.py
index e8966c2..980efcd 100644
--- a/intg/src/main/python/apache_atlas/client/lineage.py
+++ b/intg/src/main/python/apache_atlas/client/lineage.py
@@ -17,10 +17,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from http import HTTPStatus
-
-from apache_atlas.model.lineage import AtlasLineageInfo
-from apache_atlas.utils import BASE_URI, API, HttpMethod, attributes_to_params
+from apache_atlas.model.lineage import *
+from apache_atlas.utils         import *
 
 
 class LineageClient:
diff --git a/intg/src/main/python/apache_atlas/client/relationship.py b/intg/src/main/python/apache_atlas/client/relationship.py
index 9ccf644..72b701a 100644
--- a/intg/src/main/python/apache_atlas/client/relationship.py
+++ b/intg/src/main/python/apache_atlas/client/relationship.py
@@ -17,10 +17,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from http import HTTPStatus
-
-from apache_atlas.model.relationship import AtlasRelationshipWithExtInfo, AtlasRelationship
-from apache_atlas.utils import BASE_URI, API, HttpMethod
+from apache_atlas.model.relationship import *
+from apache_atlas.utils              import *
 
 
 class RelationshipClient:
diff --git a/intg/src/main/python/apache_atlas/client/typedef.py b/intg/src/main/python/apache_atlas/client/typedef.py
index 70f795f..2ee8f5a 100644
--- a/intg/src/main/python/apache_atlas/client/typedef.py
+++ b/intg/src/main/python/apache_atlas/client/typedef.py
@@ -17,11 +17,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from http import HTTPStatus
-
-from apache_atlas.utils import API, HttpMethod, BASE_URI
-from apache_atlas.model.typedef import AtlasEnumDef, AtlasClassificationDef, AtlasEntityDef, AtlasStructDef, \
-    AtlasRelationshipDef, AtlasBusinessMetadataDef, AtlasTypesDef, AtlasBaseTypeDef
+from apache_atlas.model.typedef import *
+from apache_atlas.utils         import *
 
 
 class TypeDefClient:
diff --git a/intg/src/main/python/apache_atlas/exceptions.py b/intg/src/main/python/apache_atlas/exceptions.py
index d306568..839befa 100644
--- a/intg/src/main/python/apache_atlas/exceptions.py
+++ b/intg/src/main/python/apache_atlas/exceptions.py
@@ -17,6 +17,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
 class AtlasServiceException(Exception):
     """Exception raised for errors in API calls.
 
@@ -29,14 +30,12 @@ class AtlasServiceException(Exception):
         msg = ""
 
         if api:
-            msg = "Metadata service API {method} : {path} failed".format_map({'method': api.method, 'path': api.path})
+            msg = "Metadata service API {method} : {path} failed".format(**{'method': api.method, 'path': api.path})
 
         if response.content:
             status = response.status_code if response.status_code else -1
             msg    = "Metadata service API with url {url} and method {method} : failed with status {status} and " \
                      "Response Body is :{response}". \
-                      format_map({'url': response.url, 'method': api.method, 'status': status, 'response': response.json()})
-
-        self.message = msg
+                      format(**{'url': response.url, 'method': api.method, 'status': status, 'response': response.json()})
 
-        super().__init__(self.message)
\ No newline at end of file
+        Exception.__init__(self, msg)
diff --git a/intg/src/main/python/apache_atlas/model/discovery.py b/intg/src/main/python/apache_atlas/model/discovery.py
index 18eca38..61a992c 100644
--- a/intg/src/main/python/apache_atlas/model/discovery.py
+++ b/intg/src/main/python/apache_atlas/model/discovery.py
@@ -18,158 +18,183 @@
 # limitations under the License.
 
 import enum
-import sys
-
-from apache_atlas.utils import AtlasBaseModelObject
-
-
-class SearchFilter:
-    sortType_enum = enum.Enum('sortType_enum', 'NONE ASC DESC', module=__name__)
-
-    def __init__(self, params=None, startIndex=0, maxRows=sys.maxsize, getCount=True, sortBy=None, sortType=None):
-        self.params     = params if params is not None else {}
-        self.startIndex = startIndex
-        self.maxRows    = maxRows
-        self.getCount   = getCount
-        self.sortBy     = sortBy
-        self.sortType   = sortType
-
-
-class AtlasSearchResult:
-    queryType_enum = enum.Enum('queryType_enum', 'DSL FULL_TEXT GREMLIN BASIC ATTRIBUTE RELATIONSHIP', module=__name__)
-
-    def __init__(self, queryType=None, searchParameters=None, queryText=None, type=None, classification=None,
-                 entities=None, attributes=None, fullTextResult=None, referredEntities=None, approximateCount=None):
-        self.queryType        = queryType if queryType is not None else AtlasSearchResult.queryType_enum.BASIC.name
-        self.searchParameters = searchParameters
-        self.queryText        = queryText
-        self.type             = type
-        self.classification   = classification
-        self.entities         = entities
-        self.attributes       = attributes
-        self.fullTextResult   = fullTextResult if fullTextResult is not None else []
-        self.referredEntities = referredEntities if fullTextResult is not None else {}
-        self.approximateCount = approximateCount
-
-
-class SearchParameters:
-    sortOrder_enum = enum.Enum('sortOrder_enum', 'ASCENDING DESCENDING', module=__name__)
-
-    def __init__(self, query=None, typeName=None, classification=None, termName=None, sortBy=None, excludeDeletedEntities=None,
-                 includeClassificationAttributes=None, includeSubTypes=None, includeSubClassifications=None, limit=None,
-                 offset=None, entityFilters=None, tagFilters=None, attributes=None, sortOrder=None):
-        self.query                           = query
-        self.typeName                        = typeName
-        self.classification                  = classification
-        self.termName                        = termName
-        self.sortBy                          = sortBy
-        self.excludeDeletedEntities          = excludeDeletedEntities
-        self.includeClassificationAttributes = includeClassificationAttributes
-        self.includeSubTypes                 = includeSubTypes
-        self.includeSubClassifications       = includeSubClassifications
-        self.limit                           = limit
-        self.offset                          = offset
-        self.entityFilters                   = entityFilters
-        self.tagFilters                      = tagFilters
-        self.attributes                      = attributes if attributes is not None else set()
-        self.sortOrder                       = sortOrder
-
-
-class FilterCriteria:
-    operator_enum = enum.Enum('operator_enum',
-                              '< > <= >= = != in like startsWith endsWith contains not_contains containsAny containsAll isNull notNull',
-                              module=__name__)
-    condition_enum = enum.Enum('condition_enum', 'AND OR', module=__name__)
-
-    def __init__(self, attributeName=None, operator=None, attributeValue=None, condition=None, criterion=None):
-        self.attributeName  = attributeName
-        self.operator       = operator
-        self.attributeValue = attributeValue
-        self.condition      = condition
-        self.criterion      = criterion if criterion is not None else []
 
+from apache_atlas.model.enums    import *
+from apache_atlas.model.instance import *
+from apache_atlas.utils          import *
 
-class Operator(enum.Enum):
-    LT = ("<", "lt")
-    GT = ('>', 'gt')
-    LTE = ('<=', 'lte')
-    GTE = ('>=', 'gte')
-    EQ = ('=', 'eq')
-    NEQ = ('!=', 'neq')
-    IN = ('in', 'IN')
-    LIKE = ('like', 'LIKE')
-    STARTS_WITH = ('startsWith', 'STARTSWITH', 'begins_with', 'BEGINS_WITH')
-    ENDS_WITH = ('endsWith', 'ENDSWITH', 'ends_with', 'ENDS_WITH')
-    CONTAINS = ('contains', 'CONTAINS')
-    NOT_CONTAINS = ('not_contains', 'NOT_CONTAINS')
-    CONTAINS_ANY = ('containsAny', 'CONTAINSANY', 'contains_any', 'CONTAINS_ANY')
-    CONTAINS_ALL = ('containsAll', 'CONTAINSALL', 'contains_all', 'CONTAINS_ALL')
-    IS_NULL = ('isNull', 'ISNULL', 'is_null', 'IS_NULL')
-    NOT_NULL = ('notNull', 'NOTNULL', 'not_null', 'NOT_NULL')
 
+class AtlasAggregationEntry(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-class SortOrder(enum.Enum):
-    sort_order = enum.Enum('sort_order', 'ASCENDING DESCENDING', module=__name__)
+        self.name = attrs.get('name')
+        self.name = attrs.get('count')
+
+
+class AtlasQuickSearchResult(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.searchResults      = attrs.get('searchResults')
+        self.aggregationMetrics = attrs.get('aggregationMetrics')
+
+    def type_coerce_attrs(self):
+        super(AtlasQuickSearchResult, self).type_coerce_attrs()
+
+        self.searchResults      = type_coerce(self.searchResults, AtlasSearchResult)
+        self.aggregationMetrics = type_coerce_dict_list(self.aggregationMetrics, AtlasAggregationEntry)
+
+
+class AtlasSearchResult(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.queryType        = non_null(attrs.get('queryType'), QueryType.BASIC.name)
+        self.searchParameters = attrs.get('searchParameters')
+        self.queryText        = attrs.get('queryText')
+        self.type             = attrs.get('type')
+        self.classification   = attrs.get('classification')
+        self.entities         = attrs.get('entities')
+        self.attributes       = attrs.get('attributes')
+        self.fullTextResult   = attrs.get('fullTextResult')
+        self.referredEntities = attrs.get('referredEntities')
+        self.approximateCount = non_null(attrs.get('approximateCount'), -1)
+
+    def type_coerce_attrs(self):
+        super(AtlasSearchResult, self).type_coerce_attrs()
+
+        self.entities         = type_coerce_list(self.entities, AtlasEntityHeader)
+        self.attributes       = type_coerce(self.attributes, AttributeSearchResult)
+        self.referredEntities = type_coerce_dict(self.referredEntities, AtlasEntityHeader)
+
+
+class AttributeSearchResult(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
+        self.name   = attrs.get('name')
+        self.values = attrs.get('values')
 
-class AttributeSearchResult:
 
-    def __init__(self, name=None, values=None):
-        self.name   = name
-        self.values = values if values is not None else []
+class AtlasFullTextResult(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
+        self.entity = attrs.get('entity')
+        self.score  = attrs.get('score')
 
-class AtlasFullTextResult:
+    def type_coerce_attrs(self):
+        super(AtlasFullTextResult, self).type_coerce_attrs()
 
-    def __init__(self, entity=None, score=None):
-        self.entity = entity
-        self.score  = score
+        self.entity = type_coerce(self.criterion, AtlasEntityHeader)
 
 
-class AtlasQuickSearchResult:
+class AtlasSuggestionsResult(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-    def __init__(self, searchResults=None, aggregationMetrics=None):
-        self.searchResults      = searchResults
-        self.aggregationMetrics = aggregationMetrics if aggregationMetrics is not None else {}
+        self.suggestions  = attrs.get('suggestions')
+        self.prefixString = attrs.get('prefixString')
+        self.fieldName    = attrs.get('fieldName')
 
 
-class AtlasAggregationEntry:
+class QuickSearchParameters(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-    def __init__(self, name=None, count=None):
-        self.name  = name
-        self.count = count
+        self.query                  = attrs.get('query')
+        self.typeName               = attrs.get('typeName')
+        self.entityFilters          = attrs.get('entityFilters')
+        self.includeSubTypes        = attrs.get('includeSubTypes')
+        self.excludeDeletedEntities = attrs.get('excludeDeletedEntities')
+        self.offset                 = attrs.get('offset')
+        self.limit                  = attrs.get('limit')
+        self.attributes             = attrs.get('attributes')
 
+    def type_coerce_attrs(self):
+        super(QuickSearchParameters, self).type_coerce_attrs()
 
-class QuickSearchParameters:
+        self.entityFilters = type_coerce(self.entityFilters, FilterCriteria)
 
-    def __init__(self, query=None, typeName=None, entityFilters=None, includeSubTypes=None,
-                 excludeDeletedEntities=None, offset=None, limit=None, attributes=None):
-        self.query                  = query
-        self.typeName               = typeName
-        self.entityFilters          = entityFilters
-        self.includeSubTypes        = includeSubTypes
-        self.excludeDeletedEntities = excludeDeletedEntities
-        self.offset                 = offset
-        self.limit                  = limit
-        self.attributes             = attributes if attributes is not None else set()
 
+class SearchParameters(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-class AtlasSuggestionsResult:
+        self.query                           = attrs.get('query')
+        self.typeName                        = attrs.get('typeName')
+        self.classification                  = attrs.get('classification')
+        self.termName                        = attrs.get('termName')
+        self.sortBy                          = attrs.get('sortBy')
+        self.excludeDeletedEntities          = attrs.get('excludeDeletedEntities')
+        self.includeClassificationAttributes = attrs.get('includeClassificationAttributes')
+        self.includeSubTypes                 = non_null(attrs.get('includeSubTypes'), True)
+        self.includeSubClassifications       = non_null(attrs.get('includeSubClassifications'), True)
+        self.limit                           = attrs.get('limit')
+        self.offset                          = attrs.get('offset')
+        self.entityFilters                   = attrs.get('entityFilters')
+        self.tagFilters                      = attrs.get('tagFilters')
+        self.attributes                      = attrs.get('attributes')
+        self.sortOrder                       = attrs.get('sortOrder')
 
-    def __init__(self, suggestions=None, prefixString=None, fieldName=None):
-        self.suggestions  = suggestions if suggestions is not None else []
-        self.prefixString = prefixString
-        self.fieldName    = fieldName
+    def type_coerce_attrs(self):
+        super(SearchParameters, self).type_coerce_attrs()
+
+        self.entityFilters = type_coerce(self.entityFilters, FilterCriteria)
+        self.tagFilters    = type_coerce(self.tagFilters, FilterCriteria)
+
+
+class FilterCriteria(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.attributeName  = attrs.get('attributeName')
+        self.operator       = attrs.get('operator')
+        self.attributeValue = attrs.get('attributeValue')
+        self.condition      = attrs.get('condition')
+        self.criterion      = attrs.get('criterion')
+
+    def type_coerce_attrs(self):
+        super(FilterCriteria, self).type_coerce_attrs()
+
+        self.criterion = type_coerce(self.criterion, FilterCriteria)
 
 
 class AtlasUserSavedSearch(AtlasBaseModelObject):
-    saved_search_type_enum = enum.Enum('saved_search_type_enum', 'BASIC ADVANCED', module=__name__)
+    def __init__(self, attrs={}):
+        AtlasBaseModelObject.__init__(self, attrs)
+
+        self.ownerName        = attrs.get('ownerName')
+        self.name             = attrs.get('name')
+        self.searchType       = attrs.get('searchType')
+        self.searchParameters = attrs.get('searchParameters')
+        self.uiParameters     = attrs.get('uiParameters')
+
+    def type_coerce_attrs(self):
+        super(AtlasUserSavedSearch, self).type_coerce_attrs()
+
+        self.searchParameters = type_coerce(self.searchParameters, SearchParameters)
+
+
+class Operator(enum.Enum):
+    LT = ("<", "lt")
+    GT = ('>', 'gt')
+    LTE = ('<=', 'lte')
+    GTE = ('>=', 'gte')
+    EQ = ('=', 'eq')
+    NEQ = ('!=', 'neq')
+    IN = ('in', 'IN')
+    LIKE = ('like', 'LIKE')
+    STARTS_WITH = ('startsWith', 'STARTSWITH', 'begins_with', 'BEGINS_WITH')
+    ENDS_WITH = ('endsWith', 'ENDSWITH', 'ends_with', 'ENDS_WITH')
+    CONTAINS = ('contains', 'CONTAINS')
+    NOT_CONTAINS = ('not_contains', 'NOT_CONTAINS')
+    CONTAINS_ANY = ('containsAny', 'CONTAINSANY', 'contains_any', 'CONTAINS_ANY')
+    CONTAINS_ALL = ('containsAll', 'CONTAINSALL', 'contains_all', 'CONTAINS_ALL')
+    IS_NULL = ('isNull', 'ISNULL', 'is_null', 'IS_NULL')
+    NOT_NULL = ('notNull', 'NOTNULL', 'not_null', 'NOT_NULL')
 
-    def __init__(self, guid=None, ownerName=None, name=None, searchType=None, searchParameters=None, uiParameters=None):
-        super().__init__(guid)
 
-        self.ownerName        = ownerName
-        self.name             = name
-        self.searchType       = searchType
-        self.searchParameters = searchParameters
-        self.uiParameters     = uiParameters
\ No newline at end of file
+class SortOrder(enum.Enum):
+    sort_order = enum.Enum('sort_order', 'ASCENDING DESCENDING', module=__name__)
diff --git a/intg/src/main/python/apache_atlas/model/entity.py b/intg/src/main/python/apache_atlas/model/entity.py
deleted file mode 100644
index ea66e71..0000000
--- a/intg/src/main/python/apache_atlas/model/entity.py
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/env/python
-
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import enum
-
-from apache_atlas.utils import s_nextId
-
-
-class AtlasStruct:
-
-    def __init__(self, typeName=None, attributes=None):
-        self.typeName   = typeName
-        self.attributes = attributes if attributes is not None else {}
-
-
-class AtlasEntity(AtlasStruct):
-    status_enum = enum.Enum('status_enum', 'ACTIVE DELETED PURGED', module=__name__)
-
-    def __init__(self, typeName=None, attributes=None, guid=None, homeId=None, isIncomplete=None, provenanceType=None,
-                 status=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, version=None,
-                 relationshipAttributes=None, classifications=None, meanings=None, customAttributes=None,
-                 businessAttributes=None, labels=None, proxy=None):
-
-        super().__init__(typeName, attributes)
-
-        self.guid                   = guid if guid is not None else "-" + str(s_nextId)
-        self.homeId                 = homeId
-        self.isIncomplete           = isIncomplete
-        self.provenanceType         = provenanceType
-        self.status                 = status
-        self.createdBy              = createdBy
-        self.updatedBy              = updatedBy
-        self.createTime             = createTime
-        self.updateTime             = updateTime
-        self.version                = version
-        self.relationshipAttributes = relationshipAttributes if relationshipAttributes is not None else {}
-        self.classifications        = classifications if classifications is not None else []
-        self.meanings               = meanings if meanings is not None else []
-        self.customAttributes       = customAttributes if customAttributes is not None else {}
-        self.businessAttributes     = businessAttributes if businessAttributes is not None else {}
-        self.labels                 = labels if labels is not None else set()
-        self.proxy                  = proxy
-
-
-class AtlasEntityExtInfo:
-
-    def __init__(self, referredEntities=None):
-
-        self.referredEntities = referredEntities if referredEntities is not None else {}
-
-
-class AtlasEntityWithExtInfo(AtlasEntityExtInfo):
-
-    def __init__(self, referredEntities=None, entity=None):
-        super().__init__(referredEntities)
-
-        self.entity = entity
-
-
-class AtlasEntitiesWithExtInfo(AtlasEntityExtInfo):
-
-    def __init__(self, referredEntities=None, entities=None):
-        super().__init__(referredEntities)
-
-        self.entities = entities if entities is not None else {}
-
-
-class AtlasEntityHeader(AtlasStruct):
-    status_enum = enum.Enum('status_enum', 'ACTIVE DELETED PURGED', module=__name__)
-
-    def __init__(self, typeName=None, attributes=None, guid=None, status=None, displayText=None, classificationNames=None,
-                 classifications=None, meaningNames=None, meanings=None, isIncomplete=None, labels=None):
-        super().__init__(typeName, attributes)
-
-        self.guid                = guid if guid is not None else "-" + str(s_nextId)
-        self.status              = status
-        self.displayText         = displayText
-        self.classificationNames = classificationNames if classificationNames is not None else []
-        self.classifications     = classifications
-        self.meaningNames        = meaningNames
-        self.meanings            = meanings if meanings is not None else []
-        self.isIncomplete        = isIncomplete
-        self.labels              = labels if labels is not None else set()
-
-
-class AtlasClassification(AtlasStruct):
-    entityStatus_enum = enum.Enum('entityStatus_enum', 'ACTIVE DELETED PURGED', module=__name__)
-
-    def __init__(self, typeName=None, attributes=None, entityGuid=None, entityStatus=None, propagate=None,
-                 validityPeriods=None, removePropagationsOnEntityDelete=None):
-        self.typeName                         = typeName
-        self.attributes                       = attributes
-        self.entityGuid                       = entityGuid
-        self.entityStatus                     = entityStatus
-        self.propagate                        = propagate
-        self.validityPeriods                  = validityPeriods if validityPeriods is not None else []
-        self.removePropagationsOnEntityDelete = removePropagationsOnEntityDelete
-
-
-class TimeBoundary:
-
-    def __init__(self, startTime=None, endTime=None, timeZone=None):
-        self.startTime = startTime
-        self.endTime   = endTime
-        self.timeZone  = timeZone
-
-
-class Plist:
-    sortType_enum = enum.Enum('sortType_enum', 'NONE ASC DESC', module=__name__)
-
-    def __init__(self, list=None, startIndex=None, pageSize=None, totalCount=None, sortBy=None, sortType=None):
-        self.list       = list
-        self.startIndex = startIndex
-        self.pageSize   = pageSize
-        self.totalCount = totalCount
-        self.sortBy     = sortBy
-        self.sortType   = sortType
-
-
-class AtlasClassifications(Plist):
-    sortType_enum = enum.Enum('sortType_enum', 'NONE ASC DESC', module=__name__)
-
-    def __init__(self, list=None, startIndex=None, pageSize=None, totalCount=None, sortBy=None, sortType=None):
-        super().__init__(list, startIndex, pageSize, totalCount, sortBy, sortType)
-
-
-class AtlasEntityHeaders:
-
-    def __init__(self, guidHeaderMap=None):
-        self.guidHeaderMap = guidHeaderMap if guidHeaderMap is not None else {}
-
-
-class EntityMutationResponse:
-
-    def __init__(self, mutatedEntities=None, guidAssignments=None):
-        self.mutatedEntities = mutatedEntities if mutatedEntities is not None else {}
-        self.guidAssignments = guidAssignments if guidAssignments is not None else {}
-
-
-class EntityMutations:
-    entity_operation_enum = enum.Enum('entity_operation_enum', 'CREATE UPDATE PARTIAL_UPDATE DELETE PURGE', module=__name__)
-
-    def __init__(self, entity_mutations):
-        self.entity_mutations = entity_mutations if entity_mutations is not None else []
-
-
-class EntityMutation:
-
-    def __init__(self, op, entity):
-        self.op     = op
-        self.entity = entity
\ No newline at end of file
diff --git a/intg/src/main/python/apache_atlas/model/enums.py b/intg/src/main/python/apache_atlas/model/enums.py
new file mode 100644
index 0000000..a5064f5
--- /dev/null
+++ b/intg/src/main/python/apache_atlas/model/enums.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env/python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicabwle law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import enum
+
+
+class AtlasTermAssignmentStatus(enum.Enum):
+    DISCOVERED = 0
+    PROPOSED   = 1
+    IMPORTED   = 2
+    VALIDATED  = 3
+    DEPRECATED = 4
+    OBSOLETE   = 5
+    OTHER      = 6
+
+
+class AtlasTermRelationshipStatus(enum.Enum):
+    DRAFT      = 0
+    ACTIVE     = 1
+    DEPRECATED = 2
+    OBSOLETE   = 3
+    OTHER      = 99
+
+
+class TypeCategory(enum.Enum):
+    PRIMITIVE         = 0
+    OBJECT_ID_TYPE    = 1
+    ENUM              = 2
+    STRUCT            = 3
+    CLASSIFICATION    = 4
+    ENTITY            = 5
+    ARRAY             = 6
+    MAP               = 7
+    RELATIONSHIP      = 8
+    BUSINESS_METADATA = 9
+
+
+class Cardinality(enum.Enum):
+    SINGLE = 0
+    LIST   = 1
+    SET    = 2
+
+
+class Condition(enum.Enum):
+    AND = 0
+    OR  = 1
+
+
+class EntityOperation(enum.Enum):
+    CREATE         = 0
+    UPDATE         = 1
+    PARTIAL_UPDATE = 2
+    DELETE         = 3
+    PURGE          = 4
+
+
+class EntityStatus(enum.Enum):
+    ACTIVE  = 0
+    DELETED = 1
+    PURGED  = 2
+
+
+class IndexType(enum.Enum):
+    DEFAULT = 0
+    STRING  = 1
+
+
+class LineageDirection(enum.Enum):
+    INPUT  = 0
+    OUTPUT = 1
+    BOTH   = 2
+
+
+class Operator(enum.Enum):
+    LT           = ("<", "lt")
+    GT           = ('>', 'gt')
+    LTE          = ('<=', 'lte')
+    GTE          = ('>=', 'gte')
+    EQ           = ('=', 'eq')
+    NEQ          = ('!=', 'neq')
+    IN           = ('in', 'IN')
+    LIKE         = ('like', 'LIKE')
+    STARTS_WITH  = ('startsWith', 'STARTSWITH', 'begins_with', 'BEGINS_WITH')
+    ENDS_WITH    = ('endsWith', 'ENDSWITH', 'ends_with', 'ENDS_WITH')
+    CONTAINS     = ('contains', 'CONTAINS')
+    NOT_CONTAINS = ('not_contains', 'NOT_CONTAINS')
+    CONTAINS_ANY = ('containsAny', 'CONTAINSANY', 'contains_any', 'CONTAINS_ANY')
+    CONTAINS_ALL = ('containsAll', 'CONTAINSALL', 'contains_all', 'CONTAINS_ALL')
+    IS_NULL      = ('isNull', 'ISNULL', 'is_null', 'IS_NULL')
+    NOT_NULL     = ('notNull', 'NOTNULL', 'not_null', 'NOT_NULL')
+
+
+class PropagateTags(enum.Enum):
+    NONE       = 0
+    ONE_TO_TWO = 1
+    TWO_TO_ONE = 2
+    BOTH       = 3
+
+
+class QueryType(enum.Enum):
+    DSL          = 0
+    FULL_TEXT    = 1
+    GREMLIN      = 2
+    BASIC        = 3
+    ATTRIBUTE    = 4
+    RELATIONSHIP = 5
+
+
+class RelationshipCategory(enum.Enum):
+    ASSOCIATION = 0
+    AGGREGATION = 1
+    COMPOSITION = 2
+
+
+class RelationshipStatus(enum.Enum):
+    ACTIVE  = 0
+    DELETED = 1
+
+
+class SavedSearchType(enum.Enum):
+    BASIC    = 0
+    ADVANCED = 1
+
+
+class SortOrder(enum.Enum):
+    ASCENDING  = 0
+    DESCENDING = 1
+
+
+class SortType(enum.Enum):
+    NONE = 0
+    ASC  = 1
+    DESC = 2
diff --git a/intg/src/main/python/apache_atlas/model/glossary.py b/intg/src/main/python/apache_atlas/model/glossary.py
index a9958d5..c81e333 100644
--- a/intg/src/main/python/apache_atlas/model/glossary.py
+++ b/intg/src/main/python/apache_atlas/model/glossary.py
@@ -17,191 +17,201 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import enum
+import apache_atlas.model.instance
 
-from apache_atlas.utils import AtlasBaseModelObject
+from apache_atlas.model.misc import *
+from apache_atlas.utils      import *
 
 
 class AtlasGlossaryBaseObject(AtlasBaseModelObject):
+    def __init__(self, attrs={}):
+        AtlasBaseModelObject.__init__(self, attrs)
 
-    def __init__(self, guid=None, qualifiedName=None, name=None, shortDescription=None,
-                 longDescription=None, additionalAttributes=None, classifications=None):
+        self.qualifiedName        = attrs.get('qualifiedName')
+        self.name                 = attrs.get('name')
+        self.shortDescription     = attrs.get('shortDescription')
+        self.longDescription      = attrs.get('longDescription')
+        self.additionalAttributes = attrs.get('additionalAttributes')
+        self.classifications      = attrs.get('classifications')
 
-        super().__init__(guid)
+    def type_coerce_attrs(self):
+        super(AtlasGlossaryBaseObject, self).type_coerce_attrs()
 
-        self.qualifiedName        = qualifiedName
-        self.name                 = name
-        self.shortDescription     = shortDescription
-        self.longDescription      = longDescription
-        self.additionalAttributes = additionalAttributes if additionalAttributes is not None else {}
-        self.classifications      = classifications if classifications is not None else []
+        self.classifications = type_coerce_list(self.classifications, apache_atlas.model.instance.AtlasClassification)
 
 
 class AtlasGlossary(AtlasGlossaryBaseObject):
+    def __init__(self, attrs={}):
+        AtlasGlossaryBaseObject.__init__(self, attrs)
 
-    def __init__(self, guid=None, qualifiedName=None, name=None, shortDescription=None, longDescription=None,
-                 additionalAttributes=None, classifications=None, language=None, usage=None, terms=None, categories=None):
+        self.language   = attrs.get('language')
+        self.usage      = attrs.get('usage')
+        self.terms      = attrs.get('terms')
+        self.categories = attrs.get('categories')
 
-        super().__init__(guid, qualifiedName, name, shortDescription, longDescription, additionalAttributes, classifications)
+    def type_coerce_attrs(self):
+        super(AtlasGlossary, self).type_coerce_attrs()
 
-        self.language   = language
-        self.usage      = usage
-        self.terms      = terms if terms is not None else set()
-        self.categories = categories if categories is not None else set()
+        self.terms      = type_coerce_list(self.classifications, AtlasRelatedTermHeader)
+        self.categories = type_coerce_list(self.categories, AtlasRelatedCategoryHeader)
 
 
-class AtlasRelatedTermHeader:
-    status_enum = enum.Enum('status_enum', 'DRAFT ACTIVE DEPRECATED OBSOLETE OTHER', module=__name__)
-
-    def __init__(self, termGuid=None, relationGuid=None, displayText=None, description=None,
-                 expression=None, steward=None, source=None, status=None):
-        self.termGuid     = termGuid
-        self.relationGuid = relationGuid
-        self.displayText  = displayText
-        self.description  = description
-        self.expression   = expression
-        self.steward      = steward
-        self.source       = source
-        self.status       = status
+class AtlasGlossaryExtInfo(AtlasGlossary):
+    def __init__(self, attrs={}):
+        AtlasGlossary.__init__(self, attrs)
 
+        self.termInfo     = attrs.get('termInfo')
+        self.categoryInfo = attrs.get('categoryInfo')
 
-class AtlasRelatedCategoryHeader:
+    def type_coerce_attrs(self):
+        super(AtlasGlossaryExtInfo, self).type_coerce_attrs()
 
-    def __init__(self, categoryGuid=None, parentCategoryGuid=None, relationGuid=None, displayText=None, description=None):
-        self.categoryGuid       = categoryGuid
-        self.parentCategoryGuid = parentCategoryGuid
-        self.relationGuid       = relationGuid
-        self.displayText        = displayText
-        self.description        = description
+        self.termInfo     = type_coerce_dict(self.termInfo, AtlasGlossaryTerm)
+        self.categoryInfo = type_coerce_dict(self.categoryInfo, AtlasGlossaryCategory)
 
 
-class AtlasGlossaryExtInfo(AtlasGlossary):
+class AtlasGlossaryCategory(AtlasGlossaryBaseObject):
+    def __init__(self, attrs):
+        AtlasGlossaryBaseObject.__init__(self, attrs)
 
-    def __init__(self, guid=None, qualifiedName=None, name=None, shortDescription=None, longDescription=None, additionalAttributes=None,
-                 classifications=None, language=None, usage=None, terms=None, categories=None, termInfo=None, categoryInfo=None):
+        # Inherited attributes from relations
+        self.anchor = attrs.get('anchor')
 
-        super().__init__(guid, qualifiedName, name, shortDescription, longDescription,
-                         additionalAttributes, classifications, language, usage, terms, categories)
+        # Category hierarchy links
+        self.parentCategory     = attrs.get('parentCategory')
+        self.childrenCategories = attrs.get('childrenCategories')
 
-        self.termInfo     = termInfo if termInfo is not None else {}
-        self.categoryInfo = categoryInfo if categoryInfo is not None else {}
+        # Terms associated with this category
+        self.terms = attrs.get('terms')
 
+    def type_coerce_attrs(self):
+        super(AtlasGlossaryCategory, self).type_coerce_attrs()
 
-class AtlasTermRelationshipStatus(enum.Enum):
-    DRAFT      = 0
-    ACTIVE     = 1
-    DEPRECATED = 2
-    OBSOLETE   = 3
-    OTHER      = 99
+        self.anchor             = type_coerce(self.anchor, AtlasGlossaryHeader)
+        self.parentCategory     = type_coerce(self.parentCategory, AtlasRelatedCategoryHeader)
+        self.childrenCategories = type_coerce_list(self.childrenCategories, AtlasRelatedCategoryHeader)
+        self.terms              = type_coerce_list(self.terms, AtlasRelatedTermHeader)
 
 
 class AtlasGlossaryTerm(AtlasGlossaryBaseObject):
-
-    def __init__(self, guid=None, qualifiedName=None, name=None, shortDescription=None, longDescription=None,
-                 additionalAttributes=None, classifications=None, examples=None, abbreviation=None, usage=None, anchor=None,
-                 assignedEntities=None, categories=None, seeAlso=None, synonyms=None, antonyms=None, preferredTerms=None,
-                 preferredToTerms=None, replacementTerms=None, replacedBy=None, translationTerms=None, translatedTerms=None,
-                 isA=None, classifies=None, validValues=None, validValuesFor=None):
-
-        super().__init__(guid, qualifiedName, name, shortDescription, longDescription, additionalAttributes, classifications)
+    def __init__(self, attrs={}):
+        AtlasGlossaryBaseObject.__init__(self, attrs)
 
         # Core attributes
-        self.examples     = examples if examples is not None else []
-        self.abbreviation = abbreviation
-        self.usage        = usage
+        self.examples     = attrs.get('examples')
+        self.abbreviation = attrs.get('abbreviation')
+        self.usage        = attrs.get('usage')
 
         # Attributes derived from relationships
-        self.anchor           = anchor
-        self.assignedEntities = assignedEntities if assignedEntities is not None else set()
-        self.categories       = categories if categories is not None else set()
+        self.anchor           = attrs.get('anchor')
+        self.assignedEntities = attrs.get('assignedEntities')
+        self.categories       = attrs.get('categories')
 
         # Related Terms
-        self.seeAlso = seeAlso if seeAlso is not None else set()
+        self.seeAlso = attrs.get('seeAlso')
 
         # Term Synonyms
-        self.synonyms = synonyms if synonyms is not None else set()
+        self.synonyms = attrs.get('synonyms')
 
         # Term antonyms
-        self.antonyms = antonyms if antonyms is not None else set()
+        self.antonyms = attrs.get('antonyms')
 
         # Term preference
-        self.preferredTerms   = preferredTerms if preferredTerms is not None else set()
-        self.preferredToTerms = preferredToTerms if preferredToTerms is not None else set()
+        self.preferredTerms   = attrs.get('preferredTerms')
+        self.preferredToTerms = attrs.get('preferredToTerms')
 
         # Term replacements
-        self.replacementTerms = replacementTerms if replacementTerms is not None else set()
-        self.replacedBy       = replacedBy if replacedBy is not None else set()
+        self.replacementTerms = attrs.get('replacementTerms')
+        self.replacedBy       = attrs.get('replacedBy')
 
         # Term translations
-        self.translationTerms = translationTerms if translationTerms is not None else set()
-        self.translatedTerms  = translatedTerms if translatedTerms is not None else set()
+        self.translationTerms = attrs.get('translationTerms')
+        self.translatedTerms  = attrs.get('translatedTerms')
 
         # Term classification
-        self.isA        = isA if isA is not None else set()
-        self.classifies = classifies if classifies is not None else set()
+        self.isA        = attrs.get('isA')
+        self.classifies = attrs.get('classifies')
 
         # Values for terms
-        self.validValues    = validValues if validValues is not None else set()
-        self.validValuesFor = validValuesFor if validValuesFor is not None else set()
-
-
-class AtlasGlossaryHeader:
-
-    def __init__(self, glossaryGuid=None, relationGuid=None, displayText=None):
-        self.glossaryGuid = glossaryGuid if glossaryGuid is not None else ""
-        self.relationGuid = relationGuid
-        self.displayText  = displayText
-
-
-class AtlasObjectId:
-
-    def __init__(self, guid=None, typeName=None, uniqueAttributes=None):
-        self.guid             = guid if guid is not None else ""
-        self.typeName         = typeName
-        self.uniqueAttributes = uniqueAttributes if uniqueAttributes is not None else {}
-
+        self.validValues    = attrs.get('validValues')
+        self.validValuesFor = attrs.get('validValuesFor')
+
+    def type_coerce_attrs(self):
+        super(AtlasGlossaryTerm, self).type_coerce_attrs()
+
+        self.anchor           = type_coerce(self.anchor, AtlasGlossaryHeader)
+        self.assignedEntities = type_coerce_list(self.assignedEntities, apache_atlas.model.instance.AtlasRelatedObjectId)
+        self.categories       = type_coerce_list(self.categories, AtlasTermCategorizationHeader)
+        self.seeAlso          = type_coerce_list(self.seeAlso, AtlasRelatedTermHeader)
+        self.synonyms         = type_coerce_list(self.synonyms, AtlasRelatedTermHeader)
+        self.antonyms         = type_coerce_list(self.antonyms, AtlasRelatedTermHeader)
+        self.preferredTerms   = type_coerce_list(self.preferredTerms, AtlasRelatedTermHeader)
+        self.preferredToTerms = type_coerce_list(self.preferredToTerms, AtlasRelatedTermHeader)
+        self.replacementTerms = type_coerce_list(self.replacementTerms, AtlasRelatedTermHeader)
+        self.replacedBy       = type_coerce_list(self.replacedBy, AtlasRelatedTermHeader)
+        self.translationTerms = type_coerce_list(self.translationTerms, AtlasRelatedTermHeader)
+        self.isA              = type_coerce_list(self.isA, AtlasRelatedTermHeader)
+        self.classifies       = type_coerce_list(self.classifies, AtlasRelatedTermHeader)
+        self.validValues      = type_coerce_list(self.validValues, AtlasRelatedTermHeader)
+        self.validValuesFor   = type_coerce_list(self.validValuesFor, AtlasRelatedTermHeader)
+
+
+class AtlasGlossaryHeader(AtlasBase):
+    def __init__(self, attrs):
+        AtlasBase.__init__(self, attrs)
+
+        self.glossaryGuid = attrs.get('glossaryGuid')
+        self.relationGuid = attrs.get('relationGuid')
+        self.displayText  = attrs.get('displayText')
+
+
+class AtlasRelatedCategoryHeader(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.categoryGuid       = attrs.get('categoryGuid')
+        self.parentCategoryGuid = attrs.get('parentCategoryGuid')
+        self.relationGuid       = attrs.get('relationGuid')
+        self.displayText        = attrs.get('displayText')
+        self.description        = attrs.get('description')
+
+
+class AtlasRelatedTermHeader(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.termGuid     = attrs.get('termGuid')
+        self.relationGuid = attrs.get('relationGuid')
+        self.displayText  = attrs.get('displayText')
+        self.description  = attrs.get('description')
+        self.expression   = attrs.get('expression')
+        self.steward      = attrs.get('steward')
+        self.source       = attrs.get('source')
+        self.status       = attrs.get('status')
+
+class AtlasTermAssignmentHeader(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.termGuid     = attrs.get('termGuid')
+        self.relationGuid = attrs.get('relationGuid')
+        self.description  = attrs.get('description')
+        self.displayText  = attrs.get('displayText')
+        self.expression   = attrs.get('expression')
+        self.createdBy    = attrs.get('createdBy')
+        self.steward      = attrs.get('steward')
+        self.source       = attrs.get('source')
+        self.confidence   = attrs.get('confidence')
+
+
+class AtlasTermCategorizationHeader(AtlasBase):
+    def __init__(self, attrs):
+        AtlasBase.__init__(self, attrs)
+
+        self.categoryGuid = attrs.get('categoryGuid')
+        self.relationGuid = attrs.get('relationGuid')
+        self.description  = attrs.get('description')
+        self.displayText  = attrs.get('displayText')
+        self.status       = attrs.get('status')
 
-class AtlasRelatedObjectId(AtlasObjectId):
-    entityStatus_enum       = enum.Enum('entityStatus_enum', 'ACTIVE DELETED PURGED', module=__name__)
-    relationshipStatus_enum = enum.Enum('relationshipStatus_enum', 'ACTIVE DELETED', module=__name__)
 
-    def __init__(self, guid=None, typeName=None, uniqueAttributes=None, entityStatus=None, displayText=None,
-                 relationshipType=None, relationshipGuid=None, relationshipStatus=None, relationshipAttributes=None):
-
-        super().__init__(guid, typeName, uniqueAttributes)
-
-        self.entityStatus           = entityStatus
-        self.displayText            = displayText
-        self.relationshipType       = relationshipType
-        self.relationshipGuid       = relationshipGuid
-        self.relationshipStatus     = relationshipStatus
-        self.relationshipAttributes = relationshipAttributes
-
-
-class AtlasTermCategorizationHeader:
-    status_enum = enum.Enum('status_enum', 'DRAFT ACTIVE DEPRECATED OBSOLETE OTHER', module=__name__)
-
-    def __init__(self, categoryGuid=None, relationGuid=None, description=None, displayText=None, status=None):
-        self.categoryGuid = categoryGuid if categoryGuid is not None else ""
-        self.relationGuid = relationGuid
-        self.description  = description
-        self.displayText  = displayText
-        self.status       = status
-
-
-class AtlasGlossaryCategory(AtlasGlossaryBaseObject):
-
-    def __init__(self, guid=None, qualifiedName=None, name=None, shortDescription=None, longDescription=None,
-                 additionalAttributes=None, classifications=None, anchor=None, parentCategory=None, childrenCategories=None, terms=None):
-
-        super().__init__(guid, qualifiedName, name, shortDescription, longDescription, additionalAttributes, classifications)
-
-        # Inherited attributes from relations
-        self.anchor = anchor
-
-        # Category hierarchy links
-        self.parentCategory     = parentCategory
-        self.childrenCategories = childrenCategories
-
-        # Terms associated with this category
-        self.terms = terms if terms is not None else set()
\ No newline at end of file
diff --git a/intg/src/main/python/apache_atlas/model/instance.py b/intg/src/main/python/apache_atlas/model/instance.py
new file mode 100644
index 0000000..89dbe35
--- /dev/null
+++ b/intg/src/main/python/apache_atlas/model/instance.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env/python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import apache_atlas.model.glossary
+
+from apache_atlas.model.enums import *
+from apache_atlas.model.misc  import *
+from apache_atlas.utils       import *
+
+
+class AtlasStruct(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.typeName   = attrs.get('typeName')
+        self.attributes = attrs.get('attributes')
+
+    def get_attribute(self, name):
+        return self.attributes[name] if self.attributes and name in self.attributes else None
+
+    def set_attribute(self, name, value):
+        if self.attributes is None:
+            self.attributes = {}
+
+        self.attributes[name] = value
+
+    def remove_attribute(self, name):
+        if name and self.attributes and name in self.attributes:
+            del self.attributes[name]
+
+
+class AtlasEntity(AtlasStruct):
+    def __init__(self, attrs={}):
+        AtlasStruct.__init__(self, attrs)
+
+        self.guid                   = attrs.get('guid')
+        self.relationshipAttributes = attrs.get('relationshipAttributes')
+        self.classifications        = attrs.get('classifications')
+        self.meanings               = attrs.get('meanings')
+        self.customAttributes       = attrs.get('customAttributes')
+        self.businessAttributes     = attrs.get('businessAttributes')
+        self.labels                 = attrs.get('labels')
+
+        if self.guid is None:
+            self.guid = next_id()
+
+    def type_coerce_attrs(self):
+        super(AtlasEntity, self).type_coerce_attrs()
+
+        self.classifications = type_coerce_list(self.classifications, AtlasClassification)
+        self.meanings        = type_coerce_list(self.meanings, apache_atlas.model.glossary.AtlasTermAssignmentHeader)
+
+    def get_relationship_attribute(self, name):
+        return self.relationshipAttributes[name] if self.relationshipAttributes and name in self.relationshipAttributes else None
+
+    def set_relationship_attribute(self, name, value):
+        if self.relationshipAttributes is None:
+            self.relationshipAttributes = {}
+
+        self.relationshipAttributes[name] = value
+
+    def remove_relationship_attribute(self, name):
+        if name and self.relationshipAttributes and name in self.relationshipAttributes:
+            del self.relationshipAttributes[name]
+
+
+class AtlasEntityExtInfo(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.referredEntities = attrs.get('referredEntities')
+
+    def type_coerce_attrs(self):
+        super(AtlasEntityExtInfo, self).type_coerce_attrs()
+
+        self.referredEntities = type_coerce_dict(self.referredEntities, AtlasEntity)
+
+    def get_referenced_entity(self, guid):
+        return self.referredEntities[guid] if self.referredEntities and guid in self.referredEntities else None
+
+    def add_referenced_entity(self, entity):
+        if self.referredEntities is None:
+            self.referredEntities = {}
+
+        self.referredEntities[entity.guid] = entity
+
+class AtlasEntityWithExtInfo(AtlasEntityExtInfo):
+    def __init__(self, attrs={}):
+        AtlasEntityExtInfo.__init__(self, attrs)
+
+        self.entity = attrs.get('entity')
+
+    def type_coerce_attrs(self):
+        super(AtlasEntityWithExtInfo, self).type_coerce_attrs()
+
+        self.entity = type_coerce(self.entity, AtlasEntity)
+
+
+class AtlasEntitiesWithExtInfo(AtlasEntityExtInfo):
+    def __init__(self, attrs={}):
+        AtlasEntityExtInfo.__init__(self, attrs)
+
+        self.entities = attrs.get('entities')
+
+    def type_coerce_attrs(self):
+        super(AtlasEntitiesWithExtInfo, self).type_coerce_attrs()
+
+        self.entities = type_coerce_list(self.entity, AtlasEntity)
+
+    def add_entity(self, entity):
+        if self.entities is None:
+            self.entities = []
+
+        self.entities.append(entity)
+
+
+class AtlasEntityHeader(AtlasStruct):
+    def __init__(self, attrs={}):
+        AtlasStruct.__init__(self, attrs)
+
+        self.guid                = attrs.get('guid')
+        self.status              = non_null(attrs.get('status'), EntityStatus.ACTIVE.name)
+        self.displayText         = attrs.get('displayText')
+        self.classificationNames = attrs.get('classificationNames')
+        self.classifications     = attrs.get('classifications')
+        self.meaningNames        = attrs.get('meaningNames')
+        self.meanings            = attrs.get('.meanings')
+        self.isIncomplete        = non_null(attrs.get('isIncomplete'), False)
+        self.labels              = attrs.get('labels')
+
+        if self.guid is None:
+            self.guid = next_id()
+
+
+    def type_coerce_attrs(self):
+        super(AtlasEntityHeader, self).type_coerce_attrs()
+
+        self.classifications = type_coerce_list(self.classifications, AtlasClassification)
+        self.meanings        = type_coerce_list(self.meanings, apache_atlas.model.glossary.AtlasTermAssignmentHeader)
+
+
+class AtlasClassification(AtlasStruct):
+    def __init__(self, attrs={}):
+        AtlasStruct.__init__(self, attrs)
+
+        self.entityGuid                       = attrs.get('entityGuid')
+        self.entityStatus                     = non_null(attrs.get('entityStatus'), EntityStatus.ACTIVE.name)
+        self.propagate                        = attrs.get('propagate');
+        self.validityPeriods                  = attrs.get('validityPeriods')
+        self.removePropagationsOnEntityDelete = attrs.get('removePropagationsOnEntityDelete')
+
+    def type_coerce_attrs(self):
+        super(AtlasClassification, self).type_coerce_attrs()
+
+        self.validityPeriods = type_coerce_list(self.validityPeriods, TimeBoundary)
+
+
+class AtlasObjectId(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.guid             = attrs.get('guid')
+        self.typeName         = attrs.get('typeName')
+        self.uniqueAttributes = attrs.get('uniqueAttributes')
+
+
+class AtlasRelatedObjectId(AtlasObjectId):
+    def __init__(self, attrs={}):
+        AtlasObjectId.__init__(self, attrs)
+
+        self.entityStatus           = attrs.get('entityStatus')
+        self.displayText            = attrs.get('displayText')
+        self.relationshipType       = attrs.get('relationshipType')
+        self.relationshipGuid       = attrs.get('relationshipGuid')
+        self.relationshipStatus     = attrs.get('relationshipStatus')
+        self.relationshipAttributes = attrs.get('relationshipAttributes')
+
+    def type_coerce_attrs(self):
+        super(AtlasRelatedObjectId, self).type_coerce_attrs()
+
+        self.relationshipAttributes = type_coerce(self.relationshipAttributes, AtlasStruct)
+
+
+class AtlasClassifications(Plist):
+    def __init__(self,  attrs={}):
+        Plist.__init__(self, attrs)
+
+    def type_coerce_attrs(self):
+        super(AtlasClassifications, self).type_coerce_attrs()
+
+        PList.list = type_coerce_list(Plist.list, AtlasClassification)
+
+
+class AtlasEntityHeaders(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.guidHeaderMap = attrs.get('guidHeaderMap')
+
+    def type_coerce_attrs(self):
+        super(AtlasEntityHeaders, self).type_coerce_attrs()
+
+        self.guidHeaderMap = type_coerce_dict(self.guidHeaderMap, AtlasEntityHeader)
+
+
+class EntityMutationResponse(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.mutatedEntities = attrs.get('mutatedEntities')
+        self.guidAssignments = attrs.get('guidAssignments')
+
+    def type_coerce_attrs(self):
+        super(EntityMutationResponse, self).type_coerce_attrs()
+
+        self.mutatedEntities = type_coerce_dict_list(self.mutatedEntities, AtlasEntityHeader)
+
+    def get_assigned_guid(self, guid):
+        return self.guidAssignments.get(guid) if self.guidAssignments else None
+
+
+class EntityMutations(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.entity_mutations = attrs.get('entity_mutations')
+
+    def type_coerce_attrs(self):
+        super(EntityMutations, self).type_coerce_attrs()
+
+        self.entity_mutations = type_coerce_list(self.entity_mutations, EntityMutation)
+
+
+class EntityMutation(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.op     = attrs.get('op')
+        self.entity = attrs.get('entity')
+
+    def type_coerce_attrs(self):
+        super(EntityMutation, self).type_coerce_attrs()
+
+        self.entity = type_coerce(self.entity, AtlasEntity)
+
+
+class AtlasCheckStateRequest(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.entityGuids = attrs.get('entityGuids')
+        self.entityTypes = attrs.get('entityTypes')
+        self.fixIssues   = attrs.get('fixIssues')
+
+
+class AtlasCheckStateResult(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.entitiesScanned        = attrs.get('entitiesScanned')
+        self.entitiesOk             = attrs.get('entitiesOk')
+        self.entitiesFixed          = attrs.get('entitiesFixed')
+        self.entitiesPartiallyFixed = attrs.get('entitiesPartiallyFixed')
+        self.entitiesNotFixed       = attrs.get('entitiesNotFixed')
+        self.state                  = attrs.get('state')
+        self.entities               = attrs.get('entities')
+
+    def type_coerce_attrs(self):
+        super(AtlasCheckStateResult, self).type_coerce_attrs()
+
+        self.entities = type_coerce(self.entities, AtlasEntityState)
+
+
+class AtlasEntityState(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.guid     = attrs.get('guid')
+        self.typeName = attrs.get('typeName')
+        self.name     = attrs.get('name')
+        self.status   = attrs.get('status')
+        self.state    = attrs.get('state')
+        self.issues   = attrs.get('issues')
diff --git a/intg/src/main/python/apache_atlas/model/lineage.py b/intg/src/main/python/apache_atlas/model/lineage.py
index 9e9c6e1..01ba08a 100644
--- a/intg/src/main/python/apache_atlas/model/lineage.py
+++ b/intg/src/main/python/apache_atlas/model/lineage.py
@@ -17,23 +17,32 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import enum
+from apache_atlas.model.instance import *
+from apache_atlas.utils          import *
 
 
-class AtlasLineageInfo:
-    lineageDirection_enum = enum.Enum('lineageDirection_enum', 'INPUT OUTPUT BOTH', module=__name__)
+class AtlasLineageInfo(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-    def __init__(self, baseEntityGuid=None, lineageDirection=None, lineageDepth=None, guidEntityMap=None, relations=None):
-        self.baseEntityGuid   = baseEntityGuid
-        self.lineageDirection = lineageDirection
-        self.lineageDepth     = lineageDepth
-        self.guidEntityMap    = guidEntityMap if guidEntityMap is not None else {}
-        self.relations        = relations if relations is not None else set()
+        self.baseEntityGuid   = attrs.get('baseEntityGuid')
+        self.lineageDirection = attrs.get('lineageDirection')
+        self.lineageDepth     = attrs.get('lineageDepth')
+        self.guidEntityMap    = attrs.get('guidEntityMap')
+        self.relations        = attrs.get('relations')
 
 
-class LineageRelation:
+    def type_coerce_attrs(self):
+        super(AtlasLineageInfo, self).type_coerce_attrs()
 
-    def __init__(self, fromEntityId=None, toEntityId=None, relationshipId=None):
-        self.fromEntityId   = fromEntityId
-        self.toEntityId     = toEntityId
-        self.relationshipId = relationshipId
\ No newline at end of file
+        self.guidEntityMap = type_coerce_dict(self.guidEntityMap, AtlasEntityHeader)
+        self.relations     = type_coerce_list(self.relations, LineageRelation)
+
+
+class LineageRelation(AtlasBase):
+    def __init__(self, attrs):
+        AtlasBase.__init__(self, attrs)
+
+        self.fromEntityId   = attrs.get('fromEntityId')
+        self.toEntityId     = attrs.get('toEntityId')
+        self.relationshipId = attrs.get('relationshipId')
diff --git a/atlas-examples/sample-app/src/main/python/utils.py b/intg/src/main/python/apache_atlas/model/metrics.py
similarity index 56%
copy from atlas-examples/sample-app/src/main/python/utils.py
copy to intg/src/main/python/apache_atlas/model/metrics.py
index c19382f..636a3ea 100644
--- a/atlas-examples/sample-app/src/main/python/utils.py
+++ b/intg/src/main/python/apache_atlas/model/metrics.py
@@ -17,22 +17,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-NAME        = "name"
-DESCRIPTION = "description"
+from apache_atlas.utils import *
 
-PII_TAG               = "sample_pii_Tag"
-FINANCE_TAG           = "sample_finance_Tag"
-CLASSIFICATION        = "classification"
-METRIC_CLASSIFICATION = "Metric"
 
-DATABASE_TYPE = "sample_db_type"
-PROCESS_TYPE  = "sample_process_type"
-TABLE_TYPE    = "sample_table_type"
-COLUMN_TYPE   = "sample_column_type"
+class AtlasMetrics(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-TABLE_DATABASE_TYPE       = "sample_Table_DB"
-TABLE_COLUMNS_TYPE        = "sample_Table_Columns"
-ENUM_TABLE_TYPE           = "tableType"
-BUSINESS_METADATA_TYPE    = "bmWithAllTypes"
-BUSINESS_METADATA_TYPE_MV = "bmWithAllTypesMV"
-STRUCT_TYPE_SERDE         = "serdeType"
\ No newline at end of file
+        self.data = attrs.get('data')
diff --git a/intg/src/main/python/apache_atlas/model/misc.py b/intg/src/main/python/apache_atlas/model/misc.py
new file mode 100644
index 0000000..23d0d2f
--- /dev/null
+++ b/intg/src/main/python/apache_atlas/model/misc.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env/python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+import sys
+
+from apache_atlas.utils import *
+
+
+class AtlasBase(dict):
+    def __init__(self, attrs):
+        pass
+
+    def __getattr__(self, attr):
+        return self.get(attr)
+
+    def __setattr__(self, key, value):
+        self.__setitem__(key, value)
+
+    def __setitem__(self, key, value):
+        super(AtlasBase, self).__setitem__(key, value)
+        self.__dict__.update({key: value})
+
+    def __delattr__(self, item):
+        self.__delitem__(item)
+
+    def __delitem__(self, key):
+        super(AtlasBase, self).__delitem__(key)
+        del self.__dict__[key]
+
+    def __repr__(self):
+        return json.dumps(self)
+
+    def type_coerce_attrs(self):
+        pass
+
+class AtlasBaseModelObject(AtlasBase):
+    def __init__(self, members):
+        AtlasBase.__init__(self, members)
+
+        self.guid = members.get('guid')
+
+        if self.guid is None:
+            self.guid = next_id()
+
+
+class TimeBoundary(AtlasBase):
+    def __init__(self,  attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.startTime = attrs.get('startTime')
+        self.endTime   = attrs.get('endTime')
+        self.timeZone  = attrs.get('timeZone')
+
+
+class Plist(AtlasBase):
+    def __init__(self,  attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.list       = non_null(attrs.get('list'), [])
+        self.startIndex = non_null(attrs.get('startIndex'), 0)
+        self.pageSize   = non_null(attrs.get('pageSize'), 0)
+        self.totalCount = non_null(attrs.get('totalCount'), 0)
+        self.sortBy     = attrs.get('sortBy')
+        self.sortType   = attrs.get('sortType')
+
+
+class SearchFilter(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.startIndex = non_null(attrs.get('startIndex'), 0)
+        self.maxsize    = non_null(attrs.get('maxsize'), sys.maxsize)
+        self.getCount   = non_null(attrs.get('getCount'), True)
diff --git a/intg/src/main/python/apache_atlas/model/profile.py b/intg/src/main/python/apache_atlas/model/profile.py
new file mode 100644
index 0000000..4c27702
--- /dev/null
+++ b/intg/src/main/python/apache_atlas/model/profile.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env/python
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicabwle law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from apache_atlas.model.discovery import *
+from apache_atlas.utils           import *
+
+
+class AtlasUserSavedSearch(AtlasBaseModelObject):
+    def __init__(self, attrs={}):
+        AtlasBaseModelObject.__init__(self, attrs)
+
+        self.ownerName        = attrs.get('ownerName')
+        self.name             = attrs.get('name')
+        self.searchType       = attrs.get('searchType')
+        self.searchParameters = attrs.get('searchParameters')
+        self.uiParameters     = attrs.get('uiParameters')
+
+    def type_coerce_attrs(self):
+        super(AtlasUserSavedSearch, self).type_coerce_attrs()
+
+        self.searchParameters = type_coerce(self.searchParameters, SearchParameters)
diff --git a/intg/src/main/python/apache_atlas/model/relationship.py b/intg/src/main/python/apache_atlas/model/relationship.py
index 64a59ed..58bfd1b 100644
--- a/intg/src/main/python/apache_atlas/model/relationship.py
+++ b/intg/src/main/python/apache_atlas/model/relationship.py
@@ -17,41 +17,48 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import enum
-
-from apache_atlas.model.entity import AtlasStruct
+from apache_atlas.model.instance import *
+from apache_atlas.utils          import *
 
 
 class AtlasRelationship(AtlasStruct):
+    def __init__(self, attrs={}):
+        AtlasStruct.__init__(self, attrs)
+
+        self.guid                             = attrs.get('guid')
+        self.homeId                           = attrs.get('homeId')
+        self.provenanceType                   = attrs.get('provenanceType')
+        self.end1                             = attrs.get('end1')
+        self.end2                             = attrs.get('end2')
+        self.label                            = attrs.get('label')
+        self.propagateTags                    = attrs.get('propagateTags')
+        self.status                           = attrs.get('status')
+        self.createdBy                        = attrs.get('createdBy')
+        self.updatedBy                        = attrs.get('updatedBy')
+        self.createTime                       = attrs.get('createTime')
+        self.updateTime                       = attrs.get('updateTime')
+        self.version                          = attrs.get('version')
+        self.propagatedClassifications        = attrs.get('propagatedClassifications')
+        self.blockedPropagatedClassifications = attrs.get('blockedPropagatedClassifications')
+
+    def type_coerce_attrs(self):
+        super(AtlasRelationship, self).type_coerce_attrs()
+
+        self.end1                             = type_coerce(self.end1, AtlasObjectId)
+        self.end2                             = type_coerce(self.end2, AtlasObjectId)
+        self.propagatedClassifications        = type_coerce_list(self.propagatedClassifications, AtlasClassification)
+        self.blockedPropagatedClassifications = type_coerce_list(self.blockedPropagatedClassifications, AtlasClassification)
+
+
+class AtlasRelationshipWithExtInfo(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.relationship     = attrs.get('relationship')
+        self.referredEntities = attrs.get('referredEntities')
+
+    def type_coerce_attrs(self):
+        super(AtlasBase, self).type_coerce_attrs()
 
-    propagateTags_enum = enum.Enum('propagateTags_enum', 'NONE ONE_TO_TWO TWO_TO_ONE BOTH', module=__name__)
-    status_enum        = enum.Enum('status_enum', 'ACTIVE DELETED', module=__name__)
-
-    def __init__(self, typeName=None, attributes=None, guid=None, homeId=None, provenanceType=None, end1=None, end2=None,
-                 label=None, propagateTags=None, status=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None,
-                 version=0, propagatedClassifications=None, blockedPropagatedClassifications=None):
-
-        super().__init__(typeName, attributes)
-
-        self.guid                             = guid
-        self.homeId                           = homeId
-        self.provenanceType                   = provenanceType
-        self.end1                             = end1
-        self.end2                             = end2
-        self.label                            = label
-        self.propagateTags                    = propagateTags if propagateTags is not None else AtlasRelationship.propagateTags_enum.NONE.name
-        self.status                           = status if status is not None else AtlasRelationship.status_enum.ACTIVE.name
-        self.createdBy                        = createdBy
-        self.updatedBy                        = updatedBy
-        self.createTime                       = createTime
-        self.updateTime                       = updateTime
-        self.version                          = version
-        self.propagatedClassifications        = propagatedClassifications if propagatedClassifications is not None else set()
-        self.blockedPropagatedClassifications = blockedPropagatedClassifications if blockedPropagatedClassifications is not None else set()
-
-
-class AtlasRelationshipWithExtInfo:
-
-    def __init__(self, relationship=None, referredEntities=None):
-        self.relationship     = relationship
-        self.referredEntities = referredEntities if referredEntities is not None else {}
+        self.relationship     = type_coerce(self.relationship, AtlasRelationship)
+        self.referredEntities = type_coerce_dict(self.referredEntities, AtlasEntityHeader)
diff --git a/intg/src/main/python/apache_atlas/model/typedef.py b/intg/src/main/python/apache_atlas/model/typedef.py
index 480d9fe..30e2750 100644
--- a/intg/src/main/python/apache_atlas/model/typedef.py
+++ b/intg/src/main/python/apache_atlas/model/typedef.py
@@ -17,185 +17,179 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import enum
+import logging
 
+from apache_atlas.model.enums import *
+from apache_atlas.model.misc  import *
+from apache_atlas.utils       import *
 
-class AtlasTypesDef:
 
-    def __init__(self, enumDefs=None, structDefs=None, classificationDefs=None,
-                 entityDefs=None, relationshipDefs=None, businessMetadataDefs=None):
-        self.enumDefs             = enumDefs if enumDefs is not None else []
-        self.structDefs           = structDefs if structDefs is not None else []
-        self.classificationDefs   = classificationDefs if classificationDefs is not None else []
-        self.entityDefs           = entityDefs if entityDefs is not None else []
-        self.relationshipDefs     = relationshipDefs if relationshipDefs is not None else []
-        self.businessMetadataDefs = businessMetadataDefs if businessMetadataDefs is not None else []
+LOG = logging.getLogger('apache_atlas')
 
 
-class AtlasBaseTypeDef:
+class AtlasBaseTypeDef(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-    def __init__(self, category=None, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None,
-                 version=None, name=None, description=None, typeVersion=None, serviceType=None, options=None):
-        self.category    = category
-        self.guid        = guid
-        self.createdBy   = createdBy
-        self.updatedBy   = updatedBy
-        self.createTime  = createTime
-        self.updateTime  = updateTime
-        self.version     = version
-        self.name        = name
-        self.description = description
-        self.typeVersion = typeVersion
-        self.serviceType = serviceType
-        self.options     = options if options is not None else {}
+        self.category    = attrs.get('category')
+        self.guid        = attrs.get('guid')
+        self.createdBy   = attrs.get('createdBy')
+        self.updatedBy   = attrs.get('updatedBy')
+        self.createTime  = attrs.get('createTime')
+        self.updateTime  = attrs.get('updateTime')
+        self.version     = attrs.get('version')
+        self.name        = attrs.get('name')
+        self.description = attrs.get('description')
+        self.typeVersion = attrs.get('typeVersion')
+        self.serviceType = attrs.get('serviceType')
+        self.options     = attrs.get('options')
 
 
-category_enum = enum.Enum('category_enum', 'PRIMITIVE OBJECT_ID_TYPE ENUM STRUCT CLASSIFICATION ENTITY ARRAY MAP RELATIONSHIP BUSINESS_METADATA', module=__name__)
+class AtlasEnumDef(AtlasBaseTypeDef):
+    def __init__(self, attrs={}):
+        AtlasBaseTypeDef.__init__(self, attrs)
 
+        self.elementDefs  = attrs.get('elementDefs')
+        self.defaultValue = attrs.get('defaultValue')
 
-class AtlasEnumDef(AtlasBaseTypeDef):
+    def type_coerce_attrs(self):
+        super(AtlasEnumDef, self).type_coerce_attrs()
 
-    def __init__(self, category=category_enum.ENUM.name, guid=None, createdBy=None, updatedBy=None, createTime=None,
-                 updateTime=None, version=None, name=None, description=None, typeVersion=None,
-                 serviceType=None, options=None, elementDefs=None, defaultValue=None):
+        self.elementDefs = type_coerce_list(self.elementDefs, AtlasEnumElementDef)
 
-        super().__init__(category, guid, createdBy, updatedBy, createTime, updateTime, version, name, description, typeVersion, serviceType, options)
 
-        self.elementDefs  = elementDefs if elementDefs is not None else []
-        self.defaultValue = defaultValue
+class AtlasStructDef(AtlasBaseTypeDef):
+    def __init__(self, attrs={}):
+        AtlasBaseTypeDef.__init__(self, attrs)
 
+        self.category      = non_null(attrs.get('category'), TypeCategory.STRUCT.name)
+        self.attributeDefs = attrs.get('attributeDefs')
 
-class AtlasEnumElementDef:
+    def type_coerce_attrs(self):
+        super(AtlasStructDef, self).type_coerce_attrs()
 
-    def __init__(self, value=None, description=None, ordinal=None):
-        self.value       = value
-        self.description = description
-        self.ordinal     = ordinal
+        self.attributeDefs = type_coerce_list(self.attributeDefs, AtlasAttributeDef)
 
 
-class AtlasStructDef(AtlasBaseTypeDef):
+class AtlasClassificationDef(AtlasStructDef):
+    def __init__(self, attrs={}):
+        AtlasStructDef.__init__(self, attrs)
 
-    def __init__(self, category=category_enum.STRUCT.name, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None, version=None,
-                 name=None, description=None, typeVersion=None, serviceType=None, options=None, attributeDefs=None):
+        self.category    = TypeCategory.CLASSIFICATION.name
+        self.superTypes  = attrs.get('superTypes')
+        self.entityTypes = attrs.get('entityTypes')
+        self.subTypes    = attrs.get('subTypes')
 
-        super().__init__(category, guid, createdBy, updatedBy, createTime, updateTime, version, name, description, typeVersion, serviceType, options)
 
-        self.attributeDefs = attributeDefs if attributeDefs is not None else []
+class AtlasEntityDef(AtlasStructDef):
+    def __init__(self, attrs={}):
+        AtlasStructDef.__init__(self, attrs)
 
+        self.category                  = TypeCategory.ENTITY.name
+        self.superTypes                = attrs.get('superTypes')
+        self.subTypes                  = attrs.get('subTypes')
+        self.relationshipAttributeDefs = attrs.get('relationshipAttributeDefs')
+        self.businessAttributeDefs     = attrs.get('businessAttributeDefs')
 
-class AtlasAttributeDef:
-    cardinality_enum = enum.Enum('cardinality_enum', 'SINGLE LIST SET', module=__name__)
-    indexType_enum   = enum.Enum('indexType_enum', 'DEFAULT STRING', module=__name__)
+    def type_coerce_attrs(self):
+        super(AtlasEntityDef, self).type_coerce_attrs()
 
-    def __init__(self, name=None, typeName=None, isOptional=None, cardinality=None, valuesMinCount=None, valuesMaxCount=None,
-                 isUnique=None, isIndexable=None, includeInNotification=None, defaultValue=None, description=None, searchWeight= -1,
-                 indexType=None, constraints=None, options=None, displayName=None):
+        self.relationshipAttributeDefs = type_coerce_list(self.relationshipAttributeDefs, AtlasRelationshipAttributeDef)
+        self.businessAttributeDefs     = type_coerce_dict_list(self.businessAttributeDefs, AtlasAttributeDef)
 
-        self.name                  = name
-        self.typeName              = typeName
-        self.isOptional            = isOptional
-        self.cardinality           = cardinality
-        self.valuesMinCount        = valuesMinCount
-        self.valuesMaxCount        = valuesMaxCount
-        self.isUnique              = isUnique
-        self.isIndexable           = isIndexable
-        self.includeInNotification = includeInNotification
-        self.defaultValue          = defaultValue
-        self.description           = description
-        self.searchWeight          = searchWeight
-        self.indexType             = indexType
-        self.constraints           = constraints if constraints is not None else []
-        self.options               = options if options is not None else {}
-        self.displayName           = displayName
 
+class AtlasRelationshipDef(AtlasStructDef):
+    def __init__(self, attrs={}):
+        AtlasStructDef.__init__(self, attrs)
 
-class AtlasConstraintDef:
+        self.category = TypeCategory.RELATIONSHIP.name
 
-    def __init__(self, type=None, params=None):
-        self.type   = type
-        self.params = params if params is not None else {}
 
+class AtlasBusinessMetadataDef(AtlasStructDef):
+    def __init__(self, attrs={}):
+        AtlasStructDef.__init__(self, attrs)
 
-class AtlasClassificationDef(AtlasStructDef):
+        self.category = TypeCategory.BUSINESS_METADATA.name
 
-    def __init__(self, category=category_enum.CLASSIFICATION.name, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None,
-                 version=None, name=None, description=None, typeVersion=None, serviceType=None, options=None,
-                 attributeDefs=None, superTypes=None, entityTypes=None, subTypes=None):
 
-        super().__init__(category, guid, createdBy, updatedBy, createTime, updateTime, version,
-                         name, description, typeVersion, serviceType, options, attributeDefs)
+class AtlasAttributeDef(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-        self.superTypes  = superTypes if superTypes is not None else set()
-        self.entityTypes = entityTypes if entityTypes is not None else set()
-        self.subTypes    = subTypes if subTypes is not None else set()
+        self.name                  = attrs.get('name')
+        self.typeName              = attrs.get('typeName')
+        self.isOptional            = attrs.get('isOptional')
+        self.cardinality           = attrs.get('cardinality')
+        self.valuesMinCount        = attrs.get('valuesMinCount')
+        self.valuesMaxCount        = attrs.get('valuesMaxCount')
+        self.isUnique              = attrs.get('isUnique')
+        self.isIndexable           = attrs.get('isIndexable')
+        self.includeInNotification = attrs.get('includeInNotification')
+        self.defaultValue          = attrs.get('defaultValue')
+        self.description           = attrs.get('description')
+        self.searchWeight          = non_null(attrs.get('searchWeight'), -1)
+        self.indexType             = attrs.get('indexType')
+        self.constraints           = attrs.get('constraints')
+        self.options               = attrs.get('options')
+        self.displayName           = attrs.get('displayName')
 
+    def type_coerce_attrs(self):
+        super(AtlasAttributeDef, self).type_coerce_attrs()
+
+        self.constraints = type_coerce_list(self.constraints, AtlasConstraintDef)
+
+
+class AtlasConstraintDef(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
+
+        self.type   = attrs.get('type')
+        self.params = attrs.get('params')
 
-class AtlasEntityDef(AtlasStructDef):
-    def __init__(self, category=category_enum.CLASSIFICATION.name, guid=None, createdBy=None, updatedBy=None, createTime=None, updateTime=None,
-                 version=None, name=None, description=None, typeVersion=None, serviceType=None, options=None,
-                 attributeDefs=None, superTypes=None, subTypes=None, relationshipAttributeDefs=None, businessAttributeDefs=None):
 
-        super().__init__(category, guid, createdBy, updatedBy, createTime, updateTime, version,
-                         name, description, typeVersion, serviceType, options, attributeDefs)
+class AtlasEnumElementDef(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-        self.superTypes                = superTypes if superTypes is not None else set()
-        self.subTypes                  = subTypes if subTypes is not None else set()
-        self.relationshipAttributeDefs = relationshipAttributeDefs if relationshipAttributeDefs is not None else []
-        self.businessAttributeDefs     = businessAttributeDefs if businessAttributeDefs is not None else {}
+        self.value       = attrs.get('value')
+        self.description = attrs.get('description')
+        self.ordinal     = attrs.get('ordinal')
 
 
 class AtlasRelationshipAttributeDef(AtlasAttributeDef):
-    cardinality_enum = enum.Enum('cardinality_enum', 'SINGLE LIST SET', module=__name__)
-    indexType_enum   = enum.Enum('indexType_enum', 'DEFAULT STRING', module=__name__)
+    def __init__(self, attrs={}):
+        AtlasAttributeDef.__init__(self, attrs)
 
-    def __init__(self, name=None, typeName=None, isOptional=None, cardinality=None, valuesMinCount=None,
-                 valuesMaxCount=None, isUnique=None, isIndexable=None, includeInNotification=None,
-                 defaultValue=None, description=None, searchWeight=None, indexType=None, constraints=None,
-                 options=None, displayName=None, relationshipTypeName=None, isLegacyAttribute=None):
+        self.relationshipTypeName = attrs.get('relationshipTypeName')
+        self.isLegacyAttribute    = attrs.get('isLegacyAttribute')
 
-        super().__init__(name, typeName, isOptional, cardinality, valuesMinCount, valuesMaxCount, isUnique, isIndexable,
-                         includeInNotification, defaultValue, description, searchWeight, indexType, constraints, options, displayName)
 
-        self.relationshipTypeName = relationshipTypeName
-        self.isLegacyAttribute    = isLegacyAttribute
+class AtlasRelationshipEndDef(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
+        self.cardinality = non_null(self.cardinality, Cardinality.SINGLE.name)
 
-class AtlasBusinessMetadataDef(AtlasStructDef):
 
-    def __init__(self, category=category_enum.BUSINESS_METADATA.name, guid=None, createdBy=None, updatedBy=None, createTime=None,
-                 updateTime=None, version=None, name=None, description=None, typeVersion=None,
-                 serviceType=None, options=None, attributeDefs=None):
+class AtlasTypesDef(AtlasBase):
+    def __init__(self, attrs={}):
+        AtlasBase.__init__(self, attrs)
 
-        super().__init__(category, guid, createdBy, updatedBy, createTime, updateTime, version,
-                         name, description, typeVersion, serviceType, options, attributeDefs)
+        self.enumDefs             = attrs.get('enumDefs')
+        self.structDefs           = attrs.get('structDefs')
+        self.classificationDefs   = attrs.get('classificationDefs')
+        self.entityDefs           = attrs.get('entityDefs')
+        self.relationshipDefs     = attrs.get('relationshipDefs')
+        self.businessMetadataDefs = attrs.get('businessMetadataDefs')
+
+    def type_coerce_attrs(self):
+        super(AtlasTypesDef, self).type_coerce_attrs()
+
+        self.enumDefs             = type_coerce_list(self.enumDefs, AtlasEnumDef)
+        self.structDefs           = type_coerce_list(self.structDefs, AtlasStructDef)
+        self.classificationDefs   = type_coerce_list(self.classificationDefs, AtlasClassificationDef)
+        self.entityDefs           = type_coerce_list(self.entityDefs, AtlasEntityDef)
+        self.relationshipDefs     = type_coerce_list(self.relationshipDefs, AtlasRelationshipDef)
+        self.businessMetadataDefs = type_coerce_list(self.businessMetadataDefs, AtlasBusinessMetadataDef)
 
 
-class AtlasRelationshipDef(AtlasStructDef):
-    relationshipCategory_enum = enum.Enum('relationshipCategory_enum', 'ASSOCIATION AGGREGATION COMPOSITION', module=__name__)
-    propagateTags_enum        = enum.Enum('propagateTags_enum', 'NONE ONE_TO_TWO TWO_TO_ONE BOTH', module=__name__)
-
-    def __init__(self, category=category_enum.RELATIONSHIP.name, guid=None, createdBy=None, updatedBy=None, createTime=None,
-                 updateTime=None, version=None, name=None, description=None, typeVersion=None,
-                 serviceType=None, options=None, attributeDefs=None, relationshipCategory=None,
-                 relationshipLabel=None, propagateTags=None, endDef1=None, endDef2=None):
-
-        super().__init__(category, guid, createdBy, updatedBy, createTime, updateTime, version,
-                         name, description, typeVersion, serviceType, options, attributeDefs)
-
-        self.relationshipCategory = relationshipCategory
-        self.relationshipLabel    = relationshipLabel
-        self.propagateTags        = propagateTags
-        self.endDef1              = endDef1
-        self.endDef2              = endDef2
-
-
-class AtlasRelationshipEndDef:
-    cardinality_enum = enum.Enum('cardinality_enum', 'SINGLE LIST SET', module=__name__)
-
-    def __init__(self, type=None, name=None, isContainer=None, cardinality=None, isLegacyAttribute=None, description=None):
-        self.type              = type
-        self.name              = name
-        self.isContainer       = isContainer
-        self.cardinality       = cardinality if cardinality is not None else AtlasRelationshipEndDef.cardinality_enum.SINGLE.name
-        self.isLegacyAttribute = isLegacyAttribute
-        self.description       = description
\ No newline at end of file
diff --git a/intg/src/main/python/apache_atlas/utils.py b/intg/src/main/python/apache_atlas/utils.py
index a59f29f..8384dc5 100644
--- a/intg/src/main/python/apache_atlas/utils.py
+++ b/intg/src/main/python/apache_atlas/utils.py
@@ -18,7 +18,6 @@
 # limitations under the License.
 
 import enum
-from json import JSONEncoder
 import time
 
 BASE_URI                 = "api/atlas/"
@@ -30,6 +29,12 @@ PREFIX_ATTR_             = "attr_"
 
 s_nextId = milliseconds = int(round(time.time() * 1000)) + 1
 
+def next_id():
+    global s_nextId
+
+    s_nextId += 1
+
+    return "-" + str(s_nextId)
 
 def list_attributes_to_params(attributes_list, query_params=None):
     if not query_params:
@@ -42,7 +47,6 @@ def list_attributes_to_params(attributes_list, query_params=None):
 
     return query_params
 
-
 def attributes_to_params(attributes, query_params=None):
     if not query_params:
         query_params = {}
@@ -54,12 +58,50 @@ def attributes_to_params(attributes, query_params=None):
 
     return query_params
 
+def non_null(obj, defValue):
+    return obj if obj is not None else defValue
 
-class HttpMethod(enum.Enum):
-    GET    = "GET"
-    PUT    = "PUT"
-    POST   = "POST"
-    DELETE = "DELETE"
+def type_coerce(obj, objType):
+    if isinstance(obj, objType):
+        ret = obj
+    elif isinstance(obj, dict):
+        ret = objType(obj)
+
+        ret.type_coerce_attrs()
+    else:
+        ret = None
+
+    return ret
+
+def type_coerce_list(obj, objType):
+    if isinstance(obj, list):
+        ret = []
+        for entry in obj:
+            ret.append(type_coerce(entry, objType))
+    else:
+        ret = None
+
+    return ret
+
+def type_coerce_dict(obj, objType):
+    if isinstance(obj, dict):
+        ret = {}
+        for k, v in obj.items():
+            ret[k] = type_coerce(v, objType)
+    else:
+        ret = None
+
+    return ret
+
+def type_coerce_dict_list(obj, objType):
+    if isinstance(obj, dict):
+        ret = {}
+        for k, v in obj.items():
+            ret[k] = type_coerce_list(v, objType)
+    else:
+        ret = None
+
+    return ret
 
 
 class API:
@@ -71,7 +113,7 @@ class API:
         self.produces        = produces
 
     def format_path(self, params):
-        return API(self.path.format_map(params), self.method, self.expected_status, self.consumes, self.produces)
+        return API(self.path.format(**params), self.method, self.expected_status, self.consumes, self.produces)
 
     def format_path_with_params(self, *params):
         path = self.path
@@ -82,14 +124,14 @@ class API:
         return API(path, self.method, self.expected_status, self.consumes, self.produces)
 
 
-class CustomEncoder(JSONEncoder):
-    def default(self, o):
-        if isinstance(o, set):
-            return list(o)
-
-        return o.__dict__
+class HttpMethod(enum.Enum):
+    GET    = "GET"
+    PUT    = "PUT"
+    POST   = "POST"
+    DELETE = "DELETE"
 
 
-class AtlasBaseModelObject:
-    def __init__(self, guid=None):
-        self.guid = guid if guid is not None else "-" + str(s_nextId)
\ No newline at end of file
+class HTTPStatus:
+    OK                  = 200
+    NO_CONTENT          = 204
+    SERVICE_UNAVAILABLE = 503
diff --git a/intg/src/main/python/setup.py b/intg/src/main/python/setup.py
index 60f49d2..ed33ebe 100644
--- a/intg/src/main/python/setup.py
+++ b/intg/src/main/python/setup.py
@@ -22,18 +22,22 @@ from setuptools import setup, find_packages
 # External dependencies
 requirements = ['requests>=2.24']
 
+long_description = ''
+with open("README.md", "r") as fh:
+    long_description = fh.read()
+
 setup(
     name='apache-atlas',
-    version='0.0.1',
+    version='0.0.2',
     author="Apache Atlas",
     author_email='dev@atlas.apache.org',
     description="Apache Atlas Python Client",
-    long_description="Apache Atlas Python client",
+    long_description=long_description,
     long_description_content_type="text/markdown",
     url="https://github.com/apache/atlas/tree/master/intg/src/main/python",
     license='Apache LICENSE 2.0',
     classifiers=[
-        "Programming Language :: Python :: 3",
+        "Programming Language :: Python :: 2.7",
         "License :: OSI Approved :: Apache Software License",
         "Operating System :: OS Independent",
     ],
@@ -42,4 +46,5 @@ setup(
     include_package_data=True,
     zip_safe=False,
     keywords='atlas client, apache atlas',
-)
\ No newline at end of file
+	python_requires='>=2.7',
+)