solvebio 1.5.2 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.travis.yml +13 -8
  2. data/Gemfile +4 -2
  3. data/README.md +5 -3
  4. data/demo/cheatsheet.rb +31 -0
  5. data/lib/cli/auth.rb +6 -6
  6. data/lib/cli/irbrc.rb +2 -1
  7. data/lib/cli/options.rb +1 -1
  8. data/lib/client.rb +85 -83
  9. data/lib/credentials.rb +2 -2
  10. data/lib/main.rb +11 -2
  11. data/lib/query.rb +5 -6
  12. data/lib/resource/annotation.rb +23 -0
  13. data/lib/resource/apiresource.rb +241 -0
  14. data/lib/resource/dataset.rb +91 -0
  15. data/lib/resource/datasetfield.rb +37 -0
  16. data/lib/resource/depository.rb +50 -0
  17. data/lib/resource/depositoryversion.rb +69 -0
  18. data/lib/resource/main.rb +123 -0
  19. data/lib/resource/sample.rb +75 -0
  20. data/lib/{solveobject.rb → resource/solveobject.rb} +43 -22
  21. data/lib/resource/user.rb +5 -0
  22. data/lib/solvebio.rb +1 -1
  23. data/lib/util.rb +29 -0
  24. data/solvebio.gemspec +7 -4
  25. data/test/Makefile +9 -0
  26. data/test/data/sample.vcf.gz +0 -0
  27. data/test/helper.rb +9 -2
  28. data/test/test-annotation.rb +46 -0
  29. data/test/test-auth.rb +8 -4
  30. data/test/test-client.rb +6 -6
  31. data/test/test-conversion.rb +13 -0
  32. data/test/test-dataset.rb +42 -0
  33. data/test/test-depository.rb +35 -0
  34. data/test/test-netrc.rb +13 -3
  35. data/test/test-query-batch.rb +26 -46
  36. data/test/test-query-paging.rb +77 -98
  37. data/test/test-query.rb +47 -64
  38. data/test/test-resource.rb +8 -15
  39. data/test/test-sample-access.rb +59 -0
  40. data/test/test-sample-download.rb +20 -0
  41. data/test/test-tabulate.rb +27 -23
  42. data/test/{test-solveobject.rb → test-util.rb} +17 -2
  43. metadata +128 -56
  44. data/lib/apiresource.rb +0 -130
  45. data/lib/help.rb +0 -46
  46. data/lib/resource.rb +0 -414
