diff --git a/.travis.yml b/.travis.yml
index 0e907f0..9a1fcce 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,28 +3,29 @@ sudo: required
 language: python
 python:
   - "3.6"
-before_script:
-  - sudo addgroup lxd || true
-  - sudo usermod -a -G lxd $USER || true
-  - sudo ln -s /snap/bin/juju /usr/bin/juju
-  - sudo ln -s /snap/bin/lxc /usr/bin/lxc
 before_install:
   - sudo add-apt-repository -y ppa:jonathonf/python-3.6
   - sudo add-apt-repository ppa:chris-lea/libsodium -y
   - sudo apt-get update -q
   - sudo apt-get remove -qy lxd lxd-client
   - sudo apt-get install snapd libsodium-dev -y
-  - sudo snap install lxd || true
+install:
+  - sudo snap install lxd || true  # ignore failures so that unit tests will still run, at least
+  - sudo snap install juju --classic --$JUJU_CHANNEL || true
   - sudo snap install juju-wait --classic || true
-install: pip install tox-travis
+  - pip install tox-travis
 env:
   global: >
     TEST_AGENTS='{"agents":[{"url":"https://api.staging.jujucharms.com/identity","username":"libjuju-ci@yellow"}],"key":{"private":"88OOCxIHQNguRG7zFg2y2Hx5Ob0SeVKKBRnjyehverc=","public":"fDn20+5FGyN2hYO7z0rFUyoHGUnfrleslUNtoYsjNSs="}}'
+    PATH="/snap/bin:$PATH"
   matrix:
     - JUJU_CHANNEL=stable
     - JUJU_CHANNEL=edge
+before_script:
+  - sudo bash -c 'for i in 5 10 15 30; do [[ -e /var/snap/lxd/common/lxd/unix.socket ]] && break; sleep $i; done'
+  - sudo lxd init --auto || true
+  - sudo addgroup lxd || true
+  - sudo usermod -a -G lxd $USER || true
 script:
-  - sudo snap install juju --classic --$JUJU_CHANNEL
-  - sudo ln -s /snap/bin/juju /usr/bin/juju || true
-  - sudo -E sudo -u $USER -E /snap/bin/juju bootstrap localhost test --config 'identity-url=https://api.staging.jujucharms.com/identity' --config 'allow-model-access=true'
+  - sudo -E sudo -u $USER -E juju bootstrap localhost test --config 'identity-url=https://api.staging.jujucharms.com/identity' --config 'allow-model-access=true'
   - tox -e py35,integration
diff --git a/juju/constraints.py b/juju/constraints.py
index 998862d..0050673 100644
--- a/juju/constraints.py
+++ b/juju/constraints.py
@@ -29,6 +29,8 @@ FACTORS = {
     "P": 1024 * 1024 * 1024
 }
 
+LIST_KEYS = {'tags', 'spaces'}
+
 SNAKE1 = re.compile(r'(.)([A-Z][a-z]+)')
 SNAKE2 = re.compile('([a-z0-9])([A-Z])')
 
@@ -47,8 +49,10 @@ def parse(constraints):
         return constraints
 
     constraints = {
-        normalize_key(k): normalize_value(v) for k, v in [
-            s.split("=") for s in constraints.split(" ")]}
+        normalize_key(k): (
+            normalize_list_value(v) if k in LIST_KEYS else
+            normalize_value(v)
+        ) for k, v in [s.split("=") for s in constraints.split(" ")]}
 
     return constraints
 
@@ -72,13 +76,12 @@ def normalize_value(value):
         # Translate aliases to Megabytes. e.g. 1G = 10240
         return int(value[:-1]) * FACTORS[value[-1:]]
 
-    if "," in value:
-        # Handle csv strings.
-        values = value.split(",")
-        values = [normalize_value(v) for v in values]
-        return values
-
     if value.isdigit():
         return int(value)
 
     return value
+
+
+def normalize_list_value(value):
+    values = value.strip().split(',')
+    return [normalize_value(value) for value in values]

Single tag constraint causes JujuAPIError
When a constraint spec is given to deploy or in a bundle with a single tag constraint (e.g., `tags=node1234` rather than `tags=node1234,othertag`) it causes the following exception:

```
Traceback (most recent call last):
  File "/snap/conjure-up/987/lib/python3.6/site-packages/conjureup/controllers/deploy/common.py", line 24, in do_deploy
    await app.juju.client.deploy(fn)
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/model.py", line 1186, in deploy
    await handler.execute_plan()
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/model.py", line 1780, in execute_plan
    result = await method(*step.args)
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/model.py", line 1927, in deploy
    storage=storage,
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/model.py", line 1299, in _deploy
    result = await app_facade.Deploy([app])
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/client/facade.py", line 412, in wrapper
    reply = await f(*args, **kwargs)
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/client/_client5.py", line 503, in Deploy
    reply = await self.rpc(msg)
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/client/facade.py", line 537, in rpc
    result = await self.connection.rpc(msg, encoder=TypeEncoder)
  File "/snap/conjure-up/987/lib/python3.6/site-packages/juju/client/connection.py", line 314, in rpc
    raise errors.JujuAPIError(result)
juju.errors.JujuAPIError: json: cannot unmarshal string into Go struct field Value.tags of type []string
```

