nullpol 0.2.2__tar.gz → 0.2.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.
- nullpol-0.2.3/.github/workflows/ci.yml +66 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/codeql.yml +3 -3
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/scheduled-release.yml +1 -1
- {nullpol-0.2.2 → nullpol-0.2.3}/.pre-commit-config.yaml +4 -4
- {nullpol-0.2.2 → nullpol-0.2.3}/PKG-INFO +1 -1
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/data_analysis.py +1 -1
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/tgrflow.py +88 -20
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/utility.py +5 -2
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/test_data_context.py +1 -1
- nullpol-0.2.3/tests/cli/test_data_analysis_validation.py +79 -0
- nullpol-0.2.3/tests/integrations/asimov/__init__.py +1 -0
- nullpol-0.2.3/tests/integrations/asimov/conftest.py +78 -0
- nullpol-0.2.3/tests/integrations/asimov/test_tgrflow.py +310 -0
- nullpol-0.2.3/tests/integrations/asimov/test_tgrflow_integration.py +251 -0
- nullpol-0.2.3/tests/integrations/asimov/test_utility.py +85 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/smoke_test.py +15 -3
- {nullpol-0.2.2 → nullpol-0.2.3}/uv.lock +423 -429
- nullpol-0.2.2/.github/workflows/ci.yml +0 -36
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/ISSUE_TEMPLATE/feature-request.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/pull_request_template.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/documentation.yml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/draft-release.yml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/publish.yml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/publish_testpypi.yml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/release.yml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.github/workflows/semantic-pr-check.yml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.gitignore +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.markdownlint.yaml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.prettierignore +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.prettierrc.yaml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/.typos.toml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/CITATION.cff +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/CODE_OF_CONDUCT.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/CONTRIBUTING.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/LICENSE +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/README.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/SECURITY.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/cliff.toml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/.gitignore +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/asimov.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/citing.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/contributing.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/examples/scalar-tensor.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/injections.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/installation.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/javascripts/mathjax.js +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/analysis/antenna_patterns/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/analysis/clustering/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/analysis/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/analysis/likelihood/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/analysis/null_stream/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/analysis/prior/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/analysis/tf_transforms/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/cli/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/integrations/asimov/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/integrations/htcondor/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/integrations/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/simulation/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/utils/index.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/docs/reference/nullpol/version.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/generate_injection_file.sh +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/injections.json +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/data/scalar_tensor_injection_data0_0_generation_data_dump.pickle +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1.err +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1.out +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1_final_result.err +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_analysis/scalar_tensor_injection_data0_0_analysis_H1L1V1_final_result.out +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_generation/scalar_tensor_injection_data0_0_generation.err +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/log_data_generation/scalar_tensor_injection_data0_0_generation.out +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/result/scalar_tensor_injection_data0_0_analysis_H1L1V1_dynesty.pickle +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/result/scalar_tensor_injection_data0_0_analysis_H1L1V1_resume.pickle +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/results_page/overview.html +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/scalar_tensor_injection_config_complete.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/bash_scalar_tensor_injection.sh +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.condor.sub +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.dagman.out +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.lib.err +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.lib.out +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/dag_scalar_tensor_injection.submit.metrics +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/scalar_tensor_injection_data0_0_analysis_H1L1V1.submit +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/scalar_tensor_injection_data0_0_analysis_H1L1V1_final_result.submit +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/outdir_scalar_tensor_injection/submit/scalar_tensor_injection_data0_0_generation.submit +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/prior.prior +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/scalar_tensor_injection.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor/scalar_tensor_injection.prior +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_fractional_projection/generate_injection_file.sh +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_fractional_projection/scalar_tensor_injection.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_fractional_projection/scalar_tensor_injection.prior +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_gaussian/generate_injection_file.sh +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_gaussian/scalar_tensor_injection.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_gaussian/scalar_tensor_injection.prior +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_h_marginalized/generate_injection_file.sh +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_h_marginalized/scalar_tensor_injection.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_h_marginalized/scalar_tensor_injection.prior +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_weighted_gaussian/generate_injection_file.sh +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_weighted_gaussian/scalar_tensor_injection.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/examples/injection/scalar_tensor_weighted_gaussian/scalar_tensor_injection.prior +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/pyproject.toml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/renovate.json +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/scripts/README.md +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/scripts/auto_generate_init.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/.gitignore +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/antenna_patterns/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/antenna_patterns/base.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/antenna_patterns/conditioning.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/antenna_patterns/encoding.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/antenna_patterns/processor.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/clustering/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/clustering/algorithm.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/clustering/application.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/clustering/coherent_sky_scan.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/clustering/plotting.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/clustering/threshold_filter.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/data_context.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/likelihood/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/likelihood/chi2_tf_likelihood.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/likelihood/time_frequency_likelihood.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/null_stream/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/null_stream/calculator.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/null_stream/projections.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/prior/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/prior/default.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/prior/prior_files/polarization.prior +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/result.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/inverse_wavelet_freq.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/inverse_wavelet_time.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/stft.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/utils.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/wavelet_freq.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/wavelet_time.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/analysis/tf_transforms/wavelet_transforms.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/create_injection.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/create_time_frequency_filter_from_sample.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/data_generation.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/get_asimov_yaml.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/input.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/main.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/parser.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/templates/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/templates/config.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/templates/default_config_create_injection.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/templates/default_config_create_time_frequency_filter_from_sample.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/cli/templates/example_signal_parameters_create_injection.json +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/asimov.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/pesummary.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/templates/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/templates/analysis_defaults.yaml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/templates/nullpol.ini +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/asimov/templates/nullpol_analysis.yaml +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/htcondor/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/htcondor/analysis_node.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/htcondor/generation_node.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/integrations/htcondor/nullpol_pipe_dag_creator.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/simulation/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/simulation/injection.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/simulation/source.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/utils/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/utils/error.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/utils/filesystem.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/utils/imports.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/utils/json_utils.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/utils/log.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/src/nullpol/version.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/.gitignore +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/antenna_patterns/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/antenna_patterns/test_base.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/antenna_patterns/test_conditioning.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/antenna_patterns/test_encoding.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/antenna_patterns/test_processor.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/clustering/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/clustering/test_algorithm.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/clustering/test_application.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/clustering/test_plotting.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/clustering/test_threshold_filter.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/fixtures/injections.json +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/likelihood/test_chi2_tf_likelihood.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/likelihood/test_time_frequency_likelihood.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/null_stream/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/null_stream/test_calculator.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/null_stream/test_projections.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/prior/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/prior/test_default.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/test_result.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/test_inverse_wavelet_freq.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/test_inverse_wavelet_time.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/test_stft.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/test_utils.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/test_wavelet_freq.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/test_wavelet_time.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/analysis/tf_transforms/test_wavelet_transforms.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/cli/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/cli/fixtures/mock_psd.txt +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/cli/test_create_injection.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/cli/test_create_time_frequency_filter.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/integrations/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/simulation/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/simulation/test_injection.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/simulation/test_source.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/test_import.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/test_version.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/utils/__init__.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/utils/test_error.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/utils/test_filesystem.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/utils/test_imports.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/utils/test_json_utils.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/tests/utils/test_log.py +0 -0
- {nullpol-0.2.2 → nullpol-0.2.3}/zensical.toml +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [main]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
workflow_call:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ['3.12', '3.13', '3.14']
|
|
15
|
+
os: [ubuntu-latest, macos-latest]
|
|
16
|
+
runs-on: ${{ matrix.os }}
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
19
|
+
with:
|
|
20
|
+
persist-credentials: false
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
enable-cache: 'true'
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: uv sync --group dev --frozen
|
|
30
|
+
|
|
31
|
+
- name: Run tests with pytest
|
|
32
|
+
run: uv run --frozen pytest
|
|
33
|
+
|
|
34
|
+
- name: Upload coverage to Codecov
|
|
35
|
+
if: ${{ !cancelled() }}
|
|
36
|
+
uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5
|
|
37
|
+
with:
|
|
38
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
39
|
+
|
|
40
|
+
integration:
|
|
41
|
+
# Runs the @pytest.mark.integration suite once (not in the matrix) to
|
|
42
|
+
# keep the fast unit-test matrix cheap while still gating on the
|
|
43
|
+
# heavier integration tests. Installs the optional `asimov` extra so
|
|
44
|
+
# real asimov/cbcflow paths can be exercised now and in the future.
|
|
45
|
+
needs: test
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
49
|
+
with:
|
|
50
|
+
persist-credentials: false
|
|
51
|
+
|
|
52
|
+
- name: Install uv
|
|
53
|
+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
|
|
54
|
+
with:
|
|
55
|
+
python-version: '3.13'
|
|
56
|
+
enable-cache: 'true'
|
|
57
|
+
|
|
58
|
+
- name: Install dependencies (with asimov extra)
|
|
59
|
+
run: uv sync --group dev --extra asimov --frozen
|
|
60
|
+
|
|
61
|
+
- name: Run integration tests
|
|
62
|
+
# Clear the default addopts (which selects `-m 'not integration'`)
|
|
63
|
+
# and explicitly select the integration marker instead.
|
|
64
|
+
run:
|
|
65
|
+
uv run --frozen pytest -o addopts="" -m integration --cov src
|
|
66
|
+
--cov-report=term-missing
|
|
@@ -18,12 +18,12 @@ jobs:
|
|
|
18
18
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
19
19
|
|
|
20
20
|
- name: Initialize CodeQL
|
|
21
|
-
uses: github/codeql-action/init@
|
|
21
|
+
uses: github/codeql-action/init@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
|
|
22
22
|
with:
|
|
23
23
|
languages: python
|
|
24
24
|
|
|
25
25
|
- name: Autobuild
|
|
26
|
-
uses: github/codeql-action/autobuild@
|
|
26
|
+
uses: github/codeql-action/autobuild@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
|
|
27
27
|
|
|
28
28
|
- name: Perform CodeQL Analysis
|
|
29
|
-
uses: github/codeql-action/analyze@
|
|
29
|
+
uses: github/codeql-action/analyze@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4
|
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
|
|
21
21
|
- name: Check for new commits
|
|
22
22
|
id: check_commits
|
|
23
|
-
uses: isaac-cf-wong/detect-git-changes-action@
|
|
23
|
+
uses: isaac-cf-wong/detect-git-changes-action@ecc6bf915a7987eb27f70d560c8067a69b943cb5 # v0.0.14
|
|
24
24
|
with:
|
|
25
25
|
use-latest-tag: true
|
|
26
26
|
|
|
@@ -29,18 +29,18 @@ repos:
|
|
|
29
29
|
- id: taplo-format
|
|
30
30
|
|
|
31
31
|
- repo: https://github.com/crate-ci/typos
|
|
32
|
-
rev: v1.
|
|
32
|
+
rev: v1.48.0
|
|
33
33
|
hooks:
|
|
34
34
|
- id: typos
|
|
35
35
|
args: []
|
|
36
36
|
|
|
37
37
|
- repo: https://github.com/rbubley/mirrors-prettier
|
|
38
|
-
rev: v3.9.
|
|
38
|
+
rev: v3.9.4
|
|
39
39
|
hooks:
|
|
40
40
|
- id: prettier
|
|
41
41
|
|
|
42
42
|
- repo: https://github.com/DavidAnson/markdownlint-cli2
|
|
43
|
-
rev: v0.
|
|
43
|
+
rev: v0.23.0
|
|
44
44
|
hooks:
|
|
45
45
|
- id: markdownlint-cli2
|
|
46
46
|
args:
|
|
@@ -48,7 +48,7 @@ repos:
|
|
|
48
48
|
- .markdownlint.yaml
|
|
49
49
|
|
|
50
50
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
51
|
-
rev: 0.11.
|
|
51
|
+
rev: 0.11.26
|
|
52
52
|
hooks:
|
|
53
53
|
# Update the uv lockfile
|
|
54
54
|
- id: uv-lock
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nullpol
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A package to perform model-independent polarization test of gravitational-wave signals.
|
|
5
5
|
Project-URL: Documentation, https://isaac-cf-wong.github.io/nullpol/
|
|
6
6
|
Project-URL: Source, https://github.com/isaac-cf-wong/nullpol
|
|
@@ -147,7 +147,7 @@ class DataAnalysisInput(BInput, Input):
|
|
|
147
147
|
raise NullpolError(f"Unsupported polarization-basis input: {modes}")
|
|
148
148
|
|
|
149
149
|
def _validate_polarization_model_setting(self):
|
|
150
|
-
supported_modes = ["b", "c", "
|
|
150
|
+
supported_modes = ["b", "c", "p", "l", "x", "y"]
|
|
151
151
|
# Check whether the modes are supported.
|
|
152
152
|
for mode in self.polarization_modes:
|
|
153
153
|
if mode not in supported_modes:
|
|
@@ -166,12 +166,12 @@ class Collector:
|
|
|
166
166
|
analysis_output["Notes"] = []
|
|
167
167
|
|
|
168
168
|
if analysis.comment is not None and (
|
|
169
|
-
corresponding_analysis is None or analysis.comment not in corresponding_analysis
|
|
169
|
+
corresponding_analysis is None or analysis.comment not in corresponding_analysis.get("Notes", [])
|
|
170
170
|
):
|
|
171
171
|
# We only want to add the comment to the notes if it doesn't already exist
|
|
172
172
|
analysis_output["Notes"].append(analysis.comment)
|
|
173
173
|
|
|
174
|
-
if analysis.review.status:
|
|
174
|
+
if analysis.review is not None and analysis.review.status:
|
|
175
175
|
if analysis.review.status.lower() == "approved":
|
|
176
176
|
analysis_output["ReviewStatus"] = "pass"
|
|
177
177
|
elif analysis.review.status.lower() == "rejected":
|
|
@@ -181,7 +181,8 @@ class Collector:
|
|
|
181
181
|
messages = sorted(analysis.review.messages, key=lambda k: k.timestamp)
|
|
182
182
|
if len(messages) > 0 and (
|
|
183
183
|
corresponding_analysis is None
|
|
184
|
-
or f"{messages[0].timestamp:%Y-%m-%d}: {messages[0].message}"
|
|
184
|
+
or f"{messages[0].timestamp:%Y-%m-%d}: {messages[0].message}"
|
|
185
|
+
not in corresponding_analysis.get("Notes", [])
|
|
185
186
|
):
|
|
186
187
|
analysis_output["Notes"].append(f"{messages[0].timestamp:%Y-%m-%d}: {messages[0].message}")
|
|
187
188
|
|
|
@@ -285,6 +286,69 @@ class Collector:
|
|
|
285
286
|
return {}
|
|
286
287
|
|
|
287
288
|
|
|
289
|
+
def validate_gr_pe_result(result: dict) -> bool:
|
|
290
|
+
"""Validate whether a PE result is suitable as the basis for a TGR analysis.
|
|
291
|
+
|
|
292
|
+
The result must be complete, non-deprecated, and not an online or
|
|
293
|
+
exploratory run.
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
result : dict
|
|
298
|
+
Metadata for the result to be validated.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
-------
|
|
302
|
+
bool
|
|
303
|
+
Validity of the result.
|
|
304
|
+
"""
|
|
305
|
+
uid = result.get("UID", "").lower()
|
|
306
|
+
if not uid or uid == "online" or uid.startswith("exp") or uid.startswith("detchar"):
|
|
307
|
+
return False
|
|
308
|
+
if result.get("RunStatus") != "complete":
|
|
309
|
+
return False
|
|
310
|
+
if result.get("ReviewStatus") != "pass":
|
|
311
|
+
return False
|
|
312
|
+
if result.get("Deprecated", False):
|
|
313
|
+
return False
|
|
314
|
+
# Ensure required files are present for actual PE results
|
|
315
|
+
if "ResultFile" not in result or "ConfigFile" not in result:
|
|
316
|
+
return False
|
|
317
|
+
return "PESummaryResultFile" in result
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def identify_basis_production(metadata) -> dict:
|
|
321
|
+
"""Identify the PE result that will be used as the basis for TGR analyses.
|
|
322
|
+
|
|
323
|
+
The IllustrativeResult is tried first. If it passes full validation
|
|
324
|
+
(complete, non-deprecated, not online/exp*/detchar*, and has all required
|
|
325
|
+
files) it is returned. If it is not available or does not pass, the function
|
|
326
|
+
falls back to the first result that passes the full validation. Returns an
|
|
327
|
+
empty dict if no valid result is found.
|
|
328
|
+
|
|
329
|
+
Parameters
|
|
330
|
+
----------
|
|
331
|
+
metadata :
|
|
332
|
+
CBCFlow superevent metadata.
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
-------
|
|
336
|
+
dict
|
|
337
|
+
Result metadata for the basis production, or empty dict if none found.
|
|
338
|
+
"""
|
|
339
|
+
illustrative_result_name = metadata.data["ParameterEstimation"].get("IllustrativeResult", None)
|
|
340
|
+
if illustrative_result_name is not None:
|
|
341
|
+
for result in metadata.data["ParameterEstimation"].get("Results", []):
|
|
342
|
+
if result["UID"] == illustrative_result_name and validate_gr_pe_result(result):
|
|
343
|
+
return result
|
|
344
|
+
|
|
345
|
+
for result in metadata.data["ParameterEstimation"]["Results"]:
|
|
346
|
+
if validate_gr_pe_result(result):
|
|
347
|
+
return result
|
|
348
|
+
|
|
349
|
+
return {}
|
|
350
|
+
|
|
351
|
+
|
|
288
352
|
# Functionality for information which flows from cbcflow into Asimov
|
|
289
353
|
# pylint: disable=too-few-public-methods
|
|
290
354
|
class Applicator:
|
|
@@ -369,6 +433,8 @@ class Applicator:
|
|
|
369
433
|
ligo["preferred event"] = event["UID"]
|
|
370
434
|
ligo["false alarm rate"] = event["FAR"]
|
|
371
435
|
event_time = event["GPSTime"]
|
|
436
|
+
if event_time is None:
|
|
437
|
+
raise ValueError(f"No preferred GraceDB event found for {sid}. Cannot determine event time.")
|
|
372
438
|
ligo["sname"] = sid
|
|
373
439
|
|
|
374
440
|
# also add the sampling rate to the output
|
|
@@ -387,22 +453,22 @@ class Applicator:
|
|
|
387
453
|
"event time": event_time,
|
|
388
454
|
}
|
|
389
455
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
if
|
|
405
|
-
|
|
456
|
+
basis_result = identify_basis_production(metadata)
|
|
457
|
+
if not basis_result:
|
|
458
|
+
raise ValueError(
|
|
459
|
+
"No valid GR PE result found in the library. The IllustrativeResult "
|
|
460
|
+
"(if set) and all other results either have incomplete run status, "
|
|
461
|
+
"are deprecated, or are excluded by UID."
|
|
462
|
+
)
|
|
463
|
+
gr_pe = {
|
|
464
|
+
"available": True,
|
|
465
|
+
"UID GR PE": basis_result["UID"],
|
|
466
|
+
"result file path": "/" + basis_result["ResultFile"]["Path"].split(":/")[-1],
|
|
467
|
+
"config file path": "/" + basis_result["ConfigFile"]["Path"].split(":/")[-1],
|
|
468
|
+
"pesummary result path": "/" + basis_result["PESummaryResultFile"]["Path"].split(":/")[-1],
|
|
469
|
+
}
|
|
470
|
+
if "WaveformApproximant" in basis_result:
|
|
471
|
+
quality["waveform approximant"] = basis_result["WaveformApproximant"]
|
|
406
472
|
|
|
407
473
|
# now, we need to read in the information from the config file
|
|
408
474
|
# we need the reference frequency, the psd dict and the calibration dict
|
|
@@ -410,8 +476,10 @@ class Applicator:
|
|
|
410
476
|
bilby_config = bilby_config_to_asimov(config_file)
|
|
411
477
|
|
|
412
478
|
# read in the psd information if present
|
|
413
|
-
if "psds"
|
|
479
|
+
if bilby_config.get("psds") is not None:
|
|
414
480
|
gr_pe["psds"] = bilby_config.pop("psds")
|
|
481
|
+
elif "psds" in bilby_config:
|
|
482
|
+
bilby_config.pop("psds")
|
|
415
483
|
output["gr pe info"] = gr_pe.copy()
|
|
416
484
|
output["gr pe info"]["approximant"] = bilby_config["waveform"]["approximant"]
|
|
417
485
|
# config file and cbcflow can disagree about which data to use (for example, preferred frame was updated)
|
|
@@ -37,8 +37,11 @@ def read_bilby_ini_file(file: str) -> dict:
|
|
|
37
37
|
def _convert_string_to_dict(string):
|
|
38
38
|
try:
|
|
39
39
|
return bilby_pipe.utils.convert_string_to_dict(string)
|
|
40
|
-
except (bilby_pipe.utils.BilbyPipeError, AttributeError):
|
|
41
|
-
|
|
40
|
+
except (bilby_pipe.utils.BilbyPipeError, AttributeError, TypeError):
|
|
41
|
+
try:
|
|
42
|
+
return literal_eval(string)
|
|
43
|
+
except (ValueError, SyntaxError):
|
|
44
|
+
return string
|
|
42
45
|
|
|
43
46
|
|
|
44
47
|
def fill_in_pol_specific_metadata(analysis, corresponding_analysis): # pylint: disable=unused-argument
|
|
@@ -479,7 +479,7 @@ class TestTimeFrequencyDataContext:
|
|
|
479
479
|
# Create filter with wrong shape
|
|
480
480
|
wrong_filter = np.random.rand(10, 20) # Wrong dimensions
|
|
481
481
|
|
|
482
|
-
with pytest.raises(
|
|
482
|
+
with pytest.raises(ValueError, match="does not match the time frequency filter"):
|
|
483
483
|
TimeFrequencyDataContext(
|
|
484
484
|
interferometers=ifos,
|
|
485
485
|
wavelet_frequency_resolution=2.0,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""Unit tests for :meth:`DataAnalysisInput._validate_polarization_model_setting`.
|
|
2
|
+
|
|
3
|
+
This guards the fix in commit ``74b4fc3`` where the supported-modes list
|
|
4
|
+
contained a duplicate ``"b"`` and was missing ``"p"`` (plus), causing a valid
|
|
5
|
+
``"p"`` mode to be rejected in both ``polarization-modes`` and
|
|
6
|
+
``polarization-basis`` validation.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from nullpol.cli.data_analysis import DataAnalysisInput
|
|
14
|
+
from nullpol.utils import NullpolError
|
|
15
|
+
|
|
16
|
+
SUPPORTED = ["b", "c", "p", "l", "x", "y"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _make_input(modes, basis):
|
|
20
|
+
"""Build a DataAnalysisInput bypassing the heavy __init__.
|
|
21
|
+
|
|
22
|
+
The validation method only reads the ``polarization_modes`` and
|
|
23
|
+
``polarization_basis`` properties, which are backed by the private
|
|
24
|
+
``_polarization_modes`` / ``_polarization_basis`` attributes.
|
|
25
|
+
"""
|
|
26
|
+
obj = object.__new__(DataAnalysisInput)
|
|
27
|
+
obj._polarization_modes = list(modes)
|
|
28
|
+
obj._polarization_basis = list(basis)
|
|
29
|
+
return obj
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TestValidatePolarizationModelSetting:
|
|
33
|
+
"""Tests for :meth:`_validate_polarization_model_setting`."""
|
|
34
|
+
|
|
35
|
+
@pytest.mark.parametrize("mode", SUPPORTED)
|
|
36
|
+
def test_each_supported_mode_accepted_alone(self, mode):
|
|
37
|
+
"""Every one of the six canonical modes is accepted in polarization-modes."""
|
|
38
|
+
_make_input([mode], [mode])._validate_polarization_model_setting()
|
|
39
|
+
|
|
40
|
+
def test_all_six_modes_accepted_together(self):
|
|
41
|
+
"""All six modes (b, c, p, l, x, y) pass when used together."""
|
|
42
|
+
_make_input(SUPPORTED, SUPPORTED)._validate_polarization_model_setting()
|
|
43
|
+
|
|
44
|
+
def test_plus_mode_accepted(self):
|
|
45
|
+
"""Regression: ``"p"`` (plus) must be accepted -- it was rejected before the fix."""
|
|
46
|
+
_make_input(["p", "c"], ["p"])._validate_polarization_model_setting()
|
|
47
|
+
|
|
48
|
+
def test_plus_mode_rejected_before_fix_list(self):
|
|
49
|
+
"""Sanity check: the fixed list no longer contains a duplicate ``b``."""
|
|
50
|
+
# If the old buggy list ["b","c","b","l","x","y"] were restored, "p" would fail.
|
|
51
|
+
assert SUPPORTED == ["b", "c", "p", "l", "x", "y"]
|
|
52
|
+
assert SUPPORTED.count("b") == 1
|
|
53
|
+
assert "p" in SUPPORTED
|
|
54
|
+
|
|
55
|
+
@pytest.mark.parametrize("bad_mode", ["z", "a", "B", "pc", "", "plus"])
|
|
56
|
+
def test_invalid_mode_in_modes_rejected(self, bad_mode):
|
|
57
|
+
"""An unsupported mode in ``polarization-modes`` raises NullpolError."""
|
|
58
|
+
with pytest.raises(NullpolError, match="polarization-modes"):
|
|
59
|
+
_make_input([bad_mode], [bad_mode])._validate_polarization_model_setting()
|
|
60
|
+
|
|
61
|
+
@pytest.mark.parametrize("bad_mode", ["z", "a", "P"])
|
|
62
|
+
def test_invalid_mode_in_basis_rejected(self, bad_mode):
|
|
63
|
+
"""An unsupported mode in ``polarization-basis`` raises NullpolError."""
|
|
64
|
+
with pytest.raises(NullpolError, match="polarization-basis"):
|
|
65
|
+
_make_input(["p", "c"], [bad_mode])._validate_polarization_model_setting()
|
|
66
|
+
|
|
67
|
+
def test_basis_not_subset_of_modes_rejected(self):
|
|
68
|
+
"""A basis mode that is supported but not in ``polarization-modes`` is rejected."""
|
|
69
|
+
# "b" is a supported mode, but it is not in the modes list here.
|
|
70
|
+
with pytest.raises(NullpolError, match="Basis mode"):
|
|
71
|
+
_make_input(["p", "c"], ["b"])._validate_polarization_model_setting()
|
|
72
|
+
|
|
73
|
+
def test_empty_basis_accepted(self):
|
|
74
|
+
"""An empty basis is valid (all modes are derived)."""
|
|
75
|
+
_make_input(["p", "c"], [])._validate_polarization_model_setting()
|
|
76
|
+
|
|
77
|
+
def test_basis_subset_of_modes_accepted(self):
|
|
78
|
+
"""A basis that is a strict subset of the modes is valid."""
|
|
79
|
+
_make_input(["p", "c", "b", "l"], ["p", "c"])._validate_polarization_model_setting()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Asimov integration tests."""
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Shared fixtures for the asimov integration tests.
|
|
2
|
+
|
|
3
|
+
The ``asimov`` and ``cbcflow`` packages are *optional* dependencies (see the
|
|
4
|
+
``asimov`` extra in ``pyproject.toml``) and are not installed in the default
|
|
5
|
+
test environment. Importing :mod:`nullpol.integrations.asimov` normally
|
|
6
|
+
triggers ``asimov.py`` / ``pesummary.py`` which require those packages (and
|
|
7
|
+
``htcondor``) at import time.
|
|
8
|
+
|
|
9
|
+
To allow the pure-Python logic in :mod:`nullpol.integrations.asimov.tgrflow`
|
|
10
|
+
and :mod:`nullpol.integrations.asimov.utility` to be exercised without the
|
|
11
|
+
optional deps, these fixtures:
|
|
12
|
+
|
|
13
|
+
1. Inject lightweight :class:`~unittest.mock.MagicMock` stub modules for
|
|
14
|
+
``asimov``, ``asimov.event`` and ``cbcflow`` into :data:`sys.modules`.
|
|
15
|
+
2. Replace the real ``nullpol.integrations.asimov`` package object with an
|
|
16
|
+
empty package module whose ``__path__`` points at the real source directory,
|
|
17
|
+
so the submodules ``tgrflow`` and ``utility`` can be loaded by the import
|
|
18
|
+
machinery without running the package ``__init__`` (and therefore without
|
|
19
|
+
importing the real ``asimov`` / ``htcondor``).
|
|
20
|
+
|
|
21
|
+
All stubs are scoped to the test via :class:`pytest.MonkeyPatch` and are
|
|
22
|
+
removed again afterwards.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
import sys
|
|
29
|
+
import types
|
|
30
|
+
from unittest import mock
|
|
31
|
+
|
|
32
|
+
import pytest
|
|
33
|
+
|
|
34
|
+
_STUB_MODULE_PATHS = ("asimov", "asimov.event", "cbcflow")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _make_stub(name: str) -> mock.MagicMock:
|
|
38
|
+
"""Build a stub module that auto-creates any accessed attribute."""
|
|
39
|
+
mod = mock.MagicMock(name=name)
|
|
40
|
+
mod.__name__ = name
|
|
41
|
+
mod.__path__ = []
|
|
42
|
+
return mod
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.fixture
|
|
46
|
+
def asimov_libs(monkeypatch):
|
|
47
|
+
"""Import the asimov integration modules with optional deps stubbed out.
|
|
48
|
+
|
|
49
|
+
Returns a :class:`types.SimpleNamespace` exposing the loaded ``tgrflow``
|
|
50
|
+
and ``utility`` modules together with the most commonly used symbols.
|
|
51
|
+
"""
|
|
52
|
+
for path in _STUB_MODULE_PATHS:
|
|
53
|
+
monkeypatch.setitem(sys.modules, path, _make_stub(path))
|
|
54
|
+
|
|
55
|
+
# Replace the real asimov package __init__ with an empty package module so
|
|
56
|
+
# that importing its submodules does not trigger the heavy asimov.py /
|
|
57
|
+
# pesummary.py imports (which require the real asimov + htcondor packages).
|
|
58
|
+
import nullpol
|
|
59
|
+
|
|
60
|
+
asimov_dir = os.path.join(os.path.dirname(nullpol.__file__), "integrations", "asimov")
|
|
61
|
+
fake_pkg = types.ModuleType("nullpol.integrations.asimov")
|
|
62
|
+
fake_pkg.__path__ = [asimov_dir]
|
|
63
|
+
fake_pkg.__package__ = "nullpol.integrations.asimov"
|
|
64
|
+
monkeypatch.setitem(sys.modules, "nullpol.integrations.asimov", fake_pkg)
|
|
65
|
+
|
|
66
|
+
from nullpol.integrations.asimov import tgrflow, utility
|
|
67
|
+
|
|
68
|
+
return types.SimpleNamespace(
|
|
69
|
+
tgrflow=tgrflow,
|
|
70
|
+
utility=utility,
|
|
71
|
+
validate_gr_pe_result=tgrflow.validate_gr_pe_result,
|
|
72
|
+
identify_basis_production=tgrflow.identify_basis_production,
|
|
73
|
+
Applicator=tgrflow.Applicator,
|
|
74
|
+
Collector=tgrflow.Collector,
|
|
75
|
+
convert_string_to_dict=utility._convert_string_to_dict,
|
|
76
|
+
bilby_config_to_asimov=utility.bilby_config_to_asimov,
|
|
77
|
+
deep_update=utility.deep_update,
|
|
78
|
+
)
|