ramifice 0.8.3__py3-none-any.whl → 0.8.5__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.
@@ -1,13 +1,13 @@
1
1
  """Field of Model for upload file."""
2
2
 
3
- import os
4
3
  import uuid
5
4
  from base64 import b64decode
6
5
  from datetime import date
7
- from pathlib import Path
6
+ from os import makedirs
7
+ from os.path import basename, exists, getsize
8
+ from shutil import copyfile
8
9
 
9
- import aiofiles
10
- from aioshutil import copyfile
10
+ from anyio import Path, open_file, to_thread
11
11
 
12
12
  from ramifice.fields.general.field import Field
13
13
  from ramifice.fields.general.file_group import FileGroup
@@ -127,12 +127,12 @@ class FileField(Field, FileGroup, JsonMixin):
127
127
  # Create path to target directory.
128
128
  dir_target_path = f"{MEDIA_ROOT}/uploads/{self.target_dir}/{date_str}"
129
129
  # Create target directory if it does not exist.
130
- if not await aiofiles.os.path.exists(dir_target_path):
131
- await aiofiles.os.makedirs(dir_target_path)
130
+ if not await to_thread.run_sync(exists, dir_target_path):
131
+ await to_thread.run_sync(makedirs, dir_target_path)
132
132
  # Create path to target file.
133
133
  f_target_path = f"{dir_target_path}/{f_uuid_name}"
134
134
  # Save file in target directory.
135
- async with aiofiles.open(f_target_path, mode="wb") as open_f:
135
+ async with await open_file(f_target_path, mode="wb") as open_f:
136
136
  f_content = b64decode(base64_str)
137
137
  await open_f.write(f_content)
138
138
  # Add paths to target file.
@@ -143,7 +143,7 @@ class FileField(Field, FileGroup, JsonMixin):
143
143
  # Add file extension.
144
144
  file_info["extension"] = extension
145
145
  # Add file size (in bytes).
146
- file_info["size"] = await aiofiles.os.path.getsize(f_target_path)
146
+ file_info["size"] = await to_thread.run_sync(getsize, f_target_path)
147
147
  #
148
148
  # to value.
149
149
  self.value = file_info
@@ -172,21 +172,21 @@ class FileField(Field, FileGroup, JsonMixin):
172
172
  # Create path to target directory.
173
173
  dir_target_path = f"{MEDIA_ROOT}/uploads/{self.target_dir}/{date_str}"
174
174
  # Create target directory if it does not exist.
175
- if not await aiofiles.os.path.exists(dir_target_path):
176
- await aiofiles.os.makedirs(dir_target_path)
175
+ if not await to_thread.run_sync(exists, dir_target_path):
176
+ await to_thread.run_sync(makedirs, dir_target_path)
177
177
  # Create path to target file.
178
178
  f_target_path = f"{dir_target_path}/{f_uuid_name}"
179
179
  # Save file in target directory.
180
- await copyfile(src_path, f_target_path)
180
+ await to_thread.run_sync(copyfile, src_path, f_target_path)
181
181
  # Add paths to target file.
182
182
  file_info["path"] = f_target_path
183
183
  file_info["url"] = f"{MEDIA_URL}/uploads/{self.target_dir}/{date_str}/{f_uuid_name}"
184
184
  # Add original file name.
185
- file_info["name"] = os.path.basename(src_path)
185
+ file_info["name"] = basename(src_path)
186
186
  # Add file extension.
187
187
  file_info["extension"] = extension
188
188
  # Add file size (in bytes).
189
- file_info["size"] = await aiofiles.os.path.getsize(f_target_path)
189
+ file_info["size"] = await to_thread.run_sync(getsize, f_target_path)
190
190
  #
191
191
  # to value.
192
192
  self.value = file_info
@@ -1,13 +1,13 @@
1
1
  """Field of Model for upload image."""
2
2
 
3
- import os
4
3
  import uuid
5
4
  from base64 import b64decode
6
5
  from datetime import date
7
- from pathlib import Path
6
+ from os import makedirs
7
+ from os.path import basename, exists, getsize
8
+ from shutil import copyfile
8
9
 
9
- import aiofiles
10
- from aioshutil import copyfile
10
+ from anyio import Path, open_file, to_thread
11
11
 
