Repository: Cyberwatch/cyberwatch_api_toolbox

Issue:
Add a toJSON() method in a abstract model class
Use https://stackoverflow.com/questions/3768895/how-to-make-a-class-json-serializable/15538391#15538391 to define a toJSON() method.

Discussion:
hezanathos: ./examples/affect_group_os.py:28
./examples/recovered_servers_script/communication_failure_recovered.py:90
the models have not been deleted 


Patch:
diff --git a/README.md b/README.md
index 9ecb8ba..fec1eaf 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ A simple interface for your Cyberwatch instance API.
 - [ ] [Python 3](https://www.python.org/)
 - [ ] Python [PIP](https://pypi.org/project/pip/)
 
-### Install the package
+### Install the latest package
 
 To install Cyberwatch API toolbox, simply use python 3 with:
 
@@ -32,6 +32,14 @@ To install Cyberwatch API toolbox, simply use python 3 with:
 $ pip3 install cbw-api-toolbox
 ```
 
+### Install an older package version
+
+Some scripts from version 1.X may not work in version 2.X of `cbw-api-toolbox`, to install an older version, simply do:
+
+```bash
+pip3 install cbw-api-toolbox==1.1.2
+```
+
 ### Test your installation
 
 **Create a new file called `ping.py` and copy/paste this content**
diff --git a/cbw_api_toolbox/cbw_api.py b/cbw_api_toolbox/cbw_api.py
index c0a31ae..54988d0 100644
--- a/cbw_api_toolbox/cbw_api.py
+++ b/cbw_api_toolbox/cbw_api.py
@@ -4,6 +4,7 @@ import json
 import logging
 import sys
 
+from collections import namedtuple
 from urllib.parse import urlparse
 from urllib.parse import parse_qs
 import requests
@@ -22,18 +23,6 @@ from cbw_api_toolbox.__routes__ import ROUTE_SECURITY_ISSUES
 from cbw_api_toolbox.__routes__ import ROUTE_SERVERS
 from cbw_api_toolbox.__routes__ import ROUTE_USERS
 from cbw_api_toolbox.cbw_auth import CBWAuth
-from cbw_api_toolbox.cbw_objects.cbw_agent import CBWAgent
-from cbw_api_toolbox.cbw_objects.cbw_server import CBWCve
-from cbw_api_toolbox.cbw_objects.cbw_group import CBWGroup
-from cbw_api_toolbox.cbw_objects.cbw_host import CBWHost
-from cbw_api_toolbox.cbw_objects.cbw_importer import CBWImporter
-from cbw_api_toolbox.cbw_objects.cbw_node import CBWNode
-from cbw_api_toolbox.cbw_objects.cbw_remote_access import CBWRemoteAccess
-from cbw_api_toolbox.cbw_objects.cbw_security_issue import CBWSecurityIssue
-from cbw_api_toolbox.cbw_objects.cbw_server import CBWServer
-from cbw_api_toolbox.cbw_objects.cbw_users import CBWUsers
-from cbw_api_toolbox.cbw_parser import CBWParser
-
 
 class CBWApi: # pylint: disable=R0904
     """Class used to communicate with the CBW API"""
@@ -49,6 +38,14 @@ class CBWApi: # pylint: disable=R0904
     def _build_route(self, params):
         return "{0}{1}".format(self.api_url, '/'.join(params))
 
+    def _cbw_parser(self, response):
+        """Parse the response text of an API request"""
+        try:
+            result = json.loads(response.text, object_hook=lambda d: namedtuple('cbw_object', d.keys())(*d.values()))
+        except TypeError:
+            self.logger.error("An error occurred while parsing response")
+        return result
+
     def _request(self, verb, payloads, body_params=None):
         route = self._build_route(payloads)
 
@@ -71,7 +68,7 @@ class CBWApi: # pylint: disable=R0904
             self.logger.error("An error occurred, please check your API_URL.")
             sys.exit(-1)
 
-    def _get_pages(self, verb, route, params, model):
+    def _get_pages(self, verb, route, params):
         """ Get one or more pages for a method using api v3 pagination """
         response_list = []
 
@@ -87,7 +84,7 @@ class CBWApi: # pylint: disable=R0904
             if response.status_code != 200:
                 logging.error("Error::{}".format(response.text))
                 return None
-            return CBWParser().parse_response(model, response)
+            return self._cbw_parser(response)
 
         response = self._request(verb, route, params)
 
@@ -95,13 +92,13 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        response_list.extend(CBWParser().parse_response(model, response))
+        response_list.extend(self._cbw_parser(response))
 
         while 'next' in response.links:
             next_url = urlparse(response.links['next']['url'])
             params['page'] = parse_qs(next_url .query)['page'][0]
             response = self._request(verb, route, params)
-            response_list.extend(CBWParser().parse_response(model, response))
+            response_list.extend(self._cbw_parser(response))
         return response_list
 
     @staticmethod
@@ -126,7 +123,7 @@ class CBWApi: # pylint: disable=R0904
 
     def servers(self, params=None):
         """GET request to /api/v3/servers to get all servers"""
-        response = self._get_pages("GET", [ROUTE_SERVERS], params, CBWServer)
+        response = self._get_pages("GET", [ROUTE_SERVERS], params)
 
         return response
 
@@ -137,8 +134,7 @@ class CBWApi: # pylint: disable=R0904
         if response.status_code != 200:
             logging.error("Error server id::{}".format(response.text))
             return None
-
-        return CBWParser().parse_response(CBWServer, response)
+        return self._cbw_parser(response)
 
     def server_refresh(self, server_id):
         """PUT request to /api/v3/server/{server_id}/refresh to relaunch analysis
@@ -148,7 +144,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error server id::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWServer, response)
+        return self._cbw_parser(response)
 
     def update_server(self, server_id, info):
         """PATCH request to /api/v3/servers/SERVER_ID to update the groups of a server"""
@@ -169,7 +165,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWServer, response)
+        return self._cbw_parser(response)
 
     def delete_server(self, server_id):
         """DELETE request to /api/v3/servers/SERVER_ID to delete a specific server"""
@@ -188,11 +184,11 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWServer, response)
+        return self._cbw_parser(response)
 
     def agents(self, params=None):
         """GET request to /api/v3/agents to get all agents"""
-        response = self._get_pages("GET", [ROUTE_AGENTS], params, CBWAgent)
+        response = self._get_pages("GET", [ROUTE_AGENTS], params)
         return response
 
     def agent(self, agent_id):
@@ -202,7 +198,7 @@ class CBWApi: # pylint: disable=R0904
         if response.status_code != 200:
             logging.error("Error agent id::{}".format(response.text))
             return None
-        return CBWParser().parse_response(CBWAgent, response)
+        return self._cbw_parser(response)
 
     def delete_agent(self, agent_id):
         """DELETE request to /api/v3/agents/{agent_id} to delete a specific agent"""
@@ -216,7 +212,7 @@ class CBWApi: # pylint: disable=R0904
 
     def remote_accesses(self, params=None):
         """GET request to /api/v3/remote_accesses to get all servers"""
-        response = self._get_pages("GET", [ROUTE_REMOTE_ACCESSES], params, CBWRemoteAccess)
+        response = self._get_pages("GET", [ROUTE_REMOTE_ACCESSES], params)
 
         return response
 
@@ -237,7 +233,7 @@ class CBWApi: # pylint: disable=R0904
 
         if self.verif_response(response):
             logging.info('remote access successfully created {}'.format(info["address"]))
-            return CBWParser().parse_response(CBWRemoteAccess, response)
+            return self._cbw_parser(response)
 
         logging.error("Error create connection remote access")
         return False
@@ -251,7 +247,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("error remote_access_id::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWRemoteAccess, response)
+        return self._cbw_parser(response)
 
     def delete_remote_access(self, remote_access_id):
         """DELETE request to /api/v3/remote_access/{remote_id} to delete a specific remote access"""
@@ -268,7 +264,7 @@ class CBWApi: # pylint: disable=R0904
         if remote_access_id and info:
             response = self._request("PATCH", [ROUTE_REMOTE_ACCESSES, remote_access_id], info)
             logging.debug("Update remote access::{}".format(response.text))
-            return CBWParser().parse_response(CBWRemoteAccess, response)
+            return self._cbw_parser(response)
 
         logging.error("Error update remote access")
         return False
@@ -281,11 +277,11 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error server id::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWCve, response)
+        return self._cbw_parser(response)
 
     def cve_announcements(self, params=None):
         """GET request to /api/v3/cve_announcements to get a list of cve_announcement"""
-        response = self._get_pages("GET", [ROUTE_CVE_ANNOUNCEMENTS], params, CBWCve)
+        response = self._get_pages("GET", [ROUTE_CVE_ANNOUNCEMENTS], params)
 
         return response
 
@@ -297,7 +293,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error server id::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWCve, response)
+        return self._cbw_parser(response)
 
     def delete_cve_announcement(self, cve_code):
         """DELETE request to /api/v3/cve_announcements/{cve_code} to delete
@@ -307,11 +303,11 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error server id::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWCve, response)
+        return self._cbw_parser(response)
 
     def groups(self, params=None):
         """GET request to /api/v3/groups to get a list of groups"""
-        response = self._get_pages("GET", [ROUTE_GROUPS], params, CBWGroup)
+        response = self._get_pages("GET", [ROUTE_GROUPS], params)
 
         return response
 
@@ -322,7 +318,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWGroup, response)
+        return self._cbw_parser(response)
 
     def create_group(self, params):
         """POST request to /api/v3/groups to create a group"""
@@ -331,7 +327,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWGroup, response)
+        return self._cbw_parser(response)
 
     def update_group(self, group_id, params=None):
         """PUT request to /api/v3/groups/<group_id> to update a group"""
@@ -340,7 +336,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWGroup, response)
+        return self._cbw_parser(response)
 
     def delete_group(self, group_id):
         """DELETE request to /api/v3/groups/<group_id> to delete a group"""
@@ -349,7 +345,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWGroup, response)
+        return self._cbw_parser(response)
 
     def test_deploy_remote_access(self, remote_access_id):
         """POST request to /api/v3/remote_accesses/:id/test_deploy to test an agentless deployment"""
@@ -357,11 +353,11 @@ class CBWApi: # pylint: disable=R0904
         if response.status_code != 200:
             logging.error("Error::{}".format(response.text))
             return None
-        return CBWParser().parse_response(CBWRemoteAccess, response)
+        return self._cbw_parser(response)
 
     def users(self, params=None):
         """GET request to /api/v3/users to get a list of users"""
-        response = self._get_pages("GET", [ROUTE_USERS], params, CBWUsers)
+        response = self._get_pages("GET", [ROUTE_USERS], params)
 
         return response
 
@@ -373,11 +369,11 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWUsers, response)
+        return self._cbw_parser(response)
 
     def nodes(self, params=None):
         """GET request to /api/v3/nodes to get a list of all nodes"""
-        response = self._get_pages("GET", [ROUTE_NODES], params, CBWNode)
+        response = self._get_pages("GET", [ROUTE_NODES], params)
 
         return response
 
@@ -388,7 +384,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWNode, response)
+        return self._cbw_parser(response)
 
     def delete_node(self, node_id, new_node_id):
         """DELETE request to /api/v3/nodes/<node_id> to delete a node and transfer the data to another one"""
@@ -397,11 +393,11 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWNode, response)
+        return self._cbw_parser(response)
 
     def hosts(self, params=None):
         """GET request to /api/v3/hosts to get a list of all hosts"""
-        response = self._get_pages("GET", [ROUTE_HOSTS], params, CBWHost)
+        response = self._get_pages("GET", [ROUTE_HOSTS], params)
 
         return response
 
@@ -412,7 +408,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWHost, response)
+        return self._cbw_parser(response)
 
     def create_host(self, params):
         """POST request to /api/v3/hosts to create a host"""
@@ -421,7 +417,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWHost, response)
+        return self._cbw_parser(response)
 
     def update_host(self, host_id, params=None):
         """PUT request to /api/v3/hosts/<host_id> to update a host"""
@@ -430,7 +426,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWHost, response)
+        return self._cbw_parser(response)
 
     def delete_host(self, host_id):
         """DELETE request to /api/v3/hosts/<host_id> to delete a host"""
@@ -439,11 +435,11 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWHost, response)
+        return self._cbw_parser(response)
 
     def security_issues(self, params=None):
         """GET request to /api/v3/security_issues to get a list of all security_issues"""
-        response = self._get_pages("GET", [ROUTE_SECURITY_ISSUES], params, CBWSecurityIssue)
+        response = self._get_pages("GET", [ROUTE_SECURITY_ISSUES], params)
 
         return response
 
@@ -454,7 +450,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWSecurityIssue, response)
+        return self._cbw_parser(response)
 
     def create_security_issue(self, params=None):
         """POST request to /api/v3/security_issues to create a security_issue"""
@@ -463,7 +459,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWSecurityIssue, response)
+        return self._cbw_parser(response)
 
     def update_security_issue(self, security_issue_id, params=None):
         """PUT request to /api/v3/security_issues/<security_issue_id> to update a security_issue"""
@@ -472,7 +468,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWSecurityIssue, response)
+        return self._cbw_parser(response)
 
     def delete_security_issue(self, security_issue_id):
         """DELETE request to /api/v3/security_issues/<security_issue_id> to delete a security_issue"""
@@ -481,7 +477,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWSecurityIssue, response)
+        return self._cbw_parser(response)
 
     def fetch_importer_scripts(self, params=None):
         """GET request to /api/v2/cbw_scans/scripts to get a list of all Importer scanning scripts"""
@@ -490,7 +486,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWImporter, response)
+        return self._cbw_parser(response)
 
     def fetch_importer_script(self, script_id):
         """GET request to /api/v2/cbw_scans/scripts/{SCRIPT_ID} to get a specific Importer scanning script"""
@@ -499,7 +495,7 @@ class CBWApi: # pylint: disable=R0904
             logging.error("Error::{}".format(response.text))
             return None
 
-        return CBWParser().parse_response(CBWImporter, response)
+        return self._cbw_parser(response)
 
     def upload_importer_results(self, content):
         """POST request to /api/v2/cbw_scans/scripts to upload scanning script result"""
diff --git a/cbw_api_toolbox/cbw_objects/__init__.py b/cbw_api_toolbox/cbw_objects/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/cbw_api_toolbox/cbw_objects/cbw_agent.py b/cbw_api_toolbox/cbw_objects/cbw_agent.py
deleted file mode 100644
index efdacc5..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_agent.py
+++ /dev/null
@@ -1,18 +0,0 @@
-""""Model Agent"""
-
-class CBWAgent:
-    """Model Agent"""
-    def __init__(self,
-                 id="", # pylint: disable=redefined-builtin
-                 server_id="", # pylint: disable=redefined-builtin
-                 node_id="",
-                 version="",
-                 remote_ip="",
-                 last_communication="",
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.server_id = server_id
-        self.node_id = node_id
-        self.version = version
-        self.remote_ip = remote_ip
-        self.last_communication = last_communication
diff --git a/cbw_api_toolbox/cbw_objects/cbw_deploying_period.py b/cbw_api_toolbox/cbw_objects/cbw_deploying_period.py
deleted file mode 100644
index 61792bd..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_deploying_period.py
+++ /dev/null
@@ -1,20 +0,0 @@
-""""Model deploying period"""
-
-
-class CBWDeployingPeriod:
-    """Model deploying period"""
-
-    def __init__(self,
-                 autoplanning=False,
-                 autoreboot=False,
-                 end_time="",
-                 name="",
-                 next_occurrence="",
-                 start_time="",
-                 **kwargs): # pylint: disable=unused-argument
-        self.autoplanning = autoplanning
-        self.autoreboot = autoreboot
-        self.end_time = end_time
-        self.name = name
-        self.next_occurrence = next_occurrence
-        self.start_time = start_time
diff --git a/cbw_api_toolbox/cbw_objects/cbw_group.py b/cbw_api_toolbox/cbw_objects/cbw_group.py
deleted file mode 100644
index 36aea86..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_group.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""Group Model"""
-
-
-class CBWGroup:
-    """Group Model"""
-
-    def __init__(self,
-                 id="",  # pylint: disable=redefined-builtin
-                 color="",
-                 name="",
-                 description="",
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.color = color
-        self.name = name
-        self.description = description
diff --git a/cbw_api_toolbox/cbw_objects/cbw_host.py b/cbw_api_toolbox/cbw_objects/cbw_host.py
deleted file mode 100644
index b7d5ba9..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_host.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""Host Model"""
-
-from cbw_api_toolbox.cbw_objects.cbw_package import CBWPackage
-from cbw_api_toolbox.cbw_objects.cbw_server import CBWCve
-from cbw_api_toolbox.cbw_parser import CBWParser
-
-class CBWHost:
-    """Host Model"""
-
-    def __init__(self,
-                 id,  # pylint: disable=redefined-builtin
-                 target="",
-                 hostname="",
-                 category="",
-                 created_at="",
-                 updated_at="",
-                 cve_announcements_count="",
-                 node_id="",
-                 server_id="",
-                 status="",
-                 technologies=None,
-                 security_issues=None,
-                 cve_announcements=None,
-                 scans=None,
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id # pylint: disable=invalid-name
-        self.target = target
-        self.hostname = hostname
-        self.category = category
-        self.created_at = created_at
-        self.updated_at = updated_at
-        self.cve_announcements_count = cve_announcements_count
-        self.node_id = node_id
-        self.server_id = server_id
-        self.status = status
-        self.technologies = [CBWParser().parse(CBWPackage, technology) for technology in
-                             technologies] if technologies else []
-        self.security_issues = security_issues
-        self.cve_announcements = [CBWParser().parse(CBWCve, cve) for cve in
-                                  cve_announcements] if cve_announcements else []
-        self.scans = scans
diff --git a/cbw_api_toolbox/cbw_objects/cbw_ignoring_policy.py b/cbw_api_toolbox/cbw_objects/cbw_ignoring_policy.py
deleted file mode 100644
index 12294e8..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_ignoring_policy.py
+++ /dev/null
@@ -1,18 +0,0 @@
-""""Model ignoring policy"""
-
-from cbw_api_toolbox.cbw_parser import CBWParser
-from cbw_api_toolbox.cbw_objects.cbw_ignoring_policy_items import CBWIgnoringPolicyItems
-
-
-class CBWIgnoringPolicy:
-    """Model ignoring policy"""
-
-    def __init__(self,
-                 ignoring_policy_items=None,
-                 name="",
-                 **kwargs): # pylint: disable=unused-argument
-        self.ignoring_policy_items = ([CBWParser().parse(CBWIgnoringPolicyItems,
-                                                         ignoring_policy_item) for
-                                       ignoring_policy_item in ignoring_policy_items] if
-                                      ignoring_policy_items else [])
-        self.name = name
diff --git a/cbw_api_toolbox/cbw_objects/cbw_ignoring_policy_items.py b/cbw_api_toolbox/cbw_objects/cbw_ignoring_policy_items.py
deleted file mode 100644
index 25ecd10..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_ignoring_policy_items.py
+++ /dev/null
@@ -1,12 +0,0 @@
-""""Model ignoring policy items"""
-
-
-class CBWIgnoringPolicyItems:
-    """Model ignoring policy items"""
-
-    def __init__(self,
-                 keyword="",
-                 version="",
-                 **kwargs):  # pylint: disable=unused-argument
-        self.keyword = keyword
-        self.version = version
diff --git a/cbw_api_toolbox/cbw_objects/cbw_importer.py b/cbw_api_toolbox/cbw_objects/cbw_importer.py
deleted file mode 100644
index e5ee5c0..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_importer.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""CBWImporter Model"""
-
-
-class CBWImporter:
-    """CBWImporter Model"""
-
-    def __init__(self,
-                 id="",  # pylint: disable=redefined-builtin
-                 type="", # pylint: disable=redefined-builtin
-                 contents="",
-                 attachment="",
-                 **kwargs):  # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.type = type
-        self.contents = contents
-        self.attachment = attachment
diff --git a/cbw_api_toolbox/cbw_objects/cbw_node.py b/cbw_api_toolbox/cbw_objects/cbw_node.py
deleted file mode 100644
index 9df11d8..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_node.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""Node Model"""
-
-
-class CBWNode:
-    """Node Model"""
-
-    def __init__(self,
-                 id="",  # pylint: disable=redefined-builtin
-                 name="",
-                 updated_at="",
-                 created_at="",
-                 **kwargs):  # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.name = name
-        self.created_at = created_at
-        self.updated_at = updated_at
diff --git a/cbw_api_toolbox/cbw_objects/cbw_package.py b/cbw_api_toolbox/cbw_objects/cbw_package.py
deleted file mode 100644
index 385a5dc..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_package.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Package/Application Model"""
-
-
-class CBWPackage:
-    """Package/Application Model"""
-
-    def __init__(self,
-                 hash_index="",
-                 product="",
-                 type="",  # pylint: disable=redefined-builtin
-                 vendor="",
-                 version="",
-                 **kwargs): # pylint: disable=unused-argument
-        self.hash_index = hash_index
-        self.product = product
-        self.package_type = type
-        self.vendor = vendor
-        self.version = version
diff --git a/cbw_api_toolbox/cbw_objects/cbw_remote_access.py b/cbw_api_toolbox/cbw_objects/cbw_remote_access.py
deleted file mode 100644
index ab5e8aa..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_remote_access.py
+++ /dev/null
@@ -1,23 +0,0 @@
-""""Model Remote access"""
-
-class CBWRemoteAccess:
-    """Model Remote access"""
-    def __init__(self,
-                 id="", # pylint: disable=redefined-builtin
-                 type="", # pylint: disable=redefined-builtin
-                 node_id="",
-                 address="",
-                 port="",
-                 is_valid="",
-                 last_error="",
-                 server_id="",
-                 server_groups="",
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.type = type
-        self.node_id = node_id
-        self.address = address
-        self.port = port
-        self.is_valid = is_valid
-        self.last_error = last_error
-        self.server_id = server_id
diff --git a/cbw_api_toolbox/cbw_objects/cbw_security_issue.py b/cbw_api_toolbox/cbw_objects/cbw_security_issue.py
deleted file mode 100644
index 0c70074..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_security_issue.py
+++ /dev/null
@@ -1,25 +0,0 @@
-"""Security issues Model"""
-
-class CBWSecurityIssue:
-    """Security issues Model"""
-
-    def __init__(self,
-                 sid="",
-                 cve_announcements=None,
-                 level="",
-                 id="", # pylint: disable=redefined-builtin
-                 description="",
-                 score="",
-                 title="",
-                 type="", # pylint: disable=redefined-builtin
-                 servers=None,
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id # pylint: disable=redefined-builtin, C0103
-        self.sid = sid
-        self.cve_announcements = cve_announcements if cve_announcements else []
-        self.level = level
-        self.description = description
-        self.title = title
-        self.type = type
-        self.score = score
-        self.servers = servers
diff --git a/cbw_api_toolbox/cbw_objects/cbw_server.py b/cbw_api_toolbox/cbw_objects/cbw_server.py
deleted file mode 100644
index 7331839..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_server.py
+++ /dev/null
@@ -1,106 +0,0 @@
-"""CVE Model & Server Model"""
-
-from cbw_api_toolbox.cbw_objects.cbw_deploying_period import CBWDeployingPeriod
-from cbw_api_toolbox.cbw_objects.cbw_group import CBWGroup
-from cbw_api_toolbox.cbw_objects.cbw_ignoring_policy import CBWIgnoringPolicy
-from cbw_api_toolbox.cbw_objects.cbw_package import CBWPackage
-from cbw_api_toolbox.cbw_parser import CBWParser
-
-
-class CBWCve:
-    """CVE Model"""
-
-    def __init__(self,
-                 content="",
-                 created_at="",
-                 cve_code="",
-                 cvss="",
-                 cvss_v3="",
-                 cvss_custom="",
-                 level="",
-                 score="",
-                 score_v2="",
-                 score_v3="",
-                 score_custom="",
-                 last_modified="",
-                 published="",
-                 updated_at="",
-                 exploit_code_maturity="",
-                 servers=None,
-                 **kwargs): # pylint: disable=unused-argument
-        self.content = content
-        self.created_at = created_at
-        self.cve_code = cve_code
-        self.cvss_v2 = cvss
-        self.cvss_v3 = cvss_v3
-        self.cvss_custom = cvss_custom
-        self.score = score
-        self.score_v2 = score_v2
-        self.score_v3 = score_v3
-        self.score_custom = score_custom
-        self.level = level
-        self.last_modified = last_modified
-        self.published = published
-        self.updated_at = updated_at
-        self.exploit_code_maturity = exploit_code_maturity
-        self.servers = [{"server": CBWParser().parse(CBWServer, server),
-                         "active": server["active"], "ignored": server["ignored"],
-                         "comment": server["comment"], "fixed_at": server["fixed_at"]}
-                        for server in servers] if servers else []
-
-class CBWServer:
-    """Model Server"""
-
-    def __init__(self,
-                 id,  # pylint: disable=redefined-builtin
-                 applications=None,
-                 boot_at="",
-                 category="",
-                 compliance_groups=None,
-                 created_at="",
-                 environment=None,
-                 cve_announcements=None,
-                 cve_announcements_count=0,
-                 deploying_period=None,
-                 description="",
-                 groups=None,
-                 hostname="",
-                 ignoring_policy=None,
-                 last_communication="",
-                 os=None,
-                 packages=None,
-                 reboot_required=False,
-                 remote_ip="",
-                 security_announcements=None,
-                 status=None,
-                 updates=None,
-                 updates_count=0,
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.applications = [CBWParser().parse(CBWPackage, application) for application in
-                             applications] if applications else []
-        self.boot_at = boot_at
-        self.category = category
-        self.compliance_groups = [CBWParser().parse(CBWGroup, group) for group in
-                                  compliance_groups] if compliance_groups else []
-        self.created_at = created_at
-        self.environment = environment
-        self.cve_announcements = cve_announcements
-        self.cve_announcements_count = cve_announcements_count
-        self.deploying_period = (CBWParser().parse(CBWDeployingPeriod, deploying_period) if
-                                 deploying_period else None)
-        self.description = description
-        self.groups = [CBWParser().parse(CBWGroup, group) for group in groups] if groups else []
-        self.hostname = hostname
-        self.ignoring_policy = (CBWParser().parse(CBWIgnoringPolicy, ignoring_policy) if
-                                ignoring_policy else None)
-        self.last_communication = last_communication
-        self.os = os  # pylint: disable=invalid-name
-        self.packages = [CBWParser().parse(CBWPackage, package) for package in
-                         packages] if packages else []
-        self.reboot_required = reboot_required
-        self.remote_ip = remote_ip
-        self.security_announcements = security_announcements
-        self.status = status
-        self.updates = updates
-        self.updates_count = updates_count
diff --git a/cbw_api_toolbox/cbw_objects/cbw_user_server_groups.py b/cbw_api_toolbox/cbw_objects/cbw_user_server_groups.py
deleted file mode 100644
index c272af8..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_user_server_groups.py
+++ /dev/null
@@ -1,13 +0,0 @@
-"""User Server Groups Model"""
-
-class CBWUserServerGroups:
-    """User Server Groups Model"""
-
-    def __init__(self,
-                 id="",  # pylint: disable=redefined-builtin
-                 name="",
-                 role="",
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.name = name
-        self.role = role
diff --git a/cbw_api_toolbox/cbw_objects/cbw_users.py b/cbw_api_toolbox/cbw_objects/cbw_users.py
deleted file mode 100644
index e91b687..0000000
--- a/cbw_api_toolbox/cbw_objects/cbw_users.py
+++ /dev/null
@@ -1,26 +0,0 @@
-"""Users Model"""
-
-from cbw_api_toolbox.cbw_parser import CBWParser
-from cbw_api_toolbox.cbw_objects.cbw_user_server_groups import CBWUserServerGroups
-
-class CBWUsers:
-    """Users Model"""
-
-    def __init__(self,
-                 id="",  # pylint: disable=redefined-builtin
-                 login="",
-                 name="",
-                 firstname="",
-                 email="",
-                 auth_provider="",
-                 locale="",
-                 server_groups=None,
-                 **kwargs): # pylint: disable=unused-argument
-        self.id = id  # pylint: disable=invalid-name
-        self.login = login
-        self.name = name
-        self.firstname = firstname
-        self.email = email
-        self.auth_provider = auth_provider
-        self.locale = locale
-        self.server_groups = CBWParser().parse(CBWUserServerGroups, server_groups[0]) if server_groups else []
diff --git a/cbw_api_toolbox/cbw_parser.py b/cbw_api_toolbox/cbw_parser.py
deleted file mode 100644
index 4988ccc..0000000
--- a/cbw_api_toolbox/cbw_parser.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""CbwParser Module"""
-
-import logging
-import json
-from json import JSONDecodeError
-
-
-class CBWParser:
-    """CBWParser class"""
-
-    def __init__(self):
-        self.logger = logging.getLogger(self.__class__.__name__)
-
-    def parse_response(self, parsed_class, response):
-        """Parse the response text of an API request"""
-        try:
-            result = []
-            parsed_response = json.loads(response.text)
-
-            if isinstance(parsed_response, list):
-                for class_dict in parsed_response:
-                    result.append(self.parse(parsed_class, class_dict))
-            else:
-                result = self.parse(parsed_class, parsed_response)
-
-            return result
-
-        except JSONDecodeError:
-            self.logger.exception("An error occurred when decoding {0}".format(response.text))
-
-    def parse(self, parsed_class, class_dict):
-        """Parse the API Json into class_dict"""
-        try:
-            self.logger.debug("Parsing {0} ...".format(class_dict))
-            return parsed_class(**class_dict)
-
-        except JSONDecodeError:
-            self.logger.exception("An error occurred when parsing {0} with {1}".
-                                  format(parsed_class, class_dict))
-
-        except TypeError:
-            self.logger.exception("An error occurred when parsing {0} with {1}".
-                                  format(parsed_class, class_dict))
diff --git a/documentation.md b/documentation.md
index ad73b73..5aa3477 100644
--- a/documentation.md
+++ b/documentation.md
@@ -22,7 +22,7 @@ Send a GET request to `/api/v3/servers` to retrieve the list of all servers.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).servers()
-[<cbw_api_toolbox.cbw_objects.cbw_server.CBWServer ...]
+[cbw_object(...), ...]
 ```
 
 #### Server
@@ -33,7 +33,7 @@ Send a GET request to `/api/v3/servers/{SERVER_ID}` to retrieve the information
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).server(SERVER_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_server.CBWServer]
+[cbw_object(...), ...]
 ```
 
 #### Update server
@@ -66,7 +66,7 @@ Send a GET request `/api/v3/agents` to retrieve the list of all agents.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).agents()
-[<cbw_api_toolbox.cbw_objects.cbw_agent.CBWAgent...]
+[cbw_object(...), ...]
 ```
 
 #### Agents
@@ -77,7 +77,7 @@ Send a GET request `/api/v3/agents/{AGENT_ID}` to retrieve the information of a
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).agent(AGENT_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_agent.CBWAgent]
+[cbw_object(...), ...]
 ```
 
 #### Delete agent
@@ -99,7 +99,7 @@ Send a GET request `/api/v3/remote_accesses` to retrieve the list of all remote
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).remote_accesses()
-[<cbw_api_toolbox.cbw_objects.cbw_remote_access.CBWRemoteAccess...]
+[cbw_object(...), ...]
 ```
 
 #### Remote access
