opentox-ruby 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/compound.rb CHANGED
@@ -68,6 +68,12 @@ module OpenTox
68
68
  c
69
69
  end
70
70
 
71
+ # Get InChI
72
+ # @return [String] InChI string
73
+ def to_inchi
74
+ @inchi
75
+ end
76
+
71
77
  # Get (canonical) smiles
72
78
  # @return [String] Smiles string
73
79
  def to_smiles
@@ -12,6 +12,7 @@ $stdout.sync = true
12
12
  $stderr.sync = true
13
13
  set :logging, false
14
14
  set :raise_errors, true
15
+ set :lock, true
15
16
 
16
17
  ['public','tmp'].each do |dir|
17
18
  FileUtils.mkdir_p dir unless File.exists?(dir)
data/lib/dataset.rb CHANGED
@@ -14,7 +14,7 @@ module OpenTox
14
14
  # dataset = OpenTox::Dataset.new("http:://webservices.in-silico/ch/dataset/1")
15
15
  # @param [optional, String] uri Dataset URI
16
16
  # @return [OpenTox::Dataset] Dataset object
17
- def initialize(uri=nil)
17
+ def initialize(uri=nil,subjectid=nil)
18
18
  super uri
19
19
  @features = {}
20
20
  @compounds = []
@@ -26,9 +26,9 @@ module OpenTox
26
26
  # dataset = OpenTox::Dataset.create
27
27
  # @param [optional, String] uri Dataset URI
28
28
  # @return [OpenTox::Dataset] Dataset object
