Kekik 1.7.1__tar.gz → 1.7.2__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.

Potentially problematic release.


This version of Kekik might be problematic. Click here for more details.

Files changed (48) hide show
  1. {kekik-1.7.1 → kekik-1.7.2}/Kekik/cache.py +168 -96
  2. {kekik-1.7.1 → kekik-1.7.2}/Kekik.egg-info/PKG-INFO +1 -1
  3. {kekik-1.7.1 → kekik-1.7.2}/PKG-INFO +1 -1
  4. {kekik-1.7.1 → kekik-1.7.2}/setup.py +1 -1
  5. {kekik-1.7.1 → kekik-1.7.2}/Kekik/BIST.py +0 -0
  6. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Domain2IP.py +0 -0
  7. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Nesne.py +0 -0
  8. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Sifreleme/AESManager.py +0 -0
  9. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Sifreleme/CryptoJS.py +0 -0
  10. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Sifreleme/HexCodec.py +0 -0
  11. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Sifreleme/NaysHash.py +0 -0
  12. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Sifreleme/Packer.py +0 -0
  13. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Sifreleme/StringCodec.py +0 -0
  14. {kekik-1.7.1 → kekik-1.7.2}/Kekik/Sifreleme/__init__.py +0 -0
  15. {kekik-1.7.1 → kekik-1.7.2}/Kekik/__init__.py +0 -0
  16. {kekik-1.7.1 → kekik-1.7.2}/Kekik/cli.py +0 -0
  17. {kekik-1.7.1 → kekik-1.7.2}/Kekik/csv2dict.py +0 -0
  18. {kekik-1.7.1 → kekik-1.7.2}/Kekik/dict2csv.py +0 -0
  19. {kekik-1.7.1 → kekik-1.7.2}/Kekik/dict2json.py +0 -0
  20. {kekik-1.7.1 → kekik-1.7.2}/Kekik/dosya2set.py +0 -0
  21. {kekik-1.7.1 → kekik-1.7.2}/Kekik/dosya_indir.py +0 -0
  22. {kekik-1.7.1 → kekik-1.7.2}/Kekik/hwid_kontrol.py +0 -0
  23. {kekik-1.7.1 → kekik-1.7.2}/Kekik/kisi_ver/__init__.py +0 -0
  24. {kekik-1.7.1 → kekik-1.7.2}/Kekik/kisi_ver/biyografiler.py +0 -0
  25. {kekik-1.7.1 → kekik-1.7.2}/Kekik/kisi_ver/isimler.py +0 -0
  26. {kekik-1.7.1 → kekik-1.7.2}/Kekik/kisi_ver/soyisimler.py +0 -0
  27. {kekik-1.7.1 → kekik-1.7.2}/Kekik/link_islemleri.py +0 -0
  28. {kekik-1.7.1 → kekik-1.7.2}/Kekik/list2html.py +0 -0
  29. {kekik-1.7.1 → kekik-1.7.2}/Kekik/liste_fetis.py +0 -0
  30. {kekik-1.7.1 → kekik-1.7.2}/Kekik/mail_gonder.py +0 -0
  31. {kekik-1.7.1 → kekik-1.7.2}/Kekik/okunabilir_byte.py +0 -0
  32. {kekik-1.7.1 → kekik-1.7.2}/Kekik/proxy_ver.py +0 -0
  33. {kekik-1.7.1 → kekik-1.7.2}/Kekik/qr_ver.py +0 -0
  34. {kekik-1.7.1 → kekik-1.7.2}/Kekik/ses_fetis.py +0 -0
  35. {kekik-1.7.1 → kekik-1.7.2}/Kekik/slugify.py +0 -0
  36. {kekik-1.7.1 → kekik-1.7.2}/Kekik/terminal_baslik.py +0 -0
  37. {kekik-1.7.1 → kekik-1.7.2}/Kekik/txt_fetis.py +0 -0
  38. {kekik-1.7.1 → kekik-1.7.2}/Kekik/unicode_tr.py +0 -0
  39. {kekik-1.7.1 → kekik-1.7.2}/Kekik/zaman_donustur.py +0 -0
  40. {kekik-1.7.1 → kekik-1.7.2}/Kekik.egg-info/SOURCES.txt +0 -0
  41. {kekik-1.7.1 → kekik-1.7.2}/Kekik.egg-info/dependency_links.txt +0 -0
  42. {kekik-1.7.1 → kekik-1.7.2}/Kekik.egg-info/entry_points.txt +0 -0
  43. {kekik-1.7.1 → kekik-1.7.2}/Kekik.egg-info/requires.txt +0 -0
  44. {kekik-1.7.1 → kekik-1.7.2}/Kekik.egg-info/top_level.txt +0 -0
  45. {kekik-1.7.1 → kekik-1.7.2}/LICENSE +0 -0
  46. {kekik-1.7.1 → kekik-1.7.2}/MANIFEST.in +0 -0
  47. {kekik-1.7.1 → kekik-1.7.2}/README.md +0 -0
  48. {kekik-1.7.1 → kekik-1.7.2}/setup.cfg +0 -0
