Issue 3237: Python: Naming of POA classes
Issue 3238: Python: Mapping of enumerators
Issue 3333: 00-01-12 python language mapping issue
Issue 3334: 00-01-12 python language mapping issue
Issue 3345: Python Issue: CORBA.TypeCode
Issue 3346: Python Issue: TypeCodes and CORBA.id
Issue 3347: Python Issue: Dynamic Invocation Interface
Issue 3348: Python Issue: Dynamic Skeleton Interface
Issue 3349: Python Issue: IDL generated module names
Issue 3350: Python Issue: Wide strings
Issue 3351: Python Issue: TypeCode constants?
Issue 3352: Python Issue: Object.create_request
Issue 3353: Python Issue: PortableServer.Servant._default_POA and _this
Issue 3354: Python Issue: Context.delete
Issue 3356: Python Issue: Context.delete
Issue 3358: Python Issue: widening object references and CORBA.Any.value
Issue 3430: Python-FTF: Mapping of toplevel modules
Issue 3610: Python mapping: skeleton class name
Issue 3713: Python: Alternate Mappings
Issue 3714: Python: Alternate Mappings
Issue 3715: Python: Union example
Issue 3716: Python: Constant Mapping
Issue 3717: Python: Exception base classes
Issue 3718: Python: Classes in module CORBA
Issue 3719: Python: Alternatives to skeleton
Issue 3720: Python: Servant base class
Issue 3721: Python: Mapping of ServantLocator
Issue 3723: Issue: Python language bidning January 2000 Draft
Issue 3724: Issue: Python language binding January 2000 Draft
Issue 4315: Problem with Python Language Mapping
Issue 4316: Problem with Python Language Mapping
Issue 4658: Python mapping issue: fixed point
Issue 4659: Python mapping issue: context
Issue 4660: Python mapping issue: ValueFactory
Issue 4661: Python mapping issue: value boxes
Issue 5471: In the resolution of issue 4659
Issue 5727: list of operations provided by the ORB object
Issue 5779: OpaqueValue needs to be documented in the Python Language mapping
Issue 3237: Python: Naming of POA classes (python-ftf)
Click here for this issue's archive.
Source: Humboldt-Universitaet (Mr. Martin von Loewis, loewis(at)informatik.hu-berlin.de)
Nature: Uncategorized Issue
Severity:
Summary:
On page 13 (page 18 in 99-08-02), it says that module M results in a Python package M__POA containing the skeletons. In the next paragraph, it refers to the package POA_M. They can't both be right. In omniORBpy I use POA_M, since that is what the C++ mapping does.
I also think that there is an error in the enum mapping section, which
says that
module M {
interface O {
enum Farbe {rot, gruen, blau};
};
};
maps to M.O_rot, M.O_gruen and M.O_blau. It makes much more sense for
them to map to M.O.rot, etc.
On page 1-3 of 00-01-12 module M example code maps IDL 'import' method to the Python method 'import_', ie def import_(self,what): ... this is then contradicted by the next paragraph "To avoid conflicts, IDL names that are also Python identifiers are prefixed with an underscore." ~~~~~~~~
In 00-01-12, Python language mapping: On page 2, under the section headed 'Alignment with CORBA', the Python mapping itself is not mentioned! On page 4, under 'Acknowledgements' Humboldt and DSTC are on the one line when they are indeed separate organisations.
The current python mapping (second paragraph of section 1.3.8) describes that the "CORBA.TypeCode" function can be used to create type codes by passing in a repository ID. The example that follows that paragraph then goes on to pass the CosNaming.NamingContext class to CORBA.TypeCode. Does CORBA.TypeCode expect a class or repository ID (or both)? What exceptions does CORBA.TypeCode raise if it fails to create a type code?
In section 1.3.8 of the Python Language Mapping the second paragraph states: "The repositroy ID of a type can be obtained with the function CORBA.id, passing the object representing the type." Which "object representing the type" are supposed to be supported here? - struct/exception, union, interface, enum, etc... make sense - but what about int, long, string, sequence types? What exception is to be raised if an invalid object is passed to CORBA.id?
In the third paragraph of Section 14.4.4 states that "The application may specify the repository id of the target object.". I assume that this is done in order for the ORB to lookup the operation in the given interface in and be determine parameter type/direction and return value information. This raises the following issues: - What exception is raised if the repository id is invalid (ie, can't be looked up in the IFR, etc...) - "Standard" operations (ie, _is_a, _interface, etc...) are not defined in the IFR so these need to be handled separately than other operations Should we also provide a "standard" operation (similar to C++) which takes something like a NamedValuePair sequence (or better yet a CORBA::OperationDescription)?
The exception to use when the IFR is not available is specified as INTF_REPOS in the Core. Calling pseudo-operations on the DII is not supported, according the DII specification in the Core.
Section 1.5.2 describes the "repository_id" parameter passed to PortableServer.DynamicImplementation.invoke as specifying the interface type for which the operation was called. How is the ORB able to deterimine this information? Does this really make sense anyway? Is it the repository id of the most derived interface or for the current call? There is no document describing what (if any) operations are ORB provided on PortableServer.DynamicImplementation. For example, it makes sense to provide default implementations of the following operations: - _is_a - _get_interface - _get_domain_managers Also, does it make sense to have the programmer over-ride a "_repository_id" or "_most_derived_interface" operation on this class in order to generate object references which don't require the client to invoke "_is_a" on (in order to narrow the reference)? Otherwise most calls to a python DynamicImplementation would result in the client always invoking _is_a in order to narrow.
The example in Section 1.2 "Using Scoped Names" states that:
module M { <IDL-deleted> };
"would introduce a module M.py, which contains the following definitions:"
This section never describes how the programmer gets at those names, I assume
that if you want the definitions from module M, then you say: "import M".
This introduces a disgusting and serious flaw in the mapping in that IDL
compilers need to fake out the python module system and "update" IDL files.
Mapping IDL modules and to Python modules and packages is intentional, to simplify usage of these mapped construct by the programmer.
Section 1.3.2 describes how wide strings (and wide chars) are mapped to an implementation defined type. It says that this type supports being passed to the std. python "len" function -- is the returned value of this supposed to be the length in wchars or octets? It says that CORBA.wstr returns a wide character with the code point "c" in an implementation defined encoding. What happens if "c" not a valid code point? It says that "CORBA.word (CORBA.wstr (c)) == c". Does this also imply that "len (CORBA.wstr (c)) == 1" and that CORBA.word only takes a wide string with a length of one? What exceptions are raised if this is not true?
Since the len function always returns the number of elements in a sequence, it must return the number of wide characters. The exception to raise if CORBA.wstr is called with an invalid code point is unspecified; raising a BAD_PARAM exception is probably a sensible outcome. However, since the exact meaning of wstr is implementation defined, its error behaviour should be implementation-defined as well.
Are type code constants generated by the IDL compiler, and if so are they available for use by developers (ie, not implementation specific)? If type code constants are not available, then developers have to rememeber the repository ids of certain IDL declarations (python-noops like typedef) in order to get a typecode from CORBA.TypeCode (since CORBA.id is most likely no help in this instance). I propose that type code constants be made available to developers using some standardized naming scheme (_tc_XXX?).
Close with no change. The analysis is incorrect: python-noops like typedef do get Python symbols that can be passed to CORBA.id, so there is no need to remember the repository ID. CORBA.TypeCode is sufficient to get the type code of all types.
Section 14.4.4 describes the create_request method on CORBA.Object as taking: the operation name, parameters and the opt. keyword arguments context, flags and repository id. Later on in section 1.6 the signature for create_request is shown as: create_request (context, op_name, arg_list, result, flags) Which definition is correct? Also, shouldn't the name of this operation be "_create_request" to avoid name clashes with user-defined operations?
It should be spelled _created_request; this is an editorial change. Also, the definition of that operation in 1.4.4 is correct, the definition in section 1.6 should be deleted.
Section 1.5.1 describes the _default_POA operation as returning the value of
ORB.resolve_initial_reference ("RootPOA").
What ORB is used for this call (assumed static implementation-defined)? What
if no ORB has been initialized yet? What exceptions are raised if there is no
ORB?
Also, the _this operation needs a POA -- which post likely implies that it
calls _default_POA by default. Are the same exceptions raised in this case?
Section 1.4.3 describes the mapping for CORBA.Context and states that a "delete" operation is provided to delete child contexts. This introduces an implementation detail that most likely requires circular references which is not good with python. Can the "delete" operation be deleted from the document? It is not needed because there is no way to "lookup" child contexts -- most of the other language mappings do not have this method anymore.
Section 1.4.3 describes the mapping for CORBA.Context and states that a "delete" operation is provided to delete child contexts. This introduces an implementation detail that most likely requires circular references which is not good with python. Can the "delete" operation be deleted from the document? It is not needed because there is no way to "lookup" child contexts -- most of the other language mappings do not have this method anymore.
There is an issue with widening object references using the CORBA.Any.value method. The current spec. states that the value method returns a suitable type of object for the accompanying type of the any. This is an issue when one process sends an object reference which is not staticaly known to the receiving ORB.
The adopted specification says that IDL modules map to Python modules, and seems to imply that global modules are mapped to global modules (without explicitly saying so). Is it conforming if the generated module appear in an implementation-defined package? For example, to access the CORBA module in ORB X, a number of implementations require to write from X import CORBA instead of import CORBA With this approach, it is possible to have multiple implementations of CORBA installed, but it requires applications to specify which one they want to use. Proposed resolution: In the section 1.2 (Scoped Names), add a paragraph An implementation can chose to map top-level definitions (including the module CORBA) to modules in an implementation-defined package, to allow concurrent installations of different CORBA runtime libraries. In that case, the implementation must provide a configuration option so that toplevel modules can be used without without importing them from a package.
In document ptc/00-04-07, my issue, number 3237, is resolved in a rather bizarre manner. The specification as it now stands states that to name skeleton classes: 'For the POA, the first element of the fully-scoped name of the interface is suffixed with "__POA".' The section no longer contradicts itself, but I object to the resolution to call the class M__POA, rather than POA_M. Here is a summary of how other language mappings name their skeleton classes for an interface I in module M: Ada: M.I.Impl C: POA_M_I C++: POA_M::I COBOL: POA-M-I Java: M.IPOA Smalltalk: seems not to have a skeleton mapping at all
issue closely related to issue 3237. Close with no change. This is a request that to reverse the resolution of issue 3237. Reversing this decision would break existing implementations for no reason; the issue does not indicate any defect in the mapping.
On page I-2 of ptc/00-04-08, the mentioning of alternate mappings is a serious issue, since it means that scripts may not be portable across implementations of this specification.
On page I-2 of ptc/00-04-08, the mentioning of alternate mappings is a serious issue, since it means that scripts may not be portable across implementations of this specification.
On p. I-7 of ptc/00-04-08, what is the 17 in the example?
Is there any protection against the value being changed?
Close with no change. Python does not support read-only module attributes, so there is no such protection
Where are the classes CORBA.UserException and CORBA.SystemException declared?
Close with no change. Section 1.1 states that every implementation provides a module CORBA. Clearly, these classes are defined in the module CORBA
On page I-9 of ptc/00-04-08: Are the declarations (not the implementations) of CORBA.Any, CORBA.ValueBase etc. just built into the environment, or are they explicitly declared somewhere?
Close with no change. Every implementation provides a module CORBA. This module is available through standard Python import statements (e.g. from CORBA import Any). The classes in that module are the implementations; Python does not support 'mere' declarations.
Section 1.5.1 starts with "One approach". What is the other approach?
Resolution: Clarify that the mapping only defines a single approach. The next sentence opposes this to delegation-based servant implementations, but it should be made clear that they are out of scope of the specification
On p. I-13 of ptc/00-04-08, it says the base class of all servant classes is PortableServer.Servant. I'm missing somewhat here: I thought the base class is M__POA.
Close with no change. As mentioned in section 1.5.1, the skeleton classes are named M__POA. This sentence specifies that these classes share a common base class, namely Servant.
Is ServantLocator mapped to a predefined Python type?
Close with no change. ServantLocator is an interface, so it follows the mapping for interfaces.
As far as I can tell, the language binding is silent on the subject of attribute mapping. If an IDL interface specified an attribute, how is this mapped into Python? Is this mapped to a python attribute or to accessor functions?
The Python language binding says that IDL attributes are mapped to Python accessor functions with leading '_'s in their names: "If an interface defines an attribute name, the attribute is mapped into an operation _get_name, as defined If the attribute is not readonly, there is an additional operation _set_name, as defined in chapter 3.11 of CORBA 2.2." Traditionally, Python attributes and methods with leading '_'s in their names are considered to be private. The language enforces this in some cases. For example, names with leading '_'s are not automatically exported from modules and names used in class definitions are mangled to prevent external access if they begin with double '_'s and don't end in double '_'s. I feel strongly that the language mapping should be changed to get accessor method names without leading underscore, as in get_name(), or even just name(), as in the C++ mapping.
Close with no change. All of the proposed alternatives have draw-backs. Mapping an attribute XXX to get_XXX() may cause conflicts with an operation of the same name. Mapping it to XXX() would be possible, but the proposal does not include a name for the corresponding set operation. Following the C++ mapping, it could be XXX(new_value). In Python, that would be inconvenient to implement, as it requires an implementation of the form
def XXX(self, new_value=missing):
if new_value is not missing:
self._XXX = new_value
else:
return self._XXX
Here, missing cannot be None, as None might be a valid new value. Also, changing it in this way might break existing applications.
Another possibility it to map IDL attributes to Python attributes. This has currently the draw-back that multiple implementations of __getattr__ (e.g. resulting from implementation inheritance) cannot be easily coordinated; also, implementing __getattr__ is error-prone. Therefore, experience in terms of implementations of a modified mapping should be gained before this aspect of the specification is changed.
I'd like to point out some errors in the Python Language Mapping
document, ftp://ftp.omg.org/pub/docs/formal/01-02-66.pdf,
section 1.3.9 "Mapping for an Any".
The example which accompanies the text for this section
is vague, contains errors, and is confusing to someone who
is trying to learn how to use Anys in the Python Language Mapping.
For discussion of some of the errors in this example, refer to
the following messages on the omniORB mailing list:
http://www.uk.research.att.com/omniORB/archives/2001-04/0139.html
http://www.uk.research.att.com/omniORB/archives/2001-04/0140.html
I believe the example is broken in many ways, and should
be re-written to more clearly illustrate how to use Anys
with the Python Language Mapping.
I have re-written the example as follows:
========================================================================
import CORBA
import M
# Create a value of type M.S
v = M.S(1, CORBA.TRUE)
# obtain type code
tc=CORBA.TypeCode( CORBA.id(M.S) )
# could also use: tc1=CORBA.TypeCode("IDL:M/S:1.0")
# Create any containing an M.S object
any1 = CORBA.Any(tc, v)
## the TypeCodes for the basic CORBA types are defined
## in the CORBA 2.4 standard, section 10.7.2 "TypeCode Constants"
# Create any containing CORBA Long
any2 = CORBA.Any(CORBA.TC_long, 1)
# Create any containing CORBA Float
any3 = CORBA.Any(CORBA.TC_float, 3.14)
# Create any containing CORBA Float
any4 = CORBA.Any(CORBA.TC_short, 5)
# Create any containing CORBA unsigned
any5 = CORBA.Any(CORBA.TC_ushort, 6)
# Create any containing CORBA String
any6 = CORBA.Any(CORBA.TC_string, "some string")
o = something() # somehow obtain reference to object of type M.foo
o.operate( any1 )
o.operate( any2 )
o.operate( any3 )
.
.
.
========================================================================
I believe that it is imperative that this example be changed in
Section 1.3.9 of the Python Language Mapping.
I'd like to point out some errors in the Python Language Mapping
document, ftp://ftp.omg.org/pub/docs/formal/01-02-66.pdf,
section 1.3.9 "Mapping for an Any".
The example which accompanies the text for this section
is vague, contains errors, and is confusing to someone who
is trying to learn how to use Anys in the Python Language Mapping.
For discussion of some of the errors in this example, refer to
the following messages on the omniORB mailing list:
http://www.uk.research.att.com/omniORB/archives/2001-04/0139.html
http://www.uk.research.att.com/omniORB/archives/2001-04/0140.html
I believe the example is broken in many ways, and should
be re-written to more clearly illustrate how to use Anys
with the Python Language Mapping.
I have re-written the example as follows:
========================================================================
import CORBA
import M
# Create a value of type M.S
v = M.S(1, CORBA.TRUE)
# obtain type code
tc=CORBA.TypeCode( CORBA.id(M.S) )
# could also use: tc1=CORBA.TypeCode("IDL:M/S:1.0")
# Create any containing an M.S object
any1 = CORBA.Any(tc, v)
## the TypeCodes for the basic CORBA types are defined
## in the CORBA 2.4 standard, section 10.7.2 "TypeCode Constants"
# Create any containing CORBA Long
any2 = CORBA.Any(CORBA.TC_long, 1)
# Create any containing CORBA Float
any3 = CORBA.Any(CORBA.TC_float, 3.14)
# Create any containing CORBA Float
any4 = CORBA.Any(CORBA.TC_short, 5)
# Create any containing CORBA unsigned
any5 = CORBA.Any(CORBA.TC_ushort, 6)
# Create any containing CORBA String
any6 = CORBA.Any(CORBA.TC_string, "some string")
o = something() # somehow obtain reference to object of type M.foo
o.operate( any1 )
o.operate( any2 )
o.operate( any3 )
.
.
.
========================================================================
I believe that it is imperative that this example be changed in
Section 1.3.9 of the Python Language Mapping.
The Python mapping for fixed point types is slightly unclear, and
could benefit from a few of the facilities from other language
mappings.
Below, I've written a proposed specification to replace the existing
section on fixed point. The changes are:
- replace "foo" and "bar" with "digits" and "scale"
- clarify meaning of integers used in constructor and value() method
- add a constructor taking a string
- correct "loss of precision" to be "overflow"
- add requirement for string conversion with str()
- add round() and truncate() methods
- clarify usage of CORBA.fixed() and add string-based versions
- relax the requirement that certain entities are classes
Here is the suggested replacement text:
------
IDL of the form
typedef fixed<digits,scale> MyFixed;
is mapped as follows:
* A constructor MyFixed() expecting either a string representing the
fixed point value, or an integer type representing the digits of
the value.
The string form of the constructor accepts a string representation
of a fixed point literal, with the trailing 'd' or 'D' optional.
The value is truncated if too many digits are given after the
decimal point. If there are too many digits before the decimal
point, or the string is not a valid fixed point value, a
CORBA.DATA_CONVERSION exception is raised.
The integer form of the constructor accepts a Python integer or
long integer, representing the digits of the fixed point value.
The integer is numerically the fixed point value * 10 ** scale.
If the integer has too many digits, CORBA.DATA_CONVERSION is
raised.
e.g. given IDL:
typedef fixed<5,2> MyFixed;
the following is true:
MyFixed("123.45") == MyFixed(12345)
* To facilitate the use of anonymous fixed point values, a generic
CORBA.fixed() constructor is provided. Its arguments take three
possible forms:
- A single string representing the fixed point value, with a
trailing 'd' or 'D' optional. The resulting fixed point value
derives its digits and scale from the string. Raises
DATA_CONVERSION if the value exceeds the size of CORBA fixed,
or the string is invalid.
- The digits and scale values, followed by a conforming string.
The string is treated as with named types described above.
- The digits and scale values, followed by a conforming integer or
long integer. The integer is treated as with named types
described above.
e.g.
a = CORBA.fixed("123.45")
b = CORBA.fixed(5, 2, "123.45")
c = CORBA.fixed(5, 2, 12345)
assert(a == b)
assert(b == c)
The result of calling either kind of constructor is an object with the
following properties:
* Numeric operators for addition, subtraction, multiplication, and
division, both of two fixed point numbers, and in combination with
integers. A DATA_CONVERSION exception is raised if the operation
results in an overflow.
* Operations as follows:
- value() returns an integer or long integer representing the
digits of the fixed point number, in the form accepted by the
constructors.
- precision() returns the number of digits.
- decimals() returns the scale.
- round(scale) returns a new fixed point number containing the
original number rounded to the specified scale.
- truncate(scale) returns a new fixed point number containing the
original number truncated to the specified scale.
* When a fixed point number is passed to the standard str()
function, a string representing the fixed point value is returned.
The string does not contain a trailing 'd'.
The Python mapping for context arguments is slightly unclear. I suggest adding the following paragraph at the end of section 1.4.1: If an operation in an OMG IDL specification has a context specification, then a Context parameter follows all operation-specific in and inout arguments. The caller must pass a CORBA.Context object; if the object has the incorrect type, a BAD_PARAM system exception is raised.
The ValueFactory mapping is slightly unclear. I suggest the following revised text for the third paragraph of section 1.3.10: For a given value type, the ValueFactory maps to a class instance with a __call__ method taking no arguments. When it is called, it returns a new instance of the value type. Initialiser operations of the value type map to methods of the factory object. The registry for value factories can be accessed using the standard ORB operations register_value_factory, unregister_value_factory, and lookup_value_factory. For value types without operations, a default factory is registered automatically.
I suggest a change to the mapping for value boxes, that makes them
much more convenient to use. I believe that none of the Python ORBs
implement the currently specified mapping, so changing the mapping at
this point will not affect any ORB implementations or application
code.
I suggest that the new mapping is:
------
Value boxes are mapped to the normal mapping of the boxed type, or
None for null value boxes. For example, given IDL
valuetype BoxedString string;
interface I {
void example(in BoxedString a, in BoxedString b);
};
the operation could be called as:
obj.example("Hello", None)
------
Discussion: this mapping has one limitation, in that in a boxed object
reference type it is impossible to distinguish a null value box from a
non-null value box containing a nil object reference. This is
considered acceptable since the IDL to Java mapping has the same
property; there is a clear precedent for this kind of mapping.
Discussion: this mapping has one limitation, in that in a boxed object reference type it is impossible to distinguish a null value box from a non-null value box containing a nil object reference. This is considered acceptable since the IDL to Java mapping has the same property; there is a clear precedent for this kind of mapping.
1. In the resolution of issue.... (a) The system exception that is raised is said to be BAD_PARAM. Since it is a bad context that is being taken exception to, why is the BAD_CONTEXT exception not used instead? (b) It is better to also define a standard minor code with an associated error description when a use of a standard system exception is specified. This helps the user figure out what caused the system exception to be triggered. This is missing in the resolution.
In the list of operations provided by the ORB object, the first is list_initial_references(). In the CORBA spec, there is no operation by that name in the PIDL, but there is a list_initial_services() operation. This looks like a typo
OpaqueValue, a new native type introduced in Issue 2162 (void * in DII Chapter) for add_arg, was never documented in any of the language mappings. Language Mapping that claim that the DII interfaces map according to regular rules need to provide mapping rules for OpaqueValue and document it. The mapping would simply be OpaqueValue --> (void *) or equivalent.