# Path: aioconsul/client/bases.py
# class EndpointBase:
# 
#     def __init__(self, api):
#         self._api = api
# 
#     def __repr__(self):
#         return "<%s(%r)>" % (self.__class__.__name__, str(self._api.address))
# 
# Path: aioconsul/util.py
# def extract_attr(obj, *, keys):
#     if isinstance(obj, Mapping):
#         for key in keys:
#             if key in obj:
#                 return obj[key]
#         raise TypeError("%s not found in obj %s" % (keys, obj))
#     return obj


from .bases import EndpointBase
from aioconsul.util import extract_attr
        the service's port would revert to the original value but the tags
        would maintain the updated value. As a counter example, if an external
        agent modified both the tags and port for this service and
        **EnableTagOverride** was set to false then after the next sync cycle
        the service's port and the tags would revert to the original value and
        all modifications would be lost. It's important to note that this
        applies only to the locally registered service. If you have multiple
        nodes all registering the same service their **EnableTagOverride**
        configuration and all other service configuration items are
        independent of one another. Updating the tags for the service
        registered on one node is independent of the same service (by name)
        registered on another node. If **EnableTagOverride** is not specified
        the default value is ``False``.
        """
        response = await self._api.put("/v1/agent/service/register",
                                       data=service)
        return response.status == 200

    async def deregister(self, service):
        """Deregisters a local service

        Parameters:
            service (ObjectID): Service ID
        Returns:
            bool: ``True`` on success

        The deregister endpoint is used to remove a service from the local
        agent. The agent will take care of deregistering the service with the
        Catalog. If there is an associated check, that is also deregistered.
        """

# Path: aioconsul/client/bases.py
# class EndpointBase:
# 
#     def __init__(self, api):
#         self._api = api
# 
#     def __repr__(self):
#         return "<%s(%r)>" % (self.__class__.__name__, str(self._api.address))
# 
# Path: aioconsul/util.py
# def extract_attr(obj, *, keys):
#     if isinstance(obj, Mapping):
#         for key in keys:
#             if key in obj:
#                 return obj[key]
#         raise TypeError("%s not found in obj %s" % (keys, obj))
#     return obj


# Path: aioconsul/client/services_endpoint.py
from .bases import EndpointBase
from aioconsul.util import extract_attr

        the service's port would revert to the original value but the tags
        would maintain the updated value. As a counter example, if an external
        agent modified both the tags and port for this service and
        **EnableTagOverride** was set to false then after the next sync cycle
        the service's port and the tags would revert to the original value and
        all modifications would be lost. It's important to note that this
        applies only to the locally registered service. If you have multiple
        nodes all registering the same service their **EnableTagOverride**
        configuration and all other service configuration items are
        independent of one another. Updating the tags for the service
        registered on one node is independent of the same service (by name)
        registered on another node. If **EnableTagOverride** is not specified
        the default value is ``False``.
        """
        response = await self._api.put("/v1/agent/service/register",
                                       data=service)
        return response.status == 200

    async def deregister(self, service):
        """Deregisters a local service

        Parameters:
            service (ObjectID): Service ID
        Returns:
            bool: ``True`` on success

        The deregister endpoint is used to remove a service from the local
        agent. The agent will take care of deregistering the service with the
        Catalog. If there is an associated check, that is also deregistered.
        """

        service_id = extract_attr(service, keys=["ServiceID", "ID"])