lumidatum_client 0.1.4

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7f9eb2eee7f3432b6c5628a87aead931b889382d
4
+ data.tar.gz: 699fe1ea088c18ac0db067d3e27d9fdd2cbd48d9
5
+ SHA512:
6
+ metadata.gz: ed2ffeb4a32e92a1498fb6caf1b670a0100a6a7b9c0dd5cff1dc770b75cc428441434468045086f56802abdc7087bca174a211fc9e9af47c4e05c00a8f90eb63
7
+ data.tar.gz: f9523e0ec6bbbf958dc009cb2555f4b900a7e86506456287a5029c45215e5347edce721d8bd37d2ca122b5063c95d6a763a20eb9042ac5a05ceca2e15208585b
File without changes
@@ -0,0 +1,195 @@
1
+ require "json"
2
+
3
+ require "httpclient"
4
+
5
+
6
+ class LumidatumClient
7
+ attr_accessor :authentication_token
8
+ attr_accessor :model_id
9
+ attr_accessor :host_address
10
+ attr_accessor :http_client
11
+ attr_accessor :file_handler
12
+
13
+ def initialize(authentication_token, model_id=nil, host_address="https://www.lumidatum.com", http_client=nil, file_handler=File)
14
+ if authentication_token == nil
15
+ raise ArgumentError, "authentication_token must not be nil"
16
+ end
17
+
18
+ @authentication_token = authentication_token
19
+ @model_id = model_id
20
+ @host_address = host_address.chomp("/")
21
+
22
+ if http_client == nil
23
+ @http_client = HTTPClient.new
24
+ else
25
+ @http_client = http_client;
26
+ end
27
+
28
+ @file_handler = file_handler
29
+ end
30
+
31
+
32
+ def getItemRecommendations(parameters, model_id: nil, deserialize_response: true)
33
+ model_id = _getModelIdOrError(model_id)
34
+
35
+ return api("POST", "api/predict/#{model_id}", nil, parameters, deserialize_response: deserialize_response)
36
+ end
37
+
38
+ def getUserRecommendations(parameters, model_id: nil, deserialize_response: true)
39
+ model_id = _getModelIdOrError(model_id)
40
+
41
+ return api("POST", "api/predict/#{model_id}", nil, parameters, deserialize_response: deserialize_response)
42
+ end
43
+
44
+
45
+ # Data upload
46
+ def sendUserData(data_string: nil, file_path: nil, model_id: nil)
47
+ model_id = _getModelIdOrError(model_id)
48
+
49
+ return sendData("users", data_string, file_path, model_id)
50
+ end
51
+
52
+ def sendItemData(data_string: nil, file_path: nil, model_id: nil)
53
+ model_id = _getModelIdOrError(model_id)
54
+
55
+ return sendData("items", data_string, file_path, model_id)
56
+ end
57
+
58
+ def sendTransactionData(data_string: nil, file_path: nil, model_id: nil)
59
+ model_id = _getModelIdOrError(model_id)
60
+
61
+ return sendData("transactions", data_string, file_path, model_id)
62
+ end
63
+
64
+ def sendData(data_type, data_string, file_path, model_id)
65
+ model_id = _getModelIdOrError(model_id)
66
+
67
+ url_endpoint = "api/data"
68
+
69
+ if data_string != nil
70
+ url_query_parameters = {:model_id => model_id, :data_type => data_type}
71
+
72
+ return api("POST", url_endpoint, url_query_parameters, parameters)
73
+ else
74
+ file_name = File.basename(file_path)
75
+ file_size = nil
76
+ presigned_response_object = getPresignedResponse(
77
+ nil,
78
+ model_id,
79
+ data_type: data_type,
80
+ file_name: file_name,
81
+ file_size: file_size
82
+ )
83
+ end
84
+
85
+ @file_handler.open(file_path) do |upload_file|
86
+ form_fields = presigned_response_object["fields"]
87
+ form_fields["file"] = upload_file
88
+
89
+ return @http_client.post(presigned_response_object["url"], form_fields)
90
+ end
91
+ end
92
+
93
+ # File download
94
+ def getLatestLTVReport(download_file_path, model_id: nil, zipped: true, stream_download: true)
95
+ model_id = _getModelIdOrError(model_id)
96
+
97
+ latest_key_name = getAvailableReports("LTV", model_id, zipped: zipped)
98
+
99
+ presigned_response_object = getPresignedResponse(latest_key_name, model_id, is_download: true)
100
+
101
+ report_response = @http_client.get(presigned_response_object["url"])
102
+ open(download_file_path, "wb") do |file|
103
+ file.write(report_response.body)
104
+ end
105
+
106
+ return report_response
107
+ end
108
+
109
+ def getLatestSegmentationReport(download_file_path, model_id: nil, zipped: true, stream_download: true)
110
+ model_id = _getModelIdOrError(model_id)
111
+
112
+ latest_key_name = getAvailableReports("SEG", model_id, zipped: zipped)
113
+ presigned_response_object = getPresignedResponse(latest_key_name, model_id, is_download: true)
114
+
115
+ report_response = @http_client.get(presigned_response_object["url"])
116
+ open(download_file_path, "wb") do |file|
117
+ file.write(report_response.body)
118
+ end
119
+
120
+ return report_response
121
+ end
122
+
123
+ def getAvailableReports(report_type, model_id, zipped: true, latest: true)
124
+ url_query_parameters = {:model_id => model_id, :report_type => report_type, :zipped => zipped, :latest => true}
125
+ list_reports_response = api("GET", "api/data", url_query_parameters, model_id, deserialize_response: false)
126
+ list_reports_response_object = JSON.parse(list_reports_response.body)
127
+
128
+ if list_reports_response.status != 200
129
+ raise IOError, "HTTP #{list_reports_response.status}: #{list_reports_response_object["error"]} "
130
+ end
131
+
132
+ if list_reports_response_object["latest_key_name"] != nil
133
+
134
+ return list_reports_response_object["latest_key_name"]
135
+ else
136
+
137
+ return list_reports_response_object["available_key_names"]
138
+ end
139
+ end
140
+
141
+ def getPresignedResponse(key_name, model_id, data_type: nil, file_name: nil, file_size: nil, is_download: false)
142
+ parameters = {"model_id": model_id}
143
+
144
+ if is_download
145
+ parameters["key_name"] = key_name
146
+ parameters["is_download"] = true
147
+ else
148
+ parameters["data_type"] = data_type
149
+ parameters["file_name"] = file_name
150
+ parameters["file_size"] = file_size
151
+ parameters["presigned_url_http_method"] = "PUT"
152
+ end
153
+
154
+ return api("POST", "api/data", nil, parameters)
155
+ end
156
+
157
+
158
+ def api(http_method, url_endpoint, url_query_parameters, parameters, deserialize_response: true)
159
+ formatted_url = "#{@host_address}/#{url_endpoint}"
160
+ if url_query_parameters
161
+ formatted_url = formatted_url + "?" + URI.encode_www_form(url_query_parameters)
162
+ end
163
+
164
+ headers = {"authorization" => @authentication_token, "content-type" => "application/json"}
165
+
166
+ if http_method == "GET"
167
+ api_response = @http_client.get(formatted_url, header: headers)
168
+ elsif http_method == "POST"
169
+ if parameters.class != String
170
+ parameters_str = JSON.generate(parameters)
171
+ end
172
+ api_response = @http_client.post(formatted_url, header: headers, body: parameters_str)
173
+ end
174
+
175
+ if deserialize_response
176
+ if api_response.status == 200 or api_response.status == 201
177
+
178
+ return JSON.parse(api_response.body)
179
+ end
180
+ else
181
+
182
+ return api_response
183
+ end
184
+ end
185
+
186
+
187
+ def _getModelIdOrError(model_id)
188
+ model_id = if model_id == nil then @model_id else model_id end
189
+ if model_id == nil
190
+ raise ArgumentError, "model_id must be set during client instantiation or provided during your instance method call."
191
+ end
192
+
193
+ return model_id
194
+ end
195
+ end
@@ -0,0 +1,181 @@
1
+ require "json"
2
+ require "minitest/autorun"
3
+
4
+ require "webmock/test_unit"
5
+
6
+ require "./lib/lumidatum_client.rb"
7
+
8
+
9
+ class ClientInit < Minitest::Test
10
+ def setup
11
+ @valid_api_token = "Token <API key>"
12
+ @valid_model_id = 123
13
+ @custom_host_address = "http://localhost:8000"
14
+
15
+ @default_host_address = "https://www.lumidatum.com"
16
+ end
17
+
18
+ # No specified host/default host
19
+ def test_client_init
20
+ test_client = LumidatumClient.new(@valid_api_token, @valid_model_id, @custom_host_address)
21
+
22
+ assert_instance_of(LumidatumClient, test_client)
23
+ end
24
+
25
+ def test_default_host
26
+ test_client = LumidatumClient.new(@valid_api_token, @valid_model_id)
27
+
28
+ # Default host should be https://www.lumidatum.com
29
+ assert_equal(@default_host_address, test_client.host_address)
30
+ end
31
+
32
+ def test_specifying_a_host
33
+ test_client = LumidatumClient.new(@valid_api_token, @valid_model_id, @custom_host_address)
34
+
35
+ assert_equal(@custom_host_address, test_client.host_address)
36
+ end
37
+
38
+ def test_nil_model_id_is_fine
39
+ test_client = LumidatumClient.new(@valid_api_token)
40
+
41
+ assert_nil(test_client.model_id)
42
+ end
43
+
44
+ def test_nil_api_token_error
45
+ assert_raises ArgumentError do
46
+ LumidatumClient.new(nil, @valid_model_id)
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ def createTestClient
53
+
54
+ return LumidatumClient.new("API Key", 123)
55
+ end
56
+
57
+ def createTestClientNoModelId
58
+
59
+ return LumidatumClient.new("API Key")
60
+ end
61
+
62
+
63
+ class Personalization
64
+ def setup
65
+ @test_client = createTestClient
66
+ end
67
+
68
+ def test_item_recs
69
+ test_recommendations = [[], [], []]
70
+ WebMock.stub_request(
71
+ :post,
72
+ "https://www.lumidatum.com/api/predict/123"
73
+ ).to_return(
74
+ status: 200,
75
+ body: JSON.generate(test_recommendations)
76
+ )
77
+
78
+ recommendations = @test_client.getItemRecommendations({})
79
+
80
+ assert_equal(test_recommendations, recommendations)
81
+ end
82
+ end
83
+
84
+
85
+ def setupValidUploadResponses
86
+ # Upload presign request
87
+ WebMock.stub_request(
88
+ :post,
89
+ "https://www.lumidatum.com/api/data"
90
+ ).to_return(
91
+ status: 201,
92
+ body: JSON.generate({"url" => "http://test.upload.url", "fields" => {}})
93
+ )
94
+ # S3 upload response
95
+ WebMock.stub_request(
96
+ :post,
97
+ "http://test.upload.url"
98
+ ).to_return(
99
+ status: 204
100
+ )
101
+ end
102
+
103
+
104
+ class UploadDataFiles < Minitest::Test
105
+ def setup
106
+ @test_client = createTestClient
107
+ end
108
+
109
+ def test_sending_file
110
+ setupValidUploadResponses
111
+
112
+ file_upload_response = @test_client.sendTransactionData(file_path: "tests/resources/test_data.csv")
113
+
114
+ assert_equal(204, file_upload_response.status)
115
+ end
116
+
117
+ def test_no_model_id_error
118
+ no_model_id_test_client = createTestClientNoModelId
119
+
120
+ assert_raises ArgumentError do
121
+ no_model_id_test_client.sendTransactionData(file_path: "tests/resources/test_data.csv")
122
+ end
123
+ end
124
+
125
+ def test_no_model_id_in_client
126
+ setupValidUploadResponses
127
+
128
+ no_model_id_test_client = createTestClientNoModelId
129
+
130
+ no_model_id_test_client.sendTransactionData(file_path: "tests/resources/test_data.csv", model_id: 123)
131
+ end
132
+ end
133
+
134
+ class DownloadReports < Minitest::Test
135
+ def setup
136
+ @test_client = createTestClient
137
+ end
138
+
139
+ def test_no_report_yet
140
+ # List response
141
+ WebMock.stub_request(
142
+ :get,
143
+ "https://www.lumidatum.com/api/data?latest=true&model_id=123&report_type=LTV&zipped=true&latest=true"
144
+ ).to_return(
145
+ status: 404,
146
+ body: JSON.generate({"error" => "Requested item does not exist."})
147
+ )
148
+
149
+ # Raises error for 404 response on list call
150
+ assert_raises IOError do
151
+ file_download_response = @test_client.getLatestLTVReport("test_download_file.csv")
152
+ end
153
+ end
154
+
155
+ def test_getting_report
156
+ # List response
157
+ WebMock.stub_request(
158
+ :get,
159
+ "https://www.lumidatum.com/api/data?latest=true&model_id=123&report_type=LTV&zipped=true&latest=true"
160
+ ).to_return(
161
+ status: 200,
162
+ body: JSON.generate({"key_name" => "test_key_name"})
163
+ )
164
+ # Presign response
165
+ WebMock.stub_request(
166
+ :post, "https://www.lumidatum.com/api/data"
167
+ ).to_return(
168
+ status: 200,
169
+ body: JSON.generate({"url" => "http://test.download.url"})
170
+ )
171
+ # S3 download response
172
+ WebMock.stub_request(:get, "http://test.download.url")
173
+
174
+ file_download_response = @test_client.getLatestLTVReport("test_download_file.csv")
175
+
176
+ assert_equal(200, file_download_response.status)
177
+
178
+ # Clean up
179
+ File.delete("test_download_file.csv")
180
+ end
181
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lumidatum_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Mat Lee
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httpclient
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.8'
27
+ description: ''
28
+ email:
29
+ - matt@lumidatum.com
30
+ executables:
31
+ - lumidatum_client
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - bin/lumidatum_client
36
+ - lib/lumidatum_client.rb
37
+ - tests/test_client_unit_tests.rb
38
+ homepage: https://www.lumidatum.com
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 2.6.10
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: ''
62
+ test_files:
63
+ - tests/test_client_unit_tests.rb