uopy

UniObjects for Python is a Python package from Rocket Software. It is a client API that allows Python applications to access Rocket MV Databases over the network.

Specifically, it enables Python developers to:

1) remotely connect to MV databases

1) call BASIC catalogued subroutines

2) run TCL commands

3) read/write MV files

4) handle MV dynamic arrays

5) manage MV SELECT lists

6) control MV transactions

Configuration:

UOPY supports a list of configuration parameters. They are grouped into 4 categories: connection, pooling, logging,
and ssl_auth. Internally all the configuration parameters are preset to default values deemed to work for a minimal
UOPY application development environment. To override these default values, UOPY supports an external
configuration file - 'uopy.ini', in which a user can specify different values for some or all of the parameters. In
some cases, this enables users to change how the application behaves without having to make any code changes, such
as turning connection pooling on and off or making all connections to the database secure.

For example, on Windows 10 (US-English), the default parameter values are:

    connection: {'host': 'localhost', 'account': 'XDEMO', 'port': 31438, 'timeout': 300, 'service': 'defcs',
    'encoding': 'cp1252', 'ssl': False}

    pooling: {'pooling_on': False, 'min_pool_size': 1, 'max_pool_size': 10, 'max_wait_time': 30,
    'idle_remove_threshold': 300, 'idle_remove_interval': 300}

    logging: {'level': 'WARNING', 'format': 'standard', 'dir': './logs', 'file_name': 'uopy.log', 'max_size': 524288,
    'backup_count': 5, 'unirpc_debug': False, 'log_data_max_size': 1024}

    ssl_auth: {'client_auth_required': False, 'server_cert_file': '', 'client_cert_file': '', 'client_key_file': '',
    'check_hostname': False}

If the uopy.ini file is present in the current working directory with the following settings:

    [connection]
    host = uv1211.rocketsoftware.com
    account = XDEMO
    port = 41438
    timeout = 100
    service = udcs
    ssl = True

    [ssl_auth]
    server_cert_file="c:\temp\desktop-ppdt4ds.crt"

    [pooling]
    pooling_on = True
    max_wait_time = 60
    idle_remove_threshold = 300
    idle_remove_interval = 300
    min_pool_size = 5
    max_pool_size = 15

    [logging]
    level = DEBUG
    backup_count = 10
    log_data_max_size = 256

then when uopy is imported, it will combine uopy.ini with the internal default configuration, resulting in the
actual runtime configuration (see the Examples below). Please note that most of these configuration values cannot
be changed by the application at runtime, with the exception of the values in the connection category and the pool
size values in the pooling category, which can be passed in with different values to uopy.connect().

Logging:

UOPY uses a rotating log strategy which is configurable in uopy.ini as shown above.

Specifically,
    level: the logging level, can be CRITICAL(50), ERROR(40), WARNING (30, default), INFO(20), DEBUG(10).

    format: can be standard or simple - the difference is that source code line no is provided in the standard format.

    dir: the directory where log files are stored.

    file_name: the log file name.

    max_size: the maximum size of a single log file.

    backup_count: the number of backup log files to rotate through.

    unirpc_debug: if set to True and the logging level is DEBUG, all UniRPC packets are dumped into the log files.

    log_data_max_size: the maximum length for any data logged when logging level is DEBUG - the default is 1k.
        For instance, if a subroutine parameter is a XML string greater than 1K in size, it will be truncated to 1K
        in the log file.

Constants:

UV_SERVICE, UD_SERVICE, DEFAULT_SERVICE: standard service names for back-end UO servers.

DATA_FILE, DICT_FILE: used when creating a File object to indicate which part of the file should be opened.

LOCK_WAIT, LOCK_RETAIN, LOCK_EXCLUSIVE, LOCK_SHARED: locking behaviors when working with records of hashed files.

EXEC_COMPLETE, EXEC_REPLY, EXEC_MORE_OUTPUT: Command execution status codes.

AtVar: an enum of supported MV @variables.

UOLocale(Enum): an enum of UniVerse locale definitions.

DEFAULT_MARKS: a named tuple containing the default MV delimiters (marks).

Examples:

>>> import uopy
>>> uopy.config.connection
{'host': 'uv1211.rocketsoftware.com', 'account': 'XDEMO', 'port': 41438, 'timeout': 100, 'service': 'udcs',
'encoding': 'cp1252', 'ssl': True}

>>> uopy.config.pooling
{'pooling_on': True, 'min_pool_size': 5, 'max_pool_size': 15, 'max_wait_time': 60, 'idle_remove_threshold': 300,
'idle_remove_interval': 300}

>>> uopy.config.logging
{'level': 'DEBUG', 'format': 'standard', 'dir': './logs', 'file_name': 'uopy.log', 'max_size': 524288,
'backup_count': 10, 'unirpc_debug': False, 'log_data_max_size': 256}

>>> uopy.config.ssl_auth
{'client_auth_required': False, 'server_cert_file': 'c:\temp\desktop-ppdt4ds.crt', 'client_cert_file': '',
'client_key_file': '', 'check_hostname': False}

>>> with uopy.connect(user='test', password='test'):
>>>     cmd = uopy.Command("LIST VOC")
>>>     cmd.run()
>>>     print(cmd.response[-20:])
'68 records listed.

'

__version__: Use __version__ to get the uopy version

  1# Copyright 2020 - 2020 Rocket Software, Inc. or its affiliates. All Rights Reserved.
  2#
  3
  4"""UniObjects for Python is a Python package from Rocket Software. It is a client API that allows Python applications
  5to access Rocket MV Databases over the network.
  6
  7Specifically, it enables Python developers to:
  8
  9    1) remotely connect to MV databases
 10
 11    1) call BASIC catalogued subroutines
 12
 13    2) run TCL commands
 14
 15    3) read/write MV files
 16
 17    4) handle MV dynamic arrays
 18
 19    5) manage MV SELECT lists
 20
 21    6) control MV transactions
 22
 23Configuration:
 24
 25    UOPY supports a list of configuration parameters. They are grouped into 4 categories: connection, pooling, logging,
 26    and ssl_auth. Internally all the configuration parameters are preset to default values deemed to work for a minimal
 27    UOPY application development environment. To override these default values, UOPY supports an external
 28    configuration file - 'uopy.ini', in which a user can specify different values for some or all of the parameters. In
 29    some cases, this enables users to change how the application behaves without having to make any code changes, such
 30    as turning connection pooling on and off or making all connections to the database secure.
 31
 32    For example, on Windows 10 (US-English), the default parameter values are:
 33
 34        connection: {'host': 'localhost', 'account': 'XDEMO', 'port': 31438, 'timeout': 300, 'service': 'defcs',
 35        'encoding': 'cp1252', 'ssl': False}
 36
 37        pooling: {'pooling_on': False, 'min_pool_size': 1, 'max_pool_size': 10, 'max_wait_time': 30,
 38        'idle_remove_threshold': 300, 'idle_remove_interval': 300}
 39
 40        logging: {'level': 'WARNING', 'format': 'standard', 'dir': './logs', 'file_name': 'uopy.log', 'max_size': 524288,
 41        'backup_count': 5, 'unirpc_debug': False, 'log_data_max_size': 1024}
 42
 43        ssl_auth: {'client_auth_required': False, 'server_cert_file': '', 'client_cert_file': '', 'client_key_file': '',
 44        'check_hostname': False}
 45
 46    If the uopy.ini file is present in the current working directory with the following settings:
 47
 48        [connection]
 49        host = uv1211.rocketsoftware.com
 50        account = XDEMO
 51        port = 41438
 52        timeout = 100
 53        service = udcs
 54        ssl = True
 55
 56        [ssl_auth]
 57        server_cert_file="c:\\temp\\desktop-ppdt4ds.crt"
 58
 59        [pooling]
 60        pooling_on = True
 61        max_wait_time = 60
 62        idle_remove_threshold = 300
 63        idle_remove_interval = 300
 64        min_pool_size = 5
 65        max_pool_size = 15
 66
 67        [logging]
 68        level = DEBUG
 69        backup_count = 10
 70        log_data_max_size = 256
 71
 72    then when uopy is imported, it will combine uopy.ini with the internal default configuration, resulting in the
 73    actual runtime configuration (see the Examples below). Please note that most of these configuration values cannot
 74    be changed by the application at runtime, with the exception of the values in the connection category and the pool
 75    size values in the pooling category, which can be passed in with different values to uopy.connect().
 76
 77
 78Logging:
 79
 80    UOPY uses a rotating log strategy which is configurable in uopy.ini as shown above.
 81
 82    Specifically,
 83        level: the logging level, can be CRITICAL(50), ERROR(40), WARNING (30, default), INFO(20), DEBUG(10).
 84
 85        format: can be standard or simple - the difference is that source code line no is provided in the standard format.
 86
 87        dir: the directory where log files are stored.
 88
 89        file_name: the log file name.
 90
 91        max_size: the maximum size of a single log file.
 92
 93        backup_count: the number of backup log files to rotate through.
 94
 95        unirpc_debug: if set to True and the logging level is DEBUG, all UniRPC packets are dumped into the log files.
 96
 97        log_data_max_size: the maximum length for any data logged when logging level is DEBUG - the default is 1k.
 98            For instance, if a subroutine parameter is a XML string greater than 1K in size, it will be truncated to 1K
 99            in the log file.
100
101
102Constants:
103
104    UV_SERVICE, UD_SERVICE, DEFAULT_SERVICE: standard service names for back-end UO servers.
105
106    DATA_FILE, DICT_FILE: used when creating a File object to indicate which part of the file should be opened.
107
108    LOCK_WAIT, LOCK_RETAIN, LOCK_EXCLUSIVE, LOCK_SHARED: locking behaviors when working with records of hashed files.
109
110    EXEC_COMPLETE, EXEC_REPLY, EXEC_MORE_OUTPUT: Command execution status codes.
111
112    AtVar: an enum of supported MV @variables.
113
114    UOLocale(Enum): an enum of UniVerse locale definitions.
115
116    DEFAULT_MARKS: a named tuple containing the default MV delimiters (marks).
117
118
119Examples:
120
121    >>> import uopy
122    >>> uopy.config.connection
123    {'host': 'uv1211.rocketsoftware.com', 'account': 'XDEMO', 'port': 41438, 'timeout': 100, 'service': 'udcs',
124    'encoding': 'cp1252', 'ssl': True}
125
126    >>> uopy.config.pooling
127    {'pooling_on': True, 'min_pool_size': 5, 'max_pool_size': 15, 'max_wait_time': 60, 'idle_remove_threshold': 300,
128    'idle_remove_interval': 300}
129
130    >>> uopy.config.logging
131    {'level': 'DEBUG', 'format': 'standard', 'dir': './logs', 'file_name': 'uopy.log', 'max_size': 524288,
132    'backup_count': 10, 'unirpc_debug': False, 'log_data_max_size': 256}
133
134    >>> uopy.config.ssl_auth
135    {'client_auth_required': False, 'server_cert_file': 'c:\\temp\\desktop-ppdt4ds.crt', 'client_cert_file': '',
136    'client_key_file': '', 'check_hostname': False}
137
138    >>> with uopy.connect(user='test', password='test'):
139    >>>     cmd = uopy.Command("LIST VOC")
140    >>>     cmd.run()
141    >>>     print(cmd.response[-20:])
142    '68 records listed.\r\n'
143
144__version__:
145    Use uopy.__version__ to get the uopy version
146"""
147
148from ._uopy import connect, config, Session, __version__
149from ._constants import *
150from ._command import Command
151from ._dynarray import DynArray
152from ._uoerror import UOError
153from ._uofile_error import UOFileError
154from ._sequentialfile import SequentialFile
155from ._subroutine import Subroutine
156from ._file import File
157from ._dictionary import Dictionary
158from ._list import List
159
160__all__ = [
161    "connect",
162    "config",
163    "Session",
164    "Command",
165    "DynArray",
166    "UOError",
167    "File",
168    "SequentialFile",
169    "Dictionary",
170    "List",
171    "Subroutine",
172    "UOFileError",
173    "__version__",
174]
def connect(**kwargs):
 63def connect(**kwargs):
 64    """Open a connection to an MV Database.
 65
 66    Args:
 67        kwargs: connection configuration keyword parameters:  host, port, user, password, account, service, timeout,
 68                encoding, ssl, min_pool_size, max_pool_size.
 69
 70                1. only user and password are required, the rest have default values in uopy.config.connection.
 71
 72                2. if connection pooling is turned on and connect() is called for the first time to open a connection
 73                to the database server, a connection pool will be created for the same host, account, user and password
 74                that are passed in. If min_pool_size and/or max_pool_size are passed in as well, they will be used
 75                instead of the default values in the uopy.config.pooling section to set the minimum and maximum pool
 76                sizes. Note that once a connection pool is created, its min_pool_size and max_pool_size cannot be
 77                changed. This means that the min_pool_size and max_pool_size parameters are ignored on subsequent calls
 78                to connect() for the same pool.
 79
 80    Returns:
 81        A Session object: either newly established or straight from a connection pool.
 82
 83    Raises:
 84        UOError, ValueError
 85
 86    Examples:
 87        >>> session = uopy.connect(user = 'test', password ='test')
 88
 89        >>> session = uopy.connect(host ='localhost', user = 'test', password ='test', account = 'HS.SALES',
 90                    service=uopy.UV_SERVICE, port=31438)
 91
 92        >>> config = {
 93                'user': 'test',
 94                'password': 'test',
 95                'service': 'udcs',
 96                'account': 'demo',
 97                'encoding': 'GB18030',
 98                'ssl': True
 99            }
100        >>> session = uopy.connect(**config)
101
102    """
103    global _pooling_on
104    config.update(kwargs)
105    connect_config = build_connect_config(kwargs)
106    pooling_config = build_pooling_config(kwargs)
107
108    _pooling_on = pooling_config.get("pooling_on")
109    if _pooling_on:
110        pool_key = make_pool_key(connect_config)
111        if not wrapper.hasrun:
112            wrapper()
113        with _lock:
114            pool = _pools.get(pool_key)
115            if not pool:
116                pool = Pool(connect_config, pooling_config)
117                _pools[pool_key] = pool
118
119        return pool.get()
120    else:
121        session = Session(connect_config)
122        session.connect()
123        return session

Open a connection to an MV Database.

Args: kwargs: connection configuration keyword parameters: host, port, user, password, account, service, timeout, encoding, ssl, min_pool_size, max_pool_size.

        1. only user and password are required, the rest have default values in uopy.config.connection.

        2. if connection pooling is turned on and connect() is called for the first time to open a connection
        to the database server, a connection pool will be created for the same host, account, user and password
        that are passed in. If min_pool_size and/or max_pool_size are passed in as well, they will be used
        instead of the default values in the uopy.config.pooling section to set the minimum and maximum pool
        sizes. Note that once a connection pool is created, its min_pool_size and max_pool_size cannot be
        changed. This means that the min_pool_size and max_pool_size parameters are ignored on subsequent calls
        to connect() for the same pool.

Returns: A Session object: either newly established or straight from a connection pool.

Raises: UOError, ValueError

Examples:

session = uopy.connect(user = 'test', password ='test')

>>> session = uopy.connect(host ='localhost', user = 'test', password ='test', account = 'HS.SALES',
            service=uopy.UV_SERVICE, port=31438)

>>> config = {
        'user': 'test',
        'password': 'test',
        'service': 'udcs',
        'account': 'demo',
        'encoding': 'GB18030',
        'ssl': True
    }
>>> session = uopy.connect(**config)
config = <uopy._config._Config object>
class Session:
 48class Session:
 49    """A Session represents a MV database connection. It is the foundation for and embedded in other UOPY objects.
 50
 51    Session objects can be used in Python with statement so that whatever happens in the with statement block, they
 52    are guaranteed to be closed upon exit.
 53
 54    Applications can also perform transactions on a Session, and get supported @var values from the server.
 55
 56    Note:
 57        Applications should call uopy.connect() to get a Session object instead of directly instantiating a Session.
 58
 59    Examples:
 60
 61        >>> with uopy.connect(user='test', password='test'):
 62        >>>     cmd = uopy.Command("LIST VOC")
 63        >>>     cmd.run()
 64        >>>     print(cmd.response)
 65
 66
 67        >>> with uopy.connect(user="test", password="test") as session:
 68        >>>     session.tx_start()
 69        >>>     print(session.tx_is_active())
 70        ...
 71        >>>     session.tx_commit()
 72
 73    """
 74
 75    def __init__(self, connect_config):
 76        _logger.debug(
 77            "Enter", {k: connect_config[k] for k in connect_config if k != "password"}
 78        )
 79
 80        self._config = connect_config
 81
 82        self._lock = threading.RLock()
 83
 84        self._rpc_connection = None
 85        self._is_rpc_failed = False
 86
 87        self._is_nls_enabled = False
 88        self._is_nls_locale_enabled = False
 89        self._is_ud = False
 90        self._is_d3 = False
 91
 92        self.__pool = None
 93        self._idle_start_time = 0
 94
 95        self._mac_address = "JAVA"
 96        self._license_token = ""
 97
 98        self._host_type = None
 99        self._command = None
100        self._transaction = None
101
102        self.is_active = False
103        self.marks = DEFAULT_MARKS
104
105        self._uoserver_timeout = None
106        self._uv_timeout_flag = False
107
108    def __repr__(self):
109        format_string = "<{} object {} at 0x{:016X}>"
110        details = self._config
111        return format_string.format(
112            ".".join([Session.__module__, Session.__qualname__]), details, id(self)
113        )
114
115    def __enter__(self):
116        if not self.is_active:
117            self.connect()
118        return self
119
120    def __exit__(self, exec_type, exec_value, traceback):
121        self.close()
122
123    def bind_pool(self, pool):
124        self.__pool = pool
125
126    @property
127    def config(self):
128        """A copy of all the configuration parameters for this session."""
129        return copy.deepcopy(self._config)
130
131    @property
132    def idle_start_time(self):
133        return self._idle_start_time
134
135    def start_idle(self):
136        self._idle_start_time = time.time()
137
138    @property
139    def db_type(self):
140        """str: either "UD' for UniData,'UV' for UniVerse, or "D3" for D3."""
141
142        if self._is_ud:
143            return "UD"
144        elif self._is_d3:
145            return "D3"
146        else:
147            return "UV"
148
149    @property
150    def is_nls_enabled(self):
151        """boolean: whether NLS is enabled on the server."""
152        return self._is_nls_enabled
153
154    @property
155    def encoding(self):
156        """The name of the character encoding used for conversion between Python unicode strings and MV data.
157
158        By default it is set to the local system's preferred encoding when server NLS is off, and to UTF-8 when
159        server NLS is on. However it can be overridden by the application to what reflects the actual encoding of
160        the server data.
161
162        """
163        return self._config[ENCODING]
164
165    @encoding.setter
166    def encoding(self, encoding):
167        try:
168            "".encode(encoding.strip())
169            self._config[ENCODING] = encoding.strip()
170        except LookupError as e:
171            _logger.warning(
172                "Unsupported encoding setting, encoding is not changed:" + str(e)
173            )
174
175    def _get_uv_version(self, version: str):
176        uv_version = array("i")
177        if not version.startswith("UniVerse "):
178            return None
179        version = version.removeprefix("UniVerse")
180        version = version[1:]
181        version_arr = version.split(".")
182        if len(version_arr) != 3:
183            return None
184        try:
185            for item in version_arr:
186                uv_version.append(int(item))
187        except:
188            return None
189        return uv_version
190        pass
191
192    def _compare_version(self, version1: array, version2: array):
193        # The version1 >= version2, the result is True, otherwise, the result is False
194        if version1[0] > version2[0]:
195            return True
196        elif version1[0] < version2[0]:
197            return False
198        if version1[1] > version2[1]:
199            return True
200        elif version1[1] < version2[1]:
201            return False
202        if version1[2] > version2[2]:
203            return True
204        elif version1[2] < version2[2]:
205            return False
206        return True
207
208    def _get_server_timeout(self):
209        _logger.debug("Enter")
210
211        with self._lock:
212            in_packet = UniRPCPacket()
213            out_packet = UniRPCPacket()
214
215            out_packet.write(0, FuncCodes.EIC_UOTIMEOUT)
216
217            try:
218                self._rpc_connection.call(in_packet, out_packet)
219
220                retcode = in_packet.read(0)
221
222                if retcode:
223                    if (
224                        self.db_type == "UV"
225                        and not self._uv_timeout_flag
226                        or self.db_type == "UD"
227                    ):
228                        raise UOError(code=retcode)
229                    else:
230                        self._uoserver_timeout = retcode
231                elif self.db_type == "UV":
232                    self._uoserver_timeout = retcode
233                else:
234                    self._uoserver_timeout = in_packet.read(1)
235            except Exception as e:
236                raise UOError(message=str(e))
237
238        _logger.info("Exit")
239
240    @property
241    def uoserver_timeout(self):
242        """
243        The following code snippet retrieves the UO Server timeout value after connecting to the server:
244        ses = uopy.connect(user=user,password=passwd)
245        uotimeout = ses.uoserver_timeout
246        On the server side, the timeout can be set in the unirpcservice file and passed as an argument when the uvapi_server process is started.
247        """
248        if self._uoserver_timeout == None:
249            self._get_server_timeout()
250        return self._uoserver_timeout
251
252    def sync_marks(self, mark_list):
253        self.marks = MARKS_NAMED_TUPLE(*mark_list)
254
255    def encode(self, obj):
256        if isinstance(obj, str):
257            return obj.encode(self._config[ENCODING], errors="replace")
258        elif isinstance(obj, bytes) or isinstance(obj, bytearray):
259            return obj
260        elif isinstance(obj, MvDelimited):
261            return bytes(obj)
262        elif isinstance(obj, list):
263            return bytes(MvDelimited(obj=obj, session=self))
264        elif obj is None:
265            return b""
266        else:
267            return str(obj).encode(self._config[ENCODING], errors="replace")
268
269    def decode(self, obj):
270        if isinstance(obj, bytes) or isinstance(obj, bytearray):
271            return obj.decode(self._config[ENCODING], errors="replace")
272        else:
273            return str(obj)
274
275    def _check_callable(self, in_exec=False):
276        if self._rpc_connection is None or not self._rpc_connection.is_connected:
277            raise UOError(code=ErrorCodes.UOE_SESSION_NOT_OPEN)
278
279        if not in_exec:
280            if self._command is not None:
281                if self._command.status in {EXEC_MORE_OUTPUT, EXEC_REPLY}:
282                    raise UOError(code=ErrorCodes.UOE_EXECUTEISACTIVE)
283
284    def rpc_call(self, in_packet, out_packet, in_exec=False):
285        with self._lock:
286            self._check_callable(in_exec)
287            self._rpc_connection.call(in_packet, out_packet)
288
289    def read_packet4cmd(self, packet):
290        with self._lock:
291            self._rpc_connection.read_packet(packet)
292
293    def connect(self):
294        with self._lock:
295            if self.is_active:
296                _logger.warning("Session._connect: already connected.")
297                return
298
299            self._rpc_connection = UniRPCConnection(self._config)
300            self._rpc_connection.connect()
301            self._login()
302
303            # TODO initialize the transaction object
304            # self._transaction = self.Transaction()
305
306            thread_data.session = self
307            # get server version
308            cmd = Command()
309            suffix = "\r\n"
310            if self.db_type == "UV":
311                if self._host_type == 1:
312                    # Unix
313                    cmd.command_text = 'SH -c "uv -version"'
314                else:
315                    cmd.command_text = 'DOS /c "uv -version"'
316                cmd.run()
317                uv1135 = self._get_uv_version("UniVerse 11.3.5")
318                uv_version = self._get_uv_version(cmd.response.removesuffix(suffix))
319                if uv_version is None or uv1135 is None:
320                    raise UOError(ErrorCodes.UOE_UNKNOWN_ERROR)
321                self._uv_timeout_flag = self._compare_version(uv_version, uv1135)
322
323    def _login(self):
324        in_packet = UniRPCPacket()
325        out_packet = UniRPCPacket()
326
327        out_packet.write(0, _COMMS_VERSION)
328        out_packet.write(1, _CS_VERSION)
329        out_packet.write(2, self.encode(self._config[USER]))
330        out_packet.write(3, mangle(self.encode(self._config[PASSWORD]), _COMMS_VERSION))
331        out_packet.write(4, self.encode(self._config[ACCOUNT]))
332        out_packet.write(5, self.encode(self._license_token))
333        out_packet.write(6, _RESERVED)
334
335        ip_int, hostname = get_host_info()
336
337        out_packet.write(7, ip_int)
338        out_packet.write(8, self.encode(self._mac_address))
339        out_packet.write(9, self.encode(hostname))
340        out_packet.write(10, b"")
341
342        if config.pooling[POOLING_ON]:
343            if is_cp_supported(self._rpc_connection.server_id):
344                out_packet.write(11, 1)
345            else:
346                raise UOError(
347                    code=ErrorCodes.UOE_CP_NOTSUPPORTED,
348                    message="Database Server upgrade is needed.",
349                )
350
351        self._config[PASSWORD] = ""
352        self.rpc_call(in_packet, out_packet)
353
354        resp_code = in_packet.read(0)
355        if resp_code == 0:
356            self._nls_init()
357            self._get_host_info()
358            self.is_active = True
359            self._transaction = Transaction(session=self)
360        else:
361            if in_packet.argument_count > 1:
362                last_error = self.decode(in_packet.read(1))
363                raise UOError(message=last_error)
364            else:
365                raise UOError(code=resp_code)
366
367    def _nls_init(self):
368        from ._nlsmap import NLSMap
369
370        in_packet = UniRPCPacket()
371        out_packet = UniRPCPacket()
372        out_packet.write(0, FuncCodes.EIC_GETSERVERINFO)
373        self.rpc_call(in_packet, out_packet)
374
375        resp_code = in_packet.read(0)
376        if resp_code != 0:
377            raise UOError(code=resp_code)
378
379        nls_mode = in_packet.read(1)
380        nls_lc_mode = in_packet.read(2)
381
382        if nls_mode == 1:
383            self._is_nls_enabled = True
384            if nls_lc_mode == 1:
385                self._is_nls_locale_enabled = True
386        elif nls_mode == 2:
387            self._is_ud = True
388        elif nls_mode == 3:
389            self._is_d3 = True
390
391        if self._is_nls_enabled or self._is_ud:
392            NLSMap(self).set_server_map_name("NONE")
393            if self._is_nls_enabled:
394                self.encoding = "UTF-8"
395
396            # if self.is_nls_locale_enabled:
397            #     _NLSLocale(self).set_server_locale_names("DEFAULT")
398
399    def _get_host_info(self):
400        in_packet = UniRPCPacket()
401        out_packet = UniRPCPacket()
402        out_packet.write(0, FuncCodes.EIC_SESSIONINFO)
403
404        self.rpc_call(in_packet, out_packet)
405
406        resp_code = in_packet.read(0)
407        if resp_code == 0:
408            self._host_type = in_packet.read(2)
409        else:
410            raise UOError(code=resp_code)
411
412    def check_rpc_error(self, e):
413        if e.code in _RPC_ERRORS:
414            self._is_rpc_failed = True
415
416    def health_check(self):
417        with self._lock:
418            if self._is_rpc_failed:
419                _logger.debug("RPC failed")
420                return False
421
422        return self._rpc_connection.health_check()
423
424    def hard_close(self):
425        try:
426            self._rpc_connection.close()
427
428            with self._lock:
429                if self.__pool:
430                    self.__pool.hard_free(self)
431
432        except Exception as e:
433            _logger.warning(str(e))
434        finally:
435            self.is_active = False
436            self._rpc_connection = None
437            thread_data.session = None
438
439        _logger.debug("Exit", id(self), "is hard-closed ")
440
441    def get_atvar(self, atvar):
442        """Get a @var value from the server.
443
444        Args:
445            atvar: uopy.AtVar enum.
446
447        Returns:
448            DynArray: the value of the @var
449
450        Raises:
451            UOError
452
453        Examples:
454            >>> import uopy
455            >>> for atvar in uopy.AtVar:
456                    print(atvar.name, atvar.value)
457
458            LOG_NAME 1
459            PATH 2
460            USER_NO 3
461            WHO 4
462            TRANSACTION 5
463            DATA_PENDING 6
464            USER_RETURN_CODE 7
465            SYSTEM_RETURN_CODE 8
466            NULL_STR 9
467            SCHEMA 10
468            TRANSACTION_LEVEL 11
469
470            >>>
471            >>> with uopy.connect(user='test_user', password='test_password') as session:
472                    log_name = session.get_atvar(uopy.AtVar.LOG_NAME)
473                    account_path = session.get_atvar(uopy.AtVar.PATH)
474                    print(log_name)
475                    print(account_path)
476
477            test_user
478            C:\\U2\\ud82\\XDEMO
479
480        """
481        _logger.debug("Enter", atvar)
482
483        self._check_callable()
484
485        with self._lock:
486            in_packet = UniRPCPacket()
487            out_packet = UniRPCPacket()
488            out_packet.write(0, FuncCodes.EIC_GETVALUE)
489            out_packet.write(1, atvar.value)
490
491            self._rpc_connection.call(in_packet, out_packet)
492
493            resp_code = in_packet.read(0)
494            if resp_code == 0:
495                _logger.debug("Exit")
496                return DynArray(in_packet.read(1), self)
497            else:
498                raise UOError(code=resp_code)
499
500    def reset(self):
501        _logger.debug("Enter", id(self))
502
503        if self._is_rpc_failed:
504            return False
505
506        if self._command:
507            tmp_command = self._command
508            self._command = None
509
510            if tmp_command.status in {EXEC_MORE_OUTPUT, EXEC_REPLY}:
511                _logger.warning("Session is in the middle of a command execution.")
512                return False
513
514        if self.tx_is_active():
515            _logger.warning(
516                "Session is in the middle of a transaction, will try to roll back."
517            )
518            try:
519                self._transaction.rollback()
520            except Exception as e:
521                _logger.warning("Error occurred during transaction roll back." + str(e))
522                return False
523
524        _logger.debug("Exit")
525        return True
526
527    def close(self):
528        """Close the session or return it to the connection pool.
529
530        Raises:
531            UOError
532
533        """
534        _logger.debug("Enter", id(self))
535        if not self.is_active:
536            _logger.warning("Session::disconnect: session is inactive.")
537            return
538
539        with self._lock:
540            if self.__pool:
541                self.__pool.free(self)
542            else:
543                # self.reset()
544                self.hard_close()
545
546        _logger.debug("Exit")
547
548    def bind_command(self, command_obj):
549        if self._command:
550            _logger.warning(
551                "A session can only have one bound Command object, will replace the old one"
552            )
553        self._command = command_obj
554
555    def tx_start(self):
556        """Start a transaction on the server.
557
558        Args:
559
560        Returns:
561            None
562
563        Raises:
564            UOError
565
566        """
567        self._transaction.begin()
568
569    def tx_commit(self):
570        """Commit the current transaction on the server.
571
572        Args:
573
574        Returns:
575            None
576
577        Raises:
578            UOError
579
580        """
581        self._transaction.commit()
582
583    def tx_rollback(self):
584        """Roll back the current transaction on the server.
585
586        Args:
587
588        Returns:
589            None
590
591        Raises:
592            UOError
593
594        """
595
596        self._transaction.rollback()
597
598    def tx_level(self):
599        """Return the current transaction level on the server
600
601        Args:
602
603        Returns:
604            int: the current transaction level
605
606        Raises:
607             UOError
608
609        """
610        return int(str(self.get_atvar(AtVar.TRANSACTION_LEVEL)))
611
612    def tx_is_active(self):
613        """Check if a transaction is active on the server.
614
615        Args:
616
617        Returns:
618            True/False: in transaction or not
619
620        Raises:
621            UOError
622
623        """
624        resp = self.get_atvar(AtVar.TRANSACTION)
625        if resp == "" or resp == "0":
626            return False
627        else:
628            return True
629
630    def _server_transaction(self, tx_key):
631        _logger.debug("Enter", tx_key)
632
633        with self.lock:
634            in_packet = UniRPCPacket()
635            out_packet = UniRPCPacket()
636
637            out_packet.write(0, FuncCodes.EIC_TRANSACTION)
638            out_packet.write(1, tx_key)
639
640            try:
641                self._rpc_connection.call(in_packet, out_packet, self.encryption_type)
642                ret_code = in_packet.read(0)
643            except Exception as e:
644                raise UOError(message=str(e))
645
646            if ret_code == 0:
647                pass
648            else:
649                self._session.check_rpc_is_failed(ret_code)
650                self.status = in_packet.read(1)
651                raise UOError(code=ret_code)
652
653        _logger.info("Exit")

