Kekik 1.6.9__tar.gz → 1.7.1__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.
Files changed (48) hide show
  1. {kekik-1.6.9 → kekik-1.7.1}/Kekik/cache.py +155 -55
  2. {kekik-1.6.9 → kekik-1.7.1}/Kekik.egg-info/PKG-INFO +1 -1
  3. {kekik-1.6.9 → kekik-1.7.1}/PKG-INFO +1 -1
  4. {kekik-1.6.9 → kekik-1.7.1}/setup.py +1 -1
  5. {kekik-1.6.9 → kekik-1.7.1}/Kekik/BIST.py +0 -0
  6. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Domain2IP.py +0 -0
  7. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Nesne.py +0 -0
  8. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Sifreleme/AESManager.py +0 -0
  9. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Sifreleme/CryptoJS.py +0 -0
  10. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Sifreleme/HexCodec.py +0 -0
  11. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Sifreleme/NaysHash.py +0 -0
  12. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Sifreleme/Packer.py +0 -0
  13. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Sifreleme/StringCodec.py +0 -0
  14. {kekik-1.6.9 → kekik-1.7.1}/Kekik/Sifreleme/__init__.py +0 -0
  15. {kekik-1.6.9 → kekik-1.7.1}/Kekik/__init__.py +0 -0
  16. {kekik-1.6.9 → kekik-1.7.1}/Kekik/cli.py +0 -0
  17. {kekik-1.6.9 → kekik-1.7.1}/Kekik/csv2dict.py +0 -0
  18. {kekik-1.6.9 → kekik-1.7.1}/Kekik/dict2csv.py +0 -0
  19. {kekik-1.6.9 → kekik-1.7.1}/Kekik/dict2json.py +0 -0
  20. {kekik-1.6.9 → kekik-1.7.1}/Kekik/dosya2set.py +0 -0
  21. {kekik-1.6.9 → kekik-1.7.1}/Kekik/dosya_indir.py +0 -0
  22. {kekik-1.6.9 → kekik-1.7.1}/Kekik/hwid_kontrol.py +0 -0
  23. {kekik-1.6.9 → kekik-1.7.1}/Kekik/kisi_ver/__init__.py +0 -0
  24. {kekik-1.6.9 → kekik-1.7.1}/Kekik/kisi_ver/biyografiler.py +0 -0
  25. {kekik-1.6.9 → kekik-1.7.1}/Kekik/kisi_ver/isimler.py +0 -0
  26. {kekik-1.6.9 → kekik-1.7.1}/Kekik/kisi_ver/soyisimler.py +0 -0
  27. {kekik-1.6.9 → kekik-1.7.1}/Kekik/link_islemleri.py +0 -0
  28. {kekik-1.6.9 → kekik-1.7.1}/Kekik/list2html.py +0 -0
  29. {kekik-1.6.9 → kekik-1.7.1}/Kekik/liste_fetis.py +0 -0
  30. {kekik-1.6.9 → kekik-1.7.1}/Kekik/mail_gonder.py +0 -0
  31. {kekik-1.6.9 → kekik-1.7.1}/Kekik/okunabilir_byte.py +0 -0
  32. {kekik-1.6.9 → kekik-1.7.1}/Kekik/proxy_ver.py +0 -0
  33. {kekik-1.6.9 → kekik-1.7.1}/Kekik/qr_ver.py +0 -0
  34. {kekik-1.6.9 → kekik-1.7.1}/Kekik/ses_fetis.py +0 -0
  35. {kekik-1.6.9 → kekik-1.7.1}/Kekik/slugify.py +0 -0
  36. {kekik-1.6.9 → kekik-1.7.1}/Kekik/terminal_baslik.py +0 -0
  37. {kekik-1.6.9 → kekik-1.7.1}/Kekik/txt_fetis.py +0 -0
  38. {kekik-1.6.9 → kekik-1.7.1}/Kekik/unicode_tr.py +0 -0
  39. {kekik-1.6.9 → kekik-1.7.1}/Kekik/zaman_donustur.py +0 -0
  40. {kekik-1.6.9 → kekik-1.7.1}/Kekik.egg-info/SOURCES.txt +0 -0
  41. {kekik-1.6.9 → kekik-1.7.1}/Kekik.egg-info/dependency_links.txt +0 -0
  42. {kekik-1.6.9 → kekik-1.7.1}/Kekik.egg-info/entry_points.txt +0 -0
  43. {kekik-1.6.9 → kekik-1.7.1}/Kekik.egg-info/requires.txt +0 -0
  44. {kekik-1.6.9 → kekik-1.7.1}/Kekik.egg-info/top_level.txt +0 -0
  45. {kekik-1.6.9 → kekik-1.7.1}/LICENSE +0 -0
  46. {kekik-1.6.9 → kekik-1.7.1}/MANIFEST.in +0 -0
  47. {kekik-1.6.9 → kekik-1.7.1}/README.md +0 -0
  48. {kekik-1.6.9 → kekik-1.7.1}/setup.cfg +0 -0