@@ -1,22 +1,26 @@
1
- # ! https://github.com/Fatal1ty/aiocached
1
+ # Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.
2
2
 
3
3
  from .cli import konsol
4
4
  from functools import wraps
5
- from time import time, sleep
6
5
  from hashlib import md5
7
6
  from urllib.parse import urlencode
8
- import asyncio, threading
7
+ import time
8
+ import threading
9
+ import asyncio
10
+ import pickle
11
+
12
+ # Redis için asenkron client (Redis yoksa fallback yapılacak)
13
+ import redis.asyncio as redis
9
14
 
10
15
  # -----------------------------------------------------
11
- # Yardımcı Fonksiyonlar
16
+ # Sabitler ve Yardımcı Fonksiyonlar
12
17
  # -----------------------------------------------------
13
-
14
18
  UNLIMITED = None
15
19
 
16
20
  def normalize_for_key(value):
17
21
  """
18
22
  Cache key oluşturma amacıyla verilen değeri normalize eder.
19
- - Basit tipler (int, float, str, bool, None) direk kullanılır.
23
+ - Basit tipler (int, float, str, bool, None) doğrudan kullanılır.
20
24
  - dict: Anahtarları sıralı olarak normalize eder.
21
25
  - list/tuple: Elemanları normalize eder.
22
26
  - Diğer: Sadece sınıf ismi kullanılır.
@@ -36,7 +40,7 @@ def normalize_for_key(value):
36
40
  def simple_cache_key(func, args, kwargs) -> str:
37
41
  """
38
42
  Fonksiyonun tam adı ve parametrelerini kullanarak bir cache key oluşturur.
39
- Oluşturulan stringin sonuna MD5 hash eklenir.
43
+ Oluşturulan stringin sonuna MD5 hash eklenebilir.
40
44
  """
41
45
  base_key = f"{func.__module__}.{func.__qualname__}"
42
46
 
@@ -60,7 +64,7 @@ async def make_cache_key(func, args, kwargs, is_fastapi=False) -> str:
60
64
  if not is_fastapi:
61
65
  return simple_cache_key(func, args, kwargs)
62
66
 
63
- # FastAPI: request ilk argüman ya da kwargs'dan alınır
67
+ # FastAPI: request ilk argümandan ya da kwargs'dan alınır.
64
68
  request = args[0] if args else kwargs.get("request")
65
69
 
66
70
  if request.method == "GET":
@@ -73,56 +77,52 @@ async def make_cache_key(func, args, kwargs, is_fastapi=False) -> str:
73
77
  form_data = await request.form()
74
78
  veri = dict(form_data.items())
75
79
 
80
+ # Eğer "kurek" gibi özel parametreler varsa temizleyebilirsiniz:
81
+ veri.pop("kurek", None)
82
+
76
83
  args_hash = md5(urlencode(veri).encode()).hexdigest() if veri else ""
77
84
  return f"{request.url.path}?{veri}"
78
85
 
79
-
80
86
  # -----------------------------------------------------
81
- # In-Memory (RAM) Cache
87
+ # Senkron Cache (RAM) Sınıfı
82
88
  # -----------------------------------------------------
83
89
 
84
- class Cache:
85
- def __init__(self, ttl=UNLIMITED):
86
- self._ttl = ttl
87
- self._data = {}
88
- self._times = {}
89
-
90
- def _is_expired(self, key):
91
- """Belirtilen key'in süresi dolmuşsa True döner."""
92
- if self._ttl is UNLIMITED:
93
- return False
94
-
95
- timestamp = self._times.get(key)
96
-
97
- return timestamp is not None and (time() - timestamp > self._ttl)
98
-
99
-
100
- class SyncCache(Cache):
90
+ class SyncCache:
101
91
  """
102
- Basit in-memory cache yapısı.
103
- TTL (time-to-live) süresi dolan veriler otomatik olarak temizlenir.
104
- Bu versiyonda, otomatik temizleme işlevselliği bir thread ile sağlanır.
92
+ Senkron fonksiyonlar için basit in-memory cache.
93
+ TTL süresi dolan veriler periyodik olarak arka plan thread’iyle temizlenir.
105
94
  """