A Session represents a MV database connection. It is the foundation for and embedded in other UOPY objects.

Session objects can be used in Python with statement so that whatever happens in the with statement block, they are guaranteed to be closed upon exit.

Applications can also perform transactions on a Session, and get supported @var values from the server.

Note: Applications should call uopy.connect() to get a Session object instead of directly instantiating a Session.

Examples:

>>> with uopy.connect(user='test', password='test'):
>>>     cmd = uopy.Command("LIST VOC")
>>>     cmd.run()
>>>     print(cmd.response)


>>> with uopy.connect(user="test", password="test") as session:
>>>     session.tx_start()
>>>     print(session.tx_is_active())
...
>>>     session.tx_commit()
Session(connect_config)
 75    def __init__(self, connect_config):
 76        _logger.debug(
 77            "Enter", {k: connect_config[k] for k in connect_config if k != "password"}
 78        )
 79
 80        self._config = connect_config
 81
 82        self._lock = threading.RLock()
 83
 84        self._rpc_connection = None
 85        self._is_rpc_failed = False
 86
 87        self._is_nls_enabled = False
 88        self._is_nls_locale_enabled = False
 89        self._is_ud = False
 90        self._is_d3 = False
 91
 92        self.__pool = None
 93        self._idle_start_time = 0
 94
 95        self._mac_address = "JAVA"
 96        self._license_token = ""
 97
 98        self._host_type = None
 99        self._command = None
100        self._transaction = None
101
102        self.is_active = False
103        self.marks = DEFAULT_MARKS
104
105        self._uoserver_timeout = None
106        self._uv_timeout_flag = False
is_active
marks
def bind_pool(self, pool):
123    def bind_pool(self, pool):
124        self.__pool = pool
config

A copy of all the configuration parameters for this session.

idle_start_time
def start_idle(self):
135    def start_idle(self):
136        self._idle_start_time = time.time()
db_type

str: either "UD' for UniData,'UV' for UniVerse, or "D3" for D3.

is_nls_enabled

boolean: whether NLS is enabled on the server.

encoding

The name of the character encoding used for conversion between Python unicode strings and MV data.

By default it is set to the local system's preferred encoding when server NLS is off, and to UTF-8 when server NLS is on. However it can be overridden by the application to what reflects the actual encoding of the server data.

uoserver_timeout

The following code snippet retrieves the UO Server timeout value after connecting to the server: ses = uopy.connect(user=user,password=passwd) uotimeout = ses.uoserver_timeout On the server side, the timeout can be set in the unirpcservice file and passed as an argument when the uvapi_server process is started.

def sync_marks(self, mark_list):
252    def sync_marks(self, mark_list):
253        self.marks = MARKS_NAMED_TUPLE(*mark_list)
def encode(self, obj):
255    def encode(self, obj):
256        if isinstance(obj, str):
257            return obj.encode(self._config[ENCODING], errors="replace")
258        elif isinstance(obj, bytes) or isinstance(obj, bytearray):
259            return obj
260        elif isinstance(obj, MvDelimited):
261            return bytes(obj)
262        elif isinstance(obj, list):
263            return bytes(MvDelimited(obj=obj, session=self))
264        elif obj is None:
265            return b""
266        else:
267            return str(obj).encode(self._config[ENCODING], errors="replace")
def decode(self, obj):
269    def decode(self, obj):
270        if isinstance(obj, bytes) or isinstance(obj, bytearray):
271            return obj.decode(self._config[ENCODING], errors="replace")
272        else:
273            return str(obj)
def rpc_call(self, in_packet, out_packet, in_exec=False):
284    def rpc_call(self, in_packet, out_packet, in_exec=False):
285        with self._lock:
286            self._check_callable(in_exec)
287            self._rpc_connection.call(in_packet, out_packet)
def read_packet4cmd(self, packet):
289    def read_packet4cmd(self, packet):
290        with self._lock:
291            self._rpc_connection.read_packet(packet)
def connect(self):
293    def connect(self):
294        with self._lock:
295            if self.is_active:
296                _logger.warning("Session._connect: already connected.")
297                return
298
299            self._rpc_connection = UniRPCConnection(self._config)
300            self._rpc_connection.connect()
301            self._login()
302
303            # TODO initialize the transaction object
304            # self._transaction = self.Transaction()
305
306            thread_data.session = self
307            # get server version
308            cmd = Command()
309            suffix = "\r\n"
310            if self.db_type == "UV":
311                if self._host_type == 1:
312                    # Unix
313                    cmd.command_text = 'SH -c "uv -version"'
314                else:
315                    cmd.command_text = 'DOS /c "uv -version"'
316                cmd.run()
317                uv1135 = self._get_uv_version("UniVerse 11.3.5")
318                uv_version = self._get_uv_version(cmd.response.removesuffix(suffix))
319                if uv_version is None or uv1135 is None:
320                    raise UOError(ErrorCodes.UOE_UNKNOWN_ERROR)
321                self._uv_timeout_flag = self._compare_version(uv_version, uv1135)
def check_rpc_error(self, e):
412    def check_rpc_error(self, e):
413        if e.code in _RPC_ERRORS:
414            self._is_rpc_failed = True
def health_check(self):
416    def health_check(self):
417        with self._lock:
418            if self._is_rpc_failed:
419                _logger.debug("RPC failed")
420                return False
421
422        return self._rpc_connection.health_check()
def hard_close(self):
424    def hard_close(self):
425        try:
426            self._rpc_connection.close()
427
428            with self._lock:
429                if self.__pool:
430                    self.__pool.hard_free(self)
431
432        except Exception as e:
433            _logger.warning(str(e))
434        finally:
435            self.is_active = False
436            self._rpc_connection = None
437            thread_data.session = None
438
439        _logger.debug("Exit", id(self), "is hard-closed ")
def get_atvar(self, atvar):
441    def get_atvar(self, atvar):
442        """Get a @var value from the server.
443
444        Args:
445            atvar: uopy.AtVar enum.
446
447        Returns:
448            DynArray: the value of the @var
449
450        Raises:
451            UOError
452
453        Examples:
454            >>> import uopy
455            >>> for atvar in uopy.AtVar:
456                    print(atvar.name, atvar.value)
457
458            LOG_NAME 1
459            PATH 2
460            USER_NO 3
461            WHO 4
462            TRANSACTION 5
463            DATA_PENDING 6
464            USER_RETURN_CODE 7
465            SYSTEM_RETURN_CODE 8
466            NULL_STR 9
467            SCHEMA 10
468            TRANSACTION_LEVEL 11
469
470            >>>
471            >>> with uopy.connect(user='test_user', password='test_password') as session:
472                    log_name = session.get_atvar(uopy.AtVar.LOG_NAME)
473                    account_path = session.get_atvar(uopy.AtVar.PATH)
474                    print(log_name)
475                    print(account_path)
476
477            test_user
478            C:\\U2\\ud82\\XDEMO
479
480        """
481        _logger.debug("Enter", atvar)
482
483        self._check_callable()
484
485        with self._lock:
486            in_packet = UniRPCPacket()
487            out_packet = UniRPCPacket()
488            out_packet.write(0, FuncCodes.EIC_GETVALUE)
489            out_packet.write(1, atvar.value)
490
491            self._rpc_connection.call(in_packet, out_packet)
492
493            resp_code = in_packet.read(0)
494            if resp_code == 0:
495                _logger.debug("Exit")
496                return DynArray(in_packet.read(1), self)
497            else:
498                raise UOError(code=resp_code)

Get a @var value from the server.

Args: atvar: uopy.AtVar enum.

Returns: DynArray: the value of the @var

Raises: UOError

Examples:

import uopy for atvar in uopy.AtVar: print(atvar.name, atvar.value)

LOG_NAME 1
PATH 2
USER_NO 3
WHO 4
TRANSACTION 5
DATA_PENDING 6
USER_RETURN_CODE 7
SYSTEM_RETURN_CODE 8
NULL_STR 9
SCHEMA 10
TRANSACTION_LEVEL 11

>>>
>>> with uopy.connect(user='test_user', password='test_password') as session:
        log_name = session.get_atvar(uopy.AtVar.LOG_NAME)
        account_path = session.get_atvar(uopy.AtVar.PATH)
        print(log_name)
        print(account_path)

test_user
C:\U2\ud82\XDEMO
def reset(self):
500    def reset(self):
501        _logger.debug("Enter", id(self))
502
503        if self._is_rpc_failed:
504            return False
505
506        if self._command:
507            tmp_command = self._command
508            self._command = None
509
510            if tmp_command.status in {EXEC_MORE_OUTPUT, EXEC_REPLY}:
511                _logger.warning("Session is in the middle of a command execution.")
512                return False
513
514        if self.tx_is_active():
515            _logger.warning(
516                "Session is in the middle of a transaction, will try to roll back."
517            )
518            try:
519                self._transaction.rollback()
520            except Exception as e:
521                _logger.warning("Error occurred during transaction roll back." + str(e))
522                return False
523
524        _logger.debug("Exit")
525        return True
def close(self):
527    def close(self):
528        """Close the session or return it to the connection pool.
529
530        Raises:
531            UOError
532
533        """
534        _logger.debug("Enter", id(self))
535        if not self.is_active:
536            _logger.warning("Session::disconnect: session is inactive.")
537            return
538
539        with self._lock:
540            if self.__pool:
541                self.__pool.free(self)
542            else:
543                # self.reset()
544                self.hard_close()
545
546        _logger.debug("Exit")

Close the session or return it to the connection pool.

Raises: UOError

def bind_command(self, command_obj):
548    def bind_command(self, command_obj):
549        if self._command:
550            _logger.warning(
551                "A session can only have one bound Command object, will replace the old one"
552            )
553        self._command = command_obj
def tx_start(self):
555    def tx_start(self):
556        """Start a transaction on the server.
557
558        Args:
559
560        Returns:
561            None
562
563        Raises:
564            UOError
565
566        """
567        self._transaction.begin()

Start a transaction on the server.

Args:

Returns: None

Raises: UOError

def tx_commit(self):
569    def tx_commit(self):
570        """Commit the current transaction on the server.
571
572        Args:
573
574        Returns:
575            None
576
577        Raises:
578            UOError
579
580        """
581        self._transaction.commit()

Commit the current transaction on the server.

Args:

Returns: None

Raises: UOError

def tx_rollback(self):
583    def tx_rollback(self):
584        """Roll back the current transaction on the server.
585
586        Args:
587
588        Returns:
589            None
590
591        Raises:
592            UOError
593
594        """
595
596        self._transaction.rollback()

Roll back the current transaction on the server.

Args:

Returns: None

Raises: UOError

def tx_level(self):
598    def tx_level(self):
599        """Return the current transaction level on the server
600
601        Args:
602
603        Returns:
604            int: the current transaction level
605
606        Raises:
607             UOError
608
609        """
610        return int(str(self.get_atvar(AtVar.TRANSACTION_LEVEL)))

Return the current transaction level on the server

Args:

Returns: int: the current transaction level

Raises: UOError

def tx_is_active(self):
612    def tx_is_active(self):
613        """Check if a transaction is active on the server.
614
615        Args:
616
617        Returns:
618            True/False: in transaction or not
619
620        Raises:
621            UOError
622
623        """
624        resp = self.get_atvar(AtVar.TRANSACTION)
625        if resp == "" or resp == "0":
626            return False
627        else:
628            return True

Check if a transaction is active on the server.

Args:

Returns: True/False: in transaction or not

Raises: UOError

class Command(uopy._uniobject.UniObject):
 21class Command(UniObject):
 22    """Command allows applications to run MV ECL/TCL commands or stored procedures on the remote server.
 23
 24    After a command is executed, it can have one of these three status:
 25        EXEC_COMPLETE: the command execution has completed.
 26
 27        EXEC_REPLY: the command awaits user input - the reply() method can be called to provide an input.
 28
 29        EXEC_MORE_OUTPUT: the command output buffer isn't big enough to hold all the results. In this case,
 30            the next_response() method can be called to get the next block of the response.
 31
 32    When the status is either EXEC_REPLY or EXEC_MORE_OUTPUT, the cancel() method can be called to terminate
 33    the command execution.
 34
 35    Attributes:
 36        command_text (str): the command text.
 37        at_system_return_code (int) : the value of the system variable @SYSTEM.RETURN.CODE on the server.
 38        at_selected (int): The value of the system variable @SELECTED on the server.
 39
 40    Examples:
 41
 42        >>> with uopy.connect(user='test', password='test'):
 43        >>>     cmd = uopy.Command("LIST VOC")
 44        >>>     cmd.run()
 45        >>>     print(cmd.response)
 46
 47        >>> with uopy.connect(user='test', password='test'):
 48        >>>     cmd = uopy.Command("RUN BP SAYHELLOTO")
 49        >>>     if cmd.status == uopy.EXEC_REPLY:
 50        >>>         cmd.reply("MV loyal user")
 51        >>>     print(cmd.response)
 52
 53    """
 54
 55    def __init__(self, command_text=None, session=None):
 56        """Initialize a Command object
 57
 58        Args:
 59            command_text (str, optional): the TCL/ECL command to be executed on the remote server.
 60            session (Session, optional): the Session object that the Command object is bound to.
 61                If omitted, the last opened Session in the current thread will be used.
 62
 63        Raises:
 64            UOError
 65
 66        """
 67        super().__init__(session)
 68
 69        self._buffer_size = _EXEC_DEFAULT_BUFFER_SIZE
 70        self._status = EXEC_COMPLETE
 71        self._response = ""
 72        self._next_block = ""
 73        self.command_text = "" if command_text is None else command_text
 74        self.at_system_return_code = 0
 75        self.at_selected = 0
 76        self._is_fetch_all = True
 77        self._session.bind_command(self)
 78
 79    def __repr__(self):
 80        format_string = "<{} object {} at 0x{:016X}>"
 81        details = {"command_text": self.command_text}
 82        return format_string.format(
 83            ".".join([Command.__module__, Command.__qualname__]), details, id(self)
 84        )
 85
 86    @property
 87    def status(self):
 88        """int: The current status of the Command object."""
 89        return self._status
 90
 91    @property
 92    def response(self):
 93        """str: The current response of the Command object from the server."""
 94        return self._response
 95
 96    @property
 97    def buffer_size(self):
 98        """int: The size of the output buffer for the Command object.
 99
100        If left unset, all the output of the command execution will be brought back at once.
101        If set explicitly, only the output of the specified size will be returned.
102
103        """
104        return self._buffer_size
105
106    @buffer_size.setter
107    def buffer_size(self, value):
108        if not isinstance(value, int):
109            raise UOError(message="output buffer size must be an integer!")
110        if value <= 0:
111            raise UOError(message="output buffer size must between greater than 0!")
112        self._buffer_size = value
113        self._is_fetch_all = False
114
115    def _exec(self, server_command, input_reply):
116        in_packet = UniRPCPacket()
117        out_packet = UniRPCPacket()
118
119        out_packet.write(0, server_command)
120
121        if server_command == FuncCodes.EIC_EXECUTE:
122            out_packet.write(1, self._buffer_size)
123            out_packet.write(2, self._session.encode(self.command_text))
124        elif server_command == FuncCodes.EIC_EXECUTECONTINUE:
125            out_packet.write(1, self._buffer_size)
126        elif server_command == FuncCodes.EIC_INPUTREPLY:
127            reply_str = input_reply + "\n"
128            out_packet.write(1, self._session.encode(reply_str))
129            out_packet.write(2, self._buffer_size)
130        else:
131            raise UOError(code=ErrorCodes.UOE_EINVAL)
132
133        resp_code = self._call_server(in_packet, out_packet, in_exec=True)
134
135        if resp_code == _EXEC_END:
136            tmp_resp = self._session.decode(in_packet.read(1))
137            self._session.read_packet4cmd(in_packet)
138            self.at_system_return_code = in_packet.read(1)
139            self.at_selected = in_packet.read(2)
140            resp_code = EXEC_COMPLETE
141        elif resp_code == _EXEC_BTS:
142            tmp_resp = self._session.decode(in_packet.read(1))
143            resp_code = EXEC_MORE_OUTPUT
144        elif resp_code == _EXEC_AT_INPUT:
145            tmp_resp = self._session.decode(in_packet.read(1))
146            resp_code = EXEC_REPLY
147        else:
148            e = UOError(code=resp_code)
149            _logger.debug(e)
150            raise e
151
152        if server_command == FuncCodes.EIC_EXECUTECONTINUE:
153            self._next_block = tmp_resp
154        else:
155            self._response = tmp_resp
156
157        _logger.debug("Response", tmp_resp, resp_code)
158        return resp_code
159
160    def _fetch_all(self, resp_code):
161        while resp_code == EXEC_MORE_OUTPUT:
162            resp_code = self._exec(FuncCodes.EIC_EXECUTECONTINUE, "")
163            if resp_code in [EXEC_MORE_OUTPUT, EXEC_COMPLETE]:
164                self._response += self._next_block
165        return resp_code
166
167    def run(self):
168        """Execute the command on the remote server.
169
170        Args:
171
172        Returns:
173            None
174
175        Raises:
176            UOError
177
178        """
179        _logger.debug("Enter", self.command_text)
180
181        with self._lock:
182            if self._status in {EXEC_MORE_OUTPUT, EXEC_REPLY}:
183                raise UOError(code=ErrorCodes.UOE_EXECUTEISACTIVE)
184
185            if self.command_text is None or self.command_text == "":
186                raise UOError(
187                    ErrorCodes.UOE_USAGE_ERROR, message="invalid command_text"
188                )
189
190            self.at_system_return_code = 0
191            self.at_selected = 0
192            self._response = ""
193
194            resp_code = self._exec(FuncCodes.EIC_EXECUTE, "")
195            self._status = resp_code
196
197            if self._is_fetch_all and resp_code == EXEC_MORE_OUTPUT:
198                self._status = self._fetch_all(resp_code)
199
200        _logger.debug("Exit", self._status, self._response)
201
202    def cancel(self):
203        """Cancel the execution of the command.
204
205        Args:
206
207        Returns:
208            None
209
210        Raises:
211            UOError
212
213        """
214        _logger.debug("Enter")
215
216        with self._lock:
217            in_packet = UniRPCPacket()
218            out_packet = UniRPCPacket()
219
220            if self._status in {EXEC_REPLY, EXEC_MORE_OUTPUT}:
221                self._status = EXEC_COMPLETE
222
223                out_packet.write(0, FuncCodes.EIC_CANCEL)
224
225                resp_code = self._call_server(in_packet, out_packet)
226
227                resp_code = in_packet.read(0)
228                if resp_code != 0:
229                    e = UOError(code=resp_code)
230                    _logger.debug(e)
231                    raise e
232            else:
233                _logger.warning("execution already finished")
234
235        _logger.debug("Exit")
236
237    def reply(self, reply_data):
238        """Send a reply to the server to continue the command execution.
239
240        Args:
241            reply_data: the input for the command.
242
243        Returns:
244            None
245
246        Raises:
247            UOError
248
249        """
250        _logger.debug("Enter", reply_data)
251
252        with self._lock:
253            if self._status != EXEC_REPLY:
254                raise UOError(code=ErrorCodes.UOE_NOTATINPUT)
255
256            # reply_data += "\n"
257            resp_code = self._exec(FuncCodes.EIC_INPUTREPLY, reply_data)
258
259            self._status = resp_code
260            if self._is_fetch_all and resp_code == EXEC_MORE_OUTPUT:
261                self._status = self._fetch_all(resp_code)
262
263        _logger.debug("Exit", self._status)
264
265    def next_response(self):
266        """Get the next block of output from the server.
267
268        Args:
269
270        Returns:
271            None
272
273        Raises:
274            UOError
275
276        """
277        _logger.debug("Enter")
278
279        with self._lock:
280            if self._status != EXEC_MORE_OUTPUT:
281                raise UOError(code=ErrorCodes.UOE_NOMORE)
282
283            self._response = None
284            resp_code = self._exec(FuncCodes.EIC_EXECUTECONTINUE, "")
285
286            self._response = self._next_block
287
288            self._status = resp_code
289            if self._is_fetch_all and resp_code == EXEC_MORE_OUTPUT:
290                self._status = self._fetch_all(resp_code)
291
292        _logger.debug("Exit", self._status, self._response)

Command allows applications to run MV ECL/TCL commands or stored procedures on the remote server.

After a command is executed, it can have one of these three status: EXEC_COMPLETE: the command execution has completed.

EXEC_REPLY: the command awaits user input - the reply() method can be called to provide an input.

EXEC_MORE_OUTPUT: the command output buffer isn't big enough to hold all the results. In this case,
    the next_response() method can be called to get the next block of the response.

When the status is either EXEC_REPLY or EXEC_MORE_OUTPUT, the cancel() method can be called to terminate the command execution.

Attributes: command_text (str): the command text. at_system_return_code (int) : the value of the system variable @SYSTEM.RETURN.CODE on the server. at_selected (int): The value of the system variable @SELECTED on the server.

Examples:

>>> with uopy.connect(user='test', password='test'):
>>>     cmd = uopy.Command("LIST VOC")
>>>     cmd.run()
>>>     print(cmd.response)

