Miscellaneous

mod_perl, environment vars

mod_perl, environment vars

by Steve Hideg -
Number of replies: 5
Hello.

We are using WeBWorK for administering advanced placement tests for Math. I've been asked to automate the export of test scores from WebWork and import them into our Student Information System (Banner).

I've taken a look at wwScoreGetter by Gavin LaRose. Thank you for sharing that, Gavin.

I've started constructing my own script, using the same modules that wwScoreGetter uses:

#!/usr/bin/perl -w

use strict;

my $wwHome = '/opt/webwork/webwork2';
my $wwCourseDir = "$wwHome/courses";
my $courseName = "Math_Placement_2014";

# set environment variables to allow use of WeBWorK scripts
#    to get these set correctly will probably require running this from
#    a wrapper
$ENV{WEBWORK_ROOT} = $wwHome;
$ENV{WEBWORK_DIRECTORY} = $wwHome;
$ENV{MOD_PERL_API_VERSION}=2;

use lib '/opt/webwork/pg/lib';
use lib '/opt/webwork/webwork2/lib';
use WeBWorK::PG::ImageGenerator;
use WeBWorK::CourseEnvironment;
use WeBWorK::DB;
use WeBWorK::ContentGenerator;
use WeBWorK::ContentGenerator::Instructor;
use WeBWorK::ContentGenerator::Instructor::Scoring;

exit;

When I run this, I get the following errors (separated with blank lines for readability):

Use of uninitialized value in concatenation (.) or string at /opt/webwork/webwork2/lib/WeBWorK/Localize.pm line 10.

Localize.pm: Full path for the localization directory set to |/lib/WeBWorK/Localize|

Use of uninitialized value in concatenation (.) or string at /opt/webwork/webwork2/lib/WeBWorK/Localize.pm line 11.

Subroutine WeBWorK::Localize::loc redefined at /usr/lib/perl5/site_perl/5.8.8/Locale/Maketext/Simple.pm line 123.

Subroutine WeBWorK::Localize::loc_lang redefined at /usr/lib/perl5/site_perl/5.8.8/Locale/Maketext/Simple.pm line 124.

Can't locate mod_perl.pm in @INC (@INC contains: /opt/webwork/webwork2/lib /opt/webwork/pg/lib /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-multi /usr/lib/perl5/site_perl/5.8.8 /usr/lib/perl5/site_perl /usr/lib64/perl5/vendor_perl/5.8.8/x86_64-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.8 /usr/lib/perl5/vendor_perl /usr/lib64/perl5/5.8.8/x86_64-linux-thread-multi /usr/lib/perl5/5.8.8 .) at /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm line 56.

BEGIN failed--compilation aborted at /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm line 56.

Compilation failed in require at ./wwaccess.pl line 22.

BEGIN failed--compilation aborted at ./wwaccess.pl line 22.

(Line 22 is "use WeBWorK::ContentGenerator;")

There seems to be at least 2 issues I'm facing here:

1.) It looks like the value of the WEBWORK_ROOT environment variable is not making it to Localize.pm. I've tried a wrapper script with the same results:

#!/bin/sh

WEBWORK_ROOT='/opt/webwork/webwork2'
export WEBWORK_ROOT
WEBWORK_DIRECTORY='/opt/webwork/webwork2'
export WEBWORK_DIRECTORY
MOD_PERL_API_VERSION=2
export MOD_PERL_API_VERSION

./wwaccess.pl

2.) ContentGenerator.pm needs mod_perl.pm and it can't be found. It's not installed, and when I try to install it from CPAN, it wants access to Apache source code, which is not on the host system. I don't know anything about how WebWork or Apache was installed on this machine (RedHat 5).

I think mod_perl2 is installed, based on what I've seen at http://localhost/server-info.

I'm working from a position of ignorance here. I wasn't involved in the installation and configuration of this box or the software. I'm just a dumb programmer.

Any advice on these issues would be greatly appreciated.

—Steve
In reply to Steve Hideg

Re: mod_perl, environment vars

by Davide Cervone -
This doesn't solve the issues you had above, but this is a bit of code that I had written to print out the scores for all students for a given homework set in a given class. Perhaps it is something that you can modify for your own needs.
#!/usr/bin/perl

#########################################
#
#  Values for course and set
#

my $courseID = "12FA-MTH115-01_02";
my $setID = "Week5";


#########################################

BEGIN {
  unless ($ENV{WEBWORK_ROOT}) {
    $ENV{WEBWORK_ROOT} = "/WeBWorK/webwork2";
  }
}

use lib "$ENV{WEBWORK_ROOT}/lib";
use WeBWorK::CourseEnvironment;
use WeBWorK::DB;

#########################################
#
#  Get course environment
#
our $ce = WeBWorK::CourseEnvironment->new({
  webwork_dir => $ENV{WEBWORK_ROOT},
  courseName => $courseID,
});
our $db = WeBWorK::DB->new($ce->{dbLayout});


#
#  Get problems
#
my @problemIDs = $db->listGlobalProblems($setID);

#
#  Get list of users
#
my %users;
foreach my $user ($db->getUsers($db->listUsers)) {
  next unless $user && $user->section ne "Practice";
  $users{$user->user_id} = $user
    if $ce->status_abbrev_has_behavior($user->status,"include_in_scoring");
}

