extending an exposed class using boost python - boost-python

I want to extend a class which has already exposed to python. For example:
snippet 1:
class_<DataValueContainer, DataValueContainer::Pointer>( "DataValueContainer" )
.def( "__len__", &DataValueContainer::Size )
.def( VariableIndexingPython<DataValueContainer, Variable<std::string> >() )
.def( VariableIndexingPython<DataValueContainer, Variable<int> >() )
.def( VariableIndexingPython<DataValueContainer, Variable<double> >() )
.def( self_ns::str( self ) )
;
Now in a different place I want to extend python class DataValueContainer, such as:
snippet 2:
class_<DataValueContainer, DataValueContainer::Pointer>
.def( VariableIndexingPython<DataValueContainer, Variable<MyObject> >() )
Is it possible to do it using boost.python? The reason I want to do that since the snippet 1 is in the kernel of an existing code and I hesitate to modify it.
Best regards

As far as I know, this is not possible without making some minor modifications to snippet 1, or reimplementing parts of boost::python::class_. When an object of type boost::python::class_ is instantiated, type initialization and registration occurs within the internals of Boost.Python. Instantiating class_ with the same type and arguments will effectively overwrite the previous class object.
In Python, the problem is akin to a type being redefined. In the example below, the spam identifier is used for one type, and then associated with a different type:
>>> class spam:
... def action1(self): pass
...
>>> # Redefines spam type.
... class spam:
... def action2(self): pass
...
>>> print hasattr(s, "action1")
False
>>> print hasattr(s, "action2")
True
Rather than the spam type being extended via its identifier:
>>> class spam:
... def action1(self): pass
...
>>> # Extend spam type.
... def action2(s): pass
...
>>> spam.action2 = action2
>>> s = spam()
>>> print hasattr(s, "action1")
True
>>> print hasattr(s, "action2")
True
The Boost.Python examples are fairly equivalent to the Python examples. In this snippet, the spam identifier is modified to point to a new type, as a new class_ instance was instantiated.
#include <boost/python.hpp>
class spam {};
void action1(spam& self) {}
void action2(spam& self) {}
BOOST_PYTHON_MODULE(example)
{
typedef boost::python::class_<spam> spam_class_type;
spam_class_type("spam")
.def("action1", &action1)
;
// Redefines spam type.
spam_class_type("spam")
.def("action2", &action1)
;
}
And its usage:
>>> import example
__main__:1: RuntimeWarning: to-Python converter for spam already
registered; second conversion method ignored.
>>> s = example.spam()
>>> print hasattr(s, "action1")
False
>>> print hasattr(s, "action2")
True
To extend the type in Boost.Python, one simply operates on the same class_ instance:
#include <boost/python.hpp>
class spam {};
void action1(spam& self) {}
void action2(spam& self) {}
BOOST_PYTHON_MODULE(example)
{
typedef boost::python::class_<spam> spam_class_type;
spam_class_type spam_ = spam_class_type("spam");
spam_
.def("action1", &action1)
;
// Extend spam type.
spam_
.def("action2", &action2)
;
}
And its usage:
>>> import example
>>> s = example.spam()
>>> print hasattr(s, "action1")
True
>>> print hasattr(s, "action2")
True

Related

pybind11 data type isn't matched for map, as an input argument for function

