policyengine-taxsim 3.2.2__tar.gz → 3.2.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/CHANGELOG.md +14 -0
  2. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/PKG-INFO +7 -1
  3. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/README.md +6 -0
  4. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/__init__.py +1 -1
  5. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/api.py +7 -1
  6. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/input_mapper.py +10 -0
  7. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/runners/policyengine_runner.py +17 -3
  8. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/pyproject.toml +1 -1
  9. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/scripts/dashboard-refresh-requirements.txt +1 -1
  10. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_mappers.py +14 -0
  11. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_mtr_branch_overrides.py +1 -0
  12. policyengine_taxsim-3.2.4/tests/test_student_status.py +238 -0
  13. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.claude/commands/diagnose-issue.md +0 -0
  14. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.claude/cspell.json +0 -0
  15. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/bump_version.py +0 -0
  16. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/fetch_version.py +0 -0
  17. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/get-changelog-diff.sh +0 -0
  18. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/has-functional-changes.sh +0 -0
  19. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/is-version-number-acceptable.sh +0 -0
  20. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/publish-git-tag.sh +0 -0
  21. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/workflows/ci.yml +0 -0
  22. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/workflows/deploy-pages.yml +0 -0
  23. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/workflows/refresh-dashboard.yml +0 -0
  24. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.github/workflows/scorp-e2e.yml +0 -0
  25. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/.gitignore +0 -0
  26. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/CLAUDE.md +0 -0
  27. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/LICENSE +0 -0
  28. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/Makefile +0 -0
  29. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/changelog.d/.gitkeep +0 -0
  30. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/cps_households.csv +0 -0
  31. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/.env.production +0 -0
  32. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/.gitignore +0 -0
  33. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/README.md +0 -0
  34. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/bun.lock +0 -0
  35. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/jsconfig.json +0 -0
  36. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/next.config.mjs +0 -0
  37. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/package.json +0 -0
  38. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/postcss.config.mjs +0 -0
  39. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/assets/logos/policyengine/white.svg +0 -0
  40. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/config-data.json +0 -0
  41. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2021/comparison_results_2021.csv +0 -0
  42. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2021/summary_2021.json +0 -0
  43. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2022/comparison_results_2022.csv +0 -0
  44. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2022/summary_2022.json +0 -0
  45. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2023/comparison_results_2023.csv +0 -0
  46. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2023/summary_2023.json +0 -0
  47. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2024/comparison_results_2024.csv +0 -0
  48. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2024/summary_2024.json +0 -0
  49. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2025/comparison_results_2025.csv +0 -0
  50. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/data/2025/summary_2025.json +0 -0
  51. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/manifest.json +0 -0
  52. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/policyengine.png +0 -0
  53. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/robots.txt +0 -0
  54. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/public/sample_ecps_2024.csv +0 -0
  55. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/scripts/extract-config.cjs +0 -0
  56. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/social-posts.md +0 -0
  57. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/app/dashboard/page.jsx +0 -0
  58. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/app/documentation/page.jsx +0 -0
  59. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/app/globals.css +0 -0
  60. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/app/layout.jsx +0 -0
  61. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/app/page.jsx +0 -0
  62. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/app/run/page.jsx +0 -0
  63. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/CsvRunner.jsx +0 -0
  64. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/DashboardContent.jsx +0 -0
  65. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/DocumentationContent.jsx +0 -0
  66. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/GitHubIssues.jsx +0 -0
  67. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/Header.jsx +0 -0
  68. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/HouseholdCard.jsx +0 -0
  69. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/LandingContent.jsx +0 -0
  70. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/MetricsRow.jsx +0 -0
  71. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/RunContent.jsx +0 -0
  72. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/StateFilter.jsx +0 -0
  73. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/StateTable.jsx +0 -0
  74. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/StateTaxNote.jsx +0 -0
  75. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/YearTabs.jsx +0 -0
  76. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/__tests__/DocumentationContent.test.jsx +0 -0
  77. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/__tests__/LandingContent.test.jsx +0 -0
  78. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/common/Button.jsx +0 -0
  79. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/common/ErrorMessage.jsx +0 -0
  80. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/common/LoadingSpinner.jsx +0 -0
  81. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/components/common/SortableTableHeader.jsx +0 -0
  82. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/constants/index.js +0 -0
  83. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/hooks/useHouseholdData.js +0 -0
  84. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/hooks/useYearData.js +0 -0
  85. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/test/setup.js +0 -0
  86. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/__tests__/formatters.test.js +0 -0
  87. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/__tests__/githubApi.test.js +0 -0
  88. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/basePath.js +0 -0
  89. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/codeHighlight.jsx +0 -0
  90. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/colors.js +0 -0
  91. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/configLoader.js +0 -0
  92. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/dataLoader.js +0 -0
  93. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/dataProcessing.js +0 -0
  94. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/exportData.js +0 -0
  95. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/formatters.js +0 -0
  96. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/src/utils/githubApi.js +0 -0
  97. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/vercel.json +0 -0
  98. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/dashboard/vitest.config.mjs +0 -0
  99. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/docs/dashboard-refresh.md +0 -0
  100. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/docs/scorp-validation.md +0 -0
  101. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/issue_analysis/README.md +0 -0
  102. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/policyengine_taxsim_household_with_dependent_output.csv +0 -0
  103. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/policyengine_taxsim_household_with_dependent_single_parent_output.csv +0 -0
  104. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/policyengine_taxsim_joint_household_output.csv +0 -0
  105. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/policyengine_taxsim_single_household_output.csv +0 -0
  106. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/taxsim35_household_with_dependent_output.csv +0 -0
  107. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/taxsim35_household_with_dependent_single_parent_output.csv +0 -0
  108. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/taxsim35_joint_household_output.csv +0 -0
  109. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/output/taxsim35_single_household_output.csv +0 -0
  110. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/package-lock.json +0 -0
  111. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/package.json +0 -0
  112. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/cli.py +0 -0
  113. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/comparison/__init__.py +0 -0
  114. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/comparison/comparator.py +0 -0
  115. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/comparison/statistics.py +0 -0
  116. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/config/variable_mappings.yaml +0 -0
  117. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/__init__.py +0 -0
  118. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/io.py +0 -0
  119. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/marginal_rates.py +0 -0
  120. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/output_mapper.py +0 -0
  121. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/scorp.py +0 -0
  122. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/scorp_reform.py +0 -0
  123. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/state_output_resolver.py +0 -0
  124. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/text_formatter.py +0 -0
  125. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/utils.py +0 -0
  126. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/core/yaml_generator.py +0 -0
  127. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/runners/__init__.py +0 -0
  128. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/runners/base_runner.py +0 -0
  129. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/runners/remote_taxsim_runner.py +0 -0
  130. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/runners/stitched_runner.py +0 -0
  131. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/policyengine_taxsim/runners/taxsim_runner.py +0 -0
  132. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/README.md +0 -0
  133. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/.Rbuildignore +0 -0
  134. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/.gitignore +0 -0
  135. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/DESCRIPTION +0 -0
  136. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/LICENSE +0 -0
  137. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/NAMESPACE +0 -0
  138. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/R/calculate_taxes.R +0 -0
  139. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/R/compare.R +0 -0
  140. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/R/setup.R +0 -0
  141. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/R/zzz.R +0 -0
  142. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/r-package/policyenginetaxsim/README.md +0 -0
  143. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsim35/taxsim-latest-windows.exe +0 -0
  144. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsim35/taxsim35-osx.exe +0 -0
  145. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsim35/taxsim35-unix.exe +0 -0
  146. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsim35/taxsim_input_joint_household.csv +0 -0
  147. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsim35/taxsim_input_single_household.csv +0 -0
  148. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsim35/taxsim_input_with_1_dep.csv +0 -0
  149. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsim35/taxsim_input_with_1_dep_single_parent.csv +0 -0
  150. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsimtest/README.md +0 -0
  151. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsimtest/taxsim-docker-wrapper.sh +0 -0
  152. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsimtest/taxsimtest-linux.Dockerfile +0 -0
  153. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsimtest/taxsimtest-linux.exe +0 -0
  154. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsimtest/taxsimtest-osx.exe +0 -0
  155. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/resources/taxsimtest/taxsimtest-windows.exe +0 -0
  156. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/run-project.ipynb +0 -0
  157. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/scripts/convert_h5_to_taxsim.py +0 -0
  158. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/scripts/dashboard-refresh.in +0 -0
  159. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/scripts/refresh_dashboard.py +0 -0
  160. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/scripts/validate_scorp_alignment.py +0 -0
  161. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/taxsiminputfile_2021.csv +0 -0
  162. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_addmed_excluded_from_fiitax.py +0 -0
  163. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_assume_w2_wages.py +0 -0
  164. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_cli_entry_point.py +0 -0
  165. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_cli_idtl5.py +0 -0
  166. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_dashboard_refresh.py +0 -0
  167. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_de_staxbc_elected_path.py +0 -0
  168. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_deterministic_ordering.py +0 -0
  169. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_e2e.py +0 -0
  170. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_eitc_investment_income_baskets.py +0 -0
  171. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_fica_output.py +0 -0
  172. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_imputed_transfers_zeroed.py +0 -0
  173. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_income_scaled_tolerance.py +0 -0
  174. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_intermediate_output_mappings.py +0 -0
  175. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_itemized_aggregates.py +0 -0
  176. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_ma_premium_pay.py +0 -0
  177. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_ma_taxable_income.py +0 -0
  178. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_married_filing_separately.py +0 -0
  179. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_md_local_tax_parity.py +0 -0
  180. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_me_affordability_payment.py +0 -0
  181. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_me_ptfc_utilities.py +0 -0
  182. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_mn_credit_outputs.py +0 -0
  183. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_multi_state.py +0 -0
  184. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_net_of_rebates.py +0 -0
  185. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_nonprop_mapping.py +0 -0
  186. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_ny_separate_payments.py +0 -0
  187. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_or_kicker_output.py +0 -0
  188. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_otherprop_niit.py +0 -0
  189. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_passthrough_qbid.py +0 -0
  190. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_performance.py +0 -0
  191. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_public_contract.py +0 -0
  192. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_runner_input_order.py +0 -0
  193. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_scorp_e2e.py +0 -0
  194. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_scorp_treatment.py +0 -0
  195. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_spouse_income_splitting.py +0 -0
  196. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_stata_io.py +0 -0
  197. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_state_codes.py +0 -0
  198. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_state_output_adapters.py +0 -0
  199. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_state_zero_salt.py +0 -0
  200. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_statefip.py +0 -0
  201. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_stitched_runner.py +0 -0
  202. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_taxsim32_dependent_counts.py +0 -0
  203. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_taxsim_debug_output.py +0 -0
  204. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_taxsim_docker_wrapper.py +0 -0
  205. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_taxsim_opt30.py +0 -0
  206. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_taxsim_options.py +0 -0
  207. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_three_pass_disable_salt.py +0 -0
  208. {policyengine_taxsim-3.2.2 → policyengine_taxsim-3.2.4}/tests/test_transfers_mapping.py +0 -0
