django-cfg 1.3.7__py3-none-any.whl → 1.3.11__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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/admin/__init__.py +24 -8
- django_cfg/apps/accounts/admin/activity_admin.py +146 -0
- django_cfg/apps/accounts/admin/filters.py +98 -22
- django_cfg/apps/accounts/admin/group_admin.py +86 -0
- django_cfg/apps/accounts/admin/inlines.py +42 -13
- django_cfg/apps/accounts/admin/otp_admin.py +115 -0
- django_cfg/apps/accounts/admin/registration_admin.py +173 -0
- django_cfg/apps/accounts/admin/resources.py +123 -19
- django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
- django_cfg/apps/accounts/admin/user_admin.py +362 -0
- django_cfg/apps/agents/admin/__init__.py +17 -4
- django_cfg/apps/agents/admin/execution_admin.py +204 -183
- django_cfg/apps/agents/admin/registry_admin.py +230 -255
- django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
- django_cfg/apps/agents/core/__init__.py +1 -1
- django_cfg/apps/agents/core/django_agent.py +221 -0
- django_cfg/apps/agents/core/exceptions.py +14 -0
- django_cfg/apps/agents/core/orchestrator.py +18 -3
- django_cfg/apps/knowbase/admin/__init__.py +1 -1
- django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
- django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
- django_cfg/apps/knowbase/admin/document_admin.py +269 -262
- django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
- django_cfg/apps/knowbase/config/settings.py +21 -4
- django_cfg/apps/knowbase/views/chat_views.py +3 -0
- django_cfg/apps/leads/admin/__init__.py +3 -1
- django_cfg/apps/leads/admin/leads_admin.py +235 -35
- django_cfg/apps/maintenance/admin/__init__.py +2 -2
- django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
- django_cfg/apps/maintenance/admin/log_admin.py +143 -61
- django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
- django_cfg/apps/maintenance/admin/site_admin.py +213 -352
- django_cfg/apps/newsletter/admin/__init__.py +29 -2
- django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
- django_cfg/apps/payments/admin/__init__.py +18 -27
- django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
- django_cfg/apps/payments/admin/balance_admin.py +166 -632
- django_cfg/apps/payments/admin/currencies_admin.py +235 -607
- django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
- django_cfg/apps/payments/admin/filters.py +83 -3
- django_cfg/apps/payments/admin/networks_admin.py +269 -0
- django_cfg/apps/payments/admin/payments_admin.py +183 -460
- django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
- django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
- django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +153 -34
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_card.html +121 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/payment_qr_code.html +95 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/progress_bar.html +37 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/provider_stats.html +60 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_badge.html +41 -0
- django_cfg/apps/payments/admin_interface/templates/payments/components/status_overview.html +83 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_detail.html +363 -0
- django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +43 -17
- django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
- django_cfg/apps/payments/admin_interface/views/api/payments.py +102 -0
- django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +109 -63
- django_cfg/apps/payments/admin_interface/views/forms.py +5 -1
- django_cfg/apps/payments/config/__init__.py +14 -15
- django_cfg/apps/payments/config/django_cfg_integration.py +59 -1
- django_cfg/apps/payments/config/helpers.py +8 -13
- django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
- django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
- django_cfg/apps/payments/middleware/api_access.py +32 -6
- django_cfg/apps/payments/migrations/0001_initial.py +33 -46
- django_cfg/apps/payments/migrations/0002_rename_payments_un_user_id_7f6e79_idx_payments_un_user_id_8ce187_idx_and_more.py +46 -0
- django_cfg/apps/payments/migrations/0003_universalpayment_status_changed_at.py +25 -0
- django_cfg/apps/payments/models/balance.py +12 -0
- django_cfg/apps/payments/models/currencies.py +106 -32
- django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
- django_cfg/apps/payments/models/managers/payment_managers.py +142 -25
- django_cfg/apps/payments/models/payments.py +94 -0
- django_cfg/apps/payments/services/core/base.py +4 -4
- django_cfg/apps/payments/services/core/currency_service.py +35 -28
- django_cfg/apps/payments/services/core/payment_service.py +266 -39
- django_cfg/apps/payments/services/providers/__init__.py +3 -0
- django_cfg/apps/payments/services/providers/base.py +303 -41
- django_cfg/apps/payments/services/providers/models/__init__.py +42 -0
- django_cfg/apps/payments/services/providers/models/base.py +145 -0
- django_cfg/apps/payments/services/providers/models/providers.py +87 -0
- django_cfg/apps/payments/services/providers/models/universal.py +48 -0
- django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
- django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
- django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
- django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
- django_cfg/apps/payments/services/providers/nowpayments/provider.py +557 -0
- django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
- django_cfg/apps/payments/services/providers/registry.py +9 -37
- django_cfg/apps/payments/services/providers/sync_service.py +277 -0
- django_cfg/apps/payments/services/types/requests.py +19 -7
- django_cfg/apps/payments/signals/payment_signals.py +31 -2
- django_cfg/apps/payments/static/payments/js/api-client.js +29 -6
- django_cfg/apps/payments/static/payments/js/payment-detail.js +167 -0
- django_cfg/apps/payments/static/payments/js/payment-form.js +98 -32
- django_cfg/apps/payments/tasks/__init__.py +39 -0
- django_cfg/apps/payments/tasks/types.py +73 -0
- django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
- django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
- django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
- django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
- django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
- django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
- django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
- django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
- django_cfg/apps/payments/templatetags/payment_tags.py +8 -0
- django_cfg/apps/payments/urls.py +3 -2
- django_cfg/apps/payments/urls_admin.py +1 -1
- django_cfg/apps/payments/views/api/currencies.py +8 -5
- django_cfg/apps/payments/views/overview/services.py +2 -2
- django_cfg/apps/payments/views/serializers/currencies.py +22 -8
- django_cfg/apps/support/admin/__init__.py +10 -1
- django_cfg/apps/support/admin/support_admin.py +338 -141
- django_cfg/apps/tasks/admin/__init__.py +11 -0
- django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +68 -217
- django_cfg/apps/tasks/static/tasks/js/api.js +40 -84
- django_cfg/apps/tasks/static/tasks/js/components/DataManager.js +24 -0
- django_cfg/apps/tasks/static/tasks/js/components/TabManager.js +85 -0
- django_cfg/apps/tasks/static/tasks/js/components/TaskRenderer.js +216 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/main.mjs +245 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/overview.mjs +123 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/queues.mjs +120 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/tasks.mjs +350 -0
- django_cfg/apps/tasks/static/tasks/js/dashboard/workers.mjs +169 -0
- django_cfg/apps/tasks/tasks/__init__.py +10 -0
- django_cfg/apps/tasks/tasks/demo_tasks.py +133 -0
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +42 -45
- django_cfg/apps/tasks/templates/tasks/components/{status_cards.html → overview_content.html} +30 -11
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +19 -0
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +16 -10
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +51 -0
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +30 -0
- django_cfg/apps/tasks/templates/tasks/layout/base.html +117 -0
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +82 -0
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +40 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +37 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +41 -0
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +50 -0
- django_cfg/apps/tasks/urls.py +2 -2
- django_cfg/apps/tasks/urls_admin.py +2 -2
- django_cfg/apps/tasks/utils/__init__.py +1 -0
- django_cfg/apps/tasks/utils/simulator.py +356 -0
- django_cfg/apps/tasks/views/__init__.py +16 -0
- django_cfg/apps/tasks/views/api.py +569 -0
- django_cfg/apps/tasks/views/dashboard.py +58 -0
- django_cfg/config.py +1 -1
- django_cfg/core/config.py +10 -5
- django_cfg/core/generation.py +1 -1
- django_cfg/core/integration/__init__.py +21 -0
- django_cfg/management/commands/__init__.py +13 -1
- django_cfg/management/commands/migrate_all.py +9 -3
- django_cfg/management/commands/migrator.py +11 -6
- django_cfg/management/commands/rundramatiq.py +3 -2
- django_cfg/management/commands/rundramatiq_simulator.py +430 -0
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/models/api_keys.py +115 -0
- django_cfg/models/constance.py +0 -11
- django_cfg/models/payments.py +137 -3
- django_cfg/modules/django_admin/__init__.py +64 -0
- django_cfg/modules/django_admin/decorators/__init__.py +13 -0
- django_cfg/modules/django_admin/decorators/actions.py +106 -0
- django_cfg/modules/django_admin/decorators/display.py +106 -0
- django_cfg/modules/django_admin/mixins/__init__.py +14 -0
- django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
- django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
- django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
- django_cfg/modules/django_admin/models/__init__.py +20 -0
- django_cfg/modules/django_admin/models/action_models.py +33 -0
- django_cfg/modules/django_admin/models/badge_models.py +20 -0
- django_cfg/modules/django_admin/models/base.py +26 -0
- django_cfg/modules/django_admin/models/display_models.py +31 -0
- django_cfg/modules/django_admin/utils/badges.py +159 -0
- django_cfg/modules/django_admin/utils/displays.py +247 -0
- django_cfg/modules/django_currency/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/__init__.py +2 -2
- django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
- django_cfg/modules/django_currency/core/converter.py +12 -12
- django_cfg/modules/django_currency/database/__init__.py +2 -2
- django_cfg/modules/django_currency/database/database_loader.py +93 -42
- django_cfg/modules/django_llm/llm/client.py +10 -2
- django_cfg/modules/django_tasks.py +54 -21
- django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
- django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
- django_cfg/modules/django_unfold/dashboard.py +14 -13
- django_cfg/modules/django_unfold/models/config.py +1 -1
- django_cfg/registry/core.py +7 -9
- django_cfg/registry/third_party.py +2 -2
- django_cfg/template_archive/django_sample.zip +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/METADATA +2 -1
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/RECORD +198 -160
- django_cfg/apps/accounts/admin/activity.py +0 -96
- django_cfg/apps/accounts/admin/group.py +0 -17
- django_cfg/apps/accounts/admin/otp.py +0 -59
- django_cfg/apps/accounts/admin/registration_source.py +0 -97
- django_cfg/apps/accounts/admin/twilio_response.py +0 -227
- django_cfg/apps/accounts/admin/user.py +0 -300
- django_cfg/apps/agents/core/agent.py +0 -281
- django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
- django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
- django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
- django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
- django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
- django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
- django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
- django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
- django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
- django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
- django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
- django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
- django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
- django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
- django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
- django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
- django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
- django_cfg/apps/payments/config/constance/__init__.py +0 -22
- django_cfg/apps/payments/config/constance/config_service.py +0 -123
- django_cfg/apps/payments/config/constance/fields.py +0 -69
- django_cfg/apps/payments/config/constance/settings.py +0 -160
- django_cfg/apps/payments/services/providers/nowpayments.py +0 -478
- django_cfg/apps/tasks/admin.py +0 -320
- django_cfg/apps/tasks/static/tasks/js/dashboard.js +0 -614
- django_cfg/apps/tasks/static/tasks/js/modals.js +0 -452
- django_cfg/apps/tasks/static/tasks/js/notifications.js +0 -144
- django_cfg/apps/tasks/static/tasks/js/task-monitor.js +0 -454
- django_cfg/apps/tasks/static/tasks/js/theme.js +0 -77
- django_cfg/apps/tasks/templates/tasks/base.html +0 -96
- django_cfg/apps/tasks/templates/tasks/components/info_cards.html +0 -85
- django_cfg/apps/tasks/templates/tasks/components/overview_tab.html +0 -22
- django_cfg/apps/tasks/templates/tasks/components/queues_tab.html +0 -19
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -103
- django_cfg/apps/tasks/templates/tasks/components/tasks_tab.html +0 -32
- django_cfg/apps/tasks/templates/tasks/components/workers_tab.html +0 -29
- django_cfg/apps/tasks/templates/tasks/dashboard.html +0 -29
- django_cfg/apps/tasks/views.py +0 -461
- django_cfg/management/commands/auto_generate.py +0 -486
- django_cfg/middleware/static_nocache.py +0 -55
- django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
- /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
- /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/WHEEL +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.3.7.dist-info → django_cfg-1.3.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,486 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Auto Generation Command for Django Config Toolkit
|
3
|
-
Generate configuration files, models, and other Django components.
|
4
|
-
"""
|
5
|
-
|
6
|
-
import os
|
7
|
-
import json
|
8
|
-
from pathlib import Path
|
9
|
-
from django.core.management.base import BaseCommand
|
10
|
-
from django.core.management import call_command
|
11
|
-
from django.conf import settings
|
12
|
-
import questionary
|
13
|
-
from datetime import datetime
|
14
|
-
from django_cfg.modules.django_logger import get_logger
|
15
|
-
|
16
|
-
from django_cfg import ConfigToolkit
|
17
|
-
|
18
|
-
logger = get_logger('auto_generate')
|
19
|
-
|
20
|
-
|
21
|
-
class Command(BaseCommand):
|
22
|
-
help = 'Auto-generate configuration files and Django components'
|
23
|
-
|
24
|
-
def add_arguments(self, parser):
|
25
|
-
parser.add_argument(
|
26
|
-
'--config',
|
27
|
-
action='store_true',
|
28
|
-
help='Generate configuration files only'
|
29
|
-
)
|
30
|
-
parser.add_argument(
|
31
|
-
'--models',
|
32
|
-
action='store_true',
|
33
|
-
help='Generate model files only'
|
34
|
-
)
|
35
|
-
parser.add_argument(
|
36
|
-
'--all',
|
37
|
-
action='store_true',
|
38
|
-
help='Generate all components'
|
39
|
-
)
|
40
|
-
|
41
|
-
def handle(self, *args, **options):
|
42
|
-
logger.info("Starting auto_generate command")
|
43
|
-
if options['all']:
|
44
|
-
self.generate_all()
|
45
|
-
elif options['config']:
|
46
|
-
self.generate_config_files()
|
47
|
-
elif options['models']:
|
48
|
-
self.generate_model_files()
|
49
|
-
else:
|
50
|
-
self.show_interactive_menu()
|
51
|
-
|
52
|
-
def show_interactive_menu(self):
|
53
|
-
"""Show interactive menu with generation options"""
|
54
|
-
self.stdout.write(self.style.SUCCESS('\n🚀 Auto Generation Tool - Django Config Toolkit\n'))
|
55
|
-
|
56
|
-
choices = [
|
57
|
-
questionary.Choice('⚙️ Generate Configuration Files', value='config'),
|
58
|
-
questionary.Choice('📊 Generate Model Files', value='models'),
|
59
|
-
questionary.Choice('🔄 Generate All Components', value='all'),
|
60
|
-
questionary.Choice('📝 Generate Environment Template', value='env'),
|
61
|
-
questionary.Choice('🔧 Generate Settings Template', value='settings'),
|
62
|
-
questionary.Choice('❌ Exit', value='exit')
|
63
|
-
]
|
64
|
-
|
65
|
-
choice = questionary.select(
|
66
|
-
'Select generation option:',
|
67
|
-
choices=choices
|
68
|
-
).ask()
|
69
|
-
|
70
|
-
if choice == 'config':
|
71
|
-
self.generate_config_files()
|
72
|
-
elif choice == 'models':
|
73
|
-
self.generate_model_files()
|
74
|
-
elif choice == 'all':
|
75
|
-
self.generate_all()
|
76
|
-
elif choice == 'env':
|
77
|
-
self.generate_env_template()
|
78
|
-
elif choice == 'settings':
|
79
|
-
self.generate_settings_template()
|
80
|
-
elif choice == 'exit':
|
81
|
-
self.stdout.write('Goodbye! 👋')
|
82
|
-
return
|
83
|
-
|
84
|
-
def generate_all(self):
|
85
|
-
"""Generate all components"""
|
86
|
-
self.stdout.write(self.style.SUCCESS('🔄 Generating all components...'))
|
87
|
-
|
88
|
-
self.generate_config_files()
|
89
|
-
self.generate_model_files()
|
90
|
-
self.generate_env_template()
|
91
|
-
self.generate_settings_template()
|
92
|
-
|
93
|
-
self.stdout.write(self.style.SUCCESS('✅ All components generated!'))
|
94
|
-
|
95
|
-
def generate_config_files(self):
|
96
|
-
"""Generate configuration files"""
|
97
|
-
self.stdout.write(self.style.SUCCESS('⚙️ Generating configuration files...'))
|
98
|
-
|
99
|
-
# Generate config.py
|
100
|
-
self.generate_config_py()
|
101
|
-
|
102
|
-
# Generate database config
|
103
|
-
self.generate_database_config()
|
104
|
-
|
105
|
-
# Generate security config
|
106
|
-
self.generate_security_config()
|
107
|
-
|
108
|
-
self.stdout.write(self.style.SUCCESS('✅ Configuration files generated!'))
|
109
|
-
|
110
|
-
def generate_model_files(self):
|
111
|
-
"""Generate model files"""
|
112
|
-
self.stdout.write(self.style.SUCCESS('📊 Generating model files...'))
|
113
|
-
|
114
|
-
# Generate base models
|
115
|
-
self.generate_base_models()
|
116
|
-
|
117
|
-
# Generate API models
|
118
|
-
self.generate_api_models()
|
119
|
-
|
120
|
-
self.stdout.write(self.style.SUCCESS('✅ Model files generated!'))
|
121
|
-
|
122
|
-
def generate_config_py(self):
|
123
|
-
"""Generate main config.py file"""
|
124
|
-
config_content = '''"""
|
125
|
-
Configuration file for Django Config Toolkit
|
126
|
-
Auto-generated configuration with smart defaults.
|
127
|
-
"""
|
128
|
-
|
129
|
-
from django_cfg import ConfigToolkit
|
130
|
-
|
131
|
-
# Initialize configuration
|
132
|
-
config = ConfigToolkit()
|
133
|
-
|
134
|
-
# Export all settings
|
135
|
-
globals().update(config.get_django_settings())
|
136
|
-
|
137
|
-
# Type-safe access to configuration
|
138
|
-
DEBUG = config.debug
|
139
|
-
SECRET_KEY = config.secret_key
|
140
|
-
DATABASE_URL = config.database_url
|
141
|
-
ALLOWED_HOSTS = config.allowed_hosts
|
142
|
-
'''
|
143
|
-
|
144
|
-
config_path = Path('config.py')
|
145
|
-
if not config_path.exists():
|
146
|
-
with open(config_path, 'w') as f:
|
147
|
-
f.write(config_content)
|
148
|
-
self.stdout.write(f' 📄 Created {config_path}')
|
149
|
-
|
150
|
-
def generate_database_config(self):
|
151
|
-
"""Generate database configuration"""
|
152
|
-
db_config_content = '''"""
|
153
|
-
Database Configuration
|
154
|
-
Auto-generated database settings.
|
155
|
-
"""
|
156
|
-
|
157
|
-
from django_cfg import DatabaseConfig
|
158
|
-
|
159
|
-
# Database configuration
|
160
|
-
db_config = DatabaseConfig(
|
161
|
-
database_url="sqlite:///db.sqlite3",
|
162
|
-
max_connections=20,
|
163
|
-
conn_max_age=600,
|
164
|
-
conn_health_checks=True,
|
165
|
-
ssl_require=False,
|
166
|
-
ssl_mode="prefer",
|
167
|
-
query_timeout=30,
|
168
|
-
)
|
169
|
-
|
170
|
-
# Additional databases (uncomment and configure as needed)
|
171
|
-
# db_config.read_replica_url = "postgresql://user:pass@host:port/db"
|
172
|
-
# db_config.cache_db_url = "redis://localhost:6379/1"
|
173
|
-
# db_config.analytics_db_url = "postgresql://user:pass@host:port/analytics"
|
174
|
-
|
175
|
-
# Export database settings
|
176
|
-
globals().update(db_config.to_django_settings())
|
177
|
-
'''
|
178
|
-
|
179
|
-
db_config_path = Path('database_config.py')
|
180
|
-
if not db_config_path.exists():
|
181
|
-
with open(db_config_path, 'w') as f:
|
182
|
-
f.write(db_config_content)
|
183
|
-
self.stdout.write(f' 📄 Created {db_config_path}')
|
184
|
-
|
185
|
-
def generate_security_config(self):
|
186
|
-
"""Generate security configuration"""
|
187
|
-
security_config_content = '''"""
|
188
|
-
Security Configuration
|
189
|
-
Auto-generated security settings.
|
190
|
-
"""
|
191
|
-
|
192
|
-
from django_cfg import SecurityConfig
|
193
|
-
|
194
|
-
# Security configuration
|
195
|
-
security_config = SecurityConfig(
|
196
|
-
secret_key="your-secret-key-here",
|
197
|
-
debug=False,
|
198
|
-
allowed_hosts=["localhost", "127.0.0.1"],
|
199
|
-
csrf_trusted_origins=["http://localhost:3000"],
|
200
|
-
cors_allowed_origins=["http://localhost:3000"],
|
201
|
-
cors_allowed_methods=["GET", "POST", "PUT", "DELETE"],
|
202
|
-
cors_allowed_headers=["*"],
|
203
|
-
)
|
204
|
-
|
205
|
-
# Export security settings
|
206
|
-
globals().update(security_config.to_django_settings())
|
207
|
-
'''
|
208
|
-
|
209
|
-
security_config_path = Path('security_config.py')
|
210
|
-
if not security_config_path.exists():
|
211
|
-
with open(security_config_path, 'w') as f:
|
212
|
-
f.write(security_config_content)
|
213
|
-
self.stdout.write(f' 📄 Created {security_config_path}')
|
214
|
-
|
215
|
-
def generate_base_models(self):
|
216
|
-
"""Generate base model files"""
|
217
|
-
base_models_content = '''"""
|
218
|
-
Base Models
|
219
|
-
Auto-generated base model classes.
|
220
|
-
"""
|
221
|
-
|
222
|
-
from django.db import models
|
223
|
-
from django.utils import timezone
|
224
|
-
|
225
|
-
|
226
|
-
class BaseModel(models.Model):
|
227
|
-
"""Base model with common fields."""
|
228
|
-
|
229
|
-
created_at = models.DateTimeField(auto_now_add=True)
|
230
|
-
updated_at = models.DateTimeField(auto_now=True)
|
231
|
-
is_active = models.BooleanField(default=True)
|
232
|
-
|
233
|
-
class Meta:
|
234
|
-
abstract = True
|
235
|
-
|
236
|
-
def __str__(self):
|
237
|
-
return f"{self.__class__.__name__} {self.id}"
|
238
|
-
|
239
|
-
|
240
|
-
class TimestampedModel(BaseModel):
|
241
|
-
"""Model with timestamps."""
|
242
|
-
|
243
|
-
created_by = models.ForeignKey(
|
244
|
-
'auth.User',
|
245
|
-
on_delete=models.SET_NULL,
|
246
|
-
null=True,
|
247
|
-
blank=True,
|
248
|
-
related_name='%(class)s_created'
|
249
|
-
)
|
250
|
-
updated_by = models.ForeignKey(
|
251
|
-
'auth.User',
|
252
|
-
on_delete=models.SET_NULL,
|
253
|
-
null=True,
|
254
|
-
blank=True,
|
255
|
-
related_name='%(class)s_updated'
|
256
|
-
)
|
257
|
-
|
258
|
-
class Meta:
|
259
|
-
abstract = True
|
260
|
-
'''
|
261
|
-
|
262
|
-
base_models_path = Path('models/base.py')
|
263
|
-
base_models_path.parent.mkdir(exist_ok=True)
|
264
|
-
|
265
|
-
if not base_models_path.exists():
|
266
|
-
with open(base_models_path, 'w') as f:
|
267
|
-
f.write(base_models_content)
|
268
|
-
self.stdout.write(f' 📄 Created {base_models_path}')
|
269
|
-
|
270
|
-
def generate_api_models(self):
|
271
|
-
"""Generate API model files"""
|
272
|
-
api_models_content = '''"""
|
273
|
-
API Models
|
274
|
-
Auto-generated API model classes.
|
275
|
-
"""
|
276
|
-
|
277
|
-
from django.db import models
|
278
|
-
from .base import BaseModel
|
279
|
-
|
280
|
-
|
281
|
-
class APIModel(BaseModel):
|
282
|
-
"""Base model for API resources."""
|
283
|
-
|
284
|
-
name = models.CharField(max_length=255)
|
285
|
-
description = models.TextField(blank=True)
|
286
|
-
slug = models.SlugField(max_length=255, unique=True)
|
287
|
-
|
288
|
-
class Meta:
|
289
|
-
abstract = True
|
290
|
-
|
291
|
-
def __str__(self):
|
292
|
-
return self.name
|
293
|
-
|
294
|
-
|
295
|
-
class ConfigModel(APIModel):
|
296
|
-
"""Configuration model for storing settings."""
|
297
|
-
|
298
|
-
key = models.CharField(max_length=255, unique=True)
|
299
|
-
value = models.JSONField()
|
300
|
-
value_type = models.CharField(
|
301
|
-
max_length=50,
|
302
|
-
choices=[
|
303
|
-
('string', 'String'),
|
304
|
-
('integer', 'Integer'),
|
305
|
-
('float', 'Float'),
|
306
|
-
('boolean', 'Boolean'),
|
307
|
-
('json', 'JSON'),
|
308
|
-
],
|
309
|
-
default='string'
|
310
|
-
)
|
311
|
-
|
312
|
-
class Meta:
|
313
|
-
verbose_name = 'Configuration'
|
314
|
-
verbose_name_plural = 'Configurations'
|
315
|
-
'''
|
316
|
-
|
317
|
-
api_models_path = Path('models/api.py')
|
318
|
-
api_models_path.parent.mkdir(exist_ok=True)
|
319
|
-
|
320
|
-
if not api_models_path.exists():
|
321
|
-
with open(api_models_path, 'w') as f:
|
322
|
-
f.write(api_models_content)
|
323
|
-
self.stdout.write(f' 📄 Created {api_models_path}')
|
324
|
-
|
325
|
-
def generate_env_template(self):
|
326
|
-
"""Generate environment template file"""
|
327
|
-
env_template_content = '''# Environment Configuration Template
|
328
|
-
# Copy this file to .env and configure your settings
|
329
|
-
|
330
|
-
# Django Settings
|
331
|
-
DEBUG=True
|
332
|
-
SECRET_KEY=your-secret-key-here
|
333
|
-
ALLOWED_HOSTS=localhost,127.0.0.1
|
334
|
-
|
335
|
-
# Database Settings
|
336
|
-
DATABASE_URL=sqlite:///db.sqlite3
|
337
|
-
# DATABASE_URL=postgresql://user:password@localhost:5432/dbname
|
338
|
-
# DATABASE_URL=mysql://user:password@localhost:3306/dbname
|
339
|
-
|
340
|
-
# Additional Databases (optional)
|
341
|
-
# DATABASE_URL_CARS=postgresql://user:password@localhost:5432/cars_db
|
342
|
-
# DATABASE_URL_ANALYTICS=postgresql://user:password@localhost:5432/analytics_db
|
343
|
-
# DATABASE_URL_CACHE=redis://localhost:6379/1
|
344
|
-
|
345
|
-
# Email Settings
|
346
|
-
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
|
347
|
-
EMAIL_HOST=smtp.gmail.com
|
348
|
-
EMAIL_PORT=587
|
349
|
-
EMAIL_USE_TLS=True
|
350
|
-
EMAIL_HOST_USER=your-email@gmail.com
|
351
|
-
EMAIL_HOST_PASSWORD=your-app-password
|
352
|
-
|
353
|
-
# Cache Settings
|
354
|
-
CACHE_BACKEND=django.core.cache.backends.locmem.LocMemCache
|
355
|
-
# CACHE_BACKEND=django.core.cache.backends.redis.RedisCache
|
356
|
-
# CACHE_LOCATION=redis://127.0.0.1:6379/1
|
357
|
-
|
358
|
-
# Security Settings
|
359
|
-
CSRF_TRUSTED_ORIGINS=http://localhost:3000
|
360
|
-
CORS_ALLOWED_ORIGINS=http://localhost:3000
|
361
|
-
|
362
|
-
# API Settings
|
363
|
-
API_KEY=your-api-key-here
|
364
|
-
API_RATE_LIMIT=1000
|
365
|
-
|
366
|
-
# Logging Settings
|
367
|
-
LOG_LEVEL=INFO
|
368
|
-
LOG_FILE=logs/app.log
|
369
|
-
'''
|
370
|
-
|
371
|
-
env_template_path = Path('.env.template')
|
372
|
-
if not env_template_path.exists():
|
373
|
-
with open(env_template_path, 'w') as f:
|
374
|
-
f.write(env_template_content)
|
375
|
-
self.stdout.write(f' 📄 Created {env_template_path}')
|
376
|
-
|
377
|
-
def generate_settings_template(self):
|
378
|
-
"""Generate Django settings template"""
|
379
|
-
settings_template_content = '''"""
|
380
|
-
Django Settings Template
|
381
|
-
Auto-generated Django settings with Django Config Toolkit.
|
382
|
-
"""
|
383
|
-
|
384
|
-
import os
|
385
|
-
from pathlib import Path
|
386
|
-
|
387
|
-
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
388
|
-
BASE_DIR = Path(__file__).resolve().parent.parent
|
389
|
-
|
390
|
-
# Import configuration from Django Config Toolkit
|
391
|
-
from django_cfg import ConfigToolkit
|
392
|
-
|
393
|
-
# Initialize configuration
|
394
|
-
config = ConfigToolkit()
|
395
|
-
|
396
|
-
# Export all settings
|
397
|
-
globals().update(config.get_django_settings())
|
398
|
-
|
399
|
-
# Application definition
|
400
|
-
INSTALLED_APPS = [
|
401
|
-
'django.contrib.admin',
|
402
|
-
'django.contrib.auth',
|
403
|
-
'django.contrib.contenttypes',
|
404
|
-
'django.contrib.sessions',
|
405
|
-
'django.contrib.messages',
|
406
|
-
'django.contrib.staticfiles',
|
407
|
-
|
408
|
-
# Third party apps
|
409
|
-
'rest_framework',
|
410
|
-
'corsheaders',
|
411
|
-
'django_cfg',
|
412
|
-
|
413
|
-
# Local apps
|
414
|
-
# Add your apps here
|
415
|
-
]
|
416
|
-
|
417
|
-
MIDDLEWARE = [
|
418
|
-
'corsheaders.middleware.CorsMiddleware',
|
419
|
-
'django.middleware.security.SecurityMiddleware',
|
420
|
-
'django.contrib.sessions.middleware.SessionMiddleware',
|
421
|
-
'django.middleware.common.CommonMiddleware',
|
422
|
-
'django.middleware.csrf.CsrfViewMiddleware',
|
423
|
-
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
424
|
-
'django.contrib.messages.middleware.MessageMiddleware',
|
425
|
-
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
426
|
-
]
|
427
|
-
|
428
|
-
ROOT_URLCONF = 'project.urls'
|
429
|
-
|
430
|
-
TEMPLATES = [
|
431
|
-
{
|
432
|
-
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
433
|
-
'DIRS': [BASE_DIR / 'templates'],
|
434
|
-
'APP_DIRS': True,
|
435
|
-
'OPTIONS': {
|
436
|
-
'context_processors': [
|
437
|
-
'django.template.context_processors.debug',
|
438
|
-
'django.template.context_processors.request',
|
439
|
-
'django.contrib.auth.context_processors.auth',
|
440
|
-
'django.contrib.messages.context_processors.messages',
|
441
|
-
],
|
442
|
-
},
|
443
|
-
},
|
444
|
-
]
|
445
|
-
|
446
|
-
WSGI_APPLICATION = 'project.wsgi.application'
|
447
|
-
|
448
|
-
# Static files (CSS, JavaScript, Images)
|
449
|
-
STATIC_URL = '/static/'
|
450
|
-
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
451
|
-
STATICFILES_DIRS = [BASE_DIR / 'static']
|
452
|
-
|
453
|
-
# Media files
|
454
|
-
MEDIA_URL = '/media/'
|
455
|
-
MEDIA_ROOT = BASE_DIR / 'media'
|
456
|
-
|
457
|
-
# Default primary key field type
|
458
|
-
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
459
|
-
|
460
|
-
# REST Framework settings
|
461
|
-
REST_FRAMEWORK = {
|
462
|
-
'DEFAULT_AUTHENTICATION_CLASSES': [
|
463
|
-
'rest_framework.authentication.SessionAuthentication',
|
464
|
-
'rest_framework.authentication.TokenAuthentication',
|
465
|
-
],
|
466
|
-
'DEFAULT_PERMISSION_CLASSES': [
|
467
|
-
'rest_framework.permissions.IsAuthenticated',
|
468
|
-
],
|
469
|
-
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
470
|
-
'PAGE_SIZE': 20,
|
471
|
-
}
|
472
|
-
|
473
|
-
# Health check URLs
|
474
|
-
HEALTH_CHECK_URLS = [
|
475
|
-
'health/',
|
476
|
-
'health/detailed/',
|
477
|
-
'ready/',
|
478
|
-
'alive/',
|
479
|
-
]
|
480
|
-
'''
|
481
|
-
|
482
|
-
settings_template_path = Path('settings_template.py')
|
483
|
-
if not settings_template_path.exists():
|
484
|
-
with open(settings_template_path, 'w') as f:
|
485
|
-
f.write(settings_template_content)
|
486
|
-
self.stdout.write(f' 📄 Created {settings_template_path}')
|
@@ -1,55 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Static files no-cache middleware for django-cfg.
|
3
|
-
|
4
|
-
Automatically disables caching for static files in development environments
|
5
|
-
to prevent browser caching issues during development.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from django.conf import settings
|
9
|
-
from django_cfg.core.config import EnvironmentMode
|
10
|
-
|
11
|
-
|
12
|
-
class StaticNoCacheMiddleware:
|
13
|
-
"""
|
14
|
-
Middleware to disable caching for static files in development.
|
15
|
-
|
16
|
-
This ensures that JavaScript and CSS files are always fresh during development,
|
17
|
-
preventing browser caching issues when files are updated.
|
18
|
-
|
19
|
-
Automatically detects development mode based on:
|
20
|
-
- DEBUG setting
|
21
|
-
- ENV_MODE environment variable
|
22
|
-
"""
|
23
|
-
|
24
|
-
def __init__(self, get_response):
|
25
|
-
self.get_response = get_response
|
26
|
-
|
27
|
-
# Determine if we should disable caching
|
28
|
-
self.should_disable_cache = self._should_disable_cache()
|
29
|
-
|
30
|
-
def _should_disable_cache(self):
|
31
|
-
"""Determine if caching should be disabled based on environment."""
|
32
|
-
# Always disable in DEBUG mode
|
33
|
-
if settings.DEBUG:
|
34
|
-
return True
|
35
|
-
|
36
|
-
# Check ENV_MODE if available
|
37
|
-
env_mode = getattr(settings, 'ENV_MODE', None)
|
38
|
-
if env_mode == EnvironmentMode.DEVELOPMENT or env_mode == EnvironmentMode.TEST:
|
39
|
-
return True
|
40
|
-
|
41
|
-
return False
|
42
|
-
|
43
|
-
def __call__(self, request):
|
44
|
-
response = self.get_response(request)
|
45
|
-
|
46
|
-
# Apply no-cache headers for static files in development
|
47
|
-
if self.should_disable_cache and request.path.startswith('/static/'):
|
48
|
-
response['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
|
49
|
-
response['Pragma'] = 'no-cache'
|
50
|
-
response['Expires'] = '0'
|
51
|
-
# Add ETag removal to prevent conditional requests
|
52
|
-
if 'ETag' in response:
|
53
|
-
del response['ETag']
|
54
|
-
|
55
|
-
return response
|
@@ -1,157 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import requests
|
3
|
-
import time
|
4
|
-
from datetime import datetime
|
5
|
-
from typing import Dict, Set, Optional
|
6
|
-
from cachetools import TTLCache
|
7
|
-
|
8
|
-
from ..core.models import Rate, YahooFinanceResponse
|
9
|
-
from ..core.exceptions import RateFetchError
|
10
|
-
|
11
|
-
logger = logging.getLogger(__name__)
|
12
|
-
|
13
|
-
|
14
|
-
class YahooFinanceClient:
|
15
|
-
"""Simple Yahoo Finance client without yfinance dependency."""
|
16
|
-
|
17
|
-
BASE_URL = "https://query1.finance.yahoo.com/v8/finance/chart"
|
18
|
-
|
19
|
-
def __init__(self, cache_ttl: int = 3600):
|
20
|
-
"""Initialize Yahoo Finance client with TTL cache."""
|
21
|
-
self._rate_cache = TTLCache(maxsize=500, ttl=cache_ttl)
|
22
|
-
self._session = requests.Session()
|
23
|
-
self._session.headers.update({
|
24
|
-
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
25
|
-
})
|
26
|
-
self._last_request_time = 0
|
27
|
-
self._rate_limit_delay = 1.0 # 1 second between requests
|
28
|
-
|
29
|
-
def _get_yahoo_symbol(self, base: str, quote: str) -> str:
|
30
|
-
"""Convert currency pair to Yahoo Finance symbol format."""
|
31
|
-
# Yahoo uses format like EURUSD=X for forex pairs
|
32
|
-
return f"{base}{quote}=X"
|
33
|
-
|
34
|
-
def fetch_rate(self, base: str, quote: str) -> Rate:
|
35
|
-
"""
|
36
|
-
Fetch forex rate from Yahoo Finance with caching.
|
37
|
-
|
38
|
-
Args:
|
39
|
-
base: Base currency code (e.g., EUR)
|
40
|
-
quote: Quote currency code (e.g., USD)
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
Rate object with exchange rate data
|
44
|
-
|
45
|
-
Raises:
|
46
|
-
RateFetchError: If rate fetch fails
|
47
|
-
"""
|
48
|
-
base = base.upper()
|
49
|
-
quote = quote.upper()
|
50
|
-
cache_key = f"{base}_{quote}"
|
51
|
-
|
52
|
-
# Try cache first
|
53
|
-
if cache_key in self._rate_cache:
|
54
|
-
logger.debug(f"Retrieved rate {base}/{quote} from Yahoo cache")
|
55
|
-
return self._rate_cache[cache_key]
|
56
|
-
|
57
|
-
symbol = self._get_yahoo_symbol(base, quote)
|
58
|
-
|
59
|
-
# Rate limiting
|
60
|
-
current_time = time.time()
|
61
|
-
time_since_last_request = current_time - self._last_request_time
|
62
|
-
if time_since_last_request < self._rate_limit_delay:
|
63
|
-
sleep_time = self._rate_limit_delay - time_since_last_request
|
64
|
-
logger.debug(f"Rate limiting: sleeping for {sleep_time:.2f}s")
|
65
|
-
time.sleep(sleep_time)
|
66
|
-
|
67
|
-
try:
|
68
|
-
response = self._session.get(f"{self.BASE_URL}/{symbol}")
|
69
|
-
self._last_request_time = time.time()
|
70
|
-
response.raise_for_status()
|
71
|
-
|
72
|
-
raw_data = response.json()
|
73
|
-
|
74
|
-
# Validate response using Pydantic model
|
75
|
-
try:
|
76
|
-
yahoo_response = YahooFinanceResponse(**raw_data)
|
77
|
-
except Exception as e:
|
78
|
-
raise RateFetchError(f"Invalid Yahoo Finance response format: {e}")
|
79
|
-
|
80
|
-
if not yahoo_response.chart.result:
|
81
|
-
raise RateFetchError(f"No data returned for {symbol}")
|
82
|
-
|
83
|
-
meta = yahoo_response.chart.result[0].meta
|
84
|
-
rate_value = meta.regularMarketPrice
|
85
|
-
timestamp = datetime.fromtimestamp(meta.regularMarketTime)
|
86
|
-
|
87
|
-
rate = Rate(
|
88
|
-
source="yahoo",
|
89
|
-
base_currency=base,
|
90
|
-
quote_currency=quote,
|
91
|
-
rate=float(rate_value),
|
92
|
-
timestamp=timestamp
|
93
|
-
)
|
94
|
-
|
95
|
-
self._rate_cache[cache_key] = rate
|
96
|
-
logger.info(f"Fetched rate {base}/{quote} = {rate_value} from Yahoo Finance")
|
97
|
-
return rate
|
98
|
-
|
99
|
-
except requests.exceptions.RequestException as e:
|
100
|
-
logger.error(f"Failed to fetch rate from Yahoo Finance: {e}")
|
101
|
-
raise RateFetchError(f"Yahoo Finance API error: {e}")
|
102
|
-
except (KeyError, TypeError, ValueError) as e:
|
103
|
-
logger.error(f"Failed to parse Yahoo Finance response: {e}")
|
104
|
-
raise RateFetchError(f"Invalid response format: {e}")
|
105
|
-
except Exception as e:
|
106
|
-
logger.error(f"Unexpected error fetching from Yahoo Finance: {e}")
|
107
|
-
raise RateFetchError(f"Yahoo Finance fetch failed: {e}")
|
108
|
-
|
109
|
-
def supports_pair(self, base: str, quote: str) -> bool:
|
110
|
-
"""
|
111
|
-
Check if Yahoo Finance supports the given currency pair.
|
112
|
-
|
113
|
-
Yahoo Finance primarily supports major forex pairs.
|
114
|
-
"""
|
115
|
-
base = base.upper()
|
116
|
-
quote = quote.upper()
|
117
|
-
|
118
|
-
# Major currencies supported by Yahoo Finance
|
119
|
-
major_currencies = {
|
120
|
-
'USD', 'EUR', 'GBP', 'JPY', 'CHF', 'CAD', 'AUD', 'NZD',
|
121
|
-
'SEK', 'NOK', 'DKK', 'PLN', 'CZK', 'HUF', 'RUB', 'CNY',
|
122
|
-
'INR', 'KRW', 'SGD', 'HKD', 'THB', 'MXN', 'BRL', 'ZAR',
|
123
|
-
'TRY', 'ILS'
|
124
|
-
}
|
125
|
-
|
126
|
-
return base in major_currencies and quote in major_currencies
|
127
|
-
|
128
|
-
def get_all_supported_currencies(self) -> Dict[str, str]:
|
129
|
-
"""Get all major currencies supported by Yahoo Finance."""
|
130
|
-
return {
|
131
|
-
'USD': 'US Dollar',
|
132
|
-
'EUR': 'Euro',
|
133
|
-
'GBP': 'British Pound',
|
134
|
-
'JPY': 'Japanese Yen',
|
135
|
-
'CHF': 'Swiss Franc',
|
136
|
-
'CAD': 'Canadian Dollar',
|
137
|
-
'AUD': 'Australian Dollar',
|
138
|
-
'NZD': 'New Zealand Dollar',
|
139
|
-
'SEK': 'Swedish Krona',
|
140
|
-
'NOK': 'Norwegian Krone',
|
141
|
-
'DKK': 'Danish Krone',
|
142
|
-
'PLN': 'Polish Zloty',
|
143
|
-
'CZK': 'Czech Koruna',
|
144
|
-
'HUF': 'Hungarian Forint',
|
145
|
-
'RUB': 'Russian Ruble',
|
146
|
-
'CNY': 'Chinese Yuan',
|
147
|
-
'INR': 'Indian Rupee',
|
148
|
-
'KRW': 'South Korean Won',
|
149
|
-
'SGD': 'Singapore Dollar',
|
150
|
-
'HKD': 'Hong Kong Dollar',
|
151
|
-
'THB': 'Thai Baht',
|
152
|
-
'MXN': 'Mexican Peso',
|
153
|
-
'BRL': 'Brazilian Real',
|
154
|
-
'ZAR': 'South African Rand',
|
155
|
-
'TRY': 'Turkish Lira',
|
156
|
-
'ILS': 'Israeli Shekel'
|
157
|
-
}
|
File without changes
|
File without changes
|
File without changes
|