@@ -110,7 +110,7 @@ Send a GET request `/api/v3/remote_accesses/{REMOTE_ACCESS_ID}` to retrieve the
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).remote_access(REMOTE_ACCESS_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_remote_access.CBWRemoteAccess]
+[cbw_object(...), ...]
 ```
 
 #### Create remote access
@@ -155,7 +155,7 @@ Send a POST request `/api/v3/remote_accesses/{REMOTE_ACCESS_ID}/test_deploy` to
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).test_deploy_remote_access(REMOTE_ACCESS_ID)
-<cbw_api_toolbox.cbw_objects.cbw_remote_access.CBWRemoteAccess>
+<cbw_object(...)>
 ```
 
 #### CVE Announcement
@@ -166,7 +166,7 @@ Send a GET request to `/api/v2/cve_announcements/{CVE_CODE}` to get all informat
 
 ```python
 >>> CBWApi(API_URL, API_KEY, SECRET_KEY).cve_announcement(CVE_CODE)
-[<cbw_api_toolbox.cbw_objects.cbw_cve.CBWCve]
+[cbw_object(...), ...]
 ```
 
 #### Groups
@@ -177,7 +177,7 @@ Send a GET request to `/api/v3/groups` to get informations about all groups
 
 ```python
 >>> CBWApi(API_URL, API_KEY, SECRET_KEY).groups()
-[<cbw_api_toolbox.cbw_objects.cbw_group.CBWGroup]
+[cbw_object(...), ...]
 ```
 
 #### Group