>>> with uopy.connect(user='test', password='test'):
>>>     cmd = uopy.Command("RUN BP SAYHELLOTO")
>>>     if cmd.status == uopy.EXEC_REPLY:
>>>         cmd.reply("MV loyal user")
>>>     print(cmd.response)
Command(command_text=None, session=None)
55    def __init__(self, command_text=None, session=None):
56        """Initialize a Command object
57
58        Args:
59            command_text (str, optional): the TCL/ECL command to be executed on the remote server.
60            session (Session, optional): the Session object that the Command object is bound to.
61                If omitted, the last opened Session in the current thread will be used.
62
63        Raises:
64            UOError
65
66        """
67        super().__init__(session)
68
69        self._buffer_size = _EXEC_DEFAULT_BUFFER_SIZE
70        self._status = EXEC_COMPLETE
71        self._response = ""
72        self._next_block = ""
73        self.command_text = "" if command_text is None else command_text
74        self.at_system_return_code = 0
75        self.at_selected = 0
76        self._is_fetch_all = True
77        self._session.bind_command(self)

Initialize a Command object

Args: command_text (str, optional): the TCL/ECL command to be executed on the remote server. session (Session, optional): the Session object that the Command object is bound to. If omitted, the last opened Session in the current thread will be used.

Raises: UOError

command_text
at_system_return_code
at_selected
status

int: The current status of the Command object.

response

str: The current response of the Command object from the server.

buffer_size

int: The size of the output buffer for the Command object.

If left unset, all the output of the command execution will be brought back at once. If set explicitly, only the output of the specified size will be returned.

def run(self):
167    def run(self):
168        """Execute the command on the remote server.
169
170        Args:
171
172        Returns:
173            None
174
175        Raises:
176            UOError
177
178        """
179        _logger.debug("Enter", self.command_text)
180
181        with self._lock:
182            if self._status in {EXEC_MORE_OUTPUT, EXEC_REPLY}:
183                raise UOError(code=ErrorCodes.UOE_EXECUTEISACTIVE)
184
185            if self.command_text is None or self.command_text == "":
186                raise UOError(
187                    ErrorCodes.UOE_USAGE_ERROR, message="invalid command_text"
188                )
189
190            self.at_system_return_code = 0
191            self.at_selected = 0
192            self._response = ""
193
194            resp_code = self._exec(FuncCodes.EIC_EXECUTE, "")
195            self._status = resp_code
196
197            if self._is_fetch_all and resp_code == EXEC_MORE_OUTPUT:
198                self._status = self._fetch_all(resp_code)
199
200        _logger.debug("Exit", self._status, self._response)

Execute the command on the remote server.

Args:

Returns: None

Raises: UOError

def cancel(self):
202    def cancel(self):
203        """Cancel the execution of the command.
204
205        Args:
206
207        Returns:
208            None
209
210        Raises:
211            UOError
212
213        """
214        _logger.debug("Enter")
215
216        with self._lock:
217            in_packet = UniRPCPacket()
218            out_packet = UniRPCPacket()
219
220            if self._status in {EXEC_REPLY, EXEC_MORE_OUTPUT}:
221                self._status = EXEC_COMPLETE
222
223                out_packet.write(0, FuncCodes.EIC_CANCEL)
224
225                resp_code = self._call_server(in_packet, out_packet)
226
227                resp_code = in_packet.read(0)
228                if resp_code != 0:
229                    e = UOError(code=resp_code)
230                    _logger.debug(e)
231                    raise e
232            else:
233                _logger.warning("execution already finished")
234
235        _logger.debug("Exit")

Cancel the execution of the command.

Args:

Returns: None

Raises: UOError

def reply(self, reply_data):
237    def reply(self, reply_data):
238        """Send a reply to the server to continue the command execution.
239
240        Args:
241            reply_data: the input for the command.
242
243        Returns:
244            None
245
246        Raises:
247            UOError
248
249        """
250        _logger.debug("Enter", reply_data)
251
252        with self._lock:
253            if self._status != EXEC_REPLY:
254                raise UOError(code=ErrorCodes.UOE_NOTATINPUT)
255
256            # reply_data += "\n"
257            resp_code = self._exec(FuncCodes.EIC_INPUTREPLY, reply_data)
258
259            self._status = resp_code
260            if self._is_fetch_all and resp_code == EXEC_MORE_OUTPUT:
261                self._status = self._fetch_all(resp_code)
262
263        _logger.debug("Exit", self._status)

Send a reply to the server to continue the command execution.

Args: reply_data: the input for the command.

Returns: None

Raises: UOError

def next_response(self):
265    def next_response(self):
266        """Get the next block of output from the server.
267
268        Args:
269
270        Returns:
271            None
272
273        Raises:
274            UOError
275
276        """
277        _logger.debug("Enter")
278
279        with self._lock:
280            if self._status != EXEC_MORE_OUTPUT:
281                raise UOError(code=ErrorCodes.UOE_NOMORE)
282
283            self._response = None
284            resp_code = self._exec(FuncCodes.EIC_EXECUTECONTINUE, "")
285
286            self._response = self._next_block
287
288            self._status = resp_code
289            if self._is_fetch_all and resp_code == EXEC_MORE_OUTPUT:
290                self._status = self._fetch_all(resp_code)
291
292        _logger.debug("Exit", self._status, self._response)

Get the next block of output from the server.

Args:

Returns: None

Raises: UOError

class DynArray(uopy._mvdelimited.MvDelimited):
 15class DynArray(MvDelimited):
 16    """DynArray represents MV delimited data as nested lists and supports most common Python list methods.
 17
 18    Specifically, a DynArray works with MV delimiters automatically and transparently. It can be used just like a Python
 19    list and should only be used in that manner. It is a best practice that applications do not use MV delimiters
 20    directly for internationalization reasons. Please remember that a DynArray can be passed directly to any UOPY method
 21    where MV delimited data is expected, such as file.write(), the application doesn't need to convert it first.
 22
 23    Two convenience methods: make_list and make_nested_list are provided to convert a field itself into a list or nested
 24    list. They are useful if the original field is multivalued or multi-sub-valued, but may contain scalar values.
 25    Calling them first on a field will ensure that you can safely treat the field as a list or nested list.
 26
 27    In addition, DynArray also supports two unique MV conversion functions: iconv and oconv. The details of these
 28    conversion functions are documented under each method. Because they call the remote server to do the conversion,
 29    it is strongly recommended that applications use File.read_named_fields() and File.write_named_fields() instead
 30    when reading data from or writing data to the server. They automatically perform the iconv and oconv on the
 31    specified fields on the server, and thus save a rpc call across the network.
 32
 33    Two DynArray objects can perform the mathematical operations of + and += the same way in which a python list does.
 34    However, if one of the two objects are not the DynArray type, it will throw the TypeError.
 35    """
 36
 37    def __init__(self, obj=None, session=None):
 38        """Initialize a DynArray object.
 39
 40        Args:
 41            obj (any, optional): can be a Python list, a string, a byte object, or another DynArray.
 42            session (Session, optional): the Session object that the DynArray object is bound to.
 43                If omitted, the last opened Session in the current thread will be used.
 44
 45        Raises:
 46            UOError
 47
 48        """
 49        super().__init__(obj, session)
 50
 51    def __repr__(self):
 52        self._build_list()
 53        format_string = "<{} object {} at 0x{:016X}>"
 54        details = self._list
 55        return format_string.format(
 56            ".".join([DynArray.__module__, DynArray.__qualname__]), details, id(self)
 57        )
 58
 59    def __add__(self, other):
 60        if isinstance(other, DynArray):
 61            return DynArray(self._list + other._list)
 62        else:
 63            raise TypeError("can only concatenate DynArray to DynArray")
 64
 65    def __iadd__(self, other):
 66        if isinstance(other, DynArray):
 67            self._list += other._list
 68            return self
 69        else:
 70            raise TypeError("can only concatenate DynArray to DynArray")
 71
 72    def make_list(self, index):
 73        """Check if the list item is a list itself - if not, make it as such.
 74
 75        Args:
 76            index (int): the index of the list item.
 77
 78        Returns:
 79            None
 80
 81        Examples:
 82            >>> d = uopy.DynArray([1, 2])
 83            >>> d.make_list(1)
 84            >>> d[1].append(3)
 85            >>> print(d.list)
 86            [1, [2, 3]]
 87
 88        """
 89        self._build_list()
 90        if not isinstance(self._list[index], list):
 91            self._list[index] = [self._list[index]]
 92
 93    def make_nested_list(self, index):
 94        """Check if the list item is a nested list itself - if not, make it as such.
 95
 96        Args:
 97            index (int): the index of the list item.
 98
 99        Returns:
100            None
101
102        Examples:
103            >>> d = uopy.DynArray([1, 2])
104            >>> d.make_nested_list(1)
105            >>> d[1][0].append(3)
106            >>> print(d.list)
107            [1, [[2, 3]]]
108
109        """
110        self._build_list()
111        if not isinstance(self._list[index], list):
112            self._list[index] = [[self._list[index]]]
113            return
114
115        for i, v in enumerate(self._list[index]):
116            if not isinstance(v, list):
117                self._list[index][i] = [v]
118
119    def iconv(self, conversion_code):
120        """Return the internal storage value of the DynArray based on the conversion code.
121
122        Args:
123            conversion_code (str):  the MV conversion code.
124
125        Returns:
126            DynArray: the internal storage value.
127
128        Raises:
129            UOError
130
131        """
132        return self._server_conv(conversion_code, FuncCodes.EIC_ICONV)
133
134    def oconv(self, conversion_code):
135        """Return the output format of the DynArray based on the conversion code.
136
137        Args:
138            conversion_code (str): the MV conversion code.
139
140        Returns:
141            DynArray: the output format.
142
143        Raises:
144            UOError
145
146        """
147        return self._server_conv(conversion_code, FuncCodes.EIC_OCONV)
148
149    def format(self, format_code):
150        """Return the formatted value of the DynArray based on the format code.
151
152        Args:
153            format_code (str): the format code.
154
155        Returns:
156            DynArray: the formatted value.
157
158        Raises:
159            UOError
160
161        """
162        return self._server_conv(format_code, FuncCodes.EIC_FMT)
163
164    def _server_conv(self, conversion_code, func_code):
165        _logger.debug("Enter", conversion_code, func_code, self.__bytes__())
166
167        with self._lock:
168            in_packet = UniRPCPacket()
169            out_packet = UniRPCPacket()
170            out_packet.write(0, func_code)
171            if func_code == FuncCodes.EIC_FMT:
172                out_packet.write(1, self._session.encode(conversion_code))
173                out_packet.write(2, self.__bytes__())
174            else:
175                out_packet.write(1, self.__bytes__())
176                out_packet.write(2, self._session.encode(conversion_code))
177
178            resp_code = self._call_server(in_packet, out_packet)
179            if resp_code != 0:
180                raise UOError(code=resp_code)
181
182        status = in_packet.read(1)
183        if not status:
184            result = DynArray(in_packet.read(2), self._session)
185            _logger.debug("Exit", result)
186            return result
187        else:
188            raise UOError(code=ErrorCodes.UOE_BAD_CONVERSION_DATA)

DynArray represents MV delimited data as nested lists and supports most common Python list methods.

Specifically, a DynArray works with MV delimiters automatically and transparently. It can be used just like a Python list and should only be used in that manner. It is a best practice that applications do not use MV delimiters directly for internationalization reasons. Please remember that a DynArray can be passed directly to any UOPY method where MV delimited data is expected, such as file.write(), the application doesn't need to convert it first.

Two convenience methods: make_list and make_nested_list are provided to convert a field itself into a list or nested list. They are useful if the original field is multivalued or multi-sub-valued, but may contain scalar values. Calling them first on a field will ensure that you can safely treat the field as a list or nested list.

In addition, DynArray also supports two unique MV conversion functions: iconv and oconv. The details of these conversion functions are documented under each method. Because they call the remote server to do the conversion, it is strongly recommended that applications use File.read_named_fields() and File.write_named_fields() instead when reading data from or writing data to the server. They automatically perform the iconv and oconv on the specified fields on the server, and thus save a rpc call across the network.

Two DynArray objects can perform the mathematical operations of + and += the same way in which a python list does. However, if one of the two objects are not the DynArray type, it will throw the TypeError.

DynArray(obj=None, session=None)
37    def __init__(self, obj=None, session=None):
38        """Initialize a DynArray object.
39
40        Args:
41            obj (any, optional): can be a Python list, a string, a byte object, or another DynArray.
42            session (Session, optional): the Session object that the DynArray object is bound to.
43                If omitted, the last opened Session in the current thread will be used.
44
45        Raises:
46            UOError
47
48        """
49        super().__init__(obj, session)

Initialize a DynArray object.

Args: obj (any, optional): can be a Python list, a string, a byte object, or another DynArray. session (Session, optional): the Session object that the DynArray object is bound to. If omitted, the last opened Session in the current thread will be used.

Raises: UOError

def make_list(self, index):
72    def make_list(self, index):
73        """Check if the list item is a list itself - if not, make it as such.
74
75        Args:
76            index (int): the index of the list item.
77
78        Returns:
79            None
80
81        Examples:
82            >>> d = uopy.DynArray([1, 2])
83            >>> d.make_list(1)
84            >>> d[1].append(3)
85            >>> print(d.list)
86            [1, [2, 3]]
87
88        """
89        self._build_list()
90        if not isinstance(self._list[index], list):
91            self._list[index] = [self._list[index]]

Check if the list item is a list itself - if not, make it as such.

Args: index (int): the index of the list item.

Returns: None

Examples:

d = uopy.DynArray([1, 2]) d.make_list(1) d[1].append(3) print(d.list) [1, [2, 3]]

def make_nested_list(self, index):
 93    def make_nested_list(self, index):
 94        """Check if the list item is a nested list itself - if not, make it as such.
 95
 96        Args:
 97            index (int): the index of the list item.
 98
 99        Returns:
100            None
101
102        Examples:
103            >>> d = uopy.DynArray([1, 2])
104            >>> d.make_nested_list(1)
105            >>> d[1][0].append(3)
106            >>> print(d.list)
107            [1, [[2, 3]]]
108
109        """
110        self._build_list()
111        if not isinstance(self._list[index], list):
112            self._list[index] = [[self._list[index]]]
113            return
114
115        for i, v in enumerate(self._list[index]):
116            if not isinstance(v, list):
117                self._list[index][i] = [v]

Check if the list item is a nested list itself - if not, make it as such.

Args: index (int): the index of the list item.

Returns: None

Examples:

d = uopy.DynArray([1, 2]) d.make_nested_list(1) d[1][0].append(3) print(d.list) [1, [[2, 3]]]

def iconv(self, conversion_code):
119    def iconv(self, conversion_code):
120        """Return the internal storage value of the DynArray based on the conversion code.
121
122        Args:
123            conversion_code (str):  the MV conversion code.
124
125        Returns:
126            DynArray: the internal storage value.
127
128        Raises:
129            UOError
130
131        """
132        return self._server_conv(conversion_code, FuncCodes.EIC_ICONV)

Return the internal storage value of the DynArray based on the conversion code.

Args: conversion_code (str): the MV conversion code.

Returns: DynArray: the internal storage value.

Raises: UOError

def oconv(self, conversion_code):
134    def oconv(self, conversion_code):
135        """Return the output format of the DynArray based on the conversion code.
136
137        Args:
138            conversion_code (str): the MV conversion code.
139
140        Returns:
141            DynArray: the output format.
142
143        Raises:
144            UOError
145
146        """
147        return self._server_conv(conversion_code, FuncCodes.EIC_OCONV)

Return the output format of the DynArray based on the conversion code.

Args: conversion_code (str): the MV conversion code.

Returns: DynArray: the output format.

Raises: UOError

def format(self, format_code):
149    def format(self, format_code):
150        """Return the formatted value of the DynArray based on the format code.
151
152        Args:
153            format_code (str): the format code.
154
155        Returns:
156            DynArray: the formatted value.
157
158        Raises:
159            UOError
160
161        """
162        return self._server_conv(format_code, FuncCodes.EIC_FMT)

Return the formatted value of the DynArray based on the format code.

Args: format_code (str): the format code.

Returns: DynArray: the formatted value.

Raises: UOError

Inherited Members
uopy._mvdelimited.MvDelimited
list
append
clear
copy
count
extend
index
insert
pop
remove
reverse
sort
class UOError(builtins.Exception):
108class UOError(Exception):
109    """UOError represents error conditions detected in UOPY.
110
111    It is recommended that Applications always use a try/catch block when calling any UOPY function and should rely on
112    the code and message in UOError exception for proper error handling and reporting.
113
114    Attributes:
115        message (str): the error message.
116        code (int): the error code; if the error is reported by the server, it is the server error code.
117
118    """
119
120    def __init__(self, code=ErrorCodes.UOE_UNKNOWN_ERROR, message=None, obj=None):
121        super().__init__()
122        self.code = code
123        self.message = _ERROR_MESSAGES.get(code, "Unknown Error Code")
124        if message:
125            self.message += " : " + message
126        if obj:
127            try:
128                self.message = self.message.format(obj)
129            except:
130                self.message += "on " + str(obj)
131
132    def __str__(self):
133        return "Error [{0}] : {1}".format(self.code, self.message)

UOError represents error conditions detected in UOPY.

It is recommended that Applications always use a try/catch block when calling any UOPY function and should rely on the code and message in UOError exception for proper error handling and reporting.

Attributes: message (str): the error message. code (int): the error code; if the error is reported by the server, it is the server error code.

