local-deep-research 0.4.1__tar.gz → 0.4.3__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.
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/PKG-INFO +1 -1
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/pyproject.toml +1 -1
- local_deep_research-0.4.3/src/local_deep_research/__version__.py +1 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/config/llm_config.py +1 -1
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/defaults/default_settings.json +1 -1
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/services/settings_manager.py +72 -19
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_searxng.py +1 -1
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/search_engines_config.py +3 -11
- local_deep_research-0.4.3/tests/conftest.py +119 -0
- local_deep_research-0.4.3/tests/test_settings_manager.py +260 -0
- local_deep_research-0.4.1/src/local_deep_research/__version__.py +0 -1
- local_deep_research-0.4.1/tests/test_settings_manager.py +0 -98
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/LICENSE +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/README.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/filters/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/filters/base_filter.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/filters/cross_engine_filter.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/filters/journal_reputation_filter.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/findings/base_findings.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/findings/repository.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/knowledge/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/knowledge/base_knowledge.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/knowledge/standard_knowledge.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/questions/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/questions/base_question.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/questions/decomposition_question.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/questions/standard_question.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/repositories/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/strategies/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/strategies/base_strategy.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/strategies/iterdrag_strategy.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/strategies/parallel_search_strategy.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/strategies/rapid_search_strategy.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/strategies/source_based_strategy.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/strategies/standard_strategy.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/tools/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/tools/base_tool.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/tools/knowledge_tools/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/tools/question_tools/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/advanced_search_system/tools/search_tools/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/api/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/api/benchmark_functions.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/api/research_functions.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/README.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/benchmark_functions.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/cli/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/cli/benchmark_commands.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/cli.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/comparison/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/comparison/evaluator.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/datasets/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/datasets/base.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/datasets/browsecomp.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/datasets/custom_dataset_template.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/datasets/simpleqa.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/datasets/utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/datasets.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/efficiency/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/efficiency/resource_monitor.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/efficiency/speed_profiler.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/evaluators/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/evaluators/base.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/evaluators/browsecomp.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/evaluators/composite.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/evaluators/simpleqa.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/graders.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/metrics/README.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/metrics/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/metrics/calculation.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/metrics/reporting.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/metrics/visualization.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/metrics.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/optimization/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/optimization/api.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/optimization/metrics.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/optimization/optuna_optimizer.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/runners.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/benchmarks/templates.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/citation_handler.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/config/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/config/search_config.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/defaults/.env.template +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/defaults/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/migrate_db.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/report_generator.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/search_system.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/setup_data_dir.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/test_migration.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/db_utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/enums.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/es_utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/llm_utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/log_utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/search_utilities.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/setup_utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/utilities/url_utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/app.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/app_factory.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/database/README.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/database/migrate_to_ldr_db.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/database/migrations.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/database/models.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/database/schema_upgrade.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/models/database.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/models/settings.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/routes/api_routes.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/routes/benchmark_routes.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/routes/history_routes.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/routes/research_routes.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/routes/settings_routes.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/services/research_service.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/services/resource_service.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/services/settings_service.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/services/socket_service.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/css/custom_dropdown.css +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/css/settings.css +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/css/styles.css +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/custom_dropdown.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/detail.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/fallback/formatting.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/fallback/ui.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/history.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/logpanel.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/progress.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/research.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/results.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/settings.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/components/settings_sync.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/main.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/research_form.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/services/api.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/services/audio.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/services/formatting.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/services/pdf.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/services/socket.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/js/services/ui.js +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/sounds/README.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/sounds/error.mp3 +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/static/sounds/success.mp3 +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/base.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/components/custom_dropdown.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/components/log_panel.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/components/mobile_nav.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/components/settings_form.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/components/sidebar.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/pages/details.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/pages/history.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/pages/progress.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/pages/research.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/pages/results.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/templates/settings_dashboard.html +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/utils/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/utils/formatters.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web/utils/templates.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/default_search_engines.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/full_search.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/meta_search_engine.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_arxiv.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_brave.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_ddg.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_elasticsearch.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_github.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_google_pse.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_guardian.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_local.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_local_all.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_pubmed.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_semantic_scholar.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_serpapi.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_wayback.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/engines/search_engine_wikipedia.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/search_engine_base.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/web_search_engines/search_engine_factory.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/TESTING_PROPOSAL.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/download_stuff_for_local_test.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/feature_tests/IMPLEMENTATION_GUIDE_241.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/feature_tests/README.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/feature_tests/__init__.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/feature_tests/test_custom_context.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/fix_tests/README.md +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/fix_tests/test_duplicate_links_fix.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/searxng/test_searxng_instance.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/searxng/test_searxng_integration.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/test_google_pse.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/test_url_utils.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/test_url_utils_debug.py +0 -0
- {local_deep_research-0.4.1 → local_deep_research-0.4.3}/tests/test_url_utils_simple.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: local-deep-research
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.3
|
4
4
|
Summary: AI-powered research assistant with deep, iterative analysis using LLMs and web searches
|
5
5
|
Author-Email: LearningCircuit <185559241+LearningCircuit@users.noreply.github.com>, HashedViking <6432677+HashedViking@users.noreply.github.com>
|
6
6
|
License: MIT License
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.4.3"
|
{local_deep_research-0.4.1 → local_deep_research-0.4.3}/src/local_deep_research/config/llm_config.py
RENAMED
@@ -79,7 +79,7 @@ def get_llm(model_name=None, temperature=None, provider=None, openai_endpoint_ur
|
|
79
79
|
if get_db_setting("llm.supports_max_tokens", True):
|
80
80
|
# Use 80% of context window to leave room for prompts
|
81
81
|
max_tokens = min(
|
82
|
-
get_db_setting("llm.max_tokens", 30000), int(context_window_size * 0.8)
|
82
|
+
int(get_db_setting("llm.max_tokens", 30000)), int(context_window_size * 0.8)
|
83
83
|
)
|
84
84
|
common_params["max_tokens"] = max_tokens
|
85
85
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import importlib.resources as pkg_resources
|
2
2
|
import json
|
3
3
|
import os
|
4
|
-
from typing import Any, Dict, Optional, Union
|
4
|
+
from typing import Any, Dict, Optional, Type, Union
|
5
5
|
|
6
6
|
from loguru import logger
|
7
|
-
from sqlalchemy import func
|
7
|
+
from sqlalchemy import func, or_
|
8
8
|
from sqlalchemy.exc import SQLAlchemyError
|
9
9
|
from sqlalchemy.orm import Session
|
10
10
|
|
@@ -45,6 +45,15 @@ class SettingsManager:
|
|
45
45
|
Provides methods to get and set settings, with the ability to override settings in memory.
|
46
46
|
"""
|
47
47
|
|
48
|
+
_UI_ELEMENT_TO_SETTING_TYPE = {
|
49
|
+
"text": str,
|
50
|
+
"password": str,
|
51
|
+
"select": str,
|
52
|
+
"number": float,
|
53
|
+
"range": float,
|
54
|
+
"checkbox": bool,
|
55
|
+
}
|
56
|
+
|
48
57
|
def __init__(self, db_session: Session):
|
49
58
|
"""
|
50
59
|
Initialize the settings manager
|
@@ -59,6 +68,57 @@ class SettingsManager:
|
|
59
68
|
default_settings = pkg_resources.read_text(defaults, "default_settings.json")
|
60
69
|
self.default_settings = json.loads(default_settings)
|
61
70
|
|
71
|
+
def __get_typed_setting_value(
|
72
|
+
self, setting: Type[Setting], default: Any = None, check_env: bool = True
|
73
|
+
) -> str | float | bool | None:
|
74
|
+
"""
|
75
|
+
Extracts the value for a particular setting, ensuring that it has the
|
76
|
+
correct type.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
setting: The setting to get the value for.
|
80
|
+
default: Default value to return if the value of the setting is
|
81
|
+
invalid.
|
82
|
+
check_env: If true, it will check the environment variable for
|
83
|
+
this setting before reading from the DB.
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
The value of the setting.
|
87
|
+
|
88
|
+
"""
|
89
|
+
setting_type = self._UI_ELEMENT_TO_SETTING_TYPE.get(setting.ui_element, None)
|
90
|
+
if setting_type is None:
|
91
|
+
logger.warning(
|
92
|
+
"Got unknown type {} for setting {}, returning default value.",
|
93
|
+
setting.ui_element,
|
94
|
+
setting.key,
|
95
|
+
)
|
96
|
+
return default
|
97
|
+
|
98
|
+
# Check environment variable first, then database.
|
99
|
+
if check_env:
|
100
|
+
env_value = check_env_setting(setting.key)
|
101
|
+
if env_value is not None:
|
102
|
+
try:
|
103
|
+
return setting_type(env_value)
|
104
|
+
except ValueError:
|
105
|
+
logger.warning(
|
106
|
+
"Setting {} has invalid value {}. Falling back to DB.",
|
107
|
+
setting.key,
|
108
|
+
env_value,
|
109
|
+
)
|
110
|
+
|
111
|
+
# If environment variable does not exist, read from the database.
|
112
|
+
try:
|
113
|
+
return setting_type(setting.value)
|
114
|
+
except ValueError:
|
115
|
+
logger.warning(
|
116
|
+
"Setting {} has invalid value {}. Returning default.",
|
117
|
+
setting.key,
|
118
|
+
setting.value,
|
119
|
+
)
|
120
|
+
return default
|
121
|
+
|
62
122
|
def get_setting(self, key: str, default: Any = None, check_env: bool = True) -> Any:
|
63
123
|
"""
|
64
124
|
Get a setting value
|
@@ -72,37 +132,29 @@ class SettingsManager:
|
|
72
132
|
Returns:
|
73
133
|
Setting value or default if not found
|
74
134
|
"""
|
75
|
-
if check_env:
|
76
|
-
env_value = check_env_setting(key)
|
77
|
-
if env_value is not None:
|
78
|
-
return env_value
|
79
|
-
|
80
135
|
# If using database first approach and session available, check database
|
81
136
|
if self.db_first and self.db_session:
|
82
137
|
try:
|
83
138
|
settings = (
|
84
139
|
self.db_session.query(Setting)
|
85
140
|
# This will find exact matches and any subkeys.
|
86
|
-
.filter(
|
141
|
+
.filter(
|
142
|
+
or_(Setting.key == key, Setting.key.startswith(f"{key}."))
|
143
|
+
).all()
|
87
144
|
)
|
88
145
|
if len(settings) == 1:
|
89
146
|
# This is a bottom-level key.
|
90
|
-
|
91
|
-
|
147
|
+
return self.__get_typed_setting_value(
|
148
|
+
settings[0], default, check_env
|
149
|
+
)
|
92
150
|
elif len(settings) > 1:
|
93
151
|
# This is a higher-level key.
|
94
152
|
settings_map = {}
|
95
153
|
for setting in settings:
|
96
154
|
output_key = setting.key.removeprefix(f"{key}.")
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
# Handle possible replacements from environment variables.
|
101
|
-
env_value = check_env_setting(setting.key)
|
102
|
-
if env_value is not None:
|
103
|
-
value = env_value
|
104
|
-
|
105
|
-
settings_map[output_key] = value
|
155
|
+
settings_map[output_key] = self.__get_typed_setting_value(
|
156
|
+
setting, default, check_env
|
157
|
+
)
|
106
158
|
return settings_map
|
107
159
|
except SQLAlchemyError as e:
|
108
160
|
logger.error(f"Error retrieving setting {key} from database: {e}")
|
@@ -149,6 +201,7 @@ class SettingsManager:
|
|
149
201
|
value=value,
|
150
202
|
type=setting_type,
|
151
203
|
name=key.split(".")[-1].replace("_", " ").title(),
|
204
|
+
ui_element="text",
|
152
205
|
description=f"Setting for {key}",
|
153
206
|
)
|
154
207
|
self.db_session.add(new_setting)
|
@@ -98,7 +98,7 @@ class SearXNGSearchEngine(BaseSearchEngine):
|
|
98
98
|
self.language = language
|
99
99
|
try:
|
100
100
|
self.safe_search = SafeSearchSetting[safe_search]
|
101
|
-
except
|
101
|
+
except KeyError:
|
102
102
|
logger.error(
|
103
103
|
"'{}' is not a valid safe search setting. Disabling safe search",
|
104
104
|
safe_search,
|
@@ -4,20 +4,12 @@ Loads search engine definitions from the user's configuration.
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
import json
|
7
|
-
|
8
|
-
import logging
|
9
|
-
from typing import Any, Dict, List
|
10
|
-
|
11
|
-
from ..utilities.db_utils import get_db_setting
|
12
|
-
from .default_search_engines import get_default_elasticsearch_config
|
13
|
-
|
14
|
-
from functools import cache
|
15
7
|
from typing import Any, Dict, List
|
16
8
|
|
17
9
|
from loguru import logger
|
18
10
|
|
19
|
-
|
20
11
|
from ..utilities.db_utils import get_db_setting
|
12
|
+
from .default_search_engines import get_default_elasticsearch_config
|
21
13
|
|
22
14
|
|
23
15
|
def _extract_per_engine_config(raw_config: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
|
@@ -69,7 +61,7 @@ def search_config() -> Dict[str, Any]:
|
|
69
61
|
# Add alias for 'auto' if it exists
|
70
62
|
if "auto" in search_engines and "meta" not in search_engines:
|
71
63
|
search_engines["meta"] = search_engines["auto"]
|
72
|
-
|
64
|
+
|
73
65
|
# Add Elasticsearch search engine if not already present
|
74
66
|
if "elasticsearch" not in search_engines:
|
75
67
|
logger.info("Adding default Elasticsearch search engine configuration")
|
@@ -91,7 +83,7 @@ def search_config() -> Dict[str, Any]:
|
|
91
83
|
config["paths"] = json.loads(config["paths"])
|
92
84
|
except json.decoder.JSONDecodeError:
|
93
85
|
logger.error(
|
94
|
-
f"
|
86
|
+
f"Path for local collection '{collection}' is not a valid JSON array: "
|
95
87
|
f"{config['paths']}"
|
96
88
|
)
|
97
89
|
config["paths"] = []
|
@@ -0,0 +1,119 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
import pytest
|
4
|
+
from sqlalchemy import create_engine
|
5
|
+
from sqlalchemy.exc import SQLAlchemyError
|
6
|
+
from sqlalchemy.orm import sessionmaker
|
7
|
+
|
8
|
+
import src.local_deep_research.utilities.db_utils as db_utils_module
|
9
|
+
from src.local_deep_research.web.database.models import Base
|
10
|
+
from src.local_deep_research.web.services.settings_manager import SettingsManager
|
11
|
+
|
12
|
+
|
13
|
+
@pytest.fixture(scope="session", autouse=True)
|
14
|
+
def setup_database_for_all_tests(
|
15
|
+
tmp_path_factory, session_mocker
|
16
|
+
): # Directly use the session_mocker provided by pytest-mock
|
17
|
+
"""
|
18
|
+
Provides a database setup for a temporary SQLite file database for the entire test session.
|
19
|
+
It patches db_utils.get_db_session and db_utils.get_settings_manager to use this test DB.
|
20
|
+
"""
|
21
|
+
|
22
|
+
# Call cache_clear on the functions from db_utils_module.
|
23
|
+
# This ensures any pre-existing cached instances are gone.
|
24
|
+
# We must ensure db_utils_module is imported before this point.
|
25
|
+
try:
|
26
|
+
if hasattr(db_utils_module.get_db_session, "cache_clear"):
|
27
|
+
db_utils_module.get_db_session.cache_clear()
|
28
|
+
if hasattr(db_utils_module.get_settings_manager, "cache_clear"):
|
29
|
+
db_utils_module.get_settings_manager.cache_clear()
|
30
|
+
if hasattr(db_utils_module.get_db_setting, "cache_clear"):
|
31
|
+
db_utils_module.get_db_setting.cache_clear() # Clear get_db_setting's cache too
|
32
|
+
|
33
|
+
except Exception as e:
|
34
|
+
print(f"ERROR: Failed to clear db_utils caches aggressively: {e}")
|
35
|
+
# This shouldn't prevent test run, but indicates a problem with cache_clear
|
36
|
+
|
37
|
+
# Debug tmp_path_factory behavior
|
38
|
+
temp_dir = tmp_path_factory.mktemp("db_test_data")
|
39
|
+
db_file = temp_dir / "test_settings.db"
|
40
|
+
db_url = f"sqlite:///{db_file}"
|
41
|
+
|
42
|
+
engine = None
|
43
|
+
try:
|
44
|
+
engine = create_engine(db_url)
|
45
|
+
except Exception as e:
|
46
|
+
print(f"ERROR: Failed to create SQLAlchemy engine: {e}")
|
47
|
+
raise
|
48
|
+
|
49
|
+
try:
|
50
|
+
Base.metadata.create_all(engine)
|
51
|
+
except SQLAlchemyError as e:
|
52
|
+
print(f"ERROR: SQLAlchemyError during Base.metadata.create_all: {e}")
|
53
|
+
raise
|
54
|
+
except Exception as e:
|
55
|
+
print(f"ERROR: Unexpected error during Base.metadata.create_all: {e}")
|
56
|
+
raise
|
57
|
+
|
58
|
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
59
|
+
temp_session = SessionLocal()
|
60
|
+
temp_settings_manager = SettingsManager(db_session=temp_session)
|
61
|
+
|
62
|
+
try:
|
63
|
+
temp_settings_manager.load_from_defaults_file(commit=True)
|
64
|
+
except Exception as e:
|
65
|
+
print(f"ERROR: Failed to load default settings: {e}")
|
66
|
+
temp_session.rollback() # Rollback if default loading fails
|
67
|
+
raise # Re-raise to fail the test if default loading is critical
|
68
|
+
finally:
|
69
|
+
temp_session.close() # Close the temporary session used for loading defaults
|
70
|
+
|
71
|
+
# Clear caches and patch
|
72
|
+
db_utils_module.get_db_session.cache_clear()
|
73
|
+
db_utils_module.get_settings_manager.cache_clear()
|
74
|
+
|
75
|
+
mock_get_db_session = session_mocker.patch(
|
76
|
+
"src.local_deep_research.utilities.db_utils.get_db_session"
|
77
|
+
)
|
78
|
+
mock_get_db_session.side_effect = SessionLocal
|
79
|
+
|
80
|
+
mock_get_settings_manager = session_mocker.patch(
|
81
|
+
"src.local_deep_research.utilities.db_utils.get_settings_manager"
|
82
|
+
)
|
83
|
+
mock_get_settings_manager.side_effect = lambda: SettingsManager(
|
84
|
+
db_session=mock_get_db_session()
|
85
|
+
)
|
86
|
+
|
87
|
+
yield SessionLocal # Yield the SessionLocal class for individual tests to create sessions
|
88
|
+
|
89
|
+
if engine:
|
90
|
+
engine.dispose() # Dispose the engine to close all connections
|
91
|
+
# tmp_path_factory handles deleting the temporary directory and its contents
|
92
|
+
|
93
|
+
|
94
|
+
@pytest.fixture
|
95
|
+
def mock_db_session(mocker):
|
96
|
+
return mocker.MagicMock()
|
97
|
+
|
98
|
+
|
99
|
+
@pytest.fixture
|
100
|
+
def mock_logger(mocker):
|
101
|
+
mocked_logger = mocker.patch(
|
102
|
+
"src.local_deep_research.web.services.settings_manager.logger"
|
103
|
+
)
|
104
|
+
|
105
|
+
def _print_to_console(message: str, *args: Any) -> None:
|
106
|
+
# Handle loguru formatting.
|
107
|
+
message = message.format(*args)
|
108
|
+
print(f"LOG: {message}")
|
109
|
+
return mocker.DEFAULT
|
110
|
+
|
111
|
+
# Pass through logged messages to the console.
|
112
|
+
mocked_logger.debug = mocker.MagicMock(side_effect=_print_to_console)
|
113
|
+
mocked_logger.info = mocker.MagicMock(side_effect=_print_to_console)
|
114
|
+
mocked_logger.warning = mocker.MagicMock(side_effect=_print_to_console)
|
115
|
+
mocked_logger.error = mocker.MagicMock(side_effect=_print_to_console)
|
116
|
+
mocked_logger.critical = mocker.MagicMock(side_effect=_print_to_console)
|
117
|
+
mocked_logger.exception = mocker.MagicMock(side_effect=_print_to_console)
|
118
|
+
|
119
|
+
return mocked_logger
|
@@ -0,0 +1,260 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
import pytest
|
5
|
+
from sqlalchemy.exc import SQLAlchemyError
|
6
|
+
|
7
|
+
from src.local_deep_research.web.services.settings_manager import (
|
8
|
+
Setting,
|
9
|
+
SettingsManager,
|
10
|
+
SettingType,
|
11
|
+
check_env_setting,
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
def test_check_env_setting_exists(monkeypatch):
|
16
|
+
monkeypatch.setenv("LDR_APP_VERSION", "1.0.0")
|
17
|
+
assert check_env_setting("app.version") == "1.0.0"
|
18
|
+
|
19
|
+
|
20
|
+
def test_check_env_setting_not_exists():
|
21
|
+
# Ensure the environment variable is not set
|
22
|
+
if "LDR_APP_VERSION" in os.environ:
|
23
|
+
del os.environ["LDR_APP_VERSION"]
|
24
|
+
assert check_env_setting("app.version") is None
|
25
|
+
|
26
|
+
|
27
|
+
@pytest.mark.parametrize(
|
28
|
+
"ui_element, setting_value, expected",
|
29
|
+
[
|
30
|
+
("text", "hello", "hello"),
|
31
|
+
("select", "option_a", "option_a"),
|
32
|
+
("password", "secret", "secret"),
|
33
|
+
("number", "3.14", 3.14),
|
34
|
+
("range", "3.14", 3.14),
|
35
|
+
("checkbox", "true", True),
|
36
|
+
],
|
37
|
+
)
|
38
|
+
def test_get_setting_from_db(
|
39
|
+
mocker, ui_element: str, setting_value: str, expected: Any
|
40
|
+
):
|
41
|
+
"""
|
42
|
+
Tests that we can successfully read settings from the DB.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
mocker: The fixture to use for mocking.
|
46
|
+
ui_element: The value of the `ui_element` parameter, which controls the return type.
|
47
|
+
setting_value: The value to use for the setting in the DB.
|
48
|
+
expected: The expected typed value of the setting.
|
49
|
+
"""
|
50
|
+
# Arrange: Set up the mock database session and a sample setting
|
51
|
+
mock_db_session = mocker.MagicMock()
|
52
|
+
mock_setting = Setting(
|
53
|
+
key="test.setting", value=setting_value, ui_element=ui_element
|
54
|
+
)
|
55
|
+
mock_db_session.query.return_value.filter.return_value.all.return_value = [
|
56
|
+
mock_setting
|
57
|
+
]
|
58
|
+
|
59
|
+
# Act: Call the get_setting method with the test key
|
60
|
+
settings_manager = SettingsManager(db_session=mock_db_session)
|
61
|
+
result = settings_manager.get_setting("test.setting")
|
62
|
+
|
63
|
+
# Assert: Verify that the result matches the expected value
|
64
|
+
assert result == expected, f"Expected {expected}, but got {result}"
|
65
|
+
|
66
|
+
|
67
|
+
@pytest.mark.parametrize(
|
68
|
+
"ui_element, env_value, expected",
|
69
|
+
[
|
70
|
+
("text", "hello", "hello"),
|
71
|
+
("select", "option_a", "option_a"),
|
72
|
+
("password", "secret", "secret"),
|
73
|
+
("number", "3.14", 3.14),
|
74
|
+
("range", "3.14", 3.14),
|
75
|
+
("checkbox", "true", True),
|
76
|
+
],
|
77
|
+
)
|
78
|
+
def test_get_setting_from_env(
|
79
|
+
mocker, monkeypatch, ui_element: str, env_value: str, expected: Any
|
80
|
+
):
|
81
|
+
"""
|
82
|
+
Tests that we can successfully override DB settings with environment
|
83
|
+
variables.
|
84
|
+
|
85
|
+
Args:
|
86
|
+
mocker: The fixture to use for mocking.
|
87
|
+
ui_element: The value of the `ui_element` parameter, which controls the return type.
|
88
|
+
env_value: The value to use for the setting in the environment variable.
|
89
|
+
expected: The expected typed value of the setting.
|
90
|
+
"""
|
91
|
+
# Arrange: Set up the mock database session and ensure an environment variable is set
|
92
|
+
mock_db_session = mocker.MagicMock()
|
93
|
+
monkeypatch.setenv("LDR_TEST_SETTING", env_value)
|
94
|
+
# Ensure DB query returns an old version to verify environment variable is prioritized
|
95
|
+
mock_setting = Setting(key="test.setting", value="db_value", ui_element=ui_element)
|
96
|
+
mock_db_session.query.return_value.filter.return_value.all.return_value = [
|
97
|
+
mock_setting
|
98
|
+
]
|
99
|
+
|
100
|
+
# Act: Call the get_setting method with the test key
|
101
|
+
settings_manager = SettingsManager(db_session=mock_db_session)
|
102
|
+
result = settings_manager.get_setting("test.setting")
|
103
|
+
|
104
|
+
# Assert: Verify that the result matches the expected value
|
105
|
+
assert result == expected, f"Expected {expected}, but got {result}"
|
106
|
+
|
107
|
+
|
108
|
+
def test_get_setting_default(mocker):
|
109
|
+
mock_db_session = mocker.MagicMock()
|
110
|
+
# Ensure DB query returns nothing
|
111
|
+
mock_db_session.query.return_value.filter.return_value.all.return_value = []
|
112
|
+
|
113
|
+
settings_manager = SettingsManager(db_session=mock_db_session)
|
114
|
+
assert (
|
115
|
+
settings_manager.get_setting("non_existent_setting", default="default_value")
|
116
|
+
== "default_value"
|
117
|
+
)
|
118
|
+
|
119
|
+
|
120
|
+
def test_get_setting_invalid_type(mocker):
|
121
|
+
"""
|
122
|
+
Tests that when a setting's value cannot be converted to the type
|
123
|
+
specified by the `ui_element`, it will always return the default value.
|
124
|
+
|
125
|
+
Args:
|
126
|
+
mocker: The fixture to use for mocking.
|
127
|
+
|
128
|
+
"""
|
129
|
+
# Arrange: Set up a mock DB session and setting with an invalid type
|
130
|
+
mock_db_session = mocker.MagicMock()
|
131
|
+
mock_setting = Setting(
|
132
|
+
key="test.invalid_type", value="not_a_number", ui_element="number"
|
133
|
+
)
|
134
|
+
mock_db_session.query.return_value.filter.return_value.all.return_value = [
|
135
|
+
mock_setting
|
136
|
+
]
|
137
|
+
|
138
|
+
# Act: Call get_setting with a default value and an invalid type
|
139
|
+
settings_manager = SettingsManager(db_session=mock_db_session)
|
140
|
+
result = settings_manager.get_setting("test.invalid_type", default=10)
|
141
|
+
|
142
|
+
# Assert: Check that the default value is returned and not the invalid string
|
143
|
+
assert result == 10
|
144
|
+
|
145
|
+
|
146
|
+
# The mocker fixture is automatically available
|
147
|
+
def test_set_setting_update_existing(mocker):
|
148
|
+
mock_db_session = mocker.MagicMock()
|
149
|
+
mock_setting = Setting(key="app.version", value="1.0.0")
|
150
|
+
mock_db_session.query.return_value.filter.return_value.first.return_value = (
|
151
|
+
mock_setting
|
152
|
+
)
|
153
|
+
mocker.patch(
|
154
|
+
"src.local_deep_research.web.services.settings_manager.func.now"
|
155
|
+
) # Patching the func.now call
|
156
|
+
|
157
|
+
settings_manager = SettingsManager(db_session=mock_db_session)
|
158
|
+
result = settings_manager.set_setting("app.version", "2.0.0")
|
159
|
+
|
160
|
+
assert result is True
|
161
|
+
assert mock_setting.value == "2.0.0"
|
162
|
+
mock_db_session.commit.assert_called_once()
|
163
|
+
mock_db_session.rollback.assert_not_called()
|
164
|
+
|
165
|
+
|
166
|
+
def test_set_setting_create_new(mocker):
|
167
|
+
mock_db_session = mocker.MagicMock()
|
168
|
+
mock_db_session.query.return_value.filter.return_value.first.return_value = None
|
169
|
+
mocker.patch(
|
170
|
+
"src.local_deep_research.web.services.settings_manager.func.now"
|
171
|
+
) # Patching the func.now call
|
172
|
+
|
173
|
+
settings_manager = SettingsManager(db_session=mock_db_session)
|
174
|
+
result = settings_manager.set_setting("new.setting", "new_value")
|
175
|
+
|
176
|
+
assert result is True
|
177
|
+
mock_db_session.add.assert_called_once()
|
178
|
+
new_setting = mock_db_session.add.call_args[0][0]
|
179
|
+
assert isinstance(new_setting, Setting)
|
180
|
+
assert new_setting.key == "new.setting"
|
181
|
+
assert new_setting.value == "new_value"
|
182
|
+
assert new_setting.type == SettingType.APP # Assuming 'app' type for this key
|
183
|
+
mock_db_session.commit.assert_called_once()
|
184
|
+
mock_db_session.rollback.assert_not_called()
|
185
|
+
|
186
|
+
|
187
|
+
def test_set_setting_db_error(mocker):
|
188
|
+
mock_db_session = mocker.MagicMock()
|
189
|
+
# Set the side_effect to an instance of SQLAlchemyError
|
190
|
+
mock_db_session.query.return_value.filter.return_value.first.side_effect = (
|
191
|
+
SQLAlchemyError("Simulated DB Error")
|
192
|
+
)
|
193
|
+
|
194
|
+
# Mock the logger to check if error is logged
|
195
|
+
mock_logger = mocker.patch(
|
196
|
+
"src.local_deep_research.web.services.settings_manager.logger"
|
197
|
+
)
|
198
|
+
|
199
|
+
settings_manager = SettingsManager(db_session=mock_db_session)
|
200
|
+
result = settings_manager.set_setting("app.version", "2.0.0")
|
201
|
+
|
202
|
+
# Assert that the method returned False
|
203
|
+
assert result is False
|
204
|
+
|
205
|
+
mock_db_session.rollback.assert_called_once()
|
206
|
+
mock_db_session.commit.assert_not_called()
|
207
|
+
mock_logger.error.assert_called_once()
|
208
|
+
# mock_logger.error.assert_called_once_with("Error setting value for app.version: Simulated DB Error")
|
209
|
+
|
210
|
+
|
211
|
+
def test_get_setting_with_substring_keys(setup_database_for_all_tests):
|
212
|
+
"""
|
213
|
+
Tests that we can get the correct value for a setting, even when its key
|
214
|
+
is a substring of the key for a different setting.
|
215
|
+
|
216
|
+
Args:
|
217
|
+
setup_database_for_all_tests: Fixture that sets up a real database
|
218
|
+
for testing. (This is necessary because the bug fix this is
|
219
|
+
testing depends on the actual behavior of the SQLAlchemy `filter()`
|
220
|
+
function.)
|
221
|
+
|
222
|
+
"""
|
223
|
+
# Arrange.
|
224
|
+
session_local_class = setup_database_for_all_tests
|
225
|
+
session = session_local_class()
|
226
|
+
|
227
|
+
with session:
|
228
|
+
# Add two settings with overlapping keys but different full keys
|
229
|
+
setting1 = Setting(
|
230
|
+
key="test.hello",
|
231
|
+
value="world",
|
232
|
+
ui_element="text",
|
233
|
+
type="APP",
|
234
|
+
name="Test Setting 1",
|
235
|
+
visible=True,
|
236
|
+
editable=True,
|
237
|
+
)
|
238
|
+
setting2 = Setting(
|
239
|
+
key="test.hello_world",
|
240
|
+
value="universe",
|
241
|
+
ui_element="text",
|
242
|
+
type="APP",
|
243
|
+
name="Test Setting 2",
|
244
|
+
visible=True,
|
245
|
+
editable=True,
|
246
|
+
)
|
247
|
+
session.add(setting1)
|
248
|
+
session.add(setting2)
|
249
|
+
session.commit()
|
250
|
+
|
251
|
+
settings_manager = SettingsManager(db_session=session)
|
252
|
+
|
253
|
+
# Act and assert.
|
254
|
+
# Test getting the "test.hello" setting
|
255
|
+
result1 = settings_manager.get_setting("test.hello")
|
256
|
+
assert result1 == "world"
|
257
|
+
|
258
|
+
# Test getting the "test.hello_world" setting.
|
259
|
+
result2 = settings_manager.get_setting("test.hello_world")
|
260
|
+
assert result2 == "universe"
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "0.4.1"
|