./PaxHeaders/Inline-Python-0.580000644000000000000000000000013215011105372013274 xustar0030 mtime=1747225338.983432339 30 atime=1747225338.908429576 30 ctime=1747225338.983432339 Inline-Python-0.58/0000755000076400001440000000000015011105372013052 5ustar00nineusersInline-Python-0.58/PaxHeaders/Makefile.pre.in0000644000000000000000000000013212460241150016046 xustar0030 mtime=1421951592.547048096 30 atime=1645882208.668094781 30 ctime=1747225338.909957156 Inline-Python-0.58/Makefile.pre.in0000644000076400001440000002371312460241150015712 0ustar00nineusers# Universal Unix Makefile for Python extensions # ============================================= # Short Instructions # ------------------ # 1. Build and install Python (1.5 or newer). # 2. "make -f Makefile.pre.in boot" # 3. "make" # You should now have a shared library. # Long Instructions # ----------------- # Build *and install* the basic Python 1.5 distribution. See the # Python README for instructions. (This version of Makefile.pre.in # only withs with Python 1.5, alpha 3 or newer.) # Create a file Setup.in for your extension. This file follows the # format of the Modules/Setup.dist file; see the instructions there. # For a simple module called "spam" on file "spammodule.c", it can # contain a single line: # spam spammodule.c # You can build as many modules as you want in the same directory -- # just have a separate line for each of them in the Setup.in file. # If you want to build your extension as a shared library, insert a # line containing just the string # *shared* # at the top of your Setup.in file. # Note that the build process copies Setup.in to Setup, and then works # with Setup. It doesn't overwrite Setup when Setup.in is changed, so # while you're in the process of debugging your Setup.in file, you may # want to edit Setup instead, and copy it back to Setup.in later. # (All this is done so you can distribute your extension easily and # someone else can select the modules they actually want to build by # commenting out lines in the Setup file, without editing the # original. Editing Setup is also used to specify nonstandard # locations for include or library files.) # Copy this file (Misc/Makefile.pre.in) to the directory containing # your extension. # Run "make -f Makefile.pre.in boot". This creates Makefile # (producing Makefile.pre and sedscript as intermediate files) and # config.c, incorporating the values for sys.prefix, sys.exec_prefix # and sys.version from the installed Python binary. For this to work, # the python binary must be on your path. If this fails, try # make -f Makefile.pre.in Makefile VERSION=1.5 installdir= # where is the prefix used to install Python for installdir # (and possibly similar for exec_installdir=). # Note: "make boot" implies "make clobber" -- it assumes that when you # bootstrap you may have changed platforms so it removes all previous # output files. # If you are building your extension as a shared library (your # Setup.in file starts with *shared*), run "make" or "make sharedmods" # to build the shared library files. If you are building a statically # linked Python binary (the only solution of your platform doesn't # support shared libraries, and sometimes handy if you want to # distribute or install the resulting Python binary), run "make # python". # Note: Each time you edit Makefile.pre.in or Setup, you must run # "make Makefile" before running "make". # Hint: if you want to use VPATH, you can start in an empty # subdirectory and say (e.g.): # make -f ../Makefile.pre.in boot srcdir=.. VPATH=.. # === Bootstrap variables (edited through "make boot") === # The prefix used by "make inclinstall libainstall" of core python installdir= /usr/local # The exec_prefix used by the same exec_installdir=$(installdir) # Source directory and VPATH in case you want to use VPATH. # (You will have to edit these two lines yourself -- there is no # automatic support as the Makefile is not generated by # config.status.) srcdir= . VPATH= . # === Variables that you may want to customize (rarely) === # (Static) build target TARGET= python # Installed python binary (used only by boot target) PYTHON= python # Add more -I and -D options here CFLAGS= $(OPT) -I$(INCLUDEPY) -I$(EXECINCLUDEPY) $(DEFS) # These two variables can be set in Setup to merge extensions. # See example[23]. BASELIB= BASESETUP= # === Variables set by makesetup === MODOBJS= _MODOBJS_ MODLIBS= _MODLIBS_ # === Definitions added by makesetup === # === Variables from configure (through sedscript) === VERSION= @VERSION@ CC= @CC@ LINKCC= @LINKCC@ SGI_ABI= @SGI_ABI@ OPT= @OPT@ LDFLAGS= @LDFLAGS@ LDLAST= @LDLAST@ DEFS= @DEFS@ LIBS= @LIBS@ LIBM= @LIBM@ LIBC= @LIBC@ RANLIB= @RANLIB@ MACHDEP= @MACHDEP@ SO= @SO@ LDSHARED= @LDSHARED@ CCSHARED= @CCSHARED@ LINKFORSHARED= @LINKFORSHARED@ CXX= @CXX@ # Install prefix for architecture-independent files prefix= /usr/local # Install prefix for architecture-dependent files exec_prefix= $(prefix) # Uncomment the following two lines for AIX #LINKCC= $(LIBPL)/makexp_aix $(LIBPL)/python.exp "" $(LIBRARY); $(PURIFY) $(CC) #LDSHARED= $(LIBPL)/ld_so_aix $(CC) -bI:$(LIBPL)/python.exp # === Fixed definitions === # Shell used by make (some versions default to the login shell, which is bad) SHELL= /bin/sh # Expanded directories BINDIR= $(exec_installdir)/bin LIBDIR= $(exec_prefix)/lib MANDIR= $(installdir)/man INCLUDEDIR= $(installdir)/include SCRIPTDIR= $(prefix)/lib # Detailed destination directories BINLIBDEST= $(LIBDIR)/python$(VERSION) LIBDEST= $(SCRIPTDIR)/python$(VERSION) INCLUDEPY= $(INCLUDEDIR)/python$(VERSION) EXECINCLUDEPY= $(exec_installdir)/include/python$(VERSION) LIBP= $(exec_installdir)/lib/python$(VERSION) DESTSHARED= $(BINLIBDEST)/site-packages LIBPL= $(LIBP)/config PYTHONLIBS= $(LIBPL)/libpython$(VERSION).a MAKESETUP= $(LIBPL)/makesetup MAKEFILE= $(LIBPL)/Makefile CONFIGC= $(LIBPL)/config.c CONFIGCIN= $(LIBPL)/config.c.in SETUP= $(LIBPL)/Setup.config $(LIBPL)/Setup.local $(LIBPL)/Setup SYSLIBS= $(LIBM) $(LIBC) ADDOBJS= $(LIBPL)/python.o config.o # Portable install script (configure doesn't always guess right) INSTALL= $(LIBPL)/install-sh -c # Shared libraries must be installed with executable mode on some systems; # rather than figuring out exactly which, we always give them executable mode. # Also, making them read-only seems to be a good idea... INSTALL_SHARED= ${INSTALL} -m 555 # === Fixed rules === # Default target. This builds shared libraries only default: sharedmods # Build everything all: static sharedmods # Build shared libraries from our extension modules sharedmods: $(SHAREDMODS) # Build a static Python binary containing our extension modules static: $(TARGET) $(TARGET): $(ADDOBJS) lib.a $(PYTHONLIBS) Makefile $(BASELIB) $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) \ $(ADDOBJS) lib.a $(PYTHONLIBS) \ $(LINKPATH) $(BASELIB) $(MODLIBS) $(LIBS) $(SYSLIBS) \ -o $(TARGET) $(LDLAST) install: sharedmods if test ! -d $(DESTSHARED) ; then \ mkdir $(DESTSHARED) ; else true ; fi -for i in X $(SHAREDMODS); do \ if test $$i != X; \ then $(INSTALL_SHARED) $$i $(DESTSHARED)/$$i; \ fi; \ done # Build the library containing our extension modules lib.a: $(MODOBJS) -rm -f lib.a ar cr lib.a $(MODOBJS) -$(RANLIB) lib.a # This runs makesetup *twice* to use the BASESETUP definition from Setup config.c Makefile: Makefile.pre Setup $(BASESETUP) $(MAKESETUP) $(MAKESETUP) \ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP) $(MAKE) -f Makefile do-it-again # Internal target to run makesetup for the second time do-it-again: $(MAKESETUP) \ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP) # Make config.o from the config.c created by makesetup config.o: config.c $(CC) $(CFLAGS) -c config.c # Setup is copied from Setup.in *only* if it doesn't yet exist Setup: cp $(srcdir)/Setup.in Setup # Make the intermediate Makefile.pre from Makefile.pre.in Makefile.pre: Makefile.pre.in sedscript sed -f sedscript $(srcdir)/Makefile.pre.in >Makefile.pre # Shortcuts to make the sed arguments on one line P=prefix E=exec_prefix H=Generated automatically from Makefile.pre.in by sedscript. L=LINKFORSHARED # Make the sed script used to create Makefile.pre from Makefile.pre.in sedscript: $(MAKEFILE) sed -n \ -e '1s/.*/1i\\/p' \ -e '2s%.*%# $H%p' \ -e '/^VERSION=/s/^VERSION=[ ]*\(.*\)/s%@VERSION[@]%\1%/p' \ -e '/^CC=/s/^CC=[ ]*\(.*\)/s%@CC[@]%\1%/p' \ -e '/^CXX=/s/^CXX=[ ]*\(.*\)/s%@CXX[@]%\1%/p' \ -e '/^LINKCC=/s/^LINKCC=[ ]*\(.*\)/s%@LINKCC[@]%\1%/p' \ -e '/^OPT=/s/^OPT=[ ]*\(.*\)/s%@OPT[@]%\1%/p' \ -e '/^LDFLAGS=/s/^LDFLAGS=[ ]*\(.*\)/s%@LDFLAGS[@]%\1%/p' \ -e '/^LDLAST=/s/^LDLAST=[ ]*\(.*\)/s%@LDLAST[@]%\1%/p' \ -e '/^DEFS=/s/^DEFS=[ ]*\(.*\)/s%@DEFS[@]%\1%/p' \ -e '/^LIBS=/s/^LIBS=[ ]*\(.*\)/s%@LIBS[@]%\1%/p' \ -e '/^LIBM=/s/^LIBM=[ ]*\(.*\)/s%@LIBM[@]%\1%/p' \ -e '/^LIBC=/s/^LIBC=[ ]*\(.*\)/s%@LIBC[@]%\1%/p' \ -e '/^RANLIB=/s/^RANLIB=[ ]*\(.*\)/s%@RANLIB[@]%\1%/p' \ -e '/^MACHDEP=/s/^MACHDEP=[ ]*\(.*\)/s%@MACHDEP[@]%\1%/p' \ -e '/^SO=/s/^SO=[ ]*\(.*\)/s%@SO[@]%\1%/p' \ -e '/^LDSHARED=/s/^LDSHARED=[ ]*\(.*\)/s%@LDSHARED[@]%\1%/p' \ -e '/^CCSHARED=/s/^CCSHARED=[ ]*\(.*\)/s%@CCSHARED[@]%\1%/p' \ -e '/^SGI_ABI=/s/^SGI_ABI=[ ]*\(.*\)/s%@SGI_ABI[@]%\1%/p' \ -e '/^$L=/s/^$L=[ ]*\(.*\)/s%@$L[@]%\1%/p' \ -e '/^$P=/s/^$P=\(.*\)/s%^$P=.*%$P=\1%/p' \ -e '/^$E=/s/^$E=\(.*\)/s%^$E=.*%$E=\1%/p' \ $(MAKEFILE) >sedscript echo "/^installdir=/s%=.*%= $(installdir)%" >>sedscript echo "/^exec_installdir=/s%=.*%=$(exec_installdir)%" >>sedscript echo "/^srcdir=/s%=.*%= $(srcdir)%" >>sedscript echo "/^VPATH=/s%=.*%= $(VPATH)%" >>sedscript echo "/^LINKPATH=/s%=.*%= $(LINKPATH)%" >>sedscript echo "/^BASELIB=/s%=.*%= $(BASELIB)%" >>sedscript echo "/^BASESETUP=/s%=.*%= $(BASESETUP)%" >>sedscript # Bootstrap target boot: clobber VERSION=`$(PYTHON) -c "import sys; print sys.version[:3]"`; \ installdir=`$(PYTHON) -c "import sys; print sys.prefix"`; \ exec_installdir=`$(PYTHON) -c "import sys; print sys.exec_prefix"`; \ $(MAKE) -f $(srcdir)/Makefile.pre.in VPATH=$(VPATH) srcdir=$(srcdir) \ VERSION=$$VERSION \ installdir=$$installdir \ exec_installdir=$$exec_installdir \ Makefile # Handy target to remove intermediate files and backups clean: -rm -f *.o *~ # Handy target to remove everything that is easily regenerated clobber: clean -rm -f *.a tags TAGS config.c Makefile.pre $(TARGET) sedscript -rm -f *.so *.sl so_locations # Handy target to remove everything you don't want to distribute distclean: clobber -rm -f Makefile Setup Inline-Python-0.58/PaxHeaders/t0000644000000000000000000000013015011105372013400 xustar0029 mtime=1747225338.91182982 30 atime=1747225338.909957156 29 ctime=1747225338.91182982 Inline-Python-0.58/t/0000755000076400001440000000000015011105372013315 5ustar00nineusersInline-Python-0.58/t/PaxHeaders/19testref.t0000644000000000000000000000013113760161763015510 xustar0029 mtime=1606476787.75938159 30 atime=1644320509.690584666 30 ctime=1747225338.910033222 Inline-Python-0.58/t/19testref.t0000644000076400001440000002556413760161763015363 0ustar00nineusersuse Test::Simple tests => 57; use strict; package Fart::Fiddle; sub new { my $class = shift || __PACKAGE__; $class = ref $class if ref $class; #print "Creating new ", __PACKAGE__, ": $class\n"; $::destroyed--; # warn $::destroyed; return bless {}, $class; } sub foo { my $self = shift; $self->{foo} = 'perl foo'; #warn $self->{foo}; return $self->{foo}; } sub b { return B->new; } sub DESTROY { my $self = shift; #warn "$self destroyed"; $::destroyed++; # warn $::destroyed; } sub more { my $self = shift; return ( $self->new, $self->new ); } sub more_ref { my $self = shift; return [ $self->new, $self->new ]; } sub more_hash { my $self = shift; return { a => $self->new, b => $self->new }; } sub bark { my $self = shift; return "bark: $self"; } sub pass_through { my $self = shift; return @_; } package main; sub named { my ($positional, $named) = @_; } use Inline Config => DIRECTORY => './blib_test'; use Inline::Python qw(py_eval py_call_function py_new_object); use Inline Python => < 0, 'obj.more gave values') for o in more: o.bark() def call_more_ref(obj): more = obj.more_ref() perl.ok(len(more) > 0, 'obj.more_ref gave values') for o in more: o.bark() def call_more_hash(obj): obj.more_hash() def call_method_params(obj, param): perl.ok(obj.pass_through(param) == param, 'got param back from pass_through') def call_method_param_array(obj): obj.pass_through([obj.new(), obj.new()]) def call_method_param_hash(obj): obj.pass_through({'a': obj.new(), 'b': obj.new()}) def test_exec(code, *args, **kwargs): try: exec(code, globals()) res = globals()['test_func'](*args, **kwargs) if res == sys.stdout: return "foo" return res except Exception: exc_type, e, exc_traceback = sys.exc_info() raise Exception(str(e) + ' at line ' + str(exc_traceback.tb_next.tb_lineno if exc_traceback.tb_next else exc_traceback.tb_lineno)) finally: try: del(test_func) except: pass def call_named(obj, foo): perl.named(obj, foo=foo) def py_obj_from_perl_obj(obj): return obj.b().foo() END our $destroyed = 1; sub check_destruction { $destroyed = 1; shift->(); return $destroyed == 1; } sub raise_cnt { $destroyed--; } sub lower_cnt { $destroyed++; } my $o; ok(check_destruction(sub { py_eval( <new) }), 'Perl object in Perl'); # this is more a test of check_destruction itself ok(check_destruction(sub { py_call_function('__main__', 'pass_through', Fart::Fiddle->new) }), 'pass_through in void context'); ok(check_destruction(sub { py_call_function('__main__', 'B') }), 'Python object constructor'); ok(check_destruction(sub { py_eval('B()', 0) }), 'Python object constructor in py_eval'); ok(check_destruction(sub { py_call_function('__main__', 'pass_through', B->new) }), 'pass_through of Python object in void context'); ok(check_destruction(sub { my $b = B->new; $b->foo(); py_call_function('__main__', 'swallow', $b) }), 'swallow of Python object'); ok(check_destruction(sub { my $b = B->new; py_call_function('__main__', 'py_obj_from_perl_obj', Fart::Fiddle->new) }), 'Python function gets a Python object from a Perl object'); ok(check_destruction(sub { my $o = py_call_function('__main__', 'pass_through', Fart::Fiddle->new); #warn $o; $o->foo; #warn "undefing"; undef $o; }), 'pass_through with return value'); #warn "swallow"; ok(check_destruction(sub { py_call_function('__main__', 'swallow', Fart::Fiddle->new) } ), 'swallow'); ok(check_destruction(sub { py_call_function('__main__', 'call_method', Fart::Fiddle->new) } ), 'call_method'); ok(check_destruction( sub { py_call_function('__main__', 'swallow', [Fart::Fiddle->new, Fart::Fiddle->new]) } ), 'swallow array ref'); ok(check_destruction( sub { py_call_function('__main__', 'call_methods', [Fart::Fiddle->new, Fart::Fiddle->new]) } ), 'call_methods on array ref'); ok(py_call_function('__main__', 'pass_through', 'foo') eq 'foo', 'simple string pass through'); ok(py_call_function('__main__', 'pass_through', 10) == 10, 'simple integer pass through'); ok(check_destruction( sub { my $list = py_call_function('__main__', 'give_list', Fart::Fiddle->new); my $foo = "$list"; # just to deref $foo = "@$list"; } ), 'Python list to perl'); ok(check_destruction( sub { my @list = py_call_function('__main__', 'give_list', Fart::Fiddle->new); my $foo = "@list"; } ), 'Python list to perl in list context'); ok(check_destruction( sub { my @foo = @{ py_call_function('__main__', 'give_list', Fart::Fiddle->new) }; ok(@foo == 2, 'list has two entries'); ok($foo[0], 'list value is there'); } ), 'Python list to perl dereferenced immediately'); ok(check_destruction( sub { my @array = py_call_function('__main__', 'give_array', Fart::Fiddle->new); my $foo = "@array"; } ), 'Python list to perl in list context'); ok(check_destruction( sub { my $foo = py_call_function('__main__', 'give_hash', Fart::Fiddle->new); ok(values %$foo == 2, 'hash has entries'); ok($foo->{a}, 'hash value is there'); } ), 'Python dict to perl'); ok(check_destruction( sub { my %foo = %{ py_call_function('__main__', 'give_hash', Fart::Fiddle->new) }; ok((values %foo == 2 and $foo{a}), 'hash values seem ok'); } ), 'Python dict to perl dereferenced immediately'); ok(check_destruction( sub { my $list = py_call_function('__main__', 'pass_through', [Fart::Fiddle->new, Fart::Fiddle->new]); ok(ref $list eq 'ARRAY', 'got array ref back from python'); ok((@$list == 2 and $list->[0] and $list->[1]), 'list still contains two elements'); $list->[0]->bark(); } ), 'pass_through of an array ref'); ok(check_destruction( sub { py_call_function('__main__', 'pass_through', [Fart::Fiddle->new, Fart::Fiddle->new]); } ), 'pass_through of an array ref'); my $a = py_new_object('A', '__main__', 'A'); ok($a->isa('Inline::Python::Object'), 'Python object created'); my $foo = $a->foo(); ok($foo eq 'foo', 'got foo from Python'); ok(check_destruction( sub { $a = py_new_object('A', '__main__', 'A', Fart::Fiddle->new); ok($a->isa('Inline::Python::Object'), 'Python object created with parameter'); $foo = $a->obj_foo(); ok($foo eq 'perl foo', 'got perl foo from Perl via Python'); $o = $a->obj(); ok($o->isa('Fart::Fiddle'), 'Perl object safely returned to perl'); undef $a; $o->foo(); undef $o; } ), 'Perl object destroyed after python object'); ok(check_destruction( sub { $a = py_new_object('A', '__main__', 'A', Fart::Fiddle->new); undef $a; } ), 'Perl object destroyed with python object'); $a = py_new_object('A', '__main__', 'A'); py_call_function('__main__', 'call_method', $a); ok(1, 'no segfault on call_method'); # no segfault in previous line ok(check_destruction( sub { py_call_function('__main__', 'call_more', Fart::Fiddle->new) } ), 'perl function returns list of objects to python'); ok(check_destruction( sub { py_call_function('__main__', 'call_more_ref', Fart::Fiddle->new) } ), 'perl function returns array of objects to python'); ok(check_destruction( sub { py_call_function('__main__', 'call_more_hash', Fart::Fiddle->new) } ), 'perl function returns hash of objects to python'); ok(check_destruction( sub { py_call_function('__main__', 'call_method_params', Fart::Fiddle->new, 'foo') } ), 'perl function with scalar params called from python'); ok(check_destruction( sub { py_call_function('__main__', 'call_method_params', Fart::Fiddle->new, Fart::Fiddle->new) } ), 'perl function with object params called from python'); ok(check_destruction( sub { py_call_function('__main__', 'call_method_param_array', Fart::Fiddle->new) } ), 'perl function with param array called from python'); ok(check_destruction( sub { py_call_function('__main__', 'call_method_param_hash', Fart::Fiddle->new) } ), 'perl function with param hash called from python'); ok(check_destruction( sub { my $obj = py_new_object('A', '__main__', 'A', [Fart::Fiddle->new, Fart::Fiddle->new]); my $list = $obj->obj(); ok((@$list == 2 and $list->[0]), 'array values look ok'); } ), 'method returned array ref'); my $test_func_p2 = <<'TEST_FUNC'; def test_func(context): foo = context['foo'] context['bar'] = foo.new() return foo TEST_FUNC my $test_func_p3 = <<'TEST_FUNC'; def test_func(context): foo = context['foo'] context['bar'] = foo.new() return foo TEST_FUNC if(PyVersion() == 2) { ok(check_destruction( sub { py_call_function('__main__', 'test_exec', $test_func_p2, {foo => Fart::Fiddle->new}) } ), "exec'ed and deleted function"); } else { ok(check_destruction( sub { py_call_function('__main__', 'test_exec', $test_func_p3, {foo => Fart::Fiddle->new}) } ), "exec'ed and deleted function"); } my $test_func = <<'TEST_FUNC'; def test_func(context): arr = [] def find_foo(obj, i): if i == 0: find_foo(obj, 1) arr.append(obj) find_foo(context, 0) return arr TEST_FUNC ok(check_destruction( sub { my @arr = py_call_function('__main__', 'test_exec', $test_func, Fart::Fiddle->new); py_call_function('gc', 'collect'); # Kick the GC. Otherwise the find_foo call frame would still reference arr } ), "exec'ed and deleted function"); ok(check_destruction( sub { call_named(Fart::Fiddle->new, Fart::Fiddle->new) }), 'Object passed as positional and named parameter deleted'); ok(check_destruction( sub { call_named(0, 0) }), 'Scalar passed as positional and named parameter deleted'); ok(check_destruction(sub { my $o; py_call_function('__main__', 'swallow', sub { $o = Fart::Fiddle->new }) } ), 'swallow perl sub with object ref'); ok(check_destruction(sub { my $b = B->new; py_call_function('__main__', 'swallow', sub { return $b }) }), 'swallow of Python object'); Inline-Python-0.58/t/PaxHeaders/22int.t0000644000000000000000000000013113760161763014620 xustar0029 mtime=1606476787.75938159 30 atime=1644320509.690584666 30 ctime=1747225338.910078328 Inline-Python-0.58/t/22int.t0000644000076400001440000000211313760161763014454 0ustar00nineusersuse Test; BEGIN { plan tests => 4 } use Inline Config => DIRECTORY => './blib_test'; use Inline::Python qw(py_call_function); use Inline Python => <<'END'; def get_int(): return 10 def test(i): return type(i) def PyVersion(): import sys; return sys.version_info[0] END ok(py_call_function('__main__', 'get_int'), 10, 'int arrives as int'); if (PyVersion() == 3) { ok(py_call_function('__main__', 'test', 4), "", 'int arrives as int'); ok(py_call_function('__main__', 'test', '4'), "", 'string that looks like a number arrives as string'); ok(py_call_function('__main__', 'test', py_call_function('__main__', 'get_int')), "", 'int from python to perl to python is still an int'); } else { ok(py_call_function('__main__', 'test', 4), "", 'int arrives as int'); ok(py_call_function('__main__', 'test', '4'), "", 'string that looks like a number arrives as string'); ok(py_call_function('__main__', 'test', py_call_function('__main__', 'get_int')), "", 'int from python to perl to python is still an int'); } Inline-Python-0.58/t/PaxHeaders/07nherit.t0000644000000000000000000000013212413163126015310 xustar0030 mtime=1412228694.304308305 30 atime=1645882208.784099059 30 ctime=1747225338.910129346 Inline-Python-0.58/t/07nherit.t0000644000076400001440000000236012413163126015147 0ustar00nineusersuse Test; BEGIN { plan tests => 5 } use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; class Daddy: def __init__(self): print("Who's your daddy?") self.fish = [] def push(self,dat): print("Daddy.push(%s)" % dat) return self.fish.append(dat) def pop(self): print("Daddy.pop()") return self.fish.pop() class Mommy: def __init__(self, s): print("Who's your mommy?") self.jello = s def add(self,data): self.jello = self.jello + data return self.jello def takeaway(self,data): self.jello = self.jello[0:-len(data)] return self.jello class Foo(Daddy,Mommy): def __init__(self, s): print("new Foo object being created") self.data = {} Daddy.__init__(self) Mommy.__init__(self, s) def get_data(self): return self.data def set_data(self,dat): self.data = dat END my $obj = new Foo("hello"); ok(not keys %{$obj->get_data()}); $obj->set_data({string => 'hello', number => 0.7574, array => [1, 2, 3], }); ok($obj->get_data()->{string}, "hello"); $obj->push(12); ok($obj->pop(), 12); ok($obj->add("wink"), "hellowink"); ok($obj->takeaway("fiddle"), "hel"); Inline-Python-0.58/t/PaxHeaders/01testpl.t0000644000000000000000000000013212413163126015324 xustar0030 mtime=1412228694.304308305 30 atime=1645882208.764098321 30 ctime=1747225338.910156718 Inline-Python-0.58/t/01testpl.t0000644000076400001440000000173512413163126015170 0ustar00nineusersuse Test; BEGIN { plan tests => 8 } use Inline Python => Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; def check_for_sub(sub): try: f = getattr(perl,sub) if type(f).__name__ == "_perl_sub": print("Sub %s exists!" % sub) return 1 else: print("%s is not a sub!" % sub) return 0 except AttributeError: print("Sub %s not found!" % sub) return 0 def get_sub(sub): if check_for_sub(sub): return getattr(perl,sub) else: raise AttributeError("No such sub") END ok(1); #loaded sub f { print "Hello from Perl\n"; ok(1); } use Inline::Python qw(py_eval); py_eval(< 5 } use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; class Daddy(object): def __init__(self): print("Who's your daddy?") self.fish = [] def push(self,dat): print("Daddy.push(%s)" % dat) return self.fish.append(dat) def pop(self): print("Daddy.pop()") return self.fish.pop() class Mommy: def __init__(self, s): print("Who's your mommy?") self.jello = s def add(self,data): self.jello = self.jello + data return self.jello def takeaway(self,data): self.jello = self.jello[0:-len(data)] return self.jello class Foo(Daddy,Mommy): def __init__(self, s): print("new Foo object being created") self.data = {} Daddy.__init__(self) Mommy.__init__(self, s) def get_data(self): return self.data def set_data(self,dat): self.data = dat END my $obj = new Foo("hello"); print "object is: ", ref($obj), "\n"; ok(not keys %{$obj->get_data()}); $obj->set_data({string => 'hello', number => 0.7574, array => [1, 2, 3], }); ok($obj->get_data()->{string}, "hello"); $obj->push(12); ok($obj->pop(), 12); ok($obj->add("wink"), "hellowink"); ok($obj->takeaway("fiddle"), "hel"); Inline-Python-0.58/t/PaxHeaders/34env.t0000644000000000000000000000013112515263363014615 xustar0030 mtime=1429563123.050858181 30 atime=1644320509.690584666 29 ctime=1747225338.91020436 Inline-Python-0.58/t/34env.t0000644000076400001440000000035012515263363014452 0ustar00nineusersuse Test::More; use Inline Python => < DIRECTORY => './blib_test'; BEGIN { print "1..1\n"; } use Inline Python => <<'END'; def JAxH(x): return "Just Another %s Hacker" % x END print "not " unless JAxH('Inline') eq "Just Another Inline Hacker"; print "ok 1\n"; Inline-Python-0.58/t/PaxHeaders/27pyattrs.t0000644000000000000000000000013212413163126015527 xustar0030 mtime=1412228694.315308427 30 atime=1645882208.744097584 30 ctime=1747225338.910249065 Inline-Python-0.58/t/27pyattrs.t0000644000076400001440000000274712413163126015377 0ustar00nineusersuse Test::More tests => 14; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; class Foo: def __init__(self): self.set_foo() def get_foo(self): return self.foo def set_foo(self): self.foo = 'foo' def __getattr__(self, attr): if attr == 'bar': return 'bar' raise AttributeError(attr) class KillMe: def __getattr__(self, attr): raise KeyError(attr) END my $foo = Foo->new(); is($foo->get_foo, 'foo', 'constructor worked'); is($foo->{foo}, 'foo', 'get attribute'); $foo->{foo} = 'bar'; is($foo->get_foo, 'bar', 'set attribute'); is($foo->{foo}, 'bar', 'get attribute after set attribute'); $foo->set_foo; is($foo->{foo}, 'foo', 'get attribute after Python object changes'); is($foo->{bar}, 'bar', '__getattr__ method also works'); is(Inline::Python::py_has_attr($foo, 'non_existing'), 0, 'py_has_attr returns 0 for non-existing attribute'); is(Inline::Python::py_has_attr($foo, 'foo'), 1, 'py_has_attr returns 1 for existing attribute'); ok(not(eval { $foo->{non_existing} }), 'Surviving accessing a non existent attribute'); ok(Inline::Python::py_get_attr($foo, 'get_foo'), 'Can access methods via py_get_attr'); ok($foo->{get_foo}, 'Can access methods as attributes'); is($foo->{get_foo}->(), 'foo', 'Returned method works'); my $killer = KillMe->new(); ok(not(eval { $killer->{foo} }), 'survived KeyError in __getattr__'); like($@, qr/KeyError: 'foo' at line 19/, 'Got the KeyError'); Inline-Python-0.58/t/PaxHeaders/29named_params.t0000644000000000000000000000013111346473347016466 xustar0030 mtime=1268414183.937078033 30 atime=1645882208.740097436 29 ctime=1747225338.91042965 Inline-Python-0.58/t/29named_params.t0000644000076400001440000000167111346473347016332 0ustar00nineusersuse Test::More tests => 5; use Inline Config => DIRECTORY => './blib_test'; our $fiddles = 0; use Inline Python => <new; call_method(Named->new, $fiddle); is($fiddle->foo, 'foo'); } is($fiddles, 0, 'objects got destroyed'); package Named; sub new { return bless {}; } sub meth { my ($self, $x, $a, $b) = @_; if (ref $x and ref $x eq 'ARRAY' and ref $a and ref $a eq 'HASH') { my $params = $a; foreach (qw( x a b )) { last unless @$x; $params->{$_} = shift @$x; } return $a->{b}; } else { return $b; } } package Fart::Fiddle; sub new { $::fiddles++; return bless {}; } sub foo { return 'foo'; } sub DESTROY { my $self = shift; $::fiddles--; } Inline-Python-0.58/t/PaxHeaders/cmp.t0000644000000000000000000000013212415322646014435 xustar0030 mtime=1412801958.514690258 30 atime=1645882208.728096993 30 ctime=1747225338.910634873 Inline-Python-0.58/t/cmp.t0000644000076400001440000000214312415322646014273 0ustar00nineuserspackage Comparer; sub new { my ($class, $value) = @_; return bless \$value; } sub __cmp__ { my ($self, $other) = @_; return $$self cmp $$other; } sub __eq__ { my ($self, $other) = @_; return $$self cmp $$other; } package FailComparer; sub new { my ($class, $value) = @_; return bless \$value; } sub __cmp__ { my ($self, $other) = @_; return 'foo'; } sub __eq__ { my ($self, $other) = @_; return 'foo'; } package main; use Test::More; use Data::Dumper; use Inline Config => DIRECTORY => './blib_test'; BEGIN { plan tests => 7 } use Inline::Python qw(py_eval py_call_function); py_eval(<<'END'); def test(foo1, foo2, bar): perl.ok(foo1 == foo1); perl.ok(foo2 == foo2); perl.ok(bar == bar); perl.ok(foo1 == foo2, 'foo1 == foo2'); perl.ok(foo1 != bar); perl.ok(foo2 != bar); def test_fail(o1, o2): o1 == o2 END py_call_function("__main__", "test", map { Comparer->new($_) } qw(foo foo bar)); eval { py_call_function("__main__", "test_fail", map { FailComparer->new($_) } qw(foo foo)); }; like($@, qr/__ must return an integer!/); Inline-Python-0.58/t/PaxHeaders/09bind.t0000644000000000000000000000013212413163126014735 xustar0030 mtime=1412228694.304308305 30 atime=1645882208.708096256 30 ctime=1747225338.910743261 Inline-Python-0.58/t/09bind.t0000644000076400001440000000251012413163126014571 0ustar00nineusersuse Test; BEGIN { plan tests => 6 } use Data::Dumper; use Inline::Python qw(py_bind_class py_bind_func py_eval ); py_eval <put("neil", { is => 'cool', was => 'stupid' }), undef); ok($o->get("foobar"), undef); my $r = $o->get("neil"); ok($r->{is}, 'cool'); ok($r->{was}, 'stupid'); Inline-Python-0.58/t/PaxHeaders/02testpl.t0000644000000000000000000000013213117703544015333 xustar0030 mtime=1497335652.523956876 30 atime=1644320509.690584666 30 ctime=1747225338.910770884 Inline-Python-0.58/t/02testpl.t0000644000076400001440000000164713117703544015201 0ustar00nineusersuse Test; BEGIN { plan tests => 9 } package Fart::Fiddle; sub new { my $class = shift || __PACKAGE__; print "Creating new ", __PACKAGE__, ": $class\n"; return bless {}, $class; } sub foof { my $o = shift; print Data::Dumper::Dumper("Fiddle->foof(", @_, ") called!"); main::ok(1); } package main; use Data::Dumper; use Inline Config => DIRECTORY => './blib_test'; use Inline::Python qw(py_eval); use Inline Python => < 9 } use Data::Dumper; use Inline::Python qw(py_eval py_new_object py_call_method ); py_eval <new('__main__', 'Foo'); ok($o->put("neil", { is => 'cool', was => 'stupid' }), undef); ok($o->get("foobar"), undef); my $r = $o->get("neil"); ok($r->{is}, 'cool'); ok($r->{was}, 'stupid'); #============================================================================ # Or, we can use the direct-version: py_new_object takes a Perl package to # bless the result into, then the same arguments as Inline::Python::Object. #============================================================================ $o = py_new_object('main::Quack', '__main__', 'Foo'); ok(py_call_method($o, 'put', "neil", { is => 'cool', was => 'stupid' }), undef); ok(py_call_method($o, 'get', "foobar"), undef); $r = py_call_method($o, 'get', "neil"); ok($r->{is}, 'cool'); ok($r->{was}, 'stupid'); Inline-Python-0.58/t/PaxHeaders/36utfstring.t0000644000000000000000000000013113760161763016060 xustar0029 mtime=1606476787.75938159 30 atime=1644320509.690584666 30 ctime=1747225338.910844855 Inline-Python-0.58/t/36utfstring.t0000644000076400001440000000056613760161763015726 0ustar00nineusersuse strict; use warnings; use utf8; use Test::More tests => 2; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; def add_x(string): return 'x' + string END my $str_utf8 = 'abć'; my $str_ascii = 'abc'; is add_x($str_utf8), "x$str_utf8", 'string op on unicode string'; is add_x($str_ascii), "x$str_ascii", 'string op on ascii string'; Inline-Python-0.58/t/PaxHeaders/35dictunicodememleak.t0000644000000000000000000000013214416227476017664 xustar0030 mtime=1681469246.119145284 30 atime=1681469246.119145284 30 ctime=1747225338.910870755 Inline-Python-0.58/t/35dictunicodememleak.t0000644000076400001440000000277714416227476017537 0ustar00nineusers# # Returning Python dictionaries with 'unicode' keys might lead to memory leaks. # This test creates a memory leak situation and verifies that RSS usage is normal. # use strict; use warnings; use Test::More; eval { require Proc::ProcessTable; require Test::Deep; }; plan skip_all => "Test requires Proc::ProcessTable and Test::Deep: $@" if $@; plan skip_all => "Process rss information not supported by Proc::ProcessTable on Windows" if $^O eq "MSWin32"; plan tests => 2; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; def python_dict_with_unicode_key(): return { u'abcdefghijklmno': 1, u'pqrstuvwxyz': 2, } END sub get_rss_memory { my $pt = Proc::ProcessTable->new; my %info = map { $_->pid => $_ } @{ $pt->table }; my $rss = $info{ $$ }->rss; if ($^O eq 'darwin') { # RSS is reported in kilobytes instead of bytes on OS X $rss *= 1024; } return $rss; } my $iterations = 3_000_000; my $rss_before_iterations = get_rss_memory(); # print STDERR "RSS before python_dict_with_unicode_key(): $rss_before_iterations\n"; my $dict; for (my $x = 0; $x < $iterations; ++$x) { $dict = python_dict_with_unicode_key(); } my $rss_after_iterations = get_rss_memory(); # print STDERR "RSS after python_dict_with_unicode_key(): $rss_after_iterations\n"; ok( $rss_after_iterations - $rss_before_iterations < 100 * 1024 * 1024, "RSS takes up less than 100 MB" ); Test::Deep::cmp_deeply( $dict, { 'abcdefghijklmno' => 1, 'pqrstuvwxyz' => 2 } ); Inline-Python-0.58/t/PaxHeaders/04func.t0000644000000000000000000000013212413163126014747 xustar0030 mtime=1412228694.304308305 30 atime=1645882208.832100829 30 ctime=1747225338.910894751 Inline-Python-0.58/t/04func.t0000644000076400001440000000102612413163126014604 0ustar00nineusersuse Test; use Data::Dumper; use Inline Config => DIRECTORY => './blib_test'; BEGIN { plan tests => 3 } use Inline::Python qw(py_eval py_call_function); ok(py_eval("print('Hello from Python!')"), undef); py_eval(<<'END'); class Foo: def __init__(self): print("Foo() created!") def apple(self): print("Doing an apple!") def funky(a): print(a) END ok(py_call_function("__main__","funky",{neil=>'happy'}), undef); my $o = py_call_function("__main__","Foo"); ok($o->apple, undef); print Dumper $o; print Dumper $o->apple; Inline-Python-0.58/t/PaxHeaders/25py_sub.t0000644000000000000000000000013113115501114015310 xustar0029 mtime=1496744524.04809341 30 atime=1644320509.690584666 30 ctime=1747225338.910917915 Inline-Python-0.58/t/25py_sub.t0000644000076400001440000000363113115501114015152 0ustar00nineusersuse Test::More tests => 17; use Data::Dumper; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <(), 'hello Python'); ok($sub = get_sub_with_arg(), 'Got a sub ref for a sub with arguments'); is($sub->('hello Python'), 'hello Python'); is(len_array->(), 0); ok(call_perl_sub(bless {}, 'Foo'), 'Could call Perl sub from Python'); ok($sub = get_sub_from_perl(bless {}, 'Foo'), 'Got a reference to a Perl method'); ok($sub->(), 'Perl sub got passed through successfully'); ok($sub = getattr_sub_from_perl(bless {}, 'Foo'), 'Got a reference to a Perl method via getattr'); ok($sub->(), 'Perl sub got passed through getattr successfully'); is(call_perl_object(bless {}, 'Foo'), 1, 'Calling Perl object works'); ok(pass_through(sub { return 1; }), 'Pass through of perl sub ref works'); ok(call_perl_sub(bless {}, 'Bar'), 'Call inherited Perl method via getattr'); ok($sub = getattr_sub_from_perl(bless {}, 'Bar'), 'Got a reference to an inherited Perl method via getattr'); ok($sub->(), 'Inherited Perl method got passed through getattr successfully'); my $py_foo = PyFoo->new; ok(my $method = $py_foo->get_method); is($method->(), 'foo', 'Reference to Python method works'); package Foo; use overload '&{}' => sub { return \&testsub }; sub testsub { return 1; } package Bar; use base qw(Foo); Inline-Python-0.58/t/PaxHeaders/06dict.t0000644000000000000000000000013213007042021014727 xustar0030 mtime=1478247441.132563769 30 atime=1645882208.736097289 30 ctime=1747225338.910941079 Inline-Python-0.58/t/06dict.t0000644000076400001440000000260513007042021014570 0ustar00nineusersuse strict; use warnings; use utf8; use Test::More tests => 6; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; # coding=utf-8 def PyVersion(): import sys; return sys.version_info[0] class Foo: def __init__(self): print("new Foo object being created") self.data = {} def get_data(self): return self.data def set_data(self,dat): self.data = dat if PyVersion() == 3: self.data['ü'] = 'ü' else: # u'ü' is not a valid syntax in Py3.1 s = '\xc3\xbc'.decode('utf-8') self.data[s] = s def get_dict(): if PyVersion() == 3: return {'föö': 'bar'} else: # u'föö' is not a valid syntax in Py3.1 return {'f\xc3\xb6\xc3\xb6'.decode('utf-8'): 'bar'} def access_dict(test_dict): if PyVersion() == 3: return test_dict['föö'] else: # u'föö' is not a valid syntax in Py3.1 return test_dict['f\xc3\xb6\xc3\xb6'.decode('utf-8')] END my $obj = new Foo; ok(not keys %{$obj->get_data()}); $obj->set_data({string => 'hello', number => 0.7574, array => [1, 2, 3], ütf8 => 'töst', }); is($obj->get_data()->{string}, 'hello'); is($obj->get_data()->{ütf8}, 'töst'); is($obj->get_data()->{ü}, 'ü'); is(access_dict({föö => 'bar'}), 'bar'); my $dict = get_dict(); is(access_dict($dict), 'bar'); Inline-Python-0.58/t/PaxHeaders/17once.t0000644000000000000000000000013211431442566014753 xustar0030 mtime=1281770870.641312959 30 atime=1645882208.772098616 30 ctime=1747225338.910965356 Inline-Python-0.58/t/17once.t0000644000076400001440000000107111431442566014610 0ustar00nineusersuse Test; BEGIN { plan tests => 1 } # Need to define the subs BEFORE the 'use Inline' statement, since the # Python code will run them. my $build_stage; my $load_stage; sub login { $build_stage ? $load_stage++ : $build_stage++; } use Inline Config => DIRECTORY => './blib_test'; use Inline Python; die "Error -- code was run both in build and load stages!" if $build_stage && $load_stage; ok(1); __END__ __Python__ # Put some code in the 'main' section -- it will be run during # Inline's "build" phase, but NOT run again in the "load" phase. perl.login(); Inline-Python-0.58/t/PaxHeaders/23getattr.t0000644000000000000000000000013012413163126015465 xustar0030 mtime=1412228694.305308316 29 atime=1645882208.82810068 29 ctime=1747225338.91098864 Inline-Python-0.58/t/23getattr.t0000644000076400001440000000163112413163126015326 0ustar00nineuserspackage Attrs; sub new { return bless { test => 'Attrs test!', }; } sub __getattr__ { my ($self, $attr) = @_; return unless exists $self->{$attr}; return $self->{$attr}; } package NoAttrs; sub new { return bless { test => 'NoAttrs test!', }; } package main; use Test; use Data::Dumper; use Inline Config => DIRECTORY => './blib_test'; BEGIN { plan tests => 6 } use Inline::Python qw(py_eval py_call_function); py_eval(<<'END'); def test_attrs(foo, s): perl.ok(hasattr(foo, 'test')) perl.ok(not hasattr(foo, 'foo')) perl.ok(foo.test == s) perl.ok(foo.__getattr__('test') == s) def test_noattrs(bar): try: perl.warn(bar.test) except AttributeError: return 1 return 0 END ok(py_call_function("__main__", "test_attrs", Attrs->new, 'Attrs test!'), undef); ok(py_call_function("__main__", "test_noattrs", NoAttrs->new) == 1); Inline-Python-0.58/t/PaxHeaders/03parse.t0000644000000000000000000000013212413163126015125 xustar0030 mtime=1412228694.304308305 30 atime=1645882208.840101124 30 ctime=1747225338.911066449 Inline-Python-0.58/t/03parse.t0000644000076400001440000000130012413163126014755 0ustar00nineusersuse Test::More; eval { require Parse::RecDescent; }; plan skip_all => "Test requires Parse::RecDescent: $@" if $@; plan tests => 5; sub ok_is { # Python does not allow "is" as method name &is; } use Inline::Python qw(py_eval); py_eval(<<'END'); perl.ok_is(1, 1) # Well, we got this far... perl.use("Data::Dumper") perl.use("Parse::RecDescent") perl.eval('print "Hello\n"') print(perl.Data.Dumper.Dumper({'neil': 'happy', 'others': 'sad'})) o = perl.Parse.RecDescent.new("Parse::RecDescent","dumb: 'd' 'u' 'm' 'b'") perl.ok_is(o.dumb("dumb"), 'b') perl.ok_is(o.dumb("dork"), None) END $o = Parse::RecDescent->new("dumb: 'd' 'u' 'm' 'b'"); is($o->dumb("dork"), undef); is($o->dumb("dumb"), 'b'); Inline-Python-0.58/t/PaxHeaders/21arrayref.t0000644000000000000000000000013213141072525015627 xustar0030 mtime=1501853013.758278085 30 atime=1644320509.690584666 30 ctime=1747225338.911335204 Inline-Python-0.58/t/21arrayref.t0000644000076400001440000000334713141072525015474 0ustar00nineusersuse Test::More tests => 19; use Test::Number::Delta; use Inline Config => DIRECTORY => './blib_test'; use Inline::Python qw(py_call_function py_is_tuple); use Inline Python => <<'END'; def return_empty_array(): return [] def return_onesized_array(): return [1] def bounce_array(a): return a def perl_list(a): return a.list(); def len_perl_list(a): return len(a.list()) def len_perl_array(a): return len(a.array()) def len_empty_perl_array(a): return len(a.empty_array()) def return_tuple(): return (1, 2, 3) END my $a = py_call_function('__main__', 'return_empty_array'); ok(ref $a eq 'ARRAY'); ok(@$a == 0, 'emtpy array ref -> empty list'); my @a = py_call_function('__main__', 'return_empty_array'); ok(@a == 0); ok(ref scalar py_call_function('__main__', 'return_onesized_array') eq 'ARRAY'); @a = py_call_function('__main__', 'return_onesized_array'); ok(@a == 1); ok(ref scalar py_call_function('__main__', 'bounce_array', [Foo->new]) eq 'ARRAY'); @a = py_call_function('__main__', 'bounce_array', [Foo->new]); ok(@a == 1); is((bounce_array([1, 2, 3]))[2], 3); is((perl_list(Foo->new))[2], 3); is(len_perl_list(Foo->new), 3); is(len_perl_array(Foo->new), 3); is(len_empty_perl_array(Foo->new), 0); my @b = (0.1,0.2,0.3,0.4); delta_ok((bounce_array(\@b))[0], 0.1); map($b[$_]+$b[$_], 0..$#b); delta_ok((bounce_array(\@b))[1], 0.2); is(ref return_tuple(), 'ARRAY'); is(scalar @{ return_tuple() }, 3); is(py_is_tuple(scalar return_empty_array()), 0); is(py_is_tuple(scalar return_tuple()), 1); is(py_is_tuple(scalar bounce_array(scalar return_tuple())), 1); package Foo; sub new { return bless {}; } sub list { return (1, 2, 3); } sub array { return [1, 2, 3]; } sub empty_array { return []; } Inline-Python-0.58/t/PaxHeaders/24getitem.t0000644000000000000000000000013212413163126015454 xustar0030 mtime=1412228694.315308427 30 atime=1645882208.752097878 30 ctime=1747225338.911361845 Inline-Python-0.58/t/24getitem.t0000644000076400001440000000147412413163126015320 0ustar00nineuserspackage Items; sub new { return bless { test => 'Items test!', }; } sub __getitem__ { my ($self, $item) = @_; return unless exists $self->{$item}; return $self->{$item}; } package NoItems; sub new { return bless { test => 'NoItems test!', }; } package main; use Test; use Data::Dumper; use Inline Config => DIRECTORY => './blib_test'; BEGIN { plan tests => 4 } use Inline::Python qw(py_eval py_call_function); py_eval(<<'END'); def test_items(foo, s): perl.ok(foo['test'] == s) perl.ok(foo['test'] == s) def test_noitems(bar): try: bar['test'] except TypeError: return 1 return 0 END ok(py_call_function("__main__", "test_items", Items->new, 'Items test!'), undef); ok(py_call_function("__main__", "test_noitems", NoItems->new) == 1); Inline-Python-0.58/t/PaxHeaders/30floats.t0000644000000000000000000000013113141073101015272 xustar0030 mtime=1501853249.566517598 30 atime=1644320509.690584666 29 ctime=1747225338.91142219 Inline-Python-0.58/t/30floats.t0000644000076400001440000000215613141073101015135 0ustar00nineusersuse strict; use warnings; use Inline Config => DIRECTORY => './blib_test'; use Test::More tests => 7; use Test::Number::Delta; use POSIX qw(setlocale LC_NUMERIC); use Inline Python => < 11 } use Data::Dumper; use Inline::Python qw(eval_python); #============================================================================ # Pass code directly #============================================================================ ok(not defined eval_python("1 + 2")); ok( defined eval_python("1 + 2", 0)); ok(not defined eval_python("1 + 2", 1)); ok(not defined eval_python("1 + 2", 2)); # Set up a function and class eval_python(< DIRECTORY => './blib_test'; use Test::More tests => 16; use Inline Python => <isa('Inline::Python::Boolean'), 'Got a Boolean object for True'); ok(is_boolean(get_true()), 'True got passed as Boolean through perl space'); ok(is_boolean(get_false()), 'False got passed as Boolean through perl space'); ok(values_are_boolean(get_hash_with_bools()), 'True and False work as dict values'); SKIP: { skip 'JSON module required for JSON interop tests', 2 unless eval { require JSON; }; is JSON::to_json([get_true()], {convert_blessed => 1}), '[true]'; is JSON::to_json([get_false()], {convert_blessed => 1}), '[false]'; } Inline-Python-0.58/t/PaxHeaders/33reinit.t0000644000000000000000000000013212475267552015330 xustar0030 mtime=1425370986.509161354 30 atime=1644320509.690584666 30 ctime=1747225338.911518284 Inline-Python-0.58/t/33reinit.t0000644000076400001440000000030212475267552015161 0ustar00nineusersuse Test; BEGIN { plan tests => 10 } use Inline::Python qw(); for (1 .. 10) { Inline::Python::py_finalize; Inline::Python::py_initialize; ok(Inline::Python::py_eval("True", 0)); } Inline-Python-0.58/t/PaxHeaders/28exception.t0000644000000000000000000000013212540623062016021 xustar0030 mtime=1434658354.044090029 30 atime=1644320509.690584666 30 ctime=1747225338.911543632 Inline-Python-0.58/t/28exception.t0000644000076400001440000000261512540623062015663 0ustar00nineusersuse strict; use warnings; use Test::More tests => 9; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <new; eval { $foo->error; }; like($@, qr/Exception: Error! at line 15/, 'Exception found'); eval { thrower()->(); }; like($@, qr/name 'foo' is not defined at line 18/, 'Exception found'); my $exception = catch_perl_exception(sub { die "fail!"; }); like($exception, qr/fail!/); eval { pass_through_perl_exception(sub { die "fail!"; }); }; like($@, qr/fail!/); my $foo_exception = bless {}, 'FooException'; eval { pass_through_perl_exception(sub { die $foo_exception; }); }; is(ref $@, 'FooException'); Inline-Python-0.58/t/PaxHeaders/15anon.t0000644000000000000000000000013012413163126014747 xustar0030 mtime=1412228694.305308316 30 atime=1645882208.820100386 28 ctime=1747225338.9116052 Inline-Python-0.58/t/15anon.t0000644000076400001440000000054412413163126014612 0ustar00nineusersuse Test; BEGIN { plan tests => 2 } use Inline Config => DIRECTORY => './blib_test'; use Inline PYTHON; $o = Foo(); ok(defined $o); ok($o->method("Python"), 42); __END__ __PYTHON__ def Foo(): class Bar: def __init__(self): pass def method(self, lang): print("Note: lang=%s" % lang) return 42 return Bar() Inline-Python-0.58/t/PaxHeaders/11factor.t0000644000000000000000000000013211326320221015261 xustar0030 mtime=1264165009.015794598 30 atime=1645882208.796099501 30 ctime=1747225338.911628956 Inline-Python-0.58/t/11factor.t0000644000076400001440000000166711326320221015131 0ustar00nineusersuse Test; BEGIN { plan tests => 133 } use Config; use Inline Config => DIRECTORY => './blib_test'; use Inline Python; my $ovfl = $Config{intsize} <= 4 ? "Integer too large for architecture" : 0; sub fact { my $num = shift; my $skip = shift || 0; return fact_help($num, 1, $skip); } # OK on 32- and 64-bit machines. ok(fact(1), 1); ok(fact(2), 2); ok(fact(3), 6); ok(fact(4), 24); ok(fact(5), 120); ok(fact(6), 720); ok(fact(7), 5040); ok(fact(8), 40320); ok(fact(9), 362880); ok(fact(10), 3628800); # These ones tip the scales on 32-bit machines. skip($ovfl, fact(11, $ovfl), 39916800); skip($ovfl, fact(12, $ovfl), 479001600); skip($ovfl, fact(13, $ovfl), 6227020800); skip($ovfl, fact(14, $ovfl), 87178291200); __END__ __Python__ def fact_help(num, sofar, skip): perl.skip(skip, "skip") if num == 0: return sofar if skip: return fact_help(num-1, num, skip) # don't multiply return fact_help(num-1, num*sofar, skip) Inline-Python-0.58/t/PaxHeaders/12evnodd.t0000644000000000000000000000013111326320221015262 xustar0030 mtime=1264165009.015794598 29 atime=1645882208.73209714 30 ctime=1747225338.911670846 Inline-Python-0.58/t/12evnodd.t0000644000076400001440000000063411326320221015124 0ustar00nineusersuse Test; BEGIN { plan tests => 150 } use Inline Config => DIRECTORY => './blib_test'; use Inline Python; sub even { my $n = shift; return $n == 0 ? 1 : odd($n-1); } for (my $i=0; $i<75; $i++) { my $r = $i % 2; ok(odd($i), $r); ok(even($i), 1 - $r); } __END__ __Python__ # Need to explicitly import Perl function even = perl.even def odd(n): if n == 0: return 0 return even(n-1) Inline-Python-0.58/t/PaxHeaders/00init.t0000644000000000000000000000013214416227476014771 xustar0030 mtime=1681469246.119145284 30 atime=1681469246.119145284 30 ctime=1747225338.911694742 Inline-Python-0.58/t/00init.t0000644000076400001440000000034014416227476014624 0ustar00nineusersBEGIN { print "1..1\n"; } use File::Path; rmtree("./blib_test"); sleep(1) if($^O eq 'MSWin32'); # workaround for dubious behavior on Windows... mkdir("./blib_test", 0777) or print "not ok 1\n" && exit; print "ok 1\n"; Inline-Python-0.58/t/PaxHeaders/31stringification.t0000644000000000000000000000013213114233046017206 xustar0030 mtime=1496397350.567288399 30 atime=1644320509.690584666 30 ctime=1747225338.911719118 Inline-Python-0.58/t/31stringification.t0000644000076400001440000000123213114233046017042 0ustar00nineusersuse strict; use warnings; use Inline Config => DIRECTORY => './blib_test'; use Test::More tests => 3; use Inline Python => <new('foo'); my $nostring = NoString->new('foo'); is("$stringify", 'foo'); like("$nostring", qr/NoString/); is(stringify(bless {}, 'Foo'), 'stringified', 'overloaded stringification of Perl objects works'); package Foo; use overload '""' => sub { return "stringified" }; Inline-Python-0.58/t/PaxHeaders/14study.t0000644000000000000000000000013211326320221015156 xustar0030 mtime=1264165009.015794598 30 atime=1645882208.748097731 30 ctime=1747225338.911742553 Inline-Python-0.58/t/14study.t0000644000076400001440000000162411326320221015017 0ustar00nineusersuse Test; BEGIN { plan tests => 14 } use Inline::Python qw(py_eval py_study_package); py_eval(< 277 } use Inline::Python qw(py_eval py_bind_func); # Bind __main__.fibb to main::fibb py_bind_func("main::fibb", "__main__", "fibb"); # And fill in the gap: py_eval(< 6 } use Inline::Python qw(py_eval py_call_function); py_eval(<put(foo => 'bar'); ok($bar->get('foo') eq 'bar'); Inline-Python-0.58/t/PaxHeaders/26undef.t0000644000000000000000000000013013760161763015132 xustar0029 mtime=1606476787.75938159 30 atime=1644320509.690584666 29 ctime=1747225338.91182982 Inline-Python-0.58/t/26undef.t0000644000076400001440000000044113760161763014771 0ustar00nineusersuse Test::Simple tests => 2; use strict; use warnings; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; def debug(x): return str(x) END my @a = ('foo' , 'bar', 'baz'); delete $a[1]; ok(debug(undef) eq 'None'); ok(debug(\@a) eq "['foo', None, 'baz']"); Inline-Python-0.58/t/PaxHeaders/20unicode.t0000644000000000000000000000013212415322646015446 xustar0030 mtime=1412801958.513690247 30 atime=1645882208.772098616 30 ctime=1747225338.911853235 Inline-Python-0.58/t/20unicode.t0000644000076400001440000000207612415322646015311 0ustar00nineusersuse Test::More; use strict; use warnings; use utf8; eval { require 5.008; }; plan skip_all => 'Perl 5.8 required for UTF8 tests' if $@; plan tests => 5; use Inline Config => DIRECTORY => './blib_test'; use Inline Python => <<'END'; def PyVersion(): import sys; return sys.version_info[0] def string(): return "Hello" def pass_through(a): return a if PyVersion() < 3: from types import StringType, UnicodeType def u_string(): return eval("u'Hello'") def is_unicode(a): return isinstance(a, UnicodeType) def unicode_string(): return eval("u'a'") else: def b_string(): return eval("b'Hello'") END ok(string() eq 'Hello'); ok(pass_through('ö') eq 'ö', 'utf8ness retained'); if(PyVersion() < 3) { ok(u_string() eq 'Hello'); ok(is_unicode('ö'), 'perl utf8 -> python unicode'); ok(utf8::is_utf8(unicode_string()), 'python unicode -> perl utf8'); } else { ok(b_string() eq 'Hello'); ok(!utf8::is_utf8(b_string()), 'python bytes -> not perl utf8'); ok(utf8::is_utf8(string()), 'python unicode -> perl utf8'); } Inline-Python-0.58/PaxHeaders/py2pl.c0000644000000000000000000000013215011104521014421 xustar0030 mtime=1747224913.111747192 30 atime=1747224913.111747192 30 ctime=1747225338.910054944 Inline-Python-0.58/py2pl.c0000644000076400001440000004644715011104521014276 0ustar00nineusers#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "Python.h" #include "py2pl.h" #include "util.h" #ifdef EXPOSE_PERL #include "perlmodule.h" #endif SV* py_true; SV* py_false; /**************************** * SV* Py2Pl(PyObject *obj) * * Converts arbitrary Python data structures to Perl data structures * Note on references: does not Py_DECREF(obj). * * Modifications by Eric Wilhelm 2004-07-11 marked as elw * ****************************/ SV *Py2Pl(PyObject * const obj) { /* elw: see what python says things are */ int const is_string = PY_IS_STRING(obj); #ifdef I_PY_DEBUG PyObject *this_type = PyObject_Type(obj); /* new reference */ PyObject *t_string = PyObject_Str(this_type); /* new reference */ #if PY_MAJOR_VERSION >= 3 PyObject *type_str_bytes = PyUnicode_AsUTF8String(t_string); /* new reference */ char *type_str = PyBytes_AsString(type_str_bytes); #else char *type_str = PyString_AsString(t_string); #endif Printf(("type is %s\n", type_str)); printf("Py2Pl object:\n\t"); PyObject_Print(obj, stdout, Py_PRINT_RAW); printf("\ntype:\n\t"); PyObject_Print(this_type, stdout, Py_PRINT_RAW); printf("\n"); Printf(("String check: %i\n", is_string)); Printf(("Number check: %i\n", PyNumber_Check(obj))); Printf(("Int check: %i\n", PyInt_Check(obj))); Printf(("Long check: %i\n", PyLong_Check(obj))); Printf(("Float check: %i\n", PyFloat_Check(obj))); Printf(("Type check: %i\n", PyType_Check(obj))); #if PY_MAJOR_VERSION < 3 Printf(("Class check: %i\n", PyClass_Check(obj))); Printf(("Instance check: %i\n", PyInstance_Check(obj))); #endif Printf(("Dict check: %i\n", PyDict_Check(obj))); Printf(("Mapping check: %i\n", PyMapping_Check(obj))); Printf(("Sequence check: %i\n", PySequence_Check(obj))); Printf(("Iter check: %i\n", PyIter_Check(obj))); Printf(("Function check: %i\n", PyFunction_Check(obj))); Printf(("Module check: %i\n", PyModule_Check(obj))); Printf(("Method check: %i\n", PyMethod_Check(obj))); #if PY_MAJOR_VERSION < 3 if ((obj->ob_type->tp_flags & Py_TPFLAGS_HEAPTYPE)) printf("heaptype true\n"); if ((obj->ob_type->tp_flags & Py_TPFLAGS_HAVE_CLASS)) printf("has class\n"); #else Py_DECREF(type_str_bytes); #endif Py_DECREF(t_string); Py_DECREF(this_type); #endif /* elw: this needs to be early */ /* None (like undef) */ if (!obj || obj == Py_None) { Printf(("Py2Pl: Py_None\n")); return &PL_sv_undef; } else #ifdef EXPOSE_PERL /* unwrap Perl objects */ if (PerlObjObject_Check(obj)) { Printf(("Py2Pl: Obj_object\n")); return ((PerlObj_object *) obj)->obj; } /* unwrap Perl code refs */ else if (PerlSubObject_Check(obj)) { Printf(("Py2Pl: Sub_object\n")); SV * ref = ((PerlSub_object *) obj)->ref; if (! ref) { /* probably an inherited method */ if (! ((PerlSub_object *) obj)->obj) croak("Error: could not find a code reference or object method for PerlSub"); SV * const sub_obj = (SV*)SvRV(((PerlSub_object *) obj)->obj); HV * const pkg = SvSTASH(sub_obj); #if PY_MAJOR_VERSION >= 3 char * const sub = PyBytes_AsString(((PerlSub_object *) obj)->sub); #else PyObject *obj_sub_str = PyObject_Str(((PerlSub_object *) obj)->sub); /* new ref. */ char * const sub = PyString_AsString(obj_sub_str); #endif GV * const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, sub, TRUE); if (gv && isGV(gv)) { ref = (SV *)GvCV(gv); } #if PY_MAJOR_VERSION < 3 Py_DECREF(obj_sub_str); #endif } return newRV_inc((SV *) ref); } else #endif /* wrap an instance of a Python class */ /* elw: here we need to make these look like instances: */ if (PY_IS_OBJECT(obj)) { /* This is a Python class instance -- bless it into an * Inline::Python::Object. If we're being called from an * Inline::Python class, it will be re-blessed into whatever * class that is. */ SV * const inst_ptr = newSViv(0); SV * const inst = newSVrv(inst_ptr, "Inline::Python::Object");; _inline_magic priv; /* set up magic */ priv.key = INLINE_MAGIC_KEY; sv_magic(inst, inst, PERL_MAGIC_ext, (char *) &priv, sizeof(priv)); MAGIC * const mg = mg_find(inst, PERL_MAGIC_ext); mg->mg_virtual = &inline_mg_vtbl; sv_setiv(inst, (IV) obj); /*SvREADONLY_on(inst); */ /* to uncomment this means I can't re-bless it */ Py_INCREF(obj); Printf(("Py2Pl: Instance. Obj: %p, inst_ptr: %p\n", obj, inst_ptr)); sv_2mortal(inst_ptr); return inst_ptr; } /* a tuple or a list */ else if (PySequence_Check(obj) && !is_string) { AV * const retval = newAV(); int i; int const sz = PySequence_Length(obj); Printf(("sequence (%i)\n", sz)); for (i = 0; i < sz; i++) { PyObject * const tmp = PySequence_GetItem(obj, i); /* new reference */ SV * const next = Py2Pl(tmp); av_push(retval, next); if (sv_isobject(next)) // needed because objects get mortalized in Py2Pl SvREFCNT_inc(next); Py_DECREF(tmp); } if (PyTuple_Check(obj)) { _inline_magic priv; priv.key = TUPLE_MAGIC_KEY; sv_magic((SV * const)retval, (SV * const)NULL, PERL_MAGIC_ext, (char *) &priv, sizeof(priv)); } return newRV_noinc((SV *) retval); } /* a real plain dictionary */ else if (obj->ob_type == &PyDict_Type) { HV * const retval = newHV(); int i; int const sz = PyMapping_Length(obj); PyObject * const keys = PyMapping_Keys(obj); /* new reference */ PyObject * const vals = PyMapping_Values(obj); /* new reference */ Printf(("Py2Pl: dict/map\n")); Printf(("mapping (%i)\n", sz)); for (i = 0; i < sz; i++) { PyObject * const key = PySequence_GetItem(keys, i), /* new reference */ * const val = PySequence_GetItem(vals, i); /* new reference */ SV * const sv_val = Py2Pl(val); char * key_val; if (PyUnicode_Check(key)) { PyObject * const utf8_string = PyUnicode_AsUTF8String(key); /* new reference */ #if PY_MAJOR_VERSION >= 3 key_val = PyBytes_AsString(utf8_string); SV * const utf8_key = newSVpv(key_val, PyBytes_Size(utf8_string)); #else key_val = PyString_AsString(utf8_string); SV * const utf8_key = newSVpv(key_val, PyString_Size(utf8_string)); #endif SvUTF8_on(utf8_key); hv_store_ent(retval, utf8_key, sv_val, 0); sv_2mortal(utf8_key); Py_DECREF(utf8_string); } else { PyObject * s = NULL; #if PY_MAJOR_VERSION >= 3 PyObject * s_bytes = NULL; if (PyBytes_Check(key)) { key_val = PyBytes_AsString(key); #else if (PyString_Check(key)) { key_val = PyString_AsString(key); #endif } else { /* Warning -- encountered a non-string key value while converting a * Python dictionary into a Perl hash. Perl can only use strings as * key values. Using Python's string representation of the key as * Perl's key value. */ s = PyObject_Str(key); /* new reference */ #if PY_MAJOR_VERSION >= 3 s_bytes = PyUnicode_AsUTF8String(s); /* new reference */ key_val = PyBytes_AsString(s_bytes); #else key_val = PyString_AsString(s); #endif if (PL_dowarn) warn("Stringifying non-string hash key value: '%s'", key_val); } if (!key_val) { croak("Invalid key on key %i of mapping\n", i); } hv_store(retval, key_val, strlen(key_val), sv_val, 0); #if PY_MAJOR_VERSION >= 3 Py_XDECREF(s_bytes); #endif Py_XDECREF(s); } if (sv_isobject(sv_val)) // needed because objects get mortalized in Py2Pl SvREFCNT_inc(sv_val); Py_DECREF(key); Py_DECREF(val); } Py_DECREF(keys); Py_DECREF(vals); return newRV_noinc((SV *) retval); } /* a boolean */ else if (PyBool_Check(obj)) { Printf(("Py2Pl: boolean\n")); if (obj == Py_True) return py_true; if (obj == Py_False) return py_false; croak( "Internal error: Pl2Py() caught a bool that is not True or False!? at %s, line %i.\n", __FILE__, __LINE__ ); } /* an int */ else if (PyInt_Check(obj)) { SV * const sv = newSViv(PyInt_AsLong(obj)); Printf(("Py2Pl: integer\n")); return sv; } /* a float */ else if (PyFloat_Check(obj)) { SV * const sv = newSVnv(PyFloat_AsDouble(obj)); Printf(("Py2Pl: float\n")); return sv; } /* a function or method */ else if (PyFunction_Check(obj) || PyMethod_Check(obj)) { SV * const inst_ptr = newSViv(0); SV * const inst = newSVrv(inst_ptr, "Inline::Python::Function"); _inline_magic priv; /* set up magic */ priv.key = INLINE_MAGIC_KEY; sv_magic(inst, inst, '~', (char *) &priv, sizeof(priv)); MAGIC * const mg = mg_find(inst, '~'); mg->mg_virtual = &inline_mg_vtbl; sv_setiv(inst, (IV) obj); /*SvREADONLY_on(inst); */ /* to uncomment this means I can't re-bless it */ Py_INCREF(obj); Printf(("Py2Pl: Instance. Obj: %p, inst_ptr: %p\n", obj, inst_ptr)); sv_2mortal(inst_ptr); return inst_ptr; } #if PY_MAJOR_VERSION >= 3 /* In P3, I stringify Bytes explicitly to avoid "b'fdsfd'" as Perl string. * "PyObject_Str" is fine for string object. */ else if (PyBytes_Check(obj)) { char * const str = PyBytes_AsString(obj); SV * const s2 = newSVpv(str, PyBytes_Size(obj)); Printf(("Py2Pl: bytes \n")); return s2; } #endif else if (PyUnicode_Check(obj)) { PyObject * const string = PyUnicode_AsUTF8String(obj); /* new reference */ if (!string) { Printf(("Py2Pl: string is NULL!? -> Py_None\n")); return &PL_sv_undef; } #if PY_MAJOR_VERSION >= 3 char * const str = PyBytes_AsString(string); SV * const s2 = newSVpv(str, PyBytes_Size(string)); #else char * const str = PyString_AsString(string); SV * const s2 = newSVpv(str, PyString_Size(string)); #endif SvUTF8_on(s2); Printf(("Py2Pl: utf8 string \n")); Py_DECREF(string); return s2; } /* P2: a string (or number). P3: number*/ else { PyObject * const string = PyObject_Str(obj); /* new reference */ if (!string) { Printf(("Py2Pl: string is NULL!? -> Py_None\n")); return &PL_sv_undef; } #if PY_MAJOR_VERSION >= 3 PyObject * const string_as_bytes = PyUnicode_AsUTF8String(string); /* new reference */ char * const str = PyBytes_AsString(string_as_bytes); SV * const s2 = newSVpv(str, PyBytes_Size(string_as_bytes)); Py_DECREF(string_as_bytes); #else char * const str = PyString_AsString(string); SV * const s2 = newSVpv(str, PyString_Size(string)); #endif Printf(("Py2Pl: string / number\n")); Py_DECREF(string); return s2; } } /**************************** * SV* Pl2Py(PyObject *obj) * * Converts arbitrary Perl data structures to Python data structures ****************************/ PyObject *Pl2Py(SV * const obj) { PyObject *o; /* an object */ if (sv_isobject(obj)) { /* We know it's a blessed reference: */ SV * const obj_deref = SvRV(obj); /* First check if it's one of the Inline::Python::Boolean values */ if (obj == py_true || obj_deref == SvRV(py_true)) Py_RETURN_TRUE; if (obj == py_false || obj_deref == SvRV(py_false)) Py_RETURN_FALSE; /* * Now it's time to check whether it's *really* a blessed Perl object, * or whether it's a blessed Python object with '~' magic set. * If '~' magic is set, we 'unwrap' it into its Python object. * If not, we wrap it up in a PerlObj_object. */ /* check for magic! */ MAGIC * const mg = mg_find(obj_deref, '~'); if (mg && Inline_Magic_Check(mg->mg_ptr)) { IV const ptr = SvIV(obj_deref); if (!ptr) { croak ("Internal error: Pl2Py() caught NULL PyObject* at %s, line %i.\n", __FILE__, __LINE__); } o = (PyObject *) ptr; Py_INCREF(o); } else { HV * const stash = SvSTASH(obj_deref); char * const pkg = HvNAME(stash); SV * const full_pkg = newSVpvf("main::%s::", pkg); Printf(("A Perl object (%s, refcnt: %i). Wrapping...\n", SvPV(full_pkg, PL_na), SvREFCNT(obj))); #if PY_MAJOR_VERSION >= 3 PyObject * const pkg_py = PyBytes_FromString(SvPV(full_pkg, PL_na)); #else PyObject * const pkg_py = PyString_FromString(SvPV(full_pkg, PL_na)); #endif o = newPerlObj_object(obj, pkg_py); Py_DECREF(pkg_py); SvREFCNT_dec(full_pkg); } } /* An integer */ else if (SvIOK(obj)) { Printf(("integer\n")); o = PyInt_FromLong((long) SvIV(obj)); } /* A floating-point number */ else if (SvNOK(obj)) { o = PyFloat_FromDouble(SvNV(obj)); } /* A string */ else if (SvPOKp(obj)) { STRLEN len; char * const str = SvPV(obj, len); Printf(("string = ")); Printf(("%s\n", str)); #if PY_MAJOR_VERSION >= 3 if (SvUTF8(obj) || is_ascii_string((U8*) str, len)) o = PyUnicode_DecodeUTF8(str, len, "replace"); else o = PyBytes_FromStringAndSize(str, len); #else if (SvUTF8(obj)) o = PyUnicode_DecodeUTF8(str, len, "replace"); else o = PyString_FromStringAndSize(str, len); #endif Printf(("string ok\n")); } /* An array */ else if (SvROK(obj) && SvTYPE(SvRV(obj)) == SVt_PVAV) { AV * const av = (AV *) SvRV(obj); int const len = av_len(av) + 1; int i; if (py_is_tuple(obj)) { o = PyTuple_New(len); Printf(("tuple (%i)\n", len)); for (i = 0; i < len; i++) { SV ** const tmp = av_fetch(av, i, 0); if (tmp) { PyObject * const tmp_py = Pl2Py(*tmp); PyTuple_SetItem(o, i, tmp_py); } else { Printf(("Got a NULL from av_fetch for element %i. Might be a bug!", i)); Py_INCREF(Py_None); PyTuple_SetItem(o, i, Py_None); } } } else { o = PyList_New(len); Printf(("array (%i)\n", len)); for (i = 0; i < len; i++) { SV ** const tmp = av_fetch(av, i, 0); if (tmp) { PyObject * const tmp_py = Pl2Py(*tmp); PyList_SetItem(o, i, tmp_py); } else { Printf(("Got a NULL from av_fetch for element %i. Might be a bug!", i)); Py_INCREF(Py_None); PyList_SetItem(o, i, Py_None); } } } } /* A hash */ else if (SvROK(obj) && SvTYPE(SvRV(obj)) == SVt_PVHV) { HV * const hv = (HV *) SvRV(obj); int const len = hv_iterinit(hv); int i; o = PyDict_New(); Printf(("hash (%i)\n", len)); for (i = 0; i < len; i++) { HE * const next = hv_iternext(hv); SV * const key = hv_iterkeysv(next); if (!key) croak("Hash entry without key!?"); STRLEN len; char * const key_str = SvPV(key, len); PyObject *py_key; #if PY_MAJOR_VERSION >= 3 if (SvUTF8(key) || is_ascii_string((U8*) key_str, len)) py_key = PyUnicode_DecodeUTF8(key_str, len, "replace"); else py_key = PyBytes_FromStringAndSize(key_str, len); #else if (SvUTF8(key)) py_key = PyUnicode_DecodeUTF8(key_str, len, "replace"); else py_key = PyString_FromStringAndSize(key_str, len); #endif PyObject * const val = Pl2Py(hv_iterval(hv, next)); PyDict_SetItem(o, py_key, val); Py_DECREF(py_key); Py_DECREF(val); } Printf(("returning from hash conversion.\n")); } /* A code ref */ else if (SvROK(obj) && SvTYPE(SvRV(obj)) == SVt_PVCV) { /* wrap this into a PerlSub_object */ o = (PyObject *) newPerlSub_object(NULL, NULL, obj); } else { Printf(("undef -> None\n")); o = Py_None; Py_INCREF(Py_None); } Printf(("returning from Pl2Py\n")); return o; } void croak_python_exception() { PyObject *ex_type, *ex_value, *ex_traceback; if (PyErr_ExceptionMatches(PyExc_Perl)) { PyErr_Fetch(&ex_type, &ex_value, &ex_traceback); PyErr_NormalizeException(&ex_type, &ex_value, &ex_traceback); PyObject *perl_exception_args = PyObject_GetAttrString(ex_value, "args"); PyObject *perl_exception = PySequence_GetItem(perl_exception_args, 0); SV *perl_exception_object = Py2Pl(perl_exception); sv_2mortal(perl_exception_object); SV *errsv = get_sv("@", GV_ADD); sv_setsv(errsv, perl_exception_object); croak(NULL); Py_DECREF(perl_exception); Py_DECREF(perl_exception_args); } else { PyErr_Fetch(&ex_type, &ex_value, &ex_traceback); PyErr_NormalizeException(&ex_type, &ex_value, &ex_traceback); PyObject * const ex_message = PyObject_Str(ex_value); /* new reference */ #if PY_MAJOR_VERSION >= 3 PyObject * const ex_message_bytes = PyUnicode_AsUTF8String(ex_message); /* new reference */ char * const c_ex_message = PyBytes_AsString(ex_message_bytes); #else char * const c_ex_message = PyString_AsString(ex_message); #endif if (ex_traceback) { PyObject * const tb_lineno = PyObject_GetAttrString(ex_traceback, "tb_lineno"); croak("%s: %s at line %li\n", ((PyTypeObject *)ex_type)->tp_name, c_ex_message, PyInt_AsLong(tb_lineno)); Py_DECREF(tb_lineno); } else { croak("%s: %s", ((PyTypeObject *)ex_type)->tp_name, c_ex_message); } #if PY_MAJOR_VERSION >= 3 Py_DECREF(ex_message_bytes); #endif Py_DECREF(ex_message); } Py_DECREF(ex_type); Py_DECREF(ex_value); Py_XDECREF(ex_traceback); } /* * vim: expandtab shiftwidth=4 softtabstop=4 cinoptions='\:2=2' : */ Inline-Python-0.58/PaxHeaders/Changes0000644000000000000000000000013215011105130014477 xustar0030 mtime=1747225176.676724209 30 atime=1747225176.676724209 30 ctime=1747225338.910097655 Inline-Python-0.58/Changes0000644000076400001440000002401315011105130014335 0ustar00nineusersRevision history for Perl extension Inline::Python. 0.58 Wed May 14 14:17:00 CEST 2025 (Stefan Seifert) - Fix compilation with Python 3.13 (Mattias Ellert) - Fix compiler warnings (Mattias Ellert) - Improve compatibility with strict(er) C99 compilers (Florian Weimer) - Fix Makefile logic (Mattias Ellert) - Fix build on Windows (Yaribz) 0.57 Sun Sep 18 13:20:00 CEST 2022 (Stefan Seifert) - Try to detect more object types. - Further tighten the "is it a dict or object" check - Also skip List and Tuple when checking for python object - Unify "is this an object" checks into a macro to fix method calls on strange objects - Define PY_MAJOR_VERSION automatically - Search for and prefer python3 when building - Pass ASCII strings as in Python 3 - Fix segfault on Python 3.10 by calling Py_Initialize() before calling PyBytes_FromString() - Process rss information not supported by Proc::ProcessTable on Windows 0.56 Fri Aug 04 15:30:00 CEST 2017 (Stefan Seifert) - Fix floating point related test failures on some machines. 0.55 Tue Jul 03 09:30:00 CEST 2017 (Stefan Seifert) - Pass Python floats as floats to Perl, not as string. 0.54 Tue Jun 13 08:40:00 CEST 2017 (Stefan Seifert) - Fix object stringification crashing on Perl < 5.16 (RT #122082) 0.53 Fri Jun 02 12:10:00 CEST 2017 (Stefan Seifert) - Better support for serializing booleans with JSON - Support calling Perl objects with overloaded code dereferencing - Support overloaded stringification of Perl objects 0.52 Thu Dec 01 20:31:00 CET 2016 (Stefan Seifert) - Fix test failing on lots of machines by Linas Valiukas 0.51 Thu Nov 09 08:45:00 CET 2016 (Stefan Seifert) - Fix memory leak when passing dict with Unicode keys to Perl by Linas Valiukas 0.50 Thu Jun 30 14:30:00 CEST 2016 (Stefan Seifert) - Fix memory corruption after passing a dict with a non-string key to Perl 0.49 Tue Apr 21 08:30:00 CEST 2015 (Stefan Seifert) - Fix crash during perl's shutdown when env variables were modified by Python 0.48 Sat Jan 24 10:00:00 CET 2015 (Stefan Seifert) - Fix compatibility with perl < 5.14 - Allow shutting down Python 0.47 Thu Jan 22 19:35:00 CET 2015 (Stefan Seifert) - Translate Perl exceptions into Python exceptions and make them catchable. - fix some POD errors by Gregor Herrmann 0.46 Sun Dec 07 12:30:00 CET 2014 (Stefan Seifert) - Python 3 support by Laurent Mazuel! - Correcting KeyError to AttributeError in __getattr__ by Laurent Mazuel 0.45 Sat Sep 06 10:30:00 CEST 2014 (Stefan Seifert) - Support implementing __cmp__ in Perl - Skip test requiring Parse::RecDescent if the module is not installed 0.44 Tue Sep 02 11:00:00 CEST 2014 (Stefan Seifert) - Fix memory corruption introduced with boolean support - Document the usage of Inline::Python::Boolean - Minor doc fixes by Zakariyya Mughal - Allow non-interactive installation in Makefile.PL - Add links to the github repo by mohawk2 0.43 Thu Sep 12 23:00:00 CEST 2013 (Stefan Seifert) - Fixed converting floats from Perl to Python with different locale - Fixed RT #87962 0.42 Fri May 31 20:20:00 CEST 2013 (Stefan Seifert) - Python booleans passed through Perl make it back to Python as Booleans instead of Integers. - Fix segfaults on Perl 5.18.0 caused by uninitialized fields in a data structure. Should help performance as well. 0.41 Thu Nov 08 20:15:00 CET 2012 (Stefan Seifert) - Fixed installation on systems only having a shared libpython - Code cleanup 0.40 Fri Jul 29 16:30:00 CEST 2011 (Stefan Seifert) - Finally fixed t/06dict.t allowing installation on many more machines 0.39 Wed Mar 09 13:00:00 CET 2011 (Stefan Seifert) - Added py_is_tuple and made Pl2Py recognize an array ref that has been a tuple before in Python. - Fixed memory corruption on a Python function calling a Perl function that changed the stack pointer. - Fixed several memory leaks (scalars and dict keys). - Fixed wrong refcount of return values in py_eval (RT #48081) - Fixed accessing Unicode keys in a dict passed from Perl. - Fixed compatability of t/30floats.t with Python 2.7. 0.38 Thu Dec 02 14:00:00 CEST 2010 (Stefan Seifert) - Fix Perl assertion fail if __getitem__ called multiple times - Fix "Attempt to free unreferenced scalar" sometimes happening when calling a Perl sub with named parameters from Python. - Fix several memory leaks found using valgrind - Add py_finalize to be able to shut down the Python interpreter. 0.37 Thu Sep 30 09:30:00 CEST 2010 (Stefan Seifert) - Added line numbers to Python exception messages. - Fixed passing of a perl code ref through Python space. - Allow passing references to methods from Python to Perl. - Implemented py_has_attr complementing py_get_attr. - We now support stringification of Python objects via __str__ methods. - Fixed segfault when accessing a Python object's attributes throws an exception. - Fixed some problems with the test suite, hopefully making installation work on more machines. - Fixed compilation on Win32, linking still seems broken though :( 0.36 Mon Jun 23 12:45:00 CEST 2010 (Stefan Seifert) - Fixed a segfault when passing dicts with Unicode keys to Perl - Pass Python exceptions to Perl instead of just printing to STDERR 0.35 Wed Mar 31 11:00:00 CET 2010 (Stefan Seifert) - Fixed floats sometimes getting converted to int when transfered from Perl to Python. Thanks to John McCullough for a great bug report. 0.34 Fri Mar 12 12:20:00 CET 2010 (Stefan Seifert) - Fixed refcounting of positional arguments in named argument calls to Perl subs. 0.33 Mon Feb 22 10:30:00 CET 2010 (Stefan Seifert) - Added support for named arguments for Perl subs 0.32 Fri Jan 29 20:00:00 CET 2010 (Stefan Seifert) - Perl UTF-8 strings now get converted to Python Unicode strings and vice versa. This could potentially lead to incompatibilities with existing code. - Return lists of Perl subs no longer get reversed before passing to Python. 0.31 Sun Dec 06 15:30:00 CET 2009 (Stefan Seifert) - Implement access to Inline::Python::Object data 0.30 Sun Nov 29 19:45:00 CET 2009 (Stefan Seifert) - Convert Perl arrays to Python arrays instead of tuples - First look for methods before looking for attributes in PerlObj_getattr 0.29 Tue Jul 07 17:00:00 CEST 2009 (Stefan Seifert) - Implemented passing of subroutine references and lambda expressions from Python to Perl space. - Implemented Python's __getitem__ protocol for perl objects. Perl objects can thus be used like dictionaries if they support a __getitem__ sub. - Fixed a bug in Pl2Py sometimes segfaulting on undefs in arrays. 0.28 Tue Dec 16 19:00:00 CET 2008 (Stefan Seifert) - Fixed pushing integers from Python to Perl space. They now retain their integer-ness instead of silently converting them to strings. - PerlObj objects now have a comparison function which asserts if the _same_ perl object is contained. - implemented Python's __getattr__ protocol for perl objects. Attributes can now be accessed with my_perl_object.my_attribute same as Python objects. The perl object just has to implement a __getattr__ sub. - __getattr__ now raises a KeyError if a PerlObj object does not have the requested attribute instead of silently assuming that a method is being called. - Added testcases for all these and for the Unicode fix in 0.27 0.27 Thu Nov 20 19:00:00 CET 2008 (Stefan Seifert) - Fixed a segfault in py2pl.c when converting Unicode strings from Python to Perl. - Attempt to check for Python.h in Makefile.pl to make it more visible to the user. 0.26 Mon Nov 10 13:20:00 CET 2008 (Stefan Seifert) - Fixed compatibility with Python 2.5: all tests run successfully. - Documented the --enable-shared requirement 0.25 Thu Oct 02 22:20:00 CEST 2008 (Stefan Seifert) - Added missing changes and updated documentation to reflect current status. No code changes. 0.24 Thu Oct 02 22:05:00 CEST 2008 (Stefan Seifert) - fixed many wrong refcounts leading to memory leaks and too early freed objects. Most notably when returning more than one result from a perl sub to python. - fixed segfaults in perlSub_getattr and perlSub_setattr for invalid attribute names on non-methods. - added many testcases for refcounting 0.23 Mon Sep 29 11:50:00 CEST 2008 (Stefan Seifert) - fixed segfault when returing perl objects from python functions and methods - fixed uninitialized member variables of perl subs - updated documentation to reflect new co-maintainer 0.22 Sun Jan 9 22:29:54 PST 2005 [Bug reported by David Dyck] - removed some declarations after statements - newer versions of gcc seem to accept this by default, while older versions just croak. Of course, the older versions also don't support -Wdeclaration-after-statement. 0.21 Mon Jul 26 13:40:57 CDT 2004 [Patch from Eric Wilhelm] - Added support for 'new-style' python classes which subtype builtin types per PEP's 252 and 253. 0.20 Mon Jul 9 16:46:56 PDT 2001 - Made the Makefile.PL more clever about how it picks debugging information. It accepts an optional argument, too, so it's easy to correct the mistakes. 0.20 Wed Jun 20 16:27:23 PDT 2001 - Lots of testing with different versions of Perl & Python - Makefile.PL auto-detects configuration for python >= 2.0 0.20 Sun Jun 17 19:57:18 PDT 2001 - Made eval_python return results of running code - py_bind_class(), py_bind_function(), and py_study_package() - py_eval() and py_call_function() - py_new_object() and py_call_method() - Many new test cases - Updated documentation - New language alias 'PYTHON' for Inline::Files support - 'FILTERS' Config option - Removed 'PRIVATE_PRIFIXES' Config option - Added new base class Inline::Python::Object for all objects. 0.15 Sun Jun 10 18:39:23 PDT 2001 - Ported to Inline 0.42. 0.14 Thu Mar 22 08:50:33 PST 2001 - Added support for passing binary strings between Python & Perl. 0.13 Sun Mar 4 22:09:35 PST 2001 - Added Win32 code to search for Python installations on Win32 - Eliminated GNU-specific preprocessor macro syntax 0.10 Thu Nov 23 16:46:27 PST 2000 - Created Inline::Python. Inline-Python-0.58/PaxHeaders/Makefile.PL0000644000000000000000000000013214416227476015210 xustar0030 mtime=1681469246.119145284 30 atime=1681469246.119145284 30 ctime=1747225338.910703956 Inline-Python-0.58/Makefile.PL0000644000076400001440000006027414416227476015057 0ustar00nineusersuse Data::Dumper; use Config; use Cwd qw(abs_path); use ExtUtils::MakeMaker 6.64; use Getopt::Long; use File::Spec; use File::Basename; GetOptions( 'gdb:s' => \$gdb, debug => \$debug, help => \$help, ); usage() if $help; #============================================================================ # What python are we going to try? #============================================================================ my $sel = $ENV{INLINE_PYTHON_EXECUTABLE}; my $num_python3 = 0; unless ($sel) { my @pythons; my %pythons; my $sep = $^O eq 'MSWin32' ? ";" : ":"; my $exe = $^O eq 'MSWin32' ? ".exe" : ""; for $p (split /$sep/, $ENV{PATH}) { $p =~ s/^~/$ENV{HOME}/; for $exe_version ('3', '') { my $py = File::Spec->catfile($p, "python$exe_version$exe"); next unless -f $py and -x $py; next if $pythons{abs_path($py)}++; # filter symlinked duplicates my $version = get_python_major_version($py); push @pythons, { path => $py, version => $version }; $num_python3++ if ($version == 3); } } # Keep them in PATH order. # @pythons = sort { $a->{path} cmp $b->{path} } @pythons; my $num = 1; print "Found these python executables on your PATH:\n"; print $num++ . ". " . $_->{path} . "\n" for @pythons; if (@pythons == 1 and not $sel) { $sel = $pythons[0]; print "Using the only python executable I could find\n"; print 'Set the INLINE_PYTHON_EXECUTABLE environment variable to' . " the full path to your python executable to override this selection.\n"; } elsif ($num_python3 == 1) { # Prefer python 3 for my $python (@pythons) { if ($python->{version} == 3) { $sel = $python; print "Using the only python 3 executable I could find even though python 2 was also found\n"; print 'Set the INLINE_PYTHON_EXECUTABLE environment variable to' . " the full path to your python executable to override this selection.\n"; last; } } } unless ($sel) { $sel = prompt("Use which?", '1'); if ($sel =~ /^\d+$/) { die 'Invalid number. Please enter only numbers from 1 to ' . ($num - 1) . " or the full path to your python executable.\n" . 'Set the INLINE_PYTHON_EXECUTABLE environment variable to' . " the full path to your python executable to avoid this question.\n" if $sel > ($num - 1); $sel = $pythons[$sel - 1]; } } } $sel = { path => $sel } unless ref $sel eq 'HASH'; # in case the user entered a path print "Using $sel->{path}\n"; my $py_major_version = get_python_major_version($sel->{path}); #============================================================================ # Interrogate the python interpreter (or the user) for required flags #============================================================================ interrogate($sel); # Fix up the libpath and libpython die "Could not find Python.h in include path. make will not work" unless -e File::Spec->catfile($sel->{incpath}, "Python.h"); substr($sel->{incpath}, 0, 0) = "-I"; substr($sel->{libpath}, 0, 0) = "-L"; $sel->{libpython} =~ s/lib(.*)(?:\.\Q$Config{dlext}\E|\Q$Config{_a}\E)/-l$1/; my @flags; push @flags, debug_flag() if defined $gdb; push @flags, '-DI_PY_DEBUG' if $debug; push @flags, "-DPY_MAJOR_VERSION=$py_major_version"; push @flags, 'none (perl Makefile.PL --help for details)' unless @flags; $sel->{syslib} = '' if $sel->{syslib} eq "None"; print <{syslibs} Python Lib: $sel->{libpath} $sel->{libpython} Includes: $sel->{incpath} Extra Flags: @flags END #============================================================================ # Finalize, and write the makefile #============================================================================ $defs = join ' ', qw(-DEXPOSE_PERL -DCREATE_PYTHON -UCREATE_PERL), $debug ? "-DI_PY_DEBUG" : (); WriteMakefile( $defs ? (DEFINE => $defs) : (), defined $gdb ? (OPTIMIZE => debug_flag()) : (), INC => $sel->{incpath}, LIBS => (join " ", @$sel{qw(libpath libpython syslibs)}), NAME => 'Inline::Python', ABSTRACT_FROM => 'Python.pod', AUTHOR => 'Neil Watkiss ', LICENSE => 'perl', VERSION_FROM => 'Python.pm', PREREQ_PM => { 'Inline' => 0.46, 'Digest::MD5' => 2.50, 'Data::Dumper' => 0, 'File::Spec' => 0, }, TEST_REQUIRES => { 'Test' => 0, 'Test::More' => 0, 'Test::Deep' => 0, 'Test::Number::Delta' => 0, 'Proc::ProcessTable' => '0.53', }, OBJECT => 'Python.o py2pl.o perlmodule.o util.o', META_MERGE => { "meta-spec" => { version => 2 }, resources => { repository => { type => 'git', url => 'http://github.com/niner/inline-python-pm.git', web => 'http://github.com/niner/inline-python-pm', }, }, }, clean => {FILES => 'blib_test/'}, dynamic_lib => { OTHERLDFLAGS => ($sel->{rpath} ? "-Wl,-rpath,$sel->{rpath}" : ''), }, ); #============================================================================ # Tries to ask the python interpreter what libraries we need, where its # include directories are, etc. # Typical values of the Python sysconfig variables: # # - VERSION # # - Ubuntu : 3.10 # - Windows: 310 # - macOS : 3.10 # # - BINDIR # # - Ubuntu : # - system version: /usr/bin # - pyenv version : /home/username/.pyenv/versions/3.9.4/bin # - Windows : C:\Python\Python310 (NOTE: missing trailing "bin") # - macOS : # - system version : /Applications/Xcode.app/Contents/Developer/Library # /Frameworks/Python3.framework/Versions/3.8/bin # - pyenv version : /Users/username/.pyenv/versions/3.10.0-debug/bin # # - LIBS: # # - Ubuntu : -lcrypt -lpthread -ldl -lutil -lm # - Windows: [None] # - macOS : # - system version : -ldl -lSystem -framework CoreFoundation # - pyenv version : -ldl -framework CoreFoundation # # - INCLUDEPY # # - Ubuntu : /usr/include/python3.9 # - Windows: C:\Python\Python310\Include # - macOS # - system version : /Applications/Xcode.app/Contents/Developer/Library # /Frameworks/Python3.framework/Versions/3.8/Headers # - pyenv version : /Users/username/.pyenv/versions/3.10.0-debug/include/python3.10d # # - LIBPL # # - Ubuntu : # - system version : /usr/lib/python3.9/config-3.9-x86_64-linux-gnu # - pyenv version : /home/username/.pyenv/versions/3.8.9 # /lib/python3.8/config-3.8-x86_64-linux-gnu (NOTE: this folder does # not contain a shared library even if python was built with # --enable-shared. However, the folder LIBDIR, see below, does) # - Windows: [None] (NOTE: this should be "$BINDIR/libs" on windows) # - macOS : # - system version : /Applications/Xcode.app/Contents/Developer/Library/Frameworks # /Python3.framework/Versions/3.8/lib/python3.8/config-3.8-darwin # - pyenv version : /Users/username/.pyenv/versions/3.10.0-debug/lib # /python3.10/config-3.10d-darwin # # - LDLIBRARY # # - Ubuntu : # - if python was built with --enable-shared : libpython3.9.so # - else : libpython3.9.a # - Windows: [None] (NOTE: this should be "python310.lib" on windows, # where a .lib file is a so-called import-library on Windows. The # import library reference a .dll library in $BINDIR. # On Windows there is also a stable-across-versions-subset library # called "python3.lib" (which references "python3.dll" in $BINDIR, # see https://www.python.org/dev/peps/pep-0384/ for more information.) # - macOS : # - system version: Python3.framework/Versions/3.8/Python3 (NOTE: this is a .dylib # i.e. a shared library) # - pyenv version : # - if built with --enable-shared : libpython3.10d.dylib # - else : libpython3.10d.a # # - LIBRARY # # - Ubuntu : libpython3.9.a # - Windows: [None] (NOTE: static library is not available but import library exists # see note on LDLIBRARY above) # - macOS : libpython3.10d.a # # - LIBDEST # # - Ubuntu : /home/username/.pyenv/versions/3.9.4/lib/python3.9 # - Windows: C:\Python310\Lib (NOTE: this folder does not contain anything interesting # to us. No static or shared libraries here, but the import # library is in the libs folder C:\Python310\libs and the # .dll library is in the BINDIR C:\Python310) # - macOS : # - system version : /Applications/Xcode.app/Contents/Developer/Library # /Frameworks/Python3.framework/Versions/3.8/lib/python3.8 # - pyenv version : /Users/username/.pyenv/versions/3.10.0-debug/lib/python3.10 # # - LIBDIR # # - Ubuntu : # - system version : /usr/lib/x86_64-linux-gnu # - pyenv version : /home/username/.pyenv/versions/3.9.4/lib # - Windows : [None] # - macOS : # - system version: /Applications/Xcode.app/Contents/Developer/Library # /Frameworks/Python3.framework/Versions/3.8/lib # - pyenv version : /Users/username/.pyenv/versions/3.10.0-debug/lib # #============================================================================ sub interrogate { my $ref = shift; return query_options($ref) unless test_interrogate($ref); $ref->{syslibs} = get_config_var($ref, "LIBS"); $ref->{incpath} = get_config_var($ref, "INCLUDEPY"); $ref->{libpath} = get_config_var($ref, "LIBPL"); $ref->{ldlib} = get_config_var($ref, "LDLIBRARY"); $ref->{libpython} = get_config_var($ref, "LIBRARY"); my $tmp = File::Spec->canonpath($ref->{libpython}); my @dirs = File::Spec->splitdir( $tmp ); $ref->{libpython} = $dirs[-1]; # On Windows, Python config var "LIBRARY" is not defined if ($ref->{libpython} eq 'None') { special_get_libpath($ref); } $ref->{libpath} = File::Spec->catfile(get_config_var($ref, "LIBDEST"), 'config') if ($ref->{libpath} eq 'None'); $ref->{rpath} = ''; # only used if we are linking with a shared library, see below. $ref->{cflags} = get_config_var($ref, 'CFLAGS'); $ref->{config_args} = get_config_var($ref, 'CONFIG_ARGS'); $ref->{enable_shared} = (get_config_var($ref, 'Py_ENABLE_SHARED') eq "1"); if (using_macos_system_python($ref)) { add_rpath_for_macos_system_python($ref); } elsif ($^O ne "MSWin32") { # we use the import library on Windows, # see special_get_libpath() below special_non_windows_check_shared_static_libs($ref); } return query_options($ref) unless sanity_check($ref); } # on macOS using the system python, the path to the shared and static libraries # is given by "libpath" (LIBPL). In this directory there exists two files: # - libpythonxxx.a # - libpythonxxx.dylib # the first name (the static library libpythonxxx.a) is given by the python sysconfig # variable "libpython" (LIBRARY). However, both these files are symlinks to a shared # library called "Python" which is located relative to LIBPL with path: # ../../../Python3. This file "Python3" (or "Python2" ??), is a dylib with an embedded # @rpath magic search path given by: @rpath/Python3.framework/Versions/3.8/Python3 which # is also the ID of the library (LC_ID_DYLIB) which means that Python.so (the Perl # generated interface) must include an rpath to the directory 3 levels above the # location of "Python3" (which is 6 levels above libpythonxxx.dylib in LIBPL). # This directory is fortunately given by the config variable # PYTHONFRAMEWORKPREFIX. # sub add_rpath_for_macos_system_python { my ($ref) = @_; $ref->{rpath} = get_config_var($ref, 'PYTHONFRAMEWORKPREFIX'); }; sub special_non_windows_check_shared_static_libs { my ($ref) = @_; if (shared_lib_priority($ref)) { $ref->{libpython} = $ref->{ldlib}; $ref->{rpath} = $ref->{libpath}; } else { if (!check_static_library_ok($ref)) { # In this case we may find a shared library to link with in # $LIBDIR instead of in $LIBPL, this happens if you install Python # with pyenv (on the other hand for the system python there will # a shared library in both $LIBDIR and $LIBPL, see issue #29 for more information. # TODO: However, this still does not work for pyenv (tested on Ubuntu). For some # reason this shared library does not behave well unless python was also compiled # with -fPIC option. if (( $ref->{cflags} !~ /\Q-fPIC\E/i) && ($ref->{path} !~ m{^/(?:usr/)?bin/python})) { if ($ref->{enable_shared}) { warn "WARNING: This python's shared library was compiled with --enable-shared but not " ." with -fPIC option, this might lead to strange runtime behavior.\n"; } else { # TODO: strangely this seems to work fine on macOS. # More investigation is needed here... warn "WARNING: This python was not compiled with --enable-shared and not " . "with -fPIC.\n" . "WARNING: This is known to not work on linux.\n"; } } $ref->{libpython} = $ref->{ldlib}; my $shared_lib = File::Spec->catfile($ref->{libpath}, $ref->{libpython}); if (!-f $shared_lib) { $ref->{libpath} = get_config_var($ref, "LIBDIR"); } else { $ref->{rpath} = $ref->{libpath}; } } } } sub shared_lib_priority { my ($ref) = @_; if ($ref->{libpython} ne $ref->{ldlib}) { # This should happen if python was compiled with --enable-shared # In this case the linker will prefer the shared library my $static_lib = File::Spec->catfile($ref->{libpath}, $ref->{libpython}); my $shared_lib = File::Spec->catfile($ref->{libpath}, $ref->{ldlib}); return 1 if (-f $static_lib) && (-f $shared_lib); } return 0; } sub check_static_library_ok { my ($ref) = @_; my $static_lib = File::Spec->catfile($ref->{libpath}, $ref->{libpython}); return 0 if (!-f $static_lib); # We should check if the static library was compiled with -fPIC, or else # we cannot create a shared Python.so from it. # TODO: It seem like it is possible to build python with --enable-shared # and without CFLAGS=-fPIC, and this will make both libpythonxx.so and # libpythonxx.a position independent, but in this case strange things # may happen at runtime (i.e. when running "make test"), see issue #29 # for more information. This should be investigated futher to determine what # is actually going on. # This seems to not be a problem on macOS though. return 1 if $ref->{cflags} =~ /\Q-fPIC\E/i; warn "WARNING: The static python library seems not to be position indepenent.\n" . "WARNING: If this does not work you should try again with a " . "python version that was compiled with CFLAGS=-fPIC\n"; return 0; } sub using_macos_system_python { my ($ref) = @_; return ($^O eq "darwin") && ($ref->{path} =~ m{^/usr/bin/python}); } sub check_shared_lib_support() { my ($ref) = @_; # Windows python always have a shared lib return 1 if $^O eq "MSWin32"; # The system python always have a shared lib on macOS return 1 if using_macos_system_python($ref); # See https://stackoverflow.com/a/23202055/2173773 return $ref->{enable_shared}; } sub get_python_version { my $ref = shift; my $major = `$ref->{path} -c "import sys; print(sys.version_info[0])"`; my $minor = `$ref->{path} -c "import sys; print(sys.version_info[1])"`; return ($major, $minor); } # On Windows, Python config var "LIBRARY" is not defined, so we try another method # to obtain the library path name sub special_get_libpath { my $ref = shift; my ($major, $minor) = get_python_version($ref); my $cmd; if (($major == 3 && $minor >=10) || $major > 3 ) { $cmd = 'import setuptools.command.build_ext; d=setuptools.dist.Distribution();' .'b=setuptools.command.build_ext.build_ext(d)'; } else { $cmd = 'import distutils.command.build_ext; d=distutils.core.Distribution();' . 'b=distutils.command.build_ext.build_ext(d)'; } my @lines = `$ref->{path} -c "$cmd;b.finalize_options();print(b.library_dirs[0])" 2>&1`; my $val = $lines[-1]; chomp $val; return '' if !$val; # On Windows, $val should now be equal to $BINDIR/libs my $pyscript = "import sysconfig; " . "print(sysconfig.get_config_var('VERSION'))"; my $version = `$ref->{path} -c "$pyscript"`; chomp $version; $ref->{libpath} = $val; $ref->{libpython} = "python${version}.lib"; # Note: on Windows this is an import library, # that referes to a shared library # (not a static library) # The above file should always exist, alternatively we could # set libpath to $BINDIR and libpython to python$version.dll and use the shared library # directly instead of using the import library. return $val; } sub test_interrogate { my $ref = shift; `$ref->{path} -c "import sysconfig; sysconfig.get_config_var" 2>&1`; print <{libpython} = $ref->{ldlib} if not -f File::Spec->catfile($ref->{libpath}, $ref->{libpython}) and -f File::Spec->catfile($ref->{libpath}, $ref->{ldlib}); my $libpath = File::Spec->catfile($ref->{libpath}, $ref->{libpython}); unless (-d $ref->{libpath} && -d $ref->{incpath} && (-f File::Spec->catfile($ref->{libpath}, $ref->{libpython})) ) { print <{syslibs} Python Library: $libpath Include Path: $ref->{incpath} END # ' stupid vim. } return 1; } sub get_python_major_version { my $exe = shift; my $version = `$exe --version 2>&1`; $version =~ /(\d+)\./; return $1; } sub get_config_var { my $ref = shift; my $key = shift; my $exe = $ref->{path}; my $val = `$exe -c "import sysconfig; print(sysconfig.get_config_var('$key'))"`; chomp $val; return $val; } sub get_default_python_lib_index { my $r_found_libs=shift; # Avoid limited API libraries (ABI), which are versionned with 1 digit only # (cf https://docs.python.org/3/c-api/stable.html) for my $i (0..$#{$r_found_libs}) { return ($i+1) if($r_found_libs->[$i] =~ /python\d\.?\d[^\/\\]+$/i); } return 1; } sub query_options { my $ref = shift; # Every python I've seen needs pthreads. Obviously not on windows. my $libs_guess = $ref->{syslibs} ? $ref->{syslibs} : $^O eq 'MSWin32' ? '' : '-lpthread'; print <{syslibs} = prompt("Enter extra libraries (e.g. -lfoo -lbar)", $libs_guess); print <splitpath( $lib ); $ref->{libpath} = File::Spec->canonpath(File::Spec->catpath($volume, $directories)); $ref->{libpython} = $file; print <{incpath} = $inc; } #============================================================================ # Python libraries to look for #============================================================================ sub show_python_libs { my $ref = shift; my $exe = $ref->{path}; # Convert the exe into a glob where we might find a library: $exe =~ s|[^/]+$||; $exe .= "../lib/python*/config/libpython*"; my @py_libs = ( (map { $exe . $_ } '.a', '.so', '.lib'), '/usr/lib64/libpython*.a', '/usr/lib64/libpython*.so', '/usr/lib/libpython*.a', '/usr/lib/libpython*.so', '/usr/lib64/python*/config/libpython*.a', '/usr/lib64/python*/config/libpython*.so', '/usr/lib/python*/config/libpython*.a', '/usr/lib/python*/config/libpython*.so', '/usr/local/lib/libpython*.a', '/usr/local/lib/libpython*.so', '/usr/local/ActivePython-*/lib/python*/config/libpython*.a', '/usr/local/ActivePython-*/lib/python*/config/libpython*.so', # Win32 support 'C:/Python*/libs/python*.lib', 'C:/Program Files/Python*/libs/python*.lib', ); my (@found, %found); push @found, grep { -f && $found{abspath($_)}++ == 0 } glob for @py_libs; @found = sort map { abspath($_) } @found; my $num = '1'; print "\t " . $num++ . ") " . $_ . "\n" for @found; print "\n"; return @found; } #============================================================================ # Python include files to look for #============================================================================ sub show_python_incs { my $ref = shift; my $exe = $ref->{path}; # Convert the exe into a glob where we might find the includes: $exe =~ s|[^/]+$||; $exe .= "../include/python*"; my @py_incs; if ($^O eq "MSWin32") { @py_incs = ( 'C:\Python*\include', 'C:\Program Files\Python*\include' ); } else { @py_incs = ( $exe, '/usr/local/ActivePython-*/include/python*', '/usr/include/python*', '/usr/local/include/python*', ); } my (@found, %found); push @found, grep { -d && $found{abspath($_)}++ == 0 } glob for @py_incs; @found = sort map { abspath($_) } @found; my $num = 1; print "\t " . $num++ . ") " . $_ . "\n" for @found; print "\n"; return @found; } # This can deal with files as well as directories sub abspath { use Cwd qw(abs_path); my ($path, $file) = shift; if (-f $path) { my @parts = File::Spec->splitpath($path); $path = File::Spec->canonpath(File::Spec->catpath(@parts[0..1])); $file = $parts[-1]; } $path = abs_path($path); return defined $file ? File::Spec->catfile($path, $file) : $path; } sub debug_flag { return $gdb if $gdb; $Config{osname} eq 'MSWin32' ? return '-Zi' : return '-g'; } sub usage { print <<'END'; Options: -gdb: Turn on compiler's debugging flag (use my guess). -gdb=x Pass your own debugging flag, not mine. -debug: Turn on many diagnostic print statements inside Inline::Python. This option is useful for tracing the execution path when debugging. -help: This output. END # ' stupid vim exit 0; } Inline-Python-0.58/PaxHeaders/py2pl.h0000644000000000000000000000013013760161763014450 xustar0029 mtime=1606476787.75938159 29 atime=1644320509.69458481 30 ctime=1747225338.910792024 Inline-Python-0.58/py2pl.h0000644000076400001440000000144613760161763014315 0ustar00nineusers#ifndef PY2PL_H #define PY2PL_H extern SV* Py2Pl (PyObject * const obj); extern PyObject *Pl2Py(SV * const obj); extern void croak_python_exception(); extern SV* py_true; extern SV* py_false; extern PyObject *PyExc_Perl; #if PY_MAJOR_VERSION < 3 #define PY_INSTANCE_CHECK(obj) PyInstance_Check((obj)) #define PY_IS_STRING(obj) (PyString_Check((obj)) || PyUnicode_Check((obj))) #else #define PY_INSTANCE_CHECK(obj) 0 #define PY_IS_STRING(obj) (PyBytes_Check((obj)) || PyUnicode_Check((obj))) #endif #define PY_IS_OBJECT(obj) \ (((obj)->ob_type->tp_flags & Py_TPFLAGS_HEAPTYPE) \ || PY_INSTANCE_CHECK((obj)) \ || (! is_string && PyMapping_Check((obj)) && ((obj)->ob_type != &PyDict_Type) && \ ((obj)->ob_type != &PyList_Type) && ((obj)->ob_type != &PyTuple_Type)) ) #endif Inline-Python-0.58/PaxHeaders/README0000644000000000000000000000013212415322646014106 xustar0030 mtime=1412801958.513690247 30 atime=1645882208.684095371 30 ctime=1747225338.911007937 Inline-Python-0.58/README0000644000076400001440000000403512415322646013746 0ustar00nineusersINTRODUCTION: Inline::Python -- Write Perl subs and classes in Python. Inline::Python lets you write Perl subroutines and classes in Python. You don't have to use any funky techniques for sharing most types of data between the two languages, either. Inline::Python comes with its own data translation service. It converts any Python structures it knows about into Perl structures, and vice versa. Example: use Inline Python => <<'END'; def JAxH(x): return "Just Another %s Hacker" % x END print JAxH('Inline'), "\n"; When run, this complete program prints: Just Another Inline Hacker. The almost-one-line version is: perl -le 'use Inline Python=>q{def JAxH(x):return"Just Another %s Hacker"%x};print JAxH+Inline' ------------------------------------------------------------------------------- INSTALLATION: This module requires Inline.pm version 0.46 or higher to be installed. In addition, you need Python 2.5 or greater installed. Python 2.6, Python 3.2 or greater is recommended. Python has to be configured with --enable-shared. Linux distribution packages should be fine, but keep it in mind if you compile Python yourself. To install Inline::Python do this: perl Makefile.PL make make test make install (On ActivePerl for MSWin32, use nmake instead of make.) You have to 'make install' before you can run it successfully. ------------------------------------------------------------------------------- INFORMATION: - For more information on Inline::Python see 'perldoc Inline::Python'. - For information about Inline.pm, see 'perldoc Inline'. - For information on using Python or the Python C API, visit http://www.python.org. The Inline::Python mailing list is inline@perl.org. Send mail to inline-subscribe@perl.org to subscribe. Please send questions and comments to "Stefan Seifert" Copyright (c) 2000, Neil Watkiss. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. (see http://www.perl.com/perl/misc/Artistic.html) Inline-Python-0.58/PaxHeaders/TESTED0000644000000000000000000000013211326320221014124 xustar0030 mtime=1264165009.013794163 30 atime=1657297446.218752237 30 ctime=1747225338.911025671 Inline-Python-0.58/TESTED0000644000076400001440000000211411326320221013760 0ustar00nineusersThis is a list I try to keep as up-to-date as possible with the state of the module. This list is known to be up to date with Inline::Python version 0.20. Key to reading this list: ACROSS: Python Version DOWN: Perl Version CELLS: tester's initials #============================================================================ Linux/Alpha/GCC #============================================================================ 1.5.2 1.6.1 2.0.1 2.1 AP203 AP210 5.005 NW NW NW NW NW NW 5.6.0 NW NW NW NW NW NW 5.6.1 NW NW NW NW NW NW 5.7.0 NW NW NW NW NW NW 5.7.1 NW NW NW NW NW NW AP623 NW NW NW NW NW NW AP626 NW NW NW NW NW NW #============================================================================ Linux/i686/GCC #============================================================================ 1.5.2 1.6 2.0 2.1 AP2.0 AP2.1 5.005 NW NW 5.6.0 5.6.1 5.7.0 AP623 NW NW AP626 NW NW #============================================================================ Who is this tester dude? NW Neil Watkiss NEILW@cpan.org BI Brian Ingerson INGY@cpan.org KS Ken Simpson KenS@ActiveState.com Inline-Python-0.58/PaxHeaders/ToDo0000644000000000000000000000013211326320221014001 xustar0030 mtime=1264165009.013794163 30 atime=1657297446.218752237 30 ctime=1747225338.911043095 Inline-Python-0.58/ToDo0000644000076400001440000000222311326320221013636 0ustar00nineusersComplete: +complete magic manipulation for Python objects entering perl +add __getattr__ method to modify evaluation flags for PerlSub_object: f = perl.mysub; f.flags = f.G_EVAL | f.G_SCALAR | f.G_DISCARD +support method call syntax in PerlSub_object +add "special" functions for perl: eval(), print(), use() +add Inline::Python::loadpkg("python package") => done: Inline::Python::py_bind_class() +make auto-binding to perl packages work properly. +make py_eval return the results of running the code, not 1 or 0 -make perlmodule.c work alone, as a Python extension module -add special case for constructors, to pass the package name as the first argument. How easy is that to discover? -write documentation about the perlmodule in Python-land -add the ability for perl.eval to evaluate in "main" package, and perl.Foo.eval to evaluate in the "main::Foo" package. Could be very useful? -add check for whether perl is threaded to Makefile.PL. Python is always threaded, so it should add -lpthread to the build if Perl isn't built with ithreads. Only if the auto-discovery failed. -add an option to generate Perl bytecode directly (must be specified by the user) Inline-Python-0.58/PaxHeaders/MANIFEST0000644000000000000000000000012015011105373014343 xustar0030 mtime=1747225339.014433481 20 atime=1681469246 30 ctime=1747225339.014433481 Inline-Python-0.58/MANIFEST0000644000076400001440000000150515011105373014205 0ustar00nineusersChanges Makefile.PL Makefile.pre.in MANIFEST perlmodule.c perlmodule.h py2pl.c py2pl.h Python.pm Python.pod Python.xs README Setup.in t/00init.t t/01testpl.t t/02testpl.t t/03parse.t t/04func.t t/05JAxH.t t/06dict.t t/07nherit.t t/08ipyobj.t t/09bind.t t/10pyeval.t t/11factor.t t/12evnodd.t t/13fibbon.t t/14study.t t/15anon.t t/16evalpy.t t/17once.t t/18newclass.t t/19testref.t t/20unicode.t t/21arrayref.t t/22int.t t/23getattr.t t/24getitem.t t/25py_sub.t t/26undef.t t/27pyattrs.t t/28exception.t t/29named_params.t t/30floats.t t/31stringification.t t/32boolean.t t/33reinit.t t/34env.t t/35dictunicodememleak.t t/36utfstring.t t/cmp.t TESTED ToDo util.c util.h META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Inline-Python-0.58/PaxHeaders/perlmodule.c0000644000000000000000000000013115011104521015522 xustar0030 mtime=1747224913.111747192 30 atime=1747224913.111747192 29 ctime=1747225338.91118682 Inline-Python-0.58/perlmodule.c0000644000076400001440000010644715011104521015375 0ustar00nineusers/* vim: set shiftwidth=4 softtabstop=4 expandtab: */ #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "Python.h" #include "perlmodule.h" #include "py2pl.h" #include "util.h" #ifdef __cplusplus } #endif #ifdef CREATE_PERL static PerlInterpreter *my_perl; #endif staticforward PyObject * special_perl_eval(PyObject *, PyObject *); staticforward PyObject * special_perl_use(PyObject *, PyObject *); staticforward PyObject * special_perl_require(PyObject *, PyObject *); /*************************************** * METHOD DECLARATIONS * ***************************************/ PyObject * newPerlPkg_object(PyObject *base, PyObject *pkg); staticforward void PerlPkg_dealloc(PerlPkg_object *self); staticforward PyObject * PerlPkg_repr(PerlPkg_object *self, PyObject *args); staticforward PyObject * PerlPkg_getattr(PerlPkg_object *self, char *name); PyObject * newPerlObj_object(SV *obj, PyObject *pkg); staticforward void PerlObj_dealloc(PerlObj_object *self); staticforward PyObject * PerlObj_repr(PerlObj_object *self); staticforward PyObject * PerlObj_str(PerlObj_object *self); staticforward PyObject * PerlObj_call(PerlObj_object *self, PyObject *args, PyObject *kw); staticforward PyObject * PerlObj_getattr(PerlObj_object *self, char *name); staticforward PyObject * PerlObj_mp_subscript(PerlObj_object *self, PyObject *key); PyObject * newPerlSub_object(PyObject *base, PyObject *pkg, SV *cv); PyObject * newPerlMethod_object(PyObject *base, PyObject *pkg, SV *obj); PyObject * newPerlCfun_object(PyObject* (*cfun)(PyObject *self, PyObject *args)); staticforward void PerlSub_dealloc(PerlSub_object *self); staticforward PyObject * PerlSub_call(PerlSub_object *self, PyObject *args, PyObject *kw); staticforward PyObject * PerlSub_repr(PerlSub_object *self, PyObject *args); staticforward PyObject * PerlSub_getattr(PerlSub_object *self, char *name); staticforward int PerlSub_setattr(PerlSub_object *self, char *name, PyObject *value); /************************************** * METHOD DEFINITIONS * **************************************/ /* methods of _perl_pkg */ PyObject * newPerlPkg_object(PyObject *base, PyObject *package) { PerlPkg_object * const self = PyObject_NEW(PerlPkg_object, &PerlPkg_type); #if PY_MAJOR_VERSION >= 3 char * const bs = PyBytes_AsString(base); char * const pkg = PyBytes_AsString(package); #else char * const bs = PyString_AsString(base); char * const pkg = PyString_AsString(package); #endif char * const str = (char*)malloc((strlen(bs) + strlen(pkg) + strlen("::") + 1) * sizeof(char)); if(!self) { free(str); PyErr_Format(PyExc_MemoryError, "Couldn't create Perl Package object.\n"); return NULL; } sprintf(str, "%s%s::", bs, pkg); Py_INCREF(base); Py_INCREF(package); self->base = base; self->pkg = package; #if PY_MAJOR_VERSION >= 3 self->full = PyBytes_FromString(str); #else self->full = PyString_FromString(str); #endif free(str); return (PyObject*)self; } static void PerlPkg_dealloc(PerlPkg_object *self) { Py_XDECREF(self->pkg); Py_XDECREF(self->base); Py_XDECREF(self->full); PyObject_Del(self); } static PyObject * PerlPkg_repr(PerlPkg_object *self, PyObject *args) { PyObject *s; char * const str = (char*)malloc((strlen("") + PyObject_Length(self->full) + 1) * sizeof(char)); #if PY_MAJOR_VERSION >= 3 sprintf(str, "", PyBytes_AsString(self->full)); s = PyUnicode_FromString(str); #else sprintf(str, "", PyString_AsString(self->full)); s = PyString_FromString(str); #endif free(str); return s; } static PyObject * PerlPkg_getattr(PerlPkg_object *self, char *name) { /*** Python Methods ***/ if (strcmp(name,"__methods__") == 0) { return get_perl_pkg_subs(self->full); } else if (strcmp(name,"__members__") == 0) { PyObject *retval = PyList_New(0); return retval ? retval : NULL; } else if (strcmp(name,"__dict__") == 0) { PyObject *retval = PyDict_New(); return retval ? retval : NULL; } /*** Special Names (but only for 'main' package) ***/ else if (PKG_EQ(self, "main::") && strcmp(name,"eval")==0) { /* return a PerlSub_object which just does: eval(@_) */ return newPerlCfun_object(&special_perl_eval); } else if (PKG_EQ(self, "main::") && strcmp(name,"use")==0) { /* return a PerlSub_object which just does: * eval("use $_[0]; $_[0]->import") */ return newPerlCfun_object(&special_perl_use); } else if (PKG_EQ(self, "main::") && strcmp(name,"require")==0) { /* return a PerlSub_object which just does: * eval("require $_[0];") */ return newPerlCfun_object(&special_perl_require); } /*** A Perl Package, Sub, or Method ***/ else { #if PY_MAJOR_VERSION >= 3 PyObject * const tmp = PyBytes_FromString(name); char * const full_c = PyBytes_AsString(self->full); #else PyObject * const tmp = PyString_FromString(name); char * const full_c = PyString_AsString(self->full); #endif PyObject * const res = perl_pkg_exists(full_c, name) ? newPerlPkg_object(self->full, tmp) : newPerlSub_object(self->full, tmp, NULL); Py_DECREF(tmp); return res; } } static PyObject * module_dir(PerlPkg_object *self, PyObject *args) { return get_perl_pkg_subs(self->full); } static struct PyMethodDef PerlPkg_methods[] = { {"__dir__", (PyCFunction)module_dir, METH_NOARGS, NULL}, {NULL} /* sentinel */ }; /* doc string */ static char PerlPkg_type__doc__[] = "_perl_pkg -- Wrap a Perl package in a Python class" ; /* type definition */ PyTypeObject PerlPkg_type = { PyVarObject_HEAD_INIT(NULL, 0) "_perl_pkg", /*tp_name*/ sizeof(PerlPkg_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PerlPkg_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)PerlPkg_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ #if PY_MAJOR_VERSION < 3 (cmpfunc)0, /*tp_compare*/ #else 0, /*reserved*/ #endif (reprfunc)PerlPkg_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)PerlPkg_repr, /*tp_str*/ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ PerlPkg_type__doc__, /* Documentation string */ (traverseproc)0, /* tp_traverse */ (inquiry)0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ PerlPkg_methods, /* tp_methods */ }; /* methods of _perl_obj */ PyObject * newPerlObj_object(SV *obj, PyObject *package) { PerlObj_object * const self = PyObject_NEW(PerlObj_object, &PerlObj_type); if(!self) { PyErr_Format(PyExc_MemoryError, "Couldn't create Perl Obj object.\n"); return NULL; } Py_INCREF(package); SvREFCNT_inc(obj); self->pkg = package; self->obj = obj; return (PyObject*)self; } static void PerlObj_dealloc(PerlObj_object *self) { Py_XDECREF(self->pkg); if (self->obj) sv_2mortal(self->obj); /* mortal instead of DECREF. Object might be return value */ PyObject_Del(self); } static PyObject * PerlObj_repr(PerlObj_object *self) { PyObject *s; char * const str = (char*)malloc((strlen("") + PyObject_Length(self->pkg) + 1) * sizeof(char)); #if PY_MAJOR_VERSION >= 3 sprintf(str, "", PyBytes_AsString(self->pkg)); s = PyUnicode_FromString(str); #else sprintf(str, "", PyString_AsString(self->pkg)); s = PyString_FromString(str); #endif free(str); return s; } static PyObject * PerlObj_str(PerlObj_object *self) { STRLEN len; SV* const sv = ((SvTHINKFIRST(self->obj) && !SvIsCOW(self->obj)) || isGV_with_GP(self->obj)) ? sv_mortalcopy(self->obj) : self->obj; char * const str = SvPVutf8(sv, len); return PyUnicode_DecodeUTF8(str, len, "replace"); } static PyObject * PerlObj_getattr(PerlObj_object *self, char *name) { PyObject *retval = NULL; if (strcmp(name,"__methods__") == 0) { return get_perl_pkg_subs(self->pkg); } else if (strcmp(name,"__members__") == 0) { retval = PyList_New(0); return retval ? retval : NULL; } else if (strcmp(name,"__dict__") == 0) { retval = PyDict_New(); return retval ? retval : NULL; } else { SV * const obj = (SV*)SvRV(self->obj); HV * const pkg = SvSTASH(obj); /* probably a request for a method */ GV * const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, name, TRUE); if (gv && isGV(gv)) { #if PY_MAJOR_VERSION >= 3 PyObject * const py_name = PyBytes_FromString(name); #else PyObject * const py_name = PyString_FromString(name); #endif retval = newPerlMethod_object(self->pkg, py_name, self->obj); Py_DECREF(py_name); } else { /* search for an attribute */ /* check if the object supports the __getattr__ protocol */ GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, "__getattr__", FALSE); if (gv && isGV(gv)) { /* __getattr__ supported! Let's see if an attribute is found. */ dSP; ENTER; SAVETMPS; SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv))); PUSHMARK(SP); XPUSHs(self->obj); XPUSHs(sv_2mortal(newSVpv(name, 0))); PUTBACK; /* array context needed, so it's possible to return nothing (not even undef) if the attribute does not exist */ int const count = call_sv(rv, G_ARRAY); SPAGAIN; if (count > 1) croak("__getattr__ may only return a single scalar or an empty list!\n"); if (count == 1) { /* attribute exists! Now give the value back to Python */ retval = Pl2Py(POPs); } PUTBACK; FREETMPS; LEAVE; } if (! retval) { /* give up and raise a AttributeError */ char attribute_error[strlen(name) + 21]; sprintf(attribute_error, "attribute %s not found", name); PyErr_SetString(PyExc_AttributeError, attribute_error); } } return retval; } } static PyObject* PerlObj_mp_subscript(PerlObj_object *self, PyObject *key) { /* check if the object supports the __getitem__ protocol */ PyObject *item = NULL; PyObject *key_str = PyObject_Str(key); /* new reference */ #if PY_MAJOR_VERSION >= 3 PyObject* string_as_bytes = PyUnicode_AsUTF8String(key_str);/* new reference */ char * const name = PyBytes_AsString(string_as_bytes); #else char * const name = PyString_AsString(key_str); #endif SV * const obj = (SV*)SvRV(self->obj); HV * const pkg = SvSTASH(obj); GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, "__getitem__", FALSE); if (gv && isGV(gv)) { /* __getitem__ supported! Let's see if the key is found. */ dSP; ENTER; SAVETMPS; SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv))); PUSHMARK(SP); XPUSHs(self->obj); XPUSHs(sv_2mortal(newSVpv(name, 0))); PUTBACK; /* array context needed, so it's possible to return nothing (not even undef) if the attribute does not exist */ int const count = call_sv(rv, G_ARRAY); SPAGAIN; if (count > 1) croak("__getitem__ may only return a single scalar or an empty list!\n"); if (count == 1) { /* item exists! Now give the value back to Python */ item = Pl2Py(POPs); } PUTBACK; FREETMPS; LEAVE; if (count == 0) { char attribute_error[strlen(name) + 21]; sprintf(attribute_error, "attribute %s not found", name); PyErr_SetString(PyExc_KeyError, attribute_error); } } else { PyErr_Format(PyExc_TypeError, "'%.200s' object is unsubscriptable", Py_TYPE(self)->tp_name); } #if PY_MAJOR_VERSION >= 3 Py_DECREF(string_as_bytes); #endif Py_DECREF(key_str); return item; } static PyObject * PerlObj_call(PerlObj_object *self, PyObject *args, PyObject *kw) { dSP; int i; int const len = PyObject_Length(args); int count; PyObject *retval; ENTER; SAVETMPS; PUSHMARK(SP); if (self->obj) XPUSHs(self->obj); if (kw) { /* if keyword arguments are present, positional arguments get pushed as into an arrayref */ AV * const positional = newAV(); for (i=0; iobj, G_EVAL); SPAGAIN; Py_DECREF(self); /* release*/ if (SvTRUE(ERRSV)) { PyObject *exc = Pl2Py(ERRSV); PyErr_SetObject(PyExc_Perl, exc); ERRSV = NULL; return NULL; } /* what to return? */ if (count == 0) { Py_INCREF(Py_None); retval = Py_None; } else if (count == 1) { retval = Pl2Py(POPs); } else { AV * const lst = newAV(); av_extend(lst, count); for (i = count - 1; i >= 0; i--) { av_store(lst, i, SvREFCNT_inc(POPs)); } SV * const rv_lst = newRV_inc((SV*)lst); retval = Pl2Py(rv_lst); SvREFCNT_dec(rv_lst); sv_2mortal((SV*)lst); /* this will get killed shortly */ } PUTBACK; FREETMPS; LEAVE; return retval; } #if PY_MAJOR_VERSION >= 3 // Python 3 rich compare static PyObject* PerlObj_richcompare(PerlObj_object *o1, PerlObj_object *o2, int op) { /* Unable to compare different a Perl object with something else */ if (!PerlObjObject_Check(o1) || !PerlObjObject_Check(o2)) { Py_RETURN_FALSE; } /* check if the object supports the __cmp__ protocol */ SV * const obj = (SV*)SvRV(o1->obj); HV * const pkg = SvSTASH(obj); const char* method_name = NULL; switch (op) { case Py_LT: method_name = "__lt__"; break; case Py_LE: method_name = "__le__"; break; case Py_EQ: method_name = "__eq__"; break; case Py_NE: method_name = "__ne__"; break; case Py_GT: method_name = "__gt__"; break; case Py_GE: method_name = "__ge__"; break; } GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, method_name, FALSE); if (gv && isGV(gv)) { int retval = 1; dSP; ENTER; SAVETMPS; SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv))); PUSHMARK(SP); XPUSHs(o1->obj); XPUSHs(o2->obj); PUTBACK; int const count = call_sv(rv, G_SCALAR); SPAGAIN; if (count > 1) croak("%s may only return a single scalar!\n", method_name); if (count == 1) { /* attribute exists! Now give the value back to Python */ SV * const result = POPs; if(!SvIOK(result)) croak("%s must return an integer!\n", method_name); retval = SvIV(result); } PUTBACK; FREETMPS; LEAVE; if(retval == 0) {Py_RETURN_TRUE;} Py_RETURN_FALSE; } if (SvRV(o1->obj) == SvRV(o2->obj)) {/* just compare the dereferenced object pointers */ if(op == Py_EQ) {Py_RETURN_TRUE;} Py_RETURN_FALSE; } if (SvRV(o1->obj) != SvRV(o2->obj)) { if(op == Py_NE) {Py_RETURN_TRUE;} Py_RETURN_FALSE; } Py_RETURN_NOTIMPLEMENTED; } #else // Python 2 __cmp__ method static int PerlObj_compare(PerlObj_object *o1, PerlObj_object *o2) { /* check if the object supports the __cmp__ protocol */ SV * const obj = (SV*)SvRV(o1->obj); HV * const pkg = SvSTASH(obj); GV* const gv = Perl_gv_fetchmethod_autoload(aTHX_ pkg, "__cmp__", FALSE); if (gv && isGV(gv)) { int retval = 1; dSP; ENTER; SAVETMPS; SV * const rv = sv_2mortal(newRV((SV*)GvCV(gv))); PUSHMARK(SP); XPUSHs(o1->obj); XPUSHs(o2->obj); PUTBACK; int const count = call_sv(rv, G_SCALAR); SPAGAIN; if (count > 1) croak("__cmp__ may only return a single scalar!\n"); if (count == 1) { /* attribute exists! Now give the value back to Python */ SV * const result = POPs; if(!SvIOK(result)) croak("__cmp__ must return an integer!\n"); retval = SvIV(result); } PUTBACK; FREETMPS; LEAVE; return retval; } if (SvRV(o1->obj) == SvRV(o2->obj)) /* just compare the dereferenced object pointers */ return 0; return 1; } #endif static PyObject * object_dir(PerlObj_object *self, PyObject *args) { return get_perl_pkg_subs(self->pkg); } static struct PyMethodDef PerlObj_methods[] = { {"__dir__", (PyCFunction)object_dir, METH_NOARGS, NULL}, {NULL} /* sentinel */ }; /* doc string */ static char PerlObj_type__doc__[] = "_perl_obj -- Wrap a Perl object in a Python class" ; PyMappingMethods mp_methods = { (lenfunc) 0, /*mp_length*/ (binaryfunc) PerlObj_mp_subscript, /*mp_subscript*/ (objobjargproc) 0, /*mp_ass_subscript*/ }; /* type definition */ PyTypeObject PerlObj_type = { PyVarObject_HEAD_INIT(NULL, 0) "_perl_obj", /*tp_name*/ sizeof(PerlObj_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PerlObj_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)PerlObj_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ #if PY_MAJOR_VERSION < 3 (cmpfunc)PerlObj_compare, /*tp_compare*/ #else 0, /*reserved*/ #endif (reprfunc)PerlObj_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &mp_methods, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)PerlObj_call, /*tp_call*/ (reprfunc)PerlObj_str, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, PerlObj_type__doc__, /* Documentation string */ (traverseproc)0, /* tp_traverse */ (inquiry)0, /* tp_clear */ #if PY_MAJOR_VERSION < 3 0, /* unused */ #else (richcmpfunc)PerlObj_richcompare, /* tp_richcompare */ #endif 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ PerlObj_methods, /* tp_methods */ }; /* methods of _perl_sub */ PyObject * newPerlSub_object(PyObject *package, PyObject *sub, SV *cv) { PerlSub_object * const self = PyObject_NEW(PerlSub_object, &PerlSub_type); char *str = NULL; if(!self) { PyErr_Format(PyExc_MemoryError, "Couldn't create Perl Sub object.\n"); return NULL; } /* initialize the name of the sub or method */ if (package && sub) { str = malloc((PyObject_Length(package) + PyObject_Length(sub) + 1) *sizeof(char)); #if PY_MAJOR_VERSION >= 3 sprintf(str, "%s%s", PyBytes_AsString(package), PyBytes_AsString(sub)); #else sprintf(str, "%s%s", PyString_AsString(package), PyString_AsString(sub)); #endif Py_INCREF(sub); Py_INCREF(package); self->sub = sub; self->pkg = package; #if PY_MAJOR_VERSION >= 3 self->full = PyBytes_FromString(str); #else self->full = PyString_FromString(str); #endif } else { self->sub = NULL; self->pkg = NULL; self->full = NULL; } /* we don't have to check for errors because we shouldn't have been * created unless perl_get_cv worked once. */ if (cv) { self->ref = cv; self->conf = 1; } else if (str) { self->ref = (SV*)perl_get_cv(str,0); /* can return NULL if not found */ self->conf = self->ref ? 1 : 0; } else { croak("Can't call newPerlSub_object() with all NULL arguments!\n"); } SvREFCNT_inc(self->ref); /* quite important -- otherwise we lose it */ self->obj = NULL; self->flgs = G_ARRAY; self->cfun = 0; if (str) free(str); return (PyObject*)self; } PyObject * newPerlMethod_object(PyObject *package, PyObject *sub, SV *obj) { PerlSub_object * const self = (PerlSub_object*)newPerlSub_object(package, sub, NULL); self->obj = obj; SvREFCNT_inc(obj); return (PyObject*)self; } PyObject * newPerlCfun_object(PyObject* (*cfun)(PyObject *self, PyObject *args)) { PerlSub_object * const self = PyObject_NEW(PerlSub_object, &PerlSub_type); self->pkg = NULL; self->sub = NULL; self->full = NULL; self->ref = NULL; self->obj = NULL; self->flgs = 0; self->cfun = cfun; return (PyObject *)self; } static void PerlSub_dealloc(PerlSub_object *self) { Py_XDECREF(self->sub); Py_XDECREF(self->pkg); Py_XDECREF(self->full); if (self->obj) SvREFCNT_dec(self->obj); if (self->ref) SvREFCNT_dec(self->ref); PyObject_Del(self); } static PyObject * PerlSub_call(PerlSub_object *self, PyObject *args, PyObject *kw) { dSP; int i; int const len = PyObject_Length(args); int count; PyObject *retval; /* if this wraps a C function, execute that */ if (self->cfun) return self->cfun((PyObject*)self, args); ENTER; SAVETMPS; PUSHMARK(SP); if (self->obj) XPUSHs(self->obj); if (kw) { /* if keyword arguments are present, positional arguments get pushed as into an arrayref */ AV * const positional = newAV(); for (i=0; iref) count = perl_call_sv(self->ref, self->flgs | G_EVAL); else if (self->sub && self->obj) #if PY_MAJOR_VERSION >= 3 count = perl_call_method(PyBytes_AsString(self->sub), self->flgs | G_EVAL); #else count = perl_call_method(PyString_AsString(self->sub), self->flgs | G_EVAL); #endif else { croak("Error: PerlSub called, but no C function, sub, or name found!\n"); } SPAGAIN; Py_DECREF(self); /* release*/ if (SvTRUE(ERRSV)) { PyObject *exc = Pl2Py(ERRSV); PyErr_SetObject(PyExc_Perl, exc); ERRSV = NULL; return NULL; } /* what to return? */ if (count == 0) { Py_INCREF(Py_None); retval = Py_None; } else if (count == 1) { retval = Pl2Py(POPs); } else { AV * const lst = newAV(); av_extend(lst, count); for (i = count - 1; i >= 0; i--) { av_store(lst, i, SvREFCNT_inc(POPs)); } SV * const rv_lst = newRV_inc((SV*)lst); retval = Pl2Py(rv_lst); SvREFCNT_dec(rv_lst); sv_2mortal((SV*)lst); /* this will get killed shortly */ } PUTBACK; FREETMPS; LEAVE; return retval; } static PyObject * PerlSub_repr(PerlSub_object *self, PyObject *args) { PyObject *s; char * const str = (char*)malloc((strlen("") + (self->full ? PyObject_Length(self->full) : strlen("anonymous")) + 1) * sizeof(char)); #if PY_MAJOR_VERSION >= 3 sprintf(str, "", (self->full ? PyBytes_AsString(self->full) : "anonymous")); s = PyUnicode_FromString(str); #else sprintf(str, "", (self->full ? PyString_AsString(self->full) : "anonymous")); s = PyString_FromString(str); #endif free(str); return s; } static PyObject * PerlSub_getattr(PerlSub_object *self, char *name) { PyObject *retval = NULL; if (strcmp(name,"flags")==0) { retval = PyInt_FromLong((long)self->flgs); } else if (strcmp(name,"G_VOID")==0) { retval = PyInt_FromLong((long)G_VOID); } else if (strcmp(name,"G_SCALAR")==0) { retval = PyInt_FromLong((long)G_SCALAR); } else if (strcmp(name,"G_ARRAY")==0) { retval = PyInt_FromLong((long)G_ARRAY); } else if (strcmp(name,"G_DISCARD")==0) { retval = PyInt_FromLong((long)G_DISCARD); } else if (strcmp(name,"G_NOARGS")==0) { retval = PyInt_FromLong((long)G_NOARGS); } else if (strcmp(name,"G_EVAL")==0) { retval = PyInt_FromLong((long)G_EVAL); } else if (strcmp(name,"G_KEEPERR")==0) { retval = PyInt_FromLong((long)G_KEEPERR); } else { PyErr_Format(PyExc_AttributeError, "Attribute '%s' not found for Perl sub '%s'", name, #if PY_MAJOR_VERSION < 3 (self->full ? PyString_AsString(self->full) : (self->pkg ? PyString_AsString(self->pkg) : "")) #else (self->full ? PyBytes_AsString(self->full) : (self->pkg ? PyBytes_AsString(self->pkg) : "")) #endif ); retval = NULL; } return retval; } static int PerlSub_setattr(PerlSub_object *self, char *name, PyObject *v) { if (strcmp(name, "flags")==0 && PyInt_Check(v)) { self->flgs = (int)PyInt_AsLong(v); return 0; /* success */ } else if (strcmp(name,"flags")==0) { PyErr_Format(PyExc_TypeError, "'flags' can only be set from an integer. '%s'", #if PY_MAJOR_VERSION < 3 (self->pkg ? PyString_AsString(self->pkg) : "")); #else (self->pkg ? PyBytes_AsString(self->pkg) : "")); #endif return -1; /* failure */ } else { PyErr_Format(PyExc_AttributeError, "Attribute '%s' not found for Perl sub '%s'", name, #if PY_MAJOR_VERSION < 3 (self->full ? PyString_AsString(self->full) : (self->pkg ? PyString_AsString(self->pkg) : "")) #else (self->full ? PyBytes_AsString(self->full) : (self->pkg ? PyBytes_AsString(self->pkg) : "")) #endif ); return -1; /* failure */ } } /* doc string */ static char PerlSub_type__doc__[] = "_perl_sub -- Wrap a Perl sub in a Python class" ; /* type definition */ PyTypeObject PerlSub_type = { PyVarObject_HEAD_INIT(NULL, 0) "_perl_sub", /*tp_name*/ sizeof(PerlSub_object), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)PerlSub_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)PerlSub_getattr, /*tp_getattr*/ (setattrfunc)PerlSub_setattr, /*tp_setattr*/ #if PY_MAJOR_VERSION < 3 (cmpfunc)0, /*tp_compare*/ #else 0, /*reserved*/ #endif (reprfunc)PerlSub_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)PerlSub_call, /*tp_call*/ (reprfunc)PerlSub_repr, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, PerlSub_type__doc__, /* Documentation string */ }; /* no module-public functions */ static PyMethodDef perl_functions[] = { {NULL, NULL} /* sentinel */ }; static PyObject * special_perl_eval(PyObject *ignored, PyObject *args) { dSP; SV *code; int i; int count; PyObject *retval; PyObject * const s = PyTuple_GetItem(args, 0); #if PY_MAJOR_VERSION >= 3 int is_string = PyBytes_Check(s) || PyUnicode_Check(s); #else int is_string = PyString_Check(s); #endif if(!is_string) { return NULL; } ENTER; SAVETMPS; /* not necessary -- but why not? */ PUSHMARK(SP); PUTBACK; /* run the anonymous subroutine under G_EVAL mode */ #if PY_MAJOR_VERSION >= 3 PyObject* s_bytes = 0; char* s_c_bytes = 0; if(PyUnicode_Check(s)) { s_bytes = PyUnicode_AsUTF8String(s); s_c_bytes = PyBytes_AsString(s_bytes); } else s_c_bytes = PyBytes_AsString(s); #else char* s_c_bytes = PyString_AsString(s); #endif code = newSVpv(s_c_bytes,0); count = perl_eval_sv(code, G_EVAL); #if PY_MAJOR_VERSION >= 3 Py_XDECREF(s_bytes); #endif SPAGAIN; if (SvTRUE(ERRSV)) { warn("%s\n", SvPV_nolen(ERRSV)); } if (count == 0) { retval = Py_None; Py_INCREF(retval); } else if (count == 1) { SV * const s = POPs; retval = Pl2Py(s); } else { AV * const lst = newAV(); for (i=0; i= 3 int is_string = PyBytes_Check(s) || PyUnicode_Check(s); #else int is_string = PyString_Check(s); #endif if(!is_string) { return NULL; } #if PY_MAJOR_VERSION >= 3 PyObject* s_bytes = 0; char* s_c_bytes = 0; if(PyUnicode_Check(s)) { s_bytes = PyUnicode_AsUTF8String(s); s_c_bytes = PyBytes_AsString(s_bytes); } else s_c_bytes = PyBytes_AsString(s); #else char* s_c_bytes = PyString_AsString(s); #endif Printf(("calling use...'%s'\n", s_c_bytes)); str = malloc((strlen("use ") + PyObject_Length(s) + 1) * sizeof(char)); sprintf(str, "use %s", s_c_bytes); Printf(("eval-ing now!\n")); perl_eval_pv(str, TRUE); Printf(("'twas called!\n")); free(str); #if PY_MAJOR_VERSION >= 3 Py_XDECREF(s_bytes); #endif Py_INCREF(Py_None); return Py_None; } static PyObject * special_perl_require(PyObject *ignored, PyObject *args) { PyObject * const s = PyTuple_GetItem(args, 0); #if PY_MAJOR_VERSION >= 3 int is_string = PyBytes_Check(s) || PyUnicode_Check(s); #else int is_string = PyString_Check(s); #endif if(!is_string) { return NULL; } #if PY_MAJOR_VERSION >= 3 PyObject* s_bytes = 0; char* s_c_bytes = 0; if(PyUnicode_Check(s)) { s_bytes = PyUnicode_AsUTF8String(s); s_c_bytes = PyBytes_AsString(s_bytes); } else s_c_bytes = PyBytes_AsString(s); #else char* s_c_bytes = PyString_AsString(s); #endif perl_require_pv(s_c_bytes); #if PY_MAJOR_VERSION >= 3 Py_XDECREF(s_bytes); #endif Py_INCREF(Py_None); return Py_None; } #ifdef CREATE_PERL static void create_perl() { int argc = 1; char * const argv[] = { "perl" }; /* When we create a Perl interpreter from Python, we don't get to * dynamically load Perl modules unless that Python is patched, since * Python doesn't expose the LDGLOBAL flag, which is required. This * problem doesn't exist the other way because Perl exposes this * interface. * * For this reason I haven't bothered provided an xs_init function. */ my_perl = perl_alloc(); perl_construct(my_perl); perl_parse(my_perl, NULL, argc, argv, NULL); perl_run(my_perl); } #endif PyObject *PyExc_Perl; void initperl(void){ PyObject *m, *d, *p; #if PY_MAJOR_VERSION >= 3 PyObject *dummy1 = PyBytes_FromString(""), *dummy2 = PyBytes_FromString("main"); #else PyObject *dummy1 = PyString_FromString(""), *dummy2 = PyString_FromString("main"); #endif /* Initialize the type of the new type objects here; doing it here * is required for portability to Windows without requiring C++. */ #if PY_MAJOR_VERSION >= 3 PerlPkg_type.ob_base.ob_base.ob_type = &PyType_Type; PyType_Ready(&PerlPkg_type); PerlObj_type.ob_base.ob_base.ob_type = &PyType_Type; PyType_Ready(&PerlObj_type); PerlSub_type.ob_base.ob_base.ob_type = &PyType_Type; PyType_Ready(&PerlSub_type); #else PerlPkg_type.ob_type = &PyType_Type; PerlObj_type.ob_type = &PyType_Type; PerlSub_type.ob_type = &PyType_Type; #endif /* Create the module and add the functions */ #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef perl_module = { PyModuleDef_HEAD_INIT, "perl", "perl -- Access a Perl interpreter transparently", -1, /* m_size */ perl_functions, /* m_methods */ 0, /* m_reload */ 0, /* m_traverse */ 0, /* m_clear */ 0 /* m_free */ }; m = PyModule_Create(&perl_module); #else m = Py_InitModule4("perl", perl_functions, "perl -- Access a Perl interpreter transparently", (PyObject*)NULL, PYTHON_API_VERSION); #endif /* Now replace the package 'perl' with the 'perl' object */ m = PyImport_AddModule("sys"); d = PyModule_GetDict(m); d = PyDict_GetItemString(d, "modules"); p = newPerlPkg_object(dummy1, dummy2); PyDict_SetItemString(d, "perl", p); Py_DECREF(p); #ifdef CREATE_PERL create_perl(); #endif PyExc_Perl = PyErr_NewException("perl.Exception", NULL, NULL); Py_DECREF(dummy1); Py_DECREF(dummy2); } Inline-Python-0.58/PaxHeaders/util.h0000644000000000000000000000013212415322646014354 xustar0030 mtime=1412801958.514690258 30 atime=1645882208.708096256 30 ctime=1747225338.911379749 Inline-Python-0.58/util.h0000644000076400001440000000331012415322646014207 0ustar00nineusers/* vim: set expandtab shiftwidth=4 softtabstop=4 cinoptions='\:2=2': */ #ifndef __INL_PY_UTILS__ #define __INL_PY_UTILS__ #ifdef __cplusplus extern "C" { #endif /* Python 2 => 3 rename */ #if PY_MAJOR_VERSION >= 3 #define PyInt_FromLong PyLong_FromLong #define PyInt_AsLong PyLong_AsLong #define PyInt_Check PyLong_Check #define PyClass_Check PyType_Check #define staticforward static #define statichere static #endif #ifndef Py_REFCNT /* Python 2.5 does not define this */ #define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt) #endif /* Before Perl 5.6, this didn't exist */ #ifndef SvPV_nolen #define SvPV_nolen(sv) SvPV(sv,PL_na) #endif #ifndef pTHX_ # define pTHX_ # define aTHX_ # define pTHX # define aTHX #endif #ifdef I_PY_DEBUG #define Printf(x) printf x #else #define Printf(x) #endif /* This structure is used to distinguish Python objects from regular * Perl objects. It could also be used to store additional information * about the objects, if necessary. It is a private area -- untouchable * from perl-space. */ typedef struct { I32 key; /* to make sure it came from Inline */ } _inline_magic; #define INLINE_MAGIC_KEY 0x0DD515FD #define TUPLE_MAGIC_KEY 0x7475706C #define Inline_Magic_Key(mg_ptr) (((_inline_magic*)mg_ptr)->key) #define Inline_Magic_Check(mg_ptr) (Inline_Magic_Key(mg_ptr)==INLINE_MAGIC_KEY) extern PyObject * get_perl_pkg_subs(PyObject *); extern int perl_pkg_exists(char *, char *); extern PyObject * perl_sub_exists(PyObject *, PyObject *); extern int py_is_tuple(SV *arr); extern MGVTBL inline_mg_vtbl; /* This is called when Perl deallocates a PerlObj object */ extern int free_inline_py_obj(pTHX_ SV* obj, MAGIC *mg); #ifdef __cplusplus } #endif #endif Inline-Python-0.58/PaxHeaders/Setup.in0000644000000000000000000000013211326320221014641 xustar0030 mtime=1264165009.012794366 30 atime=1657297446.218752237 30 ctime=1747225338.911398735 Inline-Python-0.58/Setup.in0000644000076400001440000000006311326320221014476 0ustar00nineusers*shared* perl perlmodule.c py2pl.c util.c Python.c Inline-Python-0.58/PaxHeaders/Python.pod0000644000000000000000000000013212460241256015210 xustar0030 mtime=1421951662.532799576 30 atime=1644320509.690584666 30 ctime=1747225338.911464782 Inline-Python-0.58/Python.pod0000644000076400001440000005705112460241256015056 0ustar00nineusers=head1 NAME Inline::Python - Write Perl subs and classes in Python. =head1 SYNOPSIS print "9 + 16 = ", add(9, 16), "\n"; print "9 - 16 = ", subtract(9, 16), "\n"; use Inline Python => <<'END_OF_PYTHON_CODE'; def add(x,y): return x + y def subtract(x,y): return x - y END_OF_PYTHON_CODE =head1 DESCRIPTION The C module allows you to put Python source code directly "inline" in a Perl script or module. It sets up an in-process Python interpreter, runs your code, and then examines Python's symbol table for things to bind to Perl. The process of interrogating the Python interpreter for globals only occurs the first time you run your Python code. The namespace is cached, and subsequent calls use the cached version. This document describes C, the Perl package which gives you access to a Python interpreter. For lack of a better place to keep it, it also gives you instructions on how to use C, the Python package which gives you access to the Perl interpreter. =head1 WHAT'S NEW? Version 0.21 provides the ability to bind to 'new-style' classes (as defined by the python PEP's 252 and 253.) See L for details. See the L file for new features in recent versions. =head1 Using the Inline::Python Module Using Inline::Python will seem very similar to using another Inline language, thanks to Inline's consistent look and feel. This section will explain the different ways to use Inline::Python. For more details on C, see 'perldoc Inline'. =head2 Giving Your Source to Inline The most basic form for using C is this: use Inline Python => 'Python source code'; Of course, you can use Perl's "here document" style of quoting to make the code slightly easier to read: use Inline Python => <<'END'; Python source code goes here. END The source code can also be specified as a filename, a subroutine reference (sub routine should return source code), or an array reference (array contains lines of source code). The recommended way of using Inline is this: use Inline Python; ... __END__ __Python__ Python source code goes here. This information is detailed in 'perldoc Inline'. =head2 Importing Functions Maybe you have a whole library written in Python that only needs one entry point. You'll want to import that function. It's as easy as this: use Inline Python; doit(); __END__ __Python__ from mylibrary import doit Inline::Python actually binds to every function in Python's "global" namespace (those of you in the know, know that namespace is called '__main__'). So if you had another function there, you'd get that too. =head2 Importing Classes If you've written a library in Python, you'll make it object-oriented. That's just something Python folks do. So you'll probably want to import a class, not a function. That's just as easy: use Inline Python; my $obj = new Myclass; __END__ __Python__ from mylibrary import myclass as Myclass =head2 New-Style Classes As of python 2.2, the python internals have begun to change in a way which makes types 'look' more like classes. This means that your python code can now subclass builtin python types such as lists, tuples, integers, and etc. It also means that identifying python objects and creating Perl bindings for them has become a little trickier. See Guido's write-up (http://www.python.org/2.2.2/descrintro.html) and the relevant Python Enhancement Proposals (PEP) numbers 252 and 253 for details about the python code. Also, see the mailing-list discussion (http://mail.python.org/pipermail/python-dev/2004-July/046060.html) for possible implications regarding C-language python extensions. This change should not affect code which uses Inline::Python, except that it allows you to bind to python classes which have been written using these new features. In most cases, you will be importing an entire class from an external library as defined in the example above. In other cases, you may be writing Inline::Python code as follows: use Inline Python => <<'END'; class Foo(object): def __init__(self): print "new Foo object being created" self.data = {} def get_data(self): return self.data def set_data(self,dat): self.data = dat END Additional caveats may exist. Note that if the python class is subclassing one of the builtin types which would normally be accessible as a 'Perlish' translation, that the instance will be an opaque object accessible only through its class methods. # Class is defined as 'def Class(float):' my $obj = Class->new(4); print $$obj, "\n"; # will NOT print '4.0' =head2 New-Style =head2 Boundary Conditions What if you have a class that wasn't imported? Can you deal with instances of that class properly? Of course you can! Check this out: use Inline Python => <tank(), "\n"; In this example, C isn't imported because it isn't a global -- it's hidden inside the function Foo(). But Foo() is imported into Perl, and it returns an instance of the C class. What happens then? Whenever Inline::Python needs to return an instance of a class to Perl, it generates an instance of Inline::Python::Object, the base class for all Inline::Python objects. This base class knows how to do all the things you need: calling methods, in this case. =head1 Exceptions Exceptions thrown in Python code get translated to Perl exceptions which you can catch using eval. =head1 Boolean Python supports a Boolean type and two constants False and True. If one of these is passed from Python to Perl, the value is represented by an Inline::Python::Boolean object that uses overload to behave like 1 or undef in boolean context in Perl. When this object is passed back to Python, it is translated back to the False or True constant it originated from. To pass a Boolean value that originated from Perl to Python use the two constants C<$Inline::Python::Boolean::true> and C<$Inline::Python::Boolean::false> if it is important that the value is of type Boolean in Python. =head1 Using Perl inside Python (inside Perl) This section doesn't talk at all about C. It's about how to use C. C is a Python module bundled with Inline::Python that gives you access to Perl from inside your Python code. In the future, it will be possible to compile Inline::Python to work the other way around -- to use Python as the main programming language, and jump into Perl when you want to. The C package exposes Perl packages and subs. It uses the same code as Inline::Python to automatically translate parameters and return values as needed. Packages and subs are represented as C and C, respectively. =head1 Using the PerlPkg Type The C package is actually not a package at all. As soon as you import it, it replaces itself with an instance of the PerlPkg class, wrapping the Perl package "main". Perl's 'main' package is analogous to '__main__' in Python. Here's what you can do with the 'main' PerlPkg: =head2 eval() eval(source code) Unlike Python, Perl has no exec() -- the eval() function always returns the result of the code it evaluated. eval() takes exactly one argument, the perl source code, and returns the result of the evaluation. =head2 require() and use() require(module name) use(module name) Use require() instead of C. In Python, you'd say this: import md5 But using the perl module, you'd say this: perl.require("Digest::MD5") Of course, in Perl there's more than one way to do it (TM). require() doesn't run the package's import() function. If you want symbols exported, for instance, use use() instead of require(). Here is the functionality common to all PerlPkg instances: =head2 __getattr__ Python's __getattr__() function allows the package to dynamically return something to satisfy the request. For instance, you can get at the subs in a perl package by using dir() (which is the same as C. Here's an example: perl.eval("sub f { 10 }") # define main::f f = perl.f f(); f("hello") # no argument checking if perl.f() != 10: import sys; sys.exit(1) Notice what happens. First we call eval() to define a sub 'f'. Then we say C, which goes into the __getattr__() method. We check the Perl namespace and see a function called f, which we return, wrapped in an instance of the PerlSub type. =head3 Accessing a perl object's data __getattr__ may also be used to access a Perl object's attributes, just like Python allows. The Perl object just has to implement a sub __getattr__ returning the requested attribute, which may even be calculated on the fly. An example for the common hash based objects: sub __getattr__ { my ($self, $attr) = @_; return $self->{$attr}; } This allows Python code to access the perl object's data like: print my_perl_object.field_name =head2 named arguments When a Perl sub is called with named arguments from Python code, Inline::Python follows the PyObject_Call protocol: positional arguments are given as array ref followed by named arguments as a hash ref. A Perl method supporting named arguments would therefore look like: sub supports_named_arguments { my ($self, $positional, $named) = @_; foreach (qw( named1 named2 )) { last unless @$positional; $named->{$_} = shift @$positional; } ... } If this method is called using only positional arguments, they would just be pushed into @_ like in any other method, complicating it to: sub supports_named_arguments { my ($self, $positional, $named) = @_; if (@_ == 3 and $size and ref $size and ref $size eq 'ARRAY' and ref $useimage eq 'HASH') { # called using named parameters foreach (qw( named1 named2 ... )) { last unless @$positional; $named->{$_} = shift @$positional; } } else { $named = { named1 => $positional, named2 => $named, named3 => $_[3], ... }; } ... } As this adds a lot of boiler plate code to subroutines, it is better to just use Perl named arguments conventions (single hashref parameter) if possible. =head1 Using the PerlSub Type All Perl subs are wrapped in the PerlSub type, so that they can emulate Python subroutines. You can call them. It's all good. Here's what you can do with PerlSub objects: =head2 Call PerlSub catches the call action and forwards the call to the real sub in Perl. =head2 Set the evaluation flags Perl has this notion of calling context. A subroutine can ask Perl what it is being used for. The idea is that if no one cares about your return value, you might be able to save time by not building it. By default, PerlSub objects evaluate in 'list' context with no extra flags turned on. perl.eval("sub f { 10 }") f = perl.f f.flags = f.flags | f.G_SCALAR x = f() Here are the most common flags you'll need. For more details about these and other possible flags, see L. =over 4 =item 1 G_VOID Calls the Perl subroutine in a void context. Guarantees that no results will be returned. If any are returned, Perl deletes them. =item 2 G_SCALAR Calls the Perl subroutine in a scalar context. Ensures that only one element is returned from the sub. If the sub returns a list, only the last element is actually saved. =item 3 G_ARRAY Calls the Perl subroutine in a list context. Ensures that any items returned from the subroutine are returned. This is the default for PerlSub objects. =item 4 G_DISCARD If you are not interested in the return values, you can optimize slightly by telling Perl, and it will discard all returned values for you. =item 5 G_NOARGS If you are not passing any arguments, you can optimize the call so that Perl doesn't bother setting up the stack for parameters. =item 6 G_EVAL It is possible for the Perl sub to fail, either by calling die() explicitly or by calling a non-existent sub. By default, the process will terminate immediately. To avoid this happening, you can trap the exception using the G_EVAL flag. =back =head1 Under the Hood When Inline::Python imports a class or function, it creates subs in Perl which delegate the action to some C functions I've written, which know how to call Python functions and methods. use Inline Python => <<'END'; class Foo: def __init__(self): print "new Foo object being created" self.data = {} def get_data(self): return self.data def set_data(self,dat): self.data = dat END Inline::Python actually generates this code and eval()s it: package main::Foo; @main::Foo::ISA = qw(Inline::Python::Object); sub new { splice @_, 1, 0, "__main__", "Foo"; return &Inline::Python::py_new_object; } sub set_data { splice @_, 1, 0, "set_data"; return &Inline::Python::py_call_method; } sub get_data { splice @_, 1, 0, "get_data"; return &Inline::Python::py_call_method; } sub __init__ { splice @_, 1, 0, "__init__"; return &Inline::Python::py_call_method; } More about those C functions, and how to generate this snippet of code yourself, in the next section. =head1 The Do-it-yourselfer's Guide to Inline::Python Sometimes you don't actually want to do things the Inline Way. Maybe you just want to use a Python class as-is, without ever treating it like a normal Perl class: use Inline::Python qw(py_eval); py_eval(<<'END'); class MyClass: def __init__(self): self.data = {} def put(self, key, value): self.data[key] = value def get(self, key): try: return self.data[key] except KeyError: return None END my $o = Inline::Python::Object->new('__main__', 'MyClass'); $o->put("candy", "yummy"); die "Ooops" unless $o->get("candy") eq 'yummy'; Inline::Python provides a full suite of exportable functions you can use to manipulate Python objects and functions "directly". =head2 py_eval() py_eval("python source code", [context]) The new py_eval() behaves a little like Perl's eval(). It evaluates the code or croaks on failure. The optional context argument can be used to place restrictions on the type of code allowed, as well as influence what happens to the result. =over 4 =item Z<>0 Accepts only expressions. Complete statements yield a syntax error. An expression is anything that can appear to the right of an '=' sign. Returns the value of the expression. =item Z<>1 The default. Accepts arbitrarily long input, which may be any valid Python code. Always returns C. =item Z<>2 Accepts exactly one statement, and prints the result to STDOUT. This is how Python works in interactive mode. Always returns C. =back =head2 py_call_function() py_call_function("package", "function", args...) This function runs a Python function and returns the result. The "package" and "function" uniquely identify a function, and the remaining args are passed to the function. Those who know Python well enough will know you can actually "run" a class and get an instance of that class back. But in case that's just too weird for you, I've given you a slightly higher-level wrapper around that common idiom. =head2 py_new_object() py_new_object("perl package", "python package", "python class", args...) This function creates an instance of a Python class. The "python class" is the name of the class inside the "python package". The new object is blessed into the given "perl package". The remaining args are passed directly to the constructor. =head2 py_call_method() py_call_method(object, "method name", args...) Given an instance of a Python class, this function can call a method on it. This is useful if you have an object which is blessed into a non-existent Perl package. Attempts to use Perl's object syntax would fail, because Perl wouldn't find any methods in that package. But py_call_method() can always perform method calls correctly since it unwraps the underlying Python object. =head2 eval_python() Unlike in previous releases of Inline::Python, eval_python() can now return the result of the code. As before, eval_python() is overloaded: =over 4 =item 1 eval_python(code, [context]) Evaluate the code using py_eval(). =item 2 eval_python(python package, function, args...) Run the given function and return the results using py_call_function(). =item 3 eval_python(object, method, args...) Invoke the given method on the object using py_call_method() and return the results. =back =head2 py_bind_func() py_bind_func("symbol name", "python package", "function") This function imports a Python function (named "function") as the symbol named by "perl symbol". After this function has been called, the Python function can be called as if it were a Perl function in the given package. use Inline::Python qw(py_eval py_bind_func); py_eval(<<'END'); def Foo(): return 42 END # For the purposes of this example, so I know the package, I set it: py_bind_func("main::Bar", "__main__", "Foo"); print "The meaning of life is: ", Bar(), "\n"; This call to py_bind_func() will generate this code and eval() it: sub main::Bar { unshift @_, "__main__", "Foo"; return &Inline::Python::py_call_function; } =head2 py_bind_class() py_bind_class("perl package", "python package", "class", methods...) This function imports a Python class (named "class") into the Perl package named by "perl package". After this function has been called, the Perl package will look just like a regular Perl class. The example I showed earlier in the "Under the Hood" section shows the output of py_bind_class. Here's another look at it: use Inline::Python qw(py_eval py_bind_class); py_eval(<<'END'); class Foo: def __init__(self): print "new Foo object being created" self.data = {} def get_data(self): return self.data def set_data(self,dat): self.data = dat END py_bind_class("main::Foo", "__main__", "Foo", "set_data", "get_data"); my $o = new Foo; This call to py_bind_class() will generate this code and eval() it: package main::Foo; @main::Foo::ISA = qw(Inline::Python::Object); sub new { splice @_, 1, 0, "__main__", "Foo"; return &Inline::Python::py_new_object; } sub set_data { splice @_, 1, 0, "set_data"; return &Inline::Python::py_call_method; } sub get_data { splice @_, 1, 0, "get_data"; return &Inline::Python::py_call_method; } Note that if you want methods to be created as I've shown, you must pass them to py_bind_class() yourself. It doesn't create anything except new() and the @ISA array. It doesn't need to, since the base class knows how to deal with any method call -- but it's also slower, since it has to walk up the inheritance tree to the AUTOLOAD method. I recommend binding to the functions you know about, especially if you're the one writing the code. If it's auto-generated, use py_study_package(), described below. =head2 py_study_package() py_study_package(["package"]) This function interrogates the Python interpreter about the given package (or '__main__' if you don't specify one). It returns a list of key/value pairs, so it should be used like this: py_eval('import pickle'); my %namespace = py_study_package("pickle"); On my machine, %namespace looks something like this: $VAR1 = { 'classes' => { ... }, 'functions' => [ '_keep_alive', 'loads', 'dump', 'load', 'dumps', 'test', 'whichmodule' ] }; Each result can be fed to py_bind_function() and py_bind_class(), which is exactly what Inline::Python itself does. =head2 py_is_tuple() my $array_ref = py_eval('(1, 2)') $is_tuple = py_is_tuple($array_ref) This function can tell you if the array reference you got from calling some Python code was a tuple in Python or not (e.g. a normal array). This can be useful if an API requires a distinction between those cases. py_is_tuple works by looking for a magic marker put onto array refs by Py2Pl. Bear in mind that this marker may get lost when copying the array data. =head1 SEE ALSO For information about using C, see L. For information about other Inline languages, see L. Inline::Python's mailing list is inline@perl.org To subscribe, send email to inline-subscribe@perl.org =head1 BUGS AND DEFICIENCIES This is a production quality release of Inline::Python. It is fairly feature complete and runs stable with no known crasher bugs or memory leaks. Further testing and expanded support for other operating systems and platforms will be a focus for future releases. When reporting a bug, please do the following: - Put "use Inline REPORTBUG;" at the top of your code, or use the command line option "perl -MInline=REPORTBUG ...". - Run your code. - Follow the printed instructions. Here are some things to watch out for: =over 4 =item 1 Note that the namespace imported into Perl is NOT recursively traversed. Only Python B are imported into Perl -- subclasses, subfunctions, and other modules are not imported. Example: use Inline Python => <<'END'; import mymodule class A: class B: pass END The namespace imported into perl is ONLY that related to C. Nothing related to C or C is imported, unless some Python code explicitly copies variables from the mymodule namespace into the global namespace before Perl binds to it. =back =head1 SUPPORTED PLATFORMS Inline::Python has been tested on RedHat Linux 6.2 with a variety of different Perl and Python configurations. It also seems to be running pretty well on openSUSE at least from 10.3 to 13.1 and on Solaris. Previous versions of Inline::Python worked on Windows and Cygwin -- this version has never been tested there. I strongly suspect it will require patching. Please send me patches. This version of Inline::Python has been tested with Python versions from 2.5 to 2.7 and from 3.1 to 3.4. =head1 PORTING YOUR INLINE PYTHON CODE FROM 2 TO 3 First of all, follow the Python guide from 2 to 3: https://docs.python.org/3/howto/pyporting.html For Perl integration: - Non-utf8-flagged Perl strings will be Python bytes, utf8-flagged Perl strings will be Python string - __cmp__ is no more supported in Python 3 and has been replaced by "rich comparison" (i.e. __eq__, __le__, etc.). Since booleans in Perl are integers, renaming __cmp__ to __eq__ is often enough while wrapping a Perl object in Python. - perl.require, perl.use and perl.eval accept either bytes or strings. =head1 SOURCE REPOSITORY The Github repository for this project is at L. Pull requests are welcome. =head1 AUTHOR Neil Watkiss Brian Ingerson is the author of Inline, Inline::C and Inline::CPR. He was responsible for much encouragement and many suggestions throughout the development of Inline::Python. Eric Wilhelm provided support for 'new-style' classes in version 0.21. Many thanks, Eric! Stefan Seifert fixed some bugs and is current co-maintainer. =head1 COPYRIGHT Copyright (c) 2001, Neil Watkiss. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. (see http://www.perl.com/perl/misc/Artistic.html) =cut Inline-Python-0.58/PaxHeaders/util.c0000644000000000000000000000013212415322646014347 xustar0030 mtime=1412801958.514690258 30 atime=1645882208.704096108 30 ctime=1747225338.911562258 Inline-Python-0.58/util.c0000644000076400001440000000651412415322646014213 0ustar00nineusers/* vim: set expandtab shiftwidth=4 softtabstop=4 cinoptions='\:2=2': */ #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "Python.h" #include "util.h" #ifdef __cplusplus } #endif MGVTBL inline_mg_vtbl = { 0x0, 0x0, 0x0, 0x0, &free_inline_py_obj, 0x0, 0x0, 0x0 }; /************************************* * UTILITY FUNCTIONS * *************************************/ int free_inline_py_obj(pTHX_ SV* obj, MAGIC *mg) { if (mg && mg->mg_type == PERL_MAGIC_ext && Inline_Magic_Check(mg->mg_ptr)) { IV const iv = SvIV(obj); /*Printf(("free_inline_py_obj: %p, iv: %p, ob_prev: %p, ob_next: %p, refcnt: %i\n", obj, iv, ((PyObject *)iv)->_ob_prev, ((PyObject *)iv)->_ob_next, ((PyObject *)iv)->ob_refcnt)); */ /* _ob_prev and _ob_next are only available if Python is compiled with reference debugging enabled */ Printf(("free_inline_py_obj: %p, iv: %p, refcnt: %i\n", obj, iv, (int)Py_REFCNT(iv))); Py_XDECREF((PyObject *)iv); /* just in case */ } else { croak("ERROR: tried to free a non-Python object. Aborting."); } return 0; } PyObject * get_perl_pkg_subs(PyObject *package) { #if PY_MAJOR_VERSION >= 3 char * const pkg = PyBytes_AsString(package); #else char * const pkg = PyString_AsString(package); #endif PyObject * const retval = PyList_New(0); HV * const hash = perl_get_hv(pkg, 0); int const len = hv_iterinit(hash); int i; for (i=0; i= 3 PyList_Append(retval, PyUnicode_FromString(key)); #else PyList_Append(retval, PyString_FromString(key)); #endif } free(test); } return retval; } int perl_pkg_exists(char *base, char *pkg) { int retval = 0; HV * const hash = perl_get_hv(base,0); char * const fpkg = (char*)malloc((strlen(pkg) + strlen("::") + 1)*sizeof(char)); sprintf(fpkg,"%s::",pkg); Printf(("perl_pkg_exists: %s, %s --> %s\n", base, pkg, fpkg)); Printf(("perl_pkg_exists: hash=%p\n", hash)); if (hash && hv_exists(hash, fpkg, strlen(fpkg))) { /* here -- check if it's a package, not something else? */ retval = 1; } free(fpkg); return retval; } PyObject * perl_sub_exists(PyObject *package, PyObject *usub) { #if PY_MAJOR_VERSION >= 3 char * const pkg = PyBytes_AsString(package); char * const sub = PyBytes_AsString(usub); #else char * const pkg = PyString_AsString(package); char * const sub = PyString_AsString(usub); #endif PyObject * retval = Py_None; char * const qsub = (char*)malloc((strlen(pkg) + strlen(sub) + 1)*sizeof(char)); sprintf(qsub,"%s%s",pkg,sub); if (perl_get_cv(qsub,0)) { retval = Py_True; } free(qsub); Py_INCREF(retval); return retval; } int py_is_tuple(SV *arr) { if (SvROK(arr) && SvTYPE(SvRV(arr)) == SVt_PVAV) { MAGIC * const mg = mg_find(SvRV(arr), PERL_MAGIC_ext); return (mg && Inline_Magic_Key(mg->mg_ptr) == TUPLE_MAGIC_KEY); } else return 0; } Inline-Python-0.58/PaxHeaders/perlmodule.h0000644000000000000000000000013214416227476015557 xustar0030 mtime=1681469246.119145284 30 atime=1681469246.119145284 30 ctime=1747225338.911581645 Inline-Python-0.58/perlmodule.h0000644000076400001440000000545014416227476015421 0ustar00nineusers/* vim: set expandtab shiftwidth=4 softtabstop=4 cinoptions='\:2=2': */ #ifndef Py_PERLMODULE_H #define Py_PERLMODULE_H #ifdef __cplusplus extern "C" { #endif /* _perl_pkg: a class which wraps Perl packages */ typedef struct { PyObject_HEAD PyObject *base; /* the name of the "parent" package */ PyObject *pkg; /* the name of the package */ PyObject *full; /* the fully-qualified name (base::pkg) */ } PerlPkg_object; /* _perl_obj: a class which wraps Perl objects */ typedef struct { PyObject_HEAD PyObject *pkg; /* the name of the package */ SV *obj; /* the blessed Perl object */ } PerlObj_object; /* _perl_sub: a class which wraps Perl subs and methods */ typedef struct { PyObject_HEAD PyObject *pkg; /* the (fully-qualified) name of the package */ PyObject *sub; /* the (unqualified) name of the sub */ PyObject *full; /* the (fully-qualified) name of the sub */ SV *ref; /* reference to the Perl subroutine (if found) */ SV *obj; /* reference to a Perl object (if a method) */ int conf; /* flag: is this sub/method confirmed to exist? */ I32 flgs; /* flags to pass to perl_call_sv() */ PyObject* (*cfun)(PyObject *self, PyObject *args); /* a regular Python function */ } PerlSub_object; extern PyTypeObject PerlPkg_type, PerlObj_type, PerlSub_type; #ifndef PyVarObject_HEAD_INIT /* Python 2.5 does not define this*/ #define PyVarObject_HEAD_INIT(type, size) \ PyObject_HEAD_INIT(type) size, #endif #ifndef Py_TYPE /* Python 2.5 does not define this*/ #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif #define PerlPkgObject_Check(v) (Py_TYPE(v) == &PerlPkg_type) #define PerlObjObject_Check(v) (Py_TYPE(v) == &PerlObj_type) #define PerlSubObject_Check(v) (Py_TYPE(v) == &PerlSub_type) #if PY_MAJOR_VERSION >= 3 #define PKG_EQ(obj,pkg) (strcmp(PyBytes_AsString((obj)->full), (pkg))==0) #else #define PKG_EQ(obj,pkg) (strcmp(PyString_AsString((obj)->full), (pkg))==0) #endif /* Macro for returning Py_NotImplemented from a function */ #ifndef Py_RETURN_NOTIMPLEMENTED /* Python 3.1 does not define this*/ #define Py_RETURN_NOTIMPLEMENTED \ return Py_INCREF(Py_NotImplemented), Py_NotImplemented #endif /*************************************** * METHOD DECLARATIONS * ***************************************/ /* methods of _perl_pkg */ extern PyObject * newPerlPkg_object(PyObject *, PyObject *); /* methods of _perl_obj */ extern PyObject * newPerlObj_object(SV *, PyObject *); /* methods of _perl_sub */ extern PyObject * newPerlSub_object(PyObject *, PyObject *, SV *); extern PyObject * newPerlMethod_object(PyObject*, PyObject*, SV*); extern PyObject * newPerlCfun_object(PyObject* (*)(PyObject *, PyObject *)); extern void initperl(void); #ifdef __cplusplus } #endif #endif Inline-Python-0.58/PaxHeaders/Python.pm0000644000000000000000000000013015011105151015024 xustar0029 mtime=1747225193.60553706 29 atime=1747225193.60553706 30 ctime=1747225338.911648323 Inline-Python-0.58/Python.pm0000644000076400001440000002453515011105151014675 0ustar00nineuserspackage Inline::Python; use strict; use Carp; require Inline; require DynaLoader; require Exporter; our ($VERSION, @ISA, @EXPORT_OK); @ISA = qw(Inline DynaLoader Exporter); $VERSION = '0.58'; @EXPORT_OK = qw(py_eval py_new_object py_call_method py_call_function py_is_tuple py_bind_class py_bind_func py_study_package eval_python ); # Prevent Inline's import from complaining sub import { Inline::Python->export_to_level(1,@_); } sub dl_load_flags { 0x01 } Inline::Python->bootstrap($VERSION); #============================================================================== # Register Python.pm as a valid Inline language #============================================================================== sub register { return { language => 'Python', aliases => ['py', 'python', 'PYTHON'], type => 'interpreted', suffix => 'pydat', }; } #============================================================================== # Validate the Python config options #============================================================================== sub validate { my $o = shift; $o->{ILSM} = {}; $o->{ILSM}{FILTERS} = []; $o->{ILSM}{AUTO_INCLUDE} = {}; $o->{ILSM}{built} = 0; $o->{ILSM}{loaded} = 0; while (@_) { my ($key, $value) = (shift, shift); if ($key eq 'AUTO_INCLUDE') { add_string($o->{ILSM}{AUTO_INCLUDE}, $key, $value, ''); warn "AUTO_INCLUDE has not been implemented yet!\n"; } elsif ($key eq 'FILTERS') { next if $value eq '1' or $value eq '0'; # ignore ENABLE, DISABLE $value = [$value] unless ref($value) eq 'ARRAY'; my %filters; for my $val (@$value) { if (ref($val) eq 'CODE') { $o->add_list($o->{ILSM}, $key, $val, []); } else { eval { require Inline::Filters }; croak "'FILTERS' option requires Inline::Filters to be installed." if $@; %filters = Inline::Filters::get_filters($o->{API}{language}) unless keys %filters; if (defined $filters{$val}) { my $filter = Inline::Filters->new($val, $filters{$val}); $o->add_list($o->{ILSM}, $key, $filter, []); } else { croak "Invalid filter $val specified."; } } } } else { croak "$key is not a valid config option for Python\n"; } next; } } sub usage_validate { return "Invalid value for config option $_[0]"; } sub add_list { my ($ref, $key, $value, $default) = @_; $value = [$value] unless ref $value; croak usage_validate($key) unless ref($value) eq 'ARRAY'; for (@$value) { if (defined $_) { push @{$ref->{$key}}, $_; } else { $ref->{$key} = $default; } } } sub add_string { my ($ref, $key, $value, $default) = @_; $value = [$value] unless ref $value; croak usage_validate($key) unless ref($value) eq 'ARRAY'; for (@$value) { if (defined $_) { $ref->{$key} .= ' ' . $_; } else { $ref->{$key} = $default; } } } sub add_text { my ($ref, $key, $value, $default) = @_; $value = [$value] unless ref $value; croak usage_validate($key) unless ref($value) eq 'ARRAY'; for (@$value) { if (defined $_) { chomp; $ref->{$key} .= $_ . "\n"; } else { $ref->{$key} = $default; } } } #========================================================================== # Print a short information section if PRINT_INFO is enabled. #========================================================================== sub info { my $o = shift; my $info = ""; $o->build unless $o->{ILSM}{built}; my @functions = @{$o->{ILSM}{namespace}{functions}||[]}; $info .= "The following Python functions have been bound to Perl:\n" if @functions; for my $function (sort @functions) { $info .= "\tdef $function()\n"; } my %classes = %{$o->{ILSM}{namespace}{classes}||{}}; $info .= "The following Python classes have been bound to Perl:\n"; for my $class (sort keys %classes) { $info .= "\tclass $class:\n"; for my $method (sort @{$o->{ILSM}{namespace}{classes}{$class}}) { $info .= "\t\tdef $method(...)\n"; } } return $info; } #========================================================================== # Run the code, study the main namespace, and cache the results. #========================================================================== sub build { my $o = shift; return if $o->{ILSM}{cached}; # Filter the code $o->{ILSM}{code} = $o->filter(@{$o->{ILSM}{FILTERS}}); # Run the code py_eval($o->{ILSM}{code}); $o->{ILSM}{evaluated}++; # Study the main namespace my %namespace = py_study_package('__main__'); # Cache the results require Inline::denter; my $namespace = Inline::denter->new ->indent( *namespace => \%namespace, *filtered => $o->{ILSM}{code}, ); $o->mkpath("$o->{API}{install_lib}/auto/$o->{API}{modpname}"); open PYDAT, "> $o->{API}{location}" or croak "Inline::Python couldn't write parse information!"; print PYDAT $namespace; close PYDAT; $o->{ILSM}{namespace} = \%namespace; $o->{ILSM}{cached}++; } #============================================================================== # Load the code, run it, and bind everything to Perl #============================================================================== sub load { my $o = shift; return if $o->{ILSM}{loaded}; # Load the code open PYDAT, $o->{API}{location} or croak "Couldn't open parse info!"; my $pydat = join '', ; close PYDAT; require Inline::denter; my %pydat = Inline::denter->new->undent($pydat); $o->{ILSM}{namespace} = $pydat{namespace}; $o->{ILSM}{code} = $pydat{filtered}; # Run it py_eval($o->{ILSM}{code}) unless $o->{ILSM}{evaluated}; # Bind it all py_bind_func($o->{API}{pkg} . "::$_", '__main__', $_) for (@{ $o->{ILSM}{namespace}{functions} || [] }); py_bind_class($o->{API}{pkg} . "::$_", '__main__', $_, @{$o->{ILSM}{namespace}{classes}{$_}}) for keys %{ $o->{ILSM}{namespace}{classes} || {} }; $o->{ILSM}{loaded}++; } #============================================================================== # Wrap a Python function with a Perl sub which calls it. #============================================================================== sub py_bind_func { my $perlfunc = shift; # What Perl package should the wrapper be in? my $pypkg = shift; # What Python package does it come from? my $function = shift; # What is the name of the Python function? my $bind = <isa("Inline::Python::Object")}; return &py_eval if @_ == 1 || $_[1] =~ /^\d+$/; return &py_call_function if @_ >= 2; croak "Invalid use of eval_python. See 'perldoc Inline::Python'"; } #============================================================================== # A more pleasing name than py_call_function, which is what really happens #============================================================================== sub py_new_object { return &Inline::Python::Object::new; } #============================================================================== # We provide Inline::Python::Object as a base class for Python objects. It # knows how to create, destroy, and call methods on objects. #============================================================================== package Inline::Python::Object; use overload '%{}' => \&__data__, '""' => \&__inline_str__, fallback => 1; sub new { my $perlpkg = shift; return bless &Inline::Python::py_call_function, $perlpkg; } sub __data__ { my ($self) = @_; tie my %data, 'Inline::Python::Object::Data', $self; return \%data; } sub __inline_str__ { my ($self) = @_; return Inline::Python::py_has_attr($self, '__str__') ? $self->__str__() : $self; } sub AUTOLOAD { no strict; $AUTOLOAD =~ s|.*::(\w+)|$1|; splice @_, 1, 0, $AUTOLOAD; return &Inline::Python::py_call_method; } # avoid AUTOLOAD warning sub DESTROY { } package Inline::Python::Object::Data; sub new { my $class = shift; return $class->TIEHASH(@_); } sub TIEHASH { my ($class, $self) = @_; return bless \$self, $class; } sub FETCH { my ($self, $key) = @_; return Inline::Python::py_get_attr($$self, $key); } sub STORE { my ($self, $key, $value) = @_; return Inline::Python::py_set_attr($$self, $key, $value); } package Inline::Python::Function; use overload '&{}' => \&call, fallback => 1; sub call { my $self = shift; return sub { Inline::Python::py_call_function_ref($$self, @_) }; } package Inline::Python::Boolean; use overload bool => \&bool, '0+' => \&bool, '!' => \&negate, fallback => 1; our $true = __PACKAGE__->new(1); our $false = __PACKAGE__->new(0); sub new { my ($class, $value) = @_; return bless \$value, $class; } sub bool { my ($self) = @_; return $$self; } sub negate { my ($self) = @_; return $self ? $false : $true; } sub TO_JSON { my ($self) = @_; return $self ? JSON::true() : JSON::false(); } 1; Inline-Python-0.58/PaxHeaders/Python.xs0000644000000000000000000000013215011104521015044 xustar0030 mtime=1747224913.111747192 30 atime=1747224913.111747192 30 ctime=1747225338.911807167 Inline-Python-0.58/Python.xs0000644000076400001440000004232515011104521014710 0ustar00nineusers/* -*- C -*- */ /* vim: set expandtab shiftwidth=4 softtabstop=4 cinoptions='\:2=2': */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "Python.h" #include "py2pl.h" #include "util.h" #ifdef EXPOSE_PERL #include "perlmodule.h" #endif /* To save a little time, I check the calling context and don't convert * the arguments if I'm in void context, flatten lists in list context, * and return only one element in scalar context. * * If this turns out to be a bad idea, it's easy enough to turn off. */ #define CHECK_CONTEXT #ifdef CREATE_PYTHON void do_pyinit() { #ifdef EXPOSE_PERL PyObject *main_dict; PyObject *perl_obj; PyObject *dummy1; PyObject *dummy2; #endif /* sometimes Python needs to know about argc and argv to be happy */ int _python_argc = 1; #if PY_MAJOR_VERSION >= 3 wchar_t *_python_argv[] = {L"python",}; #else char *_python_argv[] = {"python",}; #endif #if PY_VERSION_HEX < 0x03080000 Py_SetProgramName(_python_argv[0]); Py_Initialize(); PySys_SetArgv(_python_argc, _python_argv); /* Tk needs this */ #else PyConfig config; PyConfig_InitPythonConfig(&config); PyConfig_SetString(&config, &config.program_name, _python_argv[0]); PyConfig_SetArgv(&config, _python_argc, _python_argv); Py_InitializeFromConfig(&config); PyConfig_Clear(&config); #endif #ifdef EXPOSE_PERL #if PY_MAJOR_VERSION >= 3 dummy1 = PyBytes_FromString(""), dummy2 = PyBytes_FromString("main"); #else dummy1 = PyString_FromString(""), dummy2 = PyString_FromString("main"); #endif /* create the perl module and add functions */ initperl(); /* now -- create the main 'perl' object and add it to the dictionary. */ perl_obj = newPerlPkg_object(dummy1, dummy2); main_dict = PyModule_GetDict(PyImport_AddModule("__main__")); PyDict_SetItemString(main_dict, "perl", perl_obj); Py_DECREF(perl_obj); Py_DECREF(dummy1); Py_DECREF(dummy2); #endif } #endif MODULE = Inline::Python PACKAGE = Inline::Python BOOT: #ifndef PERL_USE_SAFE_PUTENV PL_use_safe_putenv = 1; #endif py_true = perl_get_sv("Inline::Python::Boolean::true", FALSE); py_false = perl_get_sv("Inline::Python::Boolean::false", FALSE); #ifdef CREATE_PYTHON do_pyinit(); #endif PROTOTYPES: DISABLE void py_initialize() CODE: do_pyinit(); void py_study_package(PYPKG="__main__") char* PYPKG PREINIT: PyObject *mod; PyObject *dict; PyObject *keys; int len; int i; AV* const functions = newAV(); HV* const classes = newHV(); PPCODE: mod = PyImport_AddModule(PYPKG); dict = PyModule_GetDict(mod); keys = PyMapping_Keys(dict); len = PyObject_Length(dict); Printf(("py_study_package: dict length: %i\n", len)); for (i=0; i= 3 PyObject* bytes_key = PyUnicode_AsUTF8String(key); char * const key_c_str = PyBytes_AsString(bytes_key); printf("py_study_package: #%i (%s) callable\n", i, key_c_str); Py_DECREF(bytes_key); #else printf("py_study_package: #%i (%s) callable\n", i, PyString_AsString(key)); #endif printf("val:\n\t"); PyObject_Print(val, stdout, Py_PRINT_RAW); printf("\n"); printf("object type check gives: %i\n", PyType_Check(val)); #endif if (PyFunction_Check(val)) { #if PY_MAJOR_VERSION >= 3 PyObject* bytes_key = PyUnicode_AsUTF8String(key); char * const name = PyBytes_AsString(bytes_key); #else char * const name = PyString_AsString(key); #endif Printf(("Found a function: %s\n", name)); av_push(functions, newSVpv(name,0)); #if PY_MAJOR_VERSION >= 3 Py_DECREF(bytes_key); #endif } /* elw: if we just could get it to go through here! */ else if (PyType_Check(val) || PyClass_Check(val)) { #if PY_MAJOR_VERSION >= 3 PyObject* bytes_key = PyUnicode_AsUTF8String(key); char * const name = PyBytes_AsString(bytes_key); // In P3.4, __loader__ mapping is not easy to handle... Skip for now if(strcmp(name, "__loader__") == 0) continue; #else char * const name = PyString_AsString(key); #endif PyObject * const cls_dict = PyObject_GetAttrString(val,"__dict__"); PyObject * const cls_keys = PyMapping_Keys(cls_dict); int const dict_len = PyObject_Length(cls_dict); int j; /* array of method names */ AV * const methods = newAV(); Printf(("Found a class: %s\n", name)); /* populate the array */ for (j=0; j= 3 PyObject* bytes_cls_key = PyUnicode_AsUTF8String(cls_key); char * const fname = PyBytes_AsString(bytes_cls_key); #else char * const fname = PyString_AsString(cls_key); #endif if (PyFunction_Check(cls_val)) { Printf(("Found a method of %s: %s\n", name, fname)); av_push(methods,newSVpv(fname,0)); } else { Printf(("not a method %s: %s\n", name, fname)); } #if PY_MAJOR_VERSION >= 3 Py_DECREF(bytes_cls_key); #endif } #if PY_MAJOR_VERSION >= 3 Py_DECREF(bytes_key); #endif hv_store(classes,name,strlen(name),newRV_noinc((SV*)methods), 0); } } } /* return an expanded hash */ XPUSHs(newSVpv("functions",0)); XPUSHs(newRV_noinc((SV*)functions)); XPUSHs(newSVpv("classes", 0)); XPUSHs(newRV_noinc((SV*)classes)); void py_eval(str, type=1) char *str int type PREINIT: PyObject *main_module; PyObject *globals; PyObject *locals; PyObject *py_result; int context; SV* ret = NULL; PPCODE: Printf(("py_eval: code: %s\n", str)); /* doc: if the module wasn't already loaded, you will get an empty * module object. */ main_module = PyImport_AddModule("__main__"); if(main_module == NULL) { croak("Error -- Import_AddModule of __main__ failed"); } Printf(("py_eval: main_module=%p\n", main_module)); globals = PyModule_GetDict(main_module); Printf(("py_eval: globals=%p\n", globals)); locals = globals; context = (type == 0) ? Py_eval_input : (type == 1) ? Py_file_input : Py_single_input; Printf(("py_eval: type=%i\n", type)); Printf(("py_eval: context=%i\n", context)); py_result = PyRun_String(str, context, globals, locals); if (!py_result) { PyErr_Print(); croak("Error -- py_eval raised an exception"); XSRETURN_EMPTY; } ret = Py2Pl(py_result); if (! sv_isobject(ret)) sv_2mortal(ret); /* if ret is an object, this already gets done by the following line */ Py_DECREF(py_result); if (type == 0) XPUSHs(ret); else XSRETURN_EMPTY; #undef NUM_FIXED_ARGS #define NUM_FIXED_ARGS 2 void py_call_function(PYPKG, FNAME, ...) char* PYPKG; char* FNAME; PREINIT: int i; PyObject * const mod = PyImport_AddModule(PYPKG); PyObject * const dict = PyModule_GetDict(mod); PyObject * const func = PyMapping_GetItemString(dict,FNAME); PyObject *o = NULL; PyObject *py_retval = NULL; PyObject *tuple = NULL; SV* ret = NULL; PPCODE: Printf(("py_call_function\n")); Printf(("package: %s\n", PYPKG)); Printf(("function: %s\n", FNAME)); if (!PyCallable_Check(func)) { croak("'%s' is not a callable object", FNAME); XSRETURN_EMPTY; } Printf(("function '%s' is callable!\n", FNAME)); tuple = PyTuple_New(items-NUM_FIXED_ARGS); for (i=NUM_FIXED_ARGS; i' build_requires: ExtUtils::MakeMaker: '0' Proc::ProcessTable: '0.53' Test: '0' Test::Deep: '0' Test::More: '0' Test::Number::Delta: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.74, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Inline-Python no_index: directory: - t - inc requires: Data::Dumper: '0' Digest::MD5: '2.5' File::Spec: '0' Inline: '0.46' resources: repository: http://github.com/niner/inline-python-pm.git version: '0.58' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Inline-Python-0.58/PaxHeaders/META.json0000644000000000000000000000013215011105372014635 xustar0030 mtime=1747225338.983428121 30 atime=1747225338.941430792 30 ctime=1747225338.983432339 Inline-Python-0.58/META.json0000644000076400001440000000270615011105372014500 0ustar00nineusers{ "abstract" : "Write Perl subs and classes in Python.", "author" : [ "Neil Watkiss " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.74, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Inline-Python", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Data::Dumper" : "0", "Digest::MD5" : "2.5", "File::Spec" : "0", "Inline" : "0.46" } }, "test" : { "requires" : { "Proc::ProcessTable" : "0.53", "Test" : "0", "Test::Deep" : "0", "Test::More" : "0", "Test::Number::Delta" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "type" : "git", "url" : "http://github.com/niner/inline-python-pm.git", "web" : "http://github.com/niner/inline-python-pm" } }, "version" : "0.58", "x_serialization_backend" : "JSON::PP version 4.16" }