import re

PORT_SPEC = re.compile(
    "^"  # Match full string
    "("  # External part
    "((?P<host>[a-fA-F\d.:]+):)?"  # Address
    "(?P<ext>[\d]*)(-(?P<ext_end>[\d]+))?:"  # External range
    ")?"
    "(?P<int>[\d]+)(-(?P<int_end>[\d]+))?"  # Internal range
    "(?P<proto>/(udp|tcp))?"  # Protocol
    "$"  # Match full string
)


def add_port_mapping(port_bindings, internal_port, external):
    if internal_port in port_bindings:
        port_bindings[internal_port].append(external)
    else:
        port_bindings[internal_port] = [external]


def add_port(port_bindings, internal_port_range, external_range):
    if external_range is None:
        for internal_port in internal_port_range:
            add_port_mapping(port_bindings, internal_port, None)
    else:
        ports = zip(internal_port_range, external_range)
        for internal_port, external_port in ports:
            add_port_mapping(port_bindings, internal_port, external_port)


def build_port_bindings(ports):
    port_bindings = {}
    for port in ports:
        internal_port_range, external_range = split_port(port)
        add_port(port_bindings, internal_port_range, external_range)
    return port_bindings


def _raise_invalid_port(port):
    raise ValueError('Invalid port "%s", should be '
                     '[[remote_ip:]remote_port[-remote_port]:]'
                     'port[/protocol]' % port)


def port_range(start, end, proto, randomly_available_port=False):
    if not start:
        return start
    if not end:
        return [start + proto]
    if randomly_available_port:
        return ['{}-{}'.format(start, end) + proto]
    return [str(port) + proto for port in range(int(start), int(end) + 1)]


def split_port(port):
    match = PORT_SPEC.match(port)
    if match is None:
        _raise_invalid_port(port)
    parts = match.groupdict()

    host = parts['host']
    proto = parts['proto'] or ''
    internal = port_range(parts['int'], parts['int_end'], proto)
    external = port_range(
        parts['ext'], parts['ext_end'], '', len(internal) == 1)

    if host is None:
        if external is not None and len(internal) != len(external):
            raise ValueError('Port ranges don\'t match in length')
        return internal, external
    else:
        if not external:
            external = [None] * len(internal)
        elif len(internal) != len(external):
            raise ValueError('Port ranges don\'t match in length')
        return internal, [(host, ext_port) for ext_port in external]

docker/utils/ports.py
import re

PORT_SPEC = re.compile(
    "^"  # Match full string
    "("  # External part
    "((?P<host>[a-fA-F\d.:]+):)?"  # Address
    "(?P<ext>[\d]*)(-(?P<ext_end>[\d]+))?:"  # External range
    ")?"
    "(?P<int>[\d]+)(-(?P<int_end>[\d]+))?"  # Internal range
    "(?P<proto>/(udp|tcp))?"  # Protocol
    "$"  # Match full string
)


def add_port_mapping(port_bindings, internal_port, external):
    if internal_port in port_bindings:
        port_bindings[internal_port].append(external)
    else:
        port_bindings[internal_port] = [external]


def add_port(port_bindings, internal_port_range, external_range):
    if external_range is None:
        for internal_port in internal_port_range:
            add_port_mapping(port_bindings, internal_port, None)
    else:
        ports = zip(internal_port_range, external_range)
        for internal_port, external_port in ports:
            add_port_mapping(port_bindings, internal_port, external_port)


def build_port_bindings(ports):
    port_bindings = {}
    for port in ports:
        internal_port_range, external_range = split_port(port)
        add_port(port_bindings, internal_port_range, external_range)
    return port_bindings


def _raise_invalid_port(port):
    raise ValueError('Invalid port "%s", should be '
                     '[[remote_ip:]remote_port[-remote_port]:]'
                     'port[/protocol]' % port)


def port_range(start, end, proto, randomly_available_port=False):
    if not start:
        return start
    if not end:
        return [start + proto]
    if randomly_available_port:
        return ['{}-{}'.format(start, end) + proto]
    return [str(port) + proto for port in range(int(start), int(end) + 1)]


