copyparty 1.8.0__py3-none-any.whl → 1.8.1__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.
copyparty/__main__.py CHANGED
@@ -522,6 +522,50 @@ def get_sects():
522
522
  ).rstrip()
523
523
  + build_flags_desc(),
524
524
  ],
525
+ [
526
+ "handlers",
527
+ "use plugins to handle certain events",
528
+ dedent(
529
+ """
530
+ usually copyparty returns a \033[33m404\033[0m if a file does not exist, and
531
+ \033[33m403\033[0m if a user tries to access a file they don't have access to
532
+
533
+ you can load a plugin which will be invoked right before this
534
+ happens, and the plugin can choose to override this behavior
535
+
536
+ load the plugin using --args or volflags; for example \033[36m
537
+ --on404 ~/partyhandlers/not404.py
538
+ -v .::r:c,on404=~/partyhandlers/not404.py
539
+ \033[0m
540
+ the file must define the function \033[35mmain(cli,vn,rem)\033[0m:
541
+ \033[35mcli\033[0m: the copyparty HttpCli instance
542
+ \033[35mvn\033[0m: the VFS which overlaps with the requested URL
543
+ \033[35mrem\033[0m: the remainder of the URL below the VFS mountpoint
544
+
545
+ `main` must return a string; one of the following:
546
+
547
+ > \033[32m"true"\033[0m: the plugin has responded to the request,
548
+ and the TCP connection should be kept open
549
+
550
+ > \033[32m"false"\033[0m: the plugin has responded to the request,
551
+ and the TCP connection should be terminated
552
+
553
+ > \033[32m"retry"\033[0m: the plugin has done something to resolve the 404
554
+ situation, and copyparty should reattempt reading the file.
555
+ if it still fails, a regular 404 will be returned
556
+
557
+ > \033[32m"allow"\033[0m: should ignore the insufficient permissions
558
+ and let the client continue anyways
559
+
560
+ > \033[32m""\033[0m: the plugin has not handled the request;
561
+ try the next plugin or return the usual 404 or 403
562
+
563
+ \033[1;35mPS!\033[0m the folder that contains the python file should ideally
564
+ not contain many other python files, and especially nothing
565
+ with filenames that overlap with modules used by copyparty
566
+ """
567
+ ),
568
+ ],
525
569
  [
526
570
  "hooks",
527
571
  "execute commands before/after various events",
@@ -852,6 +896,13 @@ def add_smb(ap):
852
896
  ap2.add_argument("--smbvvv", action="store_true", help="verbosest")
853
897
 
854
898
 
899
+ def add_handlers(ap):
900
+ ap2 = ap.add_argument_group('handlers (see --help-handlers)')
901
+ ap2.add_argument("--on404", metavar="PY", type=u, action="append", help="handle 404s by executing PY file")
902
+ ap2.add_argument("--on403", metavar="PY", type=u, action="append", help="handle 403s by executing PY file")
903
+ ap2.add_argument("--hot-handlers", action="store_true", help="reload handlers on each request -- expensive but convenient when hacking on stuff")
904
+
905
+
855
906
  def add_hooks(ap):
856
907
  ap2 = ap.add_argument_group('event hooks (see --help-hooks)')
857
908
  ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="execute CMD before a file upload starts")
@@ -1107,6 +1158,7 @@ def run_argparse(
1107
1158
  add_optouts(ap)
1108
1159
  add_shutdown(ap)
1109
1160
  add_yolo(ap)
1161
+ add_handlers(ap)
1110
1162
  add_hooks(ap)
1111
1163
  add_ui(ap, retry)
1112
1164
  add_admin(ap)
@@ -1254,7 +1306,7 @@ def main(argv = None) :
1254
1306
  elif not al.no_ansi:
1255
1307
  al.ansi = VT100
1256
1308
 
1257
- if WINDOWS and not al.keep_qem:
1309
+ if WINDOWS and not al.keep_qem and not al.ah_cli:
1258
1310
  try:
1259
1311
  disable_quickedit()
1260
1312
  except:
copyparty/__version__.py CHANGED
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 8, 0)
3
+ VERSION = (1, 8, 1)
4
4
  CODENAME = "argon"