29
- def self.create(uri=CONFIG[:services]["opentox-dataset"])
30
- dataset = Dataset.new
31
- dataset.save
29
+ def self.create(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
30
+ dataset = Dataset.new(nil,subjectid)
31
+ dataset.save(subjectid)
32
32
  dataset
33
33
  end
34
34
 
@@ -38,29 +38,43 @@ module OpenTox
38
38
  # - you will have to set remaining metadata manually
39
39
  # @param [String] file CSV file path
40
40
  # @return [OpenTox::Dataset] Dataset object with CSV data
41
- def self.create_from_csv_file(file)
42
- dataset = Dataset.create
41
+ def self.create_from_csv_file(file, subjectid=nil)
42
+ dataset = Dataset.create(CONFIG[:services]["opentox-dataset"], subjectid)
43
43
  parser = Parser::Spreadsheets.new
44
44
  parser.dataset = dataset
45
45
  parser.load_csv(File.open(file).read)
46
- dataset.save
46
+ dataset.save(subjectid)
47
47
  dataset
48
48
  end
49
-
49
+
50
50
  # Find a dataset and load all data. This can be time consuming, use Dataset.new together with one of the load_* methods for a fine grained control over data loading.
51
51
  # @param [String] uri Dataset URI
52
52
  # @return [OpenTox::Dataset] Dataset object with all data
53
- def self.find(uri)
54
- dataset = Dataset.new(uri)
55
- dataset.load_all
53
+ def self.find(uri, subjectid=nil)
54
+ return nil unless uri
55
+ dataset = Dataset.new(uri, subjectid)
56
+ dataset.load_all(subjectid)
56
57
  dataset
57
58
  end
59
+
60
+ # replaces find as exist check, takes not as long, does NOT raise an un-authorized exception
61
+ # @param [String] uri Dataset URI
62
+ # @return [Boolean] true if dataset exists and user has get rights, false else
63
+ def self.exist?(uri, subjectid=nil)
64
+ return false unless uri
65
+ dataset = Dataset.new(uri, subjectid)
66
+ begin
67
+ dataset.load_metadata( subjectid ).size > 0
68
+ rescue
69
+ false
70
+ end
71
+ end
58
72
 
59
73
  # Get all datasets from a service
60
74
  # @param [optional,String] uri URI of the dataset service, defaults to service specified in configuration
61
75
  # @return [Array] Array of dataset object without data (use one of the load_* methods to pull data from the server)
62
- def self.all(uri=CONFIG[:services]["opentox-dataset"])
63
- RestClientWrapper.get(uri,:accept => "text/uri-list").to_s.each_line.collect{|u| Dataset.new(u)}
76
+ def self.all(uri=CONFIG[:services]["opentox-dataset"], subjectid=nil)
77
+ RestClientWrapper.get(uri,{:accept => "text/uri-list",:subjectid => subjectid}).to_s.each_line.collect{|u| Dataset.new(u, subjectid)}
64
78
  end
65
79
 
66
80
  # Load YAML representation into the dataset
@@ -71,16 +85,21 @@ module OpenTox
71
85
  end
72
86
 
73
87
  def load_rdfxml(rdfxml)
74
- load_rdfxml_file Tempfile.open("ot-rdfxml"){|f| f.write(rdfxml)}.path
88
+ raise "rdfxml data is empty" if rdfxml.to_s.size==0
89
+ file = Tempfile.new("ot-rdfxml")
90
+ file.puts rdfxml
91
+ file.close
92
+ load_rdfxml_file file
93
+ file.delete
75
94
  end
76
95
 
77
96
  # Load RDF/XML representation from a file
78
97
  # @param [String] file File with RDF/XML representation of the dataset
79
98
  # @return [OpenTox::Dataset] Dataset object with RDF/XML data
80
- def load_rdfxml_file(file)
81
- parser = Parser::Owl::Dataset.new @uri
99
+ def load_rdfxml_file(file, subjectid=nil)
100
+ parser = Parser::Owl::Dataset.new @uri, subjectid
82
101
  parser.uri = file.path
83
- copy parser.load_uri
102
+ copy parser.load_uri(subjectid)
84
103
  end
85
104
 
86
105
  # Load CSV string (format specification: http://toxcreate.org/help)
@@ -89,8 +108,8 @@ module OpenTox
89
108
  # - you will have to set remaining metadata manually
90
109
  # @param [String] csv CSV representation of the dataset
91
110
  # @return [OpenTox::Dataset] Dataset object with CSV data
92
- def load_csv(csv)
93
- save unless @uri # get a uri for creating features
111
+ def load_csv(csv, subjectid=nil)
112
+ save(subjectid) unless @uri # get a uri for creating features
94
113
  parser = Parser::Spreadsheets.new
95
114
  parser.dataset = self
96
115
  parser.load_csv(csv)
@@ -102,8 +121,8 @@ module OpenTox
102
121
  # - you will have to set remaining metadata manually
103
122
  # @param [Excel] book Excel workbook object (created with roo gem)
104
123
  # @return [OpenTox::Dataset] Dataset object with Excel data
105
- def load_spreadsheet(book)
106
- save unless @uri # get a uri for creating features
124
+ def load_spreadsheet(book, subjectid=nil)
125
+ save(subjectid) unless @uri # get a uri for creating features
107
126
  parser = Parser::Spreadsheets.new
108
127
  parser.dataset = self
109
128
  parser.load_spreadsheet(book)
@@ -111,26 +130,26 @@ module OpenTox
111
130
 
112
131
  # Load and return only metadata of a Dataset object
113
132
  # @return [Hash] Metadata of the dataset
114
- def load_metadata
115
- add_metadata Parser::Owl::Dataset.new(@uri).load_metadata
133
+ def load_metadata(subjectid=nil)
134
+ add_metadata Parser::Owl::Dataset.new(@uri, subjectid).load_metadata(subjectid)
116
135
  self.uri = @uri if @uri # keep uri
117
136
  @metadata
118
137
  end
119
138
 
120
139
  # Load all data (metadata, data_entries, compounds and features) from URI
121
- def load_all
140
+ def load_all(subjectid=nil)
122
141
  if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
123
- copy YAML.load(RestClientWrapper.get(@uri, :accept => "application/x-yaml"))
142
+ copy YAML.load(RestClientWrapper.get(@uri, {:accept => "application/x-yaml", :subjectid => subjectid}))
124
143
  else
125
- parser = Parser::Owl::Dataset.new(@uri)
126
- copy parser.load_uri
144
+ parser = Parser::Owl::Dataset.new(@uri, subjectid)
145
+ copy parser.load_uri(subjectid)
127
146
  end
128
147
  end
129
148
 
130
149
  # Load and return only compound URIs from the dataset service
131
150
  # @return [Array] Compound URIs in the dataset
132
- def load_compounds
133
- RestClientWrapper.get(File.join(uri,"compounds"),:accept=> "text/uri-list").to_s.each_line do |compound_uri|
151
+ def load_compounds(subjectid=nil)
152
+ RestClientWrapper.get(File.join(uri,"compounds"),{:accept=> "text/uri-list", :subjectid => subjectid}).to_s.each_line do |compound_uri|
134
153
  @compounds << compound_uri.chomp
135
154
  end
136
155
  @compounds.uniq!
@@ -138,9 +157,9 @@ module OpenTox
138
157
 
139
158
  # Load and return only features from the dataset service
140
159
  # @return [Hash] Features of the dataset
141
- def load_features
142
- parser = Parser::Owl::Dataset.new(@uri)
143
- @features = parser.load_features
160
+ def load_features(subjectid=nil)
161
+ parser = Parser::Owl::Dataset.new(@uri, subjectid)
162
+ @features = parser.load_features(subjectid)
144
163
  @features
145
164
  end
146
165
 
@@ -218,7 +237,7 @@ module OpenTox
218
237
  @features[feature] = {} unless @features[feature]
219
238
  @data_entries[compound] = {} unless @data_entries[compound]
220
239
  @data_entries[compound][feature] = [] unless @data_entries[compound][feature]
221
- @data_entries[compound][feature] << value
240
+ @data_entries[compound][feature] << value if value!=nil
222
241
  end
223
242
 
224
243
  # Add/modify metadata, existing entries will be overwritten
@@ -242,34 +261,70 @@ module OpenTox
242
261
  def add_feature_metadata(feature,metadata)
243
262
  metadata.each { |k,v| @features[feature][k] = v }
244
263
  end
264
+
265
+ # Add a new compound
266
+ # @param [String] compound Compound URI
267
+ def add_compound (compound)
268
+ @compounds << compound unless @compounds.include? compound
269
+ end
270
+
271
+ # Creates a new dataset, by splitting the current dataset, i.e. using only a subset of compounds and features
272
+ # @param [Array] compounds List of compound URIs
273
+ # @param [Array] features List of feature URIs
274
+ # @param [Hash] metadata Hash containing the metadata for the new dataset
275
+ # @param [String] subjectid
276
+ # @return [OpenTox::Dataset] newly created dataset, already saved
277
+ def split( compounds, features, metadata, subjectid=nil)
278
+ LOGGER.debug "split dataset using "+compounds.size.to_s+"/"+@compounds.size.to_s+" compounds"
279
+ raise "no new compounds selected" unless compounds and compounds.size>0
280
+ dataset = OpenTox::Dataset.create(CONFIG[:services]["opentox-dataset"],subjectid)
281
+ if features.size==0
282
+ compounds.each{ |c| dataset.add_compound(c) }
283
+ else
284
+ compounds.each do |c|
285
+ features.each do |f|
286
+ unless @data_entries[c][f]
287
+ dataset.add(c,f,nil)
288
+ else
289
+ @data_entries[c][f].each do |v|
290
+ dataset.add(c,f,v)
291
+ end
292
+ end
293
+ end
294
+ end
295
+ end
296
+ dataset.add_metadata(metadata)
297
+ dataset.save(subjectid)
298
+ dataset
299
+ end
245
300
 
246
301
  # Save dataset at the dataset service
247
302
  # - creates a new dataset if uri is not set
248
303
  # - overwrites dataset if uri exists
249
304
  # @return [String] Dataset URI
250
- def save
305
+ def save(subjectid=nil)
251
306
  # TODO: rewrite feature URI's ??
252
307
  @compounds.uniq!
253
308
  if @uri
254
309
  if (CONFIG[:yaml_hosts].include?(URI.parse(@uri).host))
255
- RestClientWrapper.post(@uri,{:content_type => "application/x-yaml"},self.to_yaml)
310
+ RestClientWrapper.post(@uri,self.to_yaml,{:content_type => "application/x-yaml", :subjectid => subjectid})
256
311
  else
257
312
  File.open("ot-post-file.rdf","w+") { |f| f.write(self.to_rdfxml); @path = f.path }
258
- task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list"}).to_s.chomp
313
+ task_uri = RestClient.post(@uri, {:file => File.new(@path)},{:accept => "text/uri-list" , :subjectid => subjectid}).to_s.chomp
259
314
  #task_uri = `curl -X POST -H "Accept:text/uri-list" -F "file=@#{@path};type=application/rdf+xml" http://apps.ideaconsult.net:8080/ambit2/dataset`
260
315
  Task.find(task_uri).wait_for_completion
261
- self.uri = RestClientWrapper.get(task_uri,:accept => 'text/uri-list')
316
+ self.uri = RestClientWrapper.get(task_uri,{:accept => 'text/uri-list', :subjectid => subjectid})
262
317
  end
263
318
  else
264
319
  # create dataset if uri is empty
265
- self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{}).to_s.chomp
320
+ self.uri = RestClientWrapper.post(CONFIG[:services]["opentox-dataset"],{:subjectid => subjectid}).to_s.chomp
266
321
  end