UOError(code=-1, message=None, obj=None)
120    def __init__(self, code=ErrorCodes.UOE_UNKNOWN_ERROR, message=None, obj=None):
121        super().__init__()
122        self.code = code
123        self.message = _ERROR_MESSAGES.get(code, "Unknown Error Code")
124        if message:
125            self.message += " : " + message
126        if obj:
127            try:
128                self.message = self.message.format(obj)
129            except:
130                self.message += "on " + str(obj)
code
message
Inherited Members
builtins.BaseException
with_traceback
add_note
args
class File(uopy._uniobject.UniObject):
  70class File(UniObject):
  71    """File object represents a MV hashed file on the remote server. It is the main mechanism for applications to
  72    access MV data remotely.
  73
  74    File objects can be used in Python with statement so that whatever occurs in the with statement block, they
  75    are guaranteed to be closed upon exit.
  76
  77    Examples:
  78
  79        >>> with uopy.File("VOC") as voc_file:
  80        >>>     rec = voc_file.read("LIST")
  81        >>>     print(rec.list)
  82
  83    """
  84
  85    def __init__(self, name, dict_flag=0, session=None):
  86        """Initializes a File object.
  87        Args:
  88            name (str): the name of the MV File to be opened.
  89            dict_flag (int, optional): when it is uopy.DICT_FILE, then the File object points to the dictionary file.
  90                Otherwise, the target is the data file.
  91            session (Session, optional): the Session object that the File object is bound to.
  92                If omitted, the last opened Session in the current thread will be used.
  93
  94        Raises:
  95            UOError
  96
  97        """
  98        super().__init__(session)
  99
 100        if name is None or len(name) == 0:
 101            raise UOError(ErrorCodes.UOE_INVALIDFILENAME)
 102
 103        self._command = None
 104        self._dict_flag = 1 if dict_flag else 0
 105        self._status = 0
 106        self._handle = None
 107        self._type = 0
 108        self._name = name
 109        self._is_opened = False
 110
 111        self.open()
 112
 113    def __repr__(self):
 114        format_string = "<{} object {} at 0x{:016X}>"
 115        details = {"name": self._name, "type": "DICT" if self._dict_flag else "DATA"}
 116        return format_string.format(
 117            ".".join([File.__module__, File.__qualname__]), details, id(self)
 118        )
 119
 120    def __enter__(self):
 121        if not self._is_opened:
 122            self.open()
 123        return self
 124
 125    def __exit__(self, exec_type, exec_value, traceback):
 126        self.close()
 127
 128    @property
 129    def handle(self):
 130        return self._handle
 131
 132    @property
 133    def status(self):
 134        """The status code set by the remote server after a file operation."""
 135        return self._status
 136
 137    @property
 138    def is_opened(self):
 139        """boolean: True if the File object is opened on the remote server, otherwise False."""
 140        return self._is_opened
 141
 142    def _check_opened(self):
 143        if not self._is_opened:
 144            raise UOError(code=ErrorCodes.UOE_FILE_NOT_OPEN)
 145
 146    def open(self):
 147        """Open the named file on the remote server.
 148
 149        Args:
 150
 151        Returns:
 152            None
 153
 154        Raises:
 155            UOError
 156
 157        """
 158        _logger.debug("Enter", self._name)
 159
 160        if self._is_opened:
 161            return
 162
 163        with self._lock:
 164            in_packet = UniRPCPacket()
 165            out_packet = UniRPCPacket()
 166
 167            out_packet.write(0, FuncCodes.EIC_OPEN)
 168            out_packet.write(1, self._dict_flag)
 169            out_packet.write(2, self._session.encode(self._name))
 170            self._status = 0
 171
 172            resp_code = self._call_server(in_packet, out_packet)
 173            if resp_code != 0:
 174                raise UOError(code=resp_code, obj=self._name)
 175
 176            self._status = in_packet.read(1)
 177            self._handle = in_packet.read(2)
 178            self._type = self._status
 179            self._is_opened = True
 180
 181        _logger.debug("Exit")
 182
 183    def clear(self):
 184        """Clear the content of the file on the remote server.
 185
 186        Args:
 187
 188        Returns:
 189            None
 190
 191        Raises:
 192            UOError
 193
 194        """
 195        _logger.debug("Enter", self._name)
 196
 197        with self._lock:
 198            in_packet = UniRPCPacket()
 199            out_packet = UniRPCPacket()
 200
 201            out_packet.write(0, FuncCodes.EIC_CLEARFILE)
 202            out_packet.write(1, self._handle)
 203
 204            self._status = 0
 205            resp_code = self._call_server(in_packet, out_packet)
 206            if resp_code != 0:
 207                raise UOError(code=resp_code)
 208
 209        _logger.debug("Exit")
 210
 211    def close(self):
 212        """Close the opened file on the remote server - all file and record locks are released.
 213
 214        Args:
 215
 216        Returns:
 217            None
 218
 219        Raises:
 220            UOError
 221
 222        """
 223        _logger.debug("Enter", self._name)
 224
 225        if not self._is_opened:
 226            return
 227
 228        with self._lock:
 229            in_packet = UniRPCPacket()
 230            out_packet = UniRPCPacket()
 231
 232            out_packet.write(0, FuncCodes.EIC_CLOSE)
 233            out_packet.write(1, self._handle)
 234
 235            self._status = 0
 236            self._is_opened = False
 237            resp_code = self._call_server(in_packet, out_packet)
 238            if resp_code != 0:
 239                raise UOError(code=resp_code)
 240
 241        _logger.debug("Exit")
 242
 243    def delete(self, record_id, lock_flag=0):
 244        """Delete a record in the file.
 245
 246        Args:
 247            record_id (any ): the record id - can be str, bytes, or DynArray.
 248            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
 249
 250        Returns:
 251            None
 252
 253        Raises:
 254            UOError
 255
 256        """
 257        _logger.debug("Enter", record_id)
 258
 259        self._check_opened()
 260
 261        with self._lock:
 262            in_packet = UniRPCPacket()
 263            out_packet = UniRPCPacket()
 264
 265            out_packet.write(0, FuncCodes.EIC_DELETE)
 266            out_packet.write(1, self._handle)
 267            out_packet.write(2, _map_delete_lock_flag(lock_flag))
 268            out_packet.write(3, self._session.encode(record_id))
 269
 270            self._status = 0
 271            resp_code = self._call_server(in_packet, out_packet)
 272            if resp_code != 0:
 273                self._status = in_packet.read(1)
 274                raise UOError(code=resp_code)
 275
 276        _logger.debug("Exit")
 277
 278    def read(self, record_id, lock_flag=0):
 279        """Read a record in the file.
 280
 281        Args:
 282            record_id (any): the record id - can be str, bytes, or DynArray.
 283            lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
 284
 285        Returns:
 286            DynArray: the content of the record.
 287
 288        Raises:
 289            UOError
 290
 291        """
 292        _logger.debug("Enter", record_id, lock_flag)
 293
 294        self._check_opened()
 295        with self._lock:
 296            in_packet = UniRPCPacket()
 297            out_packet = UniRPCPacket()
 298
 299            out_packet.write(0, FuncCodes.EIC_READ)
 300            out_packet.write(1, self._handle)
 301            out_packet.write(2, _map_read_lock_flag(lock_flag))
 302            out_packet.write(3, self._session.encode(record_id))
 303
 304            resp_code = self._call_server(in_packet, out_packet)
 305            self._status = in_packet.read(1)
 306            if resp_code != 0:
 307                if resp_code == ErrorCodes.UOE_EIO:
 308                    tmp_status = self._status
 309                    if tmp_status not in _EIO_MSG_DICT:
 310                        tmp_status = 5
 311                    msg = _EIO_MSG_DICT[tmp_status]
 312                    raise UOError(code=resp_code, message=msg)
 313                else:
 314                    raise UOError(code=resp_code)
 315            else:
 316                record = DynArray(in_packet.read(2), session=self._session)
 317
 318        _logger.debug("Exit", record)
 319        return record
 320
 321    def write(self, record_id, record, lock_flag=0):
 322        """Write a record into the file.
 323
 324        Args:
 325            record_id (any): the record id - can be str, bytes, or DynArray.
 326            record (any): the record to be written - can be DynArray, str, bytes.
 327            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
 328
 329        Returns:
 330            None
 331
 332        Raises:
 333            UOError
 334
 335        """
 336        _logger.debug("Enter", record_id, record, lock_flag)
 337
 338        self._check_opened()
 339        with self._lock:
 340            in_packet = UniRPCPacket()
 341            out_packet = UniRPCPacket()
 342
 343            out_packet.write(0, FuncCodes.EIC_WRITE)
 344            out_packet.write(1, self._handle)
 345            out_packet.write(2, _map_write_lock_flag(lock_flag))
 346            out_packet.write(3, self._session.encode(record_id))
 347            out_packet.write(4, self._session.encode(record))
 348
 349            resp_code = self._call_server(in_packet, out_packet)
 350
 351            if resp_code == 0:
 352                self._status = in_packet.read(1)
 353            else:
 354                raise UOError(code=resp_code)
 355
 356        _logger.debug("Exit")
 357
 358    def read_field(self, record_id, field_num, lock_flag=0):
 359        """Read a single field of a record in the file.
 360
 361        Args:
 362            record_id (any ): the record id - can be str, bytes, or DynArray
 363            field_num (int): the field number
 364            lock_flag (int, optional): 0 (default), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
 365
 366        Returns:
 367            DynArray: the value of the field.
 368
 369        Raises:
 370            UOError
 371
 372        """
 373        _logger.debug("Enter", record_id, field_num, lock_flag)
 374
 375        self._check_opened()
 376        with self._lock:
 377            in_packet = UniRPCPacket()
 378            out_packet = UniRPCPacket()
 379
 380            out_packet.write(0, FuncCodes.EIC_READV)
 381            out_packet.write(1, self._handle)
 382            out_packet.write(2, _map_read_lock_flag(lock_flag))
 383            out_packet.write(3, field_num)
 384            out_packet.write(4, self._session.encode(record_id))
 385
 386            resp_code = self._call_server(in_packet, out_packet)
 387            self._status = in_packet.read(1)
 388            if resp_code != 0:
 389                if resp_code == ErrorCodes.UOE_EIO:
 390                    tmp_status = self._status
 391                    if tmp_status not in _EIO_MSG_DICT:
 392                        tmp_status = 5
 393                    msg = _EIO_MSG_DICT[tmp_status]
 394                    raise UOError(code=resp_code, message=msg)
 395                else:
 396                    raise UOError(code=resp_code)
 397            else:
 398                field = DynArray(in_packet.read(2), session=self._session)
 399
 400        _logger.debug("Exit", field)
 401        return field
 402
 403    def write_field(self, record_id, field_num, field_value, lock_flag=0):
 404        """Write a single field of a record to the file.
 405
 406        Args:
 407            record_id (any): the record id - can be str, bytes, or DynArray.
 408            field_num (int): the field number.
 409            field_value (any): the field value to be written - can be DynArray, str, bytes.
 410            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
 411
 412        Returns:
 413            None
 414
 415        Raises:
 416            UOError
 417
 418        """
 419        _logger.debug("Enter", record_id, field_num, field_value, lock_flag)
 420
 421        self._check_opened()
 422        with self._lock:
 423            in_packet = UniRPCPacket()
 424            out_packet = UniRPCPacket()
 425
 426            out_packet.write(0, FuncCodes.EIC_WRITEV)
 427            out_packet.write(1, self._handle)
 428            out_packet.write(2, _map_write_lock_flag(lock_flag))
 429            out_packet.write(3, field_num)
 430            out_packet.write(4, self._session.encode(record_id))
 431            out_packet.write(5, self._session.encode(field_value))
 432
 433            resp_code = self._call_server(in_packet, out_packet)
 434
 435            if resp_code == 0:
 436                self._status = in_packet.read(1)
 437            else:
 438                raise UOError(code=resp_code)
 439
 440        _logger.debug("Exit", self._status)
 441
 442    def lock_file(self):
 443        """Lock the entire file exclusively.
 444
 445        Args:
 446
 447        Returns:
 448            None
 449
 450        Raises:
 451            UOError
 452
 453        """
 454        _logger.debug("Enter", self._name)
 455
 456        self._check_opened()
 457        with self._lock:
 458            in_packet = UniRPCPacket()
 459            out_packet = UniRPCPacket()
 460
 461            out_packet.write(0, FuncCodes.EIC_FILELOCK)
 462            out_packet.write(1, self._handle)
 463
 464            resp_code = self._call_server(in_packet, out_packet)
 465            self._status = in_packet.read(1)
 466            if resp_code != 0:
 467                raise UOError(code=resp_code)
 468
 469        _logger.debug("Exit")
 470
 471    def unlock_file(self):
 472        """Release the exclusive lock on the entire file.
 473
 474        Args:
 475
 476        Returns:
 477            None
 478
 479        Raises:
 480            UOError
 481
 482        """
 483        _logger.debug("Enter", self._name)
 484
 485        self._check_opened()
 486        with self._lock:
 487            in_packet = UniRPCPacket()
 488            out_packet = UniRPCPacket()
 489
 490            out_packet.write(0, FuncCodes.EIC_FILEUNLOCK)
 491            out_packet.write(1, self._handle)
 492
 493            resp_code = self._call_server(in_packet, out_packet)
 494            self._status = in_packet.read(1)
 495            if resp_code != 0:
 496                raise UOError(code=resp_code)
 497
 498        _logger.debug("Exit")
 499
 500    def lock(self, record_id, lock_flag=LOCK_EXCLUSIVE):
 501        """Lock a record in the file.
 502
 503        Args:
 504            record_id (any): the record id - can be str, bytes, or DynArray.
 505            lock_flag (int, optional): LOCK_EXCLUSIVE (default) or LOCK_SHARED
 506
 507        Returns:
 508            None
 509
 510        Raises:
 511            UOError
 512
 513        """
 514        _logger.debug("Enter", record_id, lock_flag)
 515
 516        self._check_opened()
 517        with self._lock:
 518            in_packet = UniRPCPacket()
 519            out_packet = UniRPCPacket()
 520
 521            out_packet.write(0, FuncCodes.EIC_RECORDLOCK)
 522            out_packet.write(1, self._handle)
 523            out_packet.write(2, _map_read_lock_flag(lock_flag))
 524            out_packet.write(3, self._session.encode(record_id))
 525
 526            resp_code = self._call_server(in_packet, out_packet)
 527            self._status = in_packet.read(1)
 528            if resp_code != 0:
 529                raise UOError(code=resp_code)
 530
 531        _logger.debug("Exit")
 532
 533    def unlock(self, record_id, clear_flag=False):
 534        """Release locks owned by the current session on a record of the file.
 535
 536        Args:
 537            record_id (any): the record id - can be str, bytes, or DynArray.
 538            clear_flag (boolean, optional): False (default), only release the lock on the specified record; otherwise,
 539                release all the locks owned by the current session.
 540
 541        Returns:
 542            None
 543
 544        Raises:
 545            UOError
 546
 547        """
 548
 549        _logger.debug("Enter", record_id, clear_flag)
 550
 551        self._check_opened()
 552        with self._lock:
 553            in_packet = UniRPCPacket()
 554            out_packet = UniRPCPacket()
 555
 556            out_packet.write(0, FuncCodes.EIC_RELEASE)
 557            out_packet.write(1, self._handle)
 558            out_packet.write(2, 0 if not clear_flag else 1)
 559            out_packet.write(3, self._session.encode(record_id))
 560
 561            resp_code = self._call_server(in_packet, out_packet)
 562            if resp_code != 0:
 563                raise UOError(code=resp_code)
 564
 565        _logger.debug("Exit")
 566
 567    def is_locked(self, record_id):
 568        """Check if a record has a lock on it.
 569
 570        Args:
 571            record_id (any): the record id - can be str, bytes, or DynArray.
 572
 573        Returns:
 574            boolean: True, a lock exists on the record by either the current session or other sessions.
 575
 576        Raises:
 577            UOError
 578
 579        """
 580        _logger.debug("Enter", record_id)
 581
 582        self._check_opened()
 583        with self._lock:
 584            in_packet = UniRPCPacket()
 585            out_packet = UniRPCPacket()
 586
 587            out_packet.write(0, FuncCodes.EIC_RECORDLOCKED)
 588            out_packet.write(1, self._handle)
 589            out_packet.write(2, self._session.encode(record_id))
 590
 591            resp_code = self._call_server(in_packet, out_packet)
 592            if resp_code != 0:
 593                raise UOError(code=resp_code)
 594
 595            lock_status = in_packet.read(1)
 596            self._status = in_packet.read(2)
 597
 598        _logger.debug("Exit", lock_status, self._status)
 599        return False if lock_status == 0 else True
 600
 601    def get_ak_info(self, index_name=""):
 602        """Obtain information about the secondary key indexes available on the file.
 603
 604        Args:
 605            index_name (str, Optional). If this value is None or ignored, the list of available indices is returned.
 606
 607        Returns:
 608            DynArray:
 609                The return value will vary depending on the type of index, as follows:
 610                1. For D-Type indexes: Field 1 contains D as the first character and
 611                    Field 2 contains the location number of the indexed field.
 612                2. For I-type indexes: Field 1 contains I as the first character,
 613                    Field 2 contains the I-type expression, and the compiled I-type resides in field 19 and onward.
 614                3. For both types:
 615                    2nd value of Field 1 indicates if the index needs to be rebuilt. It is an empty string otherwise.
 616                    3rd value of Field 1 is set if the index is null-suppressed. It is an empty string otherwise.
 617                    4th value of Field 1 is set if automatic updates are disabled. It is an empty string otherwise.
 618                    6th value of Field 1 contains an S for single valued indices or M for a multivalued index.
 619
 620        Raises:
 621            UOError
 622
 623        """
 624        _logger.debug("Enter", index_name)
 625
 626        self._check_opened()
 627        with self._lock:
 628            in_packet = UniRPCPacket()
 629            out_packet = UniRPCPacket()
 630            out_packet.write(0, FuncCodes.EIC_INDICES)
 631            out_packet.write(1, self._handle)
 632            out_packet.write(2, len(index_name))
 633            out_packet.write(3, self._session.encode(index_name))
 634
 635            resp_code = self._call_server(in_packet, out_packet)
 636            if resp_code != 0:
 637                raise UOError(code=resp_code)
 638
 639            ak_info = DynArray(in_packet.read(1), self._session)
 640
 641        _logger.debug("Exit", ak_info)
 642        return ak_info
 643
 644    def itype(self, record_id, i_type_id):
 645        """Evaluates the specified I-descriptor and returns the evaluated string.
 646
 647        Args:
 648            record_id (any): the record id - can be str, bytes, or DynArray.
 649            i_type_id (any): the I-descriptor record id in the dictionary - can be str, bytes, or DynArray.
 650
 651        Returns:
 652            DynArray: the evaluated result.
 653
 654        Raises:
 655          UOError
 656
 657        """
 658        _logger.debug("Enter", record_id, i_type_id)
 659
 660        with self._lock:
 661            in_packet = UniRPCPacket()
 662            out_packet = UniRPCPacket()
 663            out_packet.write(0, FuncCodes.EIC_ITYPE)
 664            out_packet.write(1, self._session.encode(self._name))
 665            out_packet.write(2, self._session.encode(record_id))
 666            out_packet.write(3, self._session.encode(i_type_id))
 667
 668            resp_code = self._call_server(in_packet, out_packet)
 669            if resp_code != 0:
 670                raise UOError(code=resp_code)
 671
 672            result = DynArray(in_packet.read(1), session=self._session)
 673
 674        _logger.debug("Exit", result)
 675        return result
 676
 677    def read_named_fields(self, id_list, field_list, lock_flag=0):
 678        """Read a list of named fields on multiple records.
 679
 680        Note:
 681            fields can be of D-type or I/V type.
 682            If field_list contains names that are not defined in the dictionary, these names are replaced by @ID.
 683            If a field has conv code on it, an oconv is automatically performed on its internal value to get the
 684            converted output value.
 685
 686        Args:
 687            id_list: a list of record ids.
 688            field_list: a list of field names.
 689            lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
 690
 691        Returns:
 692            tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list,
 693                    4. record list.
 694
 695        Raises:
 696            UOFileError
 697
 698        Examples:
 699            >>> with File("RENTAL_DETAILS") as test_file:
 700            >>>     field_list = ["FULL_NAME", "ACTUAL_RETURN_DATE", "BALANCE_DUE"]
 701            >>>     id_list = ['1084', '1307', '1976']
 702            >>>     read_rs = test_file.read_named_fields(id_list, field_list)
 703            >>>     for l in read_rs:
 704            >>>         print(l)
 705            ['0', '0', '0']
 706            ['0', '0', '0']
 707            ['1084', '1307', '1976']
 708            [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'], '3.50'],
 709            ['Jamie Klink', ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'],
 710            ['Mo Evans', ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'], '19.04']]
 711
 712        """
 713        _logger.debug("Enter", id_list, field_list, lock_flag)
 714
 715        self._check_opened()
 716
 717        id_set = RecordSet(id_list, session=self._session)
 718
 719        with self._lock:
 720            in_packet = UniRPCPacket()
 721            out_packet = UniRPCPacket()
 722            out_packet.write(0, FuncCodes.EIC_READNAMEDFIELDSET)
 723            out_packet.write(1, self._handle)
 724            out_packet.write(2, _map_read_lock_flag(lock_flag))
 725            out_packet.write(3, bytes(id_set))
 726            out_packet.write(4, b"")
 727            out_packet.write(5, self._session.encode(field_list))
 728
 729            self._call_server(in_packet, out_packet)
 730
 731            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
 732            status_set = RecordSet(in_packet.read(2), session=self._session)
 733            return_data_set = RecordSet(in_packet.read(3), session=self._session)
 734
 735            resp_codes = list(map(int, resp_code_set.list))
 736            status_codes = list(map(int, status_set.list))
 737
 738            resp_error_codes = [key for key in resp_codes if key != 0]
 739            if len(resp_error_codes) > 0:
 740                raise UOFileError(
 741                    code=resp_error_codes[0],
 742                    obj=self._name,
 743                    response_codes=resp_codes,
 744                    status_codes=status_codes,
 745                    id_list=id_set.list,
 746                )
 747
 748            result_set = (resp_codes, status_codes, id_set.list, return_data_set.list)
 749        _logger.debug("Exit", result_set)
 750        return result_set
 751
 752    def write_named_fields(self, id_list, field_list, field_data_list, lock_flag=0):
 753        """Write a list of named fields to multiple records.
 754
 755        Note:
 756            If field_list contains names that are not defined in the dictionary, these names are ignored.
 757            If a field is of I/V type or the record id itself, it is ignored.
 758            If a field has CONV code on it, an iconv is automatically performed to use its internal value for the write.
 759
 760        Args:
 761            id_list: a list of record ids.
 762            field_list: a list of field names.
 763            field_data_list: a list of DynArray consisting of all the field values.
 764            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
 765
 766        Returns:
 767            tuple: a tuple consisting of 4 lists: 1. response code list, 2. status code list, 3. record id list,
 768                    4. field values list.
 769
 770        Raises:
 771            UOError
 772
 773        Examples:
 774            >>> with File("RENTAL_DETAILS") as test_file:
 775            >>>     field_list = ["FULL_NAME", "ACTUAL_RETURN_DATE", "BALANCE_DUE"]
 776            >>>     id_list = ['1084', '1307', '1976']
 777            >>>     field_value_list = [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'],
 778            '3.50'], ['Jamie Klink', ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'],
 779            ['Mo Evans', ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'],'19.04']]
 780            >>>     write_rs = test_file.write_named_fields(id_list, field_list, field_value_list)
 781            >>>     for l in write_rs:
 782            >>>         print(l)
 783            ['0', '0', '0']
 784            ['0', '0', '0']
 785            ['1084', '1307', '1976']
 786            [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'], '3.50'], ['Jamie Klink',
 787            ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'], ['Mo Evans',
 788            ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'], '19.04']]
 789
 790
 791        """
 792        _logger.debug("Enter", id_list, field_list, field_data_list, lock_flag)
 793
 794        self._check_opened()
 795
 796        id_set = RecordSet(id_list, session=self._session)
 797        field_data_set = RecordSet(field_data_list, session=self._session)
 798
 799        with self._lock:
 800            in_packet = UniRPCPacket()
 801            out_packet = UniRPCPacket()
 802            out_packet.write(0, FuncCodes.EIC_WRITENAMEDFIELDSET)
 803            out_packet.write(1, self._handle)
 804            out_packet.write(2, _map_write_lock_flag(lock_flag))
 805            out_packet.write(3, bytes(id_set))
 806            out_packet.write(4, bytes(field_data_set))
 807            out_packet.write(5, self._session.encode(field_list))
 808
 809            self._call_server(in_packet, out_packet)
 810
 811            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
 812            status_set = RecordSet(in_packet.read(2), session=self._session)
 813            result_set = (
 814                resp_code_set.list,
 815                status_set.list,
 816                id_set.list,
 817                field_data_set.list,
 818            )
 819
 820        _logger.debug("Exit", result_set)
 821        return result_set
 822
 823    def read_records(self, id_list, lock_flag=0):
 824        """Read multiple records from the file.
 825
 826        Args:
 827            id_list: a list of record ids.
 828            lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
 829
 830        Returns:
 831            tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list,
 832                    4. record list.
 833
 834        Raises:
 835            UOError
 836
 837        """
 838        _logger.debug("Enter", id_list, lock_flag)
 839
 840        self._check_opened()
 841
 842        id_set = RecordSet(id_list, session=self._session)
 843
 844        with self._lock:
 845            in_packet = UniRPCPacket()
 846            out_packet = UniRPCPacket()
 847            out_packet.write(0, FuncCodes.EIC_READSET)
 848            out_packet.write(1, self._handle)
 849            out_packet.write(2, _map_read_lock_flag(lock_flag))
 850            out_packet.write(3, bytes(id_set))
 851            out_packet.write(4, b"")
 852            out_packet.write(5, b"")
 853
 854            self._call_server(in_packet, out_packet)
 855
 856            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
 857            status_set = RecordSet(in_packet.read(2), session=self._session)
 858            return_data_set = RecordSet(in_packet.read(3), session=self._session)
 859            result_set = (
 860                resp_code_set.list,
 861                status_set.list,
 862                id_set.list,
 863                return_data_set.list,
 864            )
 865
 866        _logger.debug("Exit", result_set)
 867        return result_set
 868
 869    def write_records(self, id_list, record_list, lock_flag=0):
 870        """Write multiple records into the file.
 871
 872        Args:
 873            id_list: a list of record ids.
 874            record_list: a list of records.
 875            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
 876
 877        Returns:
 878            tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list,
 879                    4. record list.
 880
 881        Raises:
 882            UOError
 883
 884        """
 885        _logger.debug("Enter", id_list, record_list, lock_flag)
 886
 887        self._check_opened()
 888
 889        id_set = RecordSet(id_list, session=self._session)
 890        record_set = RecordSet(record_list, session=self._session)
 891
 892        with self._lock:
 893            in_packet = UniRPCPacket()
 894            out_packet = UniRPCPacket()
 895            out_packet.write(0, FuncCodes.EIC_WRITESET)
 896            out_packet.write(1, self._handle)
 897            out_packet.write(2, _map_write_lock_flag(lock_flag))
 898            out_packet.write(3, bytes(id_set))
 899            out_packet.write(4, bytes(record_set))
 900            out_packet.write(5, b"")
 901
 902            self._call_server(in_packet, out_packet)
 903
 904            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
 905            status_set = RecordSet(in_packet.read(2), session=self._session)
 906            result_set = (
 907                resp_code_set.list,
 908                status_set.list,
 909                id_set.list,
 910                record_set.list,
 911            )
 912
 913        _logger.debug("Exit", result_set)
 914        return result_set
 915
 916    def fileInfoEx(self):
 917        """Get information about the specified file’s configuration, such as the
 918        file’s parameters, its modulus and load, its operating system file name, and its VOC name.
 919        The information returned depends on the file type and the value of the key.
 920
 921        After calling the method fileInfoEx, you can access these attributes to get their values.
 922        For UV, these attributes will be available:
 923        isFileVar: 1 if file.variable is a valid file variable; 0 otherwise.
 924        vocName: VOC name of the file.
 925        pathName: Path name of the file.
 926        type: File type: 1 Static hashed | 3 Dynamic hashed | 4 Type 1 | 5 Sequential | 7 Distributed and Multivolume
 927        hashAlg: Hashing algorithm: 2 for GENERAL, 3 for SEQ.NUM.
 928        modulus: Current modulus.
 929        minModulus: Minimum modulus.
 930        groupSize: Group size, in 1-KB units.
 931        largeRecordSize: Large record size.
 932        mergeLoad: Merge load parameter.
 933        splitLoad: Split load parameter.
 934        currentLoad: Current loading of the file (%).
 935        nodeName: Empty string if the file resides on the local system. Otherwise, the name of the node where the file resides.
 936        isAKFile: 1 if secondary indexes exist on the file; 0 otherwise.
 937        currentLine: Current line number.
 938        partNum: For a distributed file, returns the list of currently open part numbers.
 939        fileStatus: For a distributed file, returns the list of status codes indicating whether the last I/O operation succeeded
 940                    or failed for each part. A value of –1 indicates the corresponding part file is not open.
 941        recoveryType: 1 if the file is marked as recoverable, 0 if it is not. Returns an empty string
 942                      if recovery is not supported on the file type (such as type 1 and type 19 files).
 943        recoveryId: Always returns an empty string.
 944        isFixedModulus: Always returns 0.
 945        nlsmap: If NLS is enabled, the file map name; otherwise an empty string.
 946                If the map name is the default specified in the uvconfig file, the returned string is the map name followed by the name of the configurable parameter in parentheses.
 947        encryption: Returns a dynamic array containing the following information:
 948                    â–ª For a file encrypted with the WHOLERECORD option:
 949                    -1@VM@VM
 950                    â–ª For a file encrypted at the field level:
 951                    @VM@VM
 952                    @VM[@FM
 953                    ...@VM]
 954                    â–ª Returns an empty string if the file is not encrypted.
 955        repStatus: Return values can be:
 956                    0 – The file is not published, subscribed, or subwriteable.
 957                    1 – The file is being published.
 958                    2 – The file is being subscribed.
 959                    3 – The file is subwriteable.
 960                    Note: If U2 Data Replication is not running, this function
 961                    returns 0 for any file used with this function.
 962        For UD, these attributes will be available:
 963        isFileVar: File open status. 1= Open, 0= Not open
 964        vocName: VOC name
 965        pathName: Full path name of file
 966        type: File type.
 967                2 - HASHED
 968                3 - DYNAMIC
 969                4 - DIRECTORY
 970                5 - SEQUENTIAL
 971                7 - NFA
 972                8 - OS
 973                13 - EDA
 974        hashAlg: Hashing file type
 975                HASH & DYNAMI(KEYONLY) Hash type (0, 1, or 3)
 976                DYNAMIC (KEYDATA) Hash type (32 , 33, or 35)
 977                DYNAMIC (WHOLEFILE) Hash type (48, 49, or 51)
 978                OTHERS
 979        modulus: Modulo of file
 980        minModulus: Minimum modulo
 981        groupSize: Group size of file
 982        largeRecordSize: Block size of file
 983        mergeLoad: Merge factor percentage
 984        splitLoad: Split factor percentage
 985        currentLoad: Current load percentage
 986        nodeName: Node name
 987        isAKFile: Does file contain alternate key indexes?
 988        currentLine: Next line number to read or write
 989        partNum: Part number
 990        fileStatus: Status
 991        relname: Filename
 992        blksize: Block size of file
 993        privilege: Access permissions
 994        whichIndex: Index to which the last SETINDEX statement was applied
 995        whatXValue: Index record read by last browsing statement, such as READFWD and READBCK
 996        isRecoverable: File type: recoverable or nonrecoverable
 997        isNumerical: Numeric keys
 998        isReplicated: Type of U2 Data Replication file
 999        beforeUpdateTrigger: BEFORE-UPDATE-TRIGGER catalog program name of the file <xx>.
1000        beforeDeleteTrigger: BEFORE-DELETE-TRIGGER catalog program name of the file <xx>.
1001        isEncrypted: Is the file encrypted?
1002        encinfo: Type of file encryption
1003        afterUpdateTrigger: AFTER-UPDATE-TRIGGER catalog program name of the file <xx>.
1004        afterDeleteTrigger: AFTER-DELETE-TRIGGER catalog program name of the file <xx>.
1005        is64bit: Defines the bit type
1006
1007        Args: void
1008
1009        Returns: void
1010
1011        Raise:
1012            UOError
1013
1014        Examples:
1015            >>> f = uopy.File('TEST')
1016            >>> f.fileInfoEx()
1017            >>> print(f.vocName)
1018            >>> print(f.pathName)
1019            >>> print(f.groupSize)
1020        """
1021        _logger.debug("Enter fileInfoEx")
1022
1023        self._check_opened()
1024        with self._lock:
1025            in_packet = UniRPCPacket()
1026            out_packet = UniRPCPacket()
1027            out_packet.write(0, FuncCodes.EIC_FILEINFOEx)
1028            out_packet.write(1, self._handle)
1029            resp_code = self._call_server(in_packet, out_packet)
1030
1031            if resp_code != 0:
1032                if resp_code == ErrorCodes.UOE_USC:
1033                    raise UOError(
1034                        code=resp_code,
1035                        obj=self._name,
1036                        message="fileInfoEx is not supported on versions prior to UniData 8.2.4 or prior to UniVerse 12.2.1.",
1037                    )
1038                else:
1039                    raise UOError(code=resp_code, obj=self._name)
1040
1041            fileinfo_set = RecordSet(in_packet.read(1), session=self._session)
1042            if self._session.db_type == "UD":
1043                if len(fileinfo_set.list) != UDFileInfoEx.LIST_COUNT:
1044                    raise UOError()
1045                (
1046                    self.isFileVar,
1047                    self.vocName,
1048                    self.pathName,
1049                    self.type,
1050                    self.hashAlg,
1051                    self.modulus,
1052                    self.minModulus,
1053                    self.groupSize,
1054                    self.largeRecordSize,
1055                    self.mergeLoad,
1056                    self.splitLoad,
1057                    self.currentLoad,
1058                    self.nodeName,
1059                    self.isAKFile,
1060                    self.currentLine,
1061                    self.partNum,
1062                    self.fileStatus,
1063                    self.relname,
1064                    self.blksize,
1065                    self.privilege,
1066                    self.whichIndex,
1067                    self.whatXValue,
1068                    self.isRecoverable,
1069                    self.isNumerical,
1070                    self.isReplicated,
1071                    self.beforeUpdateTrigger,
1072                    self.beforeDeleteTrigger,
1073                    self.isEncrypted,
1074                    self.encinfo,
1075                    self.afterUpdateTrigger,
1076                    self.afterDeleteTrigger,
1077                    self.is64bit,
1078                ) = fileinfo_set.list
1079                pass
1080            elif self._session.db_type == "UV":
1081                if len(fileinfo_set.list) != FileInfoEx.LIST_COUNT:
1082                    raise UOError()
1083                (
1084                    self.isFileVar,
1085                    self.vocName,
1086                    self.pathName,
1087                    self.type,
1088                    self.hashAlg,
1089                    self.modulus,
1090                    self.minModulus,
1091                    self.groupSize,
1092                    self.largeRecordSize,
1093                    self.mergeLoad,
1094                    self.splitLoad,
1095                    self.currentLoad,
1096                    self.nodeName,
1097                    self.isAKFile,
1098                    self.currentLine,
1099                    self.partNum,
1100                    self.fileStatus,
1101                    self.recoveryType,
1102                    self.recoveryId,
1103                    self.isFixedModulus,
1104                    self.nlsmap,
1105                    self.encryption,
1106                    self.repStatus,
1107                ) = fileinfo_set.list
1108                pass
1109        _logger.debug("Exit", fileinfo_set)
1110        pass

File object represents a MV hashed file on the remote server. It is the main mechanism for applications to access MV data remotely.

File objects can be used in Python with statement so that whatever occurs in the with statement block, they are guaranteed to be closed upon exit.

Examples:

>>> with uopy.File("VOC") as voc_file:
>>>     rec = voc_file.read("LIST")
>>>     print(rec.list)
File(name, dict_flag=0, session=None)
 85    def __init__(self, name, dict_flag=0, session=None):
 86        """Initializes a File object.
 87        Args:
 88            name (str): the name of the MV File to be opened.
 89            dict_flag (int, optional): when it is uopy.DICT_FILE, then the File object points to the dictionary file.
 90                Otherwise, the target is the data file.
 91            session (Session, optional): the Session object that the File object is bound to.
 92                If omitted, the last opened Session in the current thread will be used.
 93
 94        Raises:
 95            UOError
 96
 97        """
 98        super().__init__(session)
 99
