etna 0.1.21 → 0.1.26

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 920faf7833d50d01c0a22d7326d0d3c454cdec27479ce81e4bf0b4012891f0bc
4
- data.tar.gz: 189fad452f86a48ee19343eb7d5bd16bb9cf7308d8fd2dee41d042de2a76cc86
3
+ metadata.gz: 7075c5bf9637903a5aae31e83dbec99fc903945b362b5b454a3d31f95c03c6eb
4
+ data.tar.gz: 48e957e8286a613f7a1cafab2512976e625211782ae09a402053161af0f69b87
5
5
  SHA512:
6
- metadata.gz: 64b2fef7604de4803790fea8543d39d8e6466456231ed014e30e633659049348274971c10a3231964664340cd13b616a2612c0cb0c89dd71337b4fb57f9432a5
7
- data.tar.gz: 7ac816e004b1ace47c193f26944586d2eaca6e35a4c9fc7e76ab9dfe524b5f41cbf2f94abfa377006b80f59baaee1690b3582aa07f2a1ea851dc76fada707805
6
+ metadata.gz: 850effed7485f90957cb3ee53ebb97abaa3fe9c32d9de9ff16c5d30585b61f34ccf00bb88c702ee9f1271c8a883526cebc36218904c311c276d6de51aca0d1ba
7
+ data.tar.gz: 1c90072a96341cf75b869d08f9e1cd1e36c2a616873048d83c6c1cd2ffe57850c618745c80ee1e16e63c2c8c4c090cbb8c99ab19ed1541ec06d8b43d29824d0a
@@ -77,7 +77,7 @@ all_flag_completion_names="$all_flag_completion_names "
77
77
  string_flag_completion_names="$string_flag_completion_names "
78
78
  while [[ "$#" != "0" ]]; do
79
79
  if [[ "$#" == "1" ]]; then
80
- all_completion_names="apply_template attributes copy_template help"
80
+ all_completion_names="apply_template attributes copy_template help load_from_redcap"
81
81
  all_completion_names="$all_completion_names $all_flag_completion_names"
82
82
  if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
83
83
  return
@@ -136,7 +136,7 @@ all_flag_completion_names="$all_flag_completion_names "
136
136
  string_flag_completion_names="$string_flag_completion_names "
137
137
  while [[ "$#" != "0" ]]; do
138
138
  if [[ "$#" == "1" ]]; then
139
- all_completion_names="create_file_linking_csv help update_from_csv"
139
+ all_completion_names="create_file_linking_csv help load_table_from_csv update_from_csv"
140
140
  all_completion_names="$all_completion_names $all_flag_completion_names"
141
141
  if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
142
142
  return
@@ -252,6 +252,68 @@ return
252
252
  fi
253
253
  done
254
254
  return
255
+ elif [[ "$1" == "load_table_from_csv" ]]; then
256
+ shift
257
+ if [[ "$#" == "1" ]]; then
258
+ all_completion_names="__project_name__"
259
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
260
+ return
261
+ fi
262
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
263
+ return
264
+ fi
265
+ shift
266
+ if [[ "$#" == "1" ]]; then
267
+ all_completion_names="__model_name__"
268
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
269
+ return
270
+ fi
271
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
272
+ return
273
+ fi
274
+ shift
275
+ if [[ "$#" == "1" ]]; then
276
+ all_completion_names="__file_path__"
277
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
278
+ return
279
+ fi
280
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
281
+ return
282
+ fi
283
+ shift
284
+ all_flag_completion_names="$all_flag_completion_names --execute "
285
+ string_flag_completion_names="$string_flag_completion_names "
286
+ while [[ "$#" != "0" ]]; do
287
+ if [[ "$#" == "1" ]]; then
288
+ all_completion_names=""
289
+ all_completion_names="$all_completion_names $all_flag_completion_names"
290
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
291
+ return
292
+ fi
293
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
294
+ return
295
+ elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
296
+ return
297
+ elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
298
+ all_flag_completion_names="${all_flag_completion_names//$1\ /}"
299
+ a=$1
300
+ shift
301
+ if [[ "$string_flag_completion_names" =~ $a\ ]]; then
302
+ if [[ "$#" == "1" ]]; then
303
+ a="${a//--/}"
304
+ a="${a//-/_}"
305
+ i="_completions_for_$a"
306
+ all_completion_names="${!i}"
307
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
308
+ return
309
+ fi
310
+ shift
311
+ fi
312
+ else
313
+ return
314
+ fi
315
+ done
316
+ return
255
317
  elif [[ "$1" == "update_from_csv" ]]; then
256
318
  shift
257
319
  if [[ "$#" == "1" ]]; then