5
- BUILD_DT = (2023, 6, 26)
5
+ BUILD_DT = (2023, 7, 7)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
copyparty/authsrv.py CHANGED
@@ -1040,7 +1040,7 @@ class AuthSrv(object):
1040
1040
  flags[name] = True
1041
1041
  return
1042
1042
 
1043
- if name not in "mtp xbu xau xiu xbr xar xbd xad xm".split():
1043
+ if name not in "mtp xbu xau xiu xbr xar xbd xad xm on404 on403".split():
1044
1044
  if value is True:
1045
1045
  t = "└─add volflag [{}] = {} ({})"
1046
1046
  else:
@@ -1439,7 +1439,7 @@ class AuthSrv(object):
1439
1439
 
1440
1440
  # append additive args from argv to volflags
1441
1441
  hooks = "xbu xau xiu xbr xar xbd xad xm".split()
1442
- for name in ["mtp"] + hooks:
1442
+ for name in "mtp on404 on403".split() + hooks:
1443
1443
  self._read_volflag(vol.flags, name, getattr(self.args, name), True)
1444
1444
 
1445
1445
  for hn in hooks:
@@ -1828,7 +1828,7 @@ class AuthSrv(object):
1828
1828
  ]
1829
1829
 
1830
1830
  csv = set("i p".split())
1831
- lst = set("c ihead mtm mtp xad xar xau xiu xbd xbr xbu xm".split())
1831
+ lst = set("c ihead mtm mtp xad xar xau xiu xbd xbr xbu xm on404 on403".split())
1832
1832
  askip = set("a v c vc cgen theme".split())
1833
1833
 
1834
1834
  # keymap from argv to vflag
copyparty/cfg.py CHANGED
@@ -125,6 +125,10 @@ flagcats = {
125
125
  "dathumb": "disables audio thumbnails (spectrograms)",
126
126
  "dithumb": "disables image thumbnails",
127
127
  },