@@ -1,25 +1,94 @@
1
1
  # ! https://github.com/Fatal1ty/aiocached
2
2
 
3
- import asyncio
3
+ from .cli import konsol
4
4
  from functools import wraps
5
- from time import time
5
+ from time import time, sleep
6
6
  from hashlib import md5
7
7
  from urllib.parse import urlencode
8
+ import asyncio, threading
9
+
10
+ # -----------------------------------------------------
11
+ # Yardımcı Fonksiyonlar
12
+ # -----------------------------------------------------
8
13
 
9
14
  UNLIMITED = None
10
15
 
11
- class Cache:
16
+ def normalize_for_key(value):
12
17
  """
13
- Basit in-memory cache yapısı.
14
- TTL (time-to-live) süresi dolan veriler otomatik olarak temizlenir (get/erişim anında kontrol edilir).
18
+ Cache key oluşturma amacıyla verilen değeri normalize eder.
19
+ - Basit tipler (int, float, str, bool, None) direk kullanılır.
20
+ - dict: Anahtarları sıralı olarak normalize eder.
21
+ - list/tuple: Elemanları normalize eder.
22
+ - Diğer: Sadece sınıf ismi kullanılır.
15
23
  """
24
+ if isinstance(value, (int, float, str, bool, type(None))):
25
+ return value
26
+
27
+ elif isinstance(value, dict):
28
+ return {k: normalize_for_key(value[k]) for k in sorted(value)}
29
+
30
+ elif isinstance(value, (list, tuple)):
31
+ return [normalize_for_key(item) for item in value]
32
+
33
+ else:
34
+ return value.__class__.__name__
35
+
36
+ def simple_cache_key(func, args, kwargs) -> str:
37
+ """
38
+ Fonksiyonun tam adı ve parametrelerini kullanarak bir cache key oluşturur.
39
+ Oluşturulan stringin sonuna MD5 hash eklenir.
40
+ """
41
+ base_key = f"{func.__module__}.{func.__qualname__}"
42
+
43
+ if args:
44
+ norm_args = [normalize_for_key(arg) for arg in args]
45
+ base_key += f"|{norm_args}"
46
+
47
+ if kwargs:
48
+ norm_kwargs = {k: normalize_for_key(v) for k, v in kwargs.items()}
49
+ base_key += f"|{str(sorted(norm_kwargs.items()))}"
50
+
51
+ hashed = md5(base_key.encode('utf-8')).hexdigest()
52
+ return f"{base_key}" # |{hashed}
53
+
54
+ async def make_cache_key(func, args, kwargs, is_fastapi=False) -> str:
55
+ """
56
+ Cache key'ini oluşturur.
57
+ - is_fastapi=False ise simple_cache_key() kullanılır.
58
+ - True ise FastAPI Request nesnesine göre özel key oluşturulur.
59
+ """
60
+ if not is_fastapi:
61
+ return simple_cache_key(func, args, kwargs)
62
+
63
+ # FastAPI: request ilk argüman ya da kwargs'dan alınır
64
+ request = args[0] if args else kwargs.get("request")
65
+
66
+ if request.method == "GET":
67
+ # Eğer query_params boşsa {} olarak ayarla
68
+ veri = dict(request.query_params) if request.query_params else {}
69
+ else:
70
+ try:
71
+ veri = await request.json()
72
+ except Exception:
73
+ form_data = await request.form()
74
+ veri = dict(form_data.items())
75
+
76
+ args_hash = md5(urlencode(veri).encode()).hexdigest() if veri else ""
77
+ return f"{request.url.path}?{veri}"
78
+
79
+
80
+ # -----------------------------------------------------
81
+ # In-Memory (RAM) Cache
82
+ # -----------------------------------------------------
83
+
84
+ class Cache:
16
85
  def __init__(self, ttl=UNLIMITED):
17
- self._data = {}
18
86
  self._ttl = ttl
87
+ self._data = {}
19
88
  self._times = {}
20
89
 
21
90
  def _is_expired(self, key):
22
- """Belirtilen key'in süresi dolduysa True döner."""
91
+ """Belirtilen key'in süresi dolmuşsa True döner."""
23
92
  if self._ttl is UNLIMITED:
24
93
  return False
25
94
 
@@ -27,22 +96,57 @@ class Cache:
27
96
 