@@ -188,7 +188,7 @@ Send a GET request `/api/v3/groups/{GROUP_ID}` to retrieve the information of a
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).group(GROUP_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_group.CBWGroup]
+[cbw_object(...), ...]
 ```
 
 #### Create group
@@ -199,7 +199,7 @@ Send a POST request `/api/v3/groups` to create a group.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).create_group(INFO)
-[<cbw_api_toolbox.cbw_objects.cbw_group.CBWGroup]
+[cbw_object(...), ...]
 ```
 
 #### Update group
@@ -210,7 +210,7 @@ Send a PUT request `/api/v3/groups/{GROUP_ID}` to update the information of a pa
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).update_group(GROUP_ID, INFO)
-[<cbw_api_toolbox.cbw_objects.cbw_group.CBWGroup]
+[cbw_object(...), ...]
 ```
 
 #### Delete group
@@ -219,7 +219,7 @@ Send a DELETE request `/api/v3/groups/{GROUP_ID}` to delete a group.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).delete_group(GROUP_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_group.CBWGroup]
+[cbw_object(...), ...]
 ```
 
 #### User
@@ -230,7 +230,7 @@ Send a GET request to `/api/v3/users/<id>` to get informations about a specific
 
 ```python
 >>> CBWApi(API_URL, API_KEY, SECRET_KEY).users(USER_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_group.CBWUsers]
+[cbw_object(...), ...]
 ```
 
 #### Users
@@ -241,7 +241,7 @@ Send a GET request to `/api/v3/users` to get informations about all users
 
 ```python
 >>> CBWApi(API_URL, API_KEY, SECRET_KEY).users()
-[<cbw_api_toolbox.cbw_objects.cbw_group.CBWUsers]
+[cbw_object(...), ...]
 ```
 
 #### Nodes
@@ -252,7 +252,7 @@ Send a GET request to `/api/v3/nodes` to retrieve a list of all nodes.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).nodes()
-[<cbw_api_toolbox.cbw_objects.cbw_node.CBWNode ...]
+[cbw_object(...), ...]
 ```
 
 #### Node
@@ -263,7 +263,7 @@ Send a GET request to `/api/v3/nodes/{NODE_ID}` to retrieve the information of a
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).node(NODE_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_node.CBWNode]
+[cbw_object(...), ...]
 ```
 
 #### Delete Node
@@ -274,7 +274,7 @@ Send a DELETE request to `/api/v3/nodes/{NODE_ID}` to delete a node and transfer
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).node(NODE_ID, NEW_NODE_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_node.CBWNode]
+[cbw_object(...), ...]
 ```
 
 #### Host
@@ -285,7 +285,7 @@ Send a GET request `/api/v3/hosts/{HOST_ID}` to retrieve the information of a pa
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).host(HOST_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_host.CBWHost]
+[cbw_object(...), ...]
 ```
 
 #### Hosts
@@ -296,7 +296,7 @@ Send a GET request `/api/v3/hosts` to retrieve all the hosts.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).hosts()
-[<cbw_api_toolbox.cbw_objects.cbw_host.CBWHost]...]
+[cbw_object(...), ...]
 ```
 
 #### Create host
@@ -307,7 +307,7 @@ Send a POST request `/api/v3/hosts` to create a host.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).create_host(INFO)
-[<cbw_api_toolbox.cbw_objects.cbw_host.CBWHost]
+[cbw_object(...), ...]
 ```
 
 #### Update host
@@ -318,7 +318,7 @@ Send a PUT request `/api/v3/hosts/{HOST_ID}` to update the information of a part
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).update_host(HOST_ID, INFO)
-[<cbw_api_toolbox.cbw_objects.cbw_host.CBWHost]
+[cbw_object(...), ...]
 ```
 
 #### Delete host
@@ -327,7 +327,7 @@ Send a DELETE request `/api/v3/hosts/{HOST_ID}` to delete a host.
 
 ```python
 >>> CBWApi(URL, API_KEY, SECRET_KEY).delete_host(HOST_ID)