@@ -0,0 +1,123 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require_relative 'solveobject'
4
+ require_relative 'annotation'
5
+ require_relative 'apiresource'
6
+ require_relative 'dataset'
7
+ require_relative 'datasetfield'
8
+ require_relative 'depository'
9
+ require_relative 'depositoryversion'
10
+ require_relative 'sample'
11
+ require_relative 'user'
12
+
13
+ class SolveBio::ListObject < SolveBio::SolveObject
14
+
15
+ include Enumerable
16
+
17
+ def all(params={})
18
+ return request('get', self['url'], {:params => params})
19
+ end
20
+
21
+ def create(params={})
22
+ return request('post', self['url'], {:params => params})
23
+ end
24
+
25
+ def next_page(params={})
26
+ if self['links']['next']
27
+ return request('get', self['links']['next'], {:params => params})
28
+ end
29
+ return nil
30
+ end
31
+
32
+ def prev_page(params={})
33
+ if self['links']['prev']
34
+ request('get', self['links']['prev'], {:params => params})
35
+ end
36
+ return nil
37
+ end
38
+
39
+ def at(i)
40
+ self.to_a[i]
41
+ end
42
+
43
+ def to_a
44
+ return to_solve_object(self['data'])
45
+ end
46
+
47
+ def each(*pass)
48
+ return self unless block_given?
49
+ i = 0
50
+ ary = self.dup
51
+ done = false
52
+ until done
53
+ if i >= ary['data'].size
54
+ ary = next_page
55
+ break unless ary
56
+ i = 0
57
+ end
58
+ yield(ary.at(i))
59
+ i += 1
60
+ end
61
+ return self
62
+ end
63
+
64
+ def first
65
+ self['data'][0]
66
+ end
67
+
68
+ # def max
69
+ # self['data'][self['total']]
70
+ # end
71
+
72
+ end
73
+
74
+
75
+ SolveBio::SolveObject::CONVERSION = {
76
+ 'Annotation' => SolveBio::Annotation,
77
+ 'Depository' => SolveBio::Depository,
78
+ 'DepositoryVersion' => SolveBio::DepositoryVersion,
79
+ 'Dataset' => SolveBio::Dataset,
80
+ 'DatasetField' => SolveBio::DatasetField,
81
+ 'Sample' => SolveBio::Sample,
82
+ 'User' => SolveBio::User,
83
+ 'list' => SolveBio::ListObject
84
+ }
85
+
86
+ if __FILE__ == $0
87
+ puts '-' * 50
88
+ resp = {
89
+ 'class_name' => 'Dataset',
90
+ 'data_url' => 'https://api.solvebio.com/v1/datasets/25/data',
91
+ 'depository' => 'ClinVar',
92
+ 'depository_id' => 223,
93
+ 'depository_version' => 'ClinVar/2.0.0-1',
94
+ 'depository_version_id' => 15,
95
+ 'description' => '',
96
+ 'fields_url' => 'https://api.solvebio.com/v1/datasets/25/fields',
97
+ 'full_name' => 'ClinVar/2.0.0-1/Variants',
98
+ 'id' => 25,
99
+ 'name' => 'Variants',
100
+ 'title' => 'Variants',
101
+ 'url' => 'https://api.solvebio.com/v1/datasets/25'
102
+ }
103
+ so = to_solve_object(resp)
104
+ so = resp.to_solvebio
105
+ puts so.inspect
106
+ puts so.to_s
107
+
108
+ if ARGV[0]
109
+ require_relative './cli/auth.rb'
110
+ include SolveBio::Auth
111
+ login
112
+ puts '-' * 30, ' HELP ', '-' * 30
113
+ puts SolveBio::Depository.retrieve('ClinVar').help
114
+ puts '-' * 30, ' Retrieve ClinVar ','-' * 30
115
+ puts SolveBio::Depository.retrieve('ClinVar').to_s
116
+ puts '-' * 30, ' Versions ClinVar ','-' * 30
117
+ puts SolveBio::Depository.retrieve('Clinvar').versions.to_s
118
+ puts '-' * 30, ' Dataset ','-' * 30
119
+ puts SolveBio::Dataset.retrieve('Clinvar/2.0.0-1/Variants').to_s
120
+ puts '-' * 30, ' All Depository ','-' * 30
121
+ puts SolveBio::Depository.all.to_s
122
+ end
123
+ end
@@ -0,0 +1,75 @@
1
+ # Solvebio API Resource for Samples
2
+ require_relative 'apiresource'
3
+ require_relative 'solveobject'
4
+ require_relative '../errors'
5
+
6
+ # Samples are VCF files uploaded to the SolveBio API. We currently
7
+ # support uncompressed, extension `.vcf`, and gzip-compressed, extension
8
+ # `.vcf.gz`, VCF files. Any other extension will be rejected.
9
+ class SolveBio::Sample < SolveBio::APIResource
10
+
11
+ include SolveBio::DeletableAPIResource
12
+ include SolveBio::DownloadableAPIResource
13
+ include SolveBio::ListableAPIResource
14
+ include SolveBio::HelpableAPIResource
15
+
16
+ def annotate
17
+ SolveBio::Annotation.create :sample_id => self.id
18
+ end
19
+
20
+ # FIXME: Rubyize APIResource.retrieve
21
+ def self.retrieve(id, params={})
22
+ SolveBio::APIResource.retrieve(self, id)
23
+ end
24
+
25
+ def self.create(genome_build, params={})
26
+ if params.member?(:vcf_url)
27
+ if params.member?(:vcf_file)
28
+ raise TypeError,
29
+ 'Specified both vcf_url and vcf_file; use only one'
30
+ end
31
+ self.create_from_url(genome_build, params[:vcf_url])
32
+ elsif params.member?(:vcf_file)
33
+ return create_from_file(genome_build, params[:vcf_file])
34
+ else
35
+ raise TypeError,
36
+ 'Must specify exactly one of vcf_url or vcf_file parameter'
37
+ end
38
+ end
39
+
40
+ # Creates from the specified file. The data of the should be in
41
+ # VCF format.
42
+ def self.create_from_file(genome_build, vcf_file)
43
+
44
+ fh = File.open(vcf_file, 'rb')
45
+ params = {:genome_build => genome_build,
46
+ :vcf_file => fh}
47
+ response = SolveBio::Client.client.post(class_url(self), params,
48
+ :no_json => true)
49
+ to_solve_object(response)
50
+ end
51
+
52
+ # Creates from the specified URL. The data of the should be in
53
+ # VCF format.
54
+ def self.create_from_url(genome_build, vcf_url)
55
+
56
+ params = {:genome_build => genome_build,
57
+ :vcf_url => vcf_url}
58
+ begin
59
+ response = SolveBio::Client.client.post class_url(self), params
60
+ rescue SolveBio::Error => response
61
+ end
62
+ to_solve_object(response)
63
+ end
64
+ end
65
+
66
+ if __FILE__ == $0
67
+ unless SolveBio::API_HOST == 'https://api.solvebio.com'
68
+ SolveBio::SolveObject::CONVERSION = {
69
+ 'Sample' => SolveBio::Sample,
70
+ } unless defined? SolveBio::SolveObject::CONVERSION
71
+ url = 'http://downloads.solvebio.com/vcf/small_sample.vcf.gz'
72
+ response = SolveBio::Sample.create_from_url 'hg19', url
73
+ puts response
74
+ end
75
+ end
@@ -2,15 +2,7 @@
2
2
 