@@ -1,3 +1,17 @@
1
+ ## [3.2.4] - 2026-10-22
2
+
3
+ ### Fixed
4
+
5
+ - Treat every person in a TAXSIM record as a non-student, so a spouse aged 17 or younger no longer gets IRC 21(d)(2) deemed earned income for the child and dependent care credit, which TAXSIM does not give.
6
+
7
+
8
+ ## [3.2.3] - 2026-10-22
9
+
10
+ ### Fixed
11
+
12
+ - Stop trusting the compromised eMudhra CA certificates: pin certifi 2026.10.19 in the dashboard refresh environment, and make the Modal API image upgrade ca-certificates and install certifi 2026.10.19 or later.
13
+
14
+
1
15
  ## [3.2.2] - 2026-10-20
2
16
 
3
17
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: policyengine-taxsim
3
- Version: 3.2.2
3
+ Version: 3.2.4
4
4
  Summary: A TAXSIM emulator using PolicyEngine US
5
5
  Project-URL: Homepage, https://github.com/PolicyEngine/policyengine-taxsim
6
6
  Project-URL: Bug Tracker, https://github.com/PolicyEngine/policyengine-taxsim/issues
@@ -317,6 +317,12 @@ The emulator accepts CSV files with the following variables:
317
317
  | age2 | Second dependent's age | |
