diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 276e15208bf0aed2be13a19c8f609c53d0b93c7e..6def48ede0d8b0ece3952f61173415d265f2aa4e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -26,11 +26,6 @@ stages:
   - pages
   - release
 
-
-.install_pip: &install_pip |-
-  apt-get -y update && apt-get install -yq curl python3-distutils
-  curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py
-
 clean shell runner:
   stage: .pre
   tags:
@@ -44,7 +39,7 @@ build wheel for publication: # Executed on a tag
   tags:
     - docker-executor
   script:
-    - python setup.py egg_info -b+$CI_COMMIT_SHORT_SHA sdist bdist_wheel
+    - python3 setup.py egg_info -b+$CI_COMMIT_SHORT_SHA sdist bdist_wheel
   only:
     - tags
   artifacts:
@@ -56,7 +51,7 @@ build wheel for development: # Executed on a commit
   tags:
     - docker-executor
   script:
-    - python setup.py egg_info -b+dev.$CI_COMMIT_SHORT_SHA sdist bdist_wheel
+    - python3 setup.py egg_info -b+dev.$CI_COMMIT_SHORT_SHA sdist bdist_wheel
   except:
     - tags
   artifacts:
@@ -68,12 +63,11 @@ unit tests:
   image: nexus.engageska-portugal.pt/ska-docker/tango-builder:latest
   before_script:
   - docker login -u $DOCKER_REGISTRY_USERNAME -p $DOCKER_REGISTRY_PASSWORD $DOCKER_REGISTRY_HOST
-  - *install_pip
   tags:
     - docker-executor
   script:
     - echo $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA)
-    - pip3 install -U $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA) --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple
+    - python3 -m pip install -U $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA) --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple
     - make test
     - scripts/validate-metadata.sh
   artifacts:
@@ -85,12 +79,11 @@ linting:
   image: nexus.engageska-portugal.pt/ska-docker/tango-builder:latest
   before_script:
   - docker login -u $DOCKER_REGISTRY_USERNAME -p $DOCKER_REGISTRY_PASSWORD $DOCKER_REGISTRY_HOST
-  - *install_pip
   tags:
     - docker-executor
   script:
     - echo $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA)