12
12
  from ramifice.fields.general.field import Field
13
13
  from ramifice.fields.general.file_group import FileGroup
@@ -164,10 +164,10 @@ class ImageField(Field, FileGroup, JsonMixin):
164
164
  # Create path to main image.
165
165
  main_img_path = f"{imgs_dir_path}/{new_original_name}"
166
166
  # Create target directory if it does not exist.
167
- if not await aiofiles.os.path.exists(imgs_dir_path):
168
- await aiofiles.os.makedirs(imgs_dir_path)
167
+ if not await to_thread.run_sync(exists, imgs_dir_path):
168
+ await to_thread.run_sync(makedirs, imgs_dir_path)
169
169
  # Save main image in target directory.
170
- async with aiofiles.open(main_img_path, mode="wb") as open_f:
170
+ async with await open_file(main_img_path, mode="wb") as open_f:
171
171
  f_content = b64decode(base64_str)
172
172
  await open_f.write(f_content)
173
173
  # Add paths for main image.
@@ -187,7 +187,7 @@ class ImageField(Field, FileGroup, JsonMixin):
187
187
  # Add url path to target directory with images.
188
188
  img_info["imgs_dir_url"] = imgs_dir_url
189
189
  # Add size of main image (in bytes).
190
- img_info["size"] = await aiofiles.os.path.getsize(main_img_path)
190
+ img_info["size"] = await to_thread.run_sync(getsize, main_img_path)
191
191
  #
192
192
  # to value.
193
193
  self.value = img_info
@@ -222,15 +222,15 @@ class ImageField(Field, FileGroup, JsonMixin):
222
222
  # Create path to main image.
223
223
  main_img_path = f"{imgs_dir_path}/{new_original_name}"
224
224
  # Create target directory if it does not exist.
225
- if not await aiofiles.os.path.exists(imgs_dir_path):
226
- await aiofiles.os.makedirs(imgs_dir_path)
225
+ if not await to_thread.run_sync(exists, imgs_dir_path):
226
+ await to_thread.run_sync(makedirs, imgs_dir_path)
227
227
  # Save main image in target directory.
228
- await copyfile(src_path, main_img_path)
228
+ await to_thread.run_sync(copyfile, src_path, main_img_path)
229
229
  # Add paths for main image.
230
230
  img_info["path"] = main_img_path
231
231
  img_info["url"] = f"{imgs_dir_url}/{new_original_name}"
232
232
  # Add original image name.
233
- img_info["name"] = os.path.basename(src_path)
233
+ img_info["name"] = basename(src_path)
234
234
  # Add image extension.
235
235
  img_info["extension"] = extension
236
236
  # Transform extension to the upper register and delete the point.
@@ -243,7 +243,7 @@ class ImageField(Field, FileGroup, JsonMixin):
243
243
  # Add url path to target directory with images.
244
244
  img_info["imgs_dir_url"] = imgs_dir_url
245
245
  # Add size of main image (in bytes).
246
- img_info["size"] = await aiofiles.os.path.getsize(main_img_path)
246
+ img_info["size"] = await to_thread.run_sync(getsize, main_img_path)
247
247
  #
248
248
  # to value.
249
249
  self.value = img_info
@@ -1,7 +1,7 @@
1
1
  """Decorator for converting Python classes into Ramifice models."""
2
2
 
3
- import os
4
3
  import re
4
+ from os.path import exists
5
5
  from typing import Any
6
6
 
7
7
  from ramifice.commons import QCommonsMixin
