opentox-client 0.0.2pre → 1.0.0pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -1
- data/ChangeLog +2 -0
- data/README.markdown +16 -1
- data/Rakefile +0 -10
- data/VERSION +1 -0
- data/bin/opentox-client-install +46 -0
- data/lib/authorization.rb +9 -7
- data/lib/compound.rb +40 -20
- data/lib/dataset.rb +126 -16
- data/lib/error.rb +41 -83
- data/lib/model.rb +3 -2
- data/lib/opentox-client.rb +17 -12
- data/lib/opentox.rb +122 -96
- data/lib/overwrite.rb +20 -3
- data/lib/policy.rb +17 -2
- data/lib/rest-client-wrapper.rb +24 -5
- data/lib/task.rb +36 -18
- data/opentox-client.gemspec +2 -1
- metadata +60 -38
- data/test/authorization.rb +0 -107
- data/test/compound.rb +0 -52
- data/test/data/CPDBAS_v5c_1547_29Apr2008part.sdf +0 -13553
- data/test/data/EPAFHM.csv +0 -618
- data/test/data/EPAFHM.mini.csv +0 -21
- data/test/data/ISSCAN-multi.csv +0 -59
- data/test/data/cpdb_100.csv +0 -101
- data/test/data/hamster_carcinogenicity.csv +0 -86
- data/test/data/hamster_carcinogenicity.mini.csv +0 -11
- data/test/data/hamster_carcinogenicity.sdf +0 -2805
- data/test/data/hamster_carcinogenicity.xls +0 -0
- data/test/data/hamster_carcinogenicity.yaml +0 -352
- data/test/data/hamster_carcinogenicity_with_errors.csv +0 -88
- data/test/data/kazius.csv +0 -4069
- data/test/data/multi_cell_call.csv +0 -1067
- data/test/data/multicolumn.csv +0 -5
- data/test/dataset.rb +0 -99
- data/test/error.rb +0 -35
- data/test/feature.rb +0 -36
- data/test/policy.rb +0 -120
- data/test/task.rb +0 -85
data/lib/model.rb
CHANGED
@@ -6,8 +6,9 @@ module OpenTox
|
|
6
6
|
# @param [Hash] params Parameters for OpenTox model
|
7
7
|
# @param [optional,OpenTox::Task] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
|
8
8
|
# @return [text/uri-list] Task or resource URI
|
9
|
-
def run params=nil
|
10
|
-
post params, {:
|
9
|
+
def run params=nil, wait=true
|
10
|
+
uri = RestClientWrapper.post @uri, params, { :content_type => "text/uri-list", :subjectid => @subjectid}
|
11
|
+
wait_for_task uri if wait
|
11
12
|
end
|
12
13
|
|
13
14
|
end
|
data/lib/opentox-client.rb
CHANGED
@@ -2,34 +2,39 @@ require 'rubygems'
|
|
2
2
|
require "bundler/setup"
|
3
3
|
require 'rdf'
|
4
4
|
require 'rdf/raptor'
|
5
|
+
require 'rdf/n3'
|
5
6
|
require "rest-client"
|
6
7
|
require 'uri'
|
7
8
|
require 'yaml'
|
8
9
|
require 'json'
|
9
10
|
require 'logger'
|
11
|
+
require "securerandom"
|
10
12
|
|
11
13
|
# define constants and global variables
|
12
14
|
#TODO: switch services to 1.2
|
13
15
|
RDF::OT = RDF::Vocabulary.new 'http://www.opentox.org/api/1.2#'
|
14
16
|
RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
|
15
17
|
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
|
18
|
+
RDF::OLO = RDF::Vocabulary.new 'http://purl.org/ontology/olo/core#'
|
16
19
|
|
17
|
-
#CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "ErrorReport", "Investigation"]
|
18
20
|
CLASSES = ["Generic", "Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
|
19
21
|
RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
|
20
|
-
$default_rdf = "application/rdf+xml"
|
21
22
|
|
22
23
|
# Regular expressions for parsing classification data
|
23
24
|
TRUE_REGEXP = /^(true|active|1|1.0|tox|activating|carcinogen|mutagenic)$/i
|
24
25
|
FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-mutagenic)$/i
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
[
|
28
|
+
"overwrite.rb",
|
29
|
+
"rest-client-wrapper.rb",
|
30
|
+
"error.rb",
|
31
|
+
"authorization.rb",
|
32
|
+
"policy.rb",
|
33
|
+
"otlogger.rb",
|
34
|
+
"opentox.rb",
|
35
|
+
"task.rb",
|
36
|
+
"compound.rb",
|
37
|
+
"dataset.rb",
|
38
|
+
"model.rb",
|
39
|
+
].each{ |f| require File.join(File.dirname(__FILE__),f) }
|
40
|
+
|
data/lib/opentox.rb
CHANGED
@@ -4,7 +4,7 @@ $logger.level = Logger::DEBUG
|
|
4
4
|
|
5
5
|
module OpenTox
|
6
6
|
|
7
|
-
attr_accessor :uri, :subjectid, :rdf
|
7
|
+
attr_accessor :uri, :subjectid, :rdf
|
8
8
|
|
9
9
|
# Ruby interface
|
10
10
|
|
@@ -13,134 +13,156 @@ module OpenTox
|
|
13
13
|
# @param [optional,String] subjectid
|
14
14
|
# @return [OpenTox] OpenTox object
|
15
15
|
def initialize uri=nil, subjectid=nil
|
16
|
-
@uri = uri.to_s.chomp
|
17
|
-
@subjectid = subjectid
|
18
|
-
@reload = true
|
19
16
|
@rdf = RDF::Graph.new
|
17
|
+
if uri
|
18
|
+
@uri = uri.to_s.chomp
|
19
|
+
else
|
20
|
+
service = self.class.to_s.split('::').last.downcase
|
21
|
+
service_uri = eval("$#{service}[:uri]")
|
22
|
+
bad_request_error "$#{service}[:uri] variable not set. Please set $#{service}[:uri] or use an explicit uri as first constructor argument " unless service_uri
|
23
|
+
@uri = File.join service_uri, SecureRandom.uuid
|
24
|
+
end
|
25
|
+
append RDF.type, eval("RDF::OT."+self.class.to_s.split('::').last)
|
26
|
+
append RDF::DC.date, DateTime.now
|
27
|
+
@subjectid = subjectid
|
20
28
|
end
|
21
29
|
|
22
|
-
#
|
23
|
-
|
24
|
-
# TODO generic method for all formats
|
25
|
-
parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
|
26
|
-
end
|
27
|
-
|
28
|
-
# Get object metadata
|
29
|
-
# @return [Hash] Metadata
|
30
|
+
# Object metadata
|
31
|
+
# @return [Hash] Object metadata
|
30
32
|
def metadata
|
31
|
-
|
32
|
-
@rdf.to_hash[RDF::URI.new(@uri)]
|
33
|
+
# return plain strings instead of RDF objects
|
34
|
+
@rdf.to_hash[RDF::URI.new(@uri)].inject({}) { |h, (predicate, values)| h[predicate.to_s] = values.collect{|v| v.to_s}; h }
|
33
35
|
end
|
34
36
|
|
35
|
-
#
|
36
|
-
# @param [
|
37
|
-
# @return [Array]
|
38
|
-
def [](
|
39
|
-
|
40
|
-
|
41
|
-
# TODO: convert to OpenTox objects??
|
42
|
-
return nil if result and result.empty?
|
43
|
-
return result.first.to_s if result.size == 1
|
44
|
-
return result.collect{|r| r.to_s}
|
45
|
-
result
|
37
|
+
# Metadata values
|
38
|
+
# @param [String] Predicate URI
|
39
|
+
# @return [Array, String] Predicate value(s)
|
40
|
+
def [](predicate)
|
41
|
+
return nil if metadata[predicate.to_s].nil?
|
42
|
+
metadata[predicate.to_s].size == 1 ? metadata[predicate.to_s].first : metadata[predicate.to_s]
|
46
43
|
end
|
47
44
|
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
# Set object metadata
|
46
|
+
# @param [String] Predicate URI
|
47
|
+
# @param [Array, String] Predicate value(s)
|
48
|
+
def []=(predicate,values)
|
49
|
+
@rdf.delete [RDF::URI.new(@uri.to_s),RDF::URI.new(predicate.to_s),nil]
|
50
|
+
append predicate.to_s, values
|
52
51
|
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
53
|
+
def parameters
|
54
|
+
params = {}
|
55
|
+
query = RDF::Query.new({
|
56
|
+
:parameter => {
|
57
|
+
RDF.type => RDF::OT.Parameter,
|
58
|
+
:property => :value,
|
59
|
+
}
|
60
|
+
})
|
61
|
+
query.execute(@rdf).each do |solution|
|
62
|
+
params[solution.parameter] = {} unless params[solution.parameter]
|
63
|
+
params[solution.parameter][solution.property.to_s] = solution.value.to_s
|
62
64
|
end
|
65
|
+
params.values
|
66
|
+
end
|
63
67
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
rdf
|
68
|
+
def parameters=(parameters)
|
69
|
+
parameters.each do |param|
|
70
|
+
p_node = RDF::Node.new
|
71
|
+
@rdf << [RDF::URI.new(@uri), RDF::OT.parameters, p_node]
|
72
|
+
@rdf << [p_node, RDF.type, RDF::OT.Parameter]
|
73
|
+
param.each{ |p,o| @rdf << [p_node, p, o] }
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
73
|
-
|
74
|
-
|
77
|
+
# Append object metadata
|
78
|
+
# @param [String] Predicate URI
|
79
|
+
# @param [Array, String] Predicate value(s)
|
80
|
+
def append(predicate,values)
|
81
|
+
uri = RDF::URI.new @uri
|
82
|
+
predicate = RDF::URI.new predicate
|
83
|
+
[values].flatten.each { |value| @rdf << [uri, predicate, value] }
|
75
84
|
end
|
76
85
|
|
77
|
-
|
78
|
-
|
86
|
+
# Get object from webservice
|
87
|
+
def get mime_type="text/plain"
|
88
|
+
response = RestClientWrapper.get(@uri,{},{:accept => mime_type, :subjectid => @subjectid})
|
89
|
+
if URI.task?(response)
|
90
|
+
wait_for_task response
|
91
|
+
response = RestClientWrapper.get(t.resultURI,{},{:accept => mime_type, :subjectid => @subjectid})
|
92
|
+
end
|
93
|
+
parse_ntriples response if mime_type == "text/plain"
|
94
|
+
parse_rdfxml response if mime_type == "application/rdf+xml"
|
79
95
|
end
|
80
96
|
|
81
|
-
#
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
97
|
+
# Post object to webservice
|
98
|
+
def post service_uri, wait=true
|
99
|
+
# TODO: RDFXML
|
100
|
+
uri = RestClientWrapper.post service_uri, to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
|
101
|
+
wait_for_task uri if wait
|
86
102
|
end
|
87
103
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
104
|
+
# Save object at webservice
|
105
|
+
def put wait=true
|
106
|
+
# TODO: RDFXML
|
107
|
+
append RDF::DC.modified, DateTime.now
|
108
|
+
uri = RestClientWrapper.put @uri.to_s, self.to_ntriples, { :content_type => "text/plain", :subjectid => @subjectid}
|
109
|
+
wait_for_task uri if wait
|
92
110
|
end
|
93
111
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
@response = RestClientWrapper.put(@uri.to_s, payload, headers)
|
112
|
+
# Delete object at webservice
|
113
|
+
def delete
|
114
|
+
RestClientWrapper.delete(@uri.to_s,nil,{:subjectid => @subjectid})
|
98
115
|
end
|
99
116
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
117
|
+
def wait_for_task uri
|
118
|
+
if URI.task?(uri)
|
119
|
+
t = OpenTox::Task.new uri
|
120
|
+
t.wait
|
121
|
+
unless t.completed?
|
122
|
+
#TODO raise correct error
|
123
|
+
#internal_server_error "Task #{uri} failed with #{$!.inspect}"
|
124
|
+
end
|
125
|
+
uri = t.resultURI
|
126
|
+
end
|
127
|
+
uri
|
103
128
|
end
|
104
129
|
|
105
|
-
|
106
|
-
module ClassMethods
|
130
|
+
RDF_FORMATS.each do |format|
|
107
131
|
|
108
|
-
|
109
|
-
|
110
|
-
|
132
|
+
# rdf parse methods for all formats e.g. parse_rdfxml
|
133
|
+
send :define_method, "parse_#{format}".to_sym do |rdf|
|
134
|
+
@rdf = RDF::Graph.new
|
135
|
+
RDF::Reader.for(format).new(rdf) do |reader|
|
136
|
+
reader.each_statement{ |statement| @rdf << statement }
|
137
|
+
end
|
111
138
|
end
|
112
139
|
|
113
|
-
|
114
|
-
|
115
|
-
|
140
|
+
# rdf serialization methods for all formats e.g. to_rdfxml
|
141
|
+
send :define_method, "to_#{format}".to_sym do
|
142
|
+
RDF::Writer.for(format).buffer do |writer|
|
143
|
+
@rdf.each{|statement| writer << statement}
|
144
|
+
end
|
116
145
|
end
|
146
|
+
end
|
117
147
|
|
118
|
-
|
119
|
-
|
120
|
-
|
148
|
+
def to_turtle # redefine to use prefixes (not supported by RDF::Writer)
|
149
|
+
prefixes = {:rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#"}
|
150
|
+
['OT', 'DC', 'XSD', 'OLO'].each{|p| prefixes[p.downcase.to_sym] = eval("RDF::#{p}.to_s") }
|
151
|
+
RDF::N3::Writer.for(:turtle).buffer(:prefixes => prefixes) do |writer|
|
152
|
+
@rdf.each{|statement| writer << statement}
|
121
153
|
end
|
154
|
+
end
|
122
155
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
# guess class from uri, this is potentially unsafe, but polling metadata from large uri lists is way too slow (and not all service provide RDF.type in their metadata)
|
135
|
-
result = CLASSES.collect{|s| s if uri =~ /#{s.downcase}/}.compact
|
136
|
-
if result.size == 1
|
137
|
-
klass = result.first
|
138
|
-
else
|
139
|
-
klass = OpenTox::Generic.new(uri)[RDF.type]
|
140
|
-
internal_server_error "Cannot determine class from URI '#{uri} (Candidate classes are #{result.inspect}) or matadata." unless klass
|
141
|
-
end
|
142
|
-
# initialize with/without subjectid
|
143
|
-
subjectid ? eval("#{self}.new(\"#{uri}\", \"#{subjectid}\")") : eval("#{self}.new(\"#{uri}\")")
|
156
|
+
{
|
157
|
+
:title => RDF::DC.title,
|
158
|
+
:dexcription => RDF::DC.description,
|
159
|
+
:type => RDF.type
|
160
|
+
}.each do |method,predicate|
|
161
|
+
send :define_method, method do
|
162
|
+
self.[](predicate)
|
163
|
+
end
|
164
|
+
send :define_method, "#{method}=" do |value|
|
165
|
+
self.[]=(predicate,value)
|
144
166
|
end
|
145
167
|
end
|
146
168
|
|
@@ -148,7 +170,11 @@ module OpenTox
|
|
148
170
|
CLASSES.each do |klass|
|
149
171
|
c = Class.new do
|
150
172
|
include OpenTox
|
151
|
-
|
173
|
+
|
174
|
+
def self.all service_uri, subjectid=nil
|
175
|
+
uris = RestClientWrapper.get(service_uri, {}, :accept => 'text/uri-list').split("\n").compact
|
176
|
+
uris.collect{|uri| self.new(uri, subjectid)}
|
177
|
+
end
|
152
178
|
end
|
153
179
|
OpenTox.const_set klass,c
|
154
180
|
end
|
data/lib/overwrite.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
class Object
|
2
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
3
|
+
# For example, "", " ", +nil+, [], and {} are all blank.
|
4
|
+
def blank?
|
5
|
+
respond_to?(:empty?) ? empty? : !self
|
6
|
+
end
|
7
|
+
|
8
|
+
def numeric?
|
9
|
+
true if Float(self) rescue false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Enumerable
|
14
|
+
def duplicates
|
15
|
+
inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
1
19
|
class String
|
2
20
|
def underscore
|
3
21
|
self.gsub(/::/, '/').
|
@@ -68,11 +86,10 @@ module Kernel
|
|
68
86
|
stdout = stdout_stream.read
|
69
87
|
stderr = stderr_stream.read
|
70
88
|
end
|
71
|
-
internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr
|
89
|
+
internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr unless status.success?
|
72
90
|
return stdout
|
73
91
|
rescue
|
74
|
-
internal_server_error $!.message
|
92
|
+
internal_server_error $!.message
|
75
93
|
end
|
76
94
|
|
77
95
|
end
|
78
|
-
|
data/lib/policy.rb
CHANGED
@@ -58,7 +58,7 @@ module OpenTox
|
|
58
58
|
when "guest", "anonymous" then "default_guest_policy"
|
59
59
|
else "default_policy"
|
60
60
|
end
|
61
|
-
xml =
|
61
|
+
xml = get_xml_template(template)
|
62
62
|
self.load_xml(xml)
|
63
63
|
datestring = Time.now.strftime("%Y-%m-%d-%H-%M-%S-x") + rand(1000).to_s
|
64
64
|
|
@@ -78,6 +78,10 @@ module OpenTox
|
|
78
78
|
return true
|
79
79
|
end
|
80
80
|
|
81
|
+
def get_xml_template(template)
|
82
|
+
File.read(File.join(File.dirname(__FILE__), "templates/#{template}.xml"))
|
83
|
+
end
|
84
|
+
|
81
85
|
#loads a xml template
|
82
86
|
def load_xml(xml)
|
83
87
|
rexml = REXML::Document.new(xml)
|
@@ -247,19 +251,22 @@ module OpenTox
|
|
247
251
|
end
|
248
252
|
|
249
253
|
# helper method sets value and type to opentox LDAP Distinguished Name (DN) of a user
|
254
|
+
# @param [String]Username set a username into LDAP DN
|
250
255
|
def set_ot_user(username)
|
251
256
|
self.value = "uid=#{username},ou=people,dc=opentox,dc=org"
|
252
257
|
self.type = "LDAPUsers"
|
253
258
|
true
|
254
259
|
end
|
255
260
|
|
261
|
+
# @param [String]Username set a groupname into LDAP DN
|
256
262
|
def set_ot_group(groupname)
|
257
263
|
self.value = "cn=#{groupname},ou=groups,dc=opentox,dc=org"
|
258
264
|
self.type = "LDAPGroups"
|
259
265
|
true
|
260
266
|
end
|
261
267
|
|
262
|
-
#
|
268
|
+
# policyrule
|
269
|
+
# sets the permission for REST actions (GET, POST, PUT, DELETE) of a specific URI to allow/deny/nil
|
263
270
|
class Rule
|
264
271
|
|
265
272
|
attr_accessor :name, :uri, :get, :post, :put, :delete, :read, :readwrite
|
@@ -293,14 +300,18 @@ module OpenTox
|
|
293
300
|
@put = check_value(value, @put)
|
294
301
|
end
|
295
302
|
|
303
|
+
# read getter method
|
296
304
|
def read
|
297
305
|
return true if @get == "allow" && (@put == "deny" || !@put) && (@post == "deny" || !@post)
|
298
306
|
end
|
299
307
|
|
308
|
+
# readwrite getter method
|
300
309
|
def readwrite
|
301
310
|
return true if @get == "allow" && @put == "allow" && @post == "allow"
|
302
311
|
end
|
303
312
|
|
313
|
+
# Set(true case) or remove read(GET=allow) permissions.
|
314
|
+
# @param [Boolean]value (true,false)
|
304
315
|
def read=(value)
|
305
316
|
if value
|
306
317
|
@get = "allow"; @put = nil; @post = nil
|
@@ -309,6 +320,8 @@ module OpenTox
|
|
309
320
|
end
|
310
321
|
end
|
311
322
|
|
323
|
+
# Set(true case) or remove readwrite(GET=allow,POST=allow,PUT=allow) permissions.
|
324
|
+
# @param [Boolean]value (true,false)
|
312
325
|
def readwrite=(value)
|
313
326
|
if value
|
314
327
|
@get = "allow"; @put = "allow"; @post = "allow"
|
@@ -324,6 +337,8 @@ module OpenTox
|
|
324
337
|
end
|
325
338
|
end
|
326
339
|
|
340
|
+
# Subject of a policy
|
341
|
+
# name(subjectname), type('LDAPUsers' or 'LDAPGroups'), value(LDAP DN e.G.:'uid=guest,ou=people,dc=opentox,dc=org')
|
327
342
|
class Subject
|
328
343
|
|
329
344
|
attr_accessor :name, :type, :value
|