(go to: table of contents, index, prev: Python in the OpenVMS environment, next: configuration guidelines)
There a two possibilities to attack the problem from the Python side:
Beginning with version 1.5.2-V007 there is also
pyvms.file_open() available,
which does return a file object.
Some arguments of a function might not be required in a specific situation. As
keyword arguments are not implemented you have to use 'None' as a placeholder
instead - internally this will be changed to '0 passed by value'.
See the examples of vms_lib.day() or
vms_lib.getdvi() to get an idea.
OpenVMS system services usually require ALL arguments be specified.
The Python interface routines usually substitute 'None' with '0 passed by value'
to indicate an omitted argument. They also allow trailing 'unused' arguments
to be omitted.
Using a tuple or a list would raise the question of which data is stored at
which position.
The examples usually use 'dict' as the name for the reference to the object,
but this is of course no requirement.
Almost all routines within Python do not return the 'status' code from the
underlying OpenVMS service. They use the Python model of raising a Python
exception when an error happens.
There are some routines which behave differently - e.g.
vms_lib.set_logical(). The
reason for this is a uniform style of returning data - in this case it is a
dictionary. Routines with different status values that can indicate success
do not raise an exception, too.
The vms_sys.getmsg() routine
allows the translation of the code into its text message:
Sometimes, the condition value is in an IOSB (I/O status block) for which the
'vmsobj_iosb' object provides storage.
See the examples section of
vms_sys.getjpiw()
Using a "long integer" does allow the programmer to do calculations within
Python. See the next section.
Date and time values are returned as a signed long integer, however bitmasks
like privileges are returned as a positive long integer.
Although an OpenVMS 'delta time' is represented by a negative value it does
not have a "direction". If you see something like "+01:00:00" - this is a
'combination time' - it means "add one hour to the current date + time".
Let's do some examples:
Now, a one-second delta time:
Let's use a different date:
Calculate one second.
To add one second, we have to subtract the delta-time:
Remember: this value does NOT represent a one-second 'delta-time'!
This routine, however, has some restrictions. Please see 'REFMAN Modules,
vms_lib module,
vms_lib.add_times' for details.
To subtract a delta time from an absolute date + time using Python's long
integer datatype you have to ADD both values. There is also an OpenVMS RTL
routine for this - see 'REFMAN Modules, vms_lib module,
vms_lib.sub_times()'.
Using a "long integer" does allow the programmer to do calculations within
Python.
Privilege bitmask values are stored in module
'vms_prvdef'.
@@ Ignore the 'PRV$_NULL' item code in this module. It is a work-around to
a deficy in the VMSDEF2MAR.COM procedure which
currently cannot cope with a VMSDEF module that has no item codes.
A privilege bitmask is 64 bits wide. All bit definitions in 'vms_prvdef' are
defined as Python long integers.
Since 14-FEB-1999 it is no longer necessary to convert the bitmasks from a
Python integer (32-bit) to a Python long integer (64-bit) because a BITMASK64
structure has been implemented. The following bits are still defined in the
'vms_prvdef' module with their
(32-bit) values in the second longword:
PRV_M2_UPGRADE, PRV_M2_DOWNGRADE, PRV_M2_GRPPRV, PRV_M2_READALL,
PRV_M2_IMPORT, PRV_M2_AUDIT, PRV_M2_SECURITY.
'vms_prvdef' also includes the bits
with the '_M_' code and their real 64-bit value. See the example of
PRV_M_READALL above.
Privileges are used, for example, in the following routines:
Within Python a PID must always be specified as an integer data type -
it is never a hex-string. e.g.:
You can use one of the following number representations within Python:
('ctx' is either the process' PID or, during wildcard lookups, a context value.
Please see the description of vms_lib.getjpi()
for details.)
Several system services
(vms_sys.delprc(),
vms_sys.forcex(), ...)
return the target process' PID if you specifiy 0 for the PID argument and
a process name.
For consistency the Python interface always returns the target process' PID
- no matter if you specify an explicit PID or use the process name argument.
Almost all examples in this documentation use a 'low' value for the PID.
This is because development happens on non-clustered OpenVMS systems.
You do need a good understanding of RMS and you need access to the 'OpenVMS
Record Management Services Reference Manual' to make use of the interfaces -
testers are always welcome.
RMS control blocks are accessible through so-called 'VMS objects'. The 'Python
for OpenVMS Reference Manual' contains
a list of these 'VMS objects'.
There are also some minimal example scripts
in the 'demoes manual'.
Warning!
The vms_sys.format_acl()
routine accepts a binary ACE and translates it in its ASCII equivalent.
The vms_sys.parse_acl() routine
accepts an ASCII string and translates it to the binary representation that is
used inside OpenVMS.
The vms_sys.get_security()
routine and the 'vmsobj_xabpro'
object can be used to retrieve ACLs or ACEs from files and other objects
(not via XABPRO).
Some system services like
vms_sys.add_holder() require
a quadword containing the identifier in one of the longwords. The other
usually is used for the attributes. In this case the interface routines
do not use a single Python long integer but a tuple of 2 integers.
file I/O
You should also take a look at the RMS section below.
record lengths
Recent ECOs allow the programmer to set the logical name
"DECC$DEFAULT_LRL".
>>> fo = open ('TEST1.TMP', 'w')
>>> fo.write ('data')
>>> fo.close()
$ write SYS$OUTPUT F$FILE_ATTRIBUTES ("TEST1.TMP", "LRL")
32767
$
$ define DECC$DEFAULT_LRL 49
>>> fo = open ('TEST2.TMP', 'w')
>>> fo.write ('data')
>>> fo.close()
$ write SYS$OUTPUT F$FILE_ATTRIBUTES ("TEST2.TMP", "LRL")
49
$
$ deassign DECC$DEFAULT_LRL
Note that this affects ALL files created through the DEC C RTL.
>>> import os, pyvms
>>>
>>> # O_TRUNC requests a NEW version of the file to be created !
>>> flags = os.O_CREAT + os.O_TRUNC + os.O_WRONLY
>>>
>>> fd = pyvms.crtl_open ('TEST3.TMP', flags, 0777, ('mrs=53',))
>>>
>>> import posix
>>> posix.write (fd, 'data')
>>> posix.close (fd)
$ write SYS$OUTPUT F$FILE_ATTRIBUTES ("TEST3.TMP", "LRL")
53
$
functions
arguments
Some functions (e. g.: vms_lib.currency)
do not have any arguments. If you provide any, then the programming interface
WILL raise a Python exception. The redundant argument is not silently ignored!
keyword arguments
e.g.: >>> ret = routine (p1 = val1)
are not supported for OpenVMS interface routines.
functions returning no data
Some routines do not need to return any 'data' - e.g.
vms_lib.attach() returns 'None' upon
successful completion. If an error happens, they will still raise a Python
exception.
functions returning dictionaries
Some routines like 'vms_sys.getjpiw()'
need to return a variable amount of data depending on its input parameters (the
item list in this case). The data is stored under different 'keys' in a
dictionary.
OpenVMS condition values
Using the native interfaces a programmer should _always_ check the returned
condition value. Some routines also use the OpenVMS condition mechanism to
signal errors, but a programmer should not rely on it.
>>> import vms_sys
>>> print vms_sys.getmsg (0x2c)
('%SYSTEM-F-ABORT, abort', (0, 0, 0, 0))
>>>
>>> print vms_sys.getmsg (0x2c) [0]
%SYSTEM-F-ABORT, abort
>>>
special OpenVMS datatypes
On OpenVMS, Python does not have a builtin 64-bit or 128-bit datatype.
64-bit quadword
These are simulated by using Python's "long integer" datatype.
See vms_sys.gettim() or
vms_sys.asctim() for examples.
An exception are quadwords that are used for
rightslist identifiers - see the explanation more
below this text.
date and time calculations
An OpenVMS binary date + time is internally represented by a signed quadword.
A positive value (including 0) indicates an absolute date + time
(e.g. 29-FEB-2000 12:34:45.78). A negative value means a delta time
(12 21:56:34.91), meaning 12 days, twenty-one hours, fifty-six minutes,
thirty-four seconds and 91 hundredth of a second.
>>> import vms_lib, vms_sys
If you are like me and always forget VMS' base date:
>>> vms_sys.asctim (0L)
'17-NOV-1858 00:00:00.00'
>>>
The smallest increment is 100 nanoseconds. It's easy to find out how many
of these 'ticks' are in a second:
>>> vms_sys.bintim ('17-NOV-1858 00:00:01.00')
10000000L
>>>
Warning! The trailing 'L' shows that this is a Python 'long integer'.
This is not a delta-time! '10000000L' really indicates the 17th of November
in the year 1858, one second after midnight.
>>> vms_sys.bintim ('0 00:00:01.00')
-10000000L
>>>
>>> feb29_y2k = vms_sys.bintim ('29-FEB-2000 12:34:56.78')
>>> feb29_y2k
44585444967800000L
>>>
>>> one_second = vms_sys.bintim ('0 00:00:01.00')
>>> one_second
-10000000L
>>>
>>> new_time = feb29_y2k - one_second
>>> new_time
44585444977800000L
>>> vms_sys.asctim (new_time)
'29-FEB-2000 12:34:57.78'
*
>>> print new_time - feb29_y2k
10000000L
>>>
>>> new_time_2 = vms_lib.add_times (feb29_y2k, one_second)
>>> new_time_2
44585444977800000L
>>> vms_sys.asctim (new_time_2)
'29-FEB-2000 12:34:57.78'
*
>>>
128-bit octaword
These are simulated by using Python's "long integer" datatype.
See vms_sys.getutc() or
vms_sys.ascutc() for examples.
processes
privileges
The user can also enable additional privileges
from his authorized privilege mask or turn on any privilege if he has the
SETPRV privilege by calling
vms_sys.setprv().
>>> import vms_prvdef
>>>
>>> # a bit in the first longword
>>> vms_prvdef.PRV_M_ALLSPOOL
16L
>>> type (vms_prvdef.PRV_M_ALLSPOOL)
<type 'long int'>
>>>
>>> # a bit in the second longword
>>> hex (vms_prvdef.PRV_M_READALL)
'0x800000000L'
>>> type (vms_prvdef.PRV_M_READALL)
<type 'long int'>
>>>
(_M2_ indicates that this bit is located in the 2nd longword.)
process identification (PID)
OpenVMS DCL utilities use an 8-character hex number as input and output for
the PID and translate it internally because system services and run-time
library routines use a binary longword.
$ PID = F$GETJPI(0,"PID")
$ show symbol PID
PID = "0000021A"
$ NUMBER = %X'PID'
$ show symbol NUMBER
NUMBER = 538 Hex = 0000021A Octal = 00000001032
$
>>> ctx,data = vms_lib.getjpi("JPI$_IMAGNAME",538)
>>> print data
DKA100:[PYTHON.PYTHON-1_5_1.VMS]PYTHON_ALPHA.EXE;1
>>>RMS
Many parts of the interfaces to the 'Record Management Services' (RMS) are not
very thoroughly or even not at all (e.g. tape handling) tested.
security related objects
ACL + ACE
An ACL (Access Control List) is made up from one or more ACEs (Access Control
list Entries). They are stored inside normal Python strings.
ACEs are a set of bytes, not a set of printable characters. You should not
output a binary ACE/ACL to a terminal, because the data stream can contain
control sequences that alter the terminal's settings. Using the
'repr()' builtin is safe:
>>> print repr (acestr)
'\014\001\000\000\020\000\000\000\004\000\003\000'
>>>
rightslist identifiers
Identifiers (UIC and general) and their attributes are represented by Python
integers (32-bit values). The 'vms_kgbdef'
module contains the attribute bitmask values (KGB_M_name).
Translation to / from the names can be done using the
vms_sys.asctoid() and
vms_sys.idtoasc() routines.