-[<cbw_api_toolbox.cbw_objects.cbw_host.CBWHost]
+[cbw_object(...), ...]
 ```
 
 ## Available objects and their attributes
@@ -534,7 +534,7 @@ Send a DELETE request `/api/v3/hosts/{HOST_ID}` to delete a host.
 | availability_impact       | String        | Impact on availability of CVE     | "availability_impact_none"                        |
 | confidentiality_impact    | String        | Impact on confidientiality of CVE | "confidentiality_impact_none"                     |
 | integrity_impact          | String        | Impact on integrity of CVE        | "integrity_impact_high"                           |
-| privilege_required        | String        | Privilege level required for CVE  | "privilege_required_none"                         |
+| privileges_required       | String        | Privilege level required for CVE  | "privileges_required_none"                         |
 | scope                     | String        | Scope of the CVE                  | "scope_unchanged"                                 |
 | user_interaction          | String        | User interaction level for CVE    | "user_interaction_none"                           |
 
diff --git a/examples/affect_group_os.py b/examples/affect_group_os.py
index d096f1f..75cd3b9 100644
--- a/examples/affect_group_os.py
+++ b/examples/affect_group_os.py
@@ -13,6 +13,11 @@ LINUX_OS = ['Amazon', 'ArchLinux', 'Centos', 'Debian', 'Manjaro', 'Oracle', 'Ubu
 WINDOWS_OS = ['Windows']
 MAC_OS = ['Macos']
 
+LINUX_GROUP_ID = ''
+MAC_GROUP_ID = ''
+WINDOWS_GROUP_ID = ''
+OTHER_GROUP_ID = ''
+
 
 def build_groups_list(server_id, system_os):
     """Create list with system_os + other groups of server"""
@@ -25,13 +30,13 @@ def build_groups_list(server_id, system_os):
 
 for server_item in CLIENT.servers():
     if server_item.os is not None:
-        if server_item.os["type"][4:] in LINUX_OS:
-            OS = "LINUX"
-        elif server_item.os["type"][4:] in WINDOWS_OS:
-            OS = "WIN"
-        elif server_item.os["type"][4:] in MAC_OS:
-            OS = "MAC_OS"
+        if server_item.os.type[4:] in LINUX_OS:
+            GROUP_ID = LINUX_GROUP_ID
+        elif server_item.os.type[4:] in WINDOWS_OS:
+            GROUP_ID = WINDOWS_GROUP_ID
+        elif server_item.os.type[4:] in MAC_OS:
+            GROUP_ID = MAC_GROUP_ID
         else:
-            OS = "Other"
-    groups_list = build_groups_list(server_item.id, OS)
-    CLIENT.update_server(str(server_item.id), {'groups': ",".join(groups_list)})
+            GROUP_ID = OTHER_GROUP_ID
+
+    CLIENT.update_server(str(server_item.id), {'groups': [GROUP_ID]})
diff --git a/examples/cleanup_initialization_duplicates.py b/examples/cleanup_initialization_duplicates.py
index 933b167..5711dd0 100644
--- a/examples/cleanup_initialization_duplicates.py
+++ b/examples/cleanup_initialization_duplicates.py
@@ -116,7 +116,7 @@ def display_and_delete(delete_list, what, delete=False):
                     delete_server.cve_announcements_count, delete_server.created_at))
 
         if delete is True:
-            API.delete_server(delete_server.id)
+            API.delete_server(str(delete_server.id))
 
 def launch_script(parsed_args):
     '''Launch script'''
diff --git a/examples/cve_published_last_month_export_xlsx.py b/examples/cve_published_last_month_export_xlsx.py
index 8382734..e5e9aab 100644
--- a/examples/cve_published_last_month_export_xlsx.py
+++ b/examples/cve_published_last_month_export_xlsx.py
@@ -36,11 +36,11 @@ def get_updates(server):
     targeted_technology = ""
     targeted_version = ""
 
-    for update in server["server"].updates:
-        if(update["target"] is not None and update["target"]["product"] is not None
-           and update["target"]["version"] is not None):
-            targeted_technology = update["target"]["product"]
-            targeted_version = update["target"]["version"]
+    for update in server.updates:
+        if(update.target is not None and update.target.product is not None
+           and update.target.version is not None):
+            targeted_technology = update.target.product
+            targeted_version = update.target.version
             break
     return targeted_technology, targeted_version
 
@@ -88,7 +88,7 @@ def export_xls(cve_list, xls_export):
 
             for server in cve.servers:
                 # Skip if the CVE is not active on the server
-                if server["active"] is not True:
+                if server.active is not True:
                     count_fixed_computers += 1
                     continue
                 count_affected_computers += 1
@@ -98,7 +98,7 @@ def export_xls(cve_list, xls_export):
                 tab_computer_cve.write(row_computer_cve, 1, cve.score_v3)
                 tab_computer_cve.write(row_computer_cve, 2, cve.score_v2)
                 tab_computer_cve.write(row_computer_cve, 3, cve.exploit_code_maturity)
-                tab_computer_cve.write(row_computer_cve, 4, server["server"].hostname)
+                tab_computer_cve.write(row_computer_cve, 4, server.hostname)
                 tab_computer_cve.write(row_computer_cve, 5, targeted_technology)
                 tab_computer_cve.write(row_computer_cve, 6, targeted_version)
                 tab_computer_cve.write(row_computer_cve, 7, cve.published)
diff --git a/examples/recovered_servers_script/communication_failure_recovered.py b/examples/recovered_servers_script/communication_failure_recovered.py
index c4d53f6..0eef7f3 100644
--- a/examples/recovered_servers_script/communication_failure_recovered.py
+++ b/examples/recovered_servers_script/communication_failure_recovered.py
@@ -87,7 +87,7 @@ def build_server_list(client, diff):
     print("INFO: Fetching each server not in 'Communication failure' anymore...")
     servers = []
     for server in diff:
-        servers.append(client.server(str(server["id"])))
+        servers.append(client.server(str(server.id)))
     return servers
 
 
diff --git a/examples/servers_applications_export.py b/examples/servers_applications_export.py
deleted file mode 100644
index cf6ae28..0000000
--- a/examples/servers_applications_export.py
+++ /dev/null
@@ -1,37 +0,0 @@
-"""Example: Export the applications for each servers"""
-
-import os
-from configparser import ConfigParser
-import xlsxwriter  # pylint: disable=import-error
-from cbw_api_toolbox.cbw_api import CBWApi
-
-CONF = ConfigParser()
-CONF.read(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', 'api.conf'))
-CLIENT = CBWApi(CONF.get('cyberwatch', 'url'), CONF.get('cyberwatch', 'api_key'), CONF.get('cyberwatch', 'secret_key'))
-
-CLIENT.ping()
-
-SERVERS = CLIENT.servers()
-
-EXPORTED = xlsxwriter.Workbook('cbw_export_servers_applications.xlsx')
-
-for server in SERVERS:
-    server = CLIENT.server(str(server.id))
-
-    if server and server.applications:
-        print("Export applications for {0}".format(server.hostname))
-
-        worksheet = EXPORTED.add_worksheet(server.hostname)
-
-        worksheet.write(0, 0, "Application")
-        worksheet.write(0, 1, "Version")
-
-        ROW = 1
-        COL = 0
-
-        for application in server.applications:
-            worksheet.write(ROW, COL, application.product)
-            worksheet.write(ROW, COL + 1, application.version)
-            Row += 1
-
-EXPORTED.close()
diff --git a/examples/servers_detail_export_xlsx.py b/examples/servers_detail_export_xlsx.py
index 89a5e8c..9e499b0 100644
--- a/examples/servers_detail_export_xlsx.py
+++ b/examples/servers_detail_export_xlsx.py
@@ -24,7 +24,7 @@ RECOMMENDED = EXPORTED.add_worksheet("Recommended Actions")
 # Build a list with each server and it's details
 SERVERS_LIST = []
 for server in SERVERS:
-    server = CLIENT.server(server.id)
+    server = CLIENT.server(str(server.id))
     SERVERS_LIST.append(server)
 
 ROW = 0
@@ -35,7 +35,7 @@ for server in SERVERS_LIST:
     COMPUTER.write(ROW + 1, COL, server.hostname)
 
     COMPUTER.write(ROW, COL + 1, "OS")
-    COMPUTER.write(ROW + 1, COL + 1, server.os["name"])
+    COMPUTER.write(ROW + 1, COL + 1, server.os.name)
 
     COMPUTER.write(ROW, COL + 2, "Groups")
     if server.groups:
@@ -46,10 +46,10 @@ for server in SERVERS_LIST:
         COMPUTER.write(ROW + 1, COL + 2, GROUPE_NAME)
 
     COMPUTER.write(ROW, COL + 3, "Status")
-    COMPUTER.write(ROW + 1, COL + 3, server.status["comment"])
+    COMPUTER.write(ROW + 1, COL + 3, server.status)
 
-    COMPUTER.write(ROW, COL + 4, "Criticality")
-    COMPUTER.write(ROW + 1, COL + 4, server.criticality)
+    COMPUTER.write(ROW, COL + 4, "Environment")
+    COMPUTER.write(ROW + 1, COL + 4, server.environment.name)
 
     COMPUTER.write(ROW, COL + 5, "Category")
     COMPUTER.write(ROW + 1, COL + 5, server.category)
@@ -91,24 +91,23 @@ for server in SERVERS_LIST:
         VULNERABILITIES.write(ROW + 1, COL + 2, cve.score_v2)
         VULNERABILITIES.write(ROW + 1, COL + 3, cve.exploit_code_maturity)
         VULNERABILITIES.write(ROW + 1, COL + 4, cve.content)
-
-        if cve.cvss_v2 is not None:
-            VULNERABILITIES.write(ROW + 1, COL + 5, cve.cvss_v2["access_vector"])
-            VULNERABILITIES.write(ROW + 1, COL + 6, cve.cvss_v2["access_complexity"])
-            VULNERABILITIES.write(ROW + 1, COL + 7, cve.cvss_v2["authentication"])
-            VULNERABILITIES.write(ROW + 1, COL + 8, cve.cvss_v2["availability_impact"])
-            VULNERABILITIES.write(ROW + 1, COL + 9, cve.cvss_v2["confidentiality_impact"])
-            VULNERABILITIES.write(ROW + 1, COL + 10, cve.cvss_v2["integrity_impact"])
+        if cve.cvss is not None:
+            VULNERABILITIES.write(ROW + 1, COL + 5, cve.cvss.access_vector)
+            VULNERABILITIES.write(ROW + 1, COL + 6, cve.cvss.access_complexity)
+            VULNERABILITIES.write(ROW + 1, COL + 7, cve.cvss.authentication)
+            VULNERABILITIES.write(ROW + 1, COL + 8, cve.cvss.availability_impact)
+            VULNERABILITIES.write(ROW + 1, COL + 9, cve.cvss.confidentiality_impact)
+            VULNERABILITIES.write(ROW + 1, COL + 10, cve.cvss.integrity_impact)
 
         if cve.cvss_v3 is not None:
-            VULNERABILITIES.write(ROW + 1, COL + 11, cve.cvss_v3["access_vector"])
-            VULNERABILITIES.write(ROW + 1, COL + 12, cve.cvss_v3["access_complexity"])
-            VULNERABILITIES.write(ROW + 1, COL + 13, cve.cvss_v3["privilege_required"])
-            VULNERABILITIES.write(ROW + 1, COL + 14, cve.cvss_v3["user_interaction"])
-            VULNERABILITIES.write(ROW + 1, COL + 15, cve.cvss_v3["integrity_impact"])
-            VULNERABILITIES.write(ROW + 1, COL + 16, cve.cvss_v3["availability_impact"])
-            VULNERABILITIES.write(ROW + 1, COL + 17, cve.cvss_v3["confidentiality_impact"])
-            VULNERABILITIES.write(ROW + 1, COL + 18, cve.cvss_v3["scope"])
+            VULNERABILITIES.write(ROW + 1, COL + 11, cve.cvss_v3.access_vector)
+            VULNERABILITIES.write(ROW + 1, COL + 12, cve.cvss_v3.access_complexity)
+            VULNERABILITIES.write(ROW + 1, COL + 13, cve.cvss_v3.privileges_required)
+            VULNERABILITIES.write(ROW + 1, COL + 14, cve.cvss_v3.user_interaction)
+            VULNERABILITIES.write(ROW + 1, COL + 15, cve.cvss_v3.integrity_impact)
+            VULNERABILITIES.write(ROW + 1, COL + 16, cve.cvss_v3.availability_impact)
+            VULNERABILITIES.write(ROW + 1, COL + 17, cve.cvss_v3.confidentiality_impact)
+            VULNERABILITIES.write(ROW + 1, COL + 18, cve.cvss_v3.scope)
 
         ROW += 1
     ROW += 2
@@ -127,13 +126,13 @@ for server in SERVERS_LIST:
     SECURITY.write(ROW, COL + 4, "Updated date")
 
     for security_announcement in server.security_announcements:
-        SECURITY.write(ROW + 1, COL, security_announcement["sa_code"])
-        SECURITY.write(ROW + 1, COL + 2, security_announcement["link"])
-        SECURITY.write(ROW + 1, COL + 3, security_announcement["created_at"])
-        SECURITY.write(ROW + 1, COL + 4, security_announcement["updated_at"])
+        SECURITY.write(ROW + 1, COL, security_announcement.sa_code)
+        SECURITY.write(ROW + 1, COL + 2, security_announcement.link)
+        SECURITY.write(ROW + 1, COL + 3, security_announcement.created_at)
+        SECURITY.write(ROW + 1, COL + 4, security_announcement.updated_at)
 
-        for cve in security_announcement["cve_announcements"]:
-            CVE_CODE_LIST += cve["cve_code"] + ", "
+        for cve in security_announcement.cve_announcements:
+            CVE_CODE_LIST += cve.cve_code + ", "
         CVE_CODE_LIST = CVE_CODE_LIST[:-1]
         SECURITY.write(ROW + 1, COL + 1, CVE_CODE_LIST)
 
@@ -154,14 +153,14 @@ for server in SERVERS_LIST:
     RECOMMENDED.write(ROW, COL + 4, "Target version")
 
     for update in server.updates:
-        for cve in update["cve_announcements"]:
-            CVE_CODE_LIST += cve["cve_code"] + ", "
+        for cve in update.cve_announcements:
+            CVE_CODE_LIST += cve.cve_code + ", "
         CVE_CODE_LIST = CVE_CODE_LIST[:-1]
-        RECOMMENDED.write(ROW + 1, COL, update["current"]["product"])
+        RECOMMENDED.write(ROW + 1, COL, update.current.product)
         RECOMMENDED.write(ROW + 1, COL + 1, CVE_CODE_LIST)
-        RECOMMENDED.write(ROW + 1, COL + 2, update["patchable"])
-        RECOMMENDED.write(ROW + 1, COL + 3, update["current"]["version"])
-        RECOMMENDED.write(ROW + 1, COL + 4, update["target"]["version"])
+        RECOMMENDED.write(ROW + 1, COL + 2, update.patchable)
+        RECOMMENDED.write(ROW + 1, COL + 3, update.current.version)
+        RECOMMENDED.write(ROW + 1, COL + 4, update.target.version)
 
         ROW += 1
     ROW += 2
diff --git a/examples/view_dashboard_indicator.py b/examples/view_dashboard_indicator.py
index 448ba50..19680ac 100644
--- a/examples/view_dashboard_indicator.py
+++ b/examples/view_dashboard_indicator.py
@@ -23,12 +23,12 @@ def cve_lists(server_list):
     for server in servers:
         server_show = CLIENT.server(str(server.id))
         for cve in server_show.cve_announcements:
-            if not(cve['ignored']) and cve['fixed_at'] is None:
+            if not(cve.ignored) and cve.fixed_at is None:
                 cve_details = next((cve_exploitable for cve_exploitable in
-                                    cves if cve_exploitable.cve_code == cve['cve_code']), None)
+                                    cves if cve_exploitable.cve_code == cve.cve_code), None)
 
                 if cve_details is not None and cve_details.cvss_v3 is not None:
-                    server_cves[cve_details.cvss_v3['access_vector']] += 1
+                    server_cves[cve_details.cvss_v3.access_vector] += 1
     return server_cves
 
 def server_outdated_system(servers):
diff --git a/examples/view_server_patch.py b/examples/view_server_patch.py
index 3f6006f..53c8038 100644
--- a/examples/view_server_patch.py
+++ b/examples/view_server_patch.py
@@ -10,19 +10,19 @@ CLIENT = CBWApi(CONF.get('cyberwatch', 'url'), CONF.get('cyberwatch', 'api_key')
 
 SERVER_ID = ""  # add the server id
 
-SERVER = CLIENT.server(SERVER_ID)
+SERVER = CLIENT.server(str(SERVER_ID))
 
 print("Server : {}".format(SERVER.hostname))
 print("Update count : {}".format(SERVER.updates_count))
 
 print("Updates :")
 for update in SERVER.updates:
-    print("\t-Product : {}".format(update["current"]["product"]))
-    print("\t\t- Corrective action : {0} -> {1}".format(update["current"]["version"],
-                                                        update["target"]["version"]))
+    print("\t-Product : {}".format(update.current.product))
+    print("\t\t- Corrective action : {0} -> {1}".format(update.current.version,
+                                                        update.target.version))
 
     cve_list = []
-    for cve in update["cve_announcements"]:
-        cve_list.append(cve["cve_code"])
+    for cve in update.cve_announcements:
+        cve_list.append(cve)
 
     print("\t\t- Cve List : {}".format(", ".join(cve_list)))
diff --git a/setup.py b/setup.py
index d4be8ee..03e67d4 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ setup(
     description='CyberWatch Api Tools.',
     long_description=open('README.md').read().strip(),
     long_description_content_type="text/markdown",
-    version='1.1.2',
+    version='2.0.0',
     author='CyberWatch SAS',
     author_email='support-it+api@cyberwatch.fr',
     license='MIT',
diff --git a/spec/fixtures/vcr_cassettes/delete_host.yaml b/spec/fixtures/vcr_cassettes/delete_host.yaml
index 55d6a4a..240b8b7 100644
--- a/spec/fixtures/vcr_cassettes/delete_host.yaml
+++ b/spec/fixtures/vcr_cassettes/delete_host.yaml
@@ -7,24 +7,23 @@ interactions:
       Accept-Encoding:
       - gzip, deflate
       Authorization:
-      - CyberWatch APIAuth-HMAC-SHA256 zYJ0sI0f+bsPZtvaP1949kCnMFVNeex6emLTixedeGg=:4RnY7rNjFWo0m7FEDnb+nsY+TiQNByjfE5P52fSP5Sk=
+      - CyberWatch APIAuth-HMAC-SHA256 Um7C1MMU5g3tMHjh4INdxbyihUTqpTtoUshlme3lJZU=:VmRopDRVQXucHBdg4DWAwOm9A0PowdVVs1uYyI8iaNs=
       Connection:
       - keep-alive
       Content-Length:
       - '0'
       Date:
-      - Tue, 17 Dec 2019 13:29:13 GMT
+      - Thu, 06 Aug 2020 12:01:03 GMT
       User-Agent:
       - python-requests/2.22.0
     method: DELETE
-    uri: https://localhost/api/v3/hosts/12
+    uri: https://localhost/api/v3/hosts/1
   response:
     body:
       string: !!binary |
-        H4sIAAAAAAAAA42PwQrCMAyG3yVXN2mHovY5vImU0oZZmKm06XCI726c8+RFcvnz589H8oAYwOiu
-        AXa5RwYD2/Vc0IB3jH3Kk5hDpHoX65IKk7siGKrDIJERrSNKlTxekbhYL1owSmYZBRCse1M7pQ+t
-        7lq9O+qN6fZGqbVSaqW0KAHXW/g/TCmgnQ9voGAeMc/dTjp2XIsgFvuDtZEiyx6jv1AaUh9RMqfz
-        e9vXHHmysZT6NX+eWrLe0SyfL5w0mZs2AQAA
+        H4sIAAAAAAAAA12OwQrCMBBE/2WvNmF3LbXud/QmUkKztEJNJE0FEf/dVLwozGVm3sA84eJBqILs
+        0qgZBAjtJkttAxUMLusY06MUMU+aSjTFJQd3VZCwznNBkhbI925bMzIaPBhuO6ql3guxRcQdsiCW
+        8Xrz/3BrsOmIpD4K4w8cotf++2/RdNf0cVzc4MICcjq/3iCg/l7BAAAA
     headers:
       Cache-Control:
       - no-store, must-revalidate, private, max-age=0
@@ -35,7 +34,7 @@ interactions:
       Content-Type:
       - application/json; charset=utf-8
       Date:
-      - Tue, 17 Dec 2019 13:29:14 GMT
+      - Thu, 06 Aug 2020 12:01:03 GMT
       Referrer-Policy:
       - strict-origin-when-cross-origin
       Server:
@@ -53,15 +52,15 @@ interactions:
       X-Frame-Options:
       - SAMEORIGIN
       X-MiniProfiler-Ids:
-      - x0l7vgegatu29y8s6f8d,rgfgd3bg7s73n39o6nsg,gcb3qzgu0tl6x6fcqnyn,f2bqttjenuizox3kj91k,corllayah9tfmm18ike9,jhxaxqwoxoyic9y6y6ks,kg9ln51um0k2i06k56qe,z4vc5et8lxbatf3xy601,fhcygqivmtudg03xdpdn,jbowibdb6gdwlf5oe7yw,sbha5gj1jxakyaca7w4u,vogedmmo77ml3wkm3jez
+      - lyz06rrgew0c013jz64r,nrxa71otbne4pd7upnnl
       X-MiniProfiler-Original-Cache-Control:
       - max-age=0, private, must-revalidate
       X-Permitted-Cross-Domain-Policies:
       - none
       X-Request-Id:
-      - e5c1cc4b-d3ed-43ef-a7ff-e08f31e90075
+      - 9849757d-1285-4349-b967-768d5c8686d3
       X-Runtime:
-      - '0.365497'
+      - '0.049375'
       X-XSS-Protection:
       - 1; mode=block
     status:
diff --git a/spec/fixtures/vcr_cassettes/servers_ok.yaml b/spec/fixtures/vcr_cassettes/servers_ok.yaml
index 7aa96cc..40b32ae 100644
--- a/spec/fixtures/vcr_cassettes/servers_ok.yaml
+++ b/spec/fixtures/vcr_cassettes/servers_ok.yaml
@@ -1,21 +1,21 @@
 interactions:
 - request:
-    body: '{"page": "1", "reboot_required": "false"}'
+    body: '{"page": "1", "per_page": 100}'
     headers:
       Accept:
       - '*/*'
       Accept-Encoding:
       - gzip, deflate
       Authorization:
-      - CyberWatch APIAuth-HMAC-SHA256 zYJ0sI0f+bsPZtvaP1949kCnMFVNeex6emLTixedeGg=:XGypqArO/98iIGI3hKPL9FE2v27qoFF4e3255AwAjjs=
+      - CyberWatch APIAuth-HMAC-SHA256 Um7C1MMU5g3tMHjh4INdxbyihUTqpTtoUshlme3lJZU=:rkaNkxZ/hCQFMAcn1GVOCzS0CIm6nV4R/QYxN+7Y0Rw=
       Connection:
       - keep-alive
       Content-Length:
-      - '41'
+      - '30'
       Content-Type:
       - application/json
       Date:
-      - Fri, 06 Dec 2019 15:11:00 GMT
+      - Tue, 11 Aug 2020 11:55:51 GMT
       User-Agent:
       - python-requests/2.22.0
     method: GET
@@ -23,13 +23,73 @@ interactions:
   response:
     body:
       string: !!binary |
-        H4sIAAAAAAAAA22RS2/bMBCE/0qw10jCklYUh8ecA/RQt5fAIBhpYxOlSJWPIEHg/96VZOTZI2eW
-        M9+S969gB1DXFRxDyt6MBAoeyUebXP3bxlyMuw3PUMFAqY92yjZ4UL44V4EzKes+jGPxtjerAxLF
-        TS1kjd1OdAq3CkWDiJcoFCLnRHoIIetIf4uNxN2PxiWqwBzIZ/1EMa05m0Ys02PIpO3EiriWjcQG
-        F6NMg8mUuL74DAorWGJN/oKwUe2NklefEHiPzMDO5hee/nDSIw22jPPIE2njPYf3NDLYxyJelQ4h
-        zncTRSZeIonV4Xs/PwGqq82n/pRNLunt+vyEk7OG4ysIrL/CH5rTywNXFi222OquZfP8P78W/UJs
-        G2wv7nY/2TGxP7LzvO3WSQpuAZGbGttadjuUMwjiCiLPIMcQs/5PKnv5ZZrVH0mp1YFTBYcYysSE
-        93te+Uzdk36XT/t/ZL9UuVICAAA=
+        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
     headers:
       Cache-Control:
       - no-store, must-revalidate, private, max-age=0
@@ -40,7 +100,7 @@ interactions:
       Content-Type:
       - application/json; charset=utf-8
       Date:
-      - Fri, 06 Dec 2019 15:11:02 GMT
+      - Tue, 11 Aug 2020 11:55:51 GMT
       Referrer-Policy:
       - strict-origin-when-cross-origin
       Server:
@@ -57,23 +117,23 @@ interactions:
       - noopen
       X-Frame-Options:
       - SAMEORIGIN
-      X-Miniprofiler-Ids:
-      - ymh7q97ebc1ad6r41mw8,1j3le7cwg3herrm4b53d,yy85e24dr9s5h3bwzf1j,tum7jvnpfvl180rocjig,z2xxuni74hkgzmsjqyp5
-      X-Miniprofiler-Original-Cache-Control:
+      X-MiniProfiler-Ids:
+      - hwomldaiqjbjtda57xvx,qdl0y2np9miyfvco1xkz,yamrnow4ybr5f8dxnui1,qdi93uylu43bfl6ttolt,8zgfslqlj3iyjtpl3k1j,oz1p35js5jlpv775o5o4,13pn7crvo2dnxpczobjb,q9vesdxcn5nb9aygscx,nbph97bvnhwrcyff7oj2,l296mm0nsbrf9nb9nr1h,dxvq50q4qn5omamovsoc,9qlhe9cecnh2tn5rll5f,w3wrypi3iscynx7srxct,l68qk2ist6dqmt9fdxp1,uxr47jibpri6upznikbk,ztbzidw5zulpjtwce1pd,hd3uv72gxjbcbsc4pfm7,xmj9l8bsfr4p56d8cejr,yqh2fxa8opushwfik7go,gsmwgqv1ubzhnp1u1twz
+      X-MiniProfiler-Original-Cache-Control:
       - max-age=0, private, must-revalidate
       X-Page:
       - '1'
       X-Per-Page:
-      - '25'
+      - '100'
       X-Permitted-Cross-Domain-Policies:
       - none
       X-Request-Id:
-      - 73aa102a-d8d4-475a-b898-2bf66ab39e4b
+      - fec24d73-305d-4e6e-9b94-686cea44de1b
       X-Runtime:
-      - '1.513547'
+      - '0.465460'
       X-Total:
-      - '1'
-      X-Xss-Protection:
+      - '79'
+      X-XSS-Protection:
       - 1; mode=block
     status:
       code: 200
diff --git a/spec/fixtures/vcr_cassettes/update_host.yaml b/spec/fixtures/vcr_cassettes/update_host.yaml
index bf124b7..3d73bc2 100644
--- a/spec/fixtures/vcr_cassettes/update_host.yaml
+++ b/spec/fixtures/vcr_cassettes/update_host.yaml
@@ -1,32 +1,31 @@
 interactions:
 - request:
-    body: '{"target": "192.168.2.3", "node_id": "1"}'
+    body: '{"target": "192.168.1.2", "node_id": "1", "category": "other"}'
     headers:
       Accept:
       - '*/*'
       Accept-Encoding:
       - gzip, deflate
       Authorization:
-      - CyberWatch APIAuth-HMAC-SHA256 zYJ0sI0f+bsPZtvaP1949kCnMFVNeex6emLTixedeGg=:5ogpITJLXjb7XLUHvM69Vu6B538wsUTbwhKc71u2jUE=
+      - CyberWatch APIAuth-HMAC-SHA256 Um7C1MMU5g3tMHjh4INdxbyihUTqpTtoUshlme3lJZU=:2/OLSXoVMDSrVHiA1R0NnDlBdGH6VppLGd0oTqF36so=
       Connection:
       - keep-alive
       Content-Length:
-      - '41'
+      - '62'
       Content-Type:
       - application/json
       Date:
-      - Tue, 17 Dec 2019 13:29:13 GMT
+      - Thu, 06 Aug 2020 09:49:20 GMT
       User-Agent:
       - python-requests/2.22.0
     method: PUT
-    uri: https://localhost/api/v3/hosts/12
+    uri: https://localhost/api/v3/hosts/1
   response:
     body:
       string: !!binary |
-        H4sIAAAAAAAAA42PwQrCMAyG3yVXN2mHovY5vImU0oZZmKm06XCI726c8+RFcvnz589H8oAYwOiu
-        AXa5RwYD2/Vc0IB3jH3Kk5hDpHoX65IKk7siGKrDIJERrSNKlTxekbhYL1owSmYZBRCse1M7pQ+t
-        7lq9O+qN6fZGqbVSaqW0KAHXW/g/TCmgnQ9voGAeMc/dTjp2XIsgFvuDtZEiyx6jv1AaUh9RMqfz
-        e9vXHHmysZT6NX+eWrLe0SyfL5w0mZs2AQAA
+        H4sIAAAAAAAAA12OwQrCMBBE/2WvNmF3LbXud/QmUkKztEJNJE0FEf/dVLwozGVm3sA84eJBqILs
+        0qgZBAjtJkttAxUMLusY06MUMU+aSjTFJQd3VZCwznNBkhbI925bMzIaPBhuO6ql3guxRcQdsiCW
+        8Xrz/3BrsOmIpD4K4w8cotf++2/RdNf0cVzc4MICcjq/3iCg/l7BAAAA
     headers:
       Cache-Control:
       - no-store, must-revalidate, private, max-age=0
@@ -37,7 +36,7 @@ interactions:
       Content-Type:
       - application/json; charset=utf-8
       Date:
-      - Tue, 17 Dec 2019 13:29:13 GMT
+      - Thu, 06 Aug 2020 09:49:20 GMT
       Referrer-Policy:
       - strict-origin-when-cross-origin
       Server:
@@ -55,15 +54,15 @@ interactions:
       X-Frame-Options:
       - SAMEORIGIN
       X-MiniProfiler-Ids:
-      - vogedmmo77ml3wkm3jez,rgfgd3bg7s73n39o6nsg,gcb3qzgu0tl6x6fcqnyn,f2bqttjenuizox3kj91k,corllayah9tfmm18ike9,jhxaxqwoxoyic9y6y6ks,kg9ln51um0k2i06k56qe,z4vc5et8lxbatf3xy601,fhcygqivmtudg03xdpdn,jbowibdb6gdwlf5oe7yw,sbha5gj1jxakyaca7w4u
+      - wmzz72g7fpu8un06v814,kogiwk4l7a56h1fzfek5
       X-MiniProfiler-Original-Cache-Control:
       - max-age=0, private, must-revalidate
       X-Permitted-Cross-Domain-Policies:
       - none
       X-Request-Id:
-      - ef0d7595-ed49-43b3-a020-58f9cceb6bca
+      - 4ea64153-833b-4b89-9df8-e1e3d8e6a45a
       X-Runtime:
-      - '0.393925'
+      - '0.030272'
       X-XSS-Protection:
       - 1; mode=block
     status:
diff --git a/spec/fixtures/vcr_cassettes/update_server_cve_ignored.yaml b/spec/fixtures/vcr_cassettes/update_server_cve_ignored.yaml
index 01f383f..619b53e 100644
--- a/spec/fixtures/vcr_cassettes/update_server_cve_ignored.yaml
+++ b/spec/fixtures/vcr_cassettes/update_server_cve_ignored.yaml
@@ -1,45 +1,47 @@
 interactions:
 - request:
-    body: '{"ignored": "true"}'
+    body: '{"ignored": "true", "comment": "test-ignore"}'
     headers:
       Accept:
       - '*/*'
       Accept-Encoding:
       - gzip, deflate
       Authorization:
-      - CyberWatch APIAuth-HMAC-SHA256 zYJ0sI0f+bsPZtvaP1949kCnMFVNeex6emLTixedeGg=:2PTeC7OxtsqWNfUGZ5ZzkqAluOTpYK1IpsbTg30aIdw=
+      - CyberWatch APIAuth-HMAC-SHA256 Um7C1MMU5g3tMHjh4INdxbyihUTqpTtoUshlme3lJZU=:LnneLRfN19iosyc8ttYY1ZcHuA5qEF+sxj8ftMT8ghA=
       Connection:
       - keep-alive
       Content-Length:
-      - '19'
+      - '45'
       Content-Type:
       - application/json
       Date:
-      - Mon, 20 Jan 2020 08:46:14 GMT
+      - Tue, 11 Aug 2020 08:57:36 GMT
       User-Agent:
       - python-requests/2.22.0
     method: PUT
-    uri: https://localhost/api/v3/servers/9/cve_announcements/CVE-2019-3028
+    uri: https://localhost/api/v3/servers/8/cve_announcements/CVE-2020-3962
   response:
     body:
       string: !!binary |
-        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
+        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
+        ENXp4WsjYGO1ukpjGtEXpv8DgDku/KIXAAA=
     headers:
       Cache-Control:
       - no-store, must-revalidate, private, max-age=0
@@ -47,13 +49,10 @@ interactions:
       - keep-alive
       Content-Encoding:
       - gzip
-      Content-Security-Policy:
-      - 'default-src ''self''; script-src ''self'' ''unsafe-inline'' ''unsafe-eval'';
-        style-src ''self'' ''unsafe-inline''; img-src ''self'' data:'
       Content-Type:
       - application/json; charset=utf-8
       Date:
-      - Mon, 20 Jan 2020 08:46:16 GMT
+      - Tue, 11 Aug 2020 08:57:37 GMT
       Referrer-Policy:
       - strict-origin-when-cross-origin
       Server:
@@ -71,15 +70,15 @@ interactions:
       X-Frame-Options:
       - SAMEORIGIN
       X-MiniProfiler-Ids:
-      - 6ylopvdf2ckd1vs9opkd,ge614no8jkpc5p8jc8n8,nteejdol4gbx67o36jby,4uq0t490rx7y42i2kub3
+      - z1kvth88f2jr28652ol1
       X-MiniProfiler-Original-Cache-Control:
       - max-age=0, private, must-revalidate
       X-Permitted-Cross-Domain-Policies:
       - none
       X-Request-Id:
-      - a0927ed3-9d3b-43ec-b5e0-76ed95cd76a1
+      - ded25fc4-7e26-46c3-aeec-6f56680dca63
       X-Runtime:
-      - '1.130292'
+      - '0.372552'
       X-XSS-Protection:
       - 1; mode=block
     status:


Test patch:
diff --git a/spec/test_cbw_api.py b/spec/test_cbw_api.py
index 80225db..d46fe4b 100644
--- a/spec/test_cbw_api.py
+++ b/spec/test_cbw_api.py
@@ -1,19 +1,8 @@
 """Test file for cbw_api.py"""
 
-from cbw_api_toolbox.cbw_api import CBWApi
-from cbw_api_toolbox.cbw_objects.cbw_agent import CBWAgent
-from cbw_api_toolbox.cbw_objects.cbw_server import CBWCve
-from cbw_api_toolbox.cbw_objects.cbw_group import CBWGroup
-from cbw_api_toolbox.cbw_objects.cbw_host import CBWHost
-from cbw_api_toolbox.cbw_objects.cbw_importer import CBWImporter
-from cbw_api_toolbox.cbw_objects.cbw_node import CBWNode
-from cbw_api_toolbox.cbw_objects.cbw_security_issue import CBWSecurityIssue
-from cbw_api_toolbox.cbw_objects.cbw_server import CBWServer
-from cbw_api_toolbox.cbw_objects.cbw_users import CBWUsers
-from cbw_api_toolbox.cbw_objects.cbw_remote_access import CBWRemoteAccess
-
 import vcr  # pylint: disable=import-error
 import pytest  # pylint: disable=import-error
+from cbw_api_toolbox.cbw_api import CBWApi
 
 # To generate a new vcr cassette:
 # - DO NOT CHANGE THE API_URL
@@ -22,17 +11,18 @@ import pytest  # pylint: disable=import-error
 # - Remove your credentials
 # - relaunch the test. everything should work.
 
-
-
 API_KEY = ''
 SECRET_KEY = ''
 API_URL = 'https://localhost'
 
+
 class TestCBWApi:
+
     """Test for class CBWApi"""
 
     def test_ping(self):  # pylint: disable=no-self-use
         """Tests for method ping"""
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/ping_ok.yaml'):
             response = CBWApi(API_URL, API_KEY, SECRET_KEY).ping()
             assert response is True
@@ -49,34 +39,42 @@ class TestCBWApi:
             CBWApi('', API_KEY, SECRET_KEY).ping()
         assert exc.value.code == -1
 
-    def test_servers(self):  # pylint: disable=no-self-use
+    @staticmethod
+    def test_servers():
         """Tests for servers method"""
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/servers_ok.yaml'):
-            params = {
-                'page': '1',
-                'reboot_required' : 'false'
-            }
+
+            validate_server = "cbw_object(id=2, hostname='cyberwatch-esxi.localdomain', description=None, \
+last_communication='2020-07-28T15:02:08.000+02:00', reboot_required=None, updates_count=0, boot_at=None, category='hypervisor', \
+created_at='2020-07-28T15:02:05.000+02:00', cve_announcements_count=0, prioritized_cve_announcements_count=0, \
+status='server_update_comm_fail', os=cbw_object(key='vmware_esxi_7_0', name='VMware ESXi 7.0', arch='x86_64', \
+eol='2025-04-02T02:00:00.000+02:00', short_name='ESXi 7.0', type='Os::Vmware'), environment=cbw_object(id=2, name='Medium', \
+confidentiality_requirement='confidentiality_requirement_medium', integrity_requirement='integrity_requirement_medium', \
+availability_requirement='availability_requirement_medium'), groups=[], compliance_groups=[])"
+
+            params = {'page': '1'}
             response = CBWApi(API_URL, API_KEY, SECRET_KEY).servers(params)
             assert isinstance(response, list) is True
-            for server in response:
-                assert isinstance(server, CBWServer) is True
+            assert str(response[0]) == validate_server
 
-    def test_server(self): # pylint: disable=no-self-use
+    @staticmethod
+    def test_server():
         """Tests for server method"""
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/server_ok.yaml'):
-            response = CBWApi(
-                API_URL,
-                API_KEY,
-                SECRET_KEY).server("3")
-            assert isinstance(response, CBWServer) is True
+            response = CBWApi(API_URL, API_KEY, SECRET_KEY).server('3')
+            assert response.category == 'server'
+            assert response.cve_announcements[0].cve_code == 'CVE-2019-14869'
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/server_failed.yaml'):
             response = CBWApi(API_URL, API_KEY, SECRET_KEY).server('wrong_id')
-            assert isinstance(response, CBWServer) is False
+            assert response is None
 
     @staticmethod
     def test_delete_server():
         """Tests for method delete_server"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
         response = client.delete_server(None)
@@ -93,43 +91,50 @@ class TestCBWApi:
     @staticmethod
     def test_update_server():
         """Tests for server method"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
-        info = {
-            "groups": [13, 12]
-        }
+        info = {'groups': [13, 12]}
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_server.yaml'):
-            response = client.update_server('6',
-                                            info)
+            response = client.update_server('6', info)
             assert response is True
 
-        response = client.update_server('', info)
-        assert response is False
+            response = client.update_server('', info)
+            assert response is False
 
-        response = client.update_server(None, info)
-        assert response is False
+            response = client.update_server(None, info)
+            assert response is False
 
-        info = {
-            "groups": [None],
-            "compliance_groups": [None]
-        }
-        with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_server_with_group_none.yaml'):
-            response = client.update_server('6', info)
-            assert response is True
+            info = {'groups': [None], 'compliance_groups': [None]}
+            with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_server_with_group_none.yaml'):
+                response = client.update_server('6', info)
+                assert response is True
 
     @staticmethod
     def test_agents():
         """Tests for method agents"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/agents.yaml'):
-            params = {
-                'page': '1'
-            }
+            params = {'page': '1'}
+
+            servers_validate = [
+                'cbw_object(id=4, server_id=3, node_id=1, version=None, \
+remote_ip=None, last_communication=None)',
+                "cbw_object(id=5, server_id=10, node_id=2, version='9', \
+remote_ip='12.34.56.78', last_communication=None)",
+                "cbw_object(id=6, server_id=30, node_id=2, version='9', \
+remote_ip='12.34.56.78', last_communication=None)",
+                "cbw_object(id=7, server_id=3, node_id=2, version='7', \
+remote_ip='12.34.56.78', last_communication=None)"]
+
             response = client.agents(params)
             assert isinstance(response, list) is True
-            for agent in response:
-                assert isinstance(agent, CBWAgent) is True
+            assert str(response[0]) == servers_validate[0]
+            assert str(response[1]) == servers_validate[1]
+            assert str(response[2]) == servers_validate[2]
+            assert str(response[3]) == servers_validate[3]
 
     @staticmethod
     def test_agent():
@@ -138,65 +143,81 @@ class TestCBWApi:
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/agent.yaml'):
             response = client.agent('4')
-            assert isinstance(response, CBWAgent) is True
+
+            assert str(response) == "cbw_object(id=4, server_id=3, node_id=1, \
+version=None, remote_ip=None, last_communication=None)"
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/agent_wrong_id.yaml'):
             response = client.agent('wrong_id')
-            assert isinstance(response, CBWAgent) is False
+
+            assert response is None
 
     @staticmethod
     def test_delete_agent():
         """Tests for method delete_agent"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_agent.yaml'):
             response = client.delete_agent('5')
+
             assert response is True
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_agent_wrong_id.yaml'):
             response = client.delete_agent('wrong_id')
+
             assert response is False
 
     @staticmethod
     def test_remote_accesses():
         """Tests for method remote_accesses"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
+        remote_accesses_validate = [
+            "cbw_object(id=22, type='CbwRam::RemoteAccess::Ssh::WithPassword', address='10.0.2.15', \
+port=22, is_valid=False, last_error='Connection refused - connect(2) for 10.0.2.15:22', server_id=None, node_id=1)",
+            "cbw_object(id=23, type='CbwRam::RemoteAccess::Ssh::WithPassword', address='server02.example.com', \
+port=22, is_valid=False, last_error='getaddrinfo: Name or service not known', server_id=None, node_id=1)",
+            "cbw_object(id=25, type='CbwRam::RemoteAccess::Ssh::WithPassword', address='10.0.2.16', \
+port=22, is_valid=False, last_error='No route to host - connect(2) for 10.0.2.16:22', server_id=None, node_id=1)"]
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/remote_accesses.yaml'):
-            params = {
-                'page': '1'
-            }
+            params = {'page': '1'}
             response = client.remote_accesses(params)
+
             assert isinstance(response, list) is True
-            for remote in response:
-                assert isinstance(remote, CBWRemoteAccess) is True
+            assert str(response[0]) == remote_accesses_validate[0], str(response[1]) == remote_accesses_validate[2]
+            assert response[2].type == 'CbwRam::RemoteAccess::Ssh::WithPassword'
 
     @staticmethod
     def test_create_remote_access():
         """Tests for method remote_access"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
-        info = {"type": "CbwRam::RemoteAccess::Ssh::WithPassword",
-                "address": "X.X.X.X",
-                "port": "22",
-                "login": "loginssh",
-                "password": "passwordssh",
-                "key": "",  # precises the key of the connection
-                "node_id": "1",  # precises the Cyberwatch source of the connection,
-                "server_groups": "test, production",
-                "priv_password": "",
-                "auth_password": ""
-                }
+        info = {
+            'type': 'CbwRam::RemoteAccess::Ssh::WithPassword',
+            'address': 'X.X.X.X',
+            'port': '22',
+            'login': 'loginssh',
+            'password': 'passwordssh',
+            'key': '',
+            'node_id': '1',
+            'server_groups': 'test, production',
+            'priv_password': '',
+            'auth_password': '',
+        }
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/create_remote_access.yaml'):
             response = client.create_remote_access(info)
 
-            assert isinstance(response, CBWRemoteAccess) is True
+            assert response.address == 'X.X.X.X', response.server_groups == ['test', 'production']
+            assert response.type == 'CbwRam::RemoteAccess::Ssh::WithPassword', response.login == 'loginssh'
 
-        info["address"] = ""
+        info['address'] = ''
 
-        with vcr.use_cassette('spec/fixtures/vcr_cassettes/create_remote_access_failed_'
-                              'without_address.yaml'):
+        with vcr.use_cassette('spec/fixtures/vcr_cassettes/create_remote_access_failed_without_address.yaml'):
             response = client.create_remote_access(info)
 
             assert response is False
@@ -204,147 +225,164 @@ class TestCBWApi:
     @staticmethod
     def test_remote_access():
         """Tests for method remote_access"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/remote_access.yaml'):
             response = client.remote_access('15')
-            assert isinstance(response, CBWRemoteAccess) is True
+
+            assert response.address == 'X.X.X.X', response.server_groups == ['test', 'production']
+            assert response.type == 'CbwRam::RemoteAccess::Ssh::WithPassword', response.login == 'loginssh'
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/remote_access_wrong_id.yaml'):
             response = client.remote_access('wrong_id')
-            assert isinstance(response, CBWRemoteAccess) is False
+
+            assert response is None
 
     @staticmethod
     def test_delete_remote_access():
         """Tests for method delete_remote_access"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_remote_access.yaml'):
             response = client.delete_remote_access('15')
+
             assert response is True
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_remote_access_wrong_id.yaml'):
             response = client.delete_remote_access('wrong_id')
+
             assert response is False
 
     @staticmethod
     def test_update_remote_access():
         """Tests for update remote method"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
-        info = {"type": "CbwRam::RemoteAccess::Ssh::WithPassword",
-                "address": "10.10.10.228",
-                "port": "22",
-                "login": "loginssh",
-                "password": "passwordssh",
-                "key": "",
-                "node": "master"
-                }
+        info = {
+            'type': 'CbwRam::RemoteAccess::Ssh::WithPassword',
+            'address': '10.10.10.228',
+            'port': '22',
+            'login': 'loginssh',
+            'password': 'passwordssh',
+            'key': '',
+            'node': 'master',
+        }
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_remote_access.yaml'):
             response = client.update_remote_access('15', info)
 
-            assert isinstance(response, CBWRemoteAccess) is True
+            assert response.address == '10.10.10.228', response.type == 'CbwRam::RemoteAccess::Ssh::WithPassword'
 
-        info["address"] = "10.10.11.228"
+        info['address'] = '10.10.11.228'
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_remote_access_id_none.yaml'):
             response = client.update_remote_access(None, info)
 
-            assert isinstance(response, CBWRemoteAccess) is False
+            assert response is False
 
-        info["type"] = ""
+        info['type'] = ''
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_remote_access_without_type.yaml'):
             response = client.update_remote_access('15', info)
 
-            assert response.type == "CbwRam::RemoteAccess::Ssh::WithPassword"
-
+            assert response.type == 'CbwRam::RemoteAccess::Ssh::WithPassword'
 
     @staticmethod
     def test_cve_announcement():
         """Tests for method cve_announcement"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/cve_announcement.yaml'):
             response = client.cve_announcement('CVE-2017-0146')
-
-            assert isinstance(response, CBWCve) is True
+            assert response.cve_code == "CVE-2017-0146"
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/cve_announcement_failed.yaml'):
             response = client.cve_announcement('wrong_id')
 
-            assert isinstance(response, CBWCve) is False
+            assert response is None
 
     @staticmethod
     def test_group():
         """Tests for method groups"""
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
+        groups_validate = [
+            "cbw_object(id=12, name='production', description=None, color='#12AFCB')",
+            "cbw_object(id=13, name='Development', description=None, color='#12AFCB)"]
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/groups.yaml'):
             response = client.groups()
-        for group in response:
-            assert isinstance(group, CBWGroup) is True
+
+            assert str(response[0]) == groups_validate[0], str(response[1]) == groups_validate[1]
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/group.yaml'):
             response = client.group('12')
 
-            assert isinstance(response, CBWGroup) is True
+            assert str(response) == groups_validate[0]
 
         params = {
-            "name": "test", #Required, name of the group
-            "description": "test description", #Description of the created group
+            "name": "test",
+            "description": "test description",
         }
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/create_group.yaml'):
             response = client.create_group(params)
 
-            assert isinstance(response, CBWGroup) is True
+            assert response.name == "test", response.description == "test description"
 
         params["name"] = "test_change"
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_group.yaml'):
             response = client.update_group('12', params)
 
-            assert isinstance(response, CBWGroup) is True
+            assert response.name == "test_change"
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_group.yaml'):
             response = client.delete_group('12')
 
-            assert isinstance(response, CBWGroup) is True
+            assert response.name == "test_change"
 
     @staticmethod
     def test_deploy():
         """Tests for method test_deploy_remote_access"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/test_deploy.yaml'):
             response = client.test_deploy_remote_access('15')
 
-            assert isinstance(response, CBWRemoteAccess) is True
+            assert str(response) == "cbw_object(id=15, type='CbwRam::RemoteAccess::Ssh::WithPassword', \
+address='10.10.11.228', port=22, is_valid=None, last_error='Net::SSH::ConnectionTimeout', server_id=None, node_id=1)"
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/test_deploy_failed.yaml'):
             response = client.test_deploy_remote_access('wrong_id')
 
-            assert isinstance(response, CBWRemoteAccess) is False
+            assert response is None
 
     @staticmethod
     def test_users():
         """Tests for method users"""
 
-        params = {
-            "auth_provider": "local_password"
-        }
+        params = {'auth_provider': 'local_password'}
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/users.yaml'):
             response = CBWApi(API_URL, API_KEY, SECRET_KEY).users(params)
-            for user in response:
-                assert isinstance(user, CBWUsers) is True
+
+            assert str(response[0]) == "cbw_object(id=1, login='daniel@cyberwatch.fr', email='daniel@cyberwatch.fr', \
+name='', firstname='', locale='fr', auth_provider='local_password', description='', server_groups=[])"
 
     @staticmethod
     def test_user():
         """Tests for method user"""
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/user.yaml'):
             response = CBWApi(API_URL, API_KEY, SECRET_KEY).user('1')
 
-            assert isinstance(response, CBWUsers) is True
+            assert str(response) == "cbw_object(id=1, login='daniel@cyberwatch.fr', email='daniel@cyberwatch.fr', \
+name='', firstname='', locale='fr', auth_provider='local_password', description='', server_groups=[])"
 
     @staticmethod
     def test_cve_announcements():
@@ -355,97 +393,114 @@ class TestCBWApi:
         }
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/cve_announcements.yaml'):
             response = client.cve_announcements(params)
-        for cve in response:
-            assert isinstance(cve, CBWCve) is True
+
+        assert response[0].cve_code == 'CVE-2015-8158', response[10].cve_code == 'CVE-2015-8139'
 
     @staticmethod
     def test_update_cve_announcement():
         """Tests for method update_cve_announcement()"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
         cve_code = 'CVE-2019-16768'
         params = {
-            "score_custom": "7",
-            "access_complexity": "access_complexity_low",
-            "access_vector": "access_vector_adjacent_network",
-            "availability_impact": "availability_impact_none",
-            "confidentiality_impact": "confidentiality_impact_low",
-            "integrity_impact": "integrity_impact_low",
-            "privilege_required": "privilege_required_none",
-            "scope": "scope_changed",
-            "user_interaction": "user_interaction_required"
+            'score_custom': '7',
+            'access_complexity': 'access_complexity_low',
+            'access_vector': 'access_vector_adjacent_network',
+            'availability_impact': 'availability_impact_none',
+            'confidentiality_impact': 'confidentiality_impact_low',
+            'integrity_impact': 'integrity_impact_low',
+            'privilege_required': 'privilege_required_none',
+            'scope': 'scope_changed',
+            'user_interaction': 'user_interaction_required',
         }
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_cve_announcement.yaml'):
             response = client.update_cve_announcement(cve_code, params)
-        assert isinstance(response, CBWCve) is True
+
+        assert response.score_custom == 7.0, response.cvss_custom.scope == 'scope_changed'
 
     @staticmethod
     def test_delete_cve_announcement():
         """Tests for method delete_cve_announcement()"""
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
         cve_code = 'CVE-2019-16768'
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_cve_announcement.yaml'):
             response = client.delete_cve_announcement(cve_code)
-        assert isinstance(response, CBWCve) is True
+
+        assert response.cve_code == 'CVE-2019-16768'
 
     @staticmethod
     def test_nodes():
         """Tests for method nodes()"""
+
+        node_validate = [
+            "cbw_object(id=1, name='master', created_at='2019-11-08T15:06:11.000+01:00', \
+updated_at='2019-12-18T14:34:09.000+01:00')",
+            "cbw_object(id=1, name='master', created_at='2019-11-08T15:06:11.000+01:00', \
+updated_at='2019-12-16T14:17:29.000+01:00')"]
+
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
-        params = {
-            'page': '1',
-        }
+        params = {'page': '1'}
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/nodes.yaml'):
             response = client.nodes(params)
-        for node in response:
-            assert isinstance(node, CBWNode) is True
+
+        assert str(response[0]) == node_validate[0]
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/node.yaml'):
             response = client.node('1')
 
-            assert isinstance(response, CBWNode) is True
+            assert str(response) == node_validate[1]
 
-        params = {
-            "new_id": "1"
-        }
+        params = {'new_id': '1'}
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_node.yaml'):
+
             response = client.delete_node('2', params)
 
-            assert isinstance(response, CBWNode) is True
+            assert response.id == 2
 
     @staticmethod
     def test_host():
         """Tests for method hosts"""
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
+        hosts_validate = [
+            "cbw_object(id=8, target='172.18.0.13', category='linux', \
+hostname='bb79e64ccd6e.dev_default', cve_announcements_count=0, created_at='2019-11-14T11:58:50.000+01:00', \
+updated_at='2019-12-16T16:45:42.000+01:00', node_id=1, server_id=5, status='server_update_init', \
+technologies=[], security_issues=[], cve_announcements=[], scans=[])",
+            "cbw_object(id=12, target='5.5.5.5', category='linux', hostname=None, cve_announcements_count=0, \
+created_at='2019-12-17T14:28:00.000+01:00', updated_at='2019-12-17T14:28:00.000+01:00', node_id=1, \
+server_id=7, status='server_update_init', technologies=[], security_issues=[], cve_announcements=[], scans=[])"]
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/hosts.yaml'):
             response = client.hosts()
-        for host in response:
-            assert isinstance(host, CBWHost) is True
+
+        assert len(response) == 4, str(response[0]) == hosts_validate[0]
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/host.yaml'):
             response = client.host('12')
 
-            assert isinstance(response, CBWHost) is True
+            assert str(response) == hosts_validate[1]
 
         params = {
             "target": "192.168.1.2",
             "node_id": "1"
-            }
+        }
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/create_host.yaml'):
             response = client.create_host(params)
 
-            assert isinstance(response, CBWHost) is True
+            assert response.target == "192.168.1.2", response.node_id == 1
 
-        params["target"] = "192.168.2.3"
+        params["category"] = "other"
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_host.yaml'):
-            response = client.update_host('12', params)
+            response = client.update_host('1', params)
 
-        assert isinstance(response, CBWHost) is True
+        assert response.category == "other", response.node_id == 1
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_host.yaml'):
-            response = client.delete_host('12')
+            response = client.delete_host('1')
 
-            assert isinstance(response, CBWHost) is True
+            assert response.target == '10.10.1.186'
 
     @staticmethod
     def test_update_server_cve():
@@ -457,28 +512,33 @@ class TestCBWApi:
         }
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_server_cve.yaml'):
             response = client.update_server_cve('9', "CVE-2019-3028", info)
-            assert isinstance(response, CBWServer) is True
+            assert response.cve_announcements[36].comment == 'test'
 
         info = {
-            "ignored": "true"
+            "ignored": "true",
+            "comment": "test-ignore"
         }
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_server_cve_ignored.yaml'):
-            response = client.update_server_cve('9', "CVE-2019-3028", info)
-            assert isinstance(response, CBWServer) is True
+            response = client.update_server_cve('8', "CVE-2020-3962", info)
+            assert len(response.cve_announcements) == 12
 
     @staticmethod
     def test_security_issues():
         """Tests for method security_issues"""
         client = CBWApi(API_URL, API_KEY, SECRET_KEY)
 
+        security_issues_validate = [
+            "cbw_object(id=1, type=None, sid='', level='level_info', title=None, description=None)",
+            "cbw_object(id=2, type=None, sid='', level='level_info', title=None, description=None)",
+            "cbw_object(id=3, type=None, sid='', level='level_info', title=None, description=None)"]
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/security_issues.yaml'):
             params = {
                 'page': '1'
             }
             response = client.security_issues(params)
             assert isinstance(response, list) is True
-            for issue in response:
-                assert isinstance(issue, CBWSecurityIssue) is True
+            assert str(response[0]) == security_issues_validate[0], str(response[1]) == security_issues_validate[1]
 
     @staticmethod
     def test_create_security_issue():
@@ -494,7 +554,7 @@ class TestCBWApi:
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/create_security_issue.yaml'):
             response = client.create_security_issue(info)
 
-            assert isinstance(response, CBWSecurityIssue) is True
+            assert response.level == "level_critical", response.description == "Test"
 
     @staticmethod
     def test_update_security_issue():
@@ -510,15 +570,14 @@ class TestCBWApi:
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_security_issue.yaml'):
             response = client.update_security_issue('2', info)
 
-            assert isinstance(response, CBWSecurityIssue) is True
+            assert response.description == "Test update"
 
         info["level"] = "level_test"
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/update_security_issue_wrong_level.yaml'):
             response = client.update_security_issue("2", info)
 
-            assert isinstance(response, CBWSecurityIssue) is False
-
+            assert response is None
 
     @staticmethod
     def test_delete_security_issue():
@@ -527,11 +586,12 @@ class TestCBWApi:
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_security_issue.yaml'):
             response = client.delete_security_issue('1')
-            assert isinstance(response, CBWSecurityIssue) is True
+            assert str(response) == "cbw_object(id=1, type=None, sid='', level='level_info', \
+title=None, description=None, servers=[], cve_announcements=[])"
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/delete_security_issue_wrong_id.yaml'):
             response = client.delete_security_issue('wrong_id')
-            assert isinstance(response, CBWSecurityIssue) is False
+            assert response is None
 
     @staticmethod
     def test_fetch_importer_scripts():
@@ -540,4 +600,4 @@ class TestCBWApi:
 
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/fetch_importer_script.yaml'):
             response = client.fetch_importer_script('1')
-            assert isinstance(response, CBWImporter) is True
+            assert response.version == '47c8367e1c92d50fad8894362f5c09e9bfe65e712aab2d23ffbb61e354e270dd'
diff --git a/spec/test_cbw_files_xlsx.py b/spec/test_cbw_files_xlsx.py
index 4e49884..521b2ac 100644
--- a/spec/test_cbw_files_xlsx.py
+++ b/spec/test_cbw_files_xlsx.py
@@ -1,12 +1,9 @@
 """Test file for cbw_files_xlsx.py"""
 
-import xlrd
-
-from cbw_api_toolbox.cbw_objects.cbw_remote_access import CBWRemoteAccess
+import xlrd # pylint: disable=import-error
+import vcr # pylint: disable=import-error
 from cbw_api_toolbox.cbw_file_xlsx import CBWXlsx
 
-import vcr  # pylint: disable=import-error
-
 # To generate a new vcr cassette:
 # - DO NOT CHANGE THE API_URL
 # - Add your local credentials API_KEY and SECRET_KEY
@@ -15,7 +12,6 @@ import vcr  # pylint: disable=import-error
 # - relaunch the test. everything should work.
 
 
-
 API_KEY = ''
 SECRET_KEY = ''
 API_URL = 'https://localhost'
@@ -30,14 +26,23 @@ class TestCBWXlsx:
         client = CBWXlsx(API_URL, API_KEY, SECRET_KEY)
         file_xlsx = "spec/fixtures/xlsx_files/batch_import_model.xlsx"
 
+        remote_accesses_validate = [
+            "cbw_object(id=33, type='CbwRam::RemoteAccess::Ssh::WithPassword', \
+address='10.0.2.15', port=22, is_valid=None, last_error=None, server_id=None, node_id=1)",
+            "cbw_object(id=34, type='CbwRam::RemoteAccess::Ssh::WithPassword', address='server02.example.com', \
+port=22, is_valid=None, last_error=None, server_id=None, node_id=1)",
+            "cbw_object(id=35, type='CbwRam::RemoteAccess::Ssh::WithPassword', address='server01.example.com', port=22\
+, is_valid=None, last_error=None, server_id=None, node_id=1)"]
+
         with vcr.use_cassette('spec/fixtures/vcr_cassettes/'
                               'import_remote_accesses_xlsx_file.yaml'):
             response = client.import_remote_accesses_xlsx(file_xlsx)
 
             assert len(response) == 3
-            assert isinstance(response[0], CBWRemoteAccess) is True
-            assert isinstance(response[1], CBWRemoteAccess) is True
-            assert isinstance(response[2], CBWRemoteAccess) is True
+
+            assert str(response[0]) == remote_accesses_validate[0]
+            assert str(response[1]) == remote_accesses_validate[1]
+            assert str(response[2]) == remote_accesses_validate[2]
 
         file_xlsx = "spec/fixtures/xlsx_files/batch_import_model_false.xlsx"
 
@@ -46,9 +51,9 @@ class TestCBWXlsx:
             response = client.import_remote_accesses_xlsx(file_xlsx)
 
             assert len(response) == 3
-            assert isinstance(response[0], CBWRemoteAccess) is False
-            assert isinstance(response[1], CBWRemoteAccess) is False
-            assert isinstance(response[2], CBWRemoteAccess) is True
+            assert response[0] is False
+            assert response[1] is False
+            assert str(response[2]), remote_accesses_validate[2]
 
     @staticmethod
     def test_export_remote_accesses_xlsx():
@@ -66,12 +71,11 @@ class TestCBWXlsx:
                 result = sheet.row_values(rownum)
                 break
 
-            assert response is True and result == ['HOST', 'PORT', 'TYPE', 'NODE_ID', 'SERVER_GROUPS']
+            assert response is True and result == [
+                'HOST', 'PORT', 'TYPE', 'NODE_ID', 'SERVER_GROUPS']
 
             for rownum in range(1, sheet.nrows):
                 result = sheet.row_values(rownum)
                 break
             # The group is not assigned yet
-            assert result == ['10.0.2.15', 22,
-                              'CbwRam::RemoteAccess::Ssh::WithPassword',
-                              1, '']
+            assert result == ['10.0.2.15', 22, 'CbwRam::RemoteAccess::Ssh::WithPassword', 1, '']