diff --git a/devices/clients/attribute_wrapper.py b/devices/clients/attribute_wrapper.py
index 12e5c83516e2c68c2216aca5ba9b39a1fa6f4f8c..4cb389824750cb9d01fc836e8d65caf3656d59a4 100644
--- a/devices/clients/attribute_wrapper.py
+++ b/devices/clients/attribute_wrapper.py
@@ -29,7 +29,14 @@ class attribute_wrapper(attribute):
         # see also https://pytango.readthedocs.io/en/stable/server_api/server.html?highlight=devlong#module-tango.server for
         # more details about type conversion Python/numpy -> PyTango
         if "numpy" not in str(datatype) and datatype != str:
-            raise TypeError("Attribute needs to be a Tango-supported numpy or str type, but has type \"%s\"" % (datatype,))
+            raise ValueError("Attribute needs to be a Tango-supported numpy or str type, but has type \"%s\"" % (datatype,))
+
+        """
+        Numpy has a depracated string type called numpy.str_.
+        this behaves differently from numpy.str (which is literally just an str.
+        """
+        if datatype == numpy.str_:
+            raise Exception("numpy.str_ type not supported, please use numpy.str instead")
 
         self.comms_id = comms_id # store data that can be used to identify the comms interface to use. not used by the wrapper itself
         self.comms_annotation = comms_annotation  # store data that can be used by the comms interface. not used by the wrapper itself
@@ -37,10 +44,7 @@ class attribute_wrapper(attribute):
         self.init_value = init_value
         is_scalar = dims == (1,)
 
-        # tango doesn't recognise numpy.str_, for consistencies sake we convert it here and hide this from the top level
-        # NOTE: discuss, idk if this is an important detail somewhere else
-        if datatype is numpy.str_ or datatype is numpy.str:
-            datatype = str
+
 
         self.numpy_type = datatype  # tango changes our attribute to their representation (E.g numpy.int64 becomes "DevLong64")
 
diff --git a/devices/clients/opcua_client.py b/devices/clients/opcua_client.py
index 6b687837a393a97727a231cea698fb9137485946..75129ed27f70dd061d9da275a38ec5c62647b9aa 100644
--- a/devices/clients/opcua_client.py
+++ b/devices/clients/opcua_client.py
@@ -21,7 +21,7 @@ numpy_to_OPCua_dict = {
     numpy.float32: opcua.ua.VariantType.Float,
     numpy.double: opcua.ua.VariantType.Double,
     numpy.float64: opcua.ua.VariantType.Double,
-    str: opcua.ua.VariantType.String
+    numpy.str: opcua.ua.VariantType.String
 }
 
 # <class 'numpy.bool_'>
diff --git a/devices/clients/statistics_client.py b/devices/clients/statistics_client.py
index d39b62e955530bcb94a0dd569419f132b1bf57c7..eb37e9dc24b7cc80e557d9c5b2b060d73e652564 100644
--- a/devices/clients/statistics_client.py
+++ b/devices/clients/statistics_client.py
@@ -137,7 +137,7 @@ class StatisticsClient(CommClient):
         elif annotation["type"] == "replicator":
             if parameter == "clients":
                 def read_function():
-                    return numpy.array(self.tcp.clients(),dtype=numpy.str_)
+                    return numpy.array(self.tcp.clients(),dtype=numpy.str)
             elif parameter == "nof_bytes_sent":
                 def read_function():
                     return numpy.uint64(self.tcp.nof_bytes_sent)
diff --git a/devices/devices/recv.py b/devices/devices/recv.py
index 1bf57f0b420083ef961c8c340d88e226342a8848..6f1de6aedc9e6db463c2edcd7a1a8bdf3daf7c2e 100644
--- a/devices/devices/recv.py
+++ b/devices/devices/recv.py
@@ -108,7 +108,7 @@ class RECV(hardware_device):
     RCU_Pwr_dig_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_Pwr_dig_R"], datatype=numpy.bool_, dims=(32,))
     RCU_temperature_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_temperature_R"], datatype=numpy.float64, dims=(32,))
     RCU_translator_busy_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_translator_busy_R"], datatype=numpy.bool_)