@@ -417,6 +479,61 @@ return
417
479
  fi
418
480
  done
419
481
  return
482
+ elif [[ "$1" == "load_from_redcap" ]]; then
483
+ shift
484
+ if [[ "$#" == "1" ]]; then
485
+ all_completion_names="__project_name__"
486
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
487
+ return
488
+ fi
489
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
490
+ return
491
+ fi
492
+ shift
493
+ if [[ "$#" == "1" ]]; then
494
+ all_completion_names="__redcap_tokens__"
495
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
496
+ return
497
+ fi
498
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
499
+ return
500
+ fi
501
+ shift
502
+ all_flag_completion_names="$all_flag_completion_names --commit --models --record_names "
503
+ string_flag_completion_names="$string_flag_completion_names --models --record_names "
504
+ declare _completions_for_models="__models__"
505
+ declare _completions_for_record_names="__record_names__"
506
+ while [[ "$#" != "0" ]]; do
507
+ if [[ "$#" == "1" ]]; then
508
+ all_completion_names=""
509
+ all_completion_names="$all_completion_names $all_flag_completion_names"
510
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
511
+ return
512
+ fi
513
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
514
+ return
515
+ elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
516
+ return
517
+ elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
518
+ all_flag_completion_names="${all_flag_completion_names//$1\ /}"
519
+ a=$1
520
+ shift
521
+ if [[ "$string_flag_completion_names" =~ $a\ ]]; then
522
+ if [[ "$#" == "1" ]]; then
523
+ a="${a//--/}"
524
+ a="${a//-/_}"
525
+ i="_completions_for_$a"
526
+ all_completion_names="${!i}"
527
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
528
+ return
529
+ fi
530
+ shift
531
+ fi
532
+ else
533
+ return
534
+ fi
535
+ done
536
+ return
420
537
  elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
421
538
  return
422
539
  elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
@@ -54,7 +54,7 @@ class EtnaApp
54
54
  boolean_flags << '--ignore-ssl'
55
55
 
56
56
  def execute(host, ignore_ssl: false)
57
- polyphemus_client ||= Etna::Clients::Polyphemus.new(
57
+ polyphemus_client = Etna::Clients::Polyphemus.new(
58
58
  host: host,
59
59
  token: token(ignore_environment: true),
60
60
  ignore_ssl: ignore_ssl)
@@ -62,7 +62,7 @@ class EtnaApp
62
62
  polyphemus_client: polyphemus_client,
63
63
  config_file: EtnaApp.config_file_path)
64
64
  config = workflow.update_configuration_file(ignore_ssl: ignore_ssl)
65
- logger.info("Updated #{config.environment} configuration from #{host}.")
65
+ logger&.info("Updated #{config.environment} configuration from #{host}.")
66
66
  end
67
67
 
68
68
  def setup(config)
@@ -299,6 +299,87 @@ class EtnaApp
299
299
  workflow.write_csv_io(filename: file)
300
300
  end
301
301
  end
302
+
303
+ class LoadTableFromCsv < Etna::Command
304
+ include WithEtnaClients
305
+
306
+ boolean_flags << '--execute'
307
+
308
+ def execute(project_name, model_name, file_path, execute: false)
309
+ request = Etna::Clients::Magma::RetrievalRequest.new(project_name: project_name)
310
+ request.model_name = model_name
311
+ request.attribute_names = 'all'
312
+ request.record_names = 'all'
313
+ model = magma_client.retrieve(request).models.model(model_name)
314
+ model_parent_name = model.template.attributes.all.select do |attribute|
315
+ attribute.attribute_type == Etna::Clients::Magma::AttributeType::PARENT
316
+ end.first.name
317
+
318
+ other_attribute_names = model.template.attributes.all.reject do |attribute|
319
+ attribute.attribute_type == Etna::Clients::Magma::AttributeType::PARENT
320
+ end.map do |attribute|
321
+ attribute.name
322
+ end
323
+
324
+ # NOTE: This does not call ensure_parent currently because of MVIR1 consent--
325
+ # if the timepoint doesn't exist, the patient may be no study? (one example, at least)
326
+ update_request = Etna::Clients::Magma::UpdateRequest.new(project_name: project_name)
327
+
328
+ data = CSV.parse(File.read(file_path), headers: true)
329
+
330
+ data.by_row.each do |row|
331
+ revision = {}
332
+ other_attribute_names.each do |attribute_name|
333
+ revision[attribute_name] = row[attribute_name] unless row[attribute_name].nil?
334
+ end
335
+ update_request.append_table(model_parent_name, row[model_parent_name], model_name, revision)
336
+ end
337
+
338
+ puts update_request
339
+
340
+ if execute
341
+ magma_client.update_json(update_request)
342
+ end
343
+ end
344
+ end
345
+ end
346
+
347
+ class LoadFromRedcap < Etna::Command
348
+ include WithEtnaClients
349
+ include WithLogger
350
+ include StrongConfirmation
351
+
352
+ boolean_flags << '--commit'
353
+ string_flags << '--models'
354
+ string_flags << '--record_names'
355
+
356
+ def execute(project_name, redcap_tokens, models: "all", record_names: nil, commit: false)
357
+ raise "Must provide at least one REDCap token (comma-separated)." unless redcap_tokens.split(',').length > 0
358
+
359
+ puts "NOTE: This is a **preview** of what the data loading will look like. Use the --commit flag to load records into Magma." unless commit
360
+
361
+ polyphemus_client.job(Etna::Clients::Polyphemus::RedcapJobRequest.new(
362
+ model_names: "all" == models ? "all" : models.split(','),
363
+ record_names: nil == record_names || "existing" == record_names ? record_names : record_names.split(','),
364
+ redcap_tokens: redcap_tokens.split(','),
365
+ project_name: project_name,
366
+ commit: commit
367
+ )) do |response|
368
+ response.read_body do |chunk|
369
+ puts clean_sne_message(chunk)
370
+ end
371
+ end
372
+ end
373
+
374
+ def clean_sne_message(chunk)
375
+ chunk.split("\n").reject do |c|
376
+ c.start_with?("retry:") || c.start_with?("event:")
377
+ end.map do |c|
378
+ c.gsub("data:", "").strip
379
+ end.reject do |c|
380
+ c.empty?
381
+ end
382
+ end
302
383
  end
