Is there a way to tell which #INC path a module was loaded from? - perl

Use case
My sysadmin just installed a Perl module via rpm and despite the fact that I can successfully use it in a one-liner, I want to know where the module was installed.
I can obviously comb through each of the path locations in #INC, but is there a way for Perl to tell me where it successfully loaded the module from?

That's what the %INC hash is for. It shows you where a module was loaded from.
$ perl -MDBI -MData::Dumper -E'say Dumper \%INC'
$VAR1 = {
'XSLoader.pm' => '/usr/share/perl5/XSLoader.pm',
'warnings/register.pm' => '/usr/share/perl5/warnings/register.pm',
'List/Util.pm' => '/usr/local/lib64/perl5/List/Util.pm',
'warnings.pm' => '/usr/share/perl5/warnings.pm',
'DBI.pm' => '/usr/lib64/perl5/vendor_perl/DBI.pm',
'overloading.pm' => '/usr/share/perl5/overloading.pm',
'Config.pm' => '/usr/lib64/perl5/Config.pm',
'Carp.pm' => '/usr/share/perl5/vendor_perl/Carp.pm',
'bytes.pm' => '/usr/share/perl5/bytes.pm',
'Exporter/Heavy.pm' => '/usr/share/perl5/vendor_perl/Exporter/Heavy.pm',
'Scalar/Util.pm' => '/usr/local/lib64/perl5/Scalar/Util.pm',
'strict.pm' => '/usr/share/perl5/strict.pm',
'Exporter.pm' => '/usr/share/perl5/vendor_perl/Exporter.pm',
'vars.pm' => '/usr/share/perl5/vars.pm',
'constant.pm' => '/usr/share/perl5/vendor_perl/constant.pm',
'overload.pm' => '/usr/share/perl5/overload.pm',
'DynaLoader.pm' => '/usr/lib64/perl5/DynaLoader.pm',
'Data/Dumper.pm' => '/usr/lib64/perl5/vendor_perl/Data/Dumper.pm',
'feature.pm' => '/usr/share/perl5/feature.pm'
};
Update: Actually, there's an easier method.
$ perldoc -lm Your::Module

Related

pyodbc cannot find driverfile for PostgreSQL (when it exists)

I have a CentOS 8 server and I try to connect to a PostgreSQL DB.
My python-file looks like
def read_df(query):
"""
Function for fetching data from the DB.
"""
con_str = (
"DRIVER={PostgreSQL};"
"DATABASE=db;"
f"UID={user};"
f"PWD={pwd};"
f"SERVER={host};"
f"PORT={port};"
)
with pyodbc.connect(con_str) as con:
df = pd.read_sql(query,con=con)
return df
and /etc/odbcinst.ini
[PostgreSQL]
Driver = /usr/lib64/psqlodbcw.so
Setup = /usr/lib64/libodbcpsqlS.so
Driver64 = /usr/lib64/psqlodbcw.so
Setup64 = /usr/lib64/libodbcpsqlS.so
the files specified above do exist:
>ls /usr/lib64 | grep psq
psqlodbcw.so
psqlodbca.so
psqlodbc.so
libodbcpsqlS.so
and I can access the file
with open("/usr/lib64/psqlodbcw.so","r") as f:
print("It works")
"It works"
but running read_df throws
File "/home/user/db_connect.py", line 192, in read_df
with pyodbc.connect(con_str) as con:
pyodbc.Error: ('01000', "[01000] [unixODBC][Driver Manager]Can't open lib '/usr/lib64/psqlodbcw.so' : file not found (0) (SQLDriverConnect)")
I can see the file also from python import os; os.listdir("/usr/lib64") - and am completely lost.
EDIT: Running ldd /usr/lib64/psqlodbcw.so yields
$ ldd /usr/lib64/psqlodbcw.so
linux-vdso.so.1 (0x00007ffce158b000)
libpq.so.5 => /lib64/libpq.so.5 (0x00007f1e90be1000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1e909c1000)
libodbcinst.so.2 => /lib64/libodbcinst.so.2 (0x00007f1e907ab000)
libc.so.6 => /lib64/libc.so.6 (0x00007f1e903e6000)
libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007f1e90152000)
libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007f1e8fc6c000)
libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f1e8fa17000)
libldap_r-2.4.so.2 => /lib64/libldap_r-2.4.so.2 (0x00007f1e8f7c0000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1e910bb000)
libltdl.so.7 => /lib64/libltdl.so.7 (0x00007f1e8f5b6000)
libz.so.1 => /lib64/libz.so.1 (0x00007f1e8f39f000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f1e8f19b000)
libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f1e8eeb2000)
libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f1e8ec9b000)
libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f1e8ea97000)
libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f1e8e886000)
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f1e8e682000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f1e8e46b000)
liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007f1e8e25b000)
libsasl2.so.3 => /lib64/libsasl2.so.3 (0x00007f1e8e03d000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f1e8de13000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f1e8dbea000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f1e8d966000)