318
318
  | ageN | Nth dependent's age | Taxsim only allows up to 8 dependents |
319
319
 
320
+ TAXSIM input has no student status, so the emulator treats every person as a
321
+ non-student (`is_full_time_student` is false). A dependent aged 19 to 23 is
322
+ therefore not a qualifying child through the student age test, and a spouse
323
+ aged 17 or younger gets no IRC 21(d)(2) deemed earned income for the child
324
+ and dependent care credit.
325
+
320
326
  ### Income
321
327
 
322
328
  | Variable | Description |
@@ -280,6 +280,12 @@ The emulator accepts CSV files with the following variables:
280
280
  | age2 | Second dependent's age | |
281
281
  | ageN | Nth dependent's age | Taxsim only allows up to 8 dependents |
282
282
 
283
+ TAXSIM input has no student status, so the emulator treats every person as a
284
+ non-student (`is_full_time_student` is false). A dependent aged 19 to 23 is
285
+ therefore not a qualifying child through the student age test, and a spouse
286
+ aged 17 or younger gets no IRC 21(d)(2) deemed earned income for the child
287
+ and dependent care credit.
288
+
283
289
  ### Income
284
290
 
285
291
  | Variable | Description |
@@ -4,4 +4,4 @@ from .cli import cli
4
4
 
5
5
  __all__ = ["generate_household", "export_household", "cli"]
6
6
 
7
- __version__ = "3.2.2"
7
+ __version__ = "3.2.4"
@@ -14,13 +14,19 @@ Local (no Modal):
14
14
  import modal
15
15
  from typing import Literal
16
16
 