-    RCU_version_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_version_R"], datatype=numpy.str_, dims=(32,))
+    RCU_version_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_version_R"], datatype=numpy.str, dims=(32,))
 
     @log_exceptions()
     def delete_device(self):
diff --git a/devices/devices/sdp/sdp.py b/devices/devices/sdp/sdp.py
index 70c343d7347d56935912c312c6b2cdf5846a7f83..09042284a40b0149313ca3563580ca651fa99c26 100644
--- a/devices/devices/sdp/sdp.py
+++ b/devices/devices/sdp/sdp.py
@@ -99,8 +99,8 @@ class SDP(hardware_device):
     version_R = attribute(dtype=str, access=AttrWriteType.READ, fget=lambda self: get_version())
 
     # SDP will switch from FPGA_mask_RW to TR_FPGA_mask_RW, offer both for now as its a critical flag
-    FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_firmware_version_R"], datatype=numpy.str_, dims=(16,))
-    FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_hardware_version_R"], datatype=numpy.str_, dims=(16,))
+    FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_firmware_version_R"], datatype=numpy.str, dims=(16,))
+    FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["2:FPGA_hardware_version_R"], datatype=numpy.str, dims=(16,))
     FPGA_processing_enable_R = attribute_wrapper(comms_annotation=["2:FPGA_processing_enable_R"], datatype=numpy.bool_, dims=(16,))
     FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["2:FPGA_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_scrap_R = attribute_wrapper(comms_annotation=["2:FPGA_scrap_R"], datatype=numpy.int32, dims=(8192,))
@@ -131,7 +131,7 @@ class SDP(hardware_device):
     TR_fpga_mask_R = attribute_wrapper(comms_annotation=["2:TR_fpga_mask_R"], datatype=numpy.bool_, dims=(16,))
     TR_fpga_mask_RW = attribute_wrapper(comms_annotation=["2:TR_fpga_mask_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
     TR_fpga_communication_error_R = attribute_wrapper(comms_annotation=["2:TR_fpga_communication_error_R"], datatype=numpy.bool_, dims=(16,))
-    TR_software_version_R = attribute_wrapper(comms_annotation=["2:TR_software_version_R"], datatype=numpy.str_)
+    TR_software_version_R = attribute_wrapper(comms_annotation=["2:TR_software_version_R"], datatype=numpy.str)
     TR_start_time_R = attribute_wrapper(comms_annotation=["2:TR_start_time_R"], datatype=numpy.int32)
     TR_tod_R = attribute_wrapper(comms_annotation=["2:TR_tod_R"], datatype=numpy.uint64)
     TR_tod_pps_delta_R = attribute_wrapper(comms_annotation=["2:TR_tod_pps_delta_R"], datatype=numpy.float_)
diff --git a/devices/devices/sdp/sst.py b/devices/devices/sdp/sst.py
index a7e1e8e9958214469c08efe9a6fea16c9348eaf3..3b2f36236a841adb0511b284cbeb4a0fbc6ee296 100644
--- a/devices/devices/sdp/sst.py
+++ b/devices/devices/sdp/sst.py
@@ -70,10 +70,10 @@ class SST(Statistics):
     # FPGA control points for SSTs
     FPGA_sst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_sst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_enable_R"], datatype=numpy.bool_, dims=(16,))
-    FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str_, dims=(16,))
-    FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=numpy.str_, dims=(16,))
+    FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,))
+    FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,))
     FPGA_sst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_sst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,))
     FPGA_sst_offload_weighted_subbands_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_sst_offload_weighted_subbands_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
diff --git a/devices/devices/sdp/statistics.py b/devices/devices/sdp/statistics.py
index ee1c594f590099a3eaf7158500a507dffb2b41d9..7d0b970b089ff29931bfc088f8b4b208d347402c 100644
--- a/devices/devices/sdp/statistics.py
+++ b/devices/devices/sdp/statistics.py
@@ -97,8 +97,10 @@ class Statistics(hardware_device, metaclass=ABCMeta):
     # queue fill percentage, as reported by the consumer
     queue_collector_fill_percentage_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "collector_fill_percentage"}, datatype=numpy.uint64)
     queue_replicator_fill_percentage_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "replicator_fill_percentage"}, datatype=numpy.uint64)