106
95
  def __init__(self, ttl=UNLIMITED, cleanup_interval=60 * 60):
107
- super().__init__(ttl)
96
+ self._ttl = ttl
97
+ self._data = {}
98
+ self._times = {}
108
99
 
109
100
  # TTL sınırsız değilse, cleanup_interval ile ttl'den büyük olanı kullanıyoruz.
110
101
  self._cleanup_interval = max(ttl, cleanup_interval) if ttl is not UNLIMITED else cleanup_interval
111
- self._lock = threading.RLock()
112
102
 
113
103
  # Arka planda çalışan ve periyodik olarak expired entry'leri temizleyen thread başlatılıyor.
104
+ self._lock = threading.RLock()
114
105
  self._cleanup_thread = threading.Thread(target=self._auto_cleanup, daemon=True)
115
106
  self._cleanup_thread.start()
116
107
 
117
108
  def _auto_cleanup(self):
118
109
  """Belirlenen aralıklarla cache içerisindeki süresi dolmuş entry'leri temizler."""
119
110
  while True:
120
- sleep(self._cleanup_interval)
111
+ time.sleep(self._cleanup_interval)
121
112
  with self._lock:
122
113
  keys = list(self._data.keys())
123
114
  for key in keys:
124
115
  self.remove_if_expired(key)
125
116
 
117
+ def _is_expired(self, key):
118
+ """Belirtilen key'in süresi dolmuşsa True döner."""
119
+ if self._ttl is UNLIMITED:
120
+ return False
121
+
122
+ timestamp = self._times.get(key)
123
+
124
+ return timestamp is not None and (time.time() - timestamp > self._ttl)
125
+
126
126
  def remove_if_expired(self, key):
127
127
  """
128
128
  Eğer key'in cache süresi dolmuşsa, ilgili entry'yi temizler.
@@ -144,26 +144,30 @@ class SyncCache(Cache):
144
144
  def __setitem__(self, key, value):
145
145
  with self._lock:
146
146
  self._data[key] = value
147
- # konsol.log(f"[green][+] {key}")
148
147
  if self._ttl is not UNLIMITED:
149
- self._times[key] = time()
148
+ self._times[key] = time.time()
150
149
 
150
+ # -----------------------------------------------------
151
+ # Asenkron Cache (In-Memory) ve Redis Hybrid Cache
152
+ # -----------------------------------------------------
151
153
 
152
- class AsyncCache(Cache):
154
+ class AsyncCache:
153
155
  """
154
- Asenkron işlemleri destekleyen cache yapısı.
155
- Aynı key için gelen eşzamanlı çağrılar, futures kullanılarak tek sonuç üzerinden paylaşılır.
156
- Ek olarak, belirli aralıklarla cache’i kontrol edip, süresi dolmuş verileri temizleyen otomatik temizleme görevi çalışır.
156
+ Temel in-memory asenkron cache.
157
157
  """
158
158
  def __init__(self, ttl=UNLIMITED, cleanup_interval=60 * 60):
159
159
  """
160
160
  :param ttl: Her entry için geçerli süre (saniye). Örneğin 3600 saniye 1 saattir.
161
161
  :param cleanup_interval: Otomatik temizleme görevinin kaç saniyede bir çalışacağını belirler.
162
162
  """
163
- super().__init__(ttl)
163
+ self._ttl = ttl
164
+ self._data = {}
165
+ self._times = {}
164
166
  self.futures = {}
165
167
 
168
+ # TTL sınırsız değilse, cleanup_interval ile ttl'den büyük olanı kullanıyoruz.
166
169
  self._cleanup_interval = max(ttl, cleanup_interval) if ttl is not UNLIMITED else cleanup_interval
170
+
167
171
  # Aktif bir event loop varsa otomatik temizlik görevini başlatıyoruz.
168
172
  try:
169
173
  self._cleanup_task = asyncio.get_running_loop().create_task(self._auto_cleanup())
@@ -174,9 +178,7 @@ class AsyncCache(Cache):
174
178
  """Belirlenen aralıklarla cache içerisindeki süresi dolmuş entry'leri temizler."""