#
#  Sort users and print out scores for those who have taken the exam
#
foreach my $user (sort {
  lc($users{$a}->last_name)  cmp lc($users{$b}->last_name) ||
  lc($users{$a}->first_name) cmp lc($users{$b}->first_name) ||
  lc($users{$a}->user_id)    cmp lc($users{$b}->user_id)
} keys %users) {
  my $User = $users{$user};
  my $score = 0; my $attempts = 0;
  my %problems = (map {$_->problem_id => $_} $db->getAllMergedUserProblems($user, $setID));
  foreach my $id (@problemIDs) {
    my $Problem = $problems{$id};
    $score += $Problem->status * $Problem->value;
    $attempts++ if ($Problem->num_correct || 0) + ($Problem->num_incorrect || 0);
  }
  print $User->last_name.", ".$User->first_name." (".$User->user_id."): ".sprintf("%.1f",$score)."\n"
    if $attempts;
}

#########################################

1;
In reply to Davide Cervone

Re: mod_perl, environment vars

by Steve Hideg -
Davide,

Thank you for this.

I'm adapting it to our environment. It looks promising.

—Steve
In reply to Steve Hideg

Re: mod_perl, environment vars

by Danny Glin -
I got the same error when I tried to run your script on my CentOS 6 system (a RedHat clone).  I was able to get it to run without errors by adding

use mod_perl2;

after the "use lib" statements (as well as setting the environment variables at the shell level like you did).

Though I think installing mod_perl from cpan in addition to mod_perl2 will probably cause more harm than good, if you want the apache source, it should just be a matter of running:

yum install httpd-devel

Danny
In reply to Danny Glin

Re: mod_perl, environment vars

by Steve Hideg -
Danny.

Thank you. Adding use mod_perl2; stops that particular error.

I'm still faced with the environment variable issues.

—Steve
In reply to Steve Hideg

Re: mod_perl, environment vars

by Davide Cervone -
For the record, here is another version of my program that handles Gateway Quiz assignments as well as homework assignments. For gateway quizzes, it prints out the score on each version of the quiz for each student.

Davide


#!/usr/bin/perl

#########################################
#
#  Values for course and set
#

my $courseID = "dpvc-test";
my $setID = "Gateway1";


#########################################

BEGIN {
  unless ($ENV{WEBWORK_ROOT}) {
    $ENV{WEBWORK_ROOT} = "/WeBWorK/webwork2";
  }
}

use lib "$ENV{WEBWORK_ROOT}/lib";
use WeBWorK::CourseEnvironment;
use WeBWorK::DB;

#########################################
#
#  Get course environment
#
our $ce = WeBWorK::CourseEnvironment->new({
  webwork_dir => $ENV{WEBWORK_ROOT},
  courseName => $courseID,
});
our $db = WeBWorK::DB->new($ce->{dbLayout});


#
#  Get set data and problems
#
my $globalSet = ($db->getGlobalSets($setID))[0];
my $isGateway = $globalSet->assignment_type =~ /gateway/i;
my @problemIDs = $db->listGlobalProblems($setID);

#
#  Get list of users
#
my %users;
foreach my $user ($db->getUsers($db->listUsers)) {
  next unless $user && $user->section ne "Practice";
  $users{$user->user_id} = $user
    if $ce->status_abbrev_has_behavior($user->status,"include_in_scoring");
}

#
#  Sort users and print out scores for those who have attempted the set
#
foreach my $user (sort {
  lc($users{$a}->last_name)  cmp lc($users{$b}->last_name) ||
  lc($users{$a}->first_name) cmp lc($users{$b}->first_name) ||
  lc($users{$a}->user_id)    cmp lc($users{$b}->user_id)
} keys %users) {
  my $User = $users{$user};
  my $scores = ($isGateway ? getGatewayScores($user,$setID) : getHomeworkScore($user,$setID));
  if (scalar(@$scores)) {
    my $score = join(', ',map {sprintf("%.1f",$_)} @$scores);
    print $User->last_name.", ".$User->first_name." (".$User->user_id."): $score\n";
  }
}

#########################################
#
#  Compute the scores for all versions of a gateway test
#
sub getGatewayScores {
  my $user = shift; my $setID = shift;
  my @scores = ();
  foreach my $v ($db->listSetVersions($user,$setID)) {
    my $score = 0; my $attempts = 0;
    my @records = $db->getProblemVersions(map {[$user,$setID,$v,$_]} @problemIDs);
    foreach $Problem (@records) {
      $score += $Problem->status * $Problem->value;
      $attempts++ if ($Problem->num_correct || 0) + ($Problem->num_incorrect || 0);
    }
    push(@scores,$score) if $attempts;
  }
  return [@scores];
}

#########################################
#
#  Compute the score for a homework set
#
sub getHomeworkScore {
  my $user = shift; my $setID = shift;
  my $score = 0; my $attempts = 0;
  my %problems = (map {$_->problem_id => $_} $db->getAllMergedUserProblems($user, $setID));
  foreach my $id (@problemIDs) {
    my $Problem = $problems{$id};
    if ($Problem) {
      $score += $Problem->status * $Problem->value;
      $attempts++ if ($Problem->num_correct || 0) + ($Problem->num_incorrect || 0);
    }
  }
  return ($attempts ? [$score] : []);
}

#########################################

1;