Is there any way to find available CPAN version programmatically?

I am trying to find CPAN version programmatically, but ends up in failure.
Tried with perl %Config & %ENV, but couldn't find anything there.
my $cpanv = `cpan -v`;
# gives: Loading internal null logger. Install Log::Log4perl for logging messages
My goal is to auto configure cpan programmatically. CPAN config prompt varies by versions.
CPAN asks like[similar]:
1. "Do you want to manually configure?[yes]"
2. "Do you want cpan to configure?[no]"
Any way to find CPAN version or avoiding unattended CPAN configuration?
The cpan command-line program is a wrapper around App::Cpan. As far as I can see, the two files always have the same version number. That means you can do something like this:
use App::Cpan;
my $cpanv = $App::Cpan::VERSION;
Update: There are a few concepts to get straight here.
CPAN.pm is a CPAN exploration module that was added to Perl version 5.004. It includes its own basic shell.
App::Cpan is a wrapper around CPAN.pm which adds an improved command interface. It was added to Perl 5.12.
cpan is a tiny script that uses App::Cpan. It was also added to Perl version 5.12. [Update: that's the current version of cpan - there was also an earlier one that was based on CPAN.pm.]
App::Cpan and cpan share the same version number (currently 1.675). CPAN.pm is older and therefore has a larger version number (currently 2.27).
The version number from App::CPAN is what you get when you run cpan -v - so that's what I've given you in my code.
My goal is to auto configure cpan programmatically.
If you're talking about systems with a known configuration, just create (or modify) ~/.cpan/CPAN/MyConfig.pm. For example, the following is mine:
$CPAN::Config = {
'auto_commit' => q[0],
'build_cache' => q[5],
'build_dir' => q[/home/ikegami/.cpan/build],
'build_requires_install_policy' => q[yes],
'cache_metadata' => q[1],
'check_sigs' => q[0],
'commandnumber_in_prompt' => q[1],
'connect_to_internet_ok' => q[1],
'cpan_home' => q[/home/ikegami/.cpan],
'dontload_hash' => { },
'ftp' => q[/usr/bin/ftp],
'ftp_passive' => q[1],
'ftp_proxy' => q[],
'getcwd' => q[cwd],
'gpg' => q[/usr/bin/gpg],
'gzip' => q[/bin/gzip],
'halt_on_failure' => q[0],
'histfile' => q[],
'http_proxy' => q[],
'inactivity_timeout' => q[0],
'index_expire' => q[1],
'inhibit_startup_message' => q[0],
'keep_source_where' => q[/home/ikegami/.cpan/sources],
'load_module_verbosity' => q[none],
'lynx' => q[],
'make' => q[/usr/bin/make],
'make_arg' => q[],
'make_install_arg' => q[],
'make_install_make_command' => q[/usr/bin/make],
'makepl_arg' => q[],
'mbuild_arg' => q[],
'mbuild_install_arg' => q[],
'mbuild_install_build_command' => q[./Build],
'mbuildpl_arg' => q[],
'ncftpget' => q[/usr/bin/ncftpget],
'no_proxy' => q[],
'pager' => q[less],
'perl5lib_verbosity' => q[none],
'prefer_external_tar' => q[1],
'prefer_installer' => q[MB],
'prerequisites_policy' => q[follow],
'scan_cache' => q[atstart],
'shell' => q[/bin/bash],
'show_upload_date' => q[0],
'tar' => q[/bin/tar],
'tar_verbosity' => q[none],
'term_is_latin' => q[1],
'term_ornaments' => q[1],
'trust_test_report_history' => q[0],
'unzip' => q[/usr/bin/unzip],
'urllist' => [q[http://ftp.osuosl.org/pub/CPAN/], q[http://mirrors.hub.co/CPAN/], q[http://cpan.arcticnetwork.ca/]],
'use_sqlite' => q[0],
'version_timeout' => q[15],
'wget' => q[/usr/bin/wget],
'yaml_load_code' => q[0],
};
1;
__END__
Optionally, you can force the defaults to be used, and modify what needs to be changed. For example,
cpan <<<'o conf init
yes
o conf prerequisites_policy ask
o conf commit
quit
'
o conf init causes the initalization process to be started. yes accepts the defaults. o conf prerequisites_policy ask is an example of changing a default. o conf commit saves the changes.

What is the right way to insert a line of code into a moodle module?

I have a the need to add a single line of code to locallib.php in the \mod\lti directory . ('custom_user' => $USER->username,)
$requestparams = array(
'resource_link_id' => $instance->id,
'resource_link_title' => $instance->name,
'resource_link_description' => $instance->intro,
'user_id' => $USER->id,
'roles' => $role,
'context_id' => $course->id,
'context_label' => $course->shortname,
'context_title' => $course->fullname,
'launch_presentation_locale' => current_language()
);
$requestparams = array(
'resource_link_id' => $instance->id,
'resource_link_title' => $instance->name,
'resource_link_description' => $instance->intro,
'user_id' => $USER->id,
'custom_user' => $USER->username,
'roles' => $role,
'context_id' => $course->id,
'context_label' => $course->shortname,
'context_title' => $course->fullname,
'launch_presentation_locale' => current_language()
);
Is there a right way to do this? Looking at plugins, it seems that they are for adding whole new functions, not just patching individual existing code.
Just having a look at the module - haven't come across it before.
There are custom parameters but they look like literal values.
I would say its okay to put that code in. Although I would probably add // CUSTOM before and after the mod.

Perl Hash Array foreach issue

I have a response which is displayed through Data::Dumper - Dumper($cat_response->result->{'categories'})
$VAR1 = { 'literature' => '1120', 'law' => '1153', 'arts and crafts' => '1132', 'children' => '1141', 'hobbies' => '1133', 'economy' => '1166', 'jobs' => '1140', 'media' => '1144', 'music' => '1147', 'animals' => '1170', 'business' => '1119', 'diet' => '1122', 'travel reviews' => '1154', 'jewelry' => '1157', 'movies' => '1146', 'television' => '1125', 'politics' => '1168', 'internet' => '1139', 'history' => '1129', 'recipes' => '1156', 'press releases' => '1151', 'presents' => '1128', 'marketing' => '1143', 'translations' => '1162', 'fashion' => '1145', 'technology' => '1163', 'real estate' => '1138', 'computer' => '1173', 'automobile' => '1116', 'finances' => '1126', 'weddings' => '1134', 'games' => '1127', 'esoterism' => '1124', 'horoscopes' => '1135', 'shopping' => '1123', 'humor' => '1137', 'miscellaneous' => '1159', 'science' => '1167', 'programming' => '1152', 'languages' => '1161', 'beauty' => '1117', 'sports' => '1160', 'hotels' => '1136', 'plants' => '1149', 'education' => '1118', 'traveling' => '1155', 'health' => '1130', 'telecommunication' => '1164', 'environment' => '1171', 'software' => '1158', 'sweepstakes' => '1131', 'logistics' => '1142', 'home and family' => '1169', 'news' => '1148' };
To access it, I use:
my %categories = $cat_response->result->{'categories'};
foreach my $cat (keys (%categories)) {
<option value="<% $categories{'$cat'} %>"><% $cat %></option>
}
However, the value of Dumper($cat) is: $VAR1 = 'HASH(0x7fe972641560)';
Did I miss something?
You missing use strict; use warnings; for one. (Well, either that, or you forgot to tell us that Perl told you about your problem.)
$cat_response->result->{'categories'} contains a reference to a hash. Makes no sense to assign that to a hash.
my $categories = $cat_response->result->{'categories'};
foreach my $cat (keys (%$categories)) {
<option value="<% $categories->{'$cat'} %>"><% $cat %></option>
}

using localtime inside moose default values

What's wrong with the code below ? When run, I get: "Use of uninitialized value in concatenation (.) or string at ./main.pl line 14"
#!/usr/bin/perl
package Test;
use Moose;
has 'message' => (isa => 'HashRef', is => 'ro', default => sub{{(localtime)[2] => {(localtime)[3] => "hello"}}});
# the one below works fine
#has 'message' => (isa => 'HashRef', is => 'ro', default => sub{{"18" => {"16" => "hello"}}});
sub show {
my $self = shift;
print("Test: " . $self->message->{(localtime)[2]}->{(localtime)[3]} . "\n");
}
my $o = Test->new();
$o->show();
If I do not use localtime() then it works fine. Also localtime[2] and [3] do not change very often (2 is hours, 3 is month day) so the problem is not that. If I run the script with a debugger, I get:
x $self
0 Test=HASH(0x3597300)
'message' => HASH(0x3597618)
16 => 'hello'
So it looks like I 'lose' one level of indirection, not really sure why... Any idea ?
The outer {} do not parse as a hashref. Add an explicit return:
has 'message' => (isa => 'HashRef', is => 'ro', default => sub{ return {(localtime)[2] => {(localtime)[3] => "hello"}} });
A + to force this works, too.
has 'message' => (isa => 'HashRef', is => 'ro', default => sub{ +{(localtime)[2] => {(localtime)[3] => "hello"}} });