175
179
  while True:
176
180
  await asyncio.sleep(self._cleanup_interval)
177
- # _data kopyasını almak, üzerinde dönüp silme yaparken hata almamak için.
178
- keys = list(self._data.keys())
179
- for key in keys:
181
+ for key in list(self._data.keys()):
180
182
  self.remove_if_expired(key)
181
183
 
182
184
  def ensure_cleanup_task(self):
@@ -187,59 +189,137 @@ class AsyncCache(Cache):
187
189
  except RuntimeError:
188
190
  pass # Yine loop yoksa yapacak bir şey yok
189
191
 
192
+ def remove_if_expired(self, key):
193
+ """
194
+ Belirtilen key'in süresi dolduysa, cache ve futures içerisinden temizler.
195
+ """
196
+ if self._ttl is not UNLIMITED:
197
+ t = self._times.get(key)
198
+ if t is not None and (time.time() - t > self._ttl):
199
+ # konsol.log(f"[red][-] {key}")
200
+ self._data.pop(key, None)
201
+ self._times.pop(key, None)
202
+ self.futures.pop(key, None)
203
+
190
204
  async def get(self, key):
191
205
  """
192
206
  Belirtilen key için cache'de saklanan değeri asenkron olarak döndürür.
193
207
  Eğer key bulunamazsa, ilgili future üzerinden beklemeyi sağlar.
194
208
  """
209
+ # Cleanup task'in aktif olduğundan emin olun.
195
210
  self.ensure_cleanup_task()
211
+ # Eğer key'in süresi dolmuşsa, kaldırın.
196
212
  self.remove_if_expired(key)
197
213
 
198
214
  try:
199
- veri = self._data[key]
215
+ # Cache içerisinde key varsa direkt değeri döndür.
216
+ value = self._data[key]
200
217
  # konsol.log(f"[yellow][~] {key}")
201
- return veri
202
- except KeyError as e:
218
+ return value
219
+ except KeyError:
220
+ # Eğer key cache'de yoksa, aynı key ile başlatılmış future varsa onu bekle.
203
221
  future = self.futures.get(key)
204
222
  if future:
205
223
  await future
206
- veri = future.result()
224
+ # Future tamamlandığında sonucu döndür.
225
+ value = future.result()
207
226
  # konsol.log(f"[yellow][?] {key}")
208
- return veri
227
+ return value
228
+ # Eğer future da yoksa, key bulunamadığına dair hata fırlat.
229
+ raise KeyError(key)
209
230
 
210
- raise e
211
-
212
- def remove_if_expired(self, key):
213
- """
214
- Belirtilen key'in süresi dolduysa, cache ve futures içerisinden temizler.
215
- """
216
- if self._ttl is not UNLIMITED and self._is_expired(key):
217
- # konsol.log(f"[red][-] {key}")
218
- self._data.pop(key, None)
219
- self._times.pop(key, None)
220
- self.futures.pop(key, None)
221
-
222
- def __setitem__(self, key, value):
231
+ async def set(self, key, value):
232
+ """Belirtilen key için cache'e değer ekler."""
233
+ self.ensure_cleanup_task()
223
234
  self._data[key] = value
224
235
  if self._ttl is not UNLIMITED:
225
- self._times[key] = time()
236
+ self._times[key] = time.time()
237
+
238
+ class HybridAsyncCache:
239
+ """
240
+ Öncelikle Redis cache kullanılmaya çalışılır.
241
+ Hata durumunda veya Redis erişilemiyorsa in-memory AsyncCache’e geçilir.
242
+ """
243
+ def __init__(self, ttl=UNLIMITED):
244
+ self._ttl = ttl
245
+
246
+ try:
247
+ self.redis = redis.Redis(
248
+ host = "127.0.0.1",
249
+ port = 6379,
250
+ decode_responses = False
251
+ )
252
+ except Exception:
253
+ self.redis = None
254
+
255
+ self.memory = AsyncCache(ttl)
256
+ self.futures = {}
257
+
258
+ async def get(self, key):
259
+ # Eşzamanlı istek yönetimi: aynı key için bir future varsa, direkt bekleyip sonucu döndür.
260
+ if key in self.futures:
261
+ # konsol.log(f"[yellow][?] {key}")
262
+ return await self.futures[key]
263
+
264
+ # İlk önce Redis ile deneyelim
265
+ if self.redis:
266
+ try:
267
+ data = await self.redis.get(key)
268
+ except Exception:
269
+ return await self.memory.get(key)
270
+ if data is not None:
271
+ try:
272
+ result = pickle.loads(data)
273
+ # konsol.log(f"[yellow][~] {key}")
274
+ return result
275
+ except Exception:
276
+ # Deserialize hatası durumunda in-memory cache'ten dene
277
+ return await self.memory.get(key)
278
+ else:
279
+ # Redis'te veri yoksa, in-memory cache'e bak
280
+ return await self.memory.get(key)
281
+ else:
282
+ # Redis kullanılmıyorsa doğrudan in-memory cache'e bak
283
+ return await self.memory.get(key)
226
284
 
