nextpy-framework 1.0.0__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.
Files changed (49) hide show
  1. nextpy/__init__.py +50 -0
  2. nextpy/auth.py +94 -0
  3. nextpy/builder.py +123 -0
  4. nextpy/cli.py +490 -0
  5. nextpy/components/__init__.py +45 -0
  6. nextpy/components/feedback.py +210 -0
  7. nextpy/components/form.py +346 -0
  8. nextpy/components/head.py +167 -0
  9. nextpy/components/hooks_provider.py +64 -0
  10. nextpy/components/image.py +180 -0
  11. nextpy/components/layout.py +206 -0
  12. nextpy/components/link.py +132 -0
  13. nextpy/components/loader.py +65 -0
  14. nextpy/components/toast.py +101 -0
  15. nextpy/components/visual.py +185 -0
  16. nextpy/config.py +75 -0
  17. nextpy/core/__init__.py +21 -0
  18. nextpy/core/builder.py +237 -0
  19. nextpy/core/data_fetching.py +221 -0
  20. nextpy/core/renderer.py +252 -0
  21. nextpy/core/router.py +233 -0
  22. nextpy/core/sync.py +34 -0
  23. nextpy/db.py +121 -0
  24. nextpy/dev_server.py +69 -0
  25. nextpy/dev_tools.py +157 -0
  26. nextpy/errors.py +70 -0
  27. nextpy/hooks.py +348 -0
  28. nextpy/performance.py +78 -0
  29. nextpy/plugins.py +61 -0
  30. nextpy/py.typed +0 -0
  31. nextpy/server/__init__.py +6 -0
  32. nextpy/server/app.py +325 -0
  33. nextpy/server/debug.py +93 -0
  34. nextpy/server/middleware.py +88 -0
  35. nextpy/utils/__init__.py +0 -0
  36. nextpy/utils/cache.py +89 -0
  37. nextpy/utils/email.py +59 -0
  38. nextpy/utils/file_upload.py +65 -0
  39. nextpy/utils/logging.py +52 -0
  40. nextpy/utils/search.py +59 -0
  41. nextpy/utils/seo.py +85 -0
  42. nextpy/utils/validators.py +58 -0
  43. nextpy/websocket.py +76 -0
  44. nextpy_framework-1.0.0.dist-info/METADATA +343 -0
  45. nextpy_framework-1.0.0.dist-info/RECORD +49 -0
  46. nextpy_framework-1.0.0.dist-info/WHEEL +5 -0
  47. nextpy_framework-1.0.0.dist-info/entry_points.txt +2 -0
  48. nextpy_framework-1.0.0.dist-info/licenses/LICENSE +21 -0
  49. nextpy_framework-1.0.0.dist-info/top_level.txt +1 -0