267
322
  @uri
268
323
  end
269
324
 
270
325
  # Delete dataset at the dataset service
271
- def delete
272
- RestClientWrapper.delete @uri
326
+ def delete(subjectid=nil)
327
+ RestClientWrapper.delete(@uri, :subjectid => subjectid)
273
328
  end
274
329
 
275
330
  private
@@ -293,9 +348,9 @@ module OpenTox
293
348
  # Find a prediction dataset and load all data.
294
349
  # @param [String] uri Prediction dataset URI
295
350
  # @return [OpenTox::Dataset] Prediction dataset object with all data
296
- def self.find(uri)
297
- prediction = LazarPrediction.new(uri)
298
- prediction.load_all
351
+ def self.find(uri, subjectid=nil)
352
+ prediction = LazarPrediction.new(uri, subjectid)
353
+ prediction.load_all(subjectid)
299
354
  prediction
300
355
  end
301
356
 
data/lib/environment.rb CHANGED
@@ -23,22 +23,8 @@ else
23
23
  end
24
24
 
25
25
  # database
26
- if CONFIG[:database]
27
- ['dm-core', 'dm-serializer', 'dm-timestamps', 'dm-types', 'dm-migrations', 'dm-validations' ].each{|lib| require lib }
28
- case CONFIG[:database][:adapter]
29
- when /sqlite/i
30
- db_dir = File.join(basedir, "db")
31
- FileUtils.mkdir_p db_dir
32
- DataMapper::setup(:default, "sqlite3://#{db_dir}/opentox.sqlite3")
33
- else
34
- DataMapper.setup(:default, {
35
- :adapter => CONFIG[:database][:adapter],
36
- :database => CONFIG[:database][:database],
37
- :username => CONFIG[:database][:username],
38
- :password => CONFIG[:database][:password],
39
- :host => CONFIG[:database][:host]})
40
- end
41
- end
26
+ `redis-server /opt/redis/redis.conf` unless File.exists? "/var/run/redis.pid"
27
+ Ohm.connect :thread_safe => true
42
28
 