28
97
  return timestamp is not None and (time() - timestamp > self._ttl)
29
98
 
99
+
100
+ class SyncCache(Cache):
101
+ """
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.
105
+ """
106
+ def __init__(self, ttl=UNLIMITED, cleanup_interval=60 * 60):
107
+ super().__init__(ttl)
108
+
109
+ # TTL sınırsız değilse, cleanup_interval ile ttl'den büyük olanı kullanıyoruz.
110
+ self._cleanup_interval = max(ttl, cleanup_interval) if ttl is not UNLIMITED else cleanup_interval
111
+ self._lock = threading.RLock()
112
+
113
+ # Arka planda çalışan ve periyodik olarak expired entry'leri temizleyen thread başlatılıyor.
114
+ self._cleanup_thread = threading.Thread(target=self._auto_cleanup, daemon=True)
115
+ self._cleanup_thread.start()
116
+
117
+ def _auto_cleanup(self):
118
+ """Belirlenen aralıklarla cache içerisindeki süresi dolmuş entry'leri temizler."""
119
+ while True:
120
+ sleep(self._cleanup_interval)
121
+ with self._lock:
122
+ keys = list(self._data.keys())
123
+ for key in keys:
124
+ self.remove_if_expired(key)
125
+
30
126
  def remove_if_expired(self, key):
31
127
  """
32
128
  Eğer key'in cache süresi dolmuşsa, ilgili entry'yi temizler.
129
+ Thread güvenliği sağlamak için lock kullanılır.
33
130
  """
34
- if self._is_expired(key):
35
- self._data.pop(key, None)
36
- self._times.pop(key, None)
131
+ with self._lock:
132
+ if self._is_expired(key):
133
+ self._data.pop(key, None)
134
+ self._times.pop(key, None)
135
+ # konsol.log(f"[red][-] {key}")
37
136
 
38
137
  def __getitem__(self, key):
39
- self.remove_if_expired(key)
40
- return self._data[key]
138
+ with self._lock:
139
+ self.remove_if_expired(key)
140
+ veri = self._data[key]
141
+ # konsol.log(f"[yellow][~] {key}")
142
+ return veri
41
143
 
42
144
  def __setitem__(self, key, value):
43
- self._data[key] = value
44
- if self._ttl is not UNLIMITED:
45
- self._times[key] = time()
145
+ with self._lock:
146
+ self._data[key] = value
147
+ # konsol.log(f"[green][+] {key}")
148
+ if self._ttl is not UNLIMITED:
149
+ self._times[key] = time()
46
150
 
47
151
 
48
152
  class AsyncCache(Cache):
@@ -75,20 +179,33 @@ class AsyncCache(Cache):
75
179
  for key in keys:
76
180
  self.remove_if_expired(key)
77
181
 
182
+ def ensure_cleanup_task(self):
183
+ """Event loop mevcutsa, cleanup task henüz başlatılmadıysa oluştur."""
184
+ if self._cleanup_task is None:
185
+ try:
186
+ self._cleanup_task = asyncio.get_running_loop().create_task(self._auto_cleanup())
187
+ except RuntimeError:
188
+ pass # Yine loop yoksa yapacak bir şey yok
189
+
78
190
  async def get(self, key):
79
191
  """
80
192
  Belirtilen key için cache'de saklanan değeri asenkron olarak döndürür.
81
193
  Eğer key bulunamazsa, ilgili future üzerinden beklemeyi sağlar.
82
194
  """
195
+ self.ensure_cleanup_task()
83
196
  self.remove_if_expired(key)
84
197
 
85
198
  try:
86
- return self._data[key]
199
+ veri = self._data[key]
200
+ # konsol.log(f"[yellow][~] {key}")
201
+ return veri
87
202
  except KeyError as e:
88
203
  future = self.futures.get(key)
89
204
  if future:
90
205
  await future
91
- return future.result()
206
+ veri = future.result()
207
+ # konsol.log(f"[yellow][?] {key}")
208
+ return veri
92
209
 
93
210
  raise e
94
211
 
@@ -97,16 +214,26 @@ class AsyncCache(Cache):
97
214
  Belirtilen key'in süresi dolduysa, cache ve futures içerisinden temizler.
