swiftshadow 2.1.0__py3-none-any.whl → 2.2.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.
- swiftshadow/classes.py +38 -20
- swiftshadow/helpers.py +10 -0
- swiftshadow/models.py +2 -0
- swiftshadow/providers.py +67 -44
- swiftshadow/validator.py +29 -8
- {swiftshadow-2.1.0.dist-info → swiftshadow-2.2.1.dist-info}/METADATA +2 -1
- swiftshadow-2.2.1.dist-info/RECORD +14 -0
- swiftshadow-2.1.0.dist-info/RECORD +0 -14
- {swiftshadow-2.1.0.dist-info → swiftshadow-2.2.1.dist-info}/WHEEL +0 -0
- {swiftshadow-2.1.0.dist-info → swiftshadow-2.2.1.dist-info}/entry_points.txt +0 -0
- {swiftshadow-2.1.0.dist-info → swiftshadow-2.2.1.dist-info}/licenses/LICENSE +0 -0
swiftshadow/classes.py
CHANGED
@@ -1,19 +1,20 @@
|
|
1
|
+
from asyncio import run
|
1
2
|
from datetime import datetime
|
3
|
+
from logging import DEBUG, INFO, FileHandler, Formatter, StreamHandler, getLogger
|
4
|
+
from pathlib import Path
|
5
|
+
from pickle import dump, dumps, load, loads
|
2
6
|
from random import choice
|
7
|
+
from sys import stdout
|
3
8
|
from typing import Literal
|
4
|
-
|
9
|
+
|
10
|
+
import aiofiles
|
5
11
|
from appdirs import user_cache_dir
|
6
|
-
from logging import FileHandler, getLogger, Formatter, StreamHandler, INFO, DEBUG
|
7
|
-
from sys import stdout
|
8
|
-
from pickle import load, dump, loads, dumps
|
9
|
-
from swiftshadow.cache import checkExpiry, getExpiry
|
10
|
-
from swiftshadow.models import CacheData, Proxy as Proxy
|
11
12
|
|
13
|
+
from swiftshadow.cache import checkExpiry, getExpiry
|
12
14
|
from swiftshadow.exceptions import UnsupportedProxyProtocol
|
15
|
+
from swiftshadow.models import CacheData
|
16
|
+
from swiftshadow.models import Proxy as Proxy
|
13
17
|
from swiftshadow.providers import Providers
|
14
|
-
from asyncio import run
|
15
|
-
import aiofiles
|
16
|
-
|
17
18
|
|
18
19
|
logger = getLogger("swiftshadow")
|
19
20
|
logger.setLevel(INFO)
|
@@ -87,13 +88,16 @@ class ProxyInterface:
|
|
87
88
|
|
88
89
|
if protocol not in ["https", "http"]:
|
89
90
|
raise UnsupportedProxyProtocol(
|
90
|
-
f"Protocol {
|
91
|
+
f"Protocol {
|
92
|
+
protocol
|
93
|
+
} is not supported by swiftshadow, please choose between HTTP or HTTPS"
|
91
94
|
)
|
92
95
|
self.protocol: Literal["https", "http"] = protocol
|
93
96
|
|
94
97
|
self.maxproxies: int = maxProxies
|
95
98
|
self.autorotate: bool = autoRotate
|
96
99
|
self.cachePeriod: int = cachePeriod
|
100
|
+
self.configString: str = f"{maxProxies}{''.join(protocol)}{''.join(countries)}"
|
97
101
|
|
98
102
|
if debug:
|
99
103
|
logger.setLevel(DEBUG)
|
@@ -136,11 +140,15 @@ class ProxyInterface:
|
|
136
140
|
pickled_bytes = await cacheFile.read()
|
137
141
|
cache: CacheData = loads(pickled_bytes)
|
138
142
|
|
139
|
-
if
|
143
|
+
if self.configString != cache.configString:
|
144
|
+
logger.info("Cache Invalid due to configuration changes.")
|
145
|
+
elif not checkExpiry(cache.expiryIn):
|
140
146
|
self.proxies = cache.proxies
|
141
147
|
logger.info("Loaded proxies from cache.")
|
142
148
|
logger.debug(
|
143
|
-
f"Cache with {len(cache.proxies)} proxies, expire in {
|
149
|
+
f"Cache with {len(cache.proxies)} proxies, expire in {
|
150
|
+
cache.expiryIn
|
151
|
+
}"
|
144
152
|
)
|
145
153
|
self.current = self.proxies[0]
|
146
154
|
self.cacheExpiry = cache.expiryIn
|
@@ -162,7 +170,9 @@ class ProxyInterface:
|
|
162
170
|
self.countries, self.protocol
|
163
171
|
)
|
164
172
|
logger.debug(
|
165
|
-
f"{len(providerProxies)} proxies from {
|
173
|
+
f"{len(providerProxies)} proxies from {
|
174
|
+
provider.providerFunction.__name__
|
175
|
+
}"
|
166
176
|
)
|
167
177
|
self.proxies.extend(providerProxies)
|
168
178
|
|
@@ -170,14 +180,16 @@ class ProxyInterface:
|
|
170
180
|
break
|
171
181
|
|
172
182
|
if len(self.proxies) == 0:
|
173
|
-
|
183
|
+
if self.protocol == "https":
|
184
|
+
raise ValueError("No proxies were found for the current filter settings. Tip: https proxies can be rare; recommend setting protocol to http")
|
185
|
+
raise ValueError("No proxies were found for the current filter settings.")
|
174
186
|
|
175
187
|
async with aiofiles.open(
|
176
188
|
self.cacheFolderPath.joinpath("swiftshadow.pickle"), "wb+"
|
177
189
|
) as cacheFile:
|
178
190
|
cacheExpiry = getExpiry(self.cachePeriod)
|
179
191
|
self.cacheExpiry = cacheExpiry
|
180
|
-
cache = CacheData(cacheExpiry, self.proxies)
|
192
|
+
cache = CacheData(cacheExpiry, self.configString, self.proxies)
|
181
193
|
pickled_bytes = dumps(cache)
|
182
194
|
_ = await cacheFile.write(pickled_bytes)
|
183
195
|
self.current = self.proxies[0]
|
@@ -199,11 +211,15 @@ class ProxyInterface:
|
|
199
211
|
) as cacheFile:
|
200
212
|
cache: CacheData = load(cacheFile)
|
201
213
|
|
202
|
-
if
|
214
|
+
if self.configString != cache.configString:
|
215
|
+
logger.info("Cache Invalid due to configuration changes.")
|
216
|
+
elif not checkExpiry(cache.expiryIn):
|
203
217
|
self.proxies = cache.proxies
|
204
218
|
logger.info("Loaded proxies from cache.")
|
205
219
|
logger.debug(
|
206
|
-
f"Cache with {len(cache.proxies)} proxies, expire in {
|
220
|
+
f"Cache with {len(cache.proxies)} proxies, expire in {
|
221
|
+
cache.expiryIn
|
222
|
+
}"
|
207
223
|
)
|
208
224
|
self.current = self.proxies[0]
|
209
225
|
logger.debug(f"Cache set to expire at {cache.expiryIn}")
|
@@ -225,7 +241,9 @@ class ProxyInterface:
|
|
225
241
|
provider.providerFunction(self.countries, self.protocol)
|
226
242
|
)
|
227
243
|
logger.debug(
|
228
|
-
f"{len(providerProxies)} proxies from {
|
244
|
+
f"{len(providerProxies)} proxies from {
|
245
|
+
provider.providerFunction.__name__
|
246
|
+
}"
|
229
247
|
)
|
230
248
|
self.proxies.extend(providerProxies)
|
231
249
|
|
@@ -233,14 +251,14 @@ class ProxyInterface:
|
|
233
251
|
break
|
234
252
|
|
235
253
|
if len(self.proxies) == 0:
|
236
|
-
raise ValueError("No proxies
|
254
|
+
raise ValueError("No proxies were found for the current filter settings.")
|
237
255
|
|
238
256
|
with open(
|
239
257
|
self.cacheFolderPath.joinpath("swiftshadow.pickle"), "wb+"
|
240
258
|
) as cacheFile:
|
241
259
|
cacheExpiry = getExpiry(self.cachePeriod)
|
242
260
|
self.cacheExpiry = cacheExpiry
|
243
|
-
cache = CacheData(cacheExpiry, self.proxies)
|
261
|
+
cache = CacheData(cacheExpiry, self.configString, self.proxies)
|
244
262
|
dump(cache, cacheFile)
|
245
263
|
self.current = self.proxies[0]
|
246
264
|
|
swiftshadow/helpers.py
CHANGED
@@ -4,6 +4,7 @@ from typing import Literal
|
|
4
4
|
from requests import get
|
5
5
|
|
6
6
|
from swiftshadow.models import Proxy
|
7
|
+
from swiftshadow.validator import validate_proxies
|
7
8
|
|
8
9
|
|
9
10
|
def checkProxy(proxy):
|
@@ -36,3 +37,12 @@ def plaintextToProxies(text: str, protocol: Literal["http", "https"]) -> list[Pr
|
|
36
37
|
proxy = Proxy(ip=ip, port=int(port), protocol=protocol)
|
37
38
|
proxies.append(proxy)
|
38
39
|
return proxies
|
40
|
+
|
41
|
+
|
42
|
+
async def GenericPlainTextProxyProvider(
|
43
|
+
url: str, protocol: Literal["http", "https"] = "http"
|
44
|
+
) -> list[Proxy]:
|
45
|
+
raw: str = get(url).text
|
46
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol=protocol)
|
47
|
+
results = await validate_proxies(proxies)
|
48
|
+
return results
|
swiftshadow/models.py
CHANGED
@@ -46,10 +46,12 @@ class CacheData:
|
|
46
46
|
|
47
47
|
Attributes:
|
48
48
|
expiryIn: Expiry date object.
|
49
|
+
configString: Configuration String for the ProxyInterface this cache was created.
|
49
50
|
proxies: Proxies to head.
|
50
51
|
"""
|
51
52
|
|
52
53
|
expiryIn: datetime
|
54
|
+
configString: str
|
53
55
|
proxies: list[Proxy]
|
54
56
|
|
55
57
|
|
swiftshadow/providers.py
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
from typing import Literal
|
2
|
+
import aiohttp
|
2
3
|
|
3
4
|
from requests import get
|
4
5
|
|
5
|
-
from swiftshadow.helpers import
|
6
|
+
from swiftshadow.helpers import GenericPlainTextProxyProvider
|
6
7
|
from swiftshadow.models import Provider, Proxy
|
8
|
+
from asyncio import create_task, gather
|
7
9
|
from swiftshadow.types import MonosansProxyDict
|
8
10
|
from swiftshadow.validator import validate_proxies
|
11
|
+
from lxml import etree
|
9
12
|
|
10
13
|
|
11
14
|
async def Monosans(
|
@@ -20,6 +23,10 @@ async def Monosans(
|
|
20
23
|
for proxy_dict in proxy_dicts:
|
21
24
|
if proxy_dict["protocol"] != protocol:
|
22
25
|
continue
|
26
|
+
if ("country" not in proxy_dict["geolocation"].keys() # Avoid errors where geolocation is none
|
27
|
+
and len(countries) != 0
|
28
|
+
):
|
29
|
+
continue
|
23
30
|
if (
|
24
31
|
len(countries) != 0
|
25
32
|
and proxy_dict["geolocation"]["country"]["iso_code"] not in countries
|
@@ -38,11 +45,10 @@ async def Monosans(
|
|
38
45
|
async def Thespeedx(
|
39
46
|
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
40
47
|
):
|
41
|
-
|
42
|
-
"https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt"
|
43
|
-
|
44
|
-
|
45
|
-
results = await validate_proxies(proxies)
|
48
|
+
results = await GenericPlainTextProxyProvider(
|
49
|
+
url="https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt",
|
50
|
+
protocol="http",
|
51
|
+
)
|
46
52
|
return results
|
47
53
|
|
48
54
|
|
@@ -83,63 +89,83 @@ async def GoodProxy(
|
|
83
89
|
async def OpenProxyList(
|
84
90
|
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
85
91
|
):
|
86
|
-
|
87
|
-
|
88
|
-
|
92
|
+
results = await GenericPlainTextProxyProvider(
|
93
|
+
"https://raw.githubusercontent.com/roosterkid/openproxylist/refs/heads/main/HTTPS_RAW.txt",
|
94
|
+
"http",
|
95
|
+
)
|
89
96
|
return results
|
90
97
|
|
91
98
|
|
92
99
|
async def MuRongPIG(
|
93
100
|
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
94
101
|
):
|
95
|
-
|
96
|
-
"https://raw.githubusercontent.com/MuRongPIG/Proxy-Master/refs/heads/main/http_checked.txt"
|
97
|
-
|
98
|
-
|
99
|
-
results = await validate_proxies(proxies)
|
100
|
-
return results
|
101
|
-
|
102
|
-
|
103
|
-
async def KangProxy(
|
104
|
-
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
105
|
-
):
|
106
|
-
raw = get(
|
107
|
-
f"https://github.com/officialputuid/KangProxy/raw/refs/heads/KangProxy/{protocol}/{protocol}.txt"
|
108
|
-
).text
|
109
|
-
proxies: list[Proxy] = plaintextToProxies(raw, protocol=protocol)
|
110
|
-
results = await validate_proxies(proxies)
|
102
|
+
results = await GenericPlainTextProxyProvider(
|
103
|
+
"https://raw.githubusercontent.com/MuRongPIG/Proxy-Master/refs/heads/main/http_checked.txt",
|
104
|
+
"http",
|
105
|
+
)
|
111
106
|
return results
|
112
107
|
|
113
108
|
|
114
109
|
async def Mmpx12(
|
115
110
|
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
116
111
|
):
|
117
|
-
|
118
|
-
|
119
|
-
).text
|
120
|
-
proxies: list[Proxy] = plaintextToProxies(raw, protocol=protocol)
|
121
|
-
results = await validate_proxies(proxies)
|
112
|
+
url = f"https://github.com/mmpx12/proxy-list/raw/refs/heads/master/{protocol}.txt"
|
113
|
+
results = await GenericPlainTextProxyProvider(url, protocol)
|
122
114
|
return results
|
123
115
|
|
124
116
|
|
125
117
|
async def Anonym0usWork1221(
|
126
118
|
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
127
119
|
):
|
128
|
-
|
129
|
-
|
130
|
-
).text
|
131
|
-
proxies: list[Proxy] = plaintextToProxies(raw, protocol=protocol)
|
132
|
-
results = await validate_proxies(proxies)
|
120
|
+
url = f"https://github.com/Anonym0usWork1221/Free-Proxies/raw/refs/heads/main/proxy_files/{protocol}_proxies.txt"
|
121
|
+
results = await GenericPlainTextProxyProvider(url, protocol)
|
133
122
|
return results
|
134
123
|
|
135
124
|
|
136
|
-
async def
|
125
|
+
async def ProxyDB(
|
137
126
|
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
138
127
|
):
|
139
|
-
|
140
|
-
proxies: list[Proxy] =
|
141
|
-
|
142
|
-
|
128
|
+
base_url = f"https://www.proxydb.net/?protocol={protocol}&sort_column_id=uptime&sort_order_desc=true"
|
129
|
+
proxies: list[Proxy] = []
|
130
|
+
raw = get(base_url).text
|
131
|
+
total = int(
|
132
|
+
raw.split("Showing")[-1].split("total proxies")[0].split("of")[-1].strip()
|
133
|
+
)
|
134
|
+
|
135
|
+
async def parsePage(session: aiohttp.ClientSession, url: str):
|
136
|
+
proxies = []
|
137
|
+
async with session.get(url) as resp:
|
138
|
+
raw = await resp.text()
|
139
|
+
exml = etree.HTML(raw)
|
140
|
+
table = exml.find("body/div/div/table/tbody")
|
141
|
+
rows = iter(table)
|
142
|
+
for row in rows:
|
143
|
+
if len(proxies) > 500:
|
144
|
+
break
|
145
|
+
data = []
|
146
|
+
for td in row[:4]:
|
147
|
+
text = td.text.strip()
|
148
|
+
if text == "":
|
149
|
+
text = list(td)[-1].text
|
150
|
+
data.append(text)
|
151
|
+
if countries != [] and data[-1] not in countries:
|
152
|
+
continue
|
153
|
+
proxy = Proxy(data[0], protocol, data[1])
|
154
|
+
proxies.append(proxy)
|
155
|
+
return proxies
|
156
|
+
|
157
|
+
tasks = []
|
158
|
+
async with aiohttp.ClientSession() as session:
|
159
|
+
for offset in range(0, total, 30):
|
160
|
+
url = base_url + f"&offset={offset}"
|
161
|
+
task = create_task(coro=parsePage(session, url))
|
162
|
+
tasks.append(task)
|
163
|
+
results = await gather(*tasks, return_exceptions=True)
|
164
|
+
for result in results:
|
165
|
+
if isinstance(result, BaseException):
|
166
|
+
continue
|
167
|
+
proxies.extend(result)
|
168
|
+
return proxies
|
143
169
|
|
144
170
|
|
145
171
|
Providers: list[Provider] = [
|
@@ -154,9 +180,6 @@ Providers: list[Provider] = [
|
|
154
180
|
),
|
155
181
|
Provider(providerFunction=Mmpx12, countryFilter=False, protocols=["http", "https"]),
|
156
182
|
Provider(providerFunction=GoodProxy, countryFilter=False, protocols=["http"]),
|
157
|
-
Provider(
|
158
|
-
providerFunction=KangProxy, countryFilter=False, protocols=["http", "https"]
|
159
|
-
),
|
160
|
-
Provider(providerFunction=ProxySpace, countryFilter=False, protocols=["http"]),
|
161
183
|
Provider(providerFunction=OpenProxyList, countryFilter=False, protocols=["http"]),
|
184
|
+
Provider(providerFunction=ProxyDB, countryFilter=True, protocols=["http", "https"]),
|
162
185
|
]
|
swiftshadow/validator.py
CHANGED
@@ -42,21 +42,25 @@ async def get_host_ip(async_session: aiohttp.ClientSession) -> str | None:
|
|
42
42
|
return ip
|
43
43
|
|
44
44
|
|
45
|
-
async def check_proxy(
|
45
|
+
async def check_proxy(
|
46
|
+
async_session: aiohttp.ClientSession, proxy: Proxy, checker: str
|
47
|
+
) -> str:
|
46
48
|
"""
|
47
|
-
Check one proxy
|
49
|
+
Check one proxy object.
|
48
50
|
|
49
51
|
Args:
|
50
52
|
async_session: aiohttp client session object
|
51
53
|
proxy: Proxy Object
|
54
|
+
checker: Proxy checker API.
|
52
55
|
|
53
56
|
Returns:
|
54
57
|
text: API response text
|
55
58
|
"""
|
56
59
|
async with async_session.get(
|
57
|
-
url=f"{proxy.protocol}://
|
60
|
+
url=f"{proxy.protocol}://{checker}",
|
58
61
|
proxy=proxy.as_string(),
|
59
|
-
timeout=
|
62
|
+
timeout=5,
|
63
|
+
ssl=False,
|
60
64
|
) as response:
|
61
65
|
text = await response.text()
|
62
66
|
return text
|
@@ -73,16 +77,33 @@ async def validate_proxies(proxies: list[Proxy]) -> list[Proxy]:
|
|
73
77
|
working_proxies: List of working Proxies
|
74
78
|
"""
|
75
79
|
working_proxies: list[Proxy] = []
|
76
|
-
|
80
|
+
checkers = [
|
81
|
+
"checkip.amazonaws.com",
|
82
|
+
"ipinfo.io/ip",
|
83
|
+
"api.ipify.org/",
|
84
|
+
"whatsmyip.dev/api/ip",
|
85
|
+
"ip4.anysrc.net/banner",
|
86
|
+
"api4.my-ip.io/v2/ip.txt",
|
87
|
+
"api.myip.la",
|
88
|
+
"api.seeip.org",
|
89
|
+
"ips.im/api",
|
90
|
+
"ifconfig.me/ip",
|
91
|
+
"myip.expert/api/",
|
92
|
+
"checkip.info/ip",
|
93
|
+
"api.myip.com",
|
94
|
+
]
|
95
|
+
total_checkers = len(checkers)
|
96
|
+
tcp_connection = aiohttp.TCPConnector(limit=100)
|
97
|
+
async with aiohttp.ClientSession(connector=tcp_connection) as async_session:
|
77
98
|
tasks = []
|
78
99
|
|
79
100
|
host_task = asyncio.create_task(coro=get_host_ip(async_session))
|
80
101
|
tasks.append(host_task)
|
81
102
|
|
82
|
-
for proxy in proxies:
|
83
|
-
|
103
|
+
for idx, proxy in enumerate(proxies):
|
104
|
+
checker = checkers[idx % total_checkers]
|
105
|
+
task = asyncio.create_task(coro=check_proxy(async_session, proxy, checker))
|
84
106
|
tasks.append(task)
|
85
|
-
|
86
107
|
results = await asyncio.gather(*tasks, return_exceptions=True)
|
87
108
|
host_ip = results[0]
|
88
109
|
results = results[1:]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: swiftshadow
|
3
|
-
Version: 2.1
|
3
|
+
Version: 2.2.1
|
4
4
|
Summary: Free IP Proxy rotator for python
|
5
5
|
Author-email: sachin-sankar <mail.sachinsankar@gmail.com>
|
6
6
|
License-File: LICENSE
|
@@ -8,6 +8,7 @@ Requires-Python: >=3.12
|
|
8
8
|
Requires-Dist: aiofiles>=24.1.0
|
9
9
|
Requires-Dist: aiohttp>=3.11.11
|
10
10
|
Requires-Dist: appdirs>=1.4.4
|
11
|
+
Requires-Dist: lxml>=6.0.0
|
11
12
|
Requires-Dist: requests>=2.32.3
|
12
13
|
Description-Content-Type: text/markdown
|
13
14
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
swiftshadow/__init__.py,sha256=oxJDmG0YO0XyYGQpa9V_o38lZnoie7U_d4Ik_h46UXs,922
|
2
|
+
swiftshadow/cache.py,sha256=Mg8xsD6K3K012sILBwD2EZH6CE5kWCQNKCfZ5yadalI,800
|
3
|
+
swiftshadow/classes.py,sha256=hXAyvRuGXDvj_TsZxJ-bapK0pL82lhZUBGQZbQiGWN0,12280
|
4
|
+
swiftshadow/exceptions.py,sha256=qu4eXyrkWD9qd4HCIR-8vRfVcqLlTupo4sD72alCdug,129
|
5
|
+
swiftshadow/helpers.py,sha256=b8my66sBw_lTVLaKu4SaGjYQqEfIaStsuZlmK9Pmy5Y,1294
|
6
|
+
swiftshadow/models.py,sha256=rHOuOFc6UYCI8L2pwxAbvS3Fj0Ag89cHod0rt7kQ2Vc,1790
|
7
|
+
swiftshadow/providers.py,sha256=6H-PoXTCQUB7Vop0Wu7DBfMhwiYCvXCF1u_iCM7NcU4,6546
|
8
|
+
swiftshadow/types.py,sha256=Alyw3n54OESX1vSR-0kTvpYTlJ8LKfy5J9WZbtglHpE,894
|
9
|
+
swiftshadow/validator.py,sha256=3qE-99uljtbin1125uOgqAjnLRjuIgNYO5iiUAmaBC8,3102
|
10
|
+
swiftshadow-2.2.1.dist-info/METADATA,sha256=4w-4O9PpR8nCpMVihakZrUNBIKH6QhCNq6OggQOpcVk,3320
|
11
|
+
swiftshadow-2.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
+
swiftshadow-2.2.1.dist-info/entry_points.txt,sha256=yMj0uEagcmXK2dmMmNXWebTpTT9j5K03oaRrd2wkyLA,49
|
13
|
+
swiftshadow-2.2.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
+
swiftshadow-2.2.1.dist-info/RECORD,,
|
@@ -1,14 +0,0 @@
|
|
1
|
-
swiftshadow/__init__.py,sha256=oxJDmG0YO0XyYGQpa9V_o38lZnoie7U_d4Ik_h46UXs,922
|
2
|
-
swiftshadow/cache.py,sha256=Mg8xsD6K3K012sILBwD2EZH6CE5kWCQNKCfZ5yadalI,800
|
3
|
-
swiftshadow/classes.py,sha256=nTR_zykns2oxJ4Bj2UXxoXmLqNOMtkLqy17p_LH8odc,11423
|
4
|
-
swiftshadow/exceptions.py,sha256=qu4eXyrkWD9qd4HCIR-8vRfVcqLlTupo4sD72alCdug,129
|
5
|
-
swiftshadow/helpers.py,sha256=kC5PvfvDCQwigAmfkxlhb4PhcmgdCNpJksMiqyx9lU4,960
|
6
|
-
swiftshadow/models.py,sha256=YyfZV98tPdLnF1O3WmTNUNoK4t0GuchfEftzjiM03ck,1678
|
7
|
-
swiftshadow/providers.py,sha256=Z_NEOlMx0rr1Z5rfz-rA1kQ4YHKGRuI65jBxMGOyJkE,5660
|
8
|
-
swiftshadow/types.py,sha256=Alyw3n54OESX1vSR-0kTvpYTlJ8LKfy5J9WZbtglHpE,894
|
9
|
-
swiftshadow/validator.py,sha256=z0dmRKxhvPETSXfC2hTImL0t8pw0zjSYIhUaDMJcJhU,2469
|
10
|
-
swiftshadow-2.1.0.dist-info/METADATA,sha256=NTPUMBc5xlCEkcryOEC81Au_MCD8JPO8QxrhkEDo7AM,3293
|
11
|
-
swiftshadow-2.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
-
swiftshadow-2.1.0.dist-info/entry_points.txt,sha256=yMj0uEagcmXK2dmMmNXWebTpTT9j5K03oaRrd2wkyLA,49
|
13
|
-
swiftshadow-2.1.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
-
swiftshadow-2.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|