dataverse-utils 0.25.2__tar.gz → 0.26.1__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.2 → dataverse_utils-0.26.1}/PKG-INFO +1 -1
  2. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/pyproject.toml +2 -1
  3. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/__init__.py +2 -1
  4. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/archive.py +1 -3
  5. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/collections.py +38 -35
  6. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/dataverse_utils.py +8 -3
  7. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/dvdata.py +31 -3
  8. dataverse_utils-0.26.1/src/dataverse_utils/scripts/dv_tree.py +61 -0
  9. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/LICENCE.md +0 -0
  10. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/README.md +0 -0
  11. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/data/LDC_EULA_general.md +0 -0
  12. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/ldc.py +0 -0
  13. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_bagit.py +0 -0
  14. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_bulk_release.py +0 -0
  15. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_collection_info.py +0 -0
  16. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_del.py +0 -0
  17. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_ldc_uploader.py +0 -0
  18. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_list_files.py +0 -0
  19. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_manifest_gen.py +0 -0
  20. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_pg_facet_date.py +0 -0
  21. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_readme_creator.py +0 -0
  22. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_record_copy.py +0 -0
  23. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_release.py +0 -0
  24. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_replace_licence.py +0 -0
  25. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_study_migrator.py +0 -0
  26. {dataverse_utils-0.25.2 → dataverse_utils-0.26.1}/src/dataverse_utils/scripts/dv_upload_tsv.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataverse-utils
3
- Version: 0.25.2
3
+ Version: 0.26.1
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.2"
3
+ version = "0.26.1"
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, 2)
10
+ VERSION = (0, 26, 1)
11
11
  __version__ = '.'.join([str(x) for x in VERSION])
12
12
 
13
13
  USERAGENT = (f'dataverse_utils/v{__version__} ({sys.platform.capitalize()}); '
@@ -28,6 +28,7 @@ SCRIPT_VERSIONS={
28
28
  'dv_replace_licence' : (0, 1, 1),
29
29
  'dv_readme_creator' : (0, 1, 1),
30
30
  'dv_study_migrator' : (0, 5, 0),
31
+ 'dv_tree' : (0, 2, 0),
31
32
  'dv_upload_tsv' : (0, 5, 0)}
32
33
 
33
34
  def script_ver_stmt(name:str)->str:
@@ -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
@@ -389,8 +389,11 @@ def upload_file(fpath, hdl, **kwargs): #pylint:disable=too-many-locals, too-many
389
389
  override : bool, optional
390
390
  Ignore NOTAB (ie, NOTAB = [])
391
391
 
392
- return_json: bool
392
+ return_json : bool
393
393
  Returns the JSON if you need it
394
+
395
+ print : bool
396
+ Print return JSON and file ID to console. Default = True
394
397
  '''
395
398
  #Why are SPSS files getting processed anyway?
396
399
  #Does SPSS detection happen *after* upload
@@ -434,7 +437,8 @@ def upload_file(fpath, hdl, **kwargs): #pylint:disable=too-many-locals, too-many
434
437
  params=params, headers=headers, data=multi,
435
438
  timeout=kwargs.get('timeout',1000))
436
439
  try:
437
- print(upload.json())
440
+ if kwargs.get('print', True):
441
+ print(upload.json())
438
442
  except json.decoder.JSONDecodeError as exc:
439
443
  #This can happend when Glassfish crashes
440
444
  LOGGER.critical(upload.text)
@@ -449,7 +453,8 @@ def upload_file(fpath, hdl, **kwargs): #pylint:disable=too-many-locals, too-many
449
453
  #SPSS files still process despite spoof, so there's
450
454
  #a forcible unlock check
451
455
  fid = upload.json()['data']['files'][0]['dataFile']['id']
452
- print(f'FID: {fid}')
456
+ if kwargs.get('print'):
457
+ print(f'FID: {fid}')
453
458
  if kwargs.get('nowait') and check_lock(dvurl, hdl, kwargs['apikey']):
454
459
  force_notab_unlock(hdl, dvurl, fid, kwargs['apikey'])
455
460
  else:
@@ -116,8 +116,12 @@ class Study(dict): #pylint: disable=too-few-public-methods
116
116
  self.fix_licence()
117
117
  if self['source_version'] < 5.013 <= self['target_version']:
118
118
  self.fix_production_location()
119
- if self['source_version'] < 5.014 <= self['target_version']:
119
+ if (self['source_version'] < 5.014 <= self['target_version']
120
+ and self['target_version'] < 6.001):
120
121
  self.fix_series()
122
+ if (self['source_version'] < 5.014 <= self['target_version']
123
+ and self['target_version'] >= 6.001):
124
+ self.fix_series(to_series=['series', 'alternativeTitle'])
121
125
  if self['source_version'] < 6.008 <= self['target_version']:
122
126
  self.fix_geography()
123
127
 
@@ -218,6 +222,8 @@ class Study(dict): #pylint: disable=too-few-public-methods
218
222
  if not self['upload_json']['datasetVersion']['termsOfUse']:
219
223
  #This shouldn't happen, but UBC has datasets from the early 1970s
220
224
  self['upload_json']['datasetVersion']['termsOfUse'] = 'Not available'
225
+ if self['upload_json']['datasetVersion']['license'] == 'CC0':
226
+ self['upload_json']['datasetVersion'].update(self.fix_cc0())
221
227
 
222
228
  def fix_production_location(self)->None:
223
229
  '''
@@ -249,11 +255,10 @@ class Study(dict): #pylint: disable=too-few-public-methods
249
255
  ['metadataBlocks']['citation']\
250
256
  ['fields'][indy]['value']]