-    replicator_clients_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "clients"}, dims=(128,), datatype=numpy.str_)
+
+    replicator_clients_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "clients"}, dims=(128,), datatype=numpy.str)
     replicator_nof_bytes_sent_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_bytes_sent"}, datatype=numpy.uint64)
+
     replicator_nof_packets_sent_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_packets_sent"}, datatype=numpy.uint64)
     replicator_nof_tasks_pending_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_tasks_pending"}, datatype=numpy.uint64)
 
diff --git a/devices/devices/sdp/xst.py b/devices/devices/sdp/xst.py
index 104936e107d6e86cf1ce7fe391895168697b8314..caeeb5d3488369ecaf17208d1b33c2b7e6c76511 100644
--- a/devices/devices/sdp/xst.py
+++ b/devices/devices/sdp/xst.py
@@ -84,10 +84,10 @@ class XST(Statistics):
     FPGA_xst_integration_interval_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(8,16))
     FPGA_xst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_xst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_enable_R"], datatype=numpy.bool_, dims=(16,))
-    FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str_, dims=(16,))
-    FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str_, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=numpy.str_, dims=(16,))
+    FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=numpy.str, dims=(16,))
+    FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=numpy.str, dims=(16,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=numpy.str, dims=(16,))
     FPGA_xst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE)
     FPGA_xst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,))
     FPGA_xst_processing_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["2:FPGA_xst_processing_enable_RW"], datatype=numpy.bool_, dims=(16,), access=AttrWriteType.READ_WRITE)
diff --git a/devices/examples/load_from_disk/ini_client.py b/devices/examples/load_from_disk/ini_client.py
index dcc66a85ac7fae4cbe3d00a47fe46a809618938b..cd227f23458c672c08b3acf08ba65fa9a48b581d 100644
--- a/devices/examples/load_from_disk/ini_client.py
+++ b/devices/examples/load_from_disk/ini_client.py
@@ -25,7 +25,7 @@ ini_to_numpy_dict = {
     int: numpy.int64,
     float: numpy.float64,
     bool: numpy.bool_,
-    str: numpy.str_
+    str: numpy.str
 }
 
 import os
@@ -171,9 +171,9 @@ def data_handler(string, dtype):
 
         value = dtype(value)
 
-    elif dtype is numpy.str_:
+    elif dtype is numpy.str:
         for i in string.split(","):
-            val = numpy.str_(i)
+            val = numpy.str(i)
             value.append(val)
 
         value = numpy.array(value)
diff --git a/devices/examples/load_from_disk/ini_device.py b/devices/examples/load_from_disk/ini_device.py
index 4015faf0a45592c9cb2daacb8356471b26ee7c7c..07b2f419ab6b4cd5d78eb84a66c3906e169da99d 100644
--- a/devices/examples/load_from_disk/ini_device.py
+++ b/devices/examples/load_from_disk/ini_device.py
@@ -80,8 +80,8 @@ class ini_device(hardware_device):
     bool_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "bool_scalar_R"}, datatype=numpy.bool_)
     int_scalar_RW = attribute_wrapper(comms_annotation={"section": "scalar", "name": "int_scalar_RW"}, datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
     int_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "int_scalar_R"}, datatype=numpy.int64)
-    str_scalar_RW = attribute_wrapper(comms_annotation={"section": "scalar", "name": "str_scalar_RW"}, datatype=numpy.str_, access=AttrWriteType.READ_WRITE)
-    str_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "str_scalar_R"}, datatype=numpy.str_)
+    str_scalar_RW = attribute_wrapper(comms_annotation={"section": "scalar", "name": "str_scalar_RW"}, datatype=numpy.str, access=AttrWriteType.READ_WRITE)
+    str_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "str_scalar_R"}, datatype=numpy.str)
 
     double_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "double_spectrum_RW"}, datatype=numpy.double, dims=(4,), access=AttrWriteType.READ_WRITE)
     double_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "double_spectrum_R"}, datatype=numpy.double, dims=(4,))
