Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,16 @@ dmypy.json

#Jims Development
stata/various_stata_development__files
playing/

# outputs folder
/notebooks/outputs/
/notebooks/old/

# test output
/test.xlsx
/outputs/

# test datasets that can't b shared
# test datasets that can't be shared
UKDA-7401-stata12/
notebooks/old/test.ipynb
22 changes: 10 additions & 12 deletions acro/acro_stata_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,8 @@ def extract_aggfun_values_from_options(
if word in varnames:
if word not in cell_content["values"]:
cell_content["values"].append(word)
else:
if word not in cell_content["aggfuncs"]:
cell_content["aggfuncs"].append(word)
elif word not in cell_content["aggfuncs"]:
cell_content["aggfuncs"].append(word)
return cell_content


Expand Down Expand Up @@ -545,16 +544,15 @@ def extract_strings(input_string: str) -> list[str]:
colstring = words[-1]

# If the string has parentheses
else:
# If there are parentheses at the start of the string
if input_string.startswith("("):
rowstring, input_string = extract_var_within_parentheses(input_string)
colstring, tablestring = extract_colstring_tablestring(input_string)
# If there are parentheses at the start of the string
elif input_string.startswith("("):
rowstring, input_string = extract_var_within_parentheses(input_string)
colstring, tablestring = extract_colstring_tablestring(input_string)

else:
# If there are parentheses at the middle of the string
rowstring, input_string = extract_var_before_parentheses(input_string)
colstring, tablestring = extract_colstring_tablestring(input_string)
else:
# If there are parentheses at the middle of the string
rowstring, input_string = extract_var_before_parentheses(input_string)
colstring, tablestring = extract_colstring_tablestring(input_string)
varlist = [rowstring, colstring, tablestring]
return varlist

Expand Down
3 changes: 3 additions & 0 deletions acro/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""ACRO: Global constants."""

ARTIFACTS_DIR = "acro_artifacts"
# https://www.sdmx.io/learning/essential-sdmx-structural-modelling/003-concept-mapping/
DIMENSION_URI: str = "sdmx.model.Dimension"
MEASURE_URI: str = "sdmx.model.Measure"
4 changes: 4 additions & 0 deletions acro/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ zeros_are_disclosive: True
# default rounding base for the 'round' mitigation strategy on tables
safe_round_base: 5

# federated mode: if true, skip checks and output evidence.json for the
# trusted aggregator instead of running checks locally
federated: false

################################################################################
# Blocked file extensions #
################################################################################
Expand Down
58 changes: 38 additions & 20 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies = [
"pandas<=2.3.3",
"PyYAML",
"statsmodels",
"rdflib",
]

[tool.setuptools.dynamic]
Expand Down Expand Up @@ -87,11 +88,10 @@ packages = {find = {exclude = ["data*", "docs*", "notebooks*", "test*"]}}
"acro" = ["default.yaml"]

[tool.ruff]
indent-width = 4
line-length = 88
target-version = "py310"

lint.select = [
select = [
"ANN", # flake8-annotations
"ARG", # flake8-unused-arguments
"B", # flake8-bugbear
Expand Down Expand Up @@ -132,7 +132,7 @@ exclude = [
"stata/*",
]

lint.ignore = [
ignore = [
"ANN401", # dynamically typed Any
"E501", # line too long — enforced by ruff formatter, redundant in linter
"PD009", # .iat vs .iloc — .iat is intentional for scalar access
Expand All @@ -144,30 +144,48 @@ lint.ignore = [
"S301", # unsafe pickle — used intentionally in this project
]

[tool.ruff.lint.per-file-ignores]
"test/*.py" = ["ANN", "PD", "PLR0402", "PLR0913", "PLR5501", "SIM300", "T20"]
"notebooks/**" = ["E402", "PD", "T20"]
"acro/acro_stata_parser.py" = ["C901", "C417", "PLR5501", "T20"]
"acro/acro_tables.py" = ["EM", "PD002", "PD011", "PD101", "PLR0913", "PLR1714", "PLW2901", "SIM102", "SIM108"]
"acro/acro_regression.py" = ["B026"]
"acro/record.py" = ["DTZ005", "EM", "PLW2901", "T20"]
"acro/acro.py" = ["SIM113"]
"acro/utils.py" = ["PD002"]

extend-ignore = [
"ANN001", # missing argument type annotation - style preference
"ANN101", # missing self type annotation - style preference
"ANN201", # missing return type annotation - style preference
"C901", # function too complex - existing code
"C417", # unnecessary map - existing code
"EM101", # exception string literal - existing code
"EM102", # exception f-string literal - existing code
"B026", # star-arg unpacking - existing code
"PLR0912", # too many branches - existing code
"PLR0913", # too many arguments - existing code
"PLW2901", # for loop variable overwritten - acceptable pattern
"PLC1901", # comparison to empty string - acceptable pattern
"S506", # unsafe loader - intentional in yaml.load
"DTZ005", # datetime.now without tz - acceptable
"PD002", # inplace=True - acceptable for existing code
"PD011", # .values vs .to_numpy() - acceptable for existing code
"PD901", # bad variable name (df) - existing code
"E402", # module level imports not at top - acceptable for notebooks
"SIM102", # combine if statements - existing code
"SIM118", # use in dict instead of in dict.keys() - minor
"SIM210", # use bool() instead of if-else - minor
"ARG001", # unused argument - acceptable for override methods
"PT001", # pytest style - acceptable
"PD003", # pandas style - acceptable
]

[tool.ruff.lint.pylint]
[tool.ruff.pylint]
max-args = 12
max-returns = 10

[tool.ruff.lint.pep8-naming]
extend-ignore-names = ["X", "X_train", "X_predict"]
[tool.ruff.pep8-naming]
ignore-names = ["X", "X_train", "X_predict"]

[tool.ruff.lint.pydocstyle]
[tool.ruff.pydocstyle]
convention = "numpy"

[tool.ruff.format]
docstring-code-format = true
docstring-code-line-length = 20
[tool.ruff.per-file-ignores]
"notebooks/**" = ["T201"]
"notebooks/old/**" = ["T201"]
# docstring-code-format = true
# docstring-code-line-length = 20

[tool.pylint]
master.py-version = "3.10"
Expand Down
32 changes: 16 additions & 16 deletions test/test_initial.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def test_crosstab_without_suppression(data):
output = acro.results.get_index(0)
correct_summary: str = "fail; threshold: 6 cells may need suppressing; "
assert output.summary == correct_summary
assert 48 == output.output[0]["R/G"].sum()
assert output.output[0]["R/G"].sum() == 48


def test_crosstab_with_aggfunc_mode(data):
Expand All @@ -105,7 +105,7 @@ def test_crosstab_with_aggfunc_mode(data):
output = acro.results.get_index(0)
correct_summary: str = "fail; all-values-are-same: 1 cells may need suppressing; "
assert output.summary == correct_summary
assert 913000 == output.output[0]["R/G"].iat[0]
assert output.output[0]["R/G"].iat[0] == 913000


def test_crosstab_with_aggfunc_sum(data, acro):
Expand Down Expand Up @@ -200,8 +200,8 @@ def test_pivot_table_without_suppression(data):
data, index=["grant_type"], values=["inc_grants"], aggfunc=["mean", "std"]
)
output_0 = acro.results.get_index(0)
assert 36293992.0 == output_0.output[0]["mean"]["inc_grants"].sum()
assert "pass" == output_0.summary
assert output_0.output[0]["mean"]["inc_grants"].sum() == 36293992.0
assert output_0.summary == "pass"


def test_pivot_table_pass(data, acro):
Expand Down Expand Up @@ -832,7 +832,7 @@ def test_crosstab_with_totals_without_suppression(data, acro):
acro.suppress = False
_ = acro.crosstab(data.year, data.grant_type, margins=True)
output = acro.results.get_index(0)
assert 153 == output.output[0]["All"].iat[0]
assert output.output[0]["All"].iat[0] == 153

total_rows = output.output[0].iloc[-1, 0:4].sum()
total_cols = output.output[0].loc[2010:2015, "All"].sum()
Expand All @@ -843,7 +843,7 @@ def test_crosstab_with_totals_with_suppression(data, acro):
"""Test the crosstab with both margins and suppression are true."""
_ = acro.crosstab(data.year, data.grant_type, margins=True)
output = acro.results.get_index(0)
assert 145 == output.output[0]["All"].iat[0]
assert output.output[0]["All"].iat[0] == 145

total_rows = output.output[0].iloc[-1, 0:3].sum()
total_cols = output.output[0].loc[2010:2015, "All"].sum()
Expand All @@ -857,7 +857,7 @@ def test_crosstab_with_totals_with_suppression_hierarchical(data, acro):
[data.year, data.survivor], [data.grant_type, data.status], margins=True
)
output = acro.results.get_index(0)
assert 47 == output.output[0]["All"].iat[0]
assert output.output[0]["All"].iat[0] == 47

total_rows = (output.output[0].loc[("All", ""), :].sum()) - output.output[0][
"All"
Expand All @@ -879,8 +879,8 @@ def test_crosstab_with_totals_with_suppression_with_mean(data, acro):
margins=True,
)
output = acro.results.get_index(0)
assert 8689781 == output.output[0]["All"].iat[0]
assert 5425170.5 == output.output[0]["All"].iat[6]
assert output.output[0]["All"].iat[0] == 8689781
assert output.output[0]["All"].iat[6] == 5425170.5
assert "R/G" not in output.output[0].columns


Expand Down Expand Up @@ -908,7 +908,7 @@ def test_crosstab_with_manual_totals_with_suppression(data, acro):
"""Test crosstab when margins and suppression are true with the total manual function."""
_ = acro.crosstab(data.year, data.grant_type, margins=True, show_suppressed=True)
output = acro.results.get_index(0)
assert 145 == output.output[0]["All"].iat[0]
assert output.output[0]["All"].iat[0] == 145

total_rows = output.output[0].iloc[-1, 0:4].sum()
total_cols = output.output[0].loc[2010:2015, "All"].sum()
Expand All @@ -929,7 +929,7 @@ def test_crosstab_with_manual_totals_with_suppression_hierarchical(data, acro):
show_suppressed=True,
)
output = acro.results.get_index(0)
assert 47 == output.output[0]["All"].iat[0]
assert output.output[0]["All"].iat[0] == 47

total_rows = (output.output[0].loc[("All", ""), :].sum()) - output.output[0][
"All"
Expand Down Expand Up @@ -957,8 +957,8 @@ def test_crosstab_with_manual_totals_with_suppression_with_aggfunc_mean(data, ac
show_suppressed=True,
)
output = acro.results.get_index(0)
assert 8689780 == round(output.output[0]["All"].iat[0])
assert 5425170 == round(output.output[0]["All"].iat[6])
assert round(output.output[0]["All"].iat[0]) == 8689780
assert round(output.output[0]["All"].iat[6]) == 5425170
assert "R/G" in output.output[0].columns
assert np.isnan(output.output[0]["R/G"].iat[0])

Expand All @@ -979,8 +979,8 @@ def test_hierarchical_crosstab_with_manual_totals_with_mean(data, acro):
show_suppressed=True,
)
output = acro.results.get_index(0)
assert 1385162 == round(output.output[0]["All"].iat[0])
assert 5434959 == round(output.output[0]["All"].iat[12])
assert round(output.output[0]["All"].iat[0]) == 1385162
assert round(output.output[0]["All"].iat[12]) == 5434959
assert ("G", "Dead in 2015") in output.output[0].columns
assert np.isnan(output.output[0][("G", "Dead in 2015")].iat[0])

Expand Down Expand Up @@ -1021,7 +1021,7 @@ def test_pivot_table_with_totals_with_suppression(data, acro):
margins=True,
)
output = acro.results.get_index(0)
assert 74 == output.output[0][("inc_grants", "All")].iat[0]
assert output.output[0][("inc_grants", "All")].iat[0] == 74

total_rows = output.output[0].iloc[-1, 0:3].sum()
total_cols = output.output[0].loc[2010:2015, ("inc_grants", "All")].sum()
Expand Down
3 changes: 1 addition & 2 deletions test/test_stata17_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import pandas as pd
import pytest

import acro.stata_config as stata_config
from acro import ACRO
from acro import ACRO, stata_config
from acro.acro_stata_parser import find_brace_word, parse_and_run, parse_table_details
from acro.acro_tables import AGGFUNC

Expand Down
3 changes: 1 addition & 2 deletions test/test_stata_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
import pandas as pd
import pytest

import acro.stata_config as stata_config
from acro import ACRO
from acro import ACRO, stata_config
from acro.acro_stata_parser import (
apply_stata_expstmt,
apply_stata_ifstmt,
Expand Down