3
3
  require 'json'
4
4
  require 'set'
5
- require_relative 'client'
6
-
7
- # Add underscore before internal uppercase letters. Also, lowercase
8
- # all letters.
9
- def camelcase_to_underscore(name)
10
- # Using [[:upper:]] and [[:lower]] should help with Unicode.
11
- s1 = name.gsub(/(.)([[:upper:]])([[:lower:]]+)/){"#{$1}_#{$2}#{$3}"}
12
- return (s1.gsub(/([a-z0-9])([[:upper:]])/){"#{$1}_#{$2}"}).downcase
13
- end
5
+ require_relative '../client'
14
6
 
15
7
  # Base class for all SolveBio API resource objects
16
8
  class SolveBio::SolveObject < Hash
@@ -43,13 +35,13 @@ class SolveBio::SolveObject < Hash
43
35
  # Note: *key* is turned into a string before access, because the underlying key type
44
36
  # is a string.
45
37
  def [](key)
46
- return super(key.to_s)
38
+ super(key.to_s)
47
39
  end
48
40
 
49
41
  def self.construct_from(cls, values)
50
42
  instance = cls.new(values['id'])
51
43
  instance.refresh_from(values)
52
- return instance
44
+ instance
53
45
  end
54
46
 
55
47
  def refresh_from(values)
@@ -58,9 +50,10 @@ class SolveBio::SolveObject < Hash
58
50
  values.each { |k, v| self[k] = to_solve_object(v) }
59
51
  end
60
52
 
61
- def request(method, url, params=nil)
62
- response = SolveBio::Client.client.request(method, url, params)
63
- return to_solve_object(response)
53
+ def request(method, url, params={})
54
+ response = SolveBio::Client.client
55
+ .request method, url, {:params => params}
56
+ to_solve_object(response)
64
57
  end
65
58
 
66
59
  def inspect
@@ -74,27 +67,55 @@ class SolveBio::SolveObject < Hash
74
67
  ident_parts << "full_name=#{self['full_name']}"
75
68
  end
76
69
 
