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