diff --git a/pywrapgenerator.pl b/pywrapgenerator.pl new file mode 100644 index 0000000..3c1794f --- /dev/null +++ b/pywrapgenerator.pl @@ -0,0 +1,183 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2019 Ole Tange and Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see +# or write to the Free Software Foundation, Inc., 51 Franklin St, +# Fifth Floor, Boston, MA 02110-1301 USA + +use strict; + +my %opt = get_options_hash(); + +# Reserved words in Python: Replace them +my %reserved = ("return" => "_return", + "0" => "null"); +my @out = <<'_EOS'; +#!/usr/bin/python3 + +# Copyright (C) 2019 Ole Tange and Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see +# or write to the Free Software Foundation, Inc., 51 Franklin St, +# Fifth Floor, Boston, MA 02110-1301 USA + +import subprocess + +_EOS + +# Make the function definition +push @out, "def parallel(command=None, args=None, input=None, "; + +my @inner; +for my $k (keys %opt) { + $k =~ s/-/_/g; + $k =~ s/[:=].*//; + for my $p (split /\|/, $k) { + push @inner, ($reserved{$p} || $p)."=None"; + } +} +push @out, join ", ", uniq(@inner); +push @out, "):\n"; + +# Documentation string +push @out, ' """ + Python wrapper for GNU Parallel + + Use GNU Parallel options with - replaced with _. + + These: + + parallel(command="echo _{}_",args=[["A B","C D"],[1,2]],jobs="50%") + parallel("echo _{}_",args=[["A B","C D"],[1,2]],jobs="50%") + parallel("echo _{}_",[["A B","C D"],[1,2]],jobs="50%") + + will all run: + + parallel --jobs 50% echo _{}_ ::: "A B" "C D" ::: 1 2 + + This: + + parallel(command="echo _{}_",args=["A B","C D"],tag=True) + + will run: + + parallel --tag echo _{}_ ::: "A B" "C D" + + This: + + parallel(command="echo _{}_",input=b"a\nb\n",keep_order=True) + + will send "a\nb\n" on standard input (stdin) to: + + | parallel --keep-order echo _{}_ + + """',"\n"; +# Build the command for subprocess.run +push @out, " option = ['parallel']\n"; + +for my $k (keys %opt) { + my $type = "bool"; + if($k =~ s/([:=])(.*)//) { + my %typeof = ("i" => "int", + "f" => "float", + "s" => "str"); + $type = $typeof{$2}; + } + for my $p (split /\|/, $k) { + my $o = $p; + $p =~ s/-/_/g; + push @out, " if ".($reserved{$p} || $p)." is not None:\n"; + # --long-option? or -s hort? + my $dashes = ($o =~ /../) ? "--" : "-"; + if($type eq "bool") { + push @out, " option.extend(['$dashes$o'])\n"; + } + if($type eq "str" or $type eq "float" or $type eq "int") { + push @out, " option.extend(['$dashes$o',".($reserved{$p} || $p)."])\n"; + } + } +} +push @out, map { s/^/ /gm;$_ } join"\n", + ("argumentsep = ':::'", + "if argsep is not None:", + " argumentsep = argsep", + "if arg_sep is not None:", + " argumentsep = arg_sep", + "if command is not None:", + " option.append(command)", + "if args is not None:", + " if type(args[0]) is list:", + " for a in args:", + " option.extend([argumentsep])", + " option.extend(map(str,a))", + " else:", + " option.extend([argumentsep])", + " option.extend(map(str,args))", + "out = subprocess.run(option,input=input,stdout=subprocess.PIPE,stderr=subprocess.PIPE)", + "return(out.stdout,out.stderr)", + ); +push @out, join "\n", + ("",'', + 'print(parallel(command="echo _{}_",args=[["A B","C D"],[1,2]],jobs="50%"))', + 'print(parallel(command="echo _{}_",args=["A B","C D"],tag=True))', + 'print(parallel(command="echo _{}_",v=True,argsep="f",args=["A B","C D"],tag=True))', + 'print(parallel(command="echo _{}_",input=b"a\nb\n",keep_order=True))', + 'print(parallel(args=["pwd","echo foo"]))', + '' + ); + +print @out; + +sub get_options_hash { + sub which { + local $_ = qx{ LANG=C type "$_[0]" }; + my $exit += (s/ is an alias for .*// || + s/ is aliased to .*// || + s/ is a function// || + s/ is a shell function// || + s/ is a shell builtin// || + s/.* is hashed .(\S+).$/$1/ || + s/.* is (a tracked alias for )?//); + if($exit) { + return $_; + } else { + return undef; + } + } + + my $fullpath = which("parallel"); + my $parallelsource = qx{cat $fullpath}; + # Grap options hash from source + $parallelsource =~ /([(]"debug.D=s".*?[)])/s || die; + my $optsource = $1; + my %opt = eval $optsource; + return %opt; +} + +sub uniq { + # Remove duplicates and return unique values + return keys %{{ map { $_ => 1 } @_ }}; +}