Difficulty rendering form inside a loop - forms

I'm new to web.py and am having difficulty with the following:
in app.py
args = ()
for i in range(4):
args = args + (form.Checkbox('followup'+str(i)), )
my_form = form.Form(*args)
in my_template.html
$for i in range(4):
$ name = "followup"+ str(i)
$name $:form.$name.render() <br>
when I run this I get the following error:
'str' object has no attribute 'render'
How should I change my template so that I will have 4 checkboxes?
Any help would be greatly appreciated.

The problem is $:form.$name resolves to a string, prior to the call to render(). You can fix that by replacing it with $:form[name]. You're still in the "python" context with form[name], so you should use name rather than $name.
=== my_template.html ===
$def with(form)
$for i in range(4):
$ name = 'followup' + str(i)
$name $:form[name].render()<br/>
or, even simpler:
=== my_template.html ===
$def with(form)
$for i in form.inputs:
$i.description $:i.render()<br/>

Related

Global symbol requires explicit package name perl

This code is giving me a Global Symbol requires explicit package name error. It's throwing it on the second time $user is defined. Below the code is the error. I don't understand the reasoning behind $user not having one. I'm trying to add to the hash that's returned.
my $self = shift;
my %json = ('err' => 0, 'msg' => '');
my $user = Order2016::get_orders($self->usernum); # Returns Hash
# Query to grab session history data
my $sql = "select rate.duration, rate.price, rate.description, rate.active, order.user_id, order.quantity, order.add_date, order.modify_date, order.end_date, order.last_bill, order.next_bill, item.*
from rate, order, item
where order.user_id = ?
and order.rate_id = rate.id
and rate.item_id = item.id";
my $query = new SQL($sql, $self->usernum);
my $hist = $query->GetRecordsAsHashRef();
$user{'uid'} = $self->usernum;
$self->Print(to_json($user));
Global symbol "%user" requires explicit package name at /devroot/depot/wxtap/deploy/scripts//Account.pm line 1340.
Compilation failed in require at /usr/lib/perl5/Apache2/porting.pm line 90.
I suspect that $user is a hash reference, not a hash. To use it, you need to dereference it first (using the -> operator):
$user->{uid} = $self->usernum;
This could also be written as:
$$user{uid} = ...;
...but that's far less common, and it's much more idiomatic to use the former method.
Please try $user->{'uid'}.
$user is being used as a reference here.

WWW::Mechanize::Firefox xpath on previous result

Can I execute a XPath query on previous result?
I have this xpath:
my #objDivRes = $objBrow->xpath('//div[#id="result"]/ol/div/li', all => 1);
but when I execute xpath function on previous result
my #objLink = $objDivRes[0]->MozRepl::RemoteObject::Methods::xpath('//div/h3/a');
I got an error:
MozRepl::RemoteObject: TypeError: doc.evaluate is not a function at test.pl
Is there an example? Thank you
Just use 'node' option to set up a subtree $mech->xpath( $query, %options )
Note dot in the beginning of the path, which means descendands of the context node
my #objDivRes = $objBrow->xpath('//div[#id="result"]/ol/div/li', all => 1);
my #objLink = $objBrow->xpath('.//div/h3/a', node => $objDivRes[0]);

Send request parameters when calling a PHP script via command line

