opentox-client 0.0.1pre → 0.0.2pre
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/README.markdown +5 -0
- data/lib/authorization.rb +55 -79
- data/lib/dataset.rb +17 -306
- data/lib/error.rb +23 -12
- data/lib/opentox-client.rb +5 -2
- data/lib/opentox.rb +27 -15
- data/lib/overwrite.rb +10 -22
- data/lib/policy.rb +204 -127
- data/lib/rest-client-wrapper.rb +14 -7
- data/lib/task.rb +22 -31
- data/opentox-client.gemspec +5 -1
- data/test/authorization.rb +107 -0
- data/test/dataset.rb +60 -14
- data/test/feature.rb +2 -2
- data/test/policy.rb +120 -0
- data/test/task.rb +5 -5
- metadata +19 -15
data/lib/error.rb
CHANGED
@@ -45,20 +45,19 @@ module OpenTox
|
|
45
45
|
OpenTox.const_set klass,c
|
46
46
|
|
47
47
|
# define global methods for raising errors, eg. bad_request_error
|
48
|
-
Object.send(:define_method, klass.underscore.to_sym) do |message|
|
49
|
-
defined?(@uri) ? uri = @uri : uri=nil
|
50
|
-
# TODO: insert uri from sinatra
|
48
|
+
Object.send(:define_method, klass.underscore.to_sym) do |message,uri=nil|
|
51
49
|
raise c, message, uri
|
52
50
|
end
|
53
51
|
end
|
54
52
|
|
55
53
|
# Errors received from RestClientWrapper calls
|
56
54
|
class RestCallError < Error
|
57
|
-
attr_accessor :request
|
58
|
-
def initialize
|
55
|
+
attr_accessor :request#, :response
|
56
|
+
def initialize message, request, uri
|
57
|
+
#def initialize request, response, message
|
59
58
|
@request = request
|
60
|
-
|
61
|
-
super 502, message,
|
59
|
+
#@response = response
|
60
|
+
super 502, message, uri
|
62
61
|
end
|
63
62
|
end
|
64
63
|
|
@@ -66,16 +65,24 @@ module OpenTox
|
|
66
65
|
class ErrorReport
|
67
66
|
def initialize http_code, error
|
68
67
|
@http_code = http_code
|
69
|
-
#@report = report#.to_yaml
|
70
68
|
@report = {}
|
71
|
-
@report[RDF::OT.actor] = error.uri
|
72
|
-
@report[RDF::OT.message] = error.message
|
69
|
+
@report[RDF::OT.actor] = error.uri.to_s
|
70
|
+
@report[RDF::OT.message] = error.message.to_s
|
73
71
|
@report[RDF::OT.statusCode] = @http_code
|
74
72
|
@report[RDF::OT.errorCode] = error.class.to_s
|
75
|
-
|
73
|
+
|
74
|
+
# cut backtrace
|
75
|
+
backtrace = caller.collect{|line| line unless line =~ /#{File.dirname(__FILE__)}/}.compact
|
76
|
+
cut_index = backtrace.find_index{|line| line.match /sinatra|minitest/}
|
77
|
+
cut_index ||= backtrace.size
|
78
|
+
cut_index -= 1
|
79
|
+
cut_index = backtrace.size-1 if cut_index < 0
|
80
|
+
@report[RDF::OT.errorDetails] = backtrace[0..cut_index].join("\n")
|
76
81
|
@report[RDF::OT.errorDetails] += "REST paramenters:\n#{error.request.args.inspect}" if defined? error.request
|
77
|
-
|
82
|
+
#@report[RDF::OT.message] += "\n" + error.response.body.to_s if defined? error.response
|
78
83
|
# TODO fix Error cause
|
84
|
+
# should point to another errorReport, but errorReports do not have URIs
|
85
|
+
# create a separate service?
|
79
86
|
#report[RDF::OT.errorCause] = @report if defined?(@report)
|
80
87
|
end
|
81
88
|
|
@@ -84,6 +91,10 @@ module OpenTox
|
|
84
91
|
|
85
92
|
send :define_method, "to_#{format}".to_sym do
|
86
93
|
rdf = RDF::Writer.for(format).buffer do |writer|
|
94
|
+
# TODO: not used for turtle
|
95
|
+
# http://rdf.rubyforge.org/RDF/Writer.html#
|
96
|
+
writer.prefix :ot, RDF::URI('http://www.opentox.org/api/1.2#')
|
97
|
+
writer.prefix :ot1_1, RDF::URI('http://www.opentox.org/api/1.1#')
|
87
98
|
subject = RDF::Node.new
|
88
99
|
@report.each do |predicate,object|
|
89
100
|
writer << [subject, predicate, object] if object
|
data/lib/opentox-client.rb
CHANGED
@@ -5,6 +5,7 @@ require 'rdf/raptor'
|
|
5
5
|
require "rest-client"
|
6
6
|
require 'uri'
|
7
7
|
require 'yaml'
|
8
|
+
require 'json'
|
8
9
|
require 'logger'
|
9
10
|
|
10
11
|
# define constants and global variables
|
@@ -14,7 +15,7 @@ RDF::OT1 = RDF::Vocabulary.new 'http://www.opentox.org/api/1.1#'
|
|
14
15
|
RDF::OTA = RDF::Vocabulary.new 'http://www.opentox.org/algorithmTypes.owl#'
|
15
16
|
|
16
17
|
#CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "ErrorReport", "Investigation"]
|
17
|
-
CLASSES = ["Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
|
18
|
+
CLASSES = ["Generic", "Compound", "Feature", "Dataset", "Algorithm", "Model", "Validation", "Task", "Investigation"]
|
18
19
|
RDF_FORMATS = [:rdfxml,:ntriples,:turtle]
|
19
20
|
$default_rdf = "application/rdf+xml"
|
20
21
|
|
@@ -25,8 +26,10 @@ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox|deactivating|non-carcinogen|non-m
|
|
25
26
|
require File.join(File.dirname(__FILE__),"overwrite.rb")
|
26
27
|
require File.join(File.dirname(__FILE__),"error.rb")
|
27
28
|
require File.join(File.dirname(__FILE__),"rest-client-wrapper.rb")
|
29
|
+
require File.join(File.dirname(__FILE__),"authorization.rb")
|
30
|
+
require File.join(File.dirname(__FILE__),"policy.rb")
|
28
31
|
require File.join(File.dirname(__FILE__),"otlogger.rb") # avoid require conflicts with logger
|
29
32
|
require File.join(File.dirname(__FILE__),"opentox.rb")
|
30
33
|
require File.join(File.dirname(__FILE__),"task.rb")
|
31
34
|
require File.join(File.dirname(__FILE__),"compound.rb")
|
32
|
-
|
35
|
+
require File.join(File.dirname(__FILE__),"dataset.rb")
|
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, :response
|
7
|
+
attr_accessor :uri, :subjectid, :rdf, :response, :reload
|
8
8
|
|
9
9
|
# Ruby interface
|
10
10
|
|
@@ -15,34 +15,34 @@ module OpenTox
|
|
15
15
|
def initialize uri=nil, subjectid=nil
|
16
16
|
@uri = uri.to_s.chomp
|
17
17
|
@subjectid = subjectid
|
18
|
+
@reload = true
|
18
19
|
@rdf = RDF::Graph.new
|
19
20
|
end
|
20
21
|
|
21
22
|
# Load metadata from service
|
22
23
|
def pull
|
23
|
-
kind_of?(OpenTox::Dataset) ? uri = File.join(@uri,"metadata") : uri = @uri
|
24
24
|
# TODO generic method for all formats
|
25
|
-
parse_rdfxml RestClientWrapper.get(uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
|
25
|
+
parse_rdfxml RestClientWrapper.get(@uri,{},{:accept => $default_rdf, :subjectid => @subjectid})
|
26
26
|
end
|
27
27
|
|
28
28
|
# Get object metadata
|
29
29
|
# @return [Hash] Metadata
|
30
30
|
def metadata
|
31
|
-
pull if @
|
32
|
-
|
33
|
-
@rdf.query([RDF::URI.new(@uri),nil,nil]).collect do |statement|
|
34
|
-
metadata[statement.predicate] ||= []
|
35
|
-
metadata[statement.predicate] << statement.object
|
36
|
-
end
|
37
|
-
metadata
|
31
|
+
pull if @reload # force update
|
32
|
+
@rdf.to_hash[RDF::URI.new(@uri)]
|
38
33
|
end
|
39
34
|
|
40
35
|
# Get metadata values
|
41
36
|
# @param [RDF] Key from RDF Vocabularies
|
42
37
|
# @return [Array] Values for supplied key
|
43
38
|
def [](key)
|
44
|
-
pull if @
|
45
|
-
@rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
|
39
|
+
pull if @reload # force update
|
40
|
+
result = @rdf.query([RDF::URI.new(@uri),key,nil]).collect{|statement| statement.object}
|
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
|
46
46
|
end
|
47
47
|
|
48
48
|
# Save object at service
|
@@ -70,6 +70,14 @@ module OpenTox
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
+
def to_yaml
|
74
|
+
@rdf.to_hash.to_yaml
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_json
|
78
|
+
to_hash.to_json
|
79
|
+
end
|
80
|
+
|
73
81
|
# REST API
|
74
82
|
def get headers={}
|
75
83
|
headers[:subjectid] ||= @subjectid
|
@@ -125,10 +133,14 @@ module OpenTox
|
|
125
133
|
|
126
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)
|
127
135
|
result = CLASSES.collect{|s| s if uri =~ /#{s.downcase}/}.compact
|
128
|
-
|
129
|
-
|
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
|
130
142
|
# initialize with/without subjectid
|
131
|
-
subjectid ? eval("#{self}.new(\"#{uri}\", #{subjectid})") : eval("#{self}.new(\"#{uri}\")")
|
143
|
+
subjectid ? eval("#{self}.new(\"#{uri}\", \"#{subjectid}\")") : eval("#{self}.new(\"#{uri}\")")
|
132
144
|
end
|
133
145
|
end
|
134
146
|
|
data/lib/overwrite.rb
CHANGED
@@ -21,18 +21,22 @@ module URI
|
|
21
21
|
def self.dataset? uri, subjectid=nil
|
22
22
|
uri =~ /dataset/ and URI.accessible? uri, subjectid=nil
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def self.model? uri, subjectid=nil
|
26
26
|
uri =~ /model/ and URI.accessible? uri, subjectid=nil
|
27
27
|
end
|
28
28
|
|
29
|
-
def self.
|
29
|
+
def self.ssl? uri, subjectid=nil
|
30
|
+
URI.parse(uri).instance_of? URI::HTTPS
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.accessible?(uri, subjectid=nil)
|
30
34
|
if URI.task? uri or URI.compound? uri
|
31
35
|
# just try to get a response, valid tasks may return codes > 400
|
32
36
|
Net::HTTP.get_response(URI.parse(uri))
|
33
37
|
true
|
34
38
|
else
|
35
|
-
Net::HTTP.get_response(URI.parse(uri)).code.to_i < 400
|
39
|
+
Net::HTTP.get_response(URI.parse(uri + (subjectid ? "?subjectid=#{CGI.escape subjectid}" : ""))).code.to_i < 400
|
36
40
|
end
|
37
41
|
rescue
|
38
42
|
false
|
@@ -64,27 +68,11 @@ module Kernel
|
|
64
68
|
stdout = stdout_stream.read
|
65
69
|
stderr = stderr_stream.read
|
66
70
|
end
|
67
|
-
|
71
|
+
internal_server_error "`" + cmd + "` failed.\n" + stdout + stderr if !status.success?
|
68
72
|
return stdout
|
69
|
-
rescue
|
70
|
-
internal_server_error
|
73
|
+
rescue
|
74
|
+
internal_server_error $!.message
|
71
75
|
end
|
72
76
|
|
73
|
-
alias_method :system!, :system
|
74
|
-
|
75
|
-
def system cmd
|
76
|
-
`#{cmd}`
|
77
|
-
return true
|
78
|
-
end
|
79
77
|
end
|
80
78
|
|
81
|
-
class Array
|
82
|
-
def short_backtrace
|
83
|
-
short = []
|
84
|
-
each do |c|
|
85
|
-
break if c =~ /sinatra\/base/
|
86
|
-
short << c
|
87
|
-
end
|
88
|
-
short.join("\n")
|
89
|
-
end
|
90
|
-
end
|