prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  split_port() does not properly handle ":80" or "127.0.0.1:" properly
  Initially reported as https://github.com/docker/compose/issues/1887 
  
  Example:
  
  ``` python
      def test_port_only_with_colon(self):
          self.assertRaises(ValueError,
                            lambda: split_port(":80"))
  
      def test_host_only_with_colon(self):
          self.assertRaises(ValueError,
                            lambda: split_port("localhost:"))
  ```
  
  Results:
  
  ```
  ======================================================================
  ERROR: test_host_only_with_colon (__main__.UtilsTest)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "tests/utils_test.py", line 428, in test_host_only_with_colon
      lambda: split_port("localhost:"))
    File "/usr/lib/python2.7/unittest/case.py", line 473, in assertRaises
      callableObj(*args, **kwargs)
    File "tests/utils_test.py", line 428, in <lambda>
      lambda: split_port("localhost:"))
    File "/home/mark/Projects/docker-py/docker/utils/ports/ports.py", line 77, in split_port
      if len(internal_range) != len(external_range):
  TypeError: object of type 'NoneType' has no len()
  
  ======================================================================
  ERROR: test_port_only_with_colon (__main__.UtilsTest)
  ----------------------------------------------------------------------
  Traceback (most recent call last):
    File "tests/utils_test.py", line 424, in test_port_only_with_colon
      lambda: split_port(":80"))
    File "/usr/lib/python2.7/unittest/case.py", line 473, in assertRaises
      callableObj(*args, **kwargs)
    File "tests/utils_test.py", line 424, in <lambda>
      lambda: split_port(":80"))
    File "/home/mark/Projects/docker-py/docker/utils/ports/ports.py", line 77, in split_port
      if len(internal_range) != len(external_range):
  TypeError: object of type 'NoneType' has no len()
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `docker/utils/ports/ports.py`
  Content:
  ```
  1 
  2 
  3 def add_port_mapping(port_bindings, internal_port, external):
  4     if internal_port in port_bindings:
  5         port_bindings[internal_port].append(external)
  6     else:
  7         port_bindings[internal_port] = [external]
  8 
  9 
  10 def add_port(port_bindings, internal_port_range, external_range):
  11     if external_range is None:
  12         for internal_port in internal_port_range:
  13             add_port_mapping(port_bindings, internal_port, None)
  14     else:
  15         ports = zip(internal_port_range, external_range)
  16         for internal_port, external_port in ports:
  17             add_port_mapping(port_bindings, internal_port, external_port)
  18 
  19 
  20 def build_port_bindings(ports):
  21     port_bindings = {}
  22     for port in ports:
  23         internal_port_range, external_range = split_port(port)
  24         add_port(port_bindings, internal_port_range, external_range)
  25     return port_bindings
  26 
  27 
  28 def to_port_range(port):
  29     if not port:
  30         return None
  31 
  32     protocol = ""
  33     if "/" in port:
  34         parts = port.split("/")
  35         if len(parts) != 2:
  36             raise ValueError('Invalid port "%s", should be '
  37                              '[[remote_ip:]remote_port[-remote_port]:]'
  38                              'port[/protocol]' % port)
  39         port, protocol = parts
  40         protocol = "/" + protocol
  41 
  42     parts = str(port).split('-')
  43 
  44     if len(parts) == 1:
  45         return ["%s%s" % (port, protocol)]
  46 
  47     if len(parts) == 2:
  48         full_port_range = range(int(parts[0]), int(parts[1]) + 1)
  49         return ["%s%s" % (p, protocol) for p in full_port_range]
  50 
  51     raise ValueError('Invalid port range "%s", should be '
  52                      'port or startport-endport' % port)
  53 
  54 
  55 def split_port(port):
  56     parts = str(port).split(':')
  57     if not 1 <= len(parts) <= 3:
  58         raise ValueError('Invalid port "%s", should be '
  59                          '[[remote_ip:]remote_port:]port[/protocol]' % port)
  60 
  61     if len(parts) == 1:
  62         internal_port, = parts
  63         return to_port_range(internal_port), None
  64     if len(parts) == 2:
  65         external_port, internal_port = parts
  66 
  67         internal_range = to_port_range(internal_port)
  68         external_range = to_port_range(external_port)
  69         if len(internal_range) != len(external_range):
  70             raise ValueError('Port ranges don\'t match in length')
  71 
  72         return internal_range, external_range
  73 
  74     external_ip, external_port, internal_port = parts
  75     internal_range = to_port_range(internal_port)
  76     external_range = to_port_range(external_port)
  77     if not external_range:
  78         external_range = [None] * len(internal_range)
  79 
  80     if len(internal_range) != len(external_range):
  81         raise ValueError('Port ranges don\'t match in length')
  82 
  83     return internal_range, [(external_ip, ex_port or None)
  84                             for ex_port in external_range]
  85
  ```
  --- 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/docker/utils/ports/ports.py b/docker/utils/ports/ports.py
  --- a/docker/utils/ports/ports.py
  +++ b/docker/utils/ports/ports.py
  @@ -1,5 +1,4 @@
   
  -
   def add_port_mapping(port_bindings, internal_port, external):
       if internal_port in port_bindings:
           port_bindings[internal_port].append(external)
  @@ -33,9 +32,8 @@
       if "/" in port:
           parts = port.split("/")
           if len(parts) != 2:
  -            raise ValueError('Invalid port "%s", should be '
  -                             '[[remote_ip:]remote_port[-remote_port]:]'
  -                             'port[/protocol]' % port)
  +            _raise_invalid_port(port)
  +
           port, protocol = parts
           protocol = "/" + protocol
   
  @@ -52,11 +50,17 @@
                        'port or startport-endport' % port)
   
   
  +def _raise_invalid_port(port):
  +    raise ValueError('Invalid port "%s", should be '
  +                     '[[remote_ip:]remote_port[-remote_port]:]'
  +                     'port[/protocol]' % port)
  +
  +
   def split_port(port):
       parts = str(port).split(':')
  +
       if not 1 <= len(parts) <= 3:
  -        raise ValueError('Invalid port "%s", should be '
  -                         '[[remote_ip:]remote_port:]port[/protocol]' % port)
  +        _raise_invalid_port(port)
   
       if len(parts) == 1:
           internal_port, = parts
  @@ -66,6 +70,10 @@
   
           internal_range = to_port_range(internal_port)
           external_range = to_port_range(external_port)
  +
  +        if internal_range is None or external_range is None:
  +            _raise_invalid_port(port)
  +
           if len(internal_range) != len(external_range):
               raise ValueError('Port ranges don\'t match in length')
  
verification_info: {"golden_diff": "diff --git a/docker/utils/ports/ports.py b/docker/utils/ports/ports.py\n--- a/docker/utils/ports/ports.py\n+++ b/docker/utils/ports/ports.py\n@@ -1,5 +1,4 @@\n \n-\n def add_port_mapping(port_bindings, internal_port, external):\n     if internal_port in port_bindings:\n         port_bindings[internal_port].append(external)\n@@ -33,9 +32,8 @@\n     if \"/\" in port:\n         parts = port.split(\"/\")\n         if len(parts) != 2:\n-            raise ValueError('Invalid port \"%s\", should be '\n-                             '[[remote_ip:]remote_port[-remote_port]:]'\n-                             'port[/protocol]' % port)\n+            _raise_invalid_port(port)\n+\n         port, protocol = parts\n         protocol = \"/\" + protocol\n \n@@ -52,11 +50,17 @@\n                      'port or startport-endport' % port)\n \n \n+def _raise_invalid_port(port):\n+    raise ValueError('Invalid port \"%s\", should be '\n+                     '[[remote_ip:]remote_port[-remote_port]:]'\n+                     'port[/protocol]' % port)\n+\n+\n def split_port(port):\n     parts = str(port).split(':')\n+\n     if not 1 <= len(parts) <= 3:\n-        raise ValueError('Invalid port \"%s\", should be '\n-                         '[[remote_ip:]remote_port:]port[/protocol]' % port)\n+        _raise_invalid_port(port)\n \n     if len(parts) == 1:\n         internal_port, = parts\n@@ -66,6 +70,10 @@\n \n         internal_range = to_port_range(internal_port)\n         external_range = to_port_range(external_port)\n+\n+        if internal_range is None or external_range is None:\n+            _raise_invalid_port(port)\n+\n         if len(internal_range) != len(external_range):\n             raise ValueError('Port ranges don\\'t match in length')\n", "issue": "split_port() does not properly handle \":80\" or \"127.0.0.1:\" properly\nInitially reported as https://github.com/docker/compose/issues/1887 \n\nExample:\n\n``` python\n    def test_port_only_with_colon(self):\n        self.assertRaises(ValueError,\n                          lambda: split_port(\":80\"))\n\n    def test_host_only_with_colon(self):\n        self.assertRaises(ValueError,\n                          lambda: split_port(\"localhost:\"))\n```\n\nResults:\n\n```\n======================================================================\nERROR: test_host_only_with_colon (__main__.UtilsTest)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n  File \"tests/utils_test.py\", line 428, in test_host_only_with_colon\n    lambda: split_port(\"localhost:\"))\n  File \"/usr/lib/python2.7/unittest/case.py\", line 473, in assertRaises\n    callableObj(*args, **kwargs)\n  File \"tests/utils_test.py\", line 428, in <lambda>\n    lambda: split_port(\"localhost:\"))\n  File \"/home/mark/Projects/docker-py/docker/utils/ports/ports.py\", line 77, in split_port\n    if len(internal_range) != len(external_range):\nTypeError: object of type 'NoneType' has no len()\n\n======================================================================\nERROR: test_port_only_with_colon (__main__.UtilsTest)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n  File \"tests/utils_test.py\", line 424, in test_port_only_with_colon\n    lambda: split_port(\":80\"))\n  File \"/usr/lib/python2.7/unittest/case.py\", line 473, in assertRaises\n    callableObj(*args, **kwargs)\n  File \"tests/utils_test.py\", line 424, in <lambda>\n    lambda: split_port(\":80\"))\n  File \"/home/mark/Projects/docker-py/docker/utils/ports/ports.py\", line 77, in split_port\n    if len(internal_range) != len(external_range):\nTypeError: object of type 'NoneType' has no len()\n```\n\n", "before_files": [{"content": "\n\ndef add_port_mapping(port_bindings, internal_port, external):\n    if internal_port in port_bindings:\n        port_bindings[internal_port].append(external)\n    else:\n        port_bindings[internal_port] = [external]\n\n\ndef add_port(port_bindings, internal_port_range, external_range):\n    if external_range is None:\n        for internal_port in internal_port_range:\n            add_port_mapping(port_bindings, internal_port, None)\n    else:\n        ports = zip(internal_port_range, external_range)\n        for internal_port, external_port in ports:\n            add_port_mapping(port_bindings, internal_port, external_port)\n\n\ndef build_port_bindings(ports):\n    port_bindings = {}\n    for port in ports:\n        internal_port_range, external_range = split_port(port)\n        add_port(port_bindings, internal_port_range, external_range)\n    return port_bindings\n\n\ndef to_port_range(port):\n    if not port:\n        return None\n\n    protocol = \"\"\n    if \"/\" in port:\n        parts = port.split(\"/\")\n        if len(parts) != 2:\n            raise ValueError('Invalid port \"%s\", should be '\n                             '[[remote_ip:]remote_port[-remote_port]:]'\n                             'port[/protocol]' % port)\n        port, protocol = parts\n        protocol = \"/\" + protocol\n\n    parts = str(port).split('-')\n\n    if len(parts) == 1:\n        return [\"%s%s\" % (port, protocol)]\n\n    if len(parts) == 2:\n        full_port_range = range(int(parts[0]), int(parts[1]) + 1)\n        return [\"%s%s\" % (p, protocol) for p in full_port_range]\n\n    raise ValueError('Invalid port range \"%s\", should be '\n                     'port or startport-endport' % port)\n\n\ndef split_port(port):\n    parts = str(port).split(':')\n    if not 1 <= len(parts) <= 3:\n        raise ValueError('Invalid port \"%s\", should be '\n                         '[[remote_ip:]remote_port:]port[/protocol]' % port)\n\n    if len(parts) == 1:\n        internal_port, = parts\n        return to_port_range(internal_port), None\n    if len(parts) == 2:\n        external_port, internal_port = parts\n\n        internal_range = to_port_range(internal_port)\n        external_range = to_port_range(external_port)\n        if len(internal_range) != len(external_range):\n            raise ValueError('Port ranges don\\'t match in length')\n\n        return internal_range, external_range\n\n    external_ip, external_port, internal_port = parts\n    internal_range = to_port_range(internal_port)\n    external_range = to_port_range(external_port)\n    if not external_range:\n        external_range = [None] * len(internal_range)\n\n    if len(internal_range) != len(external_range):\n        raise ValueError('Port ranges don\\'t match in length')\n\n    return internal_range, [(external_ip, ex_port or None)\n                            for ex_port in external_range]\n", "path": "docker/utils/ports/ports.py"}], "after_files": [{"content": "\ndef add_port_mapping(port_bindings, internal_port, external):\n    if internal_port in port_bindings:\n        port_bindings[internal_port].append(external)\n    else:\n        port_bindings[internal_port] = [external]\n\n\ndef add_port(port_bindings, internal_port_range, external_range):\n    if external_range is None:\n        for internal_port in internal_port_range:\n            add_port_mapping(port_bindings, internal_port, None)\n    else:\n        ports = zip(internal_port_range, external_range)\n        for internal_port, external_port in ports:\n            add_port_mapping(port_bindings, internal_port, external_port)\n\n\ndef build_port_bindings(ports):\n    port_bindings = {}\n    for port in ports:\n        internal_port_range, external_range = split_port(port)\n        add_port(port_bindings, internal_port_range, external_range)\n    return port_bindings\n\n\ndef to_port_range(port):\n    if not port:\n        return None\n\n    protocol = \"\"\n    if \"/\" in port:\n        parts = port.split(\"/\")\n        if len(parts) != 2:\n            _raise_invalid_port(port)\n\n        port, protocol = parts\n        protocol = \"/\" + protocol\n\n    parts = str(port).split('-')\n\n    if len(parts) == 1:\n        return [\"%s%s\" % (port, protocol)]\n\n    if len(parts) == 2:\n        full_port_range = range(int(parts[0]), int(parts[1]) + 1)\n        return [\"%s%s\" % (p, protocol) for p in full_port_range]\n\n    raise ValueError('Invalid port range \"%s\", should be '\n                     'port or startport-endport' % port)\n\n\ndef _raise_invalid_port(port):\n    raise ValueError('Invalid port \"%s\", should be '\n                     '[[remote_ip:]remote_port[-remote_port]:]'\n                     'port[/protocol]' % port)\n\n\ndef split_port(port):\n    parts = str(port).split(':')\n\n    if not 1 <= len(parts) <= 3:\n        _raise_invalid_port(port)\n\n    if len(parts) == 1:\n        internal_port, = parts\n        return to_port_range(internal_port), None\n    if len(parts) == 2:\n        external_port, internal_port = parts\n\n        internal_range = to_port_range(internal_port)\n        external_range = to_port_range(external_port)\n\n        if internal_range is None or external_range is None:\n            _raise_invalid_port(port)\n\n        if len(internal_range) != len(external_range):\n            raise ValueError('Port ranges don\\'t match in length')\n\n        return internal_range, external_range\n\n    external_ip, external_port, internal_port = parts\n    internal_range = to_port_range(internal_port)\n    external_range = to_port_range(external_port)\n    if not external_range:\n        external_range = [None] * len(internal_range)\n\n    if len(internal_range) != len(external_range):\n        raise ValueError('Port ranges don\\'t match in length')\n\n    return internal_range, [(external_ip, ex_port or None)\n                            for ex_port in external_range]\n", "path": "docker/utils/ports/ports.py"}]}