code: def devices_or_default(
      self, devices: Sequence[str]
  ) -> Sequence[str]:  # overriden
      # TODO: this method is duplicated in Watcher and WatcherClient
  
      # make sure TCP port is attached to tcp device
      if devices is not None:
          return [
              "tcp:" + str(self.port) if device == "tcp" else device
              for device in devices
          ]
  
      # if no devices specified then use our filename and tcp:port as default devices
      devices = []
      # first open file device because it may have older data
      if self.filename is not None:
          devices.append("file:" + self.filename)
      if self.port is not None:
          devices.append("tcp:" + str(self.port))
      return devices
  
file_path: tensorwatch/tensorwatch/watcher.py
imports: import uuid
  from typing import Sequence
  from .zmq_wrapper import ZmqWrapper
  from .watcher_base import WatcherBase
  from .lv_types import CliSrvReqTypes
  from .lv_types import DefaultPorts, PublisherTopics, ServerMgmtMsg
  from .None import utils
  import threading, time
label_desc: Use image node_id 4 for calling the Watcher obj's underlying member method code with example usage: obj.devices_or_default(devices) and returns: devices, unknown