File Coverage

blib/lib/Net/Amazon/MechanicalTurk/Command/UpdateHITs.pm
Criterion Covered Total %
statement 33 112 29.4
branch 0 42 0.0
condition 0 6 0.0
subroutine 11 13 84.6
pod 0 1 0.0
total 44 174 25.2


line stmt bran cond sub pod time code
1             package Net::Amazon::MechanicalTurk::Command::UpdateHITs;
2 1     1   624 use strict;
  1         2  
  1         29  
3 1     1   5 use warnings;
  1         2  
  1         19  
4 1     1   4 use Carp;
  1         2  
  1         61  
5 1     1   5 use IO::File;
  1         1  
  1         152  
6 1     1   5 use Net::Amazon::MechanicalTurk::BulkSupport;
  1         1  
  1         16  
7 1     1   4 use Net::Amazon::MechanicalTurk::DataStructure;
  1         3  
  1         19  
8 1     1   5 use Net::Amazon::MechanicalTurk::RowData;
  1         1  
  1         19  
9 1     1   4 use Net::Amazon::MechanicalTurk::Properties;
  1         1  
  1         16  
10 1     1   4 use Net::Amazon::MechanicalTurk::Template;
  1         2  
  1         19  
11 1     1   4 use Net::Amazon::MechanicalTurk::Template::ReplacementTemplate;
  1         6  
  1         28  
12 1     1   4 use Net::Amazon::MechanicalTurk::DelimitedWriter;
  1         2  
  1         959  
