I'm trying to use Net::Google::Spreadsheets to manipulate a Google Docs spreadsheet (side note: you may have seen my previous question where I was trying to work from the inside of Google Docs, now I'm trying a different angle)
I'm trying an example pretty much straight out of the perldoc:
#!/usr/bin/perl
use strict;
use warnings;
use Net::Google::Spreadsheets;
my $service = Net::Google::Spreadsheets->new(
username => 'my.email#gmail.com',
password => 'mypassword'
);
my #spreadsheets = $service->spreadsheets();
# find a spreadsheet by key
my $spreadsheet = $service->spreadsheet(
{
title => 'Perl Test' # This is a spreadsheet I manually created already
}
);
# find a worksheet by title
my $worksheet = $spreadsheet->worksheet(
{
title => 'Sheet1'
}
);
my $cell = $worksheet->cell({col => 1, row => 1});
# update input value of a cell
$cell->input_value('new value');
When I run my code, I get this error:
request for 'https://spreadsheets.google.com/feeds/worksheets/tNdoUPkz7MhRAtVoBaaZVHQ/private/full?title=Sheet1' failed:
500 Internal Server Error
Internal Error
at /usr/local/share/perl/5.10.1/Net/Google/DataAPI/Role/Service.pm line 96
Net::Google::DataAPI::Role::Service::request('Net::Google::Spreadsheets=HASH(0x167ce60)', 'HASH(0x1c63ba8)') called at /usr/local/share/perl/5.10.1/Net/Google/DataAPI/Role/Service.pm line 158
Net::Google::DataAPI::Role::Service::get_feed('Net::Google::Spreadsheets=HASH(0x167ce60)', 'https://spreadsheets.google.com/feeds/worksheets/tNdoUPkz7MhR...', 'HASH(0x1a38d58)') called at /usr/local/share/perl/5.10.1/Net/Google/DataAPI.pm line 106
Net::Google::Spreadsheets::Spreadsheet::worksheets('Net::Google::Spreadsheets::Spreadsheet=HASH(0x1a36460)', 'HASH(0x1a38d58)') called at /usr/local/share/perl/5.10.1/Net/Google/DataAPI.pm line 119
Net::Google::Spreadsheets::Spreadsheet::worksheet('Net::Google::Spreadsheets::Spreadsheet=HASH(0x1a36460)', 'HASH(0x1a38d58)') called at spreadsheet_test.pl line 22
And then if I try to open up the Perl Test spreadsheet from within Google Docs, Google itself gives me the equivalent of a 500 error.
So what am I doing wrong?
Related
I am trying to use Perl google spreadsheet API and i am getting stuck in this error. I did exactly as per the doc at http://search.cpan.org/~danjou/Net-Google-Spreadsheets-0.1501/lib/Net/Google/Spreadsheets.pm
Here is the code
use Net::Google::Spreadsheets;
use Net::Google::DataAPI::Auth::OAuth2;
use Net::OAuth2::AccessToken;
my $oauth2;
my $service;
$oauth2 = Net::Google::DataAPI::Auth::OAuth2->new(
client_id => '<clientid>',
client_secret => '<client secret>',
scope => ['http://spreadsheets.google.com/feeds/'],
);
my $url = $oauth2->authorize_url(
access_type => 'offline',
approval_prompt => 'force',
);
print "$url\nEnter the code: ";
my $code = <STDIN>;
my $access_token = $oauth2->get_access_token($code) or die;
$service = Net::Google::Spreadsheets->new(auth => $oauth2);
print "Testing Spreadsheet";
# find a spreadsheet by key
my $spreadsheet = $service->spreadsheet( { key => '<spread sheet key>' }) or die $!;
It does not throw error during Oauth but when I try to access the spreadsheet API it gives me the following error.
Use of uninitialized value $nsURI in string eq at
/usr/local/lib/perl5/site_perl/5.14.2/mach/XML/LibXML.pm line 1705.
at /usr/local/lib/perl5/site_perl/5.14.2/mach/XML/LibXML.pm line 1699.
XML::LibXML::Element::getElementsByTagNameNS(XML::LibXML::Element=SCALAR(0x80416ed20),
undef, "entry") called at
/usr/local/lib/perl5/site_perl/5.14.2/XML/Atom/Feed.pm line 84
XML::Atom::Feed::entries_libxml(XML::Atom::Feed=HASH(0x8041938e8))
called at /usr/local/lib/perl5/site_perl/5.14.2/Net/Google/DataAPI.pm
line 113
Net::Google::Spreadsheets::spreadsheets(Net::Google::Spreadsheets=HASH(0x803045600),
HASH(0x802a5cb70)) called at
/usr/local/lib/perl5/site_perl/5.14.2/Net/Google/Spreadsheets.pm line
57
Net::Google::Spreadsheets::ANON(CODE(0x803020438), Net::Google::Spreadsheets=HASH(0x803045600), HASH(0x802a5cb70)) called
at /usr/local/lib/perl5/site_perl/5.14.2/mach/Mouse/Meta/Class.pm line
381
Mouse::Meta::Class::ANON(Net::Google::Spreadsheets=HASH(0x803045600),
HASH(0x802a5cb70)) called at
/usr/local/lib/perl5/site_perl/5.14.2/mach/Mouse/Meta/Class.pm line
334
Net::Google::Spreadsheets::spreadsheets(Net::Google::Spreadsheets=HASH(0x803045600),
HASH(0x802a5cb70)) called at
/usr/local/lib/perl5/site_perl/5.14.2/Net/Google/DataAPI.pm line 132
Net::Google::Spreadsheets::spreadsheet(Net::Google::Spreadsheets=HASH(0x803045600),
HASH(0x802a5cb70)) called at try.pl line 62
For anyone having the same problem here is the solution.
Looks like between the time when this module was written and today google has changed their API so the documentation of the module needs to be modified.
By changing the key => 'the key' to id => 'the key' solved the problem.
So the correct way to get the spreadsheet would be
my $spreadsheet = $service->spreadsheet( { id => '<spread sheet key>' }) or die
$!;
The key is part of the url
https://docs.google.com/spreadsheets/d/[spreadsheetkey]/edit
I am new in Perl and also RRDs.
I have tried to implement a simple example, and although it seems that is operating correctly the output is not displayed. The pictures are produced normally but there is no data in the graphs.
I have been following the CPAN documentation for implementation RRD::Simple and theoretically I am doing something wrong. I tried to debug the code and it seems fine, but when it comes to print the graphs there is no data.
#!/usr/bin/perl
use strict;
use warnings;
use RRD::Simple ();
use Data::Dumper;
$| = 1; # Flush the output
my ($rrd, $unixtime, $file);
$file = "perl.txt";
my $path = '/home/os/Desktop/Test_Perl/';
my $period = '3years';
my $rrdfile = 'myfile.rrd';
while (sleep 15) {
open(FH, ">>", $file) || die "Unable to open $file: $!\n";
my $range = 50;
my $minimum = 100;
my $random_number_in = int(rand($range)) + $minimum;
my $random_number_out = int(rand($range)) + $minimum;
my $random_number_sec = int(rand($range)) + $minimum;
# Create an interface object
$rrd = RRD::Simple->new(
file => $rrdfile,
cf => [qw( AVERAGE MIN MAX LAST )],
#default_dstype => "DERIVE",
);
unless (-e $rrdfile) {
# Create a new RRD file with 3 data sources called
# bytesIn, bytesOut and faultsPerSec.
$rrd->create(
$period,
step => 5, # 5 sec interval
bytesIn => "GAUGE",
bytesOut => "GAUGE",
faultsPerSec => "GAUGE"
);
}
# Put some arbitary data values in the RRD file for the same
# 3 data sources called bytesIn, bytesOut and faultsPerSec.
$rrd->update(
bytesIn => $random_number_in,
bytesOut => $random_number_out,
faultsPerSec => $random_number_sec
);
print FH "This is the bytes_in: $random_number_in\n";
print FH "This is the bytes_out: $random_number_out\n";
print FH "This is the bytes_sec: $random_number_sec\n";
# Generate graphs:
# /home/os/Desktop/Test_Perl/myfile-hourly.png, /home/os/Desktop/Test_Perl/myfile-daily.png
# /home/os/Desktop/Test_Perl/myfile-weekly.png, /home/os/Desktop/Test_Perl/myfile-monthly.png
my %rtn = $rrd->graph(
$rrdfile,
destination => $path,
basename => "my_graph",
timestamp => "both", # graph, rrd, both or none
periods => [qw(hour day week month)], # omit to generate all graphs
sources => [qw(bytesIn bytesOut faultsPerSec)],
source_colors => [qw(ff0000 aa3333 000000)],
source_labels => [("Bytes In", "Bytes Out", "Faults Per Second")],
source_drawtypes => [qw(LINE1 AREA LINE)],
line_thickness => 2,
extended_legend => 1,
title => "Network Interface eth0",
vertical_label => "Bytes/Faults",
width => 800,
height => 500,
interlaced => "", # If images are interlaced they become visible to browsers more quickly
);
printf("Created %s\n", join(", ", map { $rtn{$_}->[0] } keys %rtn));
# Return information about an RRD file
my $info = $rrd->info($rrdfile); # This method will return a complex data structure containing details about the RRD file, including RRA and data source information.
print Data::Dumper::Dumper($info);
my #sources = $rrd->sources($rrdfile);
my $seconds = $rrd->retention_period($rrdfile); # This method will return the maximum period of time (in seconds) that the RRD file will store data for.
# Get unixtime of when RRD file was last updated
$unixtime = $rrd->last($rrdfile);
print FH "myfile.rrd was last updated at " . scalar(localtime($unixtime)) . "\n";
# Get list of data source names from an RRD file
my #dsnames = $rrd->sources;
print "Available data sources: " . join(", ", #dsnames) . "\n";
my $heartbeat_In = $rrd->heartbeat($rrdfile, "bytesIn");
my $heartbeat_Out = $rrd->heartbeat($rrdfile, "bytesOut");
my $heartbeat_sec = $rrd->heartbeat($rrdfile, "faultsPerSec"); # This method will return the current heartbeat of a data source.
printf "This is the heartbeat_in: %s\n", $heartbeat_In;
my #rtn_In = $rrd->heartbeat($rrdfile, "bytesIn", 10);
my #rtn_Out = $rrd->heartbeat($rrdfile, "bytesOut", 10);
my #rtn_sec = $rrd->heartbeat($rrdfile, "faultsPerSec", 10); # This method will set a new heartbeat of a data source.
close(FH);
}
Part of the output:
'myfilerrd' => {
'last_ds' => 'U',
'value' => undef,
'min' => '0',
'max' => undef,
'minimal_heartbeat' => 120,
'index' => 3,
'type' => 'DERIVE',
'unknown_sec' => 15
}
I do not understand why the value is undefined?
After 3-4 days of testing and searching over the Internet for more information I just found the answer to my problem. RRD is a very simple to use tool but very very powerful. I would recommend anybody to use it through Perl especially with RRD::Simple module is very easy.
Answer:
I was adjusting the heart beat of my RRD to 10 sec, while my step (data collection time) is 300 by default. If the user do not specify the step "sampling frequency" by default the system will use 300. In result the graph takes 0 values so there is not output. More information and very nice analysis can be found here HeartBeat
Based on my experimentation, I found that since I am using a while loop inside the create function I have to first give the command:
my $rrd = RRD::Simple->new( file => "myfile.rrd" );
and as a second step I had to kill the process and set the step by entering the command:
my $rrd = RRD::Simple->new(
file => "myfile.rrd",
step => 50 );
Based on my experimentation I found that I had to remove this block of code below had to be added to the file as a second step. First had to make the creation and then add it on my loop. This is because initially the "myfile.rrd" has to be created with all the settings, before the user start modifying them.
unless (-f "myfile.rrd") {
$rrd->create(
step => 50,
bytesIn => "GAUGE",
bytesOut => "GAUGE",
faultsPerSec => "COUNTER"
);
}
Another point that worth mentioning here is that by default RRD Data Source (DS) is set to GAUGE. More information can be found here RRDtool
The Perl module can be found easily CPAN RRD::Simple which provides analysis and extra "features" that you can add to your code.
In conclusion RRD::Simple is very simple, it can be executed by copy-paste into your program. Any further modifications (e.g sample rates, Average/Max/Min values etc.) need a bit of reading upon but definitely worth the effort. Unfortunately there is not much of examples online so some testing need it to be done in order to understand what I need to modify in my code to make it work. By writing this short analysis and providing some links to read upon I hope to save someone else from spending a few days to come up with the answer to his problem.
Again I encourage anyone to try implementing RRD's is a very powerful tool to graphically view your results and store the data up to 3 years.
Another update that I think is useful to some people maybe. Instead of following all this process by adding and removing code in order to make the rrd file working.
After modifications and experimentation I found another solution.
use strict;
use RRD::Simple;
use RRDs;
my $rrd = RRD::Simple->new(
file => "myfile.rrd",
rrdtool => "/usr/local/rrdtool-1.2.11/bin/rrdtool", #optional
tmpdir => "/var/tmp", #optional
cf => [ qw(AVERAGE MAX) ], #optional
default_dstype => "COUNTER", #optional
on_missing_ds => "add", #optional
RRDs::tune("myfile.rrd", "-i", "Source_Name:0") #optional -i or --minimum
RRDs::tune("myfile.rrd", "-a", "Source_Name:200") #optional -a or --maximum
);
There are several optional values that someone can use, but I recommend to use all of them so you can take full control of the program.
I am using:
default_dstype => "COUNTER", #optional
Because by default RRD's will set GAUGE as Data Source (DS). By setting the DS to COUNTER the user can set the minimum and maximum values. Short examples can be found here also RRD::Simple::Examples.
I have a Solaris system with x86 CPU, when I try to connect to sybase db with perl, i got the following error(the error was generated when I run the script in debug mode and step into function DBD::Sybase::db::_login at Sybase.pm in line 94)
ct_con_props(CS_PASSWORD) failed at /usr/local/lib/perl5/site_perl/5.8.8/i86pc-solaris/DBD/Sybase.pm line 94.
at /usr/local/lib/perl5/site_perl/5.8.8/i86pc-solaris/DBD/Sybase.pm line 94
DBD::Sybase::dr::connect('DBI::dr=HASH(0x8613a5c)', 'server=server1', 'user1, 'password1', 'HASH(0x86b4e5c)') called at /usr/local/lib/perl5/site_perl/5.8.8/i86pc-solaris/DBI.pm line 617
DBI::_ANON_/usr/local/lib/perl5/site_perl/5.8.8/i86pc-solaris/DBI.pm:679 called at /usr/local/lib/perl5/site_perl/5.8.8/i86pc-solaris/DBI.pm line 681
DBI::connect('DBI', 'DBI:Sybase:server=server1', 'user1, 'password1') called at ./test.pl line 28
DBI::CODE(0x83fcdd4)(/usr/local/lib/perl5/site_perl/5.8.8/i86pc-solaris/DBI.pm:618):
618: $user = '' if !defined $user;
from the message, it seems there is something wrong with the password? but I am sure the password was correct and the same code works very well on a Spark-solaris system, could anyone tell me what's wrong, or tell me how can I get into the function DBD::Sybase::db::_login($this, $server, $user, $auth, $attr)? looks like this function was in an .xs file, but I can not find where is it, and can not debug into it.
if I run the script withtout debug, i got the following error
ct_con_props(CS_PASSWORD) failed at /usr/local/lib/perl5/site_perl/5.8.8/i86pc-solaris/DBD/Sybase.pm line 94.
DBI connect('server=server1','user1’,...) failed: OpenClient message: LAYER = (1) ORIGIN = (4) SEVERITY = (6) NUMBER = (221)
Server server1, database
Message String: ct__string_extended_encryption: user api layer: internal common library error: error string not available
at ./test.pl line 28
Connect failed at ./test.pl line 28.
here is the code of sub connect in Sybase.pm
sub connect {
my($drh, $dbase, $user, $auth, $attr) = #_;
my $ifile = '';
my $server = $dbase || $ENV{DSQUERY} || 'SYBASE';
my($this) = DBI::_new_dbh($drh, {
'Name' => $server,
'Username' => $user,
'CURRENT_USER' => $user,
});
DBD::Sybase::db::_login($this, $server, $user, $auth, $attr)
or return undef;
return $this;
}
After sending a email to Michael Peppler(the module writer), I got the following answer and the issue was fixed.
The issue is the lib3p directory, which contains libraries that are loaded at run time directly by OpenClient, in particular for things like password encryption, etc.
This directory obviously needs to be in LD_LIBRARY_PATH, or be referenced in the default library search paths.
So basically, I need to add the path of OCS-15 folder to LD_LIBRARY_PATH
I am trying to write a script using Net::IMAP::Client that outputs the body of a email, but so far every variable i try and output from the module shows up as something like: ARRAY(0x86f5524) or gives an error "Can't use an undefined value as a SCALAR reference."
The module documentation says that
# fetch full messages
my #msgs = $imap->get_rfc822_body([ #msg_ids ]);
print $$_ for (#msgs)
should contain references to a scalar. #msg_id should be an array of numbers for the email number in the inbox, but is also returned as an array reference.
I am unsure how to properly output this data so it is readable.
Here is the module reference: Net::IMAP::Client
and here is a snipit of my code:
use Net::IMAP::Client;
use Net::IMAP;
use Net::SMTP;
use strict;
use warnings;
my $imap = Net::IMAP::Client->new(
server => ,
user => , # i omitted this data for privacy
pass => ,
ssl => ,
port => ,
) or die "could not connect to IMAP server";
$imap->login or die('Login Failed: ' . $imap->last_error);
my $num_messages = $imap->select('[Gmail]/All Mail');
my #msg_id = $imap->search('ALL');
print #msg_id;
print "\n";
my #data = $imap->get_rfc822_body([#msg_id]);
print $$_ for (#data);
EDIT: I used Data::Dumper and got a big block of test containing the email and all the formatting tags. I also know that $imap-search should return something, as the inbox has 4 emails, 2 unread. But so since the variable #data IS holding the emails, i cant figure out the proper way to de-reference it in the output
$imap->search('ALL') returns an array reference not an array. So you need to change
my #msg_id = $imap->search('ALL');
to
my #msg_id = #{$imap->search('ALL')};
It would be better though to check whether the method returned a defined value before dereferencing, in case it fails.
Looking at the code, the proper usage is:
my $msgs = $imap->get_rfc822_body([ #msg_ids ]);
print $$_ for #$msgs;
The get the documented behaviour,
return $wants_many ? \#ret : $ret[0];
should be
return $wants_many ? (wantarray ? #ret : \#ret) : $ret[0];
We have private MediaWiki installation inside our company. Based on daily builds on our source code, we update the wiki with Perforce labels so that people can use the build that is labeled for streamlined process. We tried to automate this using Perl scripts on a Windows server using MediaWiki::Bot and MediaWiki::API.
use MediaWiki::Bot;
use MediaWiki::API;
my $mw = MediaWiki::API->new();
$mw->{config}->{api_url} = 'http://somewiki/w/index.php/title#feature_List';
# log in to the wiki
$mw->login({
lgname => 'username',
lgpassword => 'password'
|| die $mw->{error}->{code} . ': ' . $mw->{error}->{details};
# get a list of articles in category
my $articles = $mw->list({
action => 'query',
list => 'categorymembers',
cmtitle => 'Category:Perl',
cmlimit => 'max'
}) || die $mw->{error}->{code} . ': ' . $mw->{error}->{details};
# and print the article titles
foreach (#{$articles}) {
print "$_->{title}\n";
}
Output:
2: Failed to decode JSON returned by http://vaporwiki/w/index.php/Executor#Execu
tor_Feature_List
Decoding Error:
malformed JSON string, neither array, object, number, string or atom, at charact
er offset 0 (before "<!DOCTYPE html PUBLI...") at C:/Perl/lib/MediaWiki/API.pm l
ine 398
Returned Data: <whole page data>
The API URL is wrong. Try http://vaporwiki/w/api.php.