43
29
  # load mail settings for error messages
44
30
  load File.join config_dir,"mail.rb" if File.exists?(File.join config_dir,"mail.rb")
@@ -54,8 +40,8 @@ else
54
40
  end
55
41
 
56
42
  # Regular expressions for parsing classification data
57
- TRUE_REGEXP = /^(true|active|1|1.0)$/i
58
- FALSE_REGEXP = /^(false|inactive|0|0.0)$/i
43
+ TRUE_REGEXP = /^(true|active|1|1.0|tox)$/i
44
+ FALSE_REGEXP = /^(false|inactive|0|0.0|low tox)$/i
59
45
 
60
46
  # Task durations
61
47
  DEFAULT_TASK_MAX_DURATION = 36000
@@ -83,6 +69,11 @@ class OwlNamespace
83
69
 
84
70
  end
85
71
 
72
+ AA_SERVER = CONFIG[:authorization] ? (CONFIG[:authorization][:server] ? CONFIG[:authorization][:server] : nil) : nil
73
+ CONFIG[:authorization][:authenticate_request] = [""] unless CONFIG[:authorization][:authenticate_request]
74
+ CONFIG[:authorization][:authorize_request] = [""] unless CONFIG[:authorization][:authorize_request]
75
+ CONFIG[:authorization][:free_request] = [""] unless CONFIG[:authorization][:free_request]
76
+
86
77
  RDF = OwlNamespace.new 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
87
78
  OWL = OwlNamespace.new 'http://www.w3.org/2002/07/owl#'
88
79
  DC = OwlNamespace.new 'http://purl.org/dc/elements/1.1/'