17
+ # Naming ca-certificates makes apt upgrade the operating-system CA store,
18
+ # which urllib uses, to the newest Debian package (20250419+deb13u1 on trixie,
19
+ # 20250419~deb12u2 on bookworm). certifi is the CA list that requests, used by
20
+ # resend, reads. Those packages and certifi 2026.10.19 no longer trust the
21
+ # compromised eMudhra root "emSign ECC Root CA - G3".
17
22
  image = (
18
23
  modal.Image.debian_slim(python_version="3.11")
19
- .apt_install("git")
24
+ .apt_install("git", "ca-certificates")
20
25
  .pip_install(
21
26
  "policyengine-taxsim @ git+https://github.com/PolicyEngine/policyengine-taxsim.git@main",
22
27
  "fastapi[standard]",
23
28
  "resend",
29
+ "certifi>=2026.10.19",
24
30
  )
25
31
  )
26
32
 
@@ -330,6 +330,16 @@ def form_household_situation(year, state, taxsim_vars):
330
330
  "medical_expense_health_insurance_premiums"
331
331
  ] = {str(year): 0}
332
332
 
333
+ # TAXSIM input has no student status, and the emulator does not default
334
+ # anyone to being a student (taxsim #532). PE-US imputes is_in_k12_school
335
+ # for ages 5 to 17, which made a spouse that age a full-time student with
336
+ # the IRC 21(d)(2) deemed earned income for the CDCC, which TAXSIM-35 does
337
+ # not give. Mirrors the Microsimulation path in PolicyEngineRunner.
338
+ for person_name in household_situation["people"]:
339
+ household_situation["people"][person_name]["is_full_time_student"] = {
340
+ str(year): False
341
+ }
342
+
333
343
  # Explicitly set SNAP to 0 for all SPM units to prevent PolicyEngine from imputing SNAP benefits
334
344
  # TAXSIM does not model SNAP, so we need to ensure it's not automatically calculated
335
345
  for spm_unit_name in household_situation["spm_units"]:
@@ -1249,9 +1249,9 @@ class PolicyEngineRunner(BaseTaxRunner):
1249
1249
  self, dataset, chunk_df: pd.DataFrame, zero_salt: bool = False
1250
1250
  ):
