dataverse-utils 0.25.3__tar.gz → 0.26.2__tar.gz

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.
Files changed (26) hide show
  1. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/PKG-INFO +1 -1
  2. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/pyproject.toml +2 -1
  3. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/__init__.py +16 -15
  4. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/archive.py +1 -3
  5. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/collections.py +38 -35
  6. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_bagit.py +2 -2
  7. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_bulk_release.py +2 -2
  8. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_collection_info.py +2 -2
  9. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_del.py +2 -2
  10. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_ldc_uploader.py +2 -3
  11. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_list_files.py +2 -2
  12. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_manifest_gen.py +3 -3
  13. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_pg_facet_date.py +2 -3
  14. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_readme_creator.py +2 -2
  15. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_record_copy.py +2 -3
  16. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_release.py +2 -3
  17. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_replace_licence.py +2 -3
  18. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_study_migrator.py +2 -2
  19. dataverse_utils-0.26.2/src/dataverse_utils/scripts/dv_tree.py +61 -0
  20. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/scripts/dv_upload_tsv.py +2 -3
  21. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/LICENCE.md +0 -0
  22. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/README.md +0 -0
  23. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/data/LDC_EULA_general.md +0 -0
  24. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/dataverse_utils.py +0 -0
  25. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/dvdata.py +0 -0
  26. {dataverse_utils-0.25.3 → dataverse_utils-0.26.2}/src/dataverse_utils/ldc.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataverse-utils
3
- Version: 0.25.3
3
+ Version: 0.26.2
4
4
  Summary: Utilities for the Dataverse data respository system
5
5
  License: MIT
6
6
  License-File: LICENCE.md
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dataverse-utils"
3
- version = "0.25.3"
3
+ version = "0.26.2"
4
4
  description = "Utilities for the Dataverse data respository system"