@@ -89,8 +89,8 @@ class ini_device(hardware_device):
     bool_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "bool_spectrum_R"}, datatype=numpy.bool_, dims=(4,))
     int_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "int_spectrum_RW"}, datatype=numpy.int64, dims=(4,), access=AttrWriteType.READ_WRITE)
     int_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "int_spectrum_R"}, datatype=numpy.int64, dims=(4,))
-    str_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_RW"}, datatype=numpy.str_, dims=(4,), access=AttrWriteType.READ_WRITE)
-    str_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_R"}, datatype=numpy.str_, dims=(4,))
+    str_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_RW"}, datatype=numpy.str, dims=(4,), access=AttrWriteType.READ_WRITE)
+    str_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_R"}, datatype=numpy.str, dims=(4,))
 
     double_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "double_image_RW"}, datatype=numpy.double, dims=(3, 2), access=AttrWriteType.READ_WRITE)
     double_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "double_image_R"}, datatype=numpy.double, dims=(3, 2))
@@ -98,8 +98,8 @@ class ini_device(hardware_device):
     bool_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "bool_image_R"}, datatype=numpy.bool_, dims=(3, 2))
     int_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "int_image_RW"}, datatype=numpy.int64, dims=(3, 2), access=AttrWriteType.READ_WRITE)
     int_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "int_image_R"}, datatype=numpy.int64, dims=(3, 2))
-    str_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "str_image_RW"}, datatype=numpy.str_, dims=(3, 2), access=AttrWriteType.READ_WRITE)
-    str_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "str_image_R"}, datatype=numpy.str_, dims=(3, 2))
+    str_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "str_image_RW"}, datatype=numpy.str, dims=(3, 2), access=AttrWriteType.READ_WRITE)
+    str_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "str_image_R"}, datatype=numpy.str, dims=(3, 2))
 
     # --------
     # overloaded functions
diff --git a/devices/examples/snmp/snmp.py b/devices/examples/snmp/snmp.py
index a36f6b7305ef999b67ecf20a223fb5149b553a0f..2a912ce1443bbd8e83b662d4ed9764627d947943 100644
--- a/devices/examples/snmp/snmp.py
+++ b/devices/examples/snmp/snmp.py
@@ -70,15 +70,15 @@ class SNMP(hardware_device):
     # Attributes
     # ----------
 
-    sys_description_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.1.0"}, datatype=numpy.str_)
-    sys_objectID_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.2.0", "type": "OID"}, datatype=numpy.str_)
+    sys_description_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.1.0"}, datatype=numpy.str)
+    sys_objectID_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.2.0", "type": "OID"}, datatype=numpy.str)
     sys_uptime_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.3.0", "type": "TimeTicks"}, datatype=numpy.int64)
-    sys_name_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.5.0"}, datatype=numpy.str_)
-    ip_route_mask_127_0_0_1_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.4.21.1.11.127.0.0.1", "type": "IpAddress"}, datatype=numpy.str_)
+    sys_name_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.5.0"}, datatype=numpy.str)
+    ip_route_mask_127_0_0_1_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.4.21.1.11.127.0.0.1", "type": "IpAddress"}, datatype=numpy.str)
     TCP_active_open_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.6.5.0", "type": "Counter32"}, datatype=numpy.int64)
 
-    sys_contact_RW = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.4.0"}, datatype=numpy.str_, access=AttrWriteType.READ_WRITE)
-    sys_contact_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.4.0"}, datatype=numpy.str_)
+    sys_contact_RW = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.4.0"}, datatype=numpy.str, access=AttrWriteType.READ_WRITE)
+    sys_contact_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.1.4.0"}, datatype=numpy.str)
 
     TCP_Curr_estab_R = attribute_wrapper(comms_annotation={"oids": "1.3.6.1.2.1.6.9.0", "type": "Gauge"}, datatype=numpy.int64)
 