303
384
  end
304
385
  end
@@ -18,6 +18,8 @@ require_relative './etna/spec'
18
18
  require_relative './etna/clients'
19
19
  require_relative './etna/csvs'
20
20
  require_relative './etna/environment_scoped'
21
+ require_relative './etna/filesystem'
22
+ require_relative './etna/formatting'
21
23
 
22
24
  class EtnaApp
23
25
  include Etna::Application
@@ -1,14 +1,12 @@
1
- require 'net/http/persistent'
2
1
  require 'net/http/post/multipart'
3
2
  require 'singleton'
4
3
  require 'rack/utils'
5
4
 
6
5
  module Etna
7
6
  class Client
8
- def initialize(host, token, routes_available: true, persistent: true, ignore_ssl: false)
7
+ def initialize(host, token, routes_available: true, ignore_ssl: false)
9
8
  @host = host.sub(%r!/$!, '')
10
9
  @token = token
11
- @persistent = persistent
12
10
  @ignore_ssl = ignore_ssl
13
11
 
14
12
  if routes_available
@@ -38,6 +36,10 @@ module Etna
38
36
  query_request(Net::HTTP::Get, endpoint, params, &block)
39
37
  end
40
38
 
39
+ def head(endpoint, params = {}, &block)
40
+ query_request(Net::HTTP::Head, endpoint, params, &block)
41
+ end
42
+
41
43
  def options(endpoint, params = {}, &block)
42
44
  query_request(Net::HTTP::Options, endpoint, params, &block)
43
45
  end
@@ -79,16 +81,6 @@ module Etna
79
81
  end
80
82
  end
81
83
 
82
- def persistent_connection
83
- @http ||= begin
84
- http = Net::HTTP::Persistent.new
85
- http.read_timeout = 3600
86
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @ignore_ssl
87
- http
88
- end
89
- end
90
-
91
-
92
84
  def body_request(type, endpoint, params = {}, &block)
93
85
  uri = request_uri(endpoint)
94
86
  req = type.new(uri.request_uri, request_params)
@@ -141,36 +133,23 @@ module Etna
141
133
 
142
134
  def request(uri, data)
143
135
  if block_given?
144
- if @persistent
145
- persistent_connection.request(uri, data) do |response|
136
+ verify_mode = @ignore_ssl ?
137
+ OpenSSL::SSL::VERIFY_NONE :
138
+ OpenSSL::SSL::VERIFY_PEER
139
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: verify_mode) do |http|
140
+ http.request(data) do |response|
146
141
  status_check!(response)
147
142
  yield response
148
143
  end
149
- else
150
- verify_mode = @ignore_ssl ?
151
- OpenSSL::SSL::VERIFY_NONE :
152
- OpenSSL::SSL::VERIFY_PEER
153
- Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: verify_mode) do |http|
154
- http.request(data) do |response|
155
- status_check!(response)
156
- yield response
157
- end
158
- end
159
144
  end
160
145
  else