nextpy/hooks.py ADDED
@@ -0,0 +1,348 @@
1
+ """
2
+ React-like Hooks for NextPy State Management
3
+ Implements useState, useEffect, useContext, useReducer, useCallback, useMemo, etc.
4
+ """
5
+
6
+ from typing import Any, Callable, Dict, List, Optional, TypeVar, Generic, Tuple
7
+ from dataclasses import dataclass, field
8
+ from functools import wraps
9
+ import asyncio
10
+
11
+ T = TypeVar('T')
12
+
13
+
14
+ @dataclass
15
+ class HookState:
16
+ """Manages state for a component"""
17
+ values: Dict[str, Any] = field(default_factory=dict)
18
+ effects: Dict[str, Callable] = field(default_factory=dict)
19
+ effect_dependencies: Dict[str, List] = field(default_factory=dict)
20
+ callbacks: Dict[str, Callable] = field(default_factory=dict)
21
+ callback_dependencies: Dict[str, List] = field(default_factory=dict)
22
+
23
+
24
+ class StateManager:
25
+ """Global state manager for all hooks"""
26
+
27
+ _instance = None
28
+ _states: Dict[str, HookState] = {}
29
+ _current_component: Optional[str] = None
30
+ _hook_index: Dict[str, int] = {}
31
+
32
+ def __new__(cls):
33
+ if cls._instance is None:
34
+ cls._instance = super().__new__(cls)
35
+ return cls._instance
36
+
37
+ @classmethod
38
+ def set_component(cls, component_id: Optional[str]):
39
+ """Set current component context"""
40
+ cls._current_component = component_id
41
+ if component_id and component_id not in cls._hook_index:
42
+ cls._hook_index[component_id] = 0
43
+
44
+ @classmethod
45
+ def get_hook_index(cls) -> int:
46
+ """Get current hook index"""
47
+ if not cls._current_component:
48
+ cls._current_component = "default"
49
+ if cls._current_component not in cls._hook_index:
50
+ cls._hook_index[cls._current_component] = 0
51
+ idx = cls._hook_index[cls._current_component]
52
+ cls._hook_index[cls._current_component] += 1
53
+ return idx
54
+
55
+ @classmethod
56
+ def reset_hook_index(cls):
57
+ """Reset hook index for next render"""
58
+ if cls._current_component:
59
+ cls._hook_index[cls._current_component] = 0
60
+
61
+ @classmethod
62
+ def get_state(cls, component_id: str) -> HookState:
63
+ """Get or create state for component"""
64
+ if component_id not in cls._states:
65
+ cls._states[component_id] = HookState()
66
+ return cls._states[component_id]
67
+
68
+
69
+ def useState(initial_value: Any = None) -> Tuple[Any, Callable]:
70
+ """
71
+ React-like useState hook
72
+ Returns (value, setValue) tuple
73
+
74
+ Usage:
75
+ count, set_count = useState(0)
76
+ set_count(count + 1)
77
+ """
78
+ component_id = StateManager._current_component or "default"
79
+ hook_index = StateManager.get_hook_index()
80
+ state = StateManager.get_state(component_id)
81
+
82
+ state_key = f"state_{hook_index}"
83
+
84
+ if state_key not in state.values:
85
+ state.values[state_key] = initial_value
86
+
87
+ def setter(new_value):
88
+ if callable(new_value):
89
+ state.values[state_key] = new_value(state.values[state_key])
90
+ else:
91
+ state.values[state_key] = new_value
92
+
93
+ return state.values[state_key], setter
94
+
95
+
96
+ def useEffect(effect: Callable, dependencies: Optional[List] = None) -> None:
97
+ """
98
+ React-like useEffect hook
99
+ Runs effect function when dependencies change
100
+
101
+ Usage:
102
+ def effect():
103
+ print("Component mounted or deps changed")
104
+ return lambda: print("Cleanup")
105
+
106
+ useEffect(effect, [count])
107
+ """
108
+ component_id = StateManager._current_component or "default"
109
+ hook_index = StateManager.get_hook_index()
110
+ state = StateManager.get_state(component_id)
111
+
112
+ effect_key = f"effect_{hook_index}"
113
+ deps_key = f"deps_{hook_index}"
114
+
115
+ should_run = False
116
+
117
+ if effect_key not in state.effects:
118
+ should_run = True
119
+ elif dependencies is None:
120
+ should_run = True
121
+ elif state.effect_dependencies.get(deps_key) != dependencies:
122
+ should_run = True
123
+
124
+ if should_run:
125
+ state.effects[effect_key] = effect
126
+ state.effect_dependencies[deps_key] = dependencies or []
127
+ effect()
128
+
129
+
130
+ def useContext(context_dict: Dict[str, Any]) -> Dict[str, Any]:
131
+ """
132
+ React-like useContext hook
133
+ Provides context to component
134
+
135
+ Usage:
136
+ user_context = {"user": "John", "role": "admin"}
137
+ context = useContext(user_context)
138
+ """
139
+ return context_dict
140
+
141
+
142
+ def useReducer(reducer: Callable, initial_state: Any) -> Tuple[Any, Callable]:
143
+ """
144
+ React-like useReducer hook
145
+ Returns (state, dispatch) tuple
146
+
147
+ Usage:
148
+ def reducer(state, action):
149
+ if action["type"] == "INCREMENT":
150
+ return state + 1
151
+ return state
152
+
153
+ count, dispatch = useReducer(reducer, 0)
154
+ dispatch({"type": "INCREMENT"})
155
+ """
156
+ component_id = StateManager._current_component or "default"
157
+ hook_index = StateManager.get_hook_index()
158
+ state = StateManager.get_state(component_id)
159
+
160
+ state_key = f"reducer_{hook_index}"
161
+
162
+ if state_key not in state.values:
163
+ state.values[state_key] = initial_state
164
+
165
+ def dispatch(action):
166
+ current_state = state.values[state_key]
167
+ new_state = reducer(current_state, action)
168
+ state.values[state_key] = new_state
169
+
170
+ return state.values[state_key], dispatch
171
+
172
+
173
+ def useCallback(callback: Callable, dependencies: Optional[List[Any]] = None) -> Callable:
174
+ """
175
+ React-like useCallback hook
176
+ Memoizes callback function
177
+
178
+ Usage:
179
+ def on_click():
180
+ print("Clicked")
181
+
182
+ memoized_click = useCallback(on_click, [])
183
+ """
184
+ component_id = StateManager._current_component or "default"
185
+ hook_index = StateManager.get_hook_index()
186
+ state = StateManager.get_state(component_id)
187
+
188
+ callback_key = f"callback_{hook_index}"
189
+ deps_key = f"callback_deps_{hook_index}"
190
+
191
+ if callback_key not in state.callbacks:
192
+ state.callbacks[callback_key] = callback
193
+ state.callback_dependencies[deps_key] = dependencies or []
194
+ elif state.callback_dependencies.get(deps_key) != dependencies:
195
+ state.callbacks[callback_key] = callback
196
+ state.callback_dependencies[deps_key] = dependencies or []
197
+
198
+ return state.callbacks[callback_key]
199
+
200
+
201
+ def useMemo(compute: Callable, dependencies: Optional[List[Any]] = None) -> Any:
202
+ """
203
+ React-like useMemo hook
204
+ Memoizes expensive computations
205
+
206
+ Usage:
207
+ expensive_value = useMemo(lambda: compute_value(count), [count])
208
+ """
209
+ component_id = StateManager._current_component or "default"
210
+ hook_index = StateManager.get_hook_index()
211
+ state = StateManager.get_state(component_id)
212
+
213
+ memo_key = f"memo_{hook_index}"
214
+ deps_key = f"memo_deps_{hook_index}"
215
+
216
+ if memo_key not in state.values:
217
+ state.values[memo_key] = compute()
218
+ state.effect_dependencies[deps_key] = dependencies or []
219
+ elif state.effect_dependencies.get(deps_key) != dependencies:
220
+ state.values[memo_key] = compute()
221
+ state.effect_dependencies[deps_key] = dependencies or []
222
+
223
+ return state.values[memo_key]
224
+
225
+
226
+ def useRef(initial_value: Any = None) -> Dict[str, Any]:
227
+ """
228
+ React-like useRef hook
229
+ Returns a mutable ref object
230
+
231
+ Usage:
232
+ input_ref = useRef()
233
+ input_ref["current"] = some_value
234
+ """
235
+ component_id = StateManager._current_component or "default"
236
+ hook_index = StateManager.get_hook_index()
237
+ state = StateManager.get_state(component_id)
238
+
239
+ ref_key = f"ref_{hook_index}"
240
+
241
+ if ref_key not in state.values:
242
+ state.values[ref_key] = {"current": initial_value}
243
+
244
+ return state.values[ref_key]
245
+
246
+
247
+ class GlobalState(Generic[T]):
248
+ """Global state container for cross-component state"""
249
+
250
+ _subscribers: Dict[str, List[Callable]] = {}
251
+ _values: Dict[str, Any] = {}
252
+
253
+ def __init__(self, key: str, initial_value: T):
254
+ self.key = key
255
+ self._values[key] = initial_value
256
+ if key not in self._subscribers:
257
+ self._subscribers[key] = []
258
+
259
+ def get(self) -> Optional[T]:
260
+ """Get current value"""
261
+ return self._values.get(self.key)
262
+
263
+ def set(self, value: T) -> None:
264
+ """Set new value and notify subscribers"""
265
+ self._values[self.key] = value
266
+ self._notify_subscribers()
267
+
268
+ def subscribe(self, callback: Callable) -> Callable:
269
+ """Subscribe to value changes"""
270
+ self._subscribers[self.key].append(callback)
271
+
272
+ def unsubscribe():
273
+ self._subscribers[self.key].remove(callback)
274
+
275
+ return unsubscribe
276
+
277
+ def _notify_subscribers(self) -> None:
278
+ """Notify all subscribers of changes"""
279
+ for callback in self._subscribers.get(self.key, []):
280
+ callback(self._values[self.key])
281
+
282
+
283
+ def create_context(default_value: Any = None) -> Dict[str, Any]:
284
+ """Create a context object"""
285
+ return {
286
+ "value": default_value,
287
+ "consumers": []
288
+ }
289
+
290
+
291
+ def useGlobalState(key: str, initial_value: Any = None) -> Tuple[Any, Callable]:
292
+ """
293
+ Hook to use global state across components
294
+
295
+ Usage:
296
+ user_state = GlobalState("user", {"name": "John"})
297
+ user, set_user = useGlobalState("user", {"name": "John"})
298
+ """
299
+ if key not in GlobalState._values:
300
+ GlobalState._values[key] = initial_value
301
+ GlobalState._subscribers[key] = []
302
+
303
+ def setter(value):
304
+ GlobalState._values[key] = value
305
+ for callback in GlobalState._subscribers.get(key, []):
306
+ callback(value)
307
+
308
+ return GlobalState._values[key], setter
309
+
310
+
311
+ # Component decorator to set component context
312
+ def component(func: Callable) -> Callable:
313
+ """
314
+ Decorator to wrap component functions with hook support
315
+
316
+ Usage:
317
+ @component
318
+ def MyComponent():
319
+ count, set_count = useState(0)
320
+ return f"Count: {count}"
321
+ """
322
+ @wraps(func)
323
+ def wrapper(*args, **kwargs):
324
+ component_id = f"{func.__name__}_{id(func)}"
325
+ StateManager.set_component(component_id)
326
+ try:
327
+ result = func(*args, **kwargs)
328
+ finally:
329
+ StateManager.reset_hook_index()
330
+ return result
331
+
332
+ return wrapper
333
+
334
+
335
+ __all__ = [
336
+ 'useState',
337
+ 'useEffect',
338
+ 'useContext',
339
+ 'useReducer',
340
+ 'useCallback',
341
+ 'useMemo',
342
+ 'useRef',
343
+ 'GlobalState',
344
+ 'create_context',
345
+ 'useGlobalState',
346
+ 'component',
347
+ 'StateManager',
348
+ ]
nextpy/performance.py ADDED
@@ -0,0 +1,78 @@
1
+ """
2
+ NextPy Performance Optimization
3
+ Decorators and utilities for performance monitoring and optimization
4
+ """
5
+
6
+ import time
7
+ import functools
8
+ from typing import Callable, Any
9
+ import asyncio
10
+
11
+
12
+ def timeit(func: Callable) -> Callable:
13
+ """Decorator to measure execution time"""
14
+ @functools.wraps(func)
15
+ async def async_wrapper(*args, **kwargs):
16
+ start = time.time()
17
+ result = await func(*args, **kwargs)
18
+ elapsed = time.time() - start
19
+ print(f"{func.__name__} took {elapsed:.3f}s")
20
+ return result
21
+
22
+ @functools.wraps(func)
23
+ def sync_wrapper(*args, **kwargs):
24
+ start = time.time()
25
+ result = func(*args, **kwargs)
26
+ elapsed = time.time() - start
27
+ print(f"{func.__name__} took {elapsed:.3f}s")
28
+ return result
29
+
30
+ import inspect
31
+ if inspect.iscoroutinefunction(func):
32
+ return async_wrapper
33
+ return sync_wrapper
34
+
35
+
36
+ def batch_processor(batch_size: int = 100):
37
+ """Process items in batches for performance"""
38
+ def decorator(func: Callable) -> Callable:
39
+ @functools.wraps(func)
40
+ async def wrapper(items: list) -> list:
41
+ results = []
42
+ for i in range(0, len(items), batch_size):
43
+ batch = items[i:i + batch_size]
44
+ batch_results = await asyncio.gather(*[func(item) for item in batch])
45
+ results.extend(batch_results)
46
+ return results
47
+ return wrapper
48
+ return decorator
49
+
50
+
51
+ class RateLimiter:
52
+ """Simple rate limiter"""
53
+
54
+ def __init__(self, max_requests: int = 100, window_seconds: int = 60):
55
+ self.max_requests = max_requests
56
+ self.window_seconds = window_seconds
57
+ self.requests: Dict[str, list] = {}
58
+
59
+ def is_allowed(self, key: str) -> bool:
60
+ """Check if request is allowed"""
61
+ now = time.time()
62
+ cutoff = now - self.window_seconds
63
+
64
+ if key not in self.requests:
65
+ self.requests[key] = []
66
+
67
+ # Remove old requests
68
+ self.requests[key] = [req_time for req_time in self.requests[key] if req_time > cutoff]
69
+
70
+ if len(self.requests[key]) < self.max_requests:
71
+ self.requests[key].append(now)
72
+ return True
73
+
74
+ return False
75
+
76
+
77
+ # Global rate limiter
78
+ rate_limiter = RateLimiter()
nextpy/plugins.py ADDED
@@ -0,0 +1,61 @@
1
+ """
2
+ NextPy Plugin System - Extend framework functionality
3
+ """
4
+
5
+ from typing import Callable, Dict, Any, List
6
+ from abc import ABC, abstractmethod
7
+
8
+
9
+ class Plugin(ABC):
10
+ """Base plugin class"""
11
+
12
+ name: str = "Plugin"
13
+ version: str = "1.0.0"
14
+
15
+ @abstractmethod
16
+ def on_init(self, app):
17
+ """Called when app initializes"""
18
+ pass
19
+
20
+ @abstractmethod
21
+ def on_request(self, request):
22
+ """Called on each request"""
23
+ pass
24
+
25
+ @abstractmethod
26
+ def on_response(self, response):
27
+ """Called on each response"""
28
+ pass
29
+
30
+
31
+ class PluginManager:
32
+ """Manage plugins"""
33
+
34
+ def __init__(self):
35
+ self.plugins: List[Plugin] = []
36
+ self.hooks: Dict[str, List[Callable]] = {}
37
+
38
+ def register(self, plugin: Plugin):
39
+ """Register a plugin"""
40
+ self.plugins.append(plugin)
41
+
42
+ def register_hook(self, name: str, callback: Callable):
43
+ """Register a hook"""
44
+ if name not in self.hooks:
45
+ self.hooks[name] = []
46
+ self.hooks[name].append(callback)
47
+
48
+ async def trigger(self, name: str, *args, **kwargs):
49
+ """Trigger a hook"""
50
+ if name in self.hooks:
51
+ for callback in self.hooks[name]:
52
+ await callback(*args, **kwargs)
53
+
54
+
55
+ # Global plugin manager
56
+ _plugin_manager = PluginManager()
57
+
58
+
59
+ def get_plugin_manager() -> PluginManager:
60
+ """Get global plugin manager"""
61
+ return _plugin_manager
nextpy/py.typed ADDED
File without changes
@@ -0,0 +1,6 @@
1
+ """NextPy Server Module - FastAPI application and middleware"""
2
+
3
+ from nextpy.server.app import create_app, NextPyApp
4
+ from nextpy.server.middleware import NextPyMiddleware
5
+
6
+ __all__ = ["create_app", "NextPyApp", "NextPyMiddleware"]