77
- return '<%s:%x> JSON: %s' % [ident_parts.join(' '),
78
- self.object_id, self.to_json]
70
+ '<%s:%x> JSON: %s' % [ident_parts.join(' '),
71
+ self.object_id, self.to_json]
79
72
 
80
73
  end
81
74
 
82
75
  def to_s
83
76
  # No equivalent of Python's json sort_keys?
84
- return JSON.pretty_generate(self, :indent => ' ')
85
- # return self.to_json json.dumps(self, sort_keys=true, indent=2)
77
+ JSON.pretty_generate(self, :indent => ' ')
78
+ # self.to_json json.dumps(self, sort_keys=true, indent=2)
86
79
  end
87
80
 
88
81
  # @property
89
82
  def id
90
- return self['id']
83
+ self['id']
91
84
  end
92
85
  end
93
86
 
94
- if __FILE__ == $0
95
- %w(abc abcDef abc01Def aBcDef a1B2C3 ?Foo Dataset).each do |word|
96
- puts word + " -> " + camelcase_to_underscore(word)
87
+ class Hash
88
+ def to_solvebio(klass=nil)
89
+ resp = self.dup()
90
+ if ! klass
91
+ klass_name ||= resp['class_name']
92
+ if klass_name.kind_of?(String)
93
+ klass = SolveBio::SolveObject::CONVERSION[klass_name] ||
94
+ SolveBio::SolveObject
95
+ else
96
+ klass = SolveBio::SolveObject
97
+ end
98
+ end
99
+ SolveBio::SolveObject::construct_from(klass, resp)
100
+ end
101
+ end
102
+
103
+ class Array
104
+ def to_solvebio
105
+ return self.map{|i| to_solve_object(i)}
97
106
  end
107
+ end
108
+
109
+ def to_solve_object(resp)
110
+ if resp.kind_of?(Array) or
111
+ (not resp.kind_of? SolveBio::SolveObject and resp.kind_of?(Hash))
112
+ resp.to_solvebio
113
+ else
114
+ return resp
115
+ end
116
+ end
117
+
118
+ if __FILE__ == $0
98
119
  puts SolveBio::SolveObject.new.inspect
99
120
  puts SolveBio::SolveObject.new(64).inspect
100
121
 
@@ -0,0 +1,5 @@
1
+ require_relative 'apiresource'
2
+
3
+ class SolveBio::User < SolveBio::APIResource
4
+ include SolveBio::SingletonAPIResource
5
+ end
data/lib/solvebio.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Something to pull in the entire SolveBio API.
3
3
 
4
- require_relative 'resource'
4
+ require_relative 'resource/main'
5
5
  require_relative 'query'
6
6
 
7
7
  # cli/auth is a little nicer than credentials
data/lib/util.rb ADDED
@@ -0,0 +1,29 @@
1
+ module SolveBio
2
+
3
+ module_function
4
+ def pluralize(name)
5
+ if name.end_with?('y')
6
+ name = name[0..-2] + 'ie'
7
+ end
8
+ return name + "s"
9
+ end
10
+
11
+ # Add underscore before internal uppercase letters. Also, lowercase
12
+ # all letters.
13
+ def camelcase_to_underscore(name)
14
+ # Using [[:upper:]] and [[:lower]] should help with Unicode.
15
+ s1 = name.gsub(/(.)([[:upper:]])([[:lower:]]+)/){"#{$1}_#{$2}#{$3}"}
16
+ return (s1.gsub(/([a-z0-9])([[:upper:]])/){"#{$1}_#{$2}"}).downcase
17
+ end
18
+ end
19
+
20
+ # Demo code
21
+ if __FILE__ == $0
22
+ include SolveBio
23
+ %w(abc abcDef abc01Def aBcDef a1B2C3 ?Foo Dataset).each do |word|
24
+ puts word + " -> " + camelcase_to_underscore(word)
25
+ end
26
+ ['depository', 'dataset'].each do |word|
27
+ puts word + " -> " + pluralize(word)
28
+ end
29
+ end
data/solvebio.gemspec CHANGED
@@ -14,8 +14,8 @@ Gem::Specification.new do |s|
14
14
  ## If your rubyforge_project name is different, then edit it and comment out