diff --git a/devices/examples/snmp/snmp_client.py b/devices/examples/snmp/snmp_client.py
index 635450172387148734e5e3b42ed0f82f067a0048..96ac67140b9bdbdba7ab4d4fb8651b5e9674c219 100644
--- a/devices/examples/snmp/snmp_client.py
+++ b/devices/examples/snmp/snmp_client.py
@@ -12,11 +12,11 @@ __all__ = ["SNMP_client"]
 snmp_to_numpy_dict = {
     snmp.types.INTEGER: numpy.int64,
     snmp.types.TimeTicks: numpy.int64,
-    snmp.types.OCTET_STRING: numpy.str_,
-    snmp.types.OID: numpy.str_,
+    snmp.types.OCTET_STRING: numpy.str,
+    snmp.types.OID: numpy.str,
     snmp.types.Counter32: numpy.int64,
     snmp.types.Gauge32: numpy.int64,
-    snmp.types.IpAddress: numpy.str_,
+    snmp.types.IpAddress: numpy.str,
 }
 
 snmp_types = {
@@ -24,9 +24,9 @@ snmp_types = {
     "Gauge": numpy.int64,
     "TimeTick": numpy.int64,
     "Counter32": numpy.int64,
-    "OctetString": numpy.str_,
-    "IpAddress": numpy.str_,
-    "OID": numpy.str_,
+    "OctetString": numpy.str,
+    "IpAddress": numpy.str,
+    "OID": numpy.str,
 }
 
 
diff --git a/devices/test/clients/test_attr_wrapper.py b/devices/test/clients/test_attr_wrapper.py
index a293923acbf21774e9f221b650353f3410104a88..453e19c19d67b56eb339462cc1da7e0e8414451b 100644
--- a/devices/test/clients/test_attr_wrapper.py
+++ b/devices/test/clients/test_attr_wrapper.py
@@ -38,8 +38,8 @@ def dev_init(device):
 class TestAttributeTypes(base.TestCase):
 
     class str_scalar_device(hardware_device):
-        scalar_R = attribute_wrapper(comms_annotation="str_scalar_R", datatype=str)
-        scalar_RW = attribute_wrapper(comms_annotation="str_scalar_RW", datatype=str, access=AttrWriteType.READ_WRITE)
+        scalar_R = attribute_wrapper(comms_annotation="str_scalar_R", datatype=numpy.str)
+        scalar_RW = attribute_wrapper(comms_annotation="str_scalar_RW", datatype=numpy.str, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
@@ -122,8 +122,8 @@ class TestAttributeTypes(base.TestCase):
             dev_init(self)
 
     class str_spectrum_device(hardware_device):
-        spectrum_R = attribute_wrapper(comms_annotation="str_spectrum_R", datatype=str, dims=spectrum_dims)
-        spectrum_RW = attribute_wrapper(comms_annotation="str_spectrum_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=spectrum_dims)
+        spectrum_R = attribute_wrapper(comms_annotation="str_spectrum_R", datatype=numpy.str, dims=spectrum_dims)
+        spectrum_RW = attribute_wrapper(comms_annotation="str_spectrum_RW", datatype=numpy.str, access=AttrWriteType.READ_WRITE, dims=spectrum_dims)
 
         def configure_for_initialise(self):
             dev_init(self)
@@ -206,8 +206,8 @@ class TestAttributeTypes(base.TestCase):
             dev_init(self)
 
     class str_image_device(hardware_device):
-        image_R = attribute_wrapper(comms_annotation="str_image_R", datatype=str, dims=(2,3))
-        image_RW = attribute_wrapper(comms_annotation="str_image_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=(2,3))
+        image_R = attribute_wrapper(comms_annotation="str_image_R", datatype=numpy.str, dims=(2,3))
+        image_RW = attribute_wrapper(comms_annotation="str_image_RW", datatype=numpy.str, access=AttrWriteType.READ_WRITE, dims=(2,3))
 
         def configure_for_initialise(self):
             dev_init(self)
@@ -333,20 +333,20 @@ class TestAttributeTypes(base.TestCase):
 
             if test_type == "scalar":
 
-                if dtype is str or dtype is numpy.str_:
+                if dtype is numpy.str:
                     val = str_scalar_val
                 else:
                     val = dtype(1)
                 proxy.scalar_RW = val
             elif test_type == "spectrum":
-                if dtype is str or dtype is numpy.str_:
+                if dtype is numpy.str:
                     val = str_spectrum_val
                 else:
                     val = numpy.full(spectrum_dims, dtype=dtype, fill_value=1)
                 print(val)
                 proxy.spectrum_RW = val
             elif test_type == "image":
-                if dtype is str or dtype is numpy.str_:
+                if dtype is numpy.str:
                     val = str_image_val
                 else:
                     val = numpy.full(image_dims, dtype=dtype, fill_value=1)
@@ -408,7 +408,7 @@ class TestAttributeTypes(base.TestCase):
                 proxy.on()
 
                 if test_type == "scalar":
-                    if dtype is str or dtype is numpy.str_:
+                    if dtype is numpy.str:
                         val = str_scalar_val
                     else:
                         val = dtype(1)
@@ -416,7 +416,7 @@ class TestAttributeTypes(base.TestCase):
                     result_R = proxy.scalar_R
                     result_RW = proxy.scalar_RW
                 elif test_type == "spectrum":
-                    if dtype is str or dtype is numpy.str_:
+                    if dtype is numpy.str:
                         val = str_spectrum_val
                     else:
                         val = numpy.full(spectrum_dims, dtype=dtype, fill_value=1)
@@ -424,7 +424,7 @@ class TestAttributeTypes(base.TestCase):
                     result_R = proxy.spectrum_R
                     result_RW = proxy.spectrum_RW
                 elif test_type == "image":
-                    if dtype is str or dtype is numpy.str_:
+                    if dtype is numpy.str:
                         val = str_image_val
                     else:
                         val = numpy.full(image_dims, dtype=dtype, fill_value=1)
@@ -434,7 +434,7 @@ class TestAttributeTypes(base.TestCase):
                     result_R = proxy.image_R
                     result_RW = proxy.image_RW
 
-                    if dtype != str:
+                    if dtype != numpy.str:
                         self.assertEqual(result_R.shape, image_dims, "not the correct dimensions")
 
                         result_R = result_R.reshape(-1)
@@ -450,7 +450,7 @@ class TestAttributeTypes(base.TestCase):
                     self.assertTrue(comparison, " Value could not be handled by the atrribute_wrappers internal RW storer. attempted to write: {}".format(val))
                     comparison = result_R == val
                     self.assertTrue(comparison, " value in the clients R attribute not equal to what was written. read: {}, wrote {}".format(result_R, val))
-                elif dtype != str:
+                elif dtype != numpy.str:
                     comparison = result_RW == val
                     equal_arrays = comparison.all()
                     self.assertTrue(equal_arrays, " Value could not be handled by the atrribute_wrappers internal RW storer. attempted to write: {}".format(val))
diff --git a/devices/test/clients/test_opcua_client.py b/devices/test/clients/test_opcua_client.py
index 13b7863819fbcc9d60fc3ae95ad5a269546e200e..df9296c417857683955aa73ee3cbc0b7985ade76 100644
--- a/devices/test/clients/test_opcua_client.py
+++ b/devices/test/clients/test_opcua_client.py
@@ -164,7 +164,7 @@ class TestOPCua(base.TestCase):
     def test_type_map(self):
         for numpy_type, opcua_type in opcua_client.numpy_to_OPCua_dict.items():
             # derive a default value that can get lost in a type translation
-            if numpy_type in [str, numpy.str, numpy.str_]:
+            if numpy_type in [str, numpy.str]:
               default_value = "foo"
             elif numpy_type == numpy.bool_:
               default_value = True
@@ -191,7 +191,7 @@ class TestOPCua(base.TestCase):
             self.assertEqual(v.Value, reparsed_v.Value, msg=f"Conversion {numpy_type} -> {opcua_type} failed.")
 
             # does the OPC-UA type have the same datasize (and thus, precision?)
-            if numpy_type not in [str, numpy.str, numpy.str_]:
+            if numpy_type not in [str, numpy.str]:
                 self.assertEqual(numpy_type().itemsize, getattr(opcua.ua.ua_binary.Primitives, opcua_type.name).size, msg=f"Conversion {numpy_type} -> {opcua_type} failed: precision mismatch")