When you run a PHP script through a browser it looks something like
http://somewebsite.com/yourscript?param1=val1&param2=val2.
I am trying to achieve the same thing via command line without having to rewrite the script to accept argv instead of $_REQUEST. Is there a way to do something like this:
php yourscript.php?param1=val1&param2=val2
such that the parameters you send show up in the $_REQUEST variable?
In case you don't want to modify running script, you can specify parameters using in -B parameter to specify code to run before the input file. But in this case you must also add -F tag to specify your input file:
php -B "\$_REQUEST = array('param1' => 'val1', 'param2' => 'val2');" -F yourscript.php
I can't take credit for this but I adopted this in my bootstrap file:
// Concatenate and parse string into $_REQUEST
if (php_sapi_name() === 'cli') {
parse_str(implode('&', array_slice($argv, 1)), $_REQUEST);
}
Upon executing a PHP file from the command line:
php yourscript.php param1=val1 param2=val2
The above will insert the keys and values into $_REQUEST for later retrieval.
No, there is no easy way to achieve that. The web server will split up the request string and pass it into the PHP interpreter, who will then store it in the $_REQUEST array.
If you run from the command line and you want to accept similar parameters, you'll have to parse them yourself. The command line has completely different syntax for passing parameters than HTTP has. You might want to look into getopt.
For a brute force approach that doesn't take user error into account, you can try this snippet:
<?php
foreach( $argv as $argument ) {
if( $argument == $argv[ 0 ] ) continue;
$pair = explode( "=", $argument );
$variableName = substr( $pair[ 0 ], 2 );
$variableValue = $pair[ 1 ];
echo $variableName . " = " . $variableValue . "\n";
// Optionally store the variable in $_REQUEST
$_REQUEST[ $variableName ] = $variableValue;
}
Use it like this:
$ php test.php --param1=val1 --param2=val2
param1 = val1
param2 = val2
I wrote a short function to handle this situation -- if command line arguments are present and the $_REQUEST array is empty (ie, when you're running a script from the command line instead of though a web interface), it looks for command line arguments in key=value pairs,
Argv2Request($argv);
print_r($_REQUEST);
function Argv2Request($argv) {
/*
When $_REQUEST is empty and $argv is defined,
interpret $argv[1]...$argv[n] as key => value pairs
and load them into the $_REQUEST array
This allows the php command line to subsitute for GET/POST values, e.g.
php script.php animal=fish color=red number=1 has_car=true has_star=false
*/
if ($argv !== NULL && sizeof($_REQUEST) == 0) {
$argv0 = array_shift($argv); // first arg is different and is not needed
foreach ($argv as $pair) {
list ($k, $v) = split("=", $pair);
$_REQUEST[$k] = $v;
}
}
}
The sample input suggested in the function's comment is:
php script.php animal=fish color=red number=1 has_car=true has_star=false
which yields the output:
Array
(
[animal] => fish
[color] => red
[number] => 1
[has_car] => true
[has_star] => false
)

Perl referencing and deferencing hash values when passing to subroutine?

I've been banging my head over this issue for about 5 hours now, I'm really frustrated and need some assistance.
I'm writing a Perl script that pulls jobs out of a MySQL table and then preforms various database admin tasks. The current task is "creating databases". The script successfully creates the database(s), but when I got to generating the config file for PHP developers it blows up.
I believe it is an issue with referencing and dereferencing variables, but I'm not quite sure what exactly is happening. I think after this function call, something happens to
$$result{'databaseName'}. This is how I get result: $result = $select->fetchrow_hashref()
Here is my function call, and the function implementation:
Function call (line 127):
generateConfig($$result{'databaseName'}, $newPassword, "php");
Function implementation:
sub generateConfig {
my($inName) = $_[0];
my($inPass) = $_[1];
my($inExt) = $_[2];
my($goodData) = 1;
my($select) = $dbh->prepare("SELECT id FROM $databasesTableName WHERE name = '$inName'");
my($path) = $documentRoot.$inName."_config.".$inExt;
$select->execute();
if ($select->rows < 1 ) {
$goodData = 0;
}
while ( $result = $select->fetchrow_hashref() )
{
my($insert) = $dbh->do("INSERT INTO $configTableName(databaseId, username, password, path)".
"VALUES('$$result{'id'}', '$inName', '$inPass', '$path')");
}
return 1;
}
Errors:
Use of uninitialized value in concatenation (.) or string at ./dbcreator.pl line 142.
Use of uninitialized value in concatenation (.) or string at ./dbcreator.pl line 154.
Line 142:
$update = $dbh->do("UPDATE ${tablename}
SET ${jobStatus}='${newStatus}'
WHERE id = '$$result{'id'}'");
Line 154:
print "Successfully created $$result{'databaseName'}\n";
The reason I think the problem comes from the function call is because if I comment out the function call, everything works great!
If anyone could help me understand what's going on, that would be great.
Thanks,
p.s. If you notice a security issue with the whole storing passwords as plain text in a database, that's going to be addressed after this is working correctly. =P
Dylan
You do not want to store a reference to the $result returned from fetchrow_hashref, as each subsequent call will overwrite that reference.
That's ok, you're not using the reference when you are calling generate_config, as you are passing data in by value.
Are you using the same $result variable in generate_config and in the calling function? You should be using your own 'my $result' in generate_config.
while ( my $result = $select->fetchrow_hashref() )
# ^^ #add my
That's all that can be said with the current snippets of code you've included.
Some cleanup:
When calling generate_config you are passing by value, not by reference. This is fine.
you are getting an undef warning, this means you are running with 'use strict;'. Good!
create lexical $result within the function, via my.
While $$hashr{key} is valid code, $hashr->{key} is preferred.
you're using dbh->prepare, might as well use placeholders.
sub generateConfig {
my($inName, inPass, $inExt) = #_;
my $goodData = 1;
my $select = $dbh->prepare("SELECT id FROM $databasesTableName WHERE name = ?");
my $insert = $dbh->prepare("
INSERT INTO $configTableName(
databaseID
,username
,password
,path)
VALUES( ?, ?, ?, ?)" );
my $path = $documentRoot . $inName . "_config." . $inExt;
$select->execute( $inName );
if ($select->rows < 1 ) {
$goodData = 0;
}
while ( my $result = $select->fetchrow_hashref() )
{
insert->execute( $result->{id}, $inName, $inPass, $path );
}
return 1;
}
EDIT: after reading your comment
I think that both errors have to do with your using $$result. If $result is the return value of fetchrow_hashref, like in:
$result = $select->fetchrow_hashref()
then the correct way to refer to its values should be:
print "Successfully created " . $result{'databaseName'} . "\n";
and:
$update = $dbh->do("UPDATE ${tablename}
SET ${jobStatus}='${newStatus}'
WHERE id = '$result{'id'}'");
OLD ANSWER:
In function generateConfig, you can pass a reference in using this syntax:
generateConfig(\$result{'databaseName'},$newPassword, "php");
($$ is used to dereference a reference to a string; \ gives you a reference to the object it is applied to).
Then, in the print statement itself, I would try:
print "Successfully created $result->{'databaseName'}->{columnName}\n";
indeed, fetchrow_hashref returns a hash (not a string).
This should fix one problem.
Furthermore, you are using the variable named $dbh but you don't show where it is set. Is it a global variable so that you can use it in generateConfig? Has it been initialized when generateConfig is executed?
This was driving me crazy when I was running hetchrow_hashref from Oracle result set.
Turened out the column names are always returned in upper case.
So once I started referencing the colum in upper case, problem went away:
insert->execute( $result->{ID}, $inName, $inPass, $path );

SeleniumRC/Perl dynamic XPath selector not working

This is more a question for XPath syntax than anything else.
I have multiple product pages on a site that have multiple products on each product pages. Each product has a unique ID for the add-to-cart button. I'm trying to return all of the unique ID's so that I can add a couple of the products to the bag. Searching with XPath seems to be the correct solution for this. I have the following code for querying the HTML with XPath and returning the unique ID's:
$XPATH_COUNT = $sel->get_xpath_count("//div[\#class='quick-info-link']/a");
#my_array;
$my_array[0] = $sel->get_attribute("//div[\#class='quick-info-link']/a/\#id");
print $my_array[0];
$count = 0;
while( $count < $XPATH_COUNT )
{
$arrayCount=0;
$a = "//";
foreach( #my_array )
{
$tmp = "a[\#id!='" . $my_array[$arrayCount] . "' and ";
$b .= $tmp;
$d .= "]";
$arrayCount++;
}
$c = "img[\#alt='Quick Shop']";
$e = $c . $d . "/\#id";
$xpath_query = $a . $b . $e;
$my_array[$count] = $sel->get_attribute($xpath_query);
$count++;
}
The output of the first run of this is an XPath query that looks like this:
//a[#id!='quickview-link-PROD7029' and img[#alt='Quick Shop']]/#id
Which correctly returns quickview-link-PROD6945. The second run produces this:
//a[#id!='quickview-link-PROD7029' and a[#id!='quickview-link-PROD6945' and img[#alt='Quick Shop']]]/#id
Which throws an error in my SeleniumRC terminal window of ERROR: Element [..xpath query..] not found on session.
I am aware of the possible use of indexes (i.e. adding an [i] to the end of the XPath query) to access elements on the page, however this isn't something that has worked for me in Selenium.
Any help would be great. Thanks for your time,
Steve
//a[#id!='quickview-link-PROD7029'
and a[#id!='quickview-link-PROD6945' and
img[#alt='Quick Shop']
]
]/#id
Which throws an error in my SeleniumRC
terminal window of ERROR: Element
[..xpath query..] not found on session
It would greatly help if you provide the XML document on which the XPath expression is applied and explain which node(s) you want to select.
Without this necessary information:
The most obvious reason for this problem is that the above expression is looking for a elements that have an a child with some property.
Usually an a element doesn't have any a children.
What you really want is something like:
//a[#id != 'quickview-link-PROD7029'
and
#id != 'quickview-link-PROD6945' and img[#alt='Quick Shop']
]/#id
This can be simplified a bit:
//a[img[#alt='Quick Shop']/#id
[not(. = 'quickview-link-PROD7029'
or
. = 'quickview-link-PROD6945'
)
]