128
+ "handlers\n(better explained in --help-handlers)": {
129
+ "on404=PY": "handle 404s by executing PY file",
130
+ "on403=PY": "handle 403s by executing PY file",
131
+ },
128
132
  "event hooks\n(better explained in --help-hooks)": {
129
133
  "xbu=CMD": "execute CMD before a file upload starts",
130
134
  "xau=CMD": "execute CMD after a file upload finishes",
copyparty/httpcli.py CHANGED
@@ -58,6 +58,7 @@ from .util import (
58
58
  html_escape,
59
59
  humansize,
60
60
  ipnorm,
61
+ loadpy,
61
62
  min_ex,
62
63
  quotep,
63
64
  rand_name,
@@ -763,11 +764,27 @@ class HttpCli(object):
763
764
  return True
764
765
 
765
766
  if not self.can_read and not self.can_write and not self.can_get:
766
- if self.vpath:
767
- self.log("inaccessible: [{}]".format(self.vpath))
768
- return self.tx_404(True)
767
+ t = "@{} has no access to [{}]"
768
+ self.log(t.format(self.uname, self.vpath))
769
+
770
+ if self.avn and "on403" in self.avn.flags:
771
+ vn, rem = self.asrv.vfs.get(self.vpath, self.uname, False, False)
772
+ ret = self.on40x(vn.flags["on403"], vn, rem)
773
+ if ret == "true":
774
+ return True
775
+ elif ret == "false":
776
+ return False
777
+ elif ret == "allow":
778
+ self.log("plugin override; access permitted")
779
+ self.can_read = self.can_write = self.can_move = True
780
+ self.can_delete = self.can_get = self.can_upget = True
781
+ else:
782
+ return self.tx_404(True)
783
+ else:
784
+ if self.vpath:
785
+ return self.tx_404(True)
769
786
 
770
- self.uparam["h"] = ""
787
+ self.uparam["h"] = ""
771
788
 
772
789
  if "tree" in self.uparam:
773
790
  return self.tx_tree()
@@ -3052,6 +3069,20 @@ class HttpCli(object):
3052
3069
  self.reply(html.encode("utf-8"), status=rc)
3053
3070
  return True
3054
3071
 
3072
+ def on40x(self, mods , vn , rem ) :
3073
+ for mpath in mods:
3074
+ try:
3075
+ mod = loadpy(mpath, self.args.hot_handlers)
3076
+ except Exception as ex:
3077
+ self.log("import failed: {!r}".format(ex))
3078
+ continue
3079
+
3080
+ ret = mod.main(self, vn, rem)
3081
+ if ret:
3082
+ return ret.lower()
3083
+
3084
+ return "" # unhandled / fallthrough
3085
+
3055
3086
  def scanvol(self) :
3056
3087
  if not self.can_read or not self.can_write:
3057
3088
  raise Pebkac(403, "not allowed for user " + self.uname)
@@ -3369,7 +3400,21 @@ class HttpCli(object):
3369
3400
  try:
3370
3401
  st = bos.stat(abspath)
3371
3402
  except:
3372
- return self.tx_404()
3403
+ if "on404" not in vn.flags:
3404
+ return self.tx_404()
3405
+
3406
+ ret = self.on40x(vn.flags["on404"], vn, rem)
3407
+ if ret == "true":
3408
+ return True
3409
+ elif ret == "false":
3410
+ return False
3411
+ elif ret == "retry":
3412
+ try:
3413
+ st = bos.stat(abspath)
3414
+ except:
3415
+ return self.tx_404()
3416
+ else:
3417
+ return self.tx_404()
3373
3418
 
3374
3419
  if rem.startswith(".hist/up2k.") or (
3375
3420
  rem.endswith("/dir.txt") and rem.startswith(".hist/th/")
copyparty/ico.py CHANGED
@@ -35,7 +35,7 @@ class Ico(object):
35
35
  h = int(100 / (float(sw) / float(sh)))
36
36
  w = 100
37
37
 
38
- if chrome and as_thumb:
38
+ if chrome:
39
39
  # cannot handle more than ~2000 unique SVGs
40
40
  if HAVE_PIL:
41
41
  # svg: 3s, cache: 6s, this: 8s
@@ -45,8 +45,19 @@ class Ico(object):
45
45
  w = 64
46
46
  img = Image.new("RGB", (w, h), "#" + c[:6])
47
47
  pb = ImageDraw.Draw(img)
48
- tw, th = pb.textsize(ext)
49
- pb.text(((w - tw) // 2, (h - th) // 2), ext, fill="#" + c[6:])
48
+ try:
49
+ _, _, tw, th = pb.textbbox((0, 0), ext)
50
+ except:
51
+ tw, th = pb.textsize(ext)
52
+
53
+ tw += len(ext)
54
+ cw = tw // len(ext)
55
+ x = ((w - tw) // 2) - (cw * 2) // 3
56
+ fill = "#" + c[6:]
57
+ for ch in ext:
58
+ pb.text((x, (h - th) // 2), " %s " % (ch,), fill=fill)
59
+ x += cw
60
+
50
61
  img = img.resize((w * 3, h * 3), Image.NEAREST)
51
62
 
52
63
  buf = BytesIO()
copyparty/util.py CHANGED
@@ -2711,6 +2711,34 @@ def runhook(
2711
2711
  return True
2712
2712
 
2713
2713
 
2714
+ def loadpy(ap , hot ) :
2715
+ """
2716
+ a nice can of worms capable of causing all sorts of bugs
2717
+ depending on what other inconveniently named files happen
2718
+ to be in the same folder
2719
+ """
2720
+ if ap.startswith("~"):
2721
+ ap = os.path.expanduser(ap)
2722
+
2723
+ mdir, mfile = os.path.split(absreal(ap))
2724
+ mname = mfile.rsplit(".", 1)[0]
2725
+ sys.path.insert(0, mdir)
2726
+
2727
+ if PY2:
2728
+ mod = __import__(mname)
2729
+ if hot:
2730
+ reload(mod)
2731
+ else:
2732
+ import importlib
2733
+
2734
+ mod = importlib.import_module(mname)
2735
+ if hot:
2736
+ importlib.reload(mod)
2737
+
2738
+ sys.path.remove(mdir)
2739
+ return mod
2740
+
2741
+
2714
2742
  def gzip_orig_sz(fn ) :
2715
2743
  with open(fsenc(fn), "rb") as f:
2716
2744
  f.seek(-4, 2)
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.8.0
3
+ Version: 1.8.1
4
4
  Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
5
5
  Author-email: ed <copyparty@ocv.me>
6
6
  License: MIT
@@ -117,12 +117,14 @@ turn almost any device into a file server with resumable uploads/downloads using
117
117
  * [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
118
118
  * [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
119
119
  * [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
120
+ * [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
120
121
  * [hiding from google](#hiding-from-google) - tell search engines you dont wanna be indexed
121
122
  * [themes](#themes)
122
123
  * [complete examples](#complete-examples)
123
124
  * [reverse-proxy](#reverse-proxy) - running copyparty next to other websites
124
125
  * [packages](#packages) - the party might be closer than you think
125
126
  * [arch package](#arch-package) - now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
127
+ * [fedora package](#fedora-package) - now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/)
126
128
  * [nix package](#nix-package) - `nix profile install github:9001/copyparty`
127
129
  * [nixos module](#nixos-module)
128
130
  * [browser support](#browser-support) - TLDR: yes
@@ -1177,6 +1179,13 @@ note that this is way more complicated than the new [event hooks](#event-hooks)
1177
1179
  note that it will occupy the parsing threads, so fork anything expensive (or set `kn` to have copyparty fork it for you) -- otoh if you want to intentionally queue/singlethread you can combine it with `--mtag-mt 1`
1178
1180
 
1179
1181
 
1182
+ ## handlers
1183
+
1184
+ redefine behavior with plugins ([examples](./bin/handlers/))
1185
+
1186
+ replace 404 and 403 errors with something completely different (that's it for now)
1187
+
1188
+
1180
1189
  ## hiding from google
1181
1190
 
1182
1191
  tell search engines you dont wanna be indexed, either using the good old [robots.txt](https://www.robotstxt.org/robotstxt.html) or through copyparty settings:
@@ -1279,6 +1288,19 @@ the party might be closer than you think
1279
1288
  now [available on aur](https://aur.archlinux.org/packages/copyparty) maintained by [@icxes](https://github.com/icxes)
1280
1289
 
1281
1290
 
1291
+ ## fedora package
1292
+
1293
+ now [available on copr-pypi](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/) , maintained autonomously -- [track record](https://copr.fedorainfracloud.org/coprs/g/copr/PyPI/package/python-copyparty/) seems OK
1294
+
1295
+ ```bash
1296
+ dnf copr enable @copr/PyPI
1297
+ dnf install python3-copyparty # just a minimal install, or...
1298
+ dnf install python3-{copyparty,pillow,argon2-cffi,pyftpdlib,pyOpenSSL} ffmpeg-free # with recommended deps
1299
+ ```
1300
+
1301
+ this *may* also work on RHEL but [I'm not paying IBM to verify that](https://www.jeffgeerling.com/blog/2023/dear-red-hat-are-you-dumb)
1302
+
1303
+
1282
1304
  ## nix package
1283
1305
 
1284
1306
  `nix profile install github:9001/copyparty`
@@ -1,20 +1,20 @@
1
1
  copyparty/__init__.py,sha256=JA6xnECt2WITjgMEUsk7ZKYgxieda4QvXQtgxfnfkR4,1812
2
- copyparty/__main__.py,sha256=Nj919sul_dMEmCuZx7QXyT2W_QRoLwpqrvzr2T0ci6s,73497
3
- copyparty/__version__.py,sha256=sYUj4hbO4Bp1gZ0FQLj-ZaR-6ggn80Z-81o3UUqx1vc,246
4
- copyparty/authsrv.py,sha256=jUokKLiR52VWmw4CQmOkhT_pTXiVlv3EORV_g6G79Xc,68440
2
+ copyparty/__main__.py,sha256=IFxnXMbKWw1_ZJE6zDVzyELg5TSrxWijxoAghcGENm4,76082
3
+ copyparty/__version__.py,sha256=j2HdvQx05WBQ_Nb_j2FWXld9K3ON-ZMT3J2tZFCTtRI,245
4
+ copyparty/authsrv.py,sha256=udRfFaybO119wg20HzsLx0pMMQ7YSJWQV4_pNv1QBCU,68482
5
5
  copyparty/broker_mp.py,sha256=lWtjjoht5dsKnm9TkRlV3vdzGWOBh8JCWCgzWuRDNzI,3915
6
6
  copyparty/broker_mpw.py,sha256=GlSn4PRd_OqqeG39FiXgNvPzXVQW6UCiAcqmBSr2q6g,3200
7
7
  copyparty/broker_thr.py,sha256=eKr--HJGig5zqvNGwH9UoBG9Nvi9mT2axrRmJwknd0s,1759
8
8
  copyparty/broker_util.py,sha256=CnX_LAhQQqouONcDLtVkVlcBX3Z6pWuKDQDmmbHGEg4,1489
9
9
  copyparty/cert.py,sha256=QlfGJqxcVd_Ga5-ETSXhMOn9XDVaYLnuS3dUgrHOI2E,7135
10
- copyparty/cfg.py,sha256=aOPQWll34Duuz70su-RfQt3v4TYYICvgqgqcE6d3lw4,6997
10
+ copyparty/cfg.py,sha256=3psBpcVQY8eHY2kxCTohYB98i_mlpjNrLpi-L04RVLY,7173
11
11
  copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
12
12
  copyparty/fsutil.py,sha256=c4fTvmclKbVABNsjU4rGddsjCgRwi9YExAyo-06ATc8,3932
13
13
  copyparty/ftpd.py,sha256=7YQSsPn7LfRpGiuLRuGRG1JJX2L53NSJVLBUNGUhG40,15393
14
- copyparty/httpcli.py,sha256=DbZkYbcN3mFMWHLWx5qcralxfikyOTvpogR_TDKvDpU,124727
14
+ copyparty/httpcli.py,sha256=dJOT6ARbxsJiLnUorvnTOejvbew8riFKNyGHlSNYD2w,126305
15
15
  copyparty/httpconn.py,sha256=CJU4wK_6QJFvgK9mQwEV55j6Muh_9k-GTe4AIehzJiw,6825
16
16
  copyparty/httpsrv.py,sha256=vLKKLroFlbjLmbMIOXE2ErvrtyoZ5-QGrr469FbQMLY,15372
17
- copyparty/ico.py,sha256=rH7yBkC3jZ0CJ6NAxENECXzCZXb7hehm1ht0yGM9y84,2709
17
+ copyparty/ico.py,sha256=q9UYAUcIaZ1WgLwVoVY5BFOTEKotF8HVEUZI2tpjDbo,3016
18
18
  copyparty/mdns.py,sha256=xJS5GQS9z65nhhk0bvY78AXZcLy_9tBfA3KIQJXp6g4,17205
19
19
  copyparty/mtag.py,sha256=xQAXjTPJtDclfQhOOsMjyv35e-QVzbm8v4ng1AA41WU,16844
20
20
  copyparty/multicast.py,sha256=eQW1aBFjNNFhyaovSsYOgIqUK8daBCPj19ywCZnd96c,11520
@@ -30,7 +30,7 @@ copyparty/th_cli.py,sha256=hcb-GGN7krnHF3LIp3tDix_OYwXnCRoTpsiO0TaDqOg,3826
30
30
  copyparty/th_srv.py,sha256=Aiy5EG3q4qa6lLJr-YWF0ji4qsNlUTZcHKsA0oxtoso,22379
31
31
  copyparty/u2idx.py,sha256=HMckWFh4fBis9f939gKTlB-8Ww2ZGSWI-uyZhcUUiD8,10589
32
32
  copyparty/up2k.py,sha256=O_CchFvpWNT9ZRy_rTcVMxV82hEITa4t7l-rcHl3G_c,124240
33
- copyparty/util.py,sha256=242ruVr6dmA7aQLARA2BYUtUwJ-KQ_ppko-FT7BT3Q0,72141
33
+ copyparty/util.py,sha256=PBWeNKJ-M9CHzFX4eWVtls2joNt9-WlqlWHGqitSGZE,72768
34
34
  copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  copyparty/bos/bos.py,sha256=Md2RwMauEdOS7SfK5aiHby8T1KgQoTaoEjVCYU98_4I,1560
36
36
  copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
@@ -53,7 +53,7 @@ copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUu
53
53
  copyparty/stolen/ifaddr/_shared.py,sha256=cJACl8cOxQ-HSYphZTzKMAjAx_TAFyJwUPjfD102Xqw,6111
54
54
  copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
55
55
  copyparty/web/baguettebox.js.gz,sha256=X9cgmzW13InKW92J1Z5UtvpPsu1fDaVWlumPIZYpdzY,7296
56
- copyparty/web/browser.css.gz,sha256=Fa8YZJpsL5BTpFf8Yy6aO9j7KiA9VPMJbtithr_2vB8,10963
56
+ copyparty/web/browser.css.gz,sha256=9dzZVXXDVOiUuZgePs0ytazPi9dN8l2Bi1rM6frZH9s,11000
57
57
  copyparty/web/browser.html,sha256=BToSFHN0idtjq5O9iqOvUctOp7aQYmEXD42Big9AuZo,5317
58
58
  copyparty/web/browser.js.gz,sha256=rLBEglomQHfAKKjOywetn0rPCQ1l_b5F1sUomqctzjI,59170
59
59
  copyparty/web/browser2.html,sha256=3kR3QiDXYqtAo7gOoBtdTP3eRvibUCZHVVAbmAfaAVU,1604
@@ -99,9 +99,9 @@ copyparty/web/deps/prismd.css.gz,sha256=hzzspI_ptCygzmsIp9rKsf1M4yU12Ma7TfE-wyoX
99
99
  copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
100
100
  copyparty/web/deps/sha512.ac.js.gz,sha256=qELXngcl-Zitrpwolm4EWqVBPyEht013iP7uDuUDPk4,7043
101
101
  copyparty/web/deps/sha512.hw.js.gz,sha256=0xJaw75Tghoblu72C2h4YoU1izSR99mBtDMoGqZ3xvs,8119
102
- copyparty-1.8.0.dist-info/LICENSE,sha256=yyzj1id78vWoLs8zbMRJY7xkkLz0lv-9dfyeIauqdfM,1059
103
- copyparty-1.8.0.dist-info/METADATA,sha256=UT9tqbfnEOybojUpzf4cgufs3Ko2xCL4Bl9YkMPbjr8,97477
104
- copyparty-1.8.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
105
- copyparty-1.8.0.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
106
- copyparty-1.8.0.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
107
- copyparty-1.8.0.dist-info/RECORD,,
102
+ copyparty-1.8.1.dist-info/LICENSE,sha256=yyzj1id78vWoLs8zbMRJY7xkkLz0lv-9dfyeIauqdfM,1059
103
+ copyparty-1.8.1.dist-info/METADATA,sha256=T4lW_RBk-ph2HdSBe4en4qyEJXub2z4U0E3r9UEAJqw,98438
104
+ copyparty-1.8.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
105
+ copyparty-1.8.1.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
106
+ copyparty-1.8.1.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
107
+ copyparty-1.8.1.dist-info/RECORD,,