15
15
  ## the sub! line in the Rakefile
16
16
  s.name = 'solvebio'
17
- s.version = '1.5.2'
18
- s.date = '2014-10-01'
17
+ s.version = '1.6.1'
18
+ s.date = '2014-11-05'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
21
21
  ## as you like.
@@ -54,9 +54,12 @@ EOD
54
54
 
55
55
  ## List your runtime dependencies here. Runtime dependencies are those
56
56
  ## that are needed for an end user to actually USE your code.
57
- s.add_dependency('netrc', '>=0.7.7')
58
- # s.add_dependency('openssl', '>=1.1.0')
59
57
 
58
+ s.add_dependency('netrc', '>=0.7.7') # handling .netrc
59
+ s.add_dependency('rest_client', '>=1.8.1') # better URI handler
60
+ s.add_dependency('addressable', '>=2.3.6') # better URI parsing
61
+
62
+ # s.add_dependency('openssl', '>=1.1.0')
60
63
 
61
64
  # There is no way to specify optional dependencies.
62
65
  # s.add_optional_dependency 'launchy' # opens URL in web browser for help
data/test/Makefile ADDED
@@ -0,0 +1,9 @@
1
+ # Whatever it is you want to do other run demos, it should be forwarded to the
2
+ # to top-level directory
3
+ .PHONY: all
4
+
5
+ #: the default target - same as running "check"
6
+ all: check
7
+
8
+ %:
9
+ $(MAKE) -C .. $@
Binary file
data/test/helper.rb CHANGED
@@ -1,3 +1,10 @@
1
1
  require 'test/unit'
2
- require_relative '../lib/resource'
3
- SolveBio.api_key = 'ce68f783a65275d3e81463621d825bad20eb20b0'
2
+ ENV['SOLVEBIO_API_HOST'] ||= 'https://api.solvebio.com'
3
+ require_relative '../lib/main'
4
+
5
+ TEST_DATASET_NAME = 'HGNC/1.0.0-1/HGNC'
6
+
7
+
8
+ def local_api?
9
+ ENV['SOLVEBIO_LOCAL_API']
10
+ end
@@ -0,0 +1,46 @@
1
+ require_relative './helper'
2
+
3
+ class TestAnnotation < Test::Unit::TestCase
4
+
5
+ def check_response(response, expect, msg)
6
+ expect.each do |key, val|
7
+ assert_equal(val, response[key], msg)
8
+ end
9
+ end
10
+
11
+ def test_annotation
12
+ if SolveBio::API_HOST == 'https://api.solvebio.com'
13
+ skip "Annotation testing only on local/dev environments"
14
+ end
15
+
16
+ vcf_file = File.join(File.dirname(__FILE__), "data/sample.vcf.gz")
17
+ my_sample = SolveBio::Sample
18
+ .create('GRCh37', :vcf_file => vcf_file)
19
+ assert(my_sample)
20
+
21
+ sample_id = my_sample['id']
22
+ expect = {
23
+ 'class_name' => 'Annotation',
24
+ 'error_message' => '',
25
+ 'sample_id' => sample_id
26
+ }
27
+
28
+ response = SolveBio::Annotation.create(:sample_id => sample_id)
29
+ check_response(response, expect,
30
+ "'Annotation.create(:sample_id=>{#sample_id}")
31
+
32
+ ['status', 'user_id', 'created_at', 'updated_at'].each do |field|
33
+ assert(response.member?(field) ,
34
+ "response has field #{field}")
35
+ end
36
+
37
+ all = SolveBio::Annotation.all()
38
+ assert(all.total > 1,
39
+ "Annotation.all() returns more than one value")
40
+
41
+ response = my_sample.annotate
42
+ # FIXME: test annotate() more.
43
+
44
+ my_sample.delete
45
+ end
46
+ end