13              
14             our $VERSION = '1.00';
15              
16             =head1 NAME
17              
18             Net::Amazon::MechanicalTurk::Command::UpdateHITs - Bulk HIT update support for Amazon Mechancial Turk.
19              
20             This module adds the updateHITs method to the Net::Amazon::MechanicalTurk class.
21              
22             =head1 SYNOPSIS
23              
24             my $properties = {
25             Title => 'UpdateHITs Perl sample 2',
26             Description => 'This is a test of the bulk updating API.',
27             Keywords => 'UpdateHITs, bulkload, perl',
28             Reward => {
29             CurrencyCode => 'USD',
30             Amount => 0.02
31             },
32             RequesterAnnotation => 'test',
33             AssignmentDurationInSeconds => 60 * 60,
34             AutoApprovalDelayInSeconds => 60 * 60 * 10,
35             };
36            
37             my $mturk = Net::Amazon::MechanicalTurk->new;
38            
39             $mturk->updateHITs(
40             properties => $properties,
41             input => "updatehits-input.csv",
42             progress => \*STDOUT,
43             success => "updatehits-success.csv",
44             fail => "updatehits-failure.csv"
45             );
46              
47             =head1 C
48              
49             updateHITs
50              
51             Bulk updates many hits to have a new hit type in Mechanical Turk.
52             The method takes a set of properties used to create a HITType and its
53             associated HITs. HITIds are pulled from an input source. For each row
54             in the input source, the HIT it identifies is modified to have the
55             properties specified.
56              
57             updateHITs takes a hash reference or a hash with the following parameters:
58              
59            
60             properties - (required) Either a hash reference or the name of a file,
61             containing the properties to use for generating a HITType
62             and the associated HITs. When the properties are read from
63             a file, the method
64             Net::Amazon::MechanicalTurk::Properties->readNestedData is
65             used.
66            
67             input - (required) The input source for row data.
68             This parameter may be of the following types:
69             - Net::Amazon::MechanicalTurk::RowData
70             - An array of hashes.
71             (This is internally converted into an object of type:
72             Net::Amazon::MechanicalTurk::RowData::ArrayHashRowData)
73             - A reference to a subroutine. When the updateHITs method
74             asks for row data, the subroutine will be called and
75             passed a subroutine reference, which should be called
76             for every row generated by the input. The generated row
77             should be a hash reference.
78             (This is internally converted into an object of type
79             Net::Amazon::MechanicalTurk::RowData::SubroutineRowData)
80             - The name of a file. The file should be either a CSV or
81             tab delimited file. If the file name ends with '.csv',
82             it will read as a CSV, otherwise it is assumed to be
83             tab delimited. The first row in the file should contain
84             the column names. Each subsequence row becomes a hash
85             reference based on the column names.
86             (This is internally converted into an object of type
87             Net::Amazon::MechanicalTurk::RowData::DelimitedRowData)
88            
89             progress - (optional) Used to display progress messages. This
90             parameter may be of the following types:
91             - A subroutine. The subroutine is called with 1 parameter,
92             a message to be displayed.
93             - An IO::Handle. The progress message is written to the
94             handle.
95            
96             success - (optional) Used to handle a successfully created hit. This
97             parameter may be of the following types:
98             - A filename. HITId's and HITTypeId's will be written to
99             this file. The file will be in a delimited format,
100             with the first row containing column headers. If the
101             filename ends in ".csv" the file format will be CSV,
102             otherwise it will be tab delimited.
103             - A subroutine. The subroutine is called when a hit is
104             created and passed a hash with the following parameters:
105             - mturk - A handle to the mturk client.
106             - row - The input row the hit was created
107             from.
108             - HITId - The HITId of the updated HIT.
109             - HITTypeId - The HITTypeId the updated HIT was
110             assigned to.
111            
112             fail - (optional) Used to handle a hit which failed creation. If
113             this value is not specified and a hit fails creation, an
114             error will be raised. This value may be of the following
115             types:
116             - A filename. The input row will be written back to the
117             file in a delimited format. If the file name ends with
118             ".csv", then the file will be in CSV format, otherwise
119             it will be in a tab delimited format.
120             - A subroutine. The subroutine will be called back with
121             a hash containing the following values:
122             - mturk - A handle to the mturk client.
123             - row - The input row the hit was created
124             from.
125             - HITId - The HITId that was to be updated
126             - HITTypeId - The HITTypeId that the HIT was to
127             be assigned to.
128             - error - The error message associated with
129             the failure.
130            
131             maxHits - (optional) If this value is greater than or equal to 0, than
132             at most maxHits will be created.
133            
134             =cut
135              
136              
137             sub updateHITs {
138 0     0 0   my $mturk = shift;
139 0           my %params = @_;
140            
141 0           foreach my $required (qw{ properties input }) {
142 0 0         if (!exists $params{$required}) {
143 0           Carp::croak("Missing required parameter $required.");
144             }
145             }
146            
147 0           my $progress = Net::Amazon::MechanicalTurk::BulkSupport::progressBlock($params{progress});
148 0           my $success = Net::Amazon::MechanicalTurk::BulkSupport::successBlock($params{success});
149 0           my $fail = Net::Amazon::MechanicalTurk::BulkSupport::failBlock($params{fail});
150 0 0         my $maxHits = (exists $params{maxHits}) ? $params{maxHits} : -1;
151            
152 0 0         if ($progress) {
153 0           $progress->("--[Initializing] " . scalar localtime() . " ---");
154 0           $progress->(" URL: " . $mturk->serviceUrl);
155 0           $progress->(" Properties: $params{properties}");
156 0           $progress->(" Input: $params{input}");
157             }
158            
159 0           my $properties = Net::Amazon::MechanicalTurk::Properties->toProperties($params{properties});
160 0           my $input = Net::Amazon::MechanicalTurk::RowData->toRowData($params{input});
161            
162 0           my $createHITTypeProperties = Net::Amazon::MechanicalTurk::BulkSupport::getCreateHITTypeProperties($properties);
163              
164 0           my $hitTypeId = -1;
165 0           my $exitedEach = 0;
166 0           my $rowNumber = 0;
167 0           my $hitsLoaded = 0;
168 0           my $failures = 0;
169 0           my $start = time();
170 0           my $hitIdKey;
171             my $lastHITId;
172            
173 0           eval {
174            
175             # Register HITType
176 0 0         $progress->("--[Registering HITType] " . scalar localtime() . " ---") if ($progress);
177 0           $hitTypeId = Net::Amazon::MechanicalTurk::BulkSupport::createHITType($mturk, $createHITTypeProperties, $properties, $progress);
178 0 0         $progress->(" Created HITType (HITTypeId: $hitTypeId)") if ($progress);
179            
180 0 0         $progress->("--[Updating HITs] " . scalar localtime() . " ---") if ($progress);
181             $input->each(sub {
182 0     0     my ($_self, $row) = @_;
183 0           $rowNumber++;
184            
185 0 0 0       if ($maxHits >= 0 and $rowNumber > $maxHits) {
186 0           $exitedEach = 1;
187 0           die "Exiting each loop";
188             }
189            
190             # Need to find the column name of the HITId key
191             # The loop is for case insensitive matching and ignoring white space.
192 0 0         if (!defined $hitIdKey) {
193 0           while (my ($key,$value) = each %$row) {
194 0 0         if ($key =~ /^\s*HITId\s*$/i) {
195 0           $hitIdKey = $key;
196 0           last;
197             }
198             }
199 0 0         if (!defined $hitIdKey) {
200 0           Carp::croak("Couldn't find HITId column. Row has the following columns: " .
201             join(", ", sort keys (%$row)));
202             }
203             }
204            
205 0 0         if (!exists $row->{$hitIdKey}) {
206 0           Carp::croak("Couldn't find HITId column on row $rowNumber.");
207             }
208 0           my $hitId = $row->{$hitIdKey};
209 0           $hitId =~ s/^\s+//;
210 0           $hitId =~ s/\s+$//;
211              
212            
213 0           eval {
214 0           my $changeProps = { HITId => $hitId, HITTypeId => $hitTypeId };
215 0           $mturk->ChangeHITTypeOfHIT(HITId => $hitId, HITTypeId => $hitTypeId);
216 0 0         $progress->(" Updated HITType of HIT $rowNumber (HITId: $lastHITId) to $hitTypeId.") if ($progress);
217 0           $hitsLoaded++;
218 0           $success->(
219             mturk => $mturk,
220             row => $row,
221             HITId => $lastHITId,
222             HITTypeId => $hitTypeId
223             );
224             };
225 0 0         if ($@) {
226 0           $failures++;
227 0 0         $progress->(" $@") if $progress;
228 0           $fail->(
229             mturk => $mturk,
230             row => $row,
231             HITId => $hitId,
232             HITTypeId => $hitTypeId,
233             error => $@
234             );
235             }
236 0           }); # End each
237             };
238 0 0 0       if ($@ and !$exitedEach) {
239 0           my $message = "\nAn error occurred while updating a HIT.\n";
240 0           $message .= "\n$@\n";
241 0 0         if ($mturk->response) {
242 0 0         if ($mturk->response->errorCode) {
243 0           $message .= "\nError Code: " . $mturk->response->errorCode . "\n";
244 0           $message .= "Error Message: " . $mturk->response->errorMessage . "\n";
245             }
246             }
247 0 0         if ($rowNumber > 0) {
248 0           $message .= "\nFailed on row $rowNumber in input $params{input}.\n";
249             }
250 0 0         if ($mturk->request) {
251 0           $message .= "\nLast operation called " . $mturk->request->{Operation} . ".\n";
252 0           $message .= "\nDump of call parameters:\n" .
253             Net::Amazon::MechanicalTurk::BulkSupport::formatDataStructure($mturk->request, 4) . "\n";
254             }
255 0 0         if ($mturk->response) {
256 0           $message .= "\nDump of response:\n" .
257             Net::Amazon::MechanicalTurk::BulkSupport::formatDataStructure($mturk->response->fullResult, 4) . "\n";
258             }
259 0           Carp::croak($message);
260             }
261            
262 0 0         if ($progress) {
263 0           $progress->(" Failed to update $failures HITs.");
264 0           $progress->(" Updated $hitsLoaded HITs.");
265 0           $progress->("--[Done Updating HITs] " . scalar localtime() . " ---");
266 0           $progress->(" Total update time: " . (time() - $start) . " seconds.");
267 0           $progress->(" You may see your HITs here: " . $mturk->getHITTypeURL($hitTypeId));
268             }
269            
270 0           return { updated => $hitsLoaded, failed => $failures, HITTypeId => $hitTypeId };
271             }
272              
273             return 1;