prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Namecheap support not optional
  Unlike route53 or softlayer and unlike what setup.py suggests, the namecheap provider is not optional in 2.1.17.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `lexicon/providers/namecheap.py`
  Content:
  ```
  1 from __future__ import absolute_import
  2 from __future__ import print_function
  3 
  4 import logging
  5 
  6 import namecheap
  7 
  8 from .base import Provider as BaseProvider
  9 
  10 logger = logging.getLogger(__name__)
  11 
  12 
  13 def ProviderParser(subparser):
  14     subparser.add_argument(
  15         '--auth-token',
  16         help='specify api token used to authenticate'
  17     )
  18     subparser.add_argument(
  19         '--auth-username',
  20         help='specify email address used to authenticate'
  21     )
  22     # FIXME What is the client IP used for?
  23     subparser.add_argument(
  24         '--auth-client-ip',
  25         help='Client IP address to send to Namecheap API calls',
  26         default='127.0.0.1'
  27     )
  28     subparser.add_argument(
  29         '--auth-sandbox',
  30         help='Whether to use the sandbox server',
  31         action='store_true'
  32     )
  33 
  34 class Provider(BaseProvider):
  35 
  36     def __init__(self, options, engine_overrides=None):
  37         super(Provider, self).__init__(options, engine_overrides)
  38         self.options = options
  39         self.client = namecheap.Api(
  40             ApiUser=options.get('auth_username',''),
  41             ApiKey=options.get('auth_token',''),
  42             UserName=options.get('auth_username',''),
  43             ClientIP=options.get('auth_client_ip',''),
  44             sandbox=options.get('auth_sandbox', False),
  45             debug=False
  46         )
  47         self.domain = self.options['domain']
  48         self.domain_id = None
  49 
  50     def authenticate(self):
  51         try:
  52             domain_names = [x['Name'] for x in self.client.domains_getList()]
  53         except namecheap.ApiError:
  54             raise Exception('Authentication failed')
  55         if self.domain not in domain_names:
  56             raise Exception('The domain {} is not controlled by this Namecheap '
  57                             'account'.format(self.domain))
  58         # FIXME What is this for?
  59         self.domain_id = self.domain
  60 
  61     # Create record. If record already exists with the same content, do nothing
  62     def create_record(self, type, name, content):
  63         record = {
  64             # required
  65             'Type': type,
  66             'Name': self._relative_name(name),
  67             'Address': content
  68         }
  69         # logger.debug('create_record: %s', 'id' in payload)
  70         # return 'id' in payload
  71         self.client.domains_dns_addHost(self.domain, record)
  72         return True
  73 
  74     # List all records. Return an empty list if no records found.
  75     # type, name and content are used to filter records.
  76     # If possible filter during the query, otherwise filter after response is
  77     # received.
  78     def list_records(self, type=None, name=None, content=None, id=None):
  79 
  80 
  81         records = []
  82         raw_records = self.client.domains_dns_getHosts(self.domain)
  83         for record in raw_records:
  84             records.append(self._convert_to_lexicon(record))
  85 
  86         if id:
  87             records = [record for record in records if record['id'] == id]
  88         if type:
  89             records = [record for record in records if record['type'] == type]
  90         if name:
  91             if name.endswith('.'):
  92                 name = name[:-1]
  93             records = [record for record in records if name in record['name'] ]
  94         if content:
  95             records = [record for record in records if record['content'].lower() == content.lower()]
  96 
  97         logger.debug('list_records: %s', records)
  98         return records
  99 
  100     # Create or update a record.
  101     def update_record(self, identifier, type=None, name=None, content=None):
  102         # Delete record if it exists
  103         self.delete_record(identifier, type, name, content)
  104         return self.create_record(type, name, content)
  105 
  106     # Delete an existing record.
  107     # If record does not exist, do nothing.
  108     def delete_record(self, identifier=None, type=None, name=None, content=None):
  109 
  110         record = self.list_records(type=type, name=name, content=content, id=identifier)
  111         if record:
  112             self.client.domains_dns_delHost(self.domain, self._convert_to_namecheap(record[0]))
  113             return True
  114         else:
  115             return False
  116 
  117     def _convert_to_namecheap(self, record):
  118         """ converts from lexicon format record to namecheap format record,
  119         suitable to sending through the api to namecheap"""
  120 
  121         name = record['name']
  122         if name.endswith('.'):
  123             name = name[:-1]
  124 
  125         short_name = name[:name.find(self.domain)-1]
  126         processed_record = {
  127             'Type': record['type'],
  128             'Name': short_name,
  129             'TTL': record['ttl'],
  130             'Address': record['content'],
  131             'HostId': record['id']
  132         }
  133 
  134         return processed_record
  135 
  136     def _convert_to_lexicon(self, record):
  137         """ converts from namecheap raw record format to lexicon format record
  138         """
  139 
  140         name = record['Name']
  141         if self.domain not in name:
  142             name = "{}.{}".format(name,self.domain)
  143 
  144         processed_record = {
  145             'type': record['Type'],
  146             'name': '{0}.{1}'.format(record['Name'], self.domain),
  147             'ttl': record['TTL'],
  148             'content': record['Address'],
  149             'id': record['HostId']
  150         }
  151 
  152         return processed_record
  153
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/lexicon/providers/namecheap.py b/lexicon/providers/namecheap.py
  --- a/lexicon/providers/namecheap.py
  +++ b/lexicon/providers/namecheap.py
  @@ -3,10 +3,14 @@
   
   import logging
   
  -import namecheap
   
   from .base import Provider as BaseProvider
   
  +try:
  +    import namecheap #optional dep
  +except ImportError:
  +    pass
  +
   logger = logging.getLogger(__name__)
  
verification_info: {"golden_diff": "diff --git a/lexicon/providers/namecheap.py b/lexicon/providers/namecheap.py\n--- a/lexicon/providers/namecheap.py\n+++ b/lexicon/providers/namecheap.py\n@@ -3,10 +3,14 @@\n \n import logging\n \n-import namecheap\n \n from .base import Provider as BaseProvider\n \n+try:\n+    import namecheap #optional dep\n+except ImportError:\n+    pass\n+\n logger = logging.getLogger(__name__)\n", "issue": "Namecheap support not optional\nUnlike route53 or softlayer and unlike what setup.py suggests, the namecheap provider is not optional in 2.1.17.\n", "before_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import print_function\n\nimport logging\n\nimport namecheap\n\nfrom .base import Provider as BaseProvider\n\nlogger = logging.getLogger(__name__)\n\n\ndef ProviderParser(subparser):\n    subparser.add_argument(\n        '--auth-token',\n        help='specify api token used to authenticate'\n    )\n    subparser.add_argument(\n        '--auth-username',\n        help='specify email address used to authenticate'\n    )\n    # FIXME What is the client IP used for?\n    subparser.add_argument(\n        '--auth-client-ip',\n        help='Client IP address to send to Namecheap API calls',\n        default='127.0.0.1'\n    )\n    subparser.add_argument(\n        '--auth-sandbox',\n        help='Whether to use the sandbox server',\n        action='store_true'\n    )\n\nclass Provider(BaseProvider):\n\n    def __init__(self, options, engine_overrides=None):\n        super(Provider, self).__init__(options, engine_overrides)\n        self.options = options\n        self.client = namecheap.Api(\n            ApiUser=options.get('auth_username',''),\n            ApiKey=options.get('auth_token',''),\n            UserName=options.get('auth_username',''),\n            ClientIP=options.get('auth_client_ip',''),\n            sandbox=options.get('auth_sandbox', False),\n            debug=False\n        )\n        self.domain = self.options['domain']\n        self.domain_id = None\n\n    def authenticate(self):\n        try:\n            domain_names = [x['Name'] for x in self.client.domains_getList()]\n        except namecheap.ApiError:\n            raise Exception('Authentication failed')\n        if self.domain not in domain_names:\n            raise Exception('The domain {} is not controlled by this Namecheap '\n                            'account'.format(self.domain))\n        # FIXME What is this for?\n        self.domain_id = self.domain\n\n    # Create record. If record already exists with the same content, do nothing\n    def create_record(self, type, name, content):\n        record = {\n            # required\n            'Type': type,\n            'Name': self._relative_name(name),\n            'Address': content\n        }\n        # logger.debug('create_record: %s', 'id' in payload)\n        # return 'id' in payload\n        self.client.domains_dns_addHost(self.domain, record)\n        return True\n\n    # List all records. Return an empty list if no records found.\n    # type, name and content are used to filter records.\n    # If possible filter during the query, otherwise filter after response is\n    # received.\n    def list_records(self, type=None, name=None, content=None, id=None):\n\n\n        records = []\n        raw_records = self.client.domains_dns_getHosts(self.domain)\n        for record in raw_records:\n            records.append(self._convert_to_lexicon(record))\n\n        if id:\n            records = [record for record in records if record['id'] == id]\n        if type:\n            records = [record for record in records if record['type'] == type]\n        if name:\n            if name.endswith('.'):\n                name = name[:-1]\n            records = [record for record in records if name in record['name'] ]\n        if content:\n            records = [record for record in records if record['content'].lower() == content.lower()]\n\n        logger.debug('list_records: %s', records)\n        return records\n\n    # Create or update a record.\n    def update_record(self, identifier, type=None, name=None, content=None):\n        # Delete record if it exists\n        self.delete_record(identifier, type, name, content)\n        return self.create_record(type, name, content)\n\n    # Delete an existing record.\n    # If record does not exist, do nothing.\n    def delete_record(self, identifier=None, type=None, name=None, content=None):\n\n        record = self.list_records(type=type, name=name, content=content, id=identifier)\n        if record:\n            self.client.domains_dns_delHost(self.domain, self._convert_to_namecheap(record[0]))\n            return True\n        else:\n            return False\n\n    def _convert_to_namecheap(self, record):\n        \"\"\" converts from lexicon format record to namecheap format record,\n        suitable to sending through the api to namecheap\"\"\"\n\n        name = record['name']\n        if name.endswith('.'):\n            name = name[:-1]\n\n        short_name = name[:name.find(self.domain)-1]\n        processed_record = {\n            'Type': record['type'],\n            'Name': short_name,\n            'TTL': record['ttl'],\n            'Address': record['content'],\n            'HostId': record['id']\n        }\n\n        return processed_record\n\n    def _convert_to_lexicon(self, record):\n        \"\"\" converts from namecheap raw record format to lexicon format record\n        \"\"\"\n\n        name = record['Name']\n        if self.domain not in name:\n            name = \"{}.{}\".format(name,self.domain)\n\n        processed_record = {\n            'type': record['Type'],\n            'name': '{0}.{1}'.format(record['Name'], self.domain),\n            'ttl': record['TTL'],\n            'content': record['Address'],\n            'id': record['HostId']\n        }\n\n        return processed_record\n", "path": "lexicon/providers/namecheap.py"}], "after_files": [{"content": "from __future__ import absolute_import\nfrom __future__ import print_function\n\nimport logging\n\n\nfrom .base import Provider as BaseProvider\n\ntry:\n    import namecheap #optional dep\nexcept ImportError:\n    pass\n\nlogger = logging.getLogger(__name__)\n\n\ndef ProviderParser(subparser):\n    subparser.add_argument(\n        '--auth-token',\n        help='specify api token used to authenticate'\n    )\n    subparser.add_argument(\n        '--auth-username',\n        help='specify email address used to authenticate'\n    )\n    # FIXME What is the client IP used for?\n    subparser.add_argument(\n        '--auth-client-ip',\n        help='Client IP address to send to Namecheap API calls',\n        default='127.0.0.1'\n    )\n    subparser.add_argument(\n        '--auth-sandbox',\n        help='Whether to use the sandbox server',\n        action='store_true'\n    )\n\nclass Provider(BaseProvider):\n\n    def __init__(self, options, engine_overrides=None):\n        super(Provider, self).__init__(options, engine_overrides)\n        self.options = options\n        self.client = namecheap.Api(\n            ApiUser=options.get('auth_username',''),\n            ApiKey=options.get('auth_token',''),\n            UserName=options.get('auth_username',''),\n            ClientIP=options.get('auth_client_ip',''),\n            sandbox=options.get('auth_sandbox', False),\n            debug=False\n        )\n        self.domain = self.options['domain']\n        self.domain_id = None\n\n    def authenticate(self):\n        try:\n            domain_names = [x['Name'] for x in self.client.domains_getList()]\n        except namecheap.ApiError:\n            raise Exception('Authentication failed')\n        if self.domain not in domain_names:\n            raise Exception('The domain {} is not controlled by this Namecheap '\n                            'account'.format(self.domain))\n        # FIXME What is this for?\n        self.domain_id = self.domain\n\n    # Create record. If record already exists with the same content, do nothing\n    def create_record(self, type, name, content):\n        record = {\n            # required\n            'Type': type,\n            'Name': self._relative_name(name),\n            'Address': content\n        }\n        # logger.debug('create_record: %s', 'id' in payload)\n        # return 'id' in payload\n        self.client.domains_dns_addHost(self.domain, record)\n        return True\n\n    # List all records. Return an empty list if no records found.\n    # type, name and content are used to filter records.\n    # If possible filter during the query, otherwise filter after response is\n    # received.\n    def list_records(self, type=None, name=None, content=None, id=None):\n\n\n        records = []\n        raw_records = self.client.domains_dns_getHosts(self.domain)\n        for record in raw_records:\n            records.append(self._convert_to_lexicon(record))\n\n        if id:\n            records = [record for record in records if record['id'] == id]\n        if type:\n            records = [record for record in records if record['type'] == type]\n        if name:\n            if name.endswith('.'):\n                name = name[:-1]\n            records = [record for record in records if name in record['name'] ]\n        if content:\n            records = [record for record in records if record['content'].lower() == content.lower()]\n\n        logger.debug('list_records: %s', records)\n        return records\n\n    # Create or update a record.\n    def update_record(self, identifier, type=None, name=None, content=None):\n        # Delete record if it exists\n        self.delete_record(identifier, type, name, content)\n        return self.create_record(type, name, content)\n\n    # Delete an existing record.\n    # If record does not exist, do nothing.\n    def delete_record(self, identifier=None, type=None, name=None, content=None):\n\n        record = self.list_records(type=type, name=name, content=content, id=identifier)\n        if record:\n            self.client.domains_dns_delHost(self.domain, self._convert_to_namecheap(record[0]))\n            return True\n        else:\n            return False\n\n    def _convert_to_namecheap(self, record):\n        \"\"\" converts from lexicon format record to namecheap format record,\n        suitable to sending through the api to namecheap\"\"\"\n\n        name = record['name']\n        if name.endswith('.'):\n            name = name[:-1]\n\n        short_name = name[:name.find(self.domain)-1]\n        processed_record = {\n            'Type': record['type'],\n            'Name': short_name,\n            'TTL': record['ttl'],\n            'Address': record['content'],\n            'HostId': record['id']\n        }\n\n        return processed_record\n\n    def _convert_to_lexicon(self, record):\n        \"\"\" converts from namecheap raw record format to lexicon format record\n        \"\"\"\n\n        name = record['Name']\n        if self.domain not in name:\n            name = \"{}.{}\".format(name,self.domain)\n\n        processed_record = {\n            'type': record['Type'],\n            'name': '{0}.{1}'.format(record['Name'], self.domain),\n            'ttl': record['TTL'],\n            'content': record['Address'],\n            'id': record['HostId']\n        }\n\n        return processed_record\n", "path": "lexicon/providers/namecheap.py"}]}