def split_port(port):
    port = str(port)
    match = PORT_SPEC.match(port)
    if match is None:
        _raise_invalid_port(port)
    parts = match.groupdict()

    host = parts['host']
    proto = parts['proto'] or ''
    internal = port_range(parts['int'], parts['int_end'], proto)
    external = port_range(
        parts['ext'], parts['ext_end'], '', len(internal) == 1)

    if host is None:
        if external is not None and len(internal) != len(external):
            raise ValueError('Port ranges don\'t match in length')
        return internal, external
    else:
        if not external:
            external = [None] * len(internal)
        elif len(internal) != len(external):
            raise ValueError('Port ranges don\'t match in length')
        return internal, [(host, ext_port) for ext_port in external]

docker/utils/ports.py
diff --git a/docker/utils/ports.py b/docker/utils/ports.py
index 57332deee..8f713c720 100644
--- a/docker/utils/ports.py
+++ b/docker/utils/ports.py
@@ -54,6 +54,7 @@ def port_range(start, end, proto, randomly_available_port=False):
 
 
 def split_port(port):
+    port = str(port)
     match = PORT_SPEC.match(port)
     if match is None:
         _raise_invalid_port(port)
diff --git a/tests/unit/utils_test.py b/tests/unit/utils_test.py
index c25881d14..a2d463d71 100644
--- a/tests/unit/utils_test.py
+++ b/tests/unit/utils_test.py
@@ -587,6 +587,9 @@ def test_with_no_container_port(self):
     def test_split_port_empty_string(self):
         self.assertRaises(ValueError, lambda: split_port(""))
 
+    def test_split_port_non_string(self):
+        assert split_port(1243) == (['1243'], None)
+
     def test_build_port_bindings_with_one_port(self):
         port_bindings = build_port_bindings(["127.0.0.1:1000:1000"])
         self.assertEqual(port_bindings["1000"], [("127.0.0.1", "1000")])

Issue with port option in 2.4.0 version
Hi,
I update to the 2.4 today and i got issue with docker-compose when i try to add the following line to my configuration file (docker-compose.yml) : 
`ports:
            - "127.0.0.1:9292:9090"`

I got the following error:

`
ERROR: for ContainerName  expected string or buffer
Traceback (most recent call last):
  File "/usr/local/bin/docker-compose", line 11, in <module>
    sys.exit(main())
  File "/usr/local/lib/python2.7/dist-packages/compose/cli/main.py", line 68, in main
    command()
  File "/usr/local/lib/python2.7/dist-packages/compose/cli/main.py", line 118, in perform_command
    handler(command, command_options)
  File "/usr/local/lib/python2.7/dist-packages/compose/cli/main.py", line 926, in up
    scale_override=parse_scale_args(options['--scale']),
  File "/usr/local/lib/python2.7/dist-packages/compose/project.py", line 424, in up
    get_deps
  File "/usr/local/lib/python2.7/dist-packages/compose/parallel.py", line 69, in parallel_execute
    raise error_to_reraise
TypeError: expected string or buffer
`

I have no issue when i downgrade again to the 2.3 version of the package

To reproduce the issue, i use the following configuration ( it doesn't seem to depend on the image):
```
version: '2'

services :
    ContainerName:
        image: bae2d441e03a
        ports:
            - "127.0.0.1:9292:9090"
```

I run on Ubuntu 14.04.5 LTS with the following package:
```
docker==2.4.0
docker-compose==1.14.0
docker-pycreds==0.2.1
dockerpty==0.4.1
Python 2.7.6
Client:
 Version:      17.05.0-ce
 API version:  1.29
 Go version:   go1.7.5
 Git commit:   89658be
 Built:        Thu May  4 22:06:06 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.05.0-ce
 API version:  1.29 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   89658be
 Built:        Thu May  4 22:06:06 2017
 OS/Arch:      linux/amd64
 Experimental: false
```