This is due to the constraints parsing [only creating a list if there is a comma](https://github.com/juju/python-libjuju/blob/master/juju/constraints.py#L75) whereas it needs to happen always for `tags` and `spaces`.
diff --git a/tests/unit/test_constraints.py b/tests/unit/test_constraints.py
index 00b9156..3c52090 100644
--- a/tests/unit/test_constraints.py
+++ b/tests/unit/test_constraints.py
@@ -32,6 +32,12 @@ class TestConstraints(unittest.TestCase):
         self.assertEqual(_("10G"), 10 * 1024)
         self.assertEqual(_("10M"), 10)
         self.assertEqual(_("10"), 10)
+        self.assertEqual(_("foo,bar"), "foo,bar")
+
+    def test_normalize_list_val(self):
+        _ = constraints.normalize_list_value
+
+        self.assertEqual(_("foo"), ["foo"])
         self.assertEqual(_("foo,bar"), ["foo", "bar"])
 
     def test_parse_constraints(self):
@@ -43,6 +49,9 @@ class TestConstraints(unittest.TestCase):
         )
 
         self.assertEqual(
-            _("mem=10G foo=bar,baz"),
-            {"mem": 10 * 1024, "foo": ["bar", "baz"]}
+            _("mem=10G foo=bar,baz tags=tag1 spaces=space1,space2"),
+            {"mem": 10 * 1024,
+             "foo": "bar,baz",
+             "tags": ["tag1"],
+             "spaces": ["space1", "space2"]}
         )

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest
3.9
docs/requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
babel==2.17.0
certifi==2025.1.31
cffi==1.17.1
charset-normalizer==3.4.1
docutils==0.18.1
exceptiongroup==1.2.2
idna==3.10
imagesize==1.4.1
iniconfig==2.1.0
Jinja2==3.1.6
-e git+https://github.com/juju/python-libjuju.git@668945a53cdf696bb2d6d8da518a07094b22c7c7#egg=juju
jujubundlelib==0.5.7
macaroonbakery==1.3.4
MarkupSafe==3.0.2
packaging==24.2
pluggy==1.5.0
protobuf==6.30.2
pycparser==2.22
Pygments==2.19.1
pymacaroons==0.13.0
PyNaCl==1.5.0
pyRFC3339==1.1
pytest==8.3.5
pytz==2017.3
PyYAML==3.13
requests==2.32.3
six==1.17.0
snowballstemmer==2.2.0
Sphinx==1.6.5
sphinx-rtd-theme==1.2.1
sphinxcontrib-asyncio==0.2.0
sphinxcontrib-jquery==2.0.0
sphinxcontrib-serializinghtml==2.0.0
sphinxcontrib-websupport==1.2.4
theblues==0.5.2
tomli==2.2.1
urllib3==2.3.0
websockets==4.0.1

name: python-libjuju
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - babel==2.17.0
      - certifi==2025.1.31
      - cffi==1.17.1
      - charset-normalizer==3.4.1
      - docutils==0.18.1
      - exceptiongroup==1.2.2
      - idna==3.10
      - imagesize==1.4.1
      - iniconfig==2.1.0
      - jinja2==3.1.6
      - jujubundlelib==0.5.7
      - macaroonbakery==1.3.4
      - markupsafe==3.0.2
      - packaging==24.2
      - pluggy==1.5.0
      - protobuf==6.30.2
      - pycparser==2.22
      - pygments==2.19.1
      - pymacaroons==0.13.0
      - pynacl==1.5.0
      - pyrfc3339==1.1
      - pytest==8.3.5
      - pytz==2017.3
      - pyyaml==3.13
      - requests==2.32.3
      - six==1.17.0
      - snowballstemmer==2.2.0
      - sphinx==1.6.5
      - sphinx-rtd-theme==1.2.1
      - sphinxcontrib-asyncio==0.2.0
      - sphinxcontrib-jquery==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - sphinxcontrib-websupport==1.2.4
      - theblues==0.5.2
      - tomli==2.2.1
      - urllib3==2.3.0
      - websockets==4.0.1
prefix: /opt/conda/envs/python-libjuju

tests/unit/test_constraints.py::TestConstraints::test_normalize_list_val tests/unit/test_constraints.py::TestConstraints::test_normalize_val tests/unit/test_constraints.py::TestConstraints::test_parse_constraints
tests/unit/test_constraints.py::TestConstraints::test_mem_regex tests/unit/test_constraints.py::TestConstraints::test_normalize_key
juju/constraints.py .travis.yml
juju/constraints.py .travis.yml