data/lib/error.rb ADDED
@@ -0,0 +1,99 @@
1
+
2
+ # adding additional fields to Exception class to format errors according to OT-API
3
+ class Exception
4
+ attr_accessor :errorCause
5
+ def http_code; 500; end
6
+ end
7
+
8
+ module OpenTox
9
+
10
+ class BadRequestError < RuntimeError
11
+ def http_code; 400; end
12
+ end
13
+
14
+ class NotAuthorizedError < RuntimeError
15
+ def http_code; 401; end
16
+ end
17
+
18
+ class NotFoundError < RuntimeError
19
+ def http_code; 404; end
20
+ end
21
+
22
+ class ServiceUnavailableError < RuntimeError
23
+ def http_code; 503; end
24
+ end
25
+
26
+ class RestCallError < RuntimeError
27
+ attr_accessor :rest_params
28
+ def http_code; 502; end
29
+ end
30
+
31
+ class ErrorReport
32
+
33
+ # TODO replace params with URIs (errorCause -> OT.errorCause)
34
+ attr_reader :message, :actor, :errorCause, :http_code, :errorDetails, :errorType
35
+
36
+ private
37
+ def initialize( http_code, erroType, message, actor, errorCause, rest_params=nil, backtrace=nil )
38
+ @http_code = http_code
39
+ @errorType = erroType
40
+ @message = message
41
+ @actor = actor
42
+ @errorCause = errorCause
43
+ @rest_params = rest_params
44
+ @backtrace = backtrace
45
+ end
46
+
47
+ public
48
+ # creates a error report object, from an ruby-exception object
49
+ # @param [Exception] error
50
+ # @param [String] actor, URI of the call that cause the error
51
+ def self.create( error, actor )
52
+ rest_params = error.rest_params if error.is_a?(OpenTox::RestCallError) and error.rest_params
53
+ backtrace = error.backtrace.short_backtrace if CONFIG[:backtrace]
54
+ ErrorReport.new( error.http_code, error.class.to_s, error.message, actor, error.errorCause, rest_params, backtrace )
55
+ end
56
+
57
+ def self.from_rdf(rdf)
58
+ metadata = OpenTox::Parser::Owl.from_rdf( rdf, OT.ErrorReport ).metadata
59
+ ErrorReport.new(metadata[OT.statusCode], metadata[OT.errorCode], metadata[OT.message], metadata[OT.actor], metadata[OT.errorCause])
60
+ end
61
+
62
+ # overwrite sorting to make easier readable
63
+ def to_yaml_properties
64
+ p = super
65
+ p = ( p - ["@backtrace"]) + ["@backtrace"] if @backtrace
66
+ p = ( p - ["@errorCause"]) + ["@errorCause"] if @errorCause
67
+ p
68
+ end
69
+
70
+ def rdf_content()
71
+ c = {
72
+ RDF.type => OT.ErrorReport,
73
+ OT.statusCode => @http_code,
74
+ OT.message => @message,
75
+ OT.actor => @actor,
76
+ OT.errorCode => @errorType,
77
+ }
78
+ c[OT.errorCause] = @errorCause.rdf_content if @errorCause
79
+ c
80
+ end
81
+
82
+ def to_rdfxml
83
+ s = Serializer::Owl.new
84
+ s.add_resource(CONFIG[:services]["opentox-task"]+"/tmpId/ErrorReport/tmpId", OT.errorReport, rdf_content)
85
+ s.to_rdfxml
86
+ end
87
+ end
88
+ end
89
+
90
+ class Array
91
+ def short_backtrace
92
+ short = []
93
+ each do |c|
94
+ break if c =~ /sinatra\/base/
95
+ short << c
96
+ end
97
+ short.join("\n")
98
+ end
99
+ end
data/lib/feature.rb CHANGED
@@ -2,14 +2,42 @@ module OpenTox
2
2
  class Feature
3
3
  include OpenTox
4
4
 
5
- def self.find(uri)
5
+ def self.find(uri, subjectid=nil)
6
+ return nil unless uri
6
7
  feature = Feature.new uri
7
8
  if (CONFIG[:yaml_hosts].include?(URI.parse(uri).host))
8
- feature.add_metadata YAML.load(RestClientWrapper.get(uri,:accept => "application/x-yaml"))
9
+ feature.add_metadata YAML.load(RestClientWrapper.get(uri,{:accept => "application/x-yaml", :subjectid => subjectid}))
9
10
  else
10
11
  feature.add_metadata Parser::Owl::Dataset.new(uri).load_metadata
11
12
  end
12
13
  feature
13
14
  end
15
+
16
+ # provides domain (possible target values) of classification feature
17
+ # @return [Array] list with possible target values
18
+ def domain
19
+ if metadata[OT.acceptValue]
20
+ raise "accept value found, remove hack and implement correctly"
21
+ else
22
+ if @uri=~/feature\/26221/ || @uri=~/feature\/221726/
23
+ return ["mutagen" , "nonmutagen"]
24
+ end
25
+ return [true, false]
26
+ end
27
+ end
28
+
29
+ # provides feature type, possible types are "regression" or "classification"
30
+ # @return [String] feature type, unknown if OT.isA property is unknown/ not set
31
+ def feature_type
32
+ case metadata[OT.isA]
33
+ when /NominalFeature/
34
+ "classification"
35
+ when /NumericFeature/
36
+ "regression"
37
+ else
38
+ "unknown"
39
+ end
40
+ end
41
+
14
42
  end
15
43
  end