251
257
 
252
- def fix_series(self)->None:
258
+ def fix_series(self, to_series=['series'])->None:
253
259
  '''
254
260
  Turn series into a multiple (as of v5.14)
255
261
  '''
256
- to_series=['series'] # typeNames which must be converted
257
262
  indices = []
258
263
  for ind, val in enumerate(self['upload_json']['datasetVersion']\
259
264
  ['metadataBlocks']['citation']['fields']):
@@ -290,6 +295,29 @@ class Study(dict): #pylint: disable=too-few-public-methods
290
295
  newval['value'].append(newcoord)
291
296
  newfields.append(newval)
292
297
  self['upload_json']['datasetVersion']['metadataBlocks']['geospatial']['fields'] = newfields
298
+
299
+ def fix_cc0(self)->None:
300
+ '''
301
+ Returns CC0 licence, post v5.10
302
+ '''
303
+
304
+ cc0='''<p>
305
+ <img src="https://licensebuttons.net/p/zero/1.0/88x31.png" title="Creative Commons CC0 1.0 Universal Public Domain Dedication. " style="display:none" onload="this.style.display='inline'" />
306
+ <a href="http://creativecommons.org/publicdomain/zero/1.0" title="Creative Commons CC0 1.0 Universal Public Domain Dedication. " target="_blank">CC0 1.0</a>
307
+ </p>'''
308
+ #minimal, uncomment if it becomes a problem
309
+ ccjson = {'license':{'name': 'CC0 1.0',
310
+ 'uri': 'http://creativecommons.org/publicdomain/zero/1.0'#,
311
+ #'iconUri': 'https://licensebuttons.net/p/zero/1.0/88x31.png',
312
+ #'rightsIdentifier': 'CC0-1.0',
313
+ #'rightsIdentifierScheme': 'SPDX',
314
+ #'schemeUri': 'https://spdx.org/licenses/',
315
+ #'languageCode': 'en'
316
+ },
317
+ 'termsOfUse': cc0
318
+ }
319
+ return ccjson
320
+
293
321
  ############
294
322
  #END FIXES
295
323
  ############
@@ -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():
46
+ '''
47
+ Obviously
48
+ '''
49
+ args = parse().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()