-    - pip3 install -U $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA) --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple
+    - python3 -m pip install -U $(ls -d ./dist/*.whl | grep $CI_COMMIT_SHORT_SHA) --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple
     - make lint
   artifacts:
     paths:
@@ -106,7 +99,7 @@ publish to nexus:
   script:
     # check metadata requirements
     - scripts/validate-metadata.sh
-    - pip install twine
+    - python3 -m pip install twine
     - twine upload --repository-url $PYPI_REPOSITORY_URL dist/*
   only:
     variables:
diff --git a/.release b/.release
index ad2f3059fa13ad985b9fc17570dceea0a5dc1b6b..7d9b5377be3c06be82ba3abd1f3cde409c1e4210 100644
--- a/.release
+++ b/.release
@@ -1,2 +1,2 @@
-release=0.4.0
-tag=lmcbaseclasses-0.4.0
+release=0.4.1
+tag=lmcbaseclasses-0.4.1
diff --git a/Dockerfile b/Dockerfile
index 19dee7a99bedd3b7f51efa660c52bf300f195f31..95534ea7fc2a4b9c3fb061f072a37f977409a9c6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,10 +1,10 @@
 # Use SKA python image as base image
-FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:latest AS buildenv
-FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:latest AS runtime
+FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.1 AS buildenv
+FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:9.3.1 AS runtime
 
 # create ipython profile to so that itango doesn't fail if ipython hasn't run yet
 RUN ipython profile create
 
-# A temporary workaround until system team can investigate why 'pipenv install -e .' doesn't work
-RUN pip install -e . --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple
-CMD ["/venv/bin/python", "/app/skabase/SKABaseDevice/SKABaseDevice.py"]
+# Note: working dir is `/app` which will have a copy of our repo
+RUN python3 -m pip install -e . --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple
+CMD ["python3", "/app/skabase/SKABaseDevice/SKABaseDevice.py"]
diff --git a/README.md b/README.md
index e04c0d629418e5502698d88e9d982b1abcc972bb..6d1ad22af5a33323197c41af6bff2e0b474b9fdd 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,12 @@ The lmc-base-classe repository contains set of eight classes as mentioned in SKA
 
 ## Version History
 
+#### 0.4.1
+- Fix lost properties when re-initialising test device (remove `get_name` mock).
+- Fix Sphinx doc building.
+- Move `ObsDevice` variable initialisation from `__init__` to `init_device`.
+- Run scripts with `python3` instead of `python` and update pip usage.
+
 #### 0.4.0
 - Changed all `DevEnum` attributes to use Python `enum.IntEnum` classes.  These can be imported from the
   new `control_model` namespace, e.g., `skabase.control_model import AdminMode`.
@@ -94,7 +100,7 @@ The requirements for testing are:
 ### Installation steps
 1. Clone the repository on local machine.
 2. Navigate to the root directory of the repository from terminal
-3. Run 'pip3 install . --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple'
+3. Run 'python3 -m pip install . --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple'
 
 ## Testing
 The LMC base classes can be tested locally my invoking *make CI_JOB_ID=some_id test* command.
diff --git a/scripts/validate-metadata.sh b/scripts/validate-metadata.sh
index b6aaa36013af4ec78f255aedda7021b652005501..b6ce76792dcf96f38ebc174992285a9a34a558b3 100755
--- a/scripts/validate-metadata.sh
+++ b/scripts/validate-metadata.sh
@@ -2,37 +2,37 @@
 
 # PACKAGE METADATA
 # ----------------
-if [[ $(python setup.py --name) == "UNKNOWN" ]] ; then
+if [[ $(python3 setup.py --name) == "UNKNOWN" ]] ; then
     echo "[error] metadata: name missing"
     exit 2
 fi
 
-if [[ $(python setup.py --version) == "0.0.0" ]] ; then
+if [[ $(python3 setup.py --version) == "0.0.0" ]] ; then
     echo "[error] metadata: version missing"
     exit 2
 fi
 
-if ! python setup.py --version | grep -q -E '^([0-9]+)\.([0-9]+)\.([0-9]+)$' ; then
+if ! python3 setup.py --version | grep -q -E '^([0-9]+)\.([0-9]+)\.([0-9]+)$' ; then
     echo "[error] metadata: version is not according to versioning standards"
     exit 2
 fi
 
-if [[ $(python setup.py --url) == "UNKNOWN" ]] ; then
+if [[ $(python3 setup.py --url) == "UNKNOWN" ]] ; then
     echo "[error] metadata: url missing"
     exit 2
 fi
 
-if [[ $(python setup.py --license) == "UNKNOWN" ]] ; then
+if [[ $(python3 setup.py --license) == "UNKNOWN" ]] ; then
     echo "[error] metadata: license missing"
     exit 2
 fi
 
-if [[ $(python setup.py --description) == "UNKNOWN" ]] ; then
+if [[ $(python3 setup.py --description) == "UNKNOWN" ]] ; then
     echo "[error] metadata: description missing"
     exit 2
 fi
 
-if ! [[ $(python setup.py --classifiers) ]] ; then
+if ! [[ $(python3 setup.py --classifiers) ]] ; then
     echo "[error] metadata: classifiers missing"
     exit 2
 fi
@@ -42,8 +42,8 @@ echo "[info] metadata: all required tags present"
 # CONFIRM TAG VERSION
 # -------------------
 if [ -n "$CI_COMMIT_TAG" ]; then
-    if [[ $(python setup.py --version) != $CI_COMMIT_TAG ]] ; then
-       echo "[error] metadata: python package version [$(python setup.py --version)] differs from git tag version [$CI_COMMIT_TAG]"
+    if [[ $(python3 setup.py --version) != $CI_COMMIT_TAG ]] ; then
+       echo "[error] metadata: python package version [$(python3 setup.py --version)] differs from git tag version [$CI_COMMIT_TAG]"
        exit 2
     fi
 fi
diff --git a/setup.py b/setup.py
index 807e1395d04527db06c681cec4812871738024bb..2e6b65e08c281fc776c6981600af4391e0d3d814 100644
--- a/setup.py
+++ b/setup.py
@@ -22,10 +22,6 @@ setuptools.setup(
       license=license,
       packages=setuptools.find_packages(),
       include_package_data=True,
-      scripts=["scripts/gen_csv_info.py",
-               "scripts/purge_xmi_tree.py",
-               "scripts/elt_ctl.py",
-               ],
       url='https://www.skatelescope.org/',
       classifiers=[
           "Development Status :: 3 - Alpha",
@@ -41,5 +37,11 @@ setuptools.setup(
           "future",
           "ska_logging >= 0.2.0"
       ],
+      tests_require=[
+          "pytest",
+          "coverage",
+          "pytest-json-report",
+          "pytest-forked",
+        ],
       keywords="lmc base classes ska",
       zip_safe=False)
diff --git a/skabase/SKABaseDevice/SKABaseDevice.py b/skabase/SKABaseDevice/SKABaseDevice.py
index 244e85ff0894ca00b656c60cf683cb3118d859ff..0bd64dc4c22115a3d01990a4482926005394afac 100644
--- a/skabase/SKABaseDevice/SKABaseDevice.py
+++ b/skabase/SKABaseDevice/SKABaseDevice.py
@@ -623,14 +623,14 @@ class SKABaseDevice(Device):
     # Commands
     # --------
 
-    @command(dtype_out=('str',), doc_out="[ name: EltTelState ]",)
+    @command(dtype_out=('str',), doc_out="Version strings",)
     @DebugIt()
     def GetVersionInfo(self):
         # PROTECTED REGION ID(SKABaseDevice.GetVersionInfo) ENABLED START #
         """
         Returns the version information of the device.
 
-        :return: Version version details of the device.
+        :return: Version details of the device.
         """
         return ['{}, {}'.format(self.__class__.__name__, self.read_buildState())]
         # PROTECTED REGION END #    //  SKABaseDevice.GetVersionInfo
diff --git a/skabase/SKABaseDevice/SKABaseDevice.xmi b/skabase/SKABaseDevice/SKABaseDevice.xmi
index dd618bb5ae392d534eb80e2d46db50db0852449c..081e4c5651cfb6bdd70d2187c15acc1722dc4149 100644
--- a/skabase/SKABaseDevice/SKABaseDevice.xmi
+++ b/skabase/SKABaseDevice/SKABaseDevice.xmi
@@ -45,7 +45,7 @@
       <argin description="">
         <type xsi:type="pogoDsl:VoidType"/>
       </argin>
-      <argout description="[ name: EltTelState ]">
+      <argout description="Version strings">
         <type xsi:type="pogoDsl:StringArrayType"/>
       </argout>
       <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
diff --git a/skabase/SKAObsDevice/SKAObsDevice.py b/skabase/SKAObsDevice/SKAObsDevice.py
index 52c5dc0dade20f8c2498032d3c99eddde3fa53df..46a21832d9a49d3df30f47c821e46e4646a87132 100644
--- a/skabase/SKAObsDevice/SKAObsDevice.py
+++ b/skabase/SKAObsDevice/SKAObsDevice.py
@@ -37,18 +37,6 @@ class SKAObsDevice(SKABaseDevice):
     A generic base device for Observations for SKA.
     """
     # PROTECTED REGION ID(SKAObsDevice.class_variable) ENABLED START #
-    def __init__(self, *args, **kwargs):
-        super(SKAObsDevice, self).__init__(*args, **kwargs)
-
-        self._build_state = '{}, {}, {}'.format(release.name, release.version,
-                                                release.description)
-        self._version_id = release.version
-        # Initialize attribute values.
-        self._obs_state = ObsState.IDLE
-        self._obs_mode = ObsMode.IDLE
-        self._config_progress = 0
-        self._config_delay_expected = 0
-
     # PROTECTED REGION END #    //  SKAObsDevice.class_variable
 
     # -----------------
@@ -92,6 +80,14 @@ class SKAObsDevice(SKABaseDevice):
     def init_device(self):
         SKABaseDevice.init_device(self)
         # PROTECTED REGION ID(SKAObsDevice.init_device) ENABLED START #
+        self._build_state = '{}, {}, {}'.format(release.name, release.version,
+                                                release.description)
+        self._version_id = release.version
+        # Initialize attribute values.
+        self._obs_state = ObsState.IDLE
+        self._obs_mode = ObsMode.IDLE
+        self._config_progress = 0
+        self._config_delay_expected = 0
         # PROTECTED REGION END #    //  SKAObsDevice.init_device
 
     def always_executed_hook(self):
diff --git a/skabase/release.py b/skabase/release.py
index c0561d08b3fbd3098606ae51173b19cd5f4606bc..b71601ed073f0298332158413a2f7a4563454e6d 100644
--- a/skabase/release.py
+++ b/skabase/release.py
@@ -7,7 +7,7 @@
 """Release information for lmc-base-classes Python Package"""
 
 name = """lmcbaseclasses"""
-version = "0.4.0"
+version = "0.4.1"
 version_info = version.split(".")
 description = """A set of generic base devices for SKA Telescope."""
 author = "SKA India and SARAO"
diff --git a/test-harness/Makefile b/test-harness/Makefile
index 60a54dd99204584ad75c0c2f8738865cc58f1e34..156398d266969611162d5a81be9b30dc594db490 100644
--- a/test-harness/Makefile
+++ b/test-harness/Makefile
@@ -34,7 +34,7 @@ test:
 # FIXME: Add pylint2junit to the tango-builder:latest image so that we don't need to install it here.
 # FIXME: Missing functionality in pylint2junit prevents converting from parseable to xml. Once it's implemented there is no need to run linting twice.
 lint:
-	pip3 install pylint2junit; \
+	python3 -m pip install pylint2junit; \
 	mkdir -p /build/reports; \
 	cd /app && pylint --output-format=parseable skabase | tee /build/code_analysis.stdout; \
 	cd /app && pylint --output-format=pylint2junit.JunitReporter skabase > /build/reports/linting.xml;