5
5
  authors = [
6
6
  {name = "Paul Lesack",email = "paul.lesack@ubc.ca"}
@@ -61,6 +61,7 @@ dv_release = 'dataverse_utils.scripts.dv_release:main'
61
61
  dv_replace_licence = 'dataverse_utils.scripts.dv_replace_licence:main'
62
62
  dv_replace_license = 'dataverse_utils.scripts.dv_replace_licence:main'
63
63
  dv_study_migrator = 'dataverse_utils.scripts.dv_study_migrator:main'
64
+ dv_tree = 'dataverse_utils.scripts.dv_tree:main'
64
65
  dv_upload_tsv = 'dataverse_utils.scripts.dv_upload_tsv:main'
65
66
 
66
67
  [project.urls]
@@ -7,7 +7,7 @@ import pathlib
7
7
  import sys
8
8
  from dataverse_utils.dataverse_utils import *
9
9
 
10
- VERSION = (0, 25, 3)
10
+ VERSION = (0, 26, 2)
11
11
  __version__ = '.'.join([str(x) for x in VERSION])
12
12
 
13
13
  USERAGENT = (f'dataverse_utils/v{__version__} ({sys.platform.capitalize()}); '
@@ -15,20 +15,21 @@ USERAGENT = (f'dataverse_utils/v{__version__} ({sys.platform.capitalize()}); '
15
15
  UAHEADER = {'User-agent' : USERAGENT}
16
16
 
17
17
  SCRIPT_VERSIONS={
18
- 'dv_bagit' : (0, 1, 0),
19
- 'dv_bulk_release' : (0, 1, 0),
20
- 'dv_collection_info' : (0, 6, 0),
21
- 'dv_del' : (0, 2, 4),
22
- 'dv_ldc_uploader' : (0, 4, 1),
23
- 'dv_list_files' : (0, 1, 1),
24
- 'dv_manifest_gen' : (0, 5, 1),
25
- 'dv_pg_facet_date' : (0, 1, 1),
26
- 'dv_record_copy' : (0, 1, 2),
27
- 'dv_release' : (0, 1, 3),
28
- 'dv_replace_licence' : (0, 1, 1),
29
- 'dv_readme_creator' : (0, 1, 1),
30
- 'dv_study_migrator' : (0, 5, 0),
31
- 'dv_upload_tsv' : (0, 5, 0)}
18
+ 'dv_bagit' : (0, 1, 1),
19
+ 'dv_bulk_release' : (0, 1, 1),
20
+ 'dv_collection_info' : (0, 6, 1),
21
+ 'dv_del' : (0, 2, 5),
22
+ 'dv_ldc_uploader' : (0, 4, 2),
23
+ 'dv_list_files' : (0, 1, 2),
24
+ 'dv_manifest_gen' : (0, 5, 2),
25
+ 'dv_pg_facet_date' : (0, 1, 2),
26
+ 'dv_record_copy' : (0, 1, 3),
27
+ 'dv_release' : (0, 1, 4),
28
+ 'dv_replace_licence' : (0, 1, 2),
29
+ 'dv_readme_creator' : (0, 1, 2),
30
+ 'dv_study_migrator' : (0, 5, 1),
31
+ 'dv_tree' : (0, 2, 1),
32
+ 'dv_upload_tsv' : (0, 5, 1)}
32
33
 
33
34
  def script_ver_stmt(name:str)->str:
34
35
  '''
@@ -197,8 +197,6 @@ class Archive:
197
197
  Hash type. Supported hashes: 'sha1', 'sha224', 'sha256',
198
198
  'sha384','sha512', 'blake2b', 'blake2s', 'md5'.
199
199
  default='md5'
200
- blocksize : int
201
- Read block size in bytes
202
200
  '''
203
201
  ok_hash = {'sha1' : hashlib.sha1(),
204
202
  'sha224' : hashlib.sha224(),
@@ -208,7 +206,7 @@ class Archive:
208
206
  'blake2b' : hashlib.blake2b(),
209
207
  'blake2s' : hashlib.blake2s(),
210
208
  'md5': hashlib.md5()}
211
- #blocksize: int = 2**16
209
+ #blocksize : int = 2**16
212
210
  #fobj.seek(0)
213
211
  try:
214
212
  _hash = ok_hash[prot]
@@ -70,7 +70,7 @@ class RateLimiter:
70
70
 
71
71
  Other parameters
72
72
  ----------------
73
- rate_limit_on: bool
73
+ rate_limit_on : bool
74
74
  Turn on rate limit for requests
75
75
 
76
76
  rate_limit_min : int
@@ -131,7 +131,7 @@ class DvCollection:
131
131
  timeout : int
132
132
  retry timeout in seconds
133
133
 
134
- rate_limit_on: bool
134
+ rate_limit_on : bool
135
135
  Turn on rate limit for requests
136
136
 
137
137
  rate_limit_min : int
@@ -312,7 +312,7 @@ class DvCollection:
312
312
  self.walk(subp[1], path, output)
313
313
  return output
314
314
 
315
- def tree(self, dvtree:list=None)->io.StringIO: #pylint:disable=too-many-locals
315
+ def tree(self, dvtree:list=None, show_pids=True)->io.StringIO: #pylint:disable=too-many-locals, too-many-branches
316
316
  '''
317
317
  Outputs the collection tree as StringIO object.
318
318
  Perfect for your printing needs.
@@ -322,6 +322,9 @@ class DvCollection:
322
322
  dvtree : list
323
323
  List of tuples from self.walk. Default of None results
324
324
  in self.walk being called
325
+ show_pids : bool
326
+ Show studies in tree, ie. display the pids. If False,
327
+ will display a tree of collections only
325
328
  '''
326
329
  dvtree = dvtree if dvtree else self.walk()
327
330
  outtree = io.StringIO()
@@ -355,32 +358,30 @@ class DvCollection:
355
358
  end = ''
356
359
  line = start + middle + end + _[0].split('/')[-1] + '\n'
357
360
  outtree.write(line)
358
- #breakpoint()
359
- for n, dd in enumerate(_[2]):
360
- # For some reason putting this in a comprehension doesn't work
361
- val = _[0].split('/')[-1]
362
- tmp = [_ for _ in tree_info if val in _]
363
- lastcount = 0
364
- if max(len(x) for x in tmp) >1:
365
- tmp2 = '/'.join(tmp[0][:-1])
366
- lastcount = max(n for n,_ in enumerate(tree_info) if tmp2 in '/'.join(_))
367
- prefix_length = len(_[0].split('/'))-1
368
- mid2 = (b + t4)* prefix_length
369
- if num == lastcount and lastcount:
370
- where = mid2.rfind(b)
371
- mid2 = list(mid2)
372
- mid2[where] = ' '
373
- mid2 = ''.join(mid2)
374
- if n+1 != len(_[2]):
375
- indicator = t
376
- elif _[1]:
377
- indicator = t
378
- else: indicator = e
379
-
380
- #if 'UBC_stem_jobs' in _[0]:
381
- # breakpoint()
382
- fileline = mid2 + indicator + dd + '\n'
383
- outtree.write( fileline)
361
+ if show_pids:
362
+ for n, dd in enumerate(_[2]):
363
+ # For some reason putting this in a comprehension doesn't work
364
+ val = _[0].split('/')[-1]
365
+ tmp = [_ for _ in tree_info if val in _]
366
+ lastcount = 0
367
+ if max(len(x) for x in tmp) >1:
368
+ tmp2 = '/'.join(tmp[0][:-1])
369
+ lastcount = max(n for n,_ in enumerate(tree_info) if tmp2 in '/'.join(_))
370
+ prefix_length = len(_[0].split('/'))-1
371
+ mid2 = (b + t4)* prefix_length
372
+ if num == lastcount and lastcount:
373
+ where = mid2.rfind(b)
374
+ mid2 = list(mid2)
375
+ mid2[where] = ' '
376
+ mid2 = ''.join(mid2)
377
+ if n+1 != len(_[2]):
378
+ indicator = t
379
+ elif _[1]:
380
+ indicator = t
381
+ else: indicator = e
382
+
383
+ fileline = mid2 + indicator + dd + '\n'
384
+ outtree.write(fileline)
384
385
  outtree.seek(0)
385
386
  return outtree
386
387
 
@@ -471,7 +472,7 @@ class StudyMetadata(dict):
471
472
  #pylint: disable=too-many-instance-attributes
472
473
  def __init__(self, **kwargs):
473
474
  '''
474
- Intializize a StudyMetadata object.
475
+ Intialize a StudyMetadata object.
475
476
 
476
477
  Parameters
477
478
  ----------
@@ -493,7 +494,7 @@ class StudyMetadata(dict):
493
494
  key : str
494
495
  Dataverse instance API key (needed for unpublished studies)
495
496
 
496
- rate_limit_on: bool
497
+ rate_limit_on : bool
497
498
  Turn on rate limit for requests
498
499
 
499
500
  rate_limit_min : int
@@ -833,11 +834,13 @@ class StudyMetadata(dict):
833
834
  Parameters
834
835
  ----------
835
836
  filelist : list
836
- List containing file level metadata. Typically ['data']['latestVersion']['files']
837
- or similar
837
+ List containing file level metadata.
838
+ Typically found in:
839
+ self.study_meta['data']['latestVersion']['files'] or similar
838
840
 
839
841
  Notes
840
- -----
842
+ -----
843
+
841
844
  Will attach the study pid to the file list for easier joining
842
845
  '''
843
846
 
@@ -1366,7 +1369,7 @@ class FileAnalysis(dict):
1366
1369
  filesize_bytes : int
1367
1370
  File size in bytes
1368
1371
 
1369
- rate_limit_on: bool
1372
+ rate_limit_on : bool
1370
1373
  Turn on rate limit for requests
1371
1374
 
1372
1375
  rate_limit_min : int
@@ -55,11 +55,11 @@ def parse()->argparse.ArgumentParser:
55
55
  nargs='+')
56
56
  return parser
57
57
 
58
- def main():
58
+ def main(par=None):
59
59
  '''
60
60
  Create a bag
61
61
  '''
62
- args = parse().parse_args()
62
+ args = parse().parse_args() if not par else par().parse_args()
63
63
  for pid in tqdm.tqdm(args.pids,
64
64
  desc='Studies',
65
65
  unit='study',
@@ -137,11 +137,11 @@ def make_header(key:str)->dict:
137
137
  out.update(dataverse_utils.UAHEADER)
138
138
  return out
139
139
 
140
- def main():
140
+ def main(par:argparse.ArgumentParser=None):
141
141
  '''
142
142
  Command line bulk deleter
143
143
  '''
144
- args = parsley().parse_args()
144
+ args = parsley().parse_args() if not par else par().parse_args()
145
145
  args.majmin = args.majmin.lower()
146
146
  args.dvurl = args.dvurl.strip('/')
147
147
 
@@ -641,12 +641,12 @@ def clean_filename(args):
641
641
  instr = instr[:-len(suff)]
642
642
  return instr
643
643
 
644
- def main():
644
+ def main(par:argparse.ArgumentParser=None):
645
645
  '''
646
646
  Replacement
647
647
  '''
648
648
  #pylint: disable=too-many-branches, too-many-locals, too-many-statements
649
- args = parse().parse_args()
649
+ args = parse().parse_args() if not par else par().parse_args()
650
650
  logger = logme(args)
651
651
  args.output = clean_filename(args)
652
652
  dbase_file = pathlib.Path(args.output+extension(args)).expanduser()\
@@ -108,11 +108,11 @@ def make_header(key:str)->dict:
108
108
  out.update(dataverse_utils.UAHEADER)
109
109
  return out
110
110
 
111
- def main():
111
+ def main(par:argparse.ArgumentParser=None):
112
112
  '''
113
113
  Command line bulk deleter
114
114
  '''
115
- args = parsley().parse_args()
115
+ args = parsley().parse_args() if not par else par().parse_args()
116
116
  args.dvurl = args.dvurl.strip('/')
117
117
 
118
118
  if args.dataverse:
@@ -96,12 +96,11 @@ def upload_meta(ldccat: str, url: str, key: str,#pylint: disable = too-many-argu
96
96
  info = stud.upload_metadata(url=url, key=key, dv=dvs)
97
97
  return info['data']['persistentId']
98
98
 
99
- def main() -> None:
99
+ def main(par:argparse.ArgumentParser=None) -> None:
100
100
  '''
101
101
  Uploads metadata and data to Dataverse collection/study respectively
102
102
  '''
103
- parser = parse()
104
- args = parser.parse_args()
103
+ args = parse().parse_args() if not par else par().parse_args()
105
104
  dc_config = dc.Config()
106
105
  contact_info={'dv_contact_name' : args.cname,
107
106
  'dv_contact_email' : args.email}
@@ -50,13 +50,13 @@ def parse() -> argparse.ArgumentParser():
50
50
  help='Show version number and exit')
51
51
  return parser
52
52
 
53
- def main()->None:
53
+ def main(par:argparse.ArgumentParser=None)->None:
54
54
  '''
55
55
  The primary function
56
56
  '''
57
57
  sepchar = {'tsv' : '\t',
58
58
  'csv' : ','}
59
- args = parse().parse_args()
59
+ args = parse().parse_args() if not par else par().parse_args()
60
60
  if not args.url.lower().startswith('http'):
61
61
  args.url = f'https://{args.url}'
62
62
  output = io.StringIO(newline='')
@@ -93,12 +93,12 @@ def quotype(quote: str)-> int:
93
93
  'none' : 3}
94
94
  return vals.get(quote.lower(), -1)
95
95
 
96
- def main() -> None:
96
+ def main(par:argparse.ArgumentParser=None) -> None:
97
97
  '''
98
98
  The main function call
99
99
  '''
100
- parser = parse()
101
- args = parser.parse_args()
100
+ parser = par.parse() if par else parse()
101
+ args = parse().parse_args() if not par else par().parse_args()
102
102
  args.quote = quotype(args.quote)
103
103
  if args.quote == -1:
104
104
  parser.error('Invalid quotation type')
@@ -206,12 +206,11 @@ def reindex(pid) -> dict:
206
206
  reind = requests.get(req, timeout=30)
207
207
  return reind.json()
208
208
 
209
- def main():
209
+ def main(par:argparse.ArgumentParser=None):
210
210
  '''
211
211
  The heart of the application
212
212
  '''
213
- parser = parsely()
214
- args = parser.parse_args()
213
+ args = parsely().parse_args() if not par else par().parse_args()
215
214
  args.url = args.url.strip(' /')
216
215
  #import sys
217
216
  #print(args)
@@ -75,11 +75,11 @@ def valid_outfile(infil:str)->bool:
75
75
  return False
76
76
  return whar.parent.expanduser().absolute().exists()
77
77
 
78
- def main():
78
+ def main(par:argparse.ArgumentParser=None):
79
79
  '''
80
80
  You know what this is
81
81
  '''
82
- args = parse().parse_args()
82
+ args = parse().parse_args() if not par else par().parse_args()
83
83
 
84
84
  verify = {args.pid: (valid_pid,
85
85
  'Invalid PID. PIDs begin with hdl: or doi: '
@@ -95,12 +95,11 @@ def _output_json(injson : dict)->dict:
95
95
  }
96
96
  }
97
97
 
98
- def main():
98
+ def main(par:argparse.ArgumentParser=None):
99
99
  '''
100
100
  You know what this does
101
101
  '''
102
- parser = parsley()
103
- args = parser.parse_args()
102
+ args = parsley().parse_args() if not par else par().parse_args()
104
103
  args.url = args.url.strip('/ ')
105
104
  record = _download_original(args.url, args.pid, args.key)
106
105
  if args.collection:
@@ -198,13 +198,12 @@ class Study():
198
198
  if self.verbose:
199
199
  print(f'Released: {self.dvurl}/dataset.xhtml?persistentId={self.pid}')
200
200
 
201
- def main():
201
+ def main(par:argparse.ArgumentParser=None):
202
202
  '''
203
203
  The primary function. Will release all unreleased studies in the
204
204
  the target Dataverse collection, or selected studies as required.
205
205
  '''
206
- parser = argp()
207
- args = parser.parse_args()
206
+ args = argp().parse_args() if not par else par().parse_args()
208
207
  if args.dv:
209
208
  the_dv = Dverse(args.url, args.key, args.dv)
210
209
  un_rel = the_dv.unreleased()
@@ -115,12 +115,11 @@ def print_stat(rjson):
115
115
  print(rjson.get('data',''))
116
116
  print(rjson.get('message',''))
117
117
 
118
- def main():
118
+ def main(par:argparse.ArgumentParser=None):
119
119
  '''
120
120
  Main script function
121
121
  '''
122
- parse = parsley()
123
- args = parse.parse_args()
122
+ args = parsley().parse_args() if not par else par().parse_args()
124
123
  args.url = args.url.strip('/ ')
125
124
  with open(args.lic, encoding='utf-8') as fil:
126
125
  newlic = fil.read()
@@ -182,11 +182,11 @@ def remove_target_files(record:dataverse_utils.dvdata.Study, timeout:int=100, lo
182
182
  file = sys.stderr)
183
183
  sys.exit()
184
184
 
185
- def main():
185
+ def main(par:argparse.ArgumentParser=None):
186
186
  '''
187
187
  Run this, obviously
188
188
  '''
189
- args = parsley().parse_args()
189
+ args = parsley().parse_args() if not par else par().parse_args()
190
190
  args.source_url = args.source_url.strip('/ ')
191
191
  args.target_url = args.target_url.strip('/ ')
192
192
  target_headers={'X-Dataverse-key': args.target_key}
@@ -0,0 +1,61 @@
1
+ '''
2
+ Dataverse collection tree view
3
+ '''
4
+
5
+ import argparse
6
+ import sys
7
+ import textwrap
8
+ import dataverse_utils as du
9
+ import dataverse_utils.collections as dvc
10
+
11
+ def parse()->argparse.ArgumentParser:
12
+ '''
13
+ Argument parser
14
+ '''
15
+ description = textwrap.fill(textwrap.dedent(
16
+ '''
17
+ Produce a tree view of collection, given a top-level collection.
18
+ Outputs studies and collections in a view similar to that
19
+ of the **tree** command. Like **tree**, prints to terminal.
20
+
21
+ To save to a file, use a redirect, ie ">".
22
+ '''))
23
+
24
+ parser = argparse.ArgumentParser(description=description)
25
+ parser.add_argument('-u', '--url',
26
+ default='https://borealisdata.ca',
27
+ help=('URL of Dataverse instance. Default: '
28
+ 'https://borealisdata.ca'))
29
+ parser.add_argument('-k', '--key',
30
+ help='API key',
31
+ required=True)
32
+ parser.add_argument('-n', '--nopids',
33
+ help='Suppress PIDs and show only a *collection* tree',
34
+ action='store_true')
35
+ parser.add_argument('collection',
36
+ help='Dataverse short name of collection to traverse',
37
+ nargs='?')
38
+ parser.add_argument('-v', '--version',
39
+ action='version',
40
+ version=du.script_ver_stmt(parser.prog),
41
+ help='Show version number and exit')
42
+
43
+ return parser
44
+
45
+ def main(par:argparse.ArgumentParser=None):
46
+ '''
47
+ Obviously
48
+ '''
49
+ args = parse().parse_args() if not par else par().parse_args()
50
+ if not args.collection:
51
+ sys.exit()
52
+ try:
53
+ top = dvc.DvCollection(url=args.url, coll=args.collection, key=args.key)
54
+ tree = top.tree(show_pids=not args.nopids)
55
+ print(tree.read(), file=sys.stdout)
56
+ except (KeyError, ValueError, IndexError, dvc.requests.exceptions.HTTPError) as exc:
57
+ print(f'Error {exc}', file=sys.stderr)
58
+ sys.exit()
59
+
60
+ if __name__ == '__main__':
61
+ main()
@@ -78,12 +78,11 @@ def parse() -> argparse.ArgumentParser():
78
78
  help='Show version number and exit')
79
79
  return parser
80
80
 
81
- def main() -> None:
81
+ def main(par:argparse.ArgumentParser=None) -> None:
82
82
  '''
83
83
  Uploads data to an already existing Dataverse study
84
84
  '''
85
- parser = parse()
86
- args = parser.parse_args()
85
+ args = parse().parse_args() if not par else par().parse_args()
87
86
  if not args.nc and not args.rest:
88
87
  conf = input('File(s) will be unrestricted. Continue (y/n)? ')
89
88
  if conf.lower() == 'n' or conf.lower() == 'no':