1251
1251
  """Build a Microsimulation from the chunk dataset and apply all
1252
- emulator overrides (SALT, QBID W-2 wages, rental QBID gate, MN CRP,
1253
- imputed-transfer zeroing, MD local tax zeroing, ME rent utilities, NY
1254
- separate payments).
1252
+ emulator overrides (student status, SALT, QBID W-2 wages, rental QBID
1253
+ gate, MN CRP, imputed-transfer zeroing, MD local tax zeroing, ME rent
1254
+ utilities, NY separate payments).
1255
1255
 
1256
1256
  ``zero_salt`` zeroes the federal deduction for state and local income
1257
1257
  or sales tax for every record in the chunk: state-0 records and
@@ -1262,6 +1262,20 @@ class PolicyEngineRunner(BaseTaxRunner):
1262
1262
  sim = Microsimulation(
1263
1263
  dataset=dataset, tax_benefit_system=scorp_tax_benefit_system()
1264
1264
  )
1265
+ # Student status: TAXSIM input has none, and the emulator does not
1266
+ # default anyone to being a student (taxsim #532). PE-US imputes
1267
+ # is_in_k12_school for ages 5 to 17, which made a spouse that age a
1268
+ # full-time student and gave them the IRC 21(d)(2) deemed earned
1269
+ # income for the CDCC, which TAXSIM-35 does not give. Pinned before
1270
+ # any calculate so no cached value depends on the imputation.
1271
+ n_persons = sim.get_variable_population("is_full_time_student").count
1272
+ for year in sorted(set(chunk_df["year"].astype(int))):
1273
+ _pin_input(
1274
+ sim,
1275
+ variable_name="is_full_time_student",
1276
+ value=np.zeros(n_persons, dtype=bool),
1277
+ period=str(year),
1278
+ )
1265
1279
  for year in sorted(set(chunk_df["year"].astype(int))):
1266
1280
  period = str(year)
1267
1281
  income = sim.calculate("partnership_s_corp_income", period=period)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "policyengine-taxsim"
7
- version = "3.2.2"
7
+ version = "3.2.4"
8
8
  description = "A TAXSIM emulator using PolicyEngine US"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -10,7 +10,7 @@ blosc2==4.13.1
10
10
  # via tables
11
11
  census==0.8.27
12
12
  # via spm-calculator
13
- certifi==2026.7.22
13
+ certifi==2026.10.19
14
14
  # via
15
15
  # httpcore
16
16
  # httpx
@@ -95,6 +95,7 @@ def test_import_single_household(sample_taxsim_input):
95
95
  "early_head_start": {"2021": 0},
96
96
  "commodity_supplemental_food_program": {"2021": 0},
97
97
  "medical_expense_health_insurance_premiums": {"2021": 0},
98
+ "is_full_time_student": {"2021": False},
98
99
  }
99
100
  },
100
101
  "spm_units": {
@@ -130,6 +131,7 @@ def test_import_single_household_without_state(sample_taxsim_input_without_state
130
131
  "early_head_start": {"2021": 0},
131
132
  "commodity_supplemental_food_program": {"2021": 0},
132
133
  "medical_expense_health_insurance_premiums": {"2021": 0},
134
+ "is_full_time_student": {"2021": False},
133
135
  }
134
136
  },
135
137
  "spm_units": {
@@ -172,6 +174,7 @@ def test_import_single_household_with_state_eq_0(sample_taxsim_input_with_state_
172
174
  "early_head_start": {"2021": 0},
173
175
  "commodity_supplemental_food_program": {"2021": 0},
174
176
  "medical_expense_health_insurance_premiums": {"2021": 0},
177
+ "is_full_time_student": {"2021": False},
175
178
  }
176
179
  },
177
180
  "spm_units": {
@@ -268,6 +271,7 @@ def test_joint_household(sample_taxsim_input_for_joint):
268
271
  "early_head_start": {"2023": 0},
269
272
  "commodity_supplemental_food_program": {"2023": 0},
270
273
  "medical_expense_health_insurance_premiums": {"2023": 0},
274
+ "is_full_time_student": {"2023": False},
271
275
  },
272
276
  "your partner": {
273
277
  "age": {"2023": 40},
@@ -278,6 +282,7 @@ def test_joint_household(sample_taxsim_input_for_joint):
278
282
  "early_head_start": {"2023": 0},
279
283
  "commodity_supplemental_food_program": {"2023": 0},
280
284
  "medical_expense_health_insurance_premiums": {"2023": 0},
285
+ "is_full_time_student": {"2023": False},
281
286
  },
282
287
  "your first dependent": {
283
288
  "age": {"2023": 10},
@@ -290,6 +295,7 @@ def test_joint_household(sample_taxsim_input_for_joint):
290
295
  "early_head_start": {"2023": 0},
291
296
  "commodity_supplemental_food_program": {"2023": 0},
292
297
  "medical_expense_health_insurance_premiums": {"2023": 0},
298
+ "is_full_time_student": {"2023": False},
293
299
  },
294
300
  "your second dependent": {
295
301
  "age": {"2023": 10},
@@ -302,6 +308,7 @@ def test_joint_household(sample_taxsim_input_for_joint):
302
308
  "early_head_start": {"2023": 0},
303
309
  "commodity_supplemental_food_program": {"2023": 0},
304
310
  "medical_expense_health_insurance_premiums": {"2023": 0},
311
+ "is_full_time_student": {"2023": False},
305
312
  },
306
313
  },
307
314
  "spm_units": {
@@ -381,6 +388,7 @@ def test_household_with_dependent(sample_taxsim_input_for_household_with_depende
381
388
  "early_head_start": {"2023": 0},
382
389
  "commodity_supplemental_food_program": {"2023": 0},
383
390
  "medical_expense_health_insurance_premiums": {"2023": 0},
391
+ "is_full_time_student": {"2023": False},
384
392
  },
385
393
  "your partner": {
386
394
  "age": {"2023": 40},
@@ -391,6 +399,7 @@ def test_household_with_dependent(sample_taxsim_input_for_household_with_depende
391
399
  "early_head_start": {"2023": 0},
392
400
  "commodity_supplemental_food_program": {"2023": 0},
393
401
  "medical_expense_health_insurance_premiums": {"2023": 0},
402
+ "is_full_time_student": {"2023": False},
394
403
  },
395
404
  "your first dependent": {
396
405
  "age": {"2023": 4},
@@ -403,6 +412,7 @@ def test_household_with_dependent(sample_taxsim_input_for_household_with_depende
403
412
  "early_head_start": {"2023": 0},
404
413
  "commodity_supplemental_food_program": {"2023": 0},
405
414
  "medical_expense_health_insurance_premiums": {"2023": 0},
415
+ "is_full_time_student": {"2023": False},
406
416
  },
407
417
  "your second dependent": {
408
418
  "age": {"2023": 10},
@@ -415,6 +425,7 @@ def test_household_with_dependent(sample_taxsim_input_for_household_with_depende
415
425
  "early_head_start": {"2023": 0},
416
426
  "commodity_supplemental_food_program": {"2023": 0},
417
427
  "medical_expense_health_insurance_premiums": {"2023": 0},
428
+ "is_full_time_student": {"2023": False},
418
429
  },
419
430
  },
420
431
  "spm_units": {
@@ -484,6 +495,7 @@ def test_household_with_dependent_single_parent(
484
495
  "early_head_start": {"2023": 0},
485
496
  "commodity_supplemental_food_program": {"2023": 0},
486
497
  "medical_expense_health_insurance_premiums": {"2023": 0},
498
+ "is_full_time_student": {"2023": False},
487
499
  },
488
500
  "your first dependent": {
489
501
  "age": {"2023": 4},
@@ -496,6 +508,7 @@ def test_household_with_dependent_single_parent(
496
508
  "early_head_start": {"2023": 0},
497
509
  "commodity_supplemental_food_program": {"2023": 0},
498
510
  "medical_expense_health_insurance_premiums": {"2023": 0},
511
+ "is_full_time_student": {"2023": False},
499
512
  },
500
513
  "your second dependent": {
501
514
  "age": {"2023": 10},
@@ -508,6 +521,7 @@ def test_household_with_dependent_single_parent(
508
521
  "early_head_start": {"2023": 0},
509
522
  "commodity_supplemental_food_program": {"2023": 0},
510
523
  "medical_expense_health_insurance_premiums": {"2023": 0},
524
+ "is_full_time_student": {"2023": False},
511
525
  },
512
526
  },
513
527
  "spm_units": {
@@ -160,6 +160,7 @@ OVERRIDE_RECORDS = (
160
160
  "7,2024,33,1,35,0,1,25000,0,0,0,0,0,0,2\n"
161
161
  )
162
162
  EXPECTED_OVERRIDES = {
163
+ "is_full_time_student",
163
164
  "state_and_local_sales_or_income_tax",
164
165
  "w2_wages_from_qualified_business",
165
166
  "rental_income_would_be_qualified",
@@ -0,0 +1,238 @@
1
+ """TAXSIM input has no student status, so every person is a non-student.
2
+
3
+ The emulator does not default anyone to being a student (taxsim #532, where
4
+ a 19-year-old dependent is a non-student). PE-US's ``is_full_time_student``
5
+ reads ``is_in_k12_school``, which PE-US imputes for ages 5 to 17, so a spouse
6
+ aged 17 or younger was a full-time student. IRC 21(d)(2)
7
+ (https://www.law.cornell.edu/uscode/text/26/21#d_2) then deemed them to have
8
+ earned income for the child and dependent care credit:
9
+
10
+ > (2) Special rule for spouse who is a student or incapable of caring for
11
+ > himself In the case of a spouse who is a student or a qualifying
12
+ > individual described in subsection (b)(1)(C), for purposes of paragraph
13
+ > (1), such spouse shall be deemed for each month during which such spouse
14
+ > is a full-time student at an educational institution, or is such a
15
+ > qualifying individual, to be gainfully employed and to have earned income
16
+ > of not less than— (A) $250 if subsection (c)(1) applies for the taxable
17
+ > year, or (B) $500 if subsection (c)(2) applies for the taxable year.
18
+
19
+ So a joint return whose 17-year-old spouse earned little or nothing got a
20
+ CDCC on $3,000 or $6,000 of deemed earnings, which TAXSIM does not give.
21
+
22
+ Ground truth (evidence rule 4): every expected value below is taxsimtest
23
+ output, build cd2026081819 (resources/taxsimtest/taxsimtest-osx.exe, sha256
24
+ 4a17af9c2adbea27b1e6cce240610aede264e008bcdf64b131e0c81220f62b8c), run with
25
+ idtl=2 on exactly the PROBES rows. TAXSIM-35 (resources/taxsim35/
26
+ taxsim35-osx.exe, cdate-2025Aug23) gives the same v24 on the 2021-2024 rows;
27
+ it does not run 2025. Before this change the emulator (policyengine-us
28
+ 2.58.0) gave v24 of 600, 1,200, 0, 1,200, 600 and 1,500 on rows 1-6.
29
+
30
+ The records come from Tax-Calculator's PE-TAXSIM validation
31
+ (PSLmodels/Tax-Calculator taxcalc/validation/pe_taxsim), where five c-sample
32
+ units in 2022-2024 had a 17-year-old spouse and this CDCC difference.
33
+ """
34
+
35
+ import io
36
+ import platform
37
+ import subprocess
38
+ from pathlib import Path
39
+
40
+ import numpy as np
41
+ import pandas as pd
42
+ import pytest
43
+ from hypothesis import HealthCheck, given, settings
44
+ from hypothesis import strategies as st
45
+
46
+ import policyengine_taxsim.runners.policyengine_runner as runner_module
47
+ from policyengine_taxsim import export_household, generate_household
48
+ from policyengine_taxsim.runners.policyengine_runner import (
49
+ PolicyEngineRunner,
50
+ TaxsimMicrosimDataset,
51
+ )
52
+
53
+ TAXSIMTEST_OSX = (
54
+ Path(__file__).resolve().parent.parent
55
+ / "resources"
56
+ / "taxsimtest"
57
+ / "taxsimtest-osx.exe"
58
+ )
59
+
60
+ PROBES = (
61
+ "taxsimid,year,state,mstat,page,sage,depx,age1,age2,pwages,swages,"
62
+ "childcare,idtl\n"
63
+ # Spouse 17 with no earnings, one child under 13.
64
+ "1,2024,0,2,40,17,1,3,0,60000,0,3000,2\n"
65
+ # Spouse 17 earning $2,000, two children under 13.
66
+ "2,2024,0,2,40,17,2,3,8,60000,2000,7000,2\n"
67
+ # Control: the same as row 1 with a spouse aged 40.
68
+ "3,2024,0,2,40,40,1,3,0,60000,0,3000,2\n"
69
+ # Both spouses 17 (Tax-Calculator c23 unit 7174 pattern).
70
+ "4,2023,0,2,17,17,2,3,8,93000,0,6000,2\n"
71
+ # Spouse 16 earning $1,000 (2025).
72
+ "5,2025,0,2,40,16,1,3,0,60000,1000,3000,2\n"
73
+ # 2021, when the CDCC was refundable.
74
+ "6,2021,0,2,40,17,1,3,0,60000,0,3000,2\n"
75
+ )
76
+
77
+ # taxsimid -> (v24, fiitax), taxsimtest build cd2026081819.
78
+ TAXSIMTEST_EXPECTED = {
79
+ 1: (0.0, 1232.00),
80
+ 2: (400.0, -1072.98),
81
+ 3: (0.0, 1232.00),
82
+ 4: (0.0, 3396.00),
83
+ 5: (200.0, 663.00),
84
+ 6: (0.0, -4010.00),
85
+ }
86
+
87
+
88
+ def _records(csv: str) -> pd.DataFrame:
89
+ return pd.read_csv(io.StringIO(csv))
90
+
91
+
92
+ def _taxsim_input(row: pd.Series) -> dict:
93
+ return {
94
+ key: int(value) if float(value).is_integer() else float(value)
95
+ for key, value in row.items()
96
+ }
97
+
98
+
99
+ @pytest.fixture(scope="module")
100
+ def runner_result():
101
+ result = PolicyEngineRunner(_records(PROBES)).run(show_progress=False)
102
+ result["taxsimid"] = result["taxsimid"].astype(int)
103
+ return result.set_index("taxsimid")
104
+
105
+
106
+ @pytest.mark.parametrize("taxsimid", sorted(TAXSIMTEST_EXPECTED))
107
+ def test_runner_matches_taxsimtest(runner_result, taxsimid):
108
+ v24, fiitax = TAXSIMTEST_EXPECTED[taxsimid]
109
+ row = runner_result.loc[taxsimid]
110
+ assert row["v24"] == pytest.approx(v24, abs=0.01)
111
+ assert row["fiitax"] == pytest.approx(fiitax, abs=0.01)
112
+
113
+
114
+ @pytest.mark.parametrize("taxsimid", sorted(TAXSIMTEST_EXPECTED))
115
+ def test_single_household_path_matches_taxsimtest(taxsimid):
116
+ records = _records(PROBES).set_index("taxsimid", drop=False)
117
+ taxsim_input = _taxsim_input(records.loc[taxsimid])
118
+ situation = generate_household(dict(taxsim_input))
119
+ out = export_household(taxsim_input, situation, False, False)
120
+ v24, fiitax = TAXSIMTEST_EXPECTED[taxsimid]
121
+ assert out["v24"] == pytest.approx(v24, abs=0.01)
122
+ assert out["fiitax"] == pytest.approx(fiitax, abs=0.01)
123
+
124
+
125
+ @pytest.mark.skipif(
126
+ platform.system() != "Darwin",
127
+ reason="Expected values were taken from taxsimtest-osx.exe (cd2026081819).",
128
+ )
129
+ def test_expectations_match_taxsimtest():
130
+ """The expected constants are the bundled taxsimtest binary's output."""
131
+ try:
132
+ completed = subprocess.run(
133
+ [str(TAXSIMTEST_OSX)],
134
+ input=_records(PROBES).to_csv(index=False),
135
+ capture_output=True,
136
+ text=True,
137
+ timeout=60,
138
+ )
139
+ except OSError as error:
140
+ pytest.skip(f"taxsimtest binary cannot run here: {error}")
141
+ assert completed.returncode == 0, completed.stderr
142
+ taxsim = pd.read_csv(io.StringIO(completed.stdout))
143
+ taxsim["taxsimid"] = taxsim["taxsimid"].astype(int)
144
+ taxsim = taxsim.set_index("taxsimid")
145
+ for taxsimid, (v24, fiitax) in TAXSIMTEST_EXPECTED.items():
146
+ assert taxsim.loc[taxsimid, "v24"] == pytest.approx(v24, abs=0.01)
147
+ assert taxsim.loc[taxsimid, "fiitax"] == pytest.approx(fiitax, abs=0.01)
148
+
149
+
150
+ def test_no_person_is_a_student_in_either_path():
151
+ df = _records(PROBES)
152
+ # The runner simulates each year separately (people differ by year).
153
+ for year, year_df in df.groupby("year"):
154
+ year_df = year_df.reset_index(drop=True)
155
+ runner = PolicyEngineRunner(year_df)
156
+ dataset = TaxsimMicrosimDataset(year_df)
157
+ try:
158
+ dataset.generate()
159
+ sim = runner._build_configured_sim(dataset, year_df)
160
+ student = sim.calculate("is_full_time_student", str(int(year)))
161
+ # Every PROBES row is a joint return: two filers plus dependents.
162
+ assert len(student) == 2 * len(year_df) + int(year_df["depx"].sum())
163
+ assert not np.asarray(student).any()
164
+ assert "is_full_time_student" in sim.input_variables
165
+ finally:
166
+ dataset.cleanup()
167
+
168
+ for _, row in df.iterrows():
169
+ situation = generate_household(_taxsim_input(row))
170
+ year = str(int(row["year"]))
171
+ for person in situation["people"].values():
172
+ assert person["is_full_time_student"] == {year: False}
173
+
174
+
175
+ # Property tests. Joint returns with wages only and children under 13, so
176
+ # each spouse's earned income for IRC 21(d) is their wages. Without deemed
177
+ # income the credit is at most the applicable percentage (never above 50%)
178
+ # of the lower earner's wages.
179
+ _joint_record = st.fixed_dictionaries(
180
+ {
181
+ "year": st.integers(2021, 2025),
182
+ "page": st.integers(25, 64),
183
+ "sage": st.integers(5, 17),
184
+ "depx": st.integers(1, 2),
185
+ "age1": st.integers(1, 12),
186
+ "age2": st.integers(1, 12),
187
+ "pwages": st.integers(0, 40).map(lambda k: 5000 * k),
188
+ "swages": st.integers(0, 8).map(lambda k: 500 * k),
189
+ "childcare": st.integers(0, 20).map(lambda k: 500 * k),
190
+ }
191
+ )
192
+
193
+
194
+ def _frame(records):
195
+ rows = []
196
+ for i, rec in enumerate(records, start=1):
197
+ row = dict(rec, taxsimid=i, state=0, mstat=2, idtl=2)
198
+ if row["depx"] < 2:
199
+ row["age2"] = 0
200
+ rows.append(row)
201
+ return pd.DataFrame(rows)
202
+
203
+
204
+ @settings(
205
+ max_examples=6,
206
+ deadline=None,
207
+ suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large],
208
+ )
209
+ @given(st.lists(_joint_record, min_size=1, max_size=5))
210
+ def test_minor_spouse_gets_no_deemed_earnings(records):
211
+ """For a spouse aged 5 to 17: (1) the CDCC is at most half the lower
212
+ earner's wages; (2) the runner and single-household paths agree; (3) the
213
+ CDCC is the same as for an otherwise identical spouse aged 40, since only
214
+ student status could separate them."""
215
+ df = _frame(records)
216
+ adult = df.assign(sage=40)
217
+
218
+ def run(frame):
219
+ out = PolicyEngineRunner(frame).run(show_progress=False)
220
+ out["taxsimid"] = out["taxsimid"].astype(int)
221
+ return out.set_index("taxsimid")
222
+
223
+ minor_out = run(df)
224
+ adult_out = run(adult)
225
+ for _, rec in df.iterrows():
226
+ taxsimid = int(rec["taxsimid"])
227
+ v24 = float(minor_out.loc[taxsimid, "v24"])
228
+ lower_wages = min(rec["pwages"], rec["swages"])
229
+ assert v24 <= 0.5 * lower_wages + 0.01
230
+ assert v24 == pytest.approx(float(adult_out.loc[taxsimid, "v24"]), abs=0.01)
231
+ taxsim_input = _taxsim_input(rec)
232
+ out = export_household(
233
+ taxsim_input, generate_household(dict(taxsim_input)), False, False
234
+ )
235
+ assert out["v24"] == pytest.approx(v24, abs=0.01)
236
+ assert out["fiitax"] == pytest.approx(
237
+ float(minor_out.loc[taxsimid, "fiitax"]), abs=0.01
238
+ )