285
+ async def set(self, key, value):
286
+ # Önce veriyi pickle etmeyi deniyoruz.
287
+ try:
288
+ ser = pickle.dumps(value)
289
+ except Exception:
290
+ # Serialization hatası durumunda sadece in-memory cache'e yaz
291
+ await self.memory.set(key, value)
292
+ return
293
+
294
+ if self.redis:
295
+ try:
296
+ if self._ttl is not UNLIMITED:
297
+ await self.redis.set(key, ser, ex=self._ttl)
298
+ else:
299
+ await self.redis.set(key, ser)
300
+ return
301
+ except Exception:
302
+ # Redis yazma hatası durumunda in-memory fallback
303
+ await self.memory.set(key, value)
304
+ return
305
+ else:
306
+ # Redis yoksa in-memory cache'e yaz
307
+ await self.memory.set(key, value)
227
308
 
228
309
  # -----------------------------------------------------
229
- # Fonksiyonun Sonucunu Hesaplayıp Cache'e Yazma
310
+ # Cache'e Hesaplanmış Sonucu Yazma Yardımcı Fonksiyonları
230
311
  # -----------------------------------------------------
231
312
 
232
313
  def _sync_maybe_cache(func, key, result, unless):
233
- """Senkron sonuç için cache kaydını oluşturur (unless koşuluna bakarak)."""
314
+ """Senkron fonksiyon sonucu için cache kaydı oluşturur."""
234
315
  if unless is None or not unless(result):
235
316
  func.__cache[key] = result
236
317
  # konsol.log(f"[green][+] {key}")
237
318
 
238
319
  async def _async_compute_and_cache(func, key, unless, *args, **kwargs):
239
320
  """
240
- Asenkron fonksiyon sonucunu hesaplar ve cache'e ekler.
241
- Aynı key için işlem devam ediyorsa, mevcut sonucu bekler.
242
- Sonuç, unless(result) True değilse cache'e eklenir.
321
+ Asenkron fonksiyon sonucunu hesaplar ve cache'e yazar.
322
+ Aynı key için gelen eşzamanlı çağrılar future üzerinden bekletilir.
243
323
  """
244
324
  # __cache'den cache nesnesini alıyoruz.
245
325
  cache = func.__cache
@@ -256,12 +336,12 @@ async def _async_compute_and_cache(func, key, unless, *args, **kwargs):
256
336
  # Asenkron fonksiyonu çalıştır ve sonucu elde et.
257
337
  result = await func(*args, **kwargs)
258
338
  future.set_result(result)
259
-
339
+
260
340
  # unless koşuluna göre cache'e ekleme yap.
261
341
  if unless is None or not unless(result):
262
- cache[key] = result
342
+ await cache.set(key, result)
263
343
  # konsol.log(f"[green][+] {key}")
264
-
344
+
265
345
  return result
266
346
  except Exception as exc:
267
347
  future.cancel()
@@ -270,44 +350,35 @@ async def _async_compute_and_cache(func, key, unless, *args, **kwargs):
270
350
  # İşlem tamamlandığında future'ı temizle.
271
351
  cache.futures.pop(key, None)
272
352
 
273
-
274
353
  # -----------------------------------------------------
275
- # Dekoratör: kekik_cache
354
+ # kekik_cache Dekoratörü (Senkrondan Asenkrona)
276
355
  # -----------------------------------------------------
277
356
 