100        if name is None or len(name) == 0:
101            raise UOError(ErrorCodes.UOE_INVALIDFILENAME)
102
103        self._command = None
104        self._dict_flag = 1 if dict_flag else 0
105        self._status = 0
106        self._handle = None
107        self._type = 0
108        self._name = name
109        self._is_opened = False
110
111        self.open()

Initializes a File object. Args: name (str): the name of the MV File to be opened. dict_flag (int, optional): when it is uopy.DICT_FILE, then the File object points to the dictionary file. Otherwise, the target is the data file. session (Session, optional): the Session object that the File object is bound to. If omitted, the last opened Session in the current thread will be used.

Raises: UOError

handle
status

The status code set by the remote server after a file operation.

is_opened

boolean: True if the File object is opened on the remote server, otherwise False.

def open(self):
146    def open(self):
147        """Open the named file on the remote server.
148
149        Args:
150
151        Returns:
152            None
153
154        Raises:
155            UOError
156
157        """
158        _logger.debug("Enter", self._name)
159
160        if self._is_opened:
161            return
162
163        with self._lock:
164            in_packet = UniRPCPacket()
165            out_packet = UniRPCPacket()
166
167            out_packet.write(0, FuncCodes.EIC_OPEN)
168            out_packet.write(1, self._dict_flag)
169            out_packet.write(2, self._session.encode(self._name))
170            self._status = 0
171
172            resp_code = self._call_server(in_packet, out_packet)
173            if resp_code != 0:
174                raise UOError(code=resp_code, obj=self._name)
175
176            self._status = in_packet.read(1)
177            self._handle = in_packet.read(2)
178            self._type = self._status
179            self._is_opened = True
180
181        _logger.debug("Exit")

Open the named file on the remote server.

Args:

Returns: None

Raises: UOError

def clear(self):
183    def clear(self):
184        """Clear the content of the file on the remote server.
185
186        Args:
187
188        Returns:
189            None
190
191        Raises:
192            UOError
193
194        """
195        _logger.debug("Enter", self._name)
196
197        with self._lock:
198            in_packet = UniRPCPacket()
199            out_packet = UniRPCPacket()
200
201            out_packet.write(0, FuncCodes.EIC_CLEARFILE)
202            out_packet.write(1, self._handle)
203
204            self._status = 0
205            resp_code = self._call_server(in_packet, out_packet)
206            if resp_code != 0:
207                raise UOError(code=resp_code)
208
209        _logger.debug("Exit")

Clear the content of the file on the remote server.

Args:

Returns: None

Raises: UOError

def close(self):
211    def close(self):
212        """Close the opened file on the remote server - all file and record locks are released.
213
214        Args:
215
216        Returns:
217            None
218
219        Raises:
220            UOError
221
222        """
223        _logger.debug("Enter", self._name)
224
225        if not self._is_opened:
226            return
227
228        with self._lock:
229            in_packet = UniRPCPacket()
230            out_packet = UniRPCPacket()
231
232            out_packet.write(0, FuncCodes.EIC_CLOSE)
233            out_packet.write(1, self._handle)
234
235            self._status = 0
236            self._is_opened = False
237            resp_code = self._call_server(in_packet, out_packet)
238            if resp_code != 0:
239                raise UOError(code=resp_code)
240
241        _logger.debug("Exit")

Close the opened file on the remote server - all file and record locks are released.

Args:

Returns: None

Raises: UOError

def delete(self, record_id, lock_flag=0):
243    def delete(self, record_id, lock_flag=0):
244        """Delete a record in the file.
245
246        Args:
247            record_id (any ): the record id - can be str, bytes, or DynArray.
248            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
249
250        Returns:
251            None
252
253        Raises:
254            UOError
255
256        """
257        _logger.debug("Enter", record_id)
258
259        self._check_opened()
260
261        with self._lock:
262            in_packet = UniRPCPacket()
263            out_packet = UniRPCPacket()
264
265            out_packet.write(0, FuncCodes.EIC_DELETE)
266            out_packet.write(1, self._handle)
267            out_packet.write(2, _map_delete_lock_flag(lock_flag))
268            out_packet.write(3, self._session.encode(record_id))
269
270            self._status = 0
271            resp_code = self._call_server(in_packet, out_packet)
272            if resp_code != 0:
273                self._status = in_packet.read(1)
274                raise UOError(code=resp_code)
275
276        _logger.debug("Exit")

Delete a record in the file.

Args: record_id (any ): the record id - can be str, bytes, or DynArray. lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT

Returns: None

Raises: UOError

def read(self, record_id, lock_flag=0):
278    def read(self, record_id, lock_flag=0):
279        """Read a record in the file.
280
281        Args:
282            record_id (any): the record id - can be str, bytes, or DynArray.
283            lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
284
285        Returns:
286            DynArray: the content of the record.
287
288        Raises:
289            UOError
290
291        """
292        _logger.debug("Enter", record_id, lock_flag)
293
294        self._check_opened()
295        with self._lock:
296            in_packet = UniRPCPacket()
297            out_packet = UniRPCPacket()
298
299            out_packet.write(0, FuncCodes.EIC_READ)
300            out_packet.write(1, self._handle)
301            out_packet.write(2, _map_read_lock_flag(lock_flag))
302            out_packet.write(3, self._session.encode(record_id))
303
304            resp_code = self._call_server(in_packet, out_packet)
305            self._status = in_packet.read(1)
306            if resp_code != 0:
307                if resp_code == ErrorCodes.UOE_EIO:
308                    tmp_status = self._status
309                    if tmp_status not in _EIO_MSG_DICT:
310                        tmp_status = 5
311                    msg = _EIO_MSG_DICT[tmp_status]
312                    raise UOError(code=resp_code, message=msg)
313                else:
314                    raise UOError(code=resp_code)
315            else:
316                record = DynArray(in_packet.read(2), session=self._session)
317
318        _logger.debug("Exit", record)
319        return record

Read a record in the file.

Args: record_id (any): the record id - can be str, bytes, or DynArray. lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]

Returns: DynArray: the content of the record.

Raises: UOError

def write(self, record_id, record, lock_flag=0):
321    def write(self, record_id, record, lock_flag=0):
322        """Write a record into the file.
323
324        Args:
325            record_id (any): the record id - can be str, bytes, or DynArray.
326            record (any): the record to be written - can be DynArray, str, bytes.
327            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
328
329        Returns:
330            None
331
332        Raises:
333            UOError
334
335        """
336        _logger.debug("Enter", record_id, record, lock_flag)
337
338        self._check_opened()
339        with self._lock:
340            in_packet = UniRPCPacket()
341            out_packet = UniRPCPacket()
342
343            out_packet.write(0, FuncCodes.EIC_WRITE)
344            out_packet.write(1, self._handle)
345            out_packet.write(2, _map_write_lock_flag(lock_flag))
346            out_packet.write(3, self._session.encode(record_id))
347            out_packet.write(4, self._session.encode(record))
348
349            resp_code = self._call_server(in_packet, out_packet)
350
351            if resp_code == 0:
352                self._status = in_packet.read(1)
353            else:
354                raise UOError(code=resp_code)
355
356        _logger.debug("Exit")

Write a record into the file.

Args: record_id (any): the record id - can be str, bytes, or DynArray. record (any): the record to be written - can be DynArray, str, bytes. lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT

Returns: None

Raises: UOError

def read_field(self, record_id, field_num, lock_flag=0):
358    def read_field(self, record_id, field_num, lock_flag=0):
359        """Read a single field of a record in the file.
360
361        Args:
362            record_id (any ): the record id - can be str, bytes, or DynArray
363            field_num (int): the field number
364            lock_flag (int, optional): 0 (default), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
365
366        Returns:
367            DynArray: the value of the field.
368
369        Raises:
370            UOError
371
372        """
373        _logger.debug("Enter", record_id, field_num, lock_flag)
374
375        self._check_opened()
376        with self._lock:
377            in_packet = UniRPCPacket()
378            out_packet = UniRPCPacket()
379
380            out_packet.write(0, FuncCodes.EIC_READV)
381            out_packet.write(1, self._handle)
382            out_packet.write(2, _map_read_lock_flag(lock_flag))
383            out_packet.write(3, field_num)
384            out_packet.write(4, self._session.encode(record_id))
385
386            resp_code = self._call_server(in_packet, out_packet)
387            self._status = in_packet.read(1)
388            if resp_code != 0:
389                if resp_code == ErrorCodes.UOE_EIO:
390                    tmp_status = self._status
391                    if tmp_status not in _EIO_MSG_DICT:
392                        tmp_status = 5
393                    msg = _EIO_MSG_DICT[tmp_status]
394                    raise UOError(code=resp_code, message=msg)
395                else:
396                    raise UOError(code=resp_code)
397            else:
398                field = DynArray(in_packet.read(2), session=self._session)
399
400        _logger.debug("Exit", field)
401        return field

Read a single field of a record in the file.

Args: record_id (any ): the record id - can be str, bytes, or DynArray field_num (int): the field number lock_flag (int, optional): 0 (default), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]

Returns: DynArray: the value of the field.

Raises: UOError

def write_field(self, record_id, field_num, field_value, lock_flag=0):
403    def write_field(self, record_id, field_num, field_value, lock_flag=0):
404        """Write a single field of a record to the file.
405
406        Args:
407            record_id (any): the record id - can be str, bytes, or DynArray.
408            field_num (int): the field number.
409            field_value (any): the field value to be written - can be DynArray, str, bytes.
410            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
411
412        Returns:
413            None
414
415        Raises:
416            UOError
417
418        """
419        _logger.debug("Enter", record_id, field_num, field_value, lock_flag)
420
421        self._check_opened()
422        with self._lock:
423            in_packet = UniRPCPacket()
424            out_packet = UniRPCPacket()
425
426            out_packet.write(0, FuncCodes.EIC_WRITEV)
427            out_packet.write(1, self._handle)
428            out_packet.write(2, _map_write_lock_flag(lock_flag))
429            out_packet.write(3, field_num)
430            out_packet.write(4, self._session.encode(record_id))
431            out_packet.write(5, self._session.encode(field_value))
432
433            resp_code = self._call_server(in_packet, out_packet)
434
435            if resp_code == 0:
436                self._status = in_packet.read(1)
437            else:
438                raise UOError(code=resp_code)
439
440        _logger.debug("Exit", self._status)

Write a single field of a record to the file.

Args: record_id (any): the record id - can be str, bytes, or DynArray. field_num (int): the field number. field_value (any): the field value to be written - can be DynArray, str, bytes. lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT

Returns: None

Raises: UOError

def lock_file(self):
442    def lock_file(self):
443        """Lock the entire file exclusively.
444
445        Args:
446
447        Returns:
448            None
449
450        Raises:
451            UOError
452
453        """
454        _logger.debug("Enter", self._name)
455
456        self._check_opened()
457        with self._lock:
458            in_packet = UniRPCPacket()
459            out_packet = UniRPCPacket()
460
461            out_packet.write(0, FuncCodes.EIC_FILELOCK)
462            out_packet.write(1, self._handle)
463
464            resp_code = self._call_server(in_packet, out_packet)
465            self._status = in_packet.read(1)
466            if resp_code != 0:
467                raise UOError(code=resp_code)
468
469        _logger.debug("Exit")

Lock the entire file exclusively.

Args:

Returns: None

Raises: UOError

def unlock_file(self):
471    def unlock_file(self):
472        """Release the exclusive lock on the entire file.
473
474        Args:
475
476        Returns:
477            None
478
479        Raises:
480            UOError
481
482        """
483        _logger.debug("Enter", self._name)
484
485        self._check_opened()
486        with self._lock:
487            in_packet = UniRPCPacket()
488            out_packet = UniRPCPacket()
489
490            out_packet.write(0, FuncCodes.EIC_FILEUNLOCK)
491            out_packet.write(1, self._handle)
492
493            resp_code = self._call_server(in_packet, out_packet)
494            self._status = in_packet.read(1)
495            if resp_code != 0:
496                raise UOError(code=resp_code)
497
498        _logger.debug("Exit")

Release the exclusive lock on the entire file.

Args:

Returns: None

Raises: UOError

def lock(self, record_id, lock_flag=4):
500    def lock(self, record_id, lock_flag=LOCK_EXCLUSIVE):
501        """Lock a record in the file.
502
503        Args:
504            record_id (any): the record id - can be str, bytes, or DynArray.
505            lock_flag (int, optional): LOCK_EXCLUSIVE (default) or LOCK_SHARED
506
507        Returns:
508            None
509
510        Raises:
511            UOError
512
513        """
514        _logger.debug("Enter", record_id, lock_flag)
515
516        self._check_opened()
517        with self._lock:
518            in_packet = UniRPCPacket()
519            out_packet = UniRPCPacket()
520
521            out_packet.write(0, FuncCodes.EIC_RECORDLOCK)
522            out_packet.write(1, self._handle)
523            out_packet.write(2, _map_read_lock_flag(lock_flag))
524            out_packet.write(3, self._session.encode(record_id))
525
526            resp_code = self._call_server(in_packet, out_packet)
527            self._status = in_packet.read(1)
528            if resp_code != 0:
529                raise UOError(code=resp_code)
530
531        _logger.debug("Exit")

Lock a record in the file.

Args: record_id (any): the record id - can be str, bytes, or DynArray. lock_flag (int, optional): LOCK_EXCLUSIVE (default) or LOCK_SHARED

Returns: None

Raises: UOError

def unlock(self, record_id, clear_flag=False):
533    def unlock(self, record_id, clear_flag=False):
534        """Release locks owned by the current session on a record of the file.
535
536        Args:
537            record_id (any): the record id - can be str, bytes, or DynArray.
538            clear_flag (boolean, optional): False (default), only release the lock on the specified record; otherwise,
539                release all the locks owned by the current session.
540
541        Returns:
542            None
543
544        Raises:
545            UOError
546
547        """
548
549        _logger.debug("Enter", record_id, clear_flag)
550
551        self._check_opened()
552        with self._lock:
553            in_packet = UniRPCPacket()
554            out_packet = UniRPCPacket()
555
556            out_packet.write(0, FuncCodes.EIC_RELEASE)
557            out_packet.write(1, self._handle)
558            out_packet.write(2, 0 if not clear_flag else 1)
559            out_packet.write(3, self._session.encode(record_id))
560
561            resp_code = self._call_server(in_packet, out_packet)
562            if resp_code != 0:
563                raise UOError(code=resp_code)
564
565        _logger.debug("Exit")

Release locks owned by the current session on a record of the file.

Args: record_id (any): the record id - can be str, bytes, or DynArray. clear_flag (boolean, optional): False (default), only release the lock on the specified record; otherwise, release all the locks owned by the current session.

Returns: None

Raises: UOError

def is_locked(self, record_id):
567    def is_locked(self, record_id):
568        """Check if a record has a lock on it.
569
570        Args:
571            record_id (any): the record id - can be str, bytes, or DynArray.
572
573        Returns:
574            boolean: True, a lock exists on the record by either the current session or other sessions.
575
576        Raises:
577            UOError
578
579        """
580        _logger.debug("Enter", record_id)
581
582        self._check_opened()
583        with self._lock:
584            in_packet = UniRPCPacket()
585            out_packet = UniRPCPacket()
586
587            out_packet.write(0, FuncCodes.EIC_RECORDLOCKED)
588            out_packet.write(1, self._handle)
589            out_packet.write(2, self._session.encode(record_id))
590
591            resp_code = self._call_server(in_packet, out_packet)
592            if resp_code != 0:
593                raise UOError(code=resp_code)
594
595            lock_status = in_packet.read(1)
596            self._status = in_packet.read(2)
597
598        _logger.debug("Exit", lock_status, self._status)
599        return False if lock_status == 0 else True

Check if a record has a lock on it.

Args: record_id (any): the record id - can be str, bytes, or DynArray.

Returns: boolean: True, a lock exists on the record by either the current session or other sessions.

Raises: UOError

def get_ak_info(self, index_name=''):
601    def get_ak_info(self, index_name=""):
602        """Obtain information about the secondary key indexes available on the file.
603
604        Args:
605            index_name (str, Optional). If this value is None or ignored, the list of available indices is returned.
606
607        Returns:
608            DynArray:
609                The return value will vary depending on the type of index, as follows:
610                1. For D-Type indexes: Field 1 contains D as the first character and
611                    Field 2 contains the location number of the indexed field.
612                2. For I-type indexes: Field 1 contains I as the first character,
613                    Field 2 contains the I-type expression, and the compiled I-type resides in field 19 and onward.
614                3. For both types:
615                    2nd value of Field 1 indicates if the index needs to be rebuilt. It is an empty string otherwise.
616                    3rd value of Field 1 is set if the index is null-suppressed. It is an empty string otherwise.
617                    4th value of Field 1 is set if automatic updates are disabled. It is an empty string otherwise.
618                    6th value of Field 1 contains an S for single valued indices or M for a multivalued index.
619
620        Raises:
621            UOError
622
623        """
624        _logger.debug("Enter", index_name)
625
626        self._check_opened()
627        with self._lock:
628            in_packet = UniRPCPacket()
629            out_packet = UniRPCPacket()
630            out_packet.write(0, FuncCodes.EIC_INDICES)
631            out_packet.write(1, self._handle)
632            out_packet.write(2, len(index_name))
633            out_packet.write(3, self._session.encode(index_name))
634
635            resp_code = self._call_server(in_packet, out_packet)
636            if resp_code != 0:
637                raise UOError(code=resp_code)
638
639            ak_info = DynArray(in_packet.read(1), self._session)
640
641        _logger.debug("Exit", ak_info)
642        return ak_info

Obtain information about the secondary key indexes available on the file.

Args: index_name (str, Optional). If this value is None or ignored, the list of available indices is returned.

Returns: DynArray: The return value will vary depending on the type of index, as follows: 1. For D-Type indexes: Field 1 contains D as the first character and Field 2 contains the location number of the indexed field. 2. For I-type indexes: Field 1 contains I as the first character, Field 2 contains the I-type expression, and the compiled I-type resides in field 19 and onward. 3. For both types: 2nd value of Field 1 indicates if the index needs to be rebuilt. It is an empty string otherwise. 3rd value of Field 1 is set if the index is null-suppressed. It is an empty string otherwise. 4th value of Field 1 is set if automatic updates are disabled. It is an empty string otherwise. 6th value of Field 1 contains an S for single valued indices or M for a multivalued index.

Raises: UOError

def itype(self, record_id, i_type_id):
644    def itype(self, record_id, i_type_id):
645        """Evaluates the specified I-descriptor and returns the evaluated string.
646
647        Args:
648            record_id (any): the record id - can be str, bytes, or DynArray.
649            i_type_id (any): the I-descriptor record id in the dictionary - can be str, bytes, or DynArray.
650
651        Returns:
652            DynArray: the evaluated result.
653
654        Raises:
655          UOError
656
657        """
658        _logger.debug("Enter", record_id, i_type_id)
659
660        with self._lock:
661            in_packet = UniRPCPacket()
662            out_packet = UniRPCPacket()
663            out_packet.write(0, FuncCodes.EIC_ITYPE)
664            out_packet.write(1, self._session.encode(self._name))
665            out_packet.write(2, self._session.encode(record_id))
666            out_packet.write(3, self._session.encode(i_type_id))
667
668            resp_code = self._call_server(in_packet, out_packet)
669            if resp_code != 0:
670                raise UOError(code=resp_code)
671
672            result = DynArray(in_packet.read(1), session=self._session)
673
674        _logger.debug("Exit", result)
675        return result

Evaluates the specified I-descriptor and returns the evaluated string.

Args: record_id (any): the record id - can be str, bytes, or DynArray. i_type_id (any): the I-descriptor record id in the dictionary - can be str, bytes, or DynArray.

Returns: DynArray: the evaluated result.

Raises: UOError

def read_named_fields(self, id_list, field_list, lock_flag=0):
677    def read_named_fields(self, id_list, field_list, lock_flag=0):
678        """Read a list of named fields on multiple records.
679
680        Note:
681            fields can be of D-type or I/V type.
682            If field_list contains names that are not defined in the dictionary, these names are replaced by @ID.
683            If a field has conv code on it, an oconv is automatically performed on its internal value to get the
684            converted output value.
685
686        Args:
687            id_list: a list of record ids.
688            field_list: a list of field names.
689            lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
690
691        Returns:
692            tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list,
693                    4. record list.
694
695        Raises:
696            UOFileError
697
698        Examples:
699            >>> with File("RENTAL_DETAILS") as test_file:
700            >>>     field_list = ["FULL_NAME", "ACTUAL_RETURN_DATE", "BALANCE_DUE"]
701            >>>     id_list = ['1084', '1307', '1976']
702            >>>     read_rs = test_file.read_named_fields(id_list, field_list)
703            >>>     for l in read_rs:
704            >>>         print(l)
705            ['0', '0', '0']
706            ['0', '0', '0']
707            ['1084', '1307', '1976']
708            [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'], '3.50'],
709            ['Jamie Klink', ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'],
710            ['Mo Evans', ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'], '19.04']]
711
712        """
713        _logger.debug("Enter", id_list, field_list, lock_flag)
714
715        self._check_opened()
716
717        id_set = RecordSet(id_list, session=self._session)
718
719        with self._lock:
720            in_packet = UniRPCPacket()
721            out_packet = UniRPCPacket()
722            out_packet.write(0, FuncCodes.EIC_READNAMEDFIELDSET)
723            out_packet.write(1, self._handle)
724            out_packet.write(2, _map_read_lock_flag(lock_flag))
725            out_packet.write(3, bytes(id_set))
726            out_packet.write(4, b"")
727            out_packet.write(5, self._session.encode(field_list))
728
729            self._call_server(in_packet, out_packet)
730
731            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
732            status_set = RecordSet(in_packet.read(2), session=self._session)
733            return_data_set = RecordSet(in_packet.read(3), session=self._session)
734
735            resp_codes = list(map(int, resp_code_set.list))
736            status_codes = list(map(int, status_set.list))
737
738            resp_error_codes = [key for key in resp_codes if key != 0]
739            if len(resp_error_codes) > 0:
740                raise UOFileError(
741                    code=resp_error_codes[0],
742                    obj=self._name,
743                    response_codes=resp_codes,
744                    status_codes=status_codes,
745                    id_list=id_set.list,
746                )
747
748            result_set = (resp_codes, status_codes, id_set.list, return_data_set.list)
749        _logger.debug("Exit", result_set)
750        return result_set

Read a list of named fields on multiple records.

Note: fields can be of D-type or I/V type. If field_list contains names that are not defined in the dictionary, these names are replaced by @ID. If a field has conv code on it, an oconv is automatically performed on its internal value to get the converted output value.

Args: id_list: a list of record ids. field_list: a list of field names. lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]

Returns: tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list, 4. record list.

Raises: UOFileError

Examples:

with File("RENTAL_DETAILS") as test_file: field_list = ["FULL_NAME", "ACTUAL_RETURN_DATE", "BALANCE_DUE"] id_list = ['1084', '1307', '1976'] read_rs = test_file.read_named_fields(id_list, field_list) for l in read_rs: print(l) ['0', '0', '0'] ['0', '0', '0'] ['1084', '1307', '1976'] [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'], '3.50'], ['Jamie Klink', ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'], ['Mo Evans', ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'], '19.04']]

def write_named_fields(self, id_list, field_list, field_data_list, lock_flag=0):
752    def write_named_fields(self, id_list, field_list, field_data_list, lock_flag=0):
753        """Write a list of named fields to multiple records.
754
755        Note:
756            If field_list contains names that are not defined in the dictionary, these names are ignored.
757            If a field is of I/V type or the record id itself, it is ignored.
758            If a field has CONV code on it, an iconv is automatically performed to use its internal value for the write.
759
760        Args:
761            id_list: a list of record ids.
762            field_list: a list of field names.
763            field_data_list: a list of DynArray consisting of all the field values.
764            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
765
766        Returns:
767            tuple: a tuple consisting of 4 lists: 1. response code list, 2. status code list, 3. record id list,
768                    4. field values list.
769
770        Raises:
771            UOError
772
773        Examples:
774            >>> with File("RENTAL_DETAILS") as test_file:
775            >>>     field_list = ["FULL_NAME", "ACTUAL_RETURN_DATE", "BALANCE_DUE"]
776            >>>     id_list = ['1084', '1307', '1976']
777            >>>     field_value_list = [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'],
778            '3.50'], ['Jamie Klink', ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'],
779            ['Mo Evans', ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'],'19.04']]
780            >>>     write_rs = test_file.write_named_fields(id_list, field_list, field_value_list)
781            >>>     for l in write_rs:
782            >>>         print(l)
783            ['0', '0', '0']
784            ['0', '0', '0']
785            ['1084', '1307', '1976']
786            [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'], '3.50'], ['Jamie Klink',
787            ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'], ['Mo Evans',
788            ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'], '19.04']]
789
790
791        """
792        _logger.debug("Enter", id_list, field_list, field_data_list, lock_flag)
793
794        self._check_opened()
795
796        id_set = RecordSet(id_list, session=self._session)
797        field_data_set = RecordSet(field_data_list, session=self._session)
798
799        with self._lock:
800            in_packet = UniRPCPacket()
801            out_packet = UniRPCPacket()
802            out_packet.write(0, FuncCodes.EIC_WRITENAMEDFIELDSET)
803            out_packet.write(1, self._handle)
804            out_packet.write(2, _map_write_lock_flag(lock_flag))
805            out_packet.write(3, bytes(id_set))
806            out_packet.write(4, bytes(field_data_set))
807            out_packet.write(5, self._session.encode(field_list))
808
809            self._call_server(in_packet, out_packet)
810
811            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
812            status_set = RecordSet(in_packet.read(2), session=self._session)
813            result_set = (
814                resp_code_set.list,
815                status_set.list,
816                id_set.list,
817                field_data_set.list,
818            )
819
820        _logger.debug("Exit", result_set)
821        return result_set

Write a list of named fields to multiple records.

Note: If field_list contains names that are not defined in the dictionary, these names are ignored. If a field is of I/V type or the record id itself, it is ignored. If a field has CONV code on it, an iconv is automatically performed to use its internal value for the write.

Args: id_list: a list of record ids. field_list: a list of field names. field_data_list: a list of DynArray consisting of all the field values. lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT

Returns: tuple: a tuple consisting of 4 lists: 1. response code list, 2. status code list, 3. record id list, 4. field values list.

Raises: UOError

Examples:

with File("RENTAL_DETAILS") as test_file: field_list = ["FULL_NAME", "ACTUAL_RETURN_DATE", "BALANCE_DUE"] id_list = ['1084', '1307', '1976'] field_value_list = [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'], '3.50'], ['Jamie Klink', ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'], ['Mo Evans', ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'],'19.04']] write_rs = test_file.write_named_fields(id_list, field_list, field_value_list) for l in write_rs: print(l) ['0', '0', '0'] ['0', '0', '0'] ['1084', '1307', '1976'] [['Karen McGlone', ['03/29/2010', '03/30/2010', '03/31/2010', '03/30/2010'], '3.50'], ['Jamie Klink', ['05/05/2010', '05/07/2010', '05/05/2010', '05/07/2010', '05/05/2010'], '4.82'], ['Mo Evans', ['08/23/2010', '08/20/2010', '08/26/2010', '08/22/2010', '08/25/2010', '08/22/2010'], '19.04']]

def read_records(self, id_list, lock_flag=0):
823    def read_records(self, id_list, lock_flag=0):
824        """Read multiple records from the file.
825
826        Args:
827            id_list: a list of record ids.
828            lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]
829
830        Returns:
831            tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list,
832                    4. record list.
833
834        Raises:
835            UOError
836
837        """
838        _logger.debug("Enter", id_list, lock_flag)
839
840        self._check_opened()
841
842        id_set = RecordSet(id_list, session=self._session)
843
844        with self._lock:
845            in_packet = UniRPCPacket()
846            out_packet = UniRPCPacket()
847            out_packet.write(0, FuncCodes.EIC_READSET)
848            out_packet.write(1, self._handle)
849            out_packet.write(2, _map_read_lock_flag(lock_flag))
850            out_packet.write(3, bytes(id_set))
851            out_packet.write(4, b"")
852            out_packet.write(5, b"")
853
854            self._call_server(in_packet, out_packet)
855
856            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
857            status_set = RecordSet(in_packet.read(2), session=self._session)
858            return_data_set = RecordSet(in_packet.read(3), session=self._session)
859            result_set = (
860                resp_code_set.list,
861                status_set.list,
862                id_set.list,
863                return_data_set.list,
864            )
865
866        _logger.debug("Exit", result_set)
867        return result_set

Read multiple records from the file.

Args: id_list: a list of record ids. lock_flag (int, optional): 0 (default, no lock), or [LOCK_EXCLUSIVE or LOCK_SHARED] [+ LOCK_WAIT]

Returns: tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list, 4. record list.

Raises: UOError

def write_records(self, id_list, record_list, lock_flag=0):
869    def write_records(self, id_list, record_list, lock_flag=0):
870        """Write multiple records into the file.
871
872        Args:
873            id_list: a list of record ids.
874            record_list: a list of records.
875            lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT
876
877        Returns:
878            tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list,
879                    4. record list.
880
881        Raises:
882            UOError
883
884        """
885        _logger.debug("Enter", id_list, record_list, lock_flag)
886
887        self._check_opened()
888
889        id_set = RecordSet(id_list, session=self._session)
890        record_set = RecordSet(record_list, session=self._session)
891
892        with self._lock:
893            in_packet = UniRPCPacket()
894            out_packet = UniRPCPacket()
895            out_packet.write(0, FuncCodes.EIC_WRITESET)
896            out_packet.write(1, self._handle)
897            out_packet.write(2, _map_write_lock_flag(lock_flag))
898            out_packet.write(3, bytes(id_set))
899            out_packet.write(4, bytes(record_set))
900            out_packet.write(5, b"")
901
902            self._call_server(in_packet, out_packet)
903
904            resp_code_set = RecordSet(in_packet.read(1), session=self._session)
905            status_set = RecordSet(in_packet.read(2), session=self._session)
906            result_set = (
907                resp_code_set.list,
908                status_set.list,
909                id_set.list,
910                record_set.list,
911            )
912
913        _logger.debug("Exit", result_set)
914        return result_set

Write multiple records into the file.

Args: id_list: a list of record ids. record_list: a list of records. lock_flag (int, optional): 0 (default), LOCK_RETAIN, LOCK_WAIT, or LOCK_RETAIN + LOCK_WAIT

Returns: tuple: a tuple consisting of four lists: 1. response code list, 2. status code list, 3. record id list, 4. record list.

Raises: UOError

def fileInfoEx(self):
 916    def fileInfoEx(self):
 917        """Get information about the specified file’s configuration, such as the
 918        file’s parameters, its modulus and load, its operating system file name, and its VOC name.
 919        The information returned depends on the file type and the value of the key.
 920
 921        After calling the method fileInfoEx, you can access these attributes to get their values.
 922        For UV, these attributes will be available:
 923        isFileVar: 1 if file.variable is a valid file variable; 0 otherwise.
 924        vocName: VOC name of the file.
 925        pathName: Path name of the file.
 926        type: File type: 1 Static hashed | 3 Dynamic hashed | 4 Type 1 | 5 Sequential | 7 Distributed and Multivolume
 927        hashAlg: Hashing algorithm: 2 for GENERAL, 3 for SEQ.NUM.
 928        modulus: Current modulus.
 929        minModulus: Minimum modulus.
 930        groupSize: Group size, in 1-KB units.
 931        largeRecordSize: Large record size.
 932        mergeLoad: Merge load parameter.
 933        splitLoad: Split load parameter.
 934        currentLoad: Current loading of the file (%).
 935        nodeName: Empty string if the file resides on the local system. Otherwise, the name of the node where the file resides.
 936        isAKFile: 1 if secondary indexes exist on the file; 0 otherwise.
 937        currentLine: Current line number.
 938        partNum: For a distributed file, returns the list of currently open part numbers.
 939        fileStatus: For a distributed file, returns the list of status codes indicating whether the last I/O operation succeeded
 940                    or failed for each part. A value of –1 indicates the corresponding part file is not open.
 941        recoveryType: 1 if the file is marked as recoverable, 0 if it is not. Returns an empty string
 942                      if recovery is not supported on the file type (such as type 1 and type 19 files).
 943        recoveryId: Always returns an empty string.
 944        isFixedModulus: Always returns 0.
 945        nlsmap: If NLS is enabled, the file map name; otherwise an empty string.
 946                If the map name is the default specified in the uvconfig file, the returned string is the map name followed by the name of the configurable parameter in parentheses.
 947        encryption: Returns a dynamic array containing the following information:
 948                    â–ª For a file encrypted with the WHOLERECORD option:
 949                    -1@VM@VM
 950                    â–ª For a file encrypted at the field level:
 951                    @VM@VM
 952                    @VM[@FM
 953                    ...@VM]
 954                    â–ª Returns an empty string if the file is not encrypted.
 955        repStatus: Return values can be:
 956                    0 – The file is not published, subscribed, or subwriteable.
 957                    1 – The file is being published.
 958                    2 – The file is being subscribed.
 959                    3 – The file is subwriteable.
 960                    Note: If U2 Data Replication is not running, this function
 961                    returns 0 for any file used with this function.
 962        For UD, these attributes will be available:
 963        isFileVar: File open status. 1= Open, 0= Not open
 964        vocName: VOC name
 965        pathName: Full path name of file
 966        type: File type.
 967                2 - HASHED
 968                3 - DYNAMIC
 969                4 - DIRECTORY
 970                5 - SEQUENTIAL
 971                7 - NFA
 972                8 - OS
 973                13 - EDA
 974        hashAlg: Hashing file type
 975                HASH & DYNAMI(KEYONLY) Hash type (0, 1, or 3)
 976                DYNAMIC (KEYDATA) Hash type (32 , 33, or 35)
 977                DYNAMIC (WHOLEFILE) Hash type (48, 49, or 51)
 978                OTHERS
 979        modulus: Modulo of file
 980        minModulus: Minimum modulo
 981        groupSize: Group size of file
 982        largeRecordSize: Block size of file
 983        mergeLoad: Merge factor percentage
 984        splitLoad: Split factor percentage
 985        currentLoad: Current load percentage
 986        nodeName: Node name
 987        isAKFile: Does file contain alternate key indexes?
 988        currentLine: Next line number to read or write
 989        partNum: Part number
 990        fileStatus: Status
 991        relname: Filename
 992        blksize: Block size of file
 993        privilege: Access permissions
 994        whichIndex: Index to which the last SETINDEX statement was applied
 995        whatXValue: Index record read by last browsing statement, such as READFWD and READBCK
 996        isRecoverable: File type: recoverable or nonrecoverable
 997        isNumerical: Numeric keys
 998        isReplicated: Type of U2 Data Replication file
 999        beforeUpdateTrigger: BEFORE-UPDATE-TRIGGER catalog program name of the file <xx>.
1000        beforeDeleteTrigger: BEFORE-DELETE-TRIGGER catalog program name of the file <xx>.
1001        isEncrypted: Is the file encrypted?
1002        encinfo: Type of file encryption
1003        afterUpdateTrigger: AFTER-UPDATE-TRIGGER catalog program name of the file <xx>.
1004        afterDeleteTrigger: AFTER-DELETE-TRIGGER catalog program name of the file <xx>.
1005        is64bit: Defines the bit type
1006
1007        Args: void
1008
1009        Returns: void
1010
1011        Raise:
1012            UOError
1013
1014        Examples:
1015            >>> f = uopy.File('TEST')
1016            >>> f.fileInfoEx()
1017            >>> print(f.vocName)
1018            >>> print(f.pathName)
1019            >>> print(f.groupSize)
1020        """
1021        _logger.debug("Enter fileInfoEx")
1022
1023        self._check_opened()
1024        with self._lock:
1025            in_packet = UniRPCPacket()
1026            out_packet = UniRPCPacket()
1027            out_packet.write(0, FuncCodes.EIC_FILEINFOEx)
1028            out_packet.write(1, self._handle)
1029            resp_code = self._call_server(in_packet, out_packet)
1030
1031            if resp_code != 0:
1032                if resp_code == ErrorCodes.UOE_USC:
1033                    raise UOError(
1034                        code=resp_code,
1035                        obj=self._name,
1036                        message="fileInfoEx is not supported on versions prior to UniData 8.2.4 or prior to UniVerse 12.2.1.",
1037                    )
1038                else:
1039                    raise UOError(code=resp_code, obj=self._name)
1040
1041            fileinfo_set = RecordSet(in_packet.read(1), session=self._session)
1042            if self._session.db_type == "UD":
1043                if len(fileinfo_set.list) != UDFileInfoEx.LIST_COUNT:
1044                    raise UOError()
1045                (
1046                    self.isFileVar,
1047                    self.vocName,
1048                    self.pathName,
1049                    self.type,
1050                    self.hashAlg,
1051                    self.modulus,
1052                    self.minModulus,
1053                    self.groupSize,
1054                    self.largeRecordSize,
1055                    self.mergeLoad,
1056                    self.splitLoad,
1057                    self.currentLoad,
1058                    self.nodeName,
1059                    self.isAKFile,
1060                    self.currentLine,
1061                    self.partNum,
1062                    self.fileStatus,
1063                    self.relname,
1064                    self.blksize,
1065                    self.privilege,
1066                    self.whichIndex,
1067                    self.whatXValue,
1068                    self.isRecoverable,
1069                    self.isNumerical,
1070                    self.isReplicated,
1071                    self.beforeUpdateTrigger,
1072                    self.beforeDeleteTrigger,
1073                    self.isEncrypted,
1074                    self.encinfo,
1075                    self.afterUpdateTrigger,
1076                    self.afterDeleteTrigger,
1077                    self.is64bit,
1078                ) = fileinfo_set.list
1079                pass
1080            elif self._session.db_type == "UV":
1081                if len(fileinfo_set.list) != FileInfoEx.LIST_COUNT:
1082                    raise UOError()
1083                (
1084                    self.isFileVar,
1085                    self.vocName,
1086                    self.pathName,
1087                    self.type,
1088                    self.hashAlg,
1089                    self.modulus,
1090                    self.minModulus,
1091                    self.groupSize,
1092                    self.largeRecordSize,
1093                    self.mergeLoad,
1094                    self.splitLoad,
1095                    self.currentLoad,
1096                    self.nodeName,
1097                    self.isAKFile,
1098                    self.currentLine,
1099                    self.partNum,
1100                    self.fileStatus,
1101                    self.recoveryType,
1102                    self.recoveryId,
1103                    self.isFixedModulus,
1104                    self.nlsmap,
1105                    self.encryption,
1106                    self.repStatus,
1107                ) = fileinfo_set.list
1108                pass
1109        _logger.debug("Exit", fileinfo_set)
1110        pass

Get information about the specified file’s configuration, such as the file’s parameters, its modulus and load, its operating system file name, and its VOC name. The information returned depends on the file type and the value of the key.

After calling the method fileInfoEx, you can access these attributes to get their values. For UV, these attributes will be available: isFileVar: 1 if file.variable is a valid file variable; 0 otherwise. vocName: VOC name of the file. pathName: Path name of the file. type: File type: 1 Static hashed | 3 Dynamic hashed | 4 Type 1 | 5 Sequential | 7 Distributed and Multivolume hashAlg: Hashing algorithm: 2 for GENERAL, 3 for SEQ.NUM. modulus: Current modulus. minModulus: Minimum modulus. groupSize: Group size, in 1-KB units. largeRecordSize: Large record size. mergeLoad: Merge load parameter. splitLoad: Split load parameter. currentLoad: Current loading of the file (%). nodeName: Empty string if the file resides on the local system. Otherwise, the name of the node where the file resides. isAKFile: 1 if secondary indexes exist on the file; 0 otherwise. currentLine: Current line number. partNum: For a distributed file, returns the list of currently open part numbers. fileStatus: For a distributed file, returns the list of status codes indicating whether the last I/O operation succeeded or failed for each part. A value of –1 indicates the corresponding part file is not open. recoveryType: 1 if the file is marked as recoverable, 0 if it is not. Returns an empty string if recovery is not supported on the file type (such as type 1 and type 19 files). recoveryId: Always returns an empty string. isFixedModulus: Always returns 0. nlsmap: If NLS is enabled, the file map name; otherwise an empty string. If the map name is the default specified in the uvconfig file, the returned string is the map name followed by the name of the configurable parameter in parentheses. encryption: Returns a dynamic array containing the following information: ▪ For a file encrypted with the WHOLERECORD option: -1@VM@VM ▪ For a file encrypted at the field level: @VM@VM @VM[@FM ...@VM] ▪ Returns an empty string if the file is not encrypted. repStatus: Return values can be: 0 – The file is not published, subscribed, or subwriteable. 1 – The file is being published. 2 – The file is being subscribed. 3 – The file is subwriteable. Note: If U2 Data Replication is not running, this function returns 0 for any file used with this function. For UD, these attributes will be available: isFileVar: File open status. 1= Open, 0= Not open vocName: VOC name pathName: Full path name of file type: File type. 2 - HASHED 3 - DYNAMIC 4 - DIRECTORY 5 - SEQUENTIAL 7 - NFA 8 - OS 13 - EDA hashAlg: Hashing file type HASH & DYNAMI(KEYONLY) Hash type (0, 1, or 3) DYNAMIC (KEYDATA) Hash type (32 , 33, or 35) DYNAMIC (WHOLEFILE) Hash type (48, 49, or 51) OTHERS modulus: Modulo of file minModulus: Minimum modulo groupSize: Group size of file largeRecordSize: Block size of file mergeLoad: Merge factor percentage splitLoad: Split factor percentage currentLoad: Current load percentage nodeName: Node name isAKFile: Does file contain alternate key indexes? currentLine: Next line number to read or write partNum: Part number fileStatus: Status relname: Filename blksize: Block size of file privilege: Access permissions whichIndex: Index to which the last SETINDEX statement was applied whatXValue: Index record read by last browsing statement, such as READFWD and READBCK isRecoverable: File type: recoverable or nonrecoverable isNumerical: Numeric keys isReplicated: Type of U2 Data Replication file beforeUpdateTrigger: BEFORE-UPDATE-TRIGGER catalog program name of the file . beforeDeleteTrigger: BEFORE-DELETE-TRIGGER catalog program name of the file . isEncrypted: Is the file encrypted? encinfo: Type of file encryption afterUpdateTrigger: AFTER-UPDATE-TRIGGER catalog program name of the file . afterDeleteTrigger: AFTER-DELETE-TRIGGER catalog program name of the file . is64bit: Defines the bit type

Args: void

Returns: void

Raise: UOError

Examples:

f = uopy.File('TEST') f.fileInfoEx() print(f.vocName) print(f.pathName) print(f.groupSize)

class SequentialFile(uopy._uniobject.UniObject):
 20class SequentialFile(UniObject):
 21    """SequentialFile is used to define and manage MV Sequential Files (which are OS files).
 22
 23    SequentialFile can be used in the Python with statement so that whatever occurs in the with statement block,
 24    they are guaranteed to be closed upon exit.
 25
 26    Examples:
 27          >>> with SequentialFile("BP", "TEST_SEQ", True) as seq_file:
 28          >>>   seq_file.write_line("This is test line 1")
 29          >>>   seq_file.write_line("This is test line 2")
 30          >>>   seq_file.seek(0) # go to the beginning of the file
 31          >>>   seq_file.write_line("This is test line 0") # overwrite the first line
 32          >>>   seq_file.seek(0)
 33          >>>   seq_file.read_line()
 34          This is test line 0
 35          >>>   seq_file.read_line()
 36          This is test line 2
 37
 38    """
 39
 40    def __init__(self, file_name, record_id, create_flag=False, session=None):
 41        """Initializes a SequentialFile object.
 42
 43        Args:
 44            file_name (str): the directory file name.
 45            record_id (str): the sequential file name.
 46            create_flag (boolean, optional): when False (default), do not create the file if nonexistent;
 47                otherwise, create the file if nonexistent.
 48            session (Session, optional): the Session object that the SequentialFile object is bound to.
 49                If omitted, the last opened Session in the current thread will be used.
 50
 51        Returns:
 52            None
 53
 54        Raises:
 55            UOError
 56
 57        """
 58        super().__init__(session)
 59
 60        self._seq_file_name = str(file_name)
 61        self._seq_record_id = str(record_id)
 62        self._is_opened = False
 63        self._seq_timeout = 0
 64        self._seq_file_handle = 0
 65        self._status = 0
 66        self._block_size = _DEFAULT_BLOCK_SIZE
 67        self._is_read_all = True
 68
 69        if create_flag:
 70            self._seq_create_flag = 1
 71        else:
 72            self._seq_create_flag = 0
 73
 74        self.open()
 75
 76    def __enter__(self):
 77        if not self._is_opened:
 78            self.open()
 79        return self
 80
 81    def __exit__(self, exec_type, exec_value, traceback):
 82        self.close()
 83
 84    def __repr__(self):
 85        format_string = "<{} object {} at 0x{:016X}>"
 86        details = {"dir": self._seq_file_name, "name": self._seq_record_id}
 87        return format_string.format(
 88            ".".join([SequentialFile.__module__, SequentialFile.__qualname__]),
 89            details,
 90            id(self),
 91        )
 92
 93    @property
 94    def status(self):
 95        """int: The status code set by the remote server after a sequential file operation."""
 96        return self._status
 97
 98    @property
 99    def block_size(self):
100        """int: The block size for read_block(). The default value is 8192.
101
102        If left unset, read_block() will read the whole file back.
103        If set explicitly, it will be the maximum size of the data read_block() returns.
104
105        """
106        return self._block_size
107
108    @block_size.setter
109    def block_size(self, value):
110        if not isinstance(value, int):
111            raise UOError(message="read buffer size must be an integer!")
112        if value <= 0:
113            raise UOError(message="read buffer size must between greater than 0!")
114        self._block_size = value
115        self._is_read_all = False
116
117    @property
118    def timeout(self):
119        """int: the timeout for sequential file operations."""
120        return self._seq_timeout
121
122    @timeout.setter
123    def timeout(self, new_timeout):
124        _logger.debug("Enter")
125
126        with self._lock:
127            in_packet = UniRPCPacket()
128            out_packet = UniRPCPacket()
129
130            out_packet.write(0, FuncCodes.EIC_TIMEOUT)
131            out_packet.write(1, self._seq_file_handle)
132            out_packet.write(2, new_timeout)
133
134            resp_code = self._call_server(in_packet, out_packet)
135
136            if resp_code != 0:
137                raise UOError(code=resp_code)
138
139            self._seq_timeout = new_timeout
140
141        _logger.debug("Exit")
142
143    def open(self):
144        """Open the server-side file, creating it if the create_flag is True and the file doesn't exist.
145
146        Args:
147
148        Returns:
149
150        Raises:
151            UOError
152
153        """
154        _logger.debug("Enter", self._seq_file_name, self._seq_record_id)
155
156        if self._is_opened:
157            return
158
159        with self._lock:
160            in_packet = UniRPCPacket()
161            out_packet = UniRPCPacket()
162
163            out_packet.write(0, FuncCodes.EIC_OPENSEQ)
164            out_packet.write(1, self._session.encode(self._seq_file_name))
165            out_packet.write(2, self._session.encode(self._seq_record_id))
166            out_packet.write(3, self._seq_create_flag)
167
168            resp_code = self._call_server(in_packet, out_packet)
169            if resp_code != 0:
170                raise UOError(code=resp_code, obj=self._seq_file_name)
171
172            self._is_opened = True
173            self._seq_file_handle = in_packet.read(2)
174
175        _logger.debug("Exit")
176
177    def close(self):
178        """Close an opened sequential file.
179
180        Args:
181
182        Returns:
183            None
184
185        Raises:
186            UOError
187
188        """
189        _logger.debug("Enter", self._seq_file_name, self._seq_record_id)
190
191        if not self._is_opened:
192            return
193
194        with self._lock:
195            in_packet = UniRPCPacket()
196            out_packet = UniRPCPacket()
197
198            out_packet.write(0, FuncCodes.EIC_CLOSESEQ)
199            out_packet.write(1, self._seq_file_handle)
200
201            resp_code = self._call_server(in_packet, out_packet)
202            if resp_code != 0:
203                raise UOError(code=resp_code)
204
205        _logger.debug("Exit")
206
207    def seek(self, offset, relative_pos=0):
208        """Move the file pointer within the Sequential File by an offset position specified in bytes.
209
210        Args:
211            offset (int): specifies the number of bytes before or after relative_pos.
212                    A negative value moves the pointer to a position before aRelPos.
213            relative_pos (int): specifies the relative position within a file from which to seek. Default value is 0.
214                    0 (default) start from the beginning of the file.
215                    1 start from the current position.
216                    2 start from the end of the file.
217
218        Returns:
219            None
220
221        Raises:
222            UOError
223
224        """
225        _logger.debug("Enter", offset, relative_pos)
226
227        if relative_pos not in {_SEQ_FILE_START, _SEQ_FILE_CURR, _SEQ_FILE_END}:
228            raise UOError(code=ErrorCodes.UOE_EINVAL)
229
230        with self._lock:
231            in_packet = UniRPCPacket()
232            out_packet = UniRPCPacket()
233
234            out_packet.write(0, FuncCodes.EIC_SEEK)
235            out_packet.write(1, self._seq_file_handle)
236            out_packet.write(2, offset)
237            out_packet.write(3, relative_pos)
238
239            resp_code = self._call_server(in_packet, out_packet)
240
241            if resp_code != 0:
242                raise UOError(code=resp_code)
243
244        _logger.debug("Exit")
245
246    def write_eof(self):
247        """Write an EOF marker to the sequential file.
248
249        Args:
250
251        Returns:
252            None
253
254        Raises:
255            UOError
256
257        """
258        _logger.debug("Enter")
259
260        with self._lock:
261            in_packet = UniRPCPacket()
262            out_packet = UniRPCPacket()
263
264            out_packet.write(0, FuncCodes.EIC_WEOFSEQ)
265            out_packet.write(1, self._seq_file_handle)
266
267            resp_code = self._call_server(in_packet, out_packet)
268
269            if resp_code != 0:
270                raise UOError(code=resp_code)
271
272        _logger.debug("Exit")
273
274    def write_block(self, blk_data):
275        """Write the given block to the sequential file at the location currently set.
276
277        Args:
278            blk_data (any): The data to write - can be str, bytes or DynArray.
279
280        Returns:
281            None
282
283        Raises:
284            UOError
285
286        """
287        _logger.debug("Enter", blk_data)
288
289        with self._lock:
290            in_packet = UniRPCPacket()
291            out_packet = UniRPCPacket()
292
293            out_packet.write(0, FuncCodes.EIC_WRITEBLK)
294            out_packet.write(1, self._seq_file_handle)
295            out_packet.write(2, self._session.encode(blk_data))
296
297            resp_code = self._call_server(in_packet, out_packet)
298
299            if resp_code == 0:
300                self._status = in_packet.read(1)
301            else:
302                raise UOError(code=resp_code)
303
304        _logger.debug("Exit")
305
306    def write_line(self, line_data):
307        """Write the given line to the sequential file at the location currently set.
308
309        Args:
310            line_data (any): The data to write - can be str, bytes or DynArray.
311
312        Returns:
313            None
314
315        Raises:
316            UOError
317
318        """
319        _logger.debug("Enter", line_data)
320
321        with self._lock:
322            in_packet = UniRPCPacket()
323            out_packet = UniRPCPacket()
324
325            out_packet.write(0, FuncCodes.EIC_WRITESEQ)
326            out_packet.write(1, self._seq_file_handle)
327            out_packet.write(2, self._session.encode(line_data))
328
329            resp_code = self._call_server(in_packet, out_packet)
330
331            if resp_code == 0:
332                self._status = in_packet.read(1)
333            else:
334                raise UOError(code=resp_code)
335
336            _logger.debug("Exit")
337
338    def read_line(self):
339        """Reads a line of data from the sequential file.
340
341        The lines must be delimited with a newline character.
342
343        status property will return one of the following values:
344        -1    The file is not open for reading.
345        0        The read was successful.
346        1        The end of file was reached.
347
348        Args:
349
350        Returns:
351            str: the line of data read.
352
353        Raises:
354            UOError
355
356        """
357
358        _logger.debug("Enter")
359
360        with self._lock:
361            in_packet = UniRPCPacket()
362            out_packet = UniRPCPacket()
363
364            out_packet.write(0, FuncCodes.EIC_READSEQ)
365            out_packet.write(1, self._seq_file_handle)
366
367            resp_code = self._call_server(in_packet, out_packet)
368
369            if resp_code == 0:
370                self._status = in_packet.read(1)
371                line_ = in_packet.read(2)
372            else:
373                raise UOError(code=resp_code)
374
375        _logger.debug("Exit", line_)
376        return self._session.decode(line_)
377
378    def read_block(self):
379        """Reads a block of data from the sequential file.
380
381        Upon completion, the status property will return one of the following values:
382        -1    The file is not open for reading.
383        0     The read was successful.
384        1     The end of file was reached.
385
386        Args:
387
388        Returns:
389            bytes: the data block read.
390
391        Raises:
392            UOError
393
394        """
395
396        _logger.debug("Enter")
397
398        with self._lock:
399            bytes_buf = b""
400
401            while self._status == 0:
402                in_packet = UniRPCPacket()
403                out_packet = UniRPCPacket()
404
405                out_packet.write(0, FuncCodes.EIC_READBLK)
406                out_packet.write(1, self._seq_file_handle)
407                out_packet.write(2, self._block_size)
408
409                resp_code = self._call_server(in_packet, out_packet)
410
411                self._status = in_packet.read(1)
412
413                if resp_code == 0:
414                    bytes_buf += in_packet.read(2)
415
416                    if not self._is_read_all:
417                        break
418                else:
419                    raise UOError(code=resp_code)
420
421            _logger.debug("Exit", bytes_buf)
422            return bytes_buf

SequentialFile is used to define and manage MV Sequential Files (which are OS files).

SequentialFile can be used in the Python with statement so that whatever occurs in the with statement block, they are guaranteed to be closed upon exit.

Examples:

with SequentialFile("BP", "TEST_SEQ", True) as seq_file: seq_file.write_line("This is test line 1") seq_file.write_line("This is test line 2") seq_file.seek(0) # go to the beginning of the file seq_file.write_line("This is test line 0") # overwrite the first line seq_file.seek(0) seq_file.read_line() This is test line 0 seq_file.read_line() This is test line 2

SequentialFile(file_name, record_id, create_flag=False, session=None)
40    def __init__(self, file_name, record_id, create_flag=False, session=None):
41        """Initializes a SequentialFile object.
42
43        Args:
44            file_name (str): the directory file name.
45            record_id (str): the sequential file name.
46            create_flag (boolean, optional): when False (default), do not create the file if nonexistent;
47                otherwise, create the file if nonexistent.
48            session (Session, optional): the Session object that the SequentialFile object is bound to.
49                If omitted, the last opened Session in the current thread will be used.
50
51        Returns:
52            None
53
54        Raises:
55            UOError
56
57        """
58        super().__init__(session)
59
60        self._seq_file_name = str(file_name)
61        self._seq_record_id = str(record_id)
62        self._is_opened = False
63        self._seq_timeout = 0
64        self._seq_file_handle = 0
65        self._status = 0
66        self._block_size = _DEFAULT_BLOCK_SIZE
67        self._is_read_all = True
68
69        if create_flag:
70            self._seq_create_flag = 1
71        else:
72            self._seq_create_flag = 0
73
74        self.open()

Initializes a SequentialFile object.

Args: file_name (str): the directory file name. record_id (str): the sequential file name. create_flag (boolean, optional): when False (default), do not create the file if nonexistent; otherwise, create the file if nonexistent. session (Session, optional): the Session object that the SequentialFile object is bound to. If omitted, the last opened Session in the current thread will be used.

Returns: None

Raises: UOError

status

int: The status code set by the remote server after a sequential file operation.

block_size

int: The block size for read_block(). The default value is 8192.

If left unset, read_block() will read the whole file back. If set explicitly, it will be the maximum size of the data read_block() returns.

timeout

int: the timeout for sequential file operations.

def open(self):
143    def open(self):
144        """Open the server-side file, creating it if the create_flag is True and the file doesn't exist.
145
146        Args:
147
148        Returns:
149
150        Raises:
151            UOError
152
153        """
154        _logger.debug("Enter", self._seq_file_name, self._seq_record_id)
155
156        if self._is_opened:
157            return
158
159        with self._lock:
160            in_packet = UniRPCPacket()
161            out_packet = UniRPCPacket()
162
163            out_packet.write(0, FuncCodes.EIC_OPENSEQ)
164            out_packet.write(1, self._session.encode(self._seq_file_name))
165            out_packet.write(2, self._session.encode(self._seq_record_id))
166            out_packet.write(3, self._seq_create_flag)
167
168            resp_code = self._call_server(in_packet, out_packet)
169            if resp_code != 0:
170                raise UOError(code=resp_code, obj=self._seq_file_name)
171
172            self._is_opened = True
173            self._seq_file_handle = in_packet.read(2)
174
175        _logger.debug("Exit")

Open the server-side file, creating it if the create_flag is True and the file doesn't exist.

Args:

Returns:

Raises: UOError

def close(self):
177    def close(self):
178        """Close an opened sequential file.
179
180        Args:
181
182        Returns:
183            None
184
185        Raises:
186            UOError
187
188        """
189        _logger.debug("Enter", self._seq_file_name, self._seq_record_id)
190
191        if not self._is_opened:
192            return
193
194        with self._lock:
195            in_packet = UniRPCPacket()
196            out_packet = UniRPCPacket()
197
198            out_packet.write(0, FuncCodes.EIC_CLOSESEQ)
199            out_packet.write(1, self._seq_file_handle)
200
201            resp_code = self._call_server(in_packet, out_packet)
202            if resp_code != 0:
203                raise UOError(code=resp_code)
204
205        _logger.debug("Exit")

Close an opened sequential file.

Args:

Returns: None

Raises: UOError

def seek(self, offset, relative_pos=0):
207    def seek(self, offset, relative_pos=0):
208        """Move the file pointer within the Sequential File by an offset position specified in bytes.
209
210        Args:
211            offset (int): specifies the number of bytes before or after relative_pos.
212                    A negative value moves the pointer to a position before aRelPos.
213            relative_pos (int): specifies the relative position within a file from which to seek. Default value is 0.
214                    0 (default) start from the beginning of the file.
215                    1 start from the current position.
216                    2 start from the end of the file.
217
218        Returns:
219            None
220
221        Raises:
222            UOError
223
224        """
225        _logger.debug("Enter", offset, relative_pos)
226
227        if relative_pos not in {_SEQ_FILE_START, _SEQ_FILE_CURR, _SEQ_FILE_END}:
228            raise UOError(code=ErrorCodes.UOE_EINVAL)
229
230        with self._lock:
231            in_packet = UniRPCPacket()
232            out_packet = UniRPCPacket()
233
234            out_packet.write(0, FuncCodes.EIC_SEEK)
235            out_packet.write(1, self._seq_file_handle)
236            out_packet.write(2, offset)
237            out_packet.write(3, relative_pos)
238
239            resp_code = self._call_server(in_packet, out_packet)
240
241            if resp_code != 0:
242                raise UOError(code=resp_code)
243
244        _logger.debug("Exit")

Move the file pointer within the Sequential File by an offset position specified in bytes.

Args: offset (int): specifies the number of bytes before or after relative_pos. A negative value moves the pointer to a position before aRelPos. relative_pos (int): specifies the relative position within a file from which to seek. Default value is 0. 0 (default) start from the beginning of the file. 1 start from the current position. 2 start from the end of the file.

Returns: None

Raises: UOError

def write_eof(self):
246    def write_eof(self):
247        """Write an EOF marker to the sequential file.
248
249        Args:
250
251        Returns:
252            None
253
254        Raises:
255            UOError
256
257        """
258        _logger.debug("Enter")
259
260        with self._lock:
261            in_packet = UniRPCPacket()
262            out_packet = UniRPCPacket()
263
264            out_packet.write(0, FuncCodes.EIC_WEOFSEQ)
265            out_packet.write(1, self._seq_file_handle)
266
267            resp_code = self._call_server(in_packet, out_packet)
268
269            if resp_code != 0:
270                raise UOError(code=resp_code)
271
272        _logger.debug("Exit")

Write an EOF marker to the sequential file.

Args:

Returns: None

Raises: UOError

def write_block(self, blk_data):
274    def write_block(self, blk_data):
275        """Write the given block to the sequential file at the location currently set.
276
277        Args:
278            blk_data (any): The data to write - can be str, bytes or DynArray.
279
280        Returns:
281            None
282
283        Raises:
284            UOError
285
286        """
287        _logger.debug("Enter", blk_data)
288
289        with self._lock:
290            in_packet = UniRPCPacket()
291            out_packet = UniRPCPacket()
292
293            out_packet.write(0, FuncCodes.EIC_WRITEBLK)
294            out_packet.write(1, self._seq_file_handle)
295            out_packet.write(2, self._session.encode(blk_data))
296
297            resp_code = self._call_server(in_packet, out_packet)
298
299            if resp_code == 0:
300                self._status = in_packet.read(1)
301            else:
302                raise UOError(code=resp_code)
303
304        _logger.debug("Exit")

Write the given block to the sequential file at the location currently set.

Args: blk_data (any): The data to write - can be str, bytes or DynArray.

Returns: None

Raises: UOError

def write_line(self, line_data):
306    def write_line(self, line_data):
307        """Write the given line to the sequential file at the location currently set.
308
309        Args:
310            line_data (any): The data to write - can be str, bytes or DynArray.
311
312        Returns:
313            None
314
315        Raises:
316            UOError
317
318        """
319        _logger.debug("Enter", line_data)
320
321        with self._lock:
322            in_packet = UniRPCPacket()
323            out_packet = UniRPCPacket()
324
325            out_packet.write(0, FuncCodes.EIC_WRITESEQ)
326            out_packet.write(1, self._seq_file_handle)
327            out_packet.write(2, self._session.encode(line_data))
328
329            resp_code = self._call_server(in_packet, out_packet)
330
331            if resp_code == 0:
332                self._status = in_packet.read(1)
333            else:
334                raise UOError(code=resp_code)
335
336            _logger.debug("Exit")

Write the given line to the sequential file at the location currently set.

Args: line_data (any): The data to write - can be str, bytes or DynArray.

Returns: None

Raises: UOError

def read_line(self):
338    def read_line(self):
339        """Reads a line of data from the sequential file.
340
341        The lines must be delimited with a newline character.
342
343        status property will return one of the following values:
344        -1    The file is not open for reading.
345        0        The read was successful.
346        1        The end of file was reached.
347
348        Args:
349
350        Returns:
351            str: the line of data read.
352
353        Raises:
354            UOError
355
356        """
357
358        _logger.debug("Enter")
359
360        with self._lock:
361            in_packet = UniRPCPacket()
362            out_packet = UniRPCPacket()
363
364            out_packet.write(0, FuncCodes.EIC_READSEQ)
365            out_packet.write(1, self._seq_file_handle)
366
367            resp_code = self._call_server(in_packet, out_packet)
368
369            if resp_code == 0:
370                self._status = in_packet.read(1)
371                line_ = in_packet.read(2)
372            else:
373                raise UOError(code=resp_code)
374
375        _logger.debug("Exit", line_)
376        return self._session.decode(line_)

Reads a line of data from the sequential file.

The lines must be delimited with a newline character.

status property will return one of the following values: -1 The file is not open for reading. 0 The read was successful. 1 The end of file was reached.

Args:

Returns: str: the line of data read.

Raises: UOError

def read_block(self):
378    def read_block(self):
379        """Reads a block of data from the sequential file.
380
381        Upon completion, the status property will return one of the following values:
382        -1    The file is not open for reading.
383        0     The read was successful.
384        1     The end of file was reached.
385
386        Args:
387
388        Returns:
389            bytes: the data block read.
390
391        Raises:
392            UOError
393
394        """
395
396        _logger.debug("Enter")
397
398        with self._lock:
399            bytes_buf = b""
400
401            while self._status == 0:
402                in_packet = UniRPCPacket()
403                out_packet = UniRPCPacket()
404
405                out_packet.write(0, FuncCodes.EIC_READBLK)
406                out_packet.write(1, self._seq_file_handle)
407                out_packet.write(2, self._block_size)
408
409                resp_code = self._call_server(in_packet, out_packet)
410
411                self._status = in_packet.read(1)
412
413                if resp_code == 0:
414                    bytes_buf += in_packet.read(2)
415
416                    if not self._is_read_all:
417                        break
418                else:
419                    raise UOError(code=resp_code)
420
421            _logger.debug("Exit", bytes_buf)
422            return bytes_buf

Reads a block of data from the sequential file.

Upon completion, the status property will return one of the following values: -1 The file is not open for reading. 0 The read was successful. 1 The end of file was reached.

Args:

Returns: bytes: the data block read.

Raises: UOError

class Dictionary(uopy.File):
 17class Dictionary(File):
 18    """Dictionary provides convenient access to MV dictionary files."""
 19
 20    def __init__(self, name, session=None):
 21        """Initialize a Dictionary object.
 22
 23        Args:
 24            name (str): the name of the MV file to be opened.
 25            session (Session, optional): the Session object that the Dictionary object is bound to.
 26                If omitted, the last opened Session in the current thread will be used.
 27
 28        Raises:
 29            UOError
 30
 31        """
 32        super().__init__(name, 1, session)  # 1 is for dictionary
 33
 34    def get_assoc(self, record_id):
 35        """Return the ASSOC field of the dictionary record.
 36
 37        Args:
 38            record_id (str or DynArray): the record id of the dictionary file.
 39
 40        Returns:
 41            DynArray: the value of the ASSOC field.
 42
 43        Raises:
 44            UOError.
 45
 46        """
 47        return self.read_field(record_id, _DICT_ASSOC_INDEX)
 48
 49    def set_assoc(self, record_id, assoc):
 50        """Set the ASSOC field of the dictionary record.
 51
 52        Args:
 53            record_id (str or DynArray): the record id of the dictionary file.
 54            assoc (str or DynArray): the value of the ASSOC field.
 55
 56        Returns:
 57            None
 58
 59        Raises:
 60            UOError
 61
 62        """
 63        self.write_field(record_id, _DICT_ASSOC_INDEX, assoc)
 64
 65    def get_conv(self, record_id):
 66        """Return the CONV field of the dictionary record.
 67
 68        Args:
 69            record_id (str or DynArray): the record id of the dictionary file.
 70
 71        Returns:
 72            DynArray: the value of the CONV field.
 73
 74        Raises:
 75            UOError
 76
 77        """
 78        return self.read_field(record_id, _DICT_CONV_INDEX)
 79
 80    def set_conv(self, record_id, conv_code):
 81        """Set the CONV field of the dictionary record.
 82
 83        Args:
 84             record_id (str or DynArray): the record id of the dictionary file.
 85             conv_code (str or DynArray): the value of the CONV field.
 86
 87        Returns:
 88             None
 89
 90        Raises:
 91            UOError
 92
 93        """
 94        self.write_field(record_id, _DICT_CONV_INDEX, conv_code)
 95
 96    def get_format(self, record_id):
 97        """Return the FORMAT field of the dictionary record.
 98
 99        Args:
100            record_id (str or DynArray): the record id of the dictionary file.
101
102        Returns:
103            DynArray: the value of the FORMAT field.
104
105        Raises:
106            UOError
107
108        """
109        return self.read_field(record_id, _DICT_FORMAT_INDEX)
110
111    def set_format(self, record_id, format_code):
112        """Set the FORMAT field of the dictionary record.
113
114        Args:
115             record_id (str or DynArray): the record id of the dictionary file.
116             format_code (str or DynArray): the value of the FORMAT field.
117
118        Returns:
119             None
120
121        Raises:
122             UOError
123
124        """
125        self.write_field(record_id, _DICT_FORMAT_INDEX, format_code)
126
127    def get_loc(self, record_id):
128        """Return the LOC field of the dictionary record.
129
130        Args:
131            record_id (str or DynArray): the record id of the dictionary file.
132
133        Returns:
134            DynArray: the value of the LOC field.
135
136        Raises:
137            UOError
138
139        """
140        return self.read_field(record_id, _DICT_LOC_INDEX)
141
142    def set_loc(self, record_id, loc):
143        """Set the LOC field of the dictionary record.
144
145        Args:
146             record_id (str or DynArray): the record id of the dictionary file.
147             loc (str or DynArray): the value of the LOC field.
148
149        Returns:
150             None
151
152        Raises:
153             UOError
154
155        """
156        self.write_field(record_id, _DICT_LOC_INDEX, loc)
157
158    def get_name(self, record_id):
159        """Return the NAME field of the dictionary record.
160
161        Args:
162            record_id (str or DynArray): the record id of the dictionary file.
163
164        Returns:
165            DynArray: the value of the NAME field.
166
167        Raises:
168            UOError
169
170        """
171        return self.read_field(record_id, _DICT_NAME_INDEX)
172
173    def set_name(self, record_id, name):
174        """Set the NAME field of the dictionary record.
175
176        Args:
177             record_id (str or DynArray): the record id of the dictionary file.
178             name (str or DynArray): the value of the NAME field.
179
180        Returns:
181             None
182
183        Raises:
184             UOError
185
186        """
187        self.write_field(record_id, _DICT_NAME_INDEX, name)
188
189    def get_sm(self, record_id):
190        """Return the SM field of the dictionary record.
191
192        Args:
193            record_id (str or DynArray): the record id of the dictionary file.
194
195        Returns:
196            DynArray: the value of the SM field.
197
198        Raises:
199            UOError
200
201        """
202        return self.read_field(record_id, _DICT_SM_INDEX)
203
204    def set_sm(self, record_id, sm):
205        """Set the SM field of the dictionary record.
206
207        Args:
208             record_id (str or DynArray): the record id of the dictionary file.
209             sm (str or DynArray): the value of the SM field.
210
211        Returns:
212             None
213
214        Raises:
215             UOError
216
217        """
218        self.write_field(record_id, _DICT_SM_INDEX, sm)
219
220    def get_sql_type(self, record_id):
221        """Return the SQLType field of the dictionary record.
222
223        Args:
224            record_id (str or DynArray): the record id of the dictionary file.
225
226        Returns:
227            DynArray: the value of the SQLType field.
228
229        Raises:
230            UOError
231
232        """
233        return self.read_field(record_id, _DICT_SQLTYPE_INDEX)
234
235    def set_sql_type(self, record_id, sql_type):
236        """Set the SQLType field of the dictionary record.
237
238        Args:
239             record_id (str or DynArray): the record id of the dictionary file.
240             sql_type (str or DynArray): the value of the SQLType field.
241
242        Returns:
243             None
244
245        Raises:
246             UOError
247
248        """
249        self.write_field(record_id, _DICT_SQLTYPE_INDEX, sql_type)
250
251    def get_type(self, record_id):
252        """Return the TYPE field of the dictionary record.
253
254        Args:
255            record_id (str or DynArray): the record id of the dictionary file.
256
257        Returns:
258            DynArray: the value of the TYPE field.
259
260        Raises:
261            UOError
262
263        """
264        return self.read_field(record_id, _DICT_TYPE_INDEX)
265
266    def set_type(self, record_id, field_type):
267        """Set the TYPE field of the dictionary record.
268
269        Args:
270             record_id (str or DynArray): the record id of the dictionary file.
271             field_type (str or DynArray): the value of the TYPE field.
272
273        Returns:
274             None
275
276        Raises:
277             UOError
278
279        """
280        self.write_field(record_id, _DICT_TYPE_INDEX, field_type)

Dictionary provides convenient access to MV dictionary files.

Dictionary(name, session=None)
20    def __init__(self, name, session=None):
21        """Initialize a Dictionary object.
22
23        Args:
24            name (str): the name of the MV file to be opened.
25            session (Session, optional): the Session object that the Dictionary object is bound to.
26                If omitted, the last opened Session in the current thread will be used.
27
28        Raises:
29            UOError
30
31        """
32        super().__init__(name, 1, session)  # 1 is for dictionary

Initialize a Dictionary object.

Args: name (str): the name of the MV file to be opened. session (Session, optional): the Session object that the Dictionary object is bound to. If omitted, the last opened Session in the current thread will be used.

Raises: UOError

def get_assoc(self, record_id):
34    def get_assoc(self, record_id):
35        """Return the ASSOC field of the dictionary record.
36
37        Args:
38            record_id (str or DynArray): the record id of the dictionary file.
39
40        Returns:
41            DynArray: the value of the ASSOC field.
42
43        Raises:
44            UOError.
45
46        """
47        return self.read_field(record_id, _DICT_ASSOC_INDEX)

Return the ASSOC field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the ASSOC field.

Raises: UOError.

def set_assoc(self, record_id, assoc):
49    def set_assoc(self, record_id, assoc):
50        """Set the ASSOC field of the dictionary record.
51
52        Args:
53            record_id (str or DynArray): the record id of the dictionary file.
54            assoc (str or DynArray): the value of the ASSOC field.
55
56        Returns:
57            None
58
59        Raises:
60            UOError
61
62        """
63        self.write_field(record_id, _DICT_ASSOC_INDEX, assoc)

Set the ASSOC field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. assoc (str or DynArray): the value of the ASSOC field.

Returns: None

Raises: UOError

def get_conv(self, record_id):
65    def get_conv(self, record_id):
66        """Return the CONV field of the dictionary record.
67
68        Args:
69            record_id (str or DynArray): the record id of the dictionary file.
70
71        Returns:
72            DynArray: the value of the CONV field.
73
74        Raises:
75            UOError
76
77        """
78        return self.read_field(record_id, _DICT_CONV_INDEX)

Return the CONV field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the CONV field.

Raises: UOError

def set_conv(self, record_id, conv_code):
80    def set_conv(self, record_id, conv_code):
81        """Set the CONV field of the dictionary record.
82
83        Args:
84             record_id (str or DynArray): the record id of the dictionary file.
85             conv_code (str or DynArray): the value of the CONV field.
86
87        Returns:
88             None
89
90        Raises:
91            UOError
92
93        """
94        self.write_field(record_id, _DICT_CONV_INDEX, conv_code)

Set the CONV field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. conv_code (str or DynArray): the value of the CONV field.

Returns: None

Raises: UOError

def get_format(self, record_id):
 96    def get_format(self, record_id):
 97        """Return the FORMAT field of the dictionary record.
 98
 99        Args:
100            record_id (str or DynArray): the record id of the dictionary file.
101
102        Returns:
103            DynArray: the value of the FORMAT field.
104
105        Raises:
106            UOError
107
108        """
109        return self.read_field(record_id, _DICT_FORMAT_INDEX)

Return the FORMAT field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the FORMAT field.

Raises: UOError

def set_format(self, record_id, format_code):
111    def set_format(self, record_id, format_code):
112        """Set the FORMAT field of the dictionary record.
113
114        Args:
115             record_id (str or DynArray): the record id of the dictionary file.
116             format_code (str or DynArray): the value of the FORMAT field.
117
118        Returns:
119             None
120
121        Raises:
122             UOError
123
124        """
125        self.write_field(record_id, _DICT_FORMAT_INDEX, format_code)

Set the FORMAT field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. format_code (str or DynArray): the value of the FORMAT field.

Returns: None

Raises: UOError

def get_loc(self, record_id):
127    def get_loc(self, record_id):
128        """Return the LOC field of the dictionary record.
129
130        Args:
131            record_id (str or DynArray): the record id of the dictionary file.
132
133        Returns:
134            DynArray: the value of the LOC field.
135
136        Raises:
137            UOError
138
139        """
140        return self.read_field(record_id, _DICT_LOC_INDEX)

Return the LOC field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the LOC field.

Raises: UOError

def set_loc(self, record_id, loc):
142    def set_loc(self, record_id, loc):
143        """Set the LOC field of the dictionary record.
144
145        Args:
146             record_id (str or DynArray): the record id of the dictionary file.
147             loc (str or DynArray): the value of the LOC field.
148
149        Returns:
150             None
151
152        Raises:
153             UOError
154
155        """
156        self.write_field(record_id, _DICT_LOC_INDEX, loc)

Set the LOC field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. loc (str or DynArray): the value of the LOC field.

Returns: None

Raises: UOError

def get_name(self, record_id):
158    def get_name(self, record_id):
159        """Return the NAME field of the dictionary record.
160
161        Args:
162            record_id (str or DynArray): the record id of the dictionary file.
163
164        Returns:
165            DynArray: the value of the NAME field.
166
167        Raises:
168            UOError
169
170        """
171        return self.read_field(record_id, _DICT_NAME_INDEX)

Return the NAME field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the NAME field.

Raises: UOError

def set_name(self, record_id, name):
173    def set_name(self, record_id, name):
174        """Set the NAME field of the dictionary record.
175
176        Args:
177             record_id (str or DynArray): the record id of the dictionary file.
178             name (str or DynArray): the value of the NAME field.
179
180        Returns:
181             None
182
183        Raises:
184             UOError
185
186        """
187        self.write_field(record_id, _DICT_NAME_INDEX, name)

Set the NAME field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. name (str or DynArray): the value of the NAME field.

Returns: None

Raises: UOError

def get_sm(self, record_id):
189    def get_sm(self, record_id):
190        """Return the SM field of the dictionary record.
191
192        Args:
193            record_id (str or DynArray): the record id of the dictionary file.
194
195        Returns:
196            DynArray: the value of the SM field.
197
198        Raises:
199            UOError
200
201        """
202        return self.read_field(record_id, _DICT_SM_INDEX)

Return the SM field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the SM field.

Raises: UOError

def set_sm(self, record_id, sm):
204    def set_sm(self, record_id, sm):
205        """Set the SM field of the dictionary record.
206
207        Args:
208             record_id (str or DynArray): the record id of the dictionary file.
209             sm (str or DynArray): the value of the SM field.
210
211        Returns:
212             None
213
214        Raises:
215             UOError
216
217        """
218        self.write_field(record_id, _DICT_SM_INDEX, sm)

Set the SM field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. sm (str or DynArray): the value of the SM field.

Returns: None

Raises: UOError

def get_sql_type(self, record_id):
220    def get_sql_type(self, record_id):
221        """Return the SQLType field of the dictionary record.
222
223        Args:
224            record_id (str or DynArray): the record id of the dictionary file.
225
226        Returns:
227            DynArray: the value of the SQLType field.
228
229        Raises:
230            UOError
231
232        """
233        return self.read_field(record_id, _DICT_SQLTYPE_INDEX)

Return the SQLType field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the SQLType field.

Raises: UOError

def set_sql_type(self, record_id, sql_type):
235    def set_sql_type(self, record_id, sql_type):
236        """Set the SQLType field of the dictionary record.
237
238        Args:
239             record_id (str or DynArray): the record id of the dictionary file.
240             sql_type (str or DynArray): the value of the SQLType field.
241
242        Returns:
243             None
244
245        Raises:
246             UOError
247
248        """
249        self.write_field(record_id, _DICT_SQLTYPE_INDEX, sql_type)

Set the SQLType field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. sql_type (str or DynArray): the value of the SQLType field.

Returns: None

Raises: UOError

def get_type(self, record_id):
251    def get_type(self, record_id):
252        """Return the TYPE field of the dictionary record.
253
254        Args:
255            record_id (str or DynArray): the record id of the dictionary file.
256
257        Returns:
258            DynArray: the value of the TYPE field.
259
260        Raises:
261            UOError
262
263        """
264        return self.read_field(record_id, _DICT_TYPE_INDEX)

Return the TYPE field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file.

Returns: DynArray: the value of the TYPE field.

Raises: UOError

def set_type(self, record_id, field_type):
266    def set_type(self, record_id, field_type):
267        """Set the TYPE field of the dictionary record.
268
269        Args:
270             record_id (str or DynArray): the record id of the dictionary file.
271             field_type (str or DynArray): the value of the TYPE field.
272
273        Returns:
274             None
275
276        Raises:
277             UOError
278
279        """
280        self.write_field(record_id, _DICT_TYPE_INDEX, field_type)

Set the TYPE field of the dictionary record.

Args: record_id (str or DynArray): the record id of the dictionary file. field_type (str or DynArray): the value of the TYPE field.

Returns: None

Raises: UOError

class List(uopy._uniobject.UniObject):
 19class List(UniObject):
 20    """List is used to control, access, and manipulate server side select lists.
 21
 22    List is iterable - the iterator returns a DynArray object representing a record id.
 23    The iteration can be run only once until the select list is exhausted - subsequent iteration yields nothing.
 24
 25    Examples:
 26        >>> cmd = Command("SELECT VOC WITH F1 = 'V'")
 27        >>> cmd.run()
 28        >>> select_list = List() # default is select list 0
 29        >>> ids = select_list.read_list()
 30        >>> print(ids[:5])
 31        ['LOAD.LANG', 'BEGIN.WORK', 'CLEARSELECT', 'RELEASE.ITEMS', 'SET.WIDEZERO']
 32
 33    """
 34
 35    def __init__(self, list_no: int = 0, session: Session = None):
 36        """Initializes a new List object.
 37
 38        Args:
 39            list_no (int, optional): select list number (default is 0).
 40            session (Session, optional): the Session object that the List object is bound to.
 41                If omitted, the last opened Session in the current thread will be used.
 42
 43        Raises:
 44            UOError
 45
 46        """
 47        if list_no < 0 or list_no > 10:
 48            raise UOError(code=ErrorCodes.UOE_EINVAL)
 49
 50        super().__init__(session)
 51
 52        self._list_no = list_no
 53        self._is_all_fetched = False
 54
 55    def __repr__(self):
 56        format_string = "<{} object {} at 0x{:016X}>"
 57        details = {"list no": self._list_no}
 58        return format_string.format(
 59            ".".join([List.__module__, List.__qualname__]), details, id(self)
 60        )
 61
 62    def __iter__(self):
 63        return self
 64
 65    def __next__(self):
 66        next_id = self.next()
 67        if self._is_all_fetched:
 68            raise StopIteration()
 69        return next_id
 70
 71    def select(self, file_obj: File):
 72        """Create a new select list by selecting the File object and generating a select list of
 73        all the record ids from that file. It will overwrite the previous select list and the select
 74        list pointer will be reset to the first record id in the list.
 75
 76        Args:
 77            file_obj: File or Dictionary object to be selected.
 78
 79        Returns:
 80
 81        Raises:
 82            UOError
 83
 84        """
 85        _logger.debug("Enter", self._list_no, file_obj)
 86
 87        if not file_obj.is_opened:
 88            raise UOError(code=ErrorCodes.UOE_FILE_NOT_OPEN)
 89
 90        with self._lock:
 91            in_packet = UniRPCPacket()
 92            out_packet = UniRPCPacket()
 93
 94            out_packet.write(0, FuncCodes.EIC_SELECT)
 95            out_packet.write(1, file_obj.handle)
 96            out_packet.write(2, self._list_no)
 97
 98            resp_code = self._call_server(in_packet, out_packet)
 99            if resp_code != 0:
100                raise UOError(code=resp_code)
101
102            self._is_all_fetched = False
103
104        _logger.debug("Exit")
105        return self
106
107    def clear(self):
108        """Clear the selected list, emptying the contents and preparing for a new select list to be generated.
109
110        Args:
111
112        Returns:
113
114        Raises:
115            UOError
116
117        """
118        _logger.debug("Enter", self._list_no)
119
120        with self._lock:
121            in_packet = UniRPCPacket()
122            out_packet = UniRPCPacket()
123
124            out_packet.write(0, FuncCodes.EIC_CLEARSELECT)
125            out_packet.write(1, self._list_no)
126
127            resp_code = self._call_server(in_packet, out_packet)
128            if resp_code != 0:
129                raise UOError(code=resp_code)
130
131            self._is_all_fetched = True
132
133        _logger.debug("Exit")
134
135    def next(self):
136        """Return the next record ID in the select list.
137
138        Args:
139
140        Returns:
141            DynArray: The next record id in the select list, or None if exhausted.
142
143        Raises:
144            UOError
145
146        """
147        _logger.debug("Enter", self._list_no)
148
149        if self._is_all_fetched:
150            next_id = None
151        else:
152            with self._lock:
153                in_packet = UniRPCPacket()
154                out_packet = UniRPCPacket()
155
156                out_packet.write(0, FuncCodes.EIC_READNEXT)
157                out_packet.write(1, self._list_no)
158
159                resp_code = self._call_server(in_packet, out_packet)
160
161                if not resp_code:
162                    self._is_all_fetched = False
163                    next_id = DynArray(in_packet.read(1), session=self._session)
164                elif resp_code == ErrorCodes.UOE_LRR:
165                    self._is_all_fetched = True
166                    next_id = None
167                else:
168                    raise UOError(code=resp_code)
169
170        _logger.debug("Exit", next_id)
171        return next_id
172
173    def read_list(self):
174        """Read the entire select list back.
175
176        Args:
177
178        Returns:
179            DynArray: contains all the record ids in the select list.
180
181        Raises:
182            UOError
183
184        """
185        _logger.debug("Enter", self._list_no)
186
187        with self._lock:
188            in_packet = UniRPCPacket()
189            out_packet = UniRPCPacket()
190
191            out_packet.write(0, FuncCodes.EIC_READLIST)
192            out_packet.write(1, self._list_no)
193
194            resp_code = self._call_server(in_packet, out_packet)
195
196            if resp_code == 0:
197                self._is_all_fetched = True
198                if in_packet.read(1) > 0:
199                    ids = DynArray(in_packet.read(2), self._session)
200                else:
201                    ids = DynArray(b"", self._session)
202            elif resp_code == ErrorCodes.UOE_LRR:
203                self._is_all_fetched = True
204                ids = DynArray(b"", self._session)
205            else:
206                raise UOError(code=resp_code)
207
208        _logger.debug("Exit", ids)
209        return ids
210
211    def form_list(self, ids):
212        """Create a new select list from the supplied list of record ids.
213
214        The current select list number will be used as the new list number.
215
216        Args:
217            ids (DynArray or list): A list of record ids.
218
219        Returns:
220            None
221
222        Raises:
223            UOError
224
225        """
226        _logger.debug("Enter", self._list_no, ids)
227
228        with self._lock:
229            in_packet = UniRPCPacket()
230            out_packet = UniRPCPacket()
231
232            out_packet.write(0, FuncCodes.EIC_FORMLIST)
233            out_packet.write(1, self._list_no)
234            out_packet.write(2, self._session.encode(ids))
235
236            resp_code = self._call_server(in_packet, out_packet)
237            if resp_code != 0:
238                raise UOError(code=resp_code)
239
240            if resp_code == 0:
241                self._is_all_fetched = False
242
243        _logger.debug("Exit")
244
245    def select_alternate_key(self, file_obj: File, index_name):
246        """Generate a select list from the given File based on the specified secondary index.
247
248        Args:
249            file_obj (File): a File or a Dictionary object.
250            index_name (str): index name to select on.
251
252        Returns:
253            None
254
255        Raises:
256            UOError
257
258        """
259        return self._do_ak_select(file_obj, index_name, -1, b"")
260
261    def select_matching_ak(self, file_obj: File, index_name, index_value):
262        """Generate a select list from the given File based on the specified secondary index
263        whose value matches that of the named value.
264
265        Args:
266            file_obj (File): a File or a Dictionary object.
267            index_name (str): index name to select on.
268            index_value (any): value within the index to select - can be str, bytes, DynArray.
269
270        Returns:
271            None
272
273        Raises:
274            UOError
275
276        """
277        index_value_bytes = self._session.encode(index_value)
278        return self._do_ak_select(
279            file_obj, index_name, len(index_value_bytes), index_value_bytes
280        )
281
282    def _do_ak_select(self, file_obj, index_name, index_len, index_value):
283        _logger.debug(
284            "Enter", self._list_no, file_obj, index_name, index_len, index_value
285        )
286
287        if not isinstance(file_obj, File):
288            raise UOError(code=ErrorCodes.UOE_ENFILE)
289
290        if not file_obj.is_opened:
291            raise UOError(code=ErrorCodes.UOE_FILE_NOT_OPEN)
292
293        with self._lock:
294            in_packet = UniRPCPacket()
295            out_packet = UniRPCPacket()
296
297            out_packet.write(0, FuncCodes.EIC_SELECTINDEX)
298            out_packet.write(1, file_obj.handle)
299            out_packet.write(2, self._list_no)
300            out_packet.write(3, self._session.encode(index_name))
301            out_packet.write(4, index_len)
302            out_packet.write_char_array(5, index_value)
303
304            resp_code = self._call_server(in_packet, out_packet)
305            if resp_code != 0:
306                raise UOError(code=resp_code)
307
308            status = in_packet.read(1)
309            if status == _SELECT_LIST_EMPTY_STATE:
310                self._is_all_fetched = True
311            else:
312                self._is_all_fetched = False
313
314        _logger.debug("Exit")
315        return self

List is used to control, access, and manipulate server side select lists.

List is iterable - the iterator returns a DynArray object representing a record id. The iteration can be run only once until the select list is exhausted - subsequent iteration yields nothing.

Examples:

cmd = Command("SELECT VOC WITH F1 = 'V'") cmd.run() select_list = List() # default is select list 0 ids = select_list.read_list() print(ids[:5]) ['LOAD.LANG', 'BEGIN.WORK', 'CLEARSELECT', 'RELEASE.ITEMS', 'SET.WIDEZERO']

List(list_no: int = 0, session: Session = None)
35    def __init__(self, list_no: int = 0, session: Session = None):
36        """Initializes a new List object.
37
38        Args:
39            list_no (int, optional): select list number (default is 0).
40            session (Session, optional): the Session object that the List object is bound to.
41                If omitted, the last opened Session in the current thread will be used.
42
43        Raises:
44            UOError
45
46        """
47        if list_no < 0 or list_no > 10:
48            raise UOError(code=ErrorCodes.UOE_EINVAL)
49
50        super().__init__(session)
51
52        self._list_no = list_no
53        self._is_all_fetched = False

Initializes a new List object.

Args: list_no (int, optional): select list number (default is 0). session (Session, optional): the Session object that the List object is bound to. If omitted, the last opened Session in the current thread will be used.

Raises: UOError

def select(self, file_obj: File):
 71    def select(self, file_obj: File):
 72        """Create a new select list by selecting the File object and generating a select list of
 73        all the record ids from that file. It will overwrite the previous select list and the select
 74        list pointer will be reset to the first record id in the list.
 75
 76        Args:
 77            file_obj: File or Dictionary object to be selected.
 78
 79        Returns:
 80
 81        Raises:
 82            UOError
 83
 84        """
 85        _logger.debug("Enter", self._list_no, file_obj)
 86
 87        if not file_obj.is_opened:
 88            raise UOError(code=ErrorCodes.UOE_FILE_NOT_OPEN)
 89
 90        with self._lock:
 91            in_packet = UniRPCPacket()
 92            out_packet = UniRPCPacket()
 93
 94            out_packet.write(0, FuncCodes.EIC_SELECT)
 95            out_packet.write(1, file_obj.handle)
 96            out_packet.write(2, self._list_no)
 97
 98            resp_code = self._call_server(in_packet, out_packet)
 99            if resp_code != 0:
100                raise UOError(code=resp_code)
101
102            self._is_all_fetched = False
103
104        _logger.debug("Exit")
105        return self

Create a new select list by selecting the File object and generating a select list of all the record ids from that file. It will overwrite the previous select list and the select list pointer will be reset to the first record id in the list.

Args: file_obj: File or Dictionary object to be selected.

Returns:

Raises: UOError

def clear(self):
107    def clear(self):
108        """Clear the selected list, emptying the contents and preparing for a new select list to be generated.
109
110        Args:
111
112        Returns:
113
114        Raises:
115            UOError
116
117        """
118        _logger.debug("Enter", self._list_no)
119
120        with self._lock:
121            in_packet = UniRPCPacket()
122            out_packet = UniRPCPacket()
123
124            out_packet.write(0, FuncCodes.EIC_CLEARSELECT)
125            out_packet.write(1, self._list_no)
126
127            resp_code = self._call_server(in_packet, out_packet)
128            if resp_code != 0:
129                raise UOError(code=resp_code)
130
131            self._is_all_fetched = True
132
133        _logger.debug("Exit")

Clear the selected list, emptying the contents and preparing for a new select list to be generated.

Args:

Returns:

Raises: UOError

def next(self):
135    def next(self):
136        """Return the next record ID in the select list.
137
138        Args:
139
140        Returns:
141            DynArray: The next record id in the select list, or None if exhausted.
142
143        Raises:
144            UOError
145
146        """
147        _logger.debug("Enter", self._list_no)
148
149        if self._is_all_fetched:
150            next_id = None
151        else:
152            with self._lock:
153                in_packet = UniRPCPacket()
154                out_packet = UniRPCPacket()
155
156                out_packet.write(0, FuncCodes.EIC_READNEXT)
157                out_packet.write(1, self._list_no)
158
159                resp_code = self._call_server(in_packet, out_packet)
160
161                if not resp_code:
162                    self._is_all_fetched = False
163                    next_id = DynArray(in_packet.read(1), session=self._session)
164                elif resp_code == ErrorCodes.UOE_LRR:
165                    self._is_all_fetched = True
166                    next_id = None
167                else:
168                    raise UOError(code=resp_code)
169
170        _logger.debug("Exit", next_id)
171        return next_id

Return the next record ID in the select list.

Args:

Returns: DynArray: The next record id in the select list, or None if exhausted.

Raises: UOError

def read_list(self):
173    def read_list(self):
174        """Read the entire select list back.
175
176        Args:
177
178        Returns:
179            DynArray: contains all the record ids in the select list.
180
181        Raises:
182            UOError
183
184        """
185        _logger.debug("Enter", self._list_no)
186
187        with self._lock:
188            in_packet = UniRPCPacket()
189            out_packet = UniRPCPacket()
190
191            out_packet.write(0, FuncCodes.EIC_READLIST)
192            out_packet.write(1, self._list_no)
193
194            resp_code = self._call_server(in_packet, out_packet)
195
196            if resp_code == 0:
197                self._is_all_fetched = True
198                if in_packet.read(1) > 0:
199                    ids = DynArray(in_packet.read(2), self._session)
200                else:
201                    ids = DynArray(b"", self._session)
202            elif resp_code == ErrorCodes.UOE_LRR:
203                self._is_all_fetched = True
204                ids = DynArray(b"", self._session)
205            else:
206                raise UOError(code=resp_code)
207
208        _logger.debug("Exit", ids)
209        return ids

Read the entire select list back.

Args:

Returns: DynArray: contains all the record ids in the select list.

Raises: UOError

def form_list(self, ids):
211    def form_list(self, ids):
212        """Create a new select list from the supplied list of record ids.
213
214        The current select list number will be used as the new list number.
215
216        Args:
217            ids (DynArray or list): A list of record ids.
218
219        Returns:
220            None
221
222        Raises:
223            UOError
224
225        """
226        _logger.debug("Enter", self._list_no, ids)
227
228        with self._lock:
229            in_packet = UniRPCPacket()
230            out_packet = UniRPCPacket()
231
232            out_packet.write(0, FuncCodes.EIC_FORMLIST)
233            out_packet.write(1, self._list_no)
234            out_packet.write(2, self._session.encode(ids))
235
236            resp_code = self._call_server(in_packet, out_packet)
237            if resp_code != 0:
238                raise UOError(code=resp_code)
239
240            if resp_code == 0:
241                self._is_all_fetched = False
242
243        _logger.debug("Exit")

Create a new select list from the supplied list of record ids.

The current select list number will be used as the new list number.

Args: ids (DynArray or list): A list of record ids.

Returns: None

Raises: UOError

def select_alternate_key(self, file_obj: File, index_name):
245    def select_alternate_key(self, file_obj: File, index_name):
246        """Generate a select list from the given File based on the specified secondary index.
247
248        Args:
249            file_obj (File): a File or a Dictionary object.
250            index_name (str): index name to select on.
251
252        Returns:
253            None
254
255        Raises:
256            UOError
257
258        """
259        return self._do_ak_select(file_obj, index_name, -1, b"")

Generate a select list from the given File based on the specified secondary index.

Args: file_obj (File): a File or a Dictionary object. index_name (str): index name to select on.

Returns: None

Raises: UOError

def select_matching_ak(self, file_obj: File, index_name, index_value):
261    def select_matching_ak(self, file_obj: File, index_name, index_value):
262        """Generate a select list from the given File based on the specified secondary index
263        whose value matches that of the named value.
264
265        Args:
266            file_obj (File): a File or a Dictionary object.
267            index_name (str): index name to select on.
268            index_value (any): value within the index to select - can be str, bytes, DynArray.
269
270        Returns:
271            None
272
273        Raises:
274            UOError
275
276        """
277        index_value_bytes = self._session.encode(index_value)
278        return self._do_ak_select(
279            file_obj, index_name, len(index_value_bytes), index_value_bytes
280        )

Generate a select list from the given File based on the specified secondary index whose value matches that of the named value.

Args: file_obj (File): a File or a Dictionary object. index_name (str): index name to select on. index_value (any): value within the index to select - can be str, bytes, DynArray.

Returns: None

Raises: UOError

class Subroutine(uopy._uniobject.UniObject):
16class Subroutine(UniObject):
17    """Subroutine allows the application to call a cataloged BASIC subroutine on the server.
18
19    Arguments are used to both pass in data to and get back data from the cataloged subroutine.
20
21    Attributes:
22        name (str): the name of the cataloged BASIC subroutine.
23        num_args (int): the number of arguments defined on the cataloged subroutine.
24        args (list): the argument list for the subroutine, an argument can be a str, a DynArray, a byte array.
25
26    Examples:
27        >>> sub = Subroutine("SAYHELLOTO", 1)
28        >>> sub.args[0] = "David"
29        >>> print(sub.args)
30        ['David']
31        >>> sub.call()
32        >>> print(sub.args)
33        ['Hello, David']
34
35    """
36
37    def __init__(self, name="", num_args=0, session=None):
38        """Initialize a Subroutine object
39
40        Args:
41            name (str): the name of the cataloged BASIC subroutine.
42            num_args (int) : the number of arguments defined on the cataloged subroutine.
43            session (Session, optional): the Session object that the Subroutine object is bound to.
44                If omitted, the last opened Session in the current thread will be used.
45
46        Raises:
47            UOError
48
49        """
50        super().__init__(session)
51
52        self.name = name
53        self.num_args = int(num_args) if int(num_args) > 0 else 0
54        self.args = ["" for i in range(num_args)]
55
56    def __repr__(self):
57        format_string = "<{} object {} at 0x{:016X}>"
58        cls_name = ".".join([self.__module__, self.__class__.__qualname__])
59        details = (self.name, self.num_args, self.args)
60        return format_string.format(
61            ".".join([Subroutine.__module__, Subroutine.__qualname__]),
62            details,
63            id(self),
64        )
65
66    def call(self):
67        """Run the catalogued subroutine using the args on the remote server."""
68
69        _logger.debug("Enter", self.name, self.args)
70
71        if self.name is None or len(str(self.name)) == 0:
72            raise UOError(code=ErrorCodes.UOE_UNABLETOLOADSUB)
73
74        with self._lock:
75            in_packet = UniRPCPacket()
76            out_packet = UniRPCPacket()
77
78            out_packet.write(0, FuncCodes.EIC_SUBCALL)
79            out_packet.write(1, self.num_args)
80            out_packet.write(2, self._session.encode(self.name))
81
82            for i in range(3, self.num_args + 3):
83                out_packet.write(i, self._session.encode(self.args[i - 3]))
84
85            resp_code = self._call_server(in_packet, out_packet)
86            if resp_code != 0:
87                raise UOError(code=resp_code)
88
89            for i in range(1, self.num_args + 1):
90                self.args[i - 1] = DynArray(in_packet.read(i), self._session)
91
92        _logger.debug("Exit", self.name, self.args)

Subroutine allows the application to call a cataloged BASIC subroutine on the server.

Arguments are used to both pass in data to and get back data from the cataloged subroutine.

Attributes: name (str): the name of the cataloged BASIC subroutine. num_args (int): the number of arguments defined on the cataloged subroutine. args (list): the argument list for the subroutine, an argument can be a str, a DynArray, a byte array.

Examples:

sub = Subroutine("SAYHELLOTO", 1) sub.args[0] = "David" print(sub.args) ['David'] sub.call() print(sub.args) ['Hello, David']

Subroutine(name='', num_args=0, session=None)
37    def __init__(self, name="", num_args=0, session=None):
38        """Initialize a Subroutine object
39
40        Args:
41            name (str): the name of the cataloged BASIC subroutine.
42            num_args (int) : the number of arguments defined on the cataloged subroutine.
43            session (Session, optional): the Session object that the Subroutine object is bound to.
44                If omitted, the last opened Session in the current thread will be used.
45
46        Raises:
47            UOError
48
49        """
50        super().__init__(session)
51
52        self.name = name
53        self.num_args = int(num_args) if int(num_args) > 0 else 0
54        self.args = ["" for i in range(num_args)]

Initialize a Subroutine object

Args: name (str): the name of the cataloged BASIC subroutine. num_args (int) : the number of arguments defined on the cataloged subroutine. session (Session, optional): the Session object that the Subroutine object is bound to. If omitted, the last opened Session in the current thread will be used.

Raises: UOError

name
num_args
args
def call(self):
66    def call(self):
67        """Run the catalogued subroutine using the args on the remote server."""
68
69        _logger.debug("Enter", self.name, self.args)
70
71        if self.name is None or len(str(self.name)) == 0:
72            raise UOError(code=ErrorCodes.UOE_UNABLETOLOADSUB)
73
74        with self._lock:
75            in_packet = UniRPCPacket()
76            out_packet = UniRPCPacket()
77
78            out_packet.write(0, FuncCodes.EIC_SUBCALL)
79            out_packet.write(1, self.num_args)
80            out_packet.write(2, self._session.encode(self.name))
81
82            for i in range(3, self.num_args + 3):
83                out_packet.write(i, self._session.encode(self.args[i - 3]))
84
85            resp_code = self._call_server(in_packet, out_packet)
86            if resp_code != 0:
87                raise UOError(code=resp_code)
88
89            for i in range(1, self.num_args + 1):
90                self.args[i - 1] = DynArray(in_packet.read(i), self._session)
91
92        _logger.debug("Exit", self.name, self.args)

Run the catalogued subroutine using the args on the remote server.

class UOFileError(uopy.UOError):
 16class UOFileError(UOError):
 17    """
 18    This class extends the UOError class.
 19    This class can provide each error information for each key read while invoking the uopy.File.read_named_fields method.
 20
 21    Attributes:
 22    response_errors: a list of dictionaries.
 23    Each item in the list indicates the error information for each key read from the file.
 24    An example of the content in response_errors is [{0: 'No Error'}, {30001: 'This Record was not found'}].
 25
 26    id_list: a list of the file keys.
 27    An example of the content in id_list is ['0111', 'bad_id']
 28    """
 29
 30    def __init__(
 31        self,
 32        code=...,
 33        message=None,
 34        obj=None,
 35        response_codes=[],
 36        status_codes=[],
 37        id_list=[],
 38    ):
 39        """
 40        Initializes a UOFileError class.
 41        Args:
 42            code (int): error code
 43            message (string, optinal): error message
 44            response_codes (list, optional): a list of response codes returned from the server.
 45            status_codes (list, optional): a list of status codes returned from the server.
 46            id_list (list, optional): a list of file fields.
 47        """
 48        self._set_response_codes(response_codes)
 49        self._set_status_codes(status_codes)
 50        self._set_id_list(id_list)
 51        if code == ErrorCodes.UOE_EIO:
 52            if len(self._status_codes_list) > 0:
 53                statusCode = (
 54                    self._status_codes_list[0]
 55                    if self._status_codes_list[0] in _EIO_MSG_DICT
 56                    else 5
 57                )
 58                message = _EIO_MSG_DICT[statusCode]
 59        super().__init__(code, message, obj)
 60
 61    def _set_response_codes(self, codes):
 62        if not codes:
 63            codes = []
 64        if type(codes) != list:
 65            codes = [codes]
 66        self._response_code_list = codes
 67
 68    @property
 69    def response_errors(self):
 70        """A list of errors for each field. Each error contains a code and a message."""
 71        """
 72        self._response_errors = []
 73        for idx, response_code in enumerate(self._response_code_list):
 74            if response_code == ErrorCodes.UOE_EIO:
 75                status = self._status_codes_list[idx] if self._status_codes_list[idx] in _EIO_MSG_DICT else 5
 76                err = {response_code: _EIO_MSG_DICT[status]}
 77                self._response_errors.append(err)
 78            else:
 79                err = {response_code: _ERROR_MESSAGES.get(response_code, 'Unknown Error Code')}
 80                self._response_errors.append(err)
 81        """
 82        self._response_errors = [
 83            {
 84                code: _EIO_MSG_DICT[
 85                    self._status_codes_list[idx]
 86                    if self._status_codes_list[idx] in _EIO_MSG_DICT
 87                    else 5
 88                ]
 89            }
 90            if code == ErrorCodes.UOE_EIO
 91            else {code: _ERROR_MESSAGES.get(code, "Unknown Error Code")}
 92            for idx, code in enumerate(self._response_code_list)
 93        ]
 94        return self._response_errors
 95
 96    def _set_status_codes(self, codes):
 97        if not codes:
 98            codes = []
 99        if type(codes) != list:
100            codes = [codes]
101        self._status_codes_list = codes
102
103    def _set_id_list(self, ids):
104        if not ids:
105            self._id_list = []
106            return
107        if type(ids) != list:
108            ids = [ids]
109        self._id_list = ids
110
111    @property
112    def id_list(self):
113        """A list of fields."""
114        return self._id_list

This class extends the UOError class. This class can provide each error information for each key read while invoking the uopy.File.read_named_fields method.

Attributes: response_errors: a list of dictionaries. Each item in the list indicates the error information for each key read from the file. An example of the content in response_errors is [{0: 'No Error'}, {30001: 'This Record was not found'}].

id_list: a list of the file keys. An example of the content in id_list is ['0111', 'bad_id']

UOFileError( code=Ellipsis, message=None, obj=None, response_codes=[], status_codes=[], id_list=[])
30    def __init__(
31        self,
32        code=...,
33        message=None,
34        obj=None,
35        response_codes=[],
36        status_codes=[],
37        id_list=[],
38    ):
39        """
40        Initializes a UOFileError class.
41        Args:
42            code (int): error code
43            message (string, optinal): error message
44            response_codes (list, optional): a list of response codes returned from the server.
45            status_codes (list, optional): a list of status codes returned from the server.
46            id_list (list, optional): a list of file fields.
47        """
48        self._set_response_codes(response_codes)
49        self._set_status_codes(status_codes)
50        self._set_id_list(id_list)
51        if code == ErrorCodes.UOE_EIO:
52            if len(self._status_codes_list) > 0:
53                statusCode = (
54                    self._status_codes_list[0]
55                    if self._status_codes_list[0] in _EIO_MSG_DICT
56                    else 5
57                )
58                message = _EIO_MSG_DICT[statusCode]
59        super().__init__(code, message, obj)

Initializes a UOFileError class. Args: code (int): error code message (string, optinal): error message response_codes (list, optional): a list of response codes returned from the server. status_codes (list, optional): a list of status codes returned from the server. id_list (list, optional): a list of file fields.

response_errors

A list of errors for each field. Each error contains a code and a message.

id_list

A list of fields.

Inherited Members
UOError
code
message
builtins.BaseException
with_traceback
add_note
args
__version__ = '1.3.0'