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]
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)
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()
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
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.
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.
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")
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)
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 ")
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
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
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
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
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
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
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
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
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)
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
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.
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
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
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
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
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.
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
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]]
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]]]
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
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
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
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.
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)
Inherited Members
- builtins.BaseException
- with_traceback
- add_note
- args
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)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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']]
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']]
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
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
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
Args: void
Returns: void
Raise: UOError
Examples:
f = uopy.File('TEST') f.fileInfoEx() print(f.vocName) print(f.pathName) print(f.groupSize)
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
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
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.
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
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
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
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
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
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
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
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
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.
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
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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']
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
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
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
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
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
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
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
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
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']
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
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.
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']
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.