rda-python-miscs 3.0.2__py3-none-any.whl → 3.0.3__py3-none-any.whl

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.
@@ -33,15 +33,21 @@ class GdexCp(PgFile):
33
33
  'fp': None, # from Globus endpoint
34
34
  'tp': None, # to Globus endpoint
35
35
  'f': [], # from file names
36
+ 'i': None, # input file holding a list of from file names, one per line
36
37
  't': None, # to file name
37
38
  'r': 0, # 1 if recursive all
38
39
  'R': 0, # > 0 to set recursive limit
40
+ 'o': 0, # 1 to force a downloaded file owned by COMMONUSER; needs -fp
41
+ 'O': 0, # 1 to override an existing target file of the same size
42
+ 'm': 1, # number of multiple processes to copy files in parallel
43
+ 'd': 0, # 1 to add a dscheck record for delayed PBS batch process
39
44
  'F': 0o664, # to file mode, default to 664
40
45
  'D': 0o775, # to directory mode, default to 775
41
46
  }
42
47
  self.CINFO = {
43
48
  'tcnt': 0,
44
49
  'htcnt': 0,
50
+ 'pcnt': 0, # count of dispatched child processes for option -m
45
51
  'cpflag': 0, # 1 file only, 2 directory only, 3 both
46
52
  'cpstr': ['', 'Files', 'Directories', 'Files/Directories'],
47
53
  'fpath': None,
@@ -75,8 +81,8 @@ class GdexCp(PgFile):
75
81
  if ms:
76
82
  option = ms.group(1)
77
83
  if option not in self.RDACP: self.pglog(arg + ": Unknown Option", self.LGEREX)
78
- if option == 'r':
79
- self.RDACP['r'] = 1
84
+ if option in ('r', 'o', 'd', 'O'):
85
+ self.RDACP[option] = 1
80
86
  option = None
81
87
  continue
82
88
  if not option: self.pglog(arg + ": Value provided without option", self.LGEREX)
@@ -84,7 +90,7 @@ class GdexCp(PgFile):
84
90
  self.RDACP['f'].append(arg)
85
91
  defopt = None
86
92
  else:
87
- if option == 'R':
93
+ if option in ('R', 'm'):
88
94
  self.RDACP[option] = int(arg)
89
95
  elif option in 'FD':
90
96
  self.RDACP[option] = self.base2int(arg, 8)
@@ -95,8 +101,29 @@ class GdexCp(PgFile):
95
101
  elif option == 'fh':
96
102
  self.CINFO['fhost'] = arg + '-'
97
103
  option = defopt
104
+ if self.RDACP['i']: self.add_input_files(self.RDACP['i'])
98
105
  if dohelp or not self.RDACP['f']: self.show_usage("gdexcp")
99
-
106
+
107
+ # read source paths from an input file and append them to the -f list
108
+ def add_input_files(self, infile):
109
+ """Append source paths read from an input file to the -f source list.
110
+
111
+ Each non-empty line in the input file is treated as one source path;
112
+ leading/trailing whitespace is stripped and lines starting with '#' are
113
+ ignored as comments.
114
+
115
+ Args:
116
+ infile (str): Path to the input file holding one source path per line.
117
+ """
118
+ finfo = self.check_local_file(infile, 0, self.LGWNEX)
119
+ if not finfo: self.pglog("{}: Input file of -i not found".format(infile), self.LGEREX)
120
+ fd = open(infile, 'r')
121
+ for line in fd:
122
+ line = line.strip()
123
+ if not line or line[0] == '#': continue
124
+ self.RDACP['f'].append(line)
125
+ fd.close()
126
+
100
127
  # function to start actions
101
128
  def start_actions(self):
102
129
  """Validate copy targets, configure host/bucket/endpoint context, and dispatch copies.
@@ -132,7 +159,23 @@ class GdexCp(PgFile):
132
159
  self.PGLOG['BACKUPEP'] = self.RDACP['fp']
133
160
  elif self.RDACP['tp']:
134
161
  self.PGLOG['BACKUPEP'] = self.RDACP['tp']
162
+ if self.RDACP['o']:
163
+ if not self.RDACP['fp']:
164
+ self.pglog("-o: works only when source Globus endpoint -fp is provided", self.LGEREX)
165
+ if self.RDACP['th'] or self.RDACP['tp'] or self.RDACP['tb']:
166
+ self.pglog("-o: works only for downloading to local files (no -th/-tp/-tb)", self.LGEREX)
167
+ if self.RDACP['m'] < 1: self.RDACP['m'] = 1
168
+ if self.RDACP['m'] > 16:
169
+ self.pglog("-m {}: process count too large, capped at 16".format(self.RDACP['m']), self.LOGWRN)
170
+ self.RDACP['m'] = 16
171
+ if self.RDACP['d']:
172
+ self.add_delayed_check()
173
+ self.cmdlog()
174
+ return
175
+ if self.RDACP['m'] > 1:
176
+ self.start_none_daemon('gdexcp', '', self.PGLOG['CURUID'], self.RDACP['m'], 120)
135
177
  self.copy_top_list(self.RDACP['f'])
178
+ if self.RDACP['m'] > 1: self.check_child(None, 0, self.LOGWRN, 1)
136
179
  hinfo = ''
137
180
  if self.RDACP['fh']: hinfo += " From " + self.RDACP['fh']
138
181
  if self.RDACP['th']: hinfo += " To " + self.RDACP['th']
@@ -175,7 +218,7 @@ class GdexCp(PgFile):
175
218
  if not re.match(r'^/', file): file = self.join_paths(self.CINFO['curdir'], file)
176
219
  self.CINFO['fpath'] = (file if dosub else op.dirname(file)) + "/"
177
220
  if info['isfile']:
178
- self.CINFO['tcnt'] += self.copy_file(file, info['isfile'])
221
+ self.CINFO['tcnt'] += self.dispatch_copy(file, info)
179
222
  elif dosub or self.RDACP['R']:
180
223
  flist = self.gdex_glob(file, self.RDACP['fh'], 0, self.LGWNEX)
181
224
  if flist: self.copy_list(flist, 1, file)
@@ -197,7 +240,7 @@ class GdexCp(PgFile):
197
240
  fcnt = 0
198
241
  for file in tlist:
199
242
  if tlist[file]['isfile']:
200
- fcnt += self.copy_file(file, tlist[file]['isfile'])
243
+ fcnt += self.dispatch_copy(file, tlist[file])
201
244
  self.CINFO['cpflag'] |= (1 if tlist[file]['isfile'] else 2)
202
245
  elif level < self.RDACP['R']:
203
246
  flist = self.gdex_glob(file, self.RDACP['fh'], 0, self.LGWNEX)
@@ -206,20 +249,50 @@ class GdexCp(PgFile):
206
249
  self.pglog("{}{}: {} {} copied from directory".format(self.CINFO['fhost'], cdir, fcnt, self.CINFO['cpstr'][self.CINFO['cpflag']]), self.LOGWRN)
207
250
  self.CINFO['tcnt'] += fcnt
208
251
 
252
+ # copy one file, forking a child process when running with option -m
253
+ def dispatch_copy(self, fromfile, finfo):
254
+ """Copy one file, dispatching the copy to a child process when -m > 1.
255
+
256
+ With a single process (-m 1) the file is copied in line. With multiple
257
+ processes the copy is forked to a child via the PgSIG process pool (up to
258
+ RDACP['m'] children run concurrently); the parent records one dispatched
259
+ file and continues traversing, while each child performs the copy, logs
260
+ its own result, and exits.
261
+
262
+ Args:
263
+ fromfile (str): Absolute source file path.
264
+ finfo (dict): Source file-info dict (with 'isfile' and 'data_size').
265
+
266
+ Returns:
267
+ int: 1 if the file was copied (single process) or dispatched to a
268
+ child process (-m > 1), 0 otherwise.
269
+ """
270
+ if self.RDACP['m'] < 2: return self.copy_file(fromfile, finfo)
271
+ stat = self.start_child("gdexcp_{}".format(self.CINFO['pcnt']), self.LOGWRN, 1)
272
+ if stat <= 0: self.pglog("{}: cannot start child process to copy".format(fromfile), self.LGEREX)
273
+ if self.PGSIG['PPID'] > 1: # in child process
274
+ self.copy_file(fromfile, finfo)
275
+ sys.exit(0)
276
+ self.CINFO['pcnt'] += 1 # in parent process; child already dropped its DB link
277
+ return 1
278
+
209
279
  # copy one file
210
- def copy_file(self, fromfile, isfile):
280
+ def copy_file(self, fromfile, finfo):
211
281
  """Resolve the destination path for one source file and perform the copy.
212
282
 
213
283
  When a target directory is set (tpath), strips the source base path prefix
214
284
  and joins the remainder to tpath. Otherwise copies directly to the -t value.
285
+ Skips the copy when the target already exists with the same size as the
286
+ source, unless -O is given to override an existing same-size target.
215
287
 
216
288
  Args:
217
289
  fromfile (str): Absolute source file path.
218
- isfile (int): Non-zero when the source is a regular file (vs. a symlink type).
290
+ finfo (dict): Source file-info dict (with 'isfile' and 'data_size').
219
291
 
220
292
  Returns:
221
293
  int: 1 if the file was copied successfully, 0 otherwise.
222
294
  """
295
+ isfile = finfo['isfile']
223
296
  if self.CINFO['tpath']:
224
297
  fname = re.sub(r'^{}'.format(self.CINFO['fpath']), '', fromfile)
225
298
  if isfile:
@@ -228,7 +301,77 @@ class GdexCp(PgFile):
228
301
  tofile = self.CINFO['tpath'] + '/'
229
302
  else:
230
303
  tofile = self.RDACP['t']
231
- return (1 if self.copy_gdex_file(tofile, fromfile, self.RDACP['th'], self.RDACP['fh'], self.LGWNEX) else 0)
304
+ if isfile and not self.RDACP['O']:
305
+ tinfo = self.check_gdex_file(tofile, self.RDACP['th'], 0, self.LGWNEX)
306
+ if tinfo and tinfo['data_size'] == finfo['data_size']:
307
+ self.pglog("{}{}: Target exists with same size, skip copying".format(self.CINFO['thost'], tofile), self.LOGWRN)
308
+ return 0
309
+ if self.RDACP['o']: return self.force_owner_copy(tofile, fromfile)
310
+ logact = self.LGWNEX | (self.OVRIDE if self.RDACP['O'] else 0)
311
+ return (1 if self.copy_gdex_file(tofile, fromfile, self.RDACP['th'], self.RDACP['fh'], logact) else 0)
312
+
313
+ # copy one file from a Globus endpoint and force COMMONUSER ownership
314
+ def force_owner_copy(self, tofile, fromfile):
315
+ """Download a Globus file via a tmp file so the final copy is owned by COMMONUSER.
316
+
317
+ A Globus endpoint dumps the local file owned by the endpoint's mapped user
318
+ rather than COMMONUSER ('gdexdata'). This downloads to a tmp file under
319
+ PGLOG['TMPPATH'], makes it group readable/writable as its owner via the
320
+ pgstart_<user> setuid wrapper, then copies it locally so the final file is
321
+ owned by COMMONUSER, and removes the tmp file.
322
+
323
+ Args:
324
+ tofile (str): Final local destination path.
325
+ fromfile (str): Source file path on the Globus endpoint.
326
+
327
+ Returns:
328
+ int: 1 if the file was copied successfully, 0 otherwise.
329
+ """
330
+ tmpfile = self.join_paths(self.PGLOG['TMPPATH'], "{}.{}".format(op.basename(fromfile), os.getpid()))
331
+ if not self.copy_gdex_file(tmpfile, fromfile, self.RDACP['th'], self.RDACP['fh'], self.LGWNEX): return 0
332
+ finfo = self.check_local_file(tmpfile, 2, self.LGWNEX)
333
+ owner = finfo['logname'] if finfo else None
334
+ if owner and owner != self.PGLOG['COMMONUSER']:
335
+ self.pgsystem(self.get_local_command("chmod g+rw " + tmpfile, owner), self.LGWNEX)
336
+ ret = self.copy_gdex_file(tofile, tmpfile, self.RDACP['th'], None, self.LGWNEX)
337
+ self.delete_local_file(tmpfile, self.LGWNEX)
338
+ return (1 if ret else 0)
339
+
340
+ # add a dscheck record so this gdexcp command runs later as a PBS batch job
341
+ def add_delayed_check(self):
342
+ """Queue this gdexcp invocation as a delayed PBS batch job via a dscheck record.
343
+
344
+ Records the current command (with the -d flag stripped so the batch run
345
+ performs the actual copy) into the RDADB dscheck table for the dscheck
346
+ daemon to later submit to PBS through bashqsub/tcshqsub. The qsub resource
347
+ option always sets a 24 hour walltime; when -m > 1 it also reserves a single
348
+ node with (number of processes) cpus and 1gb of memory per cpu.
349
+ """
350
+ argv = [arg for arg in sys.argv[1:] if arg != '-d']
351
+ argstr = self.argv_to_string(argv, 1)
352
+ argextra = None
353
+ if len(argstr) > 100:
354
+ argextra = argstr[100:]
355
+ argstr = argstr[0:100]
356
+ record = {
357
+ 'command': 'gdexcp',
358
+ 'argv': argstr,
359
+ 'specialist': self.PGLOG['CURUID'],
360
+ 'workdir': self.CINFO['curdir'],
361
+ 'oindex': 0,
362
+ 'otype': '',
363
+ 'action': None,
364
+ 'dsid': None,
365
+ 'mcount': 1,
366
+ }
367
+ (record['date'], record['time']) = self.get_date_time()
368
+ if argextra: record['argextra'] = argextra
369
+ qoptions = "-l walltime=24:00:00"
370
+ if self.RDACP['m'] > 1:
371
+ qoptions += ",select=1:ncpus={0}:mem={0}gb".format(self.RDACP['m'])
372
+ record['qoptions'] = qoptions
373
+ cidx = self.pgadd("dscheck", record, self.LGWNEX|self.AUTOID)
374
+ self.pglog("Chk{}: gdexcp {} added for delayed batch process".format(cidx, argstr), self.LOGWRN)
232
375
 
233
376
  # main function to execute this script
234
377
  def main():
@@ -1,77 +1,145 @@
1
1
 
2
- Copy files and directories to a target location. Source and target may each
3
- reside on the local host, a remote host, an Object Store bucket, or a Globus
2
+ Name: gdexcp - copy files and directories as user 'gdexdata'
3
+
4
+ Copy files and directories to a target location. The source and the target may
5
+ each reside on the local host, a remote host, an Object Store bucket, or a Globus
4
6
  endpoint. Target files are owned by 'gdexdata' and created with configurable
5
7
  permission modes.
6
8
 
7
9
  Usage: gdexcp [-f] FromDirectories/Files [-t ToDirectory/FileName] \
10
+ [-i InputFile] [-m ProcessCount] [-d] [-r] [-R RecursiveLevel] \
8
11
  [-fh FromHostName] [-th ToHostName] \
9
12
  [-fb FromBucket] [-tb ToBucket] \
10
13
  [-fp FromGlobusEndpoint] [-tp ToGlobusEndpoint] \
11
- [-F FileMode] [-D DirectoryMode] [-r] [-R RecursiveLevel] [-h]
14
+ [-F FileMode] [-D DirectoryMode] [-o] [-O] [-h]
15
+
16
+ gdexcp can be run from any directory. Usage is displayed when no source paths
17
+ are given.
18
+
19
+
20
+ SOURCE AND TARGET
21
+
22
+ -f FromDirectories/Files
23
+ Source directories and/or files to copy. This is the default option,
24
+ so paths may be given without the -f flag. Shell wildcards are
25
+ supported; use './' or '*' to copy everything in the current directory.
26
+ A trailing '/' on a source directory path copies the contents of that
27
+ directory (as a file list) rather than the directory entry itself.
28
+ Source paths must be readable by user 'gdexdata'; gdexcp attempts to
29
+ fix the mode when they are not.
30
+
31
+ -i InputFile
32
+ A file holding a list of source paths to copy, one path per line.
33
+ Blank lines and lines starting with '#' are ignored. The paths read
34
+ are appended to the -f source list.
35
+
36
+ -t ToDirectory/FileName
37
+ Target directory or file name. Defaults to '.' (the current
38
+ directory). A trailing '/' forces the target to be treated as a
39
+ directory. Multiple source files cannot be copied to a single target
40
+ file name.
41
+
42
+
43
+ SOURCE/TARGET LOCATIONS (default to the local host)
44
+
45
+ -fh FromHostName host name where the source files reside.
46
+ -th ToHostName host name where the target files are written.
47
+ -fb FromBucket Object Store bucket name for the source files.
48
+ -tb ToBucket Object Store bucket name for the target files.
49
+ -fp FromGlobusEndpoint Globus endpoint for the source files.
50
+ -tp ToGlobusEndpoint Globus endpoint for the target files.
51
+
52
+
53
+ COPY BEHAVIOR
54
+
55
+ -r Copy directories and files recursively, with no depth limit.
56
+
57
+ -R RecursiveLevel
58
+ Copy recursively up to the given depth. -R 1 copies only the
59
+ immediate contents of each source directory.
60
+
61
+ -m ProcessCount
62
+ Number of processes used to copy files in parallel. Defaults to 1.
63
+ When greater than 1, the source files are distributed across that many
64
+ concurrent child processes. Capped at 16; a larger value is reduced to
65
+ 16 with a warning.
66
+
67
+ -d Add a dscheck record so this gdexcp command runs later as a delayed PBS
68
+ batch job (submitted by the dscheck daemon via bashqsub / tcshqsub).
69
+ The qsub resource always sets a 24 hour walltime; when -m is greater
70
+ than 1 it also reserves a single node with (ProcessCount) cpus and 1gb
71
+ of memory per cpu.
72
+
73
+ -o Force a downloaded file to be owned by 'gdexdata'. A Globus endpoint
74
+ writes the local file owned by the endpoint's mapped user; with -o the
75
+ file is downloaded to a tmp file, then copied locally so the final file
76
+ is owned by 'gdexdata'. Only valid together with -fp and for
77
+ downloading to local files (not with -th/-tp/-tb).
78
+
79
+ -O Override an existing target. By default a source file is skipped when
80
+ the target already exists with the same size; give -O to copy it anyway
81
+ and overwrite the existing target.
82
+
83
+
84
+ TARGET PERMISSIONS (octal notation)
12
85
 
13
- - Option -f, source directories and/or files to copy. This is the
14
- default option, so paths may be given without the -f flag.
15
- Shell wildcards are supported. Use './' or '*' to copy everything
16
- in the current directory. Source paths must be readable by user
17
- 'gdexdata'; gdexcp will attempt to fix the mode if they are not;
86
+ -F FileMode permission mode for target files. Defaults to 664.
87
+ -D DirectoryMode permission mode for target directories. Defaults to 775.
18
88
 
19
- - Option -t, target directory or file name. Defaults to '.' (current
20
- directory). Multiple source files cannot be copied to a single
21
- target file name. A trailing '/' on the target path treats it as
22
- a directory;
23
89
 
24
- - Option -fh, host name where the source files reside.
25
- Defaults to the local host;
90
+ MISCELLANEOUS
26
91
 
27
- - Option -th, host name where the target files should be written.
28
- Defaults to the local host;
92
+ -h Display this help document.
29
93
 
30
- - Option -fb, Object Store bucket name for the source files;
31
94
 
32
- - Option -tb, Object Store bucket name for the target files;
95
+ NOTES
33
96
 
34
- - Option -fp, Globus endpoint for the source files;
97
+ - A trailing '/' on a source directory path copies the contents of that
98
+ directory rather than the directory entry itself.
99
+ - By default an unchanged target (same size) is skipped; use -O to overwrite.
100
+ - If a Globus endpoint (-fp/-tp) is locally accessible, a direct local copy
101
+ (omitting -fp/-tp and giving the local path) is faster, avoiding the Globus
102
+ transfer overhead.
103
+ - A delayed batch job (-d) is given a 24 hour walltime. Do not submit a single
104
+ batch job to copy too many files at once; if the copy cannot finish within 24
105
+ hours the job is killed. Split a very large copy into multiple -d jobs (and/or
106
+ raise -m) so each one completes well within the walltime.
35
107
 
36
- - Option -tp, Globus endpoint for the target files;
37
108
 
38
- - Option -F, permission mode for target files in octal notation.
39
- Defaults to 664;
109
+ EXAMPLES
40
110
 
41
- - Option -D, permission mode for target directories in octal notation.
42
- Defaults to 775;
111
+ 1. Copy all files and subdirectories under the current directory to a remote
112
+ host:
43
113
 
44
- - Option -r, copy directories and files recursively (no depth limit);
114
+ gdexcp -r -f * -t /PathTo/d277006/ -th castle
45
115
 
46
- - Option -R RecursiveLevel, copy recursively up to the specified depth.
47
- -R 1 copies only the immediate contents of each source directory;
116
+ 2. Copy the contents of a local directory to a remote location (trailing '/'
117
+ on the source omits the directory entry itself):
48
118
 
49
- - Option -h, display this help document;
119
+ gdexcp -r -f /PathTo/DirectoryName/ -t /PathTo/d277006/ -th castle
50
120
 
51
- This utility can be run from any directory. Usage is displayed if no source
52
- files are provided. A trailing '/' on a source directory path copies the
53
- contents of that directory rather than the directory entry itself.
121
+ Without the trailing '/', DirectoryName itself is also copied:
54
122
 
55
- Examples:
123
+ gdexcp -r -f /PathTo/DirectoryName -t /PathTo/d277006/ -th castle
56
124
 
57
- 1. Copy all files and subdirectories under the current directory to a
58
- remote host:
125
+ 3. Copy a single file to an Object Store bucket:
59
126
 
60
- gdexcp -r -f * -t /PathTo/d277006/ -th castle
127
+ gdexcp -f /PathTo/myfile.nc -tb my-bucket -t myfile.nc
61
128
 
62
- 2. Copy the contents of a specific local directory to a remote location
63
- (trailing '/' on source omits the directory entry itself):
129
+ 4. Copy files from a remote host to the local current directory:
64
130
 
65
- gdexcp -r -f /PathTo/DirectoryName/ -t /PathTo/d277006/ -th castle
131
+ gdexcp -fh castle -f /PathTo/d277006/myfile.nc
66
132
 
67
- Without the trailing '/', DirectoryName itself is also copied:
133
+ 5. Download a file from a source Globus endpoint and force the local file to
134
+ be owned by 'gdexdata' (-o requires -fp):
68
135
 
69
- gdexcp -r -f /PathTo/DirectoryName -t /PathTo/d277006/ -th castle
136
+ gdexcp -fp gdex-quasar -f /d277006/myfile.nc -t /PathTo/myfile.nc -o
70
137
 
71
- 3. Copy a single file to an Object Store bucket:
138
+ 6. Copy the source paths listed in an input file using 4 parallel processes:
72
139
 
73
- gdexcp -f /PathTo/myfile.nc -tb my-bucket -t myfile.nc
140
+ gdexcp -i filelist.txt -t /PathTo/d277006/ -m 4
74
141
 
75
- 4. Copy files from a remote host to the local current directory:
142
+ 7. Queue a delayed PBS batch job to copy a directory in parallel; the dscheck
143
+ daemon submits it later, reserving one node with 4 cpus and 4gb of memory:
76
144
 
77
- gdexcp -fh castle -f /PathTo/d277006/myfile.nc
145
+ gdexcp -r -f /PathTo/DirectoryName/ -t /PathTo/d277006/ -m 4 -d
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rda_python_miscs
3
- Version: 3.0.2
3
+ Version: 3.0.3
4
4
  Summary: RDA Python package to hold RDA miscellaneous utility programs
5
5
  Author-email: Zaihua Ji <zji@ucar.edu>
6
6
  Project-URL: Homepage, https://github.com/NCAR/rda-python-miscs
@@ -3,8 +3,8 @@ rda_python_miscs/bash_qsub.py,sha256=NsYg1A7zeRy3mR_rAaJEQoWSDaWFxE7cpHNc4mA_JwA
3
3
  rda_python_miscs/bashqsub.py,sha256=SadPwz1ZXHx2zGNYb2VityItQjMEYj-Favq3xDrPBK0,10127
4
4
  rda_python_miscs/bashqsub.usg,sha256=QDaFr1FiQ-5FC9UzCRQ0geYjsPXBnVMhe3lM8qH1xss,2176
5
5
  rda_python_miscs/gdex_ls.py,sha256=fg9jfYajOT8ps6eEhFUUqmQ791BdGwBkrT_pyjmGGvQ,8860
6
- rda_python_miscs/gdexcp.py,sha256=b8ZJspBKDP_u8nH15eWkwI0CSABLSX0MzPw2CVyFJYY,10933
7
- rda_python_miscs/gdexcp.usg,sha256=O-qXc6vMvojEmBWQIqns1pntI2AqxPB4d7LJw4AqV6M,3197
6
+ rda_python_miscs/gdexcp.py,sha256=jCkDzNrZhi7vhZqeSXHR7d1XIKtsionSJE5ntWoZE0g,18110
7
+ rda_python_miscs/gdexcp.usg,sha256=6r8XVi9inPuWuFth6CAzcd3EpXX4Y_ZrT6YubmQ82kM,6172
8
8
  rda_python_miscs/gdexkill.py,sha256=sWa5MCBXvDpN-5iqVBLNrfO8og1vZMZhu7HlCR9c7bI,11607
9
9
  rda_python_miscs/gdexkill.usg,sha256=ptx_1GuFNI9ISi4mjMVTc4aDj9J4JpMG0gvzKbhDJqA,2459
10
10
  rda_python_miscs/gdexls.py,sha256=Z-iB3nC0zUm2fOUIkhpZd_N82j-5WPRbjDcmGKTRGhY,14396
@@ -40,9 +40,9 @@ rda_python_miscs/tcshqsub.py,sha256=QxBq9MdVIUs9t2d6vHhkxM1nrcLwRNqcq1lJiWhXKUM,
40
40
  rda_python_miscs/tcshqsub.usg,sha256=JYfhrK7cqme-Sij_JfquONOs3HMu-d5dDGI9K_RdudU,2180
41
41
  rda_python_miscs/rst_templates/index.rst.temp,sha256=YSa1JM6X9x2SC6UiqJu_9xRrVYGLKwNI43DBJEGDX08,523
42
42
  rda_python_miscs/rst_templates/section.rst.temp,sha256=-CUtutvctG2tIdkqrkFxVEzmNN3atRJXBDQaTnMJ6Gw,572
43
- rda_python_miscs-3.0.2.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
44
- rda_python_miscs-3.0.2.dist-info/METADATA,sha256=2rjjjAkl_aCtq1tCb880gu1r2oHlZCEy5iLKRg2IpRc,5803
45
- rda_python_miscs-3.0.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
46
- rda_python_miscs-3.0.2.dist-info/entry_points.txt,sha256=pBgb-_g4yZhm6YynwDHtNTAzxVrb8SoDMd7Eiys8gv4,806
47
- rda_python_miscs-3.0.2.dist-info/top_level.txt,sha256=W5rz7DrWb7hXABUbGgWcwe6D644X338LR8_zdgmtLhg,17
48
- rda_python_miscs-3.0.2.dist-info/RECORD,,
43
+ rda_python_miscs-3.0.3.dist-info/licenses/LICENSE,sha256=1dck4EAQwv8QweDWCXDx-4Or0S8YwiCstaso_H57Pno,1097
44
+ rda_python_miscs-3.0.3.dist-info/METADATA,sha256=b4yrhKT1F_QySBljOiOujWrWLMStJO0Vymjx8dO47f4,5803
45
+ rda_python_miscs-3.0.3.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
46
+ rda_python_miscs-3.0.3.dist-info/entry_points.txt,sha256=pBgb-_g4yZhm6YynwDHtNTAzxVrb8SoDMd7Eiys8gv4,806
47
+ rda_python_miscs-3.0.3.dist-info/top_level.txt,sha256=W5rz7DrWb7hXABUbGgWcwe6D644X338LR8_zdgmtLhg,17
48
+ rda_python_miscs-3.0.3.dist-info/RECORD,,