98
215
  """
99
216
  if self._ttl is not UNLIMITED and self._is_expired(key):
217
+ # konsol.log(f"[red][-] {key}")
100
218
  self._data.pop(key, None)
101
219
  self._times.pop(key, None)
102
220
  self.futures.pop(key, None)
103
221
 
222
+ def __setitem__(self, key, value):
223
+ self._data[key] = value
224
+ if self._ttl is not UNLIMITED:
225
+ self._times[key] = time()
226
+
227
+
228
+ # -----------------------------------------------------
229
+ # Fonksiyonun Sonucunu Hesaplayıp Cache'e Yazma
230
+ # -----------------------------------------------------
104
231
 
105
232
  def _sync_maybe_cache(func, key, result, unless):
106
233
  """Senkron sonuç için cache kaydını oluşturur (unless koşuluna bakarak)."""
107
234
  if unless is None or not unless(result):
108
235
  func.__cache[key] = result
109
-
236
+ # konsol.log(f"[green][+] {key}")
110
237
 
111
238
  async def _async_compute_and_cache(func, key, unless, *args, **kwargs):
112
239
  """
@@ -133,6 +260,7 @@ async def _async_compute_and_cache(func, key, unless, *args, **kwargs):
133
260
  # unless koşuluna göre cache'e ekleme yap.
134
261
  if unless is None or not unless(result):
135
262
  cache[key] = result
263
+ # konsol.log(f"[green][+] {key}")
136
264
 
137
265
  return result
138
266
  except Exception as exc:
@@ -142,34 +270,10 @@ async def _async_compute_and_cache(func, key, unless, *args, **kwargs):
142
270
  # İşlem tamamlandığında future'ı temizle.
143
271
  cache.futures.pop(key, None)
144
272
 
145
- async def make_cache_key(args, kwargs, is_fastapi=False):
146
- """
147
- Cache key'ini oluşturur.
148
-
149
- :param is_fastapi (bool): Eğer True ise, ilk argümanın bir FastAPI Request nesnesi olduğu varsayılır.
150
- Bu durumda, cache key, request nesnesinin URL yolunu (request.url.path) ve
151
- isteğe ait verilerden (GET istekleri için query parametreleri; diğer istekler için JSON veya form verileri)
152
- elde edilen verinin URL uyumlu halinin md5 hash'inin birleşiminden oluşturulur.
153
- Böylece, aynı URL ve aynı istek verileri için her seferinde aynı cache key üretilecektir.
154
- Eğer False ise, cache key args ve kwargs değerlerinden, sıralı bir tuple olarak oluşturulur.
155
- """
156
- if not is_fastapi:
157
- return (args, tuple(sorted(kwargs.items())))
158
-
159
- request = args[0] if args else kwargs.get("request")
160
-
161
- if request.method == "GET":
162
- veri = dict(request.query_params) if request.query_params else None
163
- else:
164
- try:
165
- veri = await request.json()
166
- except Exception:
167
- form_data = await request.form()
168
- veri = dict(form_data.items())
169
-
170
- args_hash = md5(urlencode(veri).encode()).hexdigest() if veri else ""
171
- return f"{request.url.path}?{args_hash}"
172
273
 
274
+ # -----------------------------------------------------
275
+ # Dekoratör: kekik_cache
276
+ # -----------------------------------------------------
173
277
 
174
278
  def kekik_cache(ttl=UNLIMITED, unless=None, is_fastapi=False):
175
279
  """
@@ -203,13 +307,11 @@ def kekik_cache(ttl=UNLIMITED, unless=None, is_fastapi=False):
203
307
 
204
308
  def decorator(func):
205
309
  if asyncio.iscoroutinefunction(func):
310
+ func.__cache = AsyncCache(ttl)
311
+
206
312
  @wraps(func)
207
313
  async def async_wrapper(*args, **kwargs):
208
- # Lazy initialization: İlk çağrıda cache oluşturuluyor
209
- if not hasattr(func, "__cache"):
210
- func.__cache = AsyncCache(ttl)
211
-
212
- key = await make_cache_key(args, kwargs, is_fastapi)
314
+ key = await make_cache_key(func, args, kwargs, is_fastapi)
213
315
 
214
316
  try:
215
317
  return await func.__cache.get(key)
@@ -218,13 +320,11 @@ def kekik_cache(ttl=UNLIMITED, unless=None, is_fastapi=False):
218
320
 
219
321
  return async_wrapper
220
322
  else:
323
+ func.__cache = SyncCache(ttl)
324
+
221
325
  @wraps(func)
222
326
  def sync_wrapper(*args, **kwargs):
223
- # Lazy initialization: İlk çağrıda cache oluşturuluyor
224
- if not hasattr(func, "__cache"):
225
- func.__cache = AsyncCache(ttl)
226
-
227
- key = (args, tuple(sorted(kwargs.items())))
327
+ key = simple_cache_key(func, args, kwargs)
228
328
 
229
329
  try:
230
330
  return func.__cache[key]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Kekik
3
- Version: 1.6.9
3
+ Version: 1.7.1
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.6.9
3
+ Version: 1.7.1
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.6.9",
9
+ version = "1.7.1",
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