161
- if @persistent
162
- response = persistent_connection.request(uri, data)
146
+ verify_mode = @ignore_ssl ?
147
+ OpenSSL::SSL::VERIFY_NONE :
148
+ OpenSSL::SSL::VERIFY_PEER
149
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: verify_mode) do |http|
150
+ response = http.request(data)
163
151
  status_check!(response)
164
152
  return response
165
- else
166
- verify_mode = @ignore_ssl ?
167
- OpenSSL::SSL::VERIFY_NONE :
168
- OpenSSL::SSL::VERIFY_PEER
169
- Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: verify_mode) do |http|
170
- response = http.request(data)
171
- status_check!(response)
172
- return response
173
- end
174
153
  end
175
154
  end
176
155
  end
@@ -0,0 +1,39 @@
1
+ require 'base64'
2
+ require 'json'
3
+ require 'date'
4
+
5
+ module Etna
6
+ module Clients
7
+ class BaseClient
8
+ attr_reader :host, :token, :ignore_ssl
9
+ def initialize(host:, token:, ignore_ssl: false)
10
+ raise "#{self.class.name} client configuration is missing host." unless host
11
+ raise "#{self.class.name} client configuration is missing token." unless token
12
+
13
+ @token = token
14
+ raise "Your token is expired." if token_expired?
15
+
16
+ @etna_client = ::Etna::Client.new(
17
+ host,
18
+ token,
19
+ routes_available: false,
20
+ ignore_ssl: ignore_ssl)
21
+ @host = host
22
+ @ignore_ssl = ignore_ssl
23
+ end
24
+
25
+ def token_expired?
26
+ # Has the token already expired?
27
+ token_will_expire?(0)
28
+ end
29
+
30
+ def token_will_expire?(offset=3000)
31
+ # offset in seconds
32
+ # Will the user's token expire in the given amount of time?
33
+ epoch_seconds = JSON.parse(Base64.urlsafe_decode64(token.split('.')[1]))["exp"]
34
+ expiration = DateTime.strptime(epoch_seconds.to_s, "%s")
35
+ expiration <= DateTime.now.new_offset + offset
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,23 +1,12 @@
1
- require 'net/http/persistent'
2
1
  require 'net/http/post/multipart'
3
2
  require 'singleton'
4
3
  require_relative '../../client'
5
4
  require_relative './models'
5
+ require_relative '../base_client'
6
6
 
7
7
  module Etna
8
8
  module Clients
9
- class Janus
10
- def initialize(host:, token:, persistent: true, ignore_ssl: false)
11
- raise 'Janus client configuration is missing host.' unless host
12
- raise 'Janus client configuration is missing token.' unless token
13
- @etna_client = ::Etna::Client.new(
14
- host,
15
- token,
16
- routes_available: false,
17
- persistent: persistent,
18
- ignore_ssl: ignore_ssl)
19
- end
20
-
9
+ class Janus < Etna::Clients::BaseClient
21
10
  def get_project(get_project_request = GetProjectRequest.new)
22
11
  html = nil
23
12
  @etna_client.get(
@@ -1,11 +1,12 @@
1
1
  require 'ostruct'
2
2
  require_relative '../../json_serializable_struct'
3
+ require_relative '../base_client'
3
4
 
4
5
  # TODO: In the near future, I'd like to transition to specifying apis via SWAGGER and generating model stubs from the
5
6
  # common definitions. For nowe I've written them out by hand here.
6
7
  module Etna
7
8
  module Clients
8
- class Janus
9
+ class Janus < Etna::Clients::BaseClient
9
10
  class GetProjectRequest < Struct.new(:project_name, keyword_init: true)
10
11
  include JsonSerializableStruct
11
12
 
@@ -1,27 +1,12 @@
1
- require 'net/http/persistent'
2
1
  require 'net/http/post/multipart'
3
2
  require 'singleton'
3
+ require_relative '../base_client'
4
4
  require_relative '../../client'
5
5
  require_relative './models'
6
6
 
7
7
  module Etna
8
8
  module Clients
9
- class Magma
10
- attr_reader :host, :token, :ignore_ssl
11
- def initialize(host:, token:, persistent: true, ignore_ssl: false)
12
- raise 'Magma client configuration is missing host.' unless host
13
- raise 'Magma client configuration is missing token.' unless token
14
- @etna_client = ::Etna::Client.new(
15
- host,
16
- token,
17
- routes_available: false,
18
- persistent: persistent,
19
- ignore_ssl: ignore_ssl)
20
- @host = host
21
- @token = token
22
- @ignore_ssl = ignore_ssl
23
- end
24
-
9
+ class Magma < Etna::Clients::BaseClient
25
10
  # This endpoint returns models and records by name:
26
11
  # e.g. params:
27
12
  # {