@@ -42,7 +42,8 @@ def model(
42
42
  raise DoesNotMatchRegexError("^[A-Z][a-zA-Z0-9]{0,24}$")
43
43
  if fixture_name is not None:
44
44
  fixture_path = f"config/fixtures/{fixture_name}.yml"
45
- if not os.path.exists(fixture_path):
45
+
46
+ if not exists(fixture_path):
46
47
  msg = (
47
48
  f"Model: `{cls.__module__}.{cls.__name__}` > "
48
49
  + f"META param: `fixture_name` => "
@@ -1,9 +1,10 @@
1
1
  """Validation of Model data before saving to the database."""
2
2
 
3
+ from os import remove
4
+ from shutil import rmtree
3
5
  from typing import Any
4
6
 
5
- from aiofiles import os
6
- from aioshutil import rmtree
7
+ from anyio import to_thread
7
8
  from bson.objectid import ObjectId
8
9
  from pymongo.asynchronous.collection import AsyncCollection
9
10
 
@@ -133,7 +134,7 @@ class CheckMixin(
133
134
  file_data = result_map.get(field_name)
134
135
  if file_data is not None:
135
136
  if file_data["is_new_file"]:
136
- await os.remove(file_data["path"])
137
+ await to_thread.run_sync(remove, file_data["path"])
137
138
  field_data.value = None
138
139
  if curr_doc is not None:
139
140
  field_data.value = curr_doc[field_name]
@@ -141,7 +142,7 @@ class CheckMixin(
141
142
  img_data = result_map.get(field_name)
142
143
  if img_data is not None:
143
144
  if img_data["is_new_img"]:
144
- await rmtree(img_data["imgs_dir_path"]) # type: ignore[call-arg]
145
+ await to_thread.run_sync(rmtree, img_data["imgs_dir_path"])
145
146
  field_data.value = None
146
147
  if curr_doc is not None:
147
148
  field_data.value = curr_doc[field_name]
@@ -1,9 +1,10 @@
1
1
  """Delete document from database."""
2
2
 
3
+ from os import remove
4
+ from shutil import rmtree
3
5
  from typing import Any
4
6
 
5
- from aiofiles import os
6
- from aioshutil import rmtree
7
+ from anyio import to_thread
7
8
  from pymongo.asynchronous.collection import AsyncCollection
8
9
 
9
10
  from ramifice.utils import constants
@@ -77,12 +78,12 @@ class DeleteMixin:
77
78
  if group == "file":
78
79
  file_data = mongo_doc[field_name]
79
80
  if file_data is not None and len(file_data["path"]) > 0:
80
- await os.remove(file_data["path"])
81
+ await to_thread.run_sync(remove, file_data["path"])
81
82
  file_data = None
82
83
  elif group == "img":
83
84
  file_data = mongo_doc[field_name]
84
85
  if file_data is not None and len(file_data["imgs_dir_path"]) > 0:
85
- await rmtree(file_data["imgs_dir_path"]) # type: ignore[call-arg]
86
+ await to_thread.run_sync(rmtree, file_data["imgs_dir_path"])
86
87
  file_data = None
87
88
  field_data.value = None
88
89
  # Run hook.
@@ -3,7 +3,7 @@
3
3
  Supported fields: ImageField
4
4
  """
5
5
 
6
- import asyncio
6
+ from asyncio import to_thread
7
7
  from typing import Any
8
8
 
9
9
  from PIL import Image
@@ -80,7 +80,7 @@ class ImgGroupMixin:
80
80
  # Extension to the upper register and delete the point.
81
81
  ext_upper = value["ext_upper"]
82
82
  # Get image file.
83
- with await asyncio.to_thread(Image.open, path) as img:
83
+ with await to_thread(Image.open, path) as img:
84
84
  width, height = img.size
85
85
  value["width"] = width
86
86
  value["height"] = height
@@ -93,7 +93,7 @@ class ImgGroupMixin:
93
93
  if size_name == "lg":
94
94
  value["path_lg"] = f"{imgs_dir_path}/lg{extension}"
95
95
  value["url_lg"] = f"{imgs_dir_url}/lg{extension}"
96
- await asyncio.to_thread(
96
+ await to_thread(
97
97
  img.save,
98
98
  fp=value["path_lg"],
99
99
  format=ext_upper,
@@ -101,7 +101,7 @@ class ImgGroupMixin:
101
101
  elif size_name == "md":
102
102
  value["path_md"] = f"{imgs_dir_path}/md{extension}"
103
103
  value["url_md"] = f"{imgs_dir_url}/md{extension}"
104
- await asyncio.to_thread(
104
+ await to_thread(
105
105
  img.save,
106
106
  fp=value["path_md"],
107
107
  format=ext_upper,
@@ -109,7 +109,7 @@ class ImgGroupMixin:
109
109
  elif size_name == "sm":
110
110
  value["path_sm"] = f"{imgs_dir_path}/sm{extension}"
111
111
  value["url_sm"] = f"{imgs_dir_url}/sm{extension}"
112
- await asyncio.to_thread(
112
+ await to_thread(
113
113
  img.save,
114
114
  fp=value["path_sm"],
115
115
  format=ext_upper,
@@ -117,7 +117,7 @@ class ImgGroupMixin:
117
117
  elif size_name == "xs":
118
118
  value["path_xs"] = f"{imgs_dir_path}/xs{extension}"
119
119
  value["url_xs"] = f"{imgs_dir_url}/xs{extension}"
120
- await asyncio.to_thread(
120
+ await to_thread(
121
121
  img.save,
122
122
  fp=value["path_xs"],
123
123
  format=ext_upper,
ramifice/utils/tools.py CHANGED
@@ -1,9 +1,9 @@
1
1
  """Global collection of auxiliary methods."""
2
2
 
3
- import asyncio
4
3
  import ipaddress
5
4
  import math
6
- import os
5
+ from asyncio import to_thread
6
+ from os.path import getsize
7
7
  from typing import Any
8
8
  from urllib.parse import urlparse
9
9
 
@@ -29,9 +29,9 @@ def to_human_size(size: int) -> str:
29
29
  return f"{size} {order}"
30
30
 
31
31
 
32
- def get_file_size(path: str) -> int:
32
+ async def get_file_size(path: str) -> int:
33
33
  """Get file size in bytes."""
34
- size: int = os.path.getsize(path)
34
+ size: int = await to_thread(getsize, path)
35
35
  return size
36
36
 
37
37
 
@@ -43,7 +43,10 @@ def normal_email(email: str | None) -> str | None:
43
43
  """
44
44
  normal: str | None = None
45
45
  try:
46
- emailinfo = validate_email(str(email), check_deliverability=False)
46
+ emailinfo = validate_email(
47
+ str(email),
48
+ check_deliverability=False,
49
+ )
47
50
  normal = emailinfo.normalized
48
51
  except EmailNotValidError:
49
52
  pass
@@ -53,7 +56,7 @@ def normal_email(email: str | None) -> str | None:
53
56
  async def is_email(email: str | None) -> bool:
54
57
  """Validate Email address."""
55
58
  try:
56
- await asyncio.to_thread(
59
+ await to_thread(
57
60
  validate_email,
58
61
  str(email),
59
62
  check_deliverability=True,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ramifice
3
- Version: 0.8.3
3
+ Version: 0.8.5
4
4
  Summary: ORM-like API MongoDB for Python language.
5
5
  Project-URL: Homepage, https://github.com/kebasyaty/ramifice
6
6
  Project-URL: Documentation, https://kebasyaty.github.io/ramifice/
@@ -23,8 +23,7 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
23
23
  Classifier: Topic :: Database
24
24
  Classifier: Typing :: Typed
25
25
  Requires-Python: <4.0,>=3.12
26
- Requires-Dist: aiofiles>=24.1.0
27
- Requires-Dist: aioshutil>=1.5
26
+ Requires-Dist: anyio>=4.9.0
28
27
  Requires-Dist: argon2-cffi>=25.1.0
29
28
  Requires-Dist: babel>=2.17.0
30
29
  Requires-Dist: email-validator>=2.2.0
@@ -25,10 +25,10 @@ ramifice/fields/color_field.py,sha256=K-lYp8f08HTZt6WU0kY3CQWaAmx6I3-uyKHBq7xAeS
25
25
  ramifice/fields/date_field.py,sha256=-M_dD8tVUXcDCQD5Hy5Ns9Z2QGlRya0qbvoWgA4qpmg,5277
26
26
  ramifice/fields/date_time_field.py,sha256=ahjX-cD5Qj-V7JUi5QAZ8qgv9UePhYYYzJghiasKdqE,5312
27
27
  ramifice/fields/email_field.py,sha256=4Kxy1K6CXJUJ8Db0CQuopjodiY4ybe7V0GT756t7Nks,3481
28
- ramifice/fields/file_field.py,sha256=jYAiP0KmhsrjJwVgEHUCA0zqJzKZmjFw9OeXv583ln0,8202
28
+ ramifice/fields/file_field.py,sha256=2uc2YyuS0WDYO-jD0I8b3RL74m1Fw5DKAc7GlkzU8LE,8305
29
29
  ramifice/fields/float_field.py,sha256=JeVwoIi6j-dovXarZ3NgmSQI7f3qZzydlRs_yqp3Faw,4637
30
30
  ramifice/fields/id_field.py,sha256=YO5oIwXtqgURjjd2oYe2ouXxdpaiJp5ZhUgUA2pkNeo,4183
31
- ramifice/fields/image_field.py,sha256=g3z_Ug5Ob514OZdacm6qpHTRpPBauuL3WqBTfQgEO1I,11621
31
+ ramifice/fields/image_field.py,sha256=_UseQMYOh7jUebsH1u4bYlTt3xTM3Yb09yrTtQx2wi0,11724
32
32
  ramifice/fields/integer_field.py,sha256=xPwpdhYNz4MyHgOypqa29oGNdKZic05yyUYHg5CDD3E,4609
33
33
  ramifice/fields/ip_field.py,sha256=tBFGFMC_zwAyLGtVRNNfiu4vQoxXPcgVHhX_aoHrvns,3390
34
34
  ramifice/fields/password_field.py,sha256=USD4Y8MTI89QZVT6zqLGBmb5kqOKrXqh73-z99cOvtk,3266
@@ -44,11 +44,11 @@ ramifice/fields/general/file_group.py,sha256=pC9bGUpDeu7FLJVD6NMCzq18aPETotipknS
44
44
  ramifice/fields/general/number_group.py,sha256=LOPHbKAnIuqW4DEh2fH78w6qOQjp0OhkuP7MoikhlkA,761
45
45
  ramifice/fields/general/text_group.py,sha256=m9EnlYGwqlck-JIYOCUd0hUYAVr8jH4YCnTmm9QlCkQ,1103
46
46
  ramifice/models/__init__.py,sha256=h_QQ5rSJNZ-7kmx7wIFd8E8RmUS94b_x4jdwMbq8zm4,15
47
- ramifice/models/decorator.py,sha256=fL9xc7-_BEiFEqfwgql6CihYWB6MC-JgiC0FSSK_JHA,5956
47
+ ramifice/models/decorator.py,sha256=4NwnWcu2wxiX0EI_YXhbleyn4LB22mgDaDkQzJbHKD0,5967
48
48
  ramifice/models/model.py,sha256=e5UWHKIHwm7saxQ4bbamsTkz1VVBIqTRlAmJCOg5uRE,7160
49
49
  ramifice/paladins/__init__.py,sha256=EJ6EEKXUcMG5P1bDmlEa4W3fsxSz5u6mzDG_oU1efMQ,618
50
- ramifice/paladins/check.py,sha256=9lLJ6SnNQBI9eyAwWSqjFa7_F2A2QbTg4WHyrPL3E20,6584
51
- ramifice/paladins/delete.py,sha256=90ZiTzYxa2bnhOJhkEBe7XR_Yi4gaTvrJ3u4dSik0mU,3430
50
+ ramifice/paladins/check.py,sha256=sDTdUECMTSfV37Hm4_HDZOB_YRWs58H5fnOY6dTT90k,6619
51
+ ramifice/paladins/delete.py,sha256=V3vahfx_kVCv5dTG6PVRsDlehVk4OtET4nHtxr9M5s0,3465
52
52
  ramifice/paladins/password.py,sha256=G-tMz2dIiOYEhOeSHYgAmc2e4tG_TJ2gt5tzPwBapkw,3047
53
53
  ramifice/paladins/refrash.py,sha256=hIZQEBGtoIhuGGg2KQYGApCaMb8WhK_QZlzi1_-zzU0,1100
54
54
  ramifice/paladins/save.py,sha256=mFau65uWYy4dSVyTVdZGR3VUnP-I_NPdMvq7F5n1sFo,3899
@@ -60,7 +60,7 @@ ramifice/paladins/groups/choice_group.py,sha256=KmrjbuHLLl6yGbRkdoMflf1thh17GLWr
60
60
  ramifice/paladins/groups/date_group.py,sha256=V3MCp8eA7txVLh6xmg76G9_y62TzWIQWqH59Ip26Xag,3779
61
61
  ramifice/paladins/groups/file_group.py,sha256=ySS7L5zcm2XrZRQUUOU8kgzqrucZ95UYzXD6pALWqE4,2982
62
62
  ramifice/paladins/groups/id_group.py,sha256=zN_Glu_cMGk8jMSDli3vYPvYrQXvQJNJFzb-t-qtZlQ,1290
63
- ramifice/paladins/groups/img_group.py,sha256=YDJTvbRoqQ2nf7-2QbIQ72I4j_c98_d5LZNrD9kCy0Q,6040
63
+ ramifice/paladins/groups/img_group.py,sha256=YOTUiXlmpNcsbzuLOEGB0eyemQxwaLkOBN9kzPb-lkI,6015
64
64
  ramifice/paladins/groups/num_group.py,sha256=sbxzTdl33TVySfaNfqMixyBkJ69v6AqEgraFUN3Kftk,2317
65
65
  ramifice/paladins/groups/pass_group.py,sha256=uuIIqMBXsYG7vTHc_AhdgWuNCivxTgQMjkEu0-ElSmY,1887
66
66
  ramifice/paladins/groups/slug_group.py,sha256=ztiA2v7e5lQYRZtlLw8WGOhSWaYQfOdZ6wkKbx3ZbTM,2329
@@ -70,7 +70,7 @@ ramifice/utils/constants.py,sha256=dTSk07FVc6hgXwG1IF0_klPnbfxlFHiaRmym5zWgzIM,2
70
70
  ramifice/utils/errors.py,sha256=iuhq7fzpUmsOyeXeg2fJjta8yAuqlXLKsZVMpfUhtHE,1901
71
71
  ramifice/utils/fixtures.py,sha256=PMRl1Ud0Ek0eX5F7BPiL7az_H7YKtIVKB8MJ17CeBdw,3179
72
72
  ramifice/utils/migration.py,sha256=5VYYB7DFMzLCRYWdlwtqGRSUPFdXp5SMxuMWraofVCw,11106
73
- ramifice/utils/tools.py,sha256=dJjG92nevSq_US30pUdbBy37pvqBdxXHBeHZxpOInKM,2843
73
+ ramifice/utils/tools.py,sha256=6N0YNlYB6c6Tz-4rhHrZJPi-KCUbRZhtK0VXHdusnNs,2921
74
74
  ramifice/utils/translations.py,sha256=Ibx6HqPcnsNxuBfXDs9mCLEA7xu4mkl3q39vqFaK-GI,4233
75
75
  ramifice/utils/unit.py,sha256=PPNKWYFJ8cz0nwbBPaTdL58_Nr7N0fIHFJBpKG2ZLKI,2482
76
76
  ramifice/utils/mixins/__init__.py,sha256=GrxJDsw73bEkitIh0-0BCxNnUK-N5uRXMCRlaPoaz1o,265
@@ -78,7 +78,7 @@ ramifice/utils/mixins/add_valid.py,sha256=TLOObedzXNA9eCylfAVbVCqIKE5sV-P5AdIN7a
78
78
  ramifice/utils/mixins/hooks.py,sha256=33jvJRhfnJeL2Hd_YFXk3M_7wjqHaByU2wRjKyboL6s,914
79
79
  ramifice/utils/mixins/indexing.py,sha256=Z0427HoaVRyNmSNN8Fx0mSICgAKV-gDdu3iR5qYUEbs,329
80
80
  ramifice/utils/mixins/json_converter.py,sha256=2K_PZ34AzpesusgyyQFOLXFPcjXez3TWn-m9CHIKwRo,1131
81
- ramifice-0.8.3.dist-info/METADATA,sha256=oPmjSfAlrM-Uf-jeztkvHapDj1HkLptyEvwiPZkLrO4,21016
82
- ramifice-0.8.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
- ramifice-0.8.3.dist-info/licenses/LICENSE,sha256=LrEL0aTZx90HDwFUQCJutORiDjJL9AnuVvCtspXIqt4,1095
84
- ramifice-0.8.3.dist-info/RECORD,,
81
+ ramifice-0.8.5.dist-info/METADATA,sha256=W52KVNywCe-f2e4gR_VBW5J9nJ3cKgjAoOAq64uUtGE,20982
82
+ ramifice-0.8.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
+ ramifice-0.8.5.dist-info/licenses/LICENSE,sha256=LrEL0aTZx90HDwFUQCJutORiDjJL9AnuVvCtspXIqt4,1095
84
+ ramifice-0.8.5.dist-info/RECORD,,