Data type:
std::map<platform::String, platform::String> ssmap;
Binding code:
dt.cpp (-> import dt)
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include "./ssmap.h"
PYBIND11_MAKE_OPAQUE(std::map<platform::String, platform::String>>)
void bind_string(py::module &m)
{
py::classplatform::String pyClass(m, "String);
pyClass.def(py::init<const std::String&>(), py::return_value_policy::move);
...
}
void bind_ssmap(py::module &m)
{
py::bind_map<platform::String, platform::String>>(m, "ssmap");
}
...
Then in another module, I'll use ssmap:
vp.cpp (import vp)
void bind_vp(py::module &m)
{
py::class pyClass(m, "vp", py::module_local());
pyClass.def("reset", &vp::reset, py::arg("val")); ---> val is type of ssmap
}
// test script:
import dt
import vp
val = dt.ssmap()
print("type of val is ", type(val))
str = dt.string("Hi")
val[str]=str
vp.reset(val) --> gave error
Errors: TypeError: reset(): incompatible function arguments. The following argument types are supported:
(self: vp, value: Dict[std::String, std::String]) -> None
If I checked the type of val, it shows:
type of val is : <class 'dt.ssmap'>
So why the input argument (val) is taken as Dict, but the ssmap is taken as class of ssmap (but not Dict), What is the right way to deal with this case?
Thanks for any suggestions!
You have to put PYBIND11_MAKE_OPAQUE(std::map<platform::String, platform::String>>) in vp.cpp as well, or at least in a common header. Otherwise when you bind reset the bindings will not be aware that this type is opaque.

can I use an interface for a property list?

I have an interface def
In order to use in many places, i understand I have to split it into its own file (at least with ES5 output). So:
//ICommand.ts>
interface RegExp {
$1: string;
$2: string;
$3: string;
// etc
}
interface IBotCommand {
regex: RegExp
// fixme - clearer def
// cmd: ():Output
cmd: any
}
export = IBotCommand;
//BotCommand.ts >
import ICommand = require("./ICommand");
class BotCommand {
commandList: ICommand
But this gives Error: cannot find name ICommand
Is this possible? What is the best syntax?
it seems this maybe down to my environment not recompiling these scripts.
also the RegExp definition is taken from here:
TypeScript and RegExp
and may not be fully functional
You are exporting the interface like this:
export = IBotCommand;
// but you are importing it with:
import ICommand = require('./ICommand');
With you export being the way it is, change your import to be:
import { IBotCommand } from './ICommand';
If you'd like to import it like this:
import ICommand from './ICommand';
then you will want to export it like this:
export default IBotCommand;
If you don't use default then you must use the object notation to reference your imports.
There is a caveat to the object notation, in that you could also do this:
import * as cmds from './ICommand';
// and use it like this:
class SomeClass implements cmds.IBotCommand {}

How can I export an interface that I have imported?

I am creating a library in typescript, which is spread across multiple files. I take all the classes and constants I have defines and import them into one module, which exports them all under one namespace. I have just defines an interface, and I wish to include it in the same namespace/module as all the other parts of my library. But apparently I can't.
Here's a simplified example:
/app.ts is the entry point of the application, all I do in it at the moment is include my library MyLib:
//app.ts
import myLib = require("lib/MyLib/MyLib"); // this works fine
/lib/MyLib/MyLib.ts is the file in which I import all of the things defined by MyLib, and export them together:
// lib/MyLib/MyLib.ts
import VehiclesImport = require("./transport/vehicles");
// error under VehiclesImport.IAutomobile, saying that VehiclesImport has no property IAutomobile
export var IAutomobile = VehiclesImport.IAutomobile;
export var Car = VehiclesImport.Car;
In /lib/MyLib/transport/vehicles.ts, I define several classes and interfaces of vehicles, here, I'll just show IAutomobile and Car:
// lib/MyLib/transport/vehicles.ts
export interface IAutomobile {
weight: number
}
export class Car implements IAutomobile {
weight = 3000
}
I have tried creating a class truck in MyLib.ts, which properly implements IAutomobile, and that works fine, without any error messages. The problem only seems to arise when I want to access IAutomobile outside of an 'implements' statement.
I apologize if this seems like a 'code dump', but in my opinion, this is a serious problem that I cannot access my interfaces except in a class declaration. I have searched Google for the past two hours and found nothing on the subject. Thanks for any help you can give me!
Edit: I understand that typescript interfaces are not part of the compiled javascript code, but that should not stop me from manipulating them within typescript.
Use the import keyword to bring in something into the type declaration space (as opposed to var which brings it into the variable declaration space).
This is demonstrated below. a.ts:
export interface A {
val: number;
}
To re-export this from another file b.ts:
import a = require('./a');
export import B = a.A; // Important use of import
Sample usage in some other file c.ts:
import b = require('./b');
var foo: b.B;
foo.val = 123;
interface C extends b.B {
val2:number;
}
var bar: C;
bar.val2 = 456;
The example rewritten following TS language specification:
a.ts:
export interface A {
val: number;
}
To re-export this from another file b.ts:
export {A} from './a'
Usage in some other file c.ts:
import {A} from './b'
var foo: A = {val: 2};
foo.val = 123;
interface C extends A {
val2:number;
}
var bar: C = {val: 1, val2: 3};
bar.val2 = 456;
Types can't be assigned to variables, they exist in different "declaration spaces". Classes can be assigned to variables, because they contribute their names to the type declaration space as well as defining the class objects. Interfaces only contribute to the types declaration space, so can't be referenced as values.
The language is a bit verbose, but this is spelt out in detail in section 2.3 of the language spec
foo.ts
export interface ITest {
...
}
bar.ts
import * as foo from "./foo";
export type ITest = foo.ITest;
This works to re-export types/interfaces
import type { MyInterface, MyType } from './randomModule';
export { MyInterface, MyType }
The key is the surrounding braces in the export statement. Works in TypeScript 4.7.4. Reference.
In TypeScript 3.9.6, this worked for me:
import { Foo as FooType } from './some-path';
export type Foo = FooType;

System Verilog: enum inside interface

I have an interface:
interface my_intf();
typedef enum logic [1:0] {
VAL_0 = 2'b00,
VAL_1 = 2'b01,
VAL_2 = 2'b10,
VAL_3 = 2'b11
} T_VAL;
T_VAL val;
endinterface
My module uses this interface:
my_intf intf;
The problem is to assign the val with a value from the enum.
I can assign it as:
intf.val = 0; (and receiving warning or error)
but not as:
intf.val=VAL_0;
Nor as
intf.val = my_intf.T_VAL.VAL_0
How I overcome that problem?
I have only dealt with packages for containing enums before, and avoid interfaces. This is how I use packages. Import the package before the module definition with which you want to use it:
import my_intf_pkg::* ;
module bla(
output my_val_t intf
);
initial begin
intf = VAL_0 ;
end
endmodule
The package containing enums might look like:
package my_intf_pkg;
typedef enum logic [1:0] {
VAL_0 = 2'b00,
VAL_1 = 2'b01,
VAL_2 = 2'b10,
VAL_3 = 2'b11
} my_val_t;
endpackage : my_intf_pkg
Note that the VAL_0 etc are global and not tied to the T_VAL typedef. Therefore I often make them a bit more unique including the typedef in the name. T_VAL_0 for T_VAL typedefs etc.
Here is an example on EDAplayground.
intf.val = 0; should be an error because you are trying to assign a integral type to an enum without a cast.
intf.val = VAL_0; is an error because VAL_0 is not defined in the current scope.
You should be able to do
intf.val = intf.VAL_0;
However, the best solution in to put shared types in a package, an import the package where needed.

How to parametrize my exports?

I'd like to be able to parametrize my exports not only with types (as in, generic exports), but also with values.
Something like:
class Greeter
{
readonly string _format;
public Greeter( string format ) { _format = format; }
public string Greet( string name ) { return string.Format( _format, name ); }
}
// ...
var e = new ExportProvider();
e.ExportParametrized<Greeter>( args: new[] { "Hi, {0}!" } );
e.ExportParametrized<Greeter>( args: new[] { "¡Hola, {0}!" } );
// And then:
[ImportMany] IEnumerable<Greeter> Greeters { get; set; }
foreach( var g in Greeters ) Console.WriteLine( g.Greet( "John" ) );
// Should print out:
// Hello, John!
// ¡Hola, John!
One might ask: why don't I simply export the value new Greeter( "Hello, {0}!" ) using ComposablePartExportProvider and CompositionBatch?
While this approach would work in this particular case, it has an important flaw: if the Greeter class had any imports of its own, they would not be satisfied.
The usual way I would go about this is to declare two classes - EnglishGreeter and SpanishGreeter, inherit them both from Greeter, and then provide the appropriate arguments in the call to base constructor.
But this doesn't work for two reasons:
This is a lot of noise to write. Not only do I have to type the whole shebang, I also have to come up with names for those classes, and it doesn't always make sense to have names. Not to mention the DRY principle. But even besides the noise...
Sometimes I don't know the parameters upfront. Say, for example, my greeting formats were coming from some kind of config file.
Here is another thought, to somewhat clarify what I'm looking for.
This problem is almost solved in the TypeCatalog. See, the TypeCatalog knows about the type and it calls the type's constructor to create the part on demand.
One can think of this process from another standpoint: the catalog has a factory function; using that function, it creates the part, then satisfies its non-prerequisite imports, and then returns the part back to the requestor.
Now, in the particular case of TypeCatalog, the factory function just happens to be the type's own constructor. If only I could hook in and replace the factory function with my own, but still leverage the rest of the machinery, that would be exactly what I'm looking for.
You can achieve this by using property exports. You could define a class specifically for those kinds of exports, and it will look like this:
class MyParameterizedExports
{
[Export(typeof(Greeter))]
private Greeter EnglishGreeter
{
get
{
Greeter g = new Greeter("Hi, {0}!");
container.SatisfyImportsOnce(g);
return g;
}
}
[Export(typeof(Greeter))]
private Greeter SpanishGreeter
{
get
{
Greeter g = new Greeter("¡Hola, {0}!");
container.SatisfyImportsOnce(g);
return g;
}
}
}
Here you export two separate Greeter instances without having to define a new class for each type of Greeter.