278
- def kekik_cache(ttl=UNLIMITED, unless=None, is_fastapi=False):
357
+ def kekik_cache(ttl=UNLIMITED, unless=None, is_fastapi=False, use_redis=True):
279
358
  """
280
- Bir fonksiyon veya coroutine'in sonucunu cache'ler.
281
-
282
- Args:
283
- ttl (int, optional): Cachein geçerlilik süresi (saniye).
284
- Eğer `UNLIMITED` ise süresizdir. Varsayılan olarak `UNLIMITED`'dir.
285
- unless (callable, optional): Fonksiyonun sonucunu argüman olarak alan bir callable.
286
- Eğer `True` dönerse, sonuç cache'e alınmaz. Varsayılan olarak `None`'dır.
287
- is_fastapi (bool, optional): Eğer `True` ise, cache key'i oluştururken FastAPI request nesnesine özel şekilde davranır.
288
- Varsayılan olarak `False`'tır.
289
-
290
- Notlar:
291
- -------
292
- Normalde yalnızca Redis cache kullanılmak istenir.
293
- Ancak Redis'e ulaşılamayan durumlarda RAM fallback kullanılır.
294
-
295
- ---
296
-
297
- Örn.:
359
+ Bir fonksiyonun (senkron/asenkron) sonucunu cache'ler.
360
+
361
+ Parametreler:
362
+ - ttl: Cache'in geçerlilik süresi (saniye). UNLIMITED ise süresizdir.
363
+ - unless: Sonuç alınmadan önce çağrılan, True dönerse cache'e alınmaz.
364
+ - is_fastapi: True ise, FastAPI Request nesnesine göre key oluşturur.
365
+ - use_redis: Asenkron fonksiyonlarda Redis kullanımı (Hybrid cache) için True verilebilir.
298
366
 
299
- @kekik_cache(ttl=15, unless=lambda sonuc: bool(sonuc is None))
367
+ Örnek Kullanım:
368
+
369
+ @kekik_cache(ttl=15, unless=lambda sonuc: sonuc is None)
300
370
  async def bakalim(param):
301
- # Burada cache işlemi yapılır.
302
371
  return param
303
372
  """
304
- # Parametresiz kullanıldığında
373
+ # Parametresiz kullanım durumunda
305
374
  if callable(ttl):
306
- return kekik_cache(UNLIMITED, unless=unless, is_fastapi=is_fastapi)(ttl)
375
+ return kekik_cache(UNLIMITED, unless=unless, is_fastapi=is_fastapi, use_redis=use_redis)(ttl)
307
376
 
308
377
  def decorator(func):
309
378
  if asyncio.iscoroutinefunction(func):
310
- func.__cache = AsyncCache(ttl)
379
+ # Asenkron fonksiyonlar için cache türünü seçelim:
380
+
381
+ func.__cache = HybridAsyncCache(ttl) if use_redis else AsyncCache(ttl)
311
382
 
312
383
  @wraps(func)
313
384
  async def async_wrapper(*args, **kwargs):
@@ -320,6 +391,7 @@ def kekik_cache(ttl=UNLIMITED, unless=None, is_fastapi=False):
320
391
 
321
392
  return async_wrapper
322
393
  else:
394
+ # Senkron fonksiyonlar için
323
395
  func.__cache = SyncCache(ttl)
324
396
 
325
397
  @wraps(func)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Kekik
3
- Version: 1.7.1
3
+ Version: 1.7.2
4
4
  Summary: İşlerimizi kolaylaştıracak fonksiyonların el altında durduğu kütüphane..
5
5
  Home-page: https://github.com/keyiflerolsun/Kekik
6
6
  Author: keyiflerolsun
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Kekik
3
- Version: 1.7.1
3
+ Version: 1.7.2
4
4
  Summary: İşlerimizi kolaylaştıracak fonksiyonların el altında durduğu kütüphane..
5
5
  Home-page: https://github.com/keyiflerolsun/Kekik
6
6
  Author: keyiflerolsun
@@ -6,7 +6,7 @@ from io import open
6
6
  setup(
7
7
  # ? Genel Bilgiler
8
8
  name = "Kekik",
9
- version = "1.7.1",
9
+ version = "1.7.2",
10
10
  url = "https://github.com/keyiflerolsun/Kekik",
11
11
  description = "İşlerimizi kolaylaştıracak fonksiyonların el altında durduğu kütüphane..",
12
12
  keywords = ["Kekik", "KekikAkademi", "keyiflerolsun"],
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes