Skip to content

Commit a9961c0

Browse files
authored
Merge pull request #1109 from jdebacker/fix_log
Merging
2 parents fabccaa + 33b2203 commit a9961c0

9 files changed

Lines changed: 97 additions & 53 deletions

File tree

.github/dependabot.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Basic `dependabot.yml` file with
2+
# minimum configuration for three package managers
3+
4+
version: 2
5+
updates:
6+
# Enable version updates for npm
7+
- package-ecosystem: "npm"
8+
# Look for `package.json` and `lock` files in the `root` directory
9+
directory: "/"
10+
# Check the npm registry for updates every week
11+
schedule:
12+
interval: "weekly"
13+
14+
# Enable version updates for Docker
15+
- package-ecosystem: "docker"
16+
# Look for a `Dockerfile` in the `root` directory
17+
directory: "/"
18+
# Check for updates once a week
19+
schedule:
20+
interval: "weekly"
21+
22+
# Enable version updates for GitHub Actions
23+
- package-ecosystem: "github-actions"
24+
# Workflow files stored in the default location of `.github/workflows`
25+
# You don't need to specify `/.github/workflows` for `directory`. You can use `directory: "/"`.
26+
directory: "/"
27+
schedule:
28+
interval: "weekly"

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.15.9] - 2026-04-23 03:00:00
9+
10+
### Added
11+
12+
- Create a `ogcore` logging environment so that logging specificed in `ogcore.config` is not overridden by other logging configurations in user code. See PR [#1109](https://github.com/PSLmodels/OG-Core/pull/1109).
13+
814
## [0.15.8] - 2026-04-16 00:30:00
915

1016
### Added
1117

1218
- Updates the `uv.lock` file to the current version of `ogcore` package (0.15.8)
1319
- Adds `'**.lock'` to the paths in `build_and_test.yml` so that any changes to the `uv.lock` file trigger the GH Action CI tests in `build_and_test.yml`
1420
- Incorporates the dependabot updates to `uv.lock` versions from [PR 1105](https://github.com/PSLmodels/OG-Core/pull/1105) and [PR 1106](https://github.com/PSLmodels/OG-Core/pull/1106).
21+
- Includes [PR 1111](https://github.com/PSLmodels/OG-Core/pull/1111) and [PR 1112](https://github.com/PSLmodels/OG-Core/pull/1112) that change `build_and_test.yml` to not upload CodeCov statistics for PRs generated by dependabots and updates the `codecov-action` to v5.
1522

1623
## [0.15.7] - 2026-04-15 20:00:00
1724

@@ -538,6 +545,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
538545
- Any earlier versions of OG-USA can be found in the [`OG-Core`](https://github.com/PSLmodels/OG-Core) repository [release history](https://github.com/PSLmodels/OG-Core/releases) from [v.0.6.4](https://github.com/PSLmodels/OG-Core/releases/tag/v0.6.4) (Jul. 20, 2021) or earlier.
539546

540547

548+
[0.15.9]: https://github.com/PSLmodels/OG-Core/compare/v0.15.8...v0.15.9
541549
[0.15.8]: https://github.com/PSLmodels/OG-Core/compare/v0.15.7...v0.15.8
542550
[0.15.7]: https://github.com/PSLmodels/OG-Core/compare/v0.15.6...v0.15.7
543551
[0.15.6]: https://github.com/PSLmodels/OG-Core/compare/v0.15.5...v0.15.6

ogcore/SS.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import warnings
99
import logging
1010

11+
logger = logging.getLogger(__name__)
12+
1113
if not SHOW_RUNTIME:
1214
warnings.simplefilter("ignore", RuntimeWarning)
1315

@@ -333,9 +335,8 @@ def inner_loop(outer_loop_vars, p, client):
333335
results = client.gather(futures)
334336
except Exception as e:
335337
# Cancel remaining futures and fall back to serial computation
336-
import logging
337338

338-
logging.warning(
339+
logger.warning(
339340
f"Dask computation failed with error: {e}. "
340341
"Falling back to serial computation."
341342
)
@@ -812,9 +813,9 @@ def SS_solver(
812813
if iteration > 10:
813814
if dist_vec[iteration] - dist_vec[iteration - 1] > 0:
814815
nu_ss /= 2.0
815-
logging.info(f"New value of nu: {nu_ss}")
816+
logger.info(f"New value of nu: {nu_ss}")
816817
iteration += 1
817-
logging.info(f"Iteration: {iteration} Distance: {dist}")
818+
logger.info(f"Iteration: {iteration} Distance: {dist}")
818819

819820
# Generate the SS values of variables, including euler errors
820821
bssmat_s = np.append(np.zeros((1, p.J)), bmat[:-1, :], axis=0)
@@ -845,7 +846,7 @@ def SS_solver(
845846
debt_service,
846847
new_borrowing_f,
847848
) = fiscal.get_D_ss(r_gov_ss, Yss, p)
848-
logging.info(f"SS debt = {Dss}, {new_borrowing_f}")
849+
logger.info(f"SS debt = {Dss}, {new_borrowing_f}")
849850
w_open = firm.get_w_from_r(p.world_int_rate[-1], p, "SS")
850851
K_demand_open_ss = np.zeros(p.M)
851852
for m in range(p.M):
@@ -1103,7 +1104,7 @@ def SS_solver(
11031104
# Fill in arrays, noting that M-1 industries only produce consumption goods
11041105
G_vec_ss = np.zeros(p.M)
11051106
# Map consumption goods back to demands for production goods
1106-
logging.info(f"IO: {p.io_matrix.T.shape}, C: {C_vec_ss.shape}")
1107+
logger.info(f"IO: {p.io_matrix.T.shape}, C: {C_vec_ss.shape}")
11071108
C_m_vec_ss = np.dot(p.io_matrix.T, C_vec_ss)
11081109
G_vec_ss[-1] = Gss
11091110
I_d_vec_ss = np.zeros(p.M)
@@ -1124,18 +1125,18 @@ def SS_solver(
11241125
net_capital_outflows_vec,
11251126
RM_vec_ss,
11261127
)
1127-
logging.info(f"Foreign debt holdings = {D_f_ss}")
1128-
logging.info(f"Foreign capital holdings = {K_f_ss}")
1129-
logging.info(f"resource constraint: {RC}")
1128+
logger.info(f"Foreign debt holdings = {D_f_ss}")
1129+
logger.info(f"Foreign capital holdings = {K_f_ss}")
1130+
logger.info(f"resource constraint: {RC}")
11301131

11311132
if Gss < 0:
1132-
logging.warning(
1133+
logger.warning(
11331134
"Steady state government spending is negative to satisfy"
11341135
+ " budget"
11351136
)
11361137

11371138
if ENFORCE_SOLUTION_CHECKS and (max(np.absolute(RC)) > p.RC_SS):
1138-
logging.warning(f"Resource Constraint Difference: {RC}")
1139+
logger.warning(f"Resource Constraint Difference: {RC}")
11391140
err = "Steady state aggregate resource constraint not satisfied"
11401141
raise RuntimeError(err)
11411142

@@ -1144,11 +1145,11 @@ def SS_solver(
11441145

11451146
euler_savings = euler_errors[: p.S, :]
11461147
euler_labor_leisure = euler_errors[p.S :, :]
1147-
logging.info(
1148+
logger.info(
11481149
"Maximum error in labor FOC = "
11491150
f"{np.absolute(euler_labor_leisure).max()}"
11501151
)
1151-
logging.info(
1152+
logger.info(
11521153
f"Maximum error in savings FOC = {np.absolute(euler_savings).max()}"
11531154
)
11541155

@@ -1353,7 +1354,7 @@ def SS_fsolve(guesses, *args):
13531354
+ [error_TR]
13541355
)
13551356
error_string = [f"{error:.3e}" for error in errors]
1356-
logging.info(f"GE loop errors = {error_string}")
1357+
logger.info(f"GE loop errors = {error_string}")
13571358

13581359
return errors
13591360

@@ -1436,7 +1437,7 @@ def run_SS(p, client=None):
14361437
p.S,
14371438
p.J,
14381439
) and np.squeeze(ss_solutions["Y_m"].shape) == (p.M):
1439-
logging.info("Using previous solutions for SS")
1440+
logger.info("Using previous solutions for SS")
14401441
(
14411442
b_guess,
14421443
n_guess,
@@ -1497,12 +1498,12 @@ def run_SS(p, client=None):
14971498
tol=p.mindist_SS,
14981499
)
14991500
else:
1500-
logging.warning(
1501+
logger.warning(
15011502
"Dimensions of previous solutions for SS do not match"
15021503
)
15031504
use_new_guesses = True
15041505
except KeyError:
1505-
logging.warning("KeyError: previous solutions for SS not found")
1506+
logger.warning("KeyError: previous solutions for SS not found")
15061507
use_new_guesses = True
15071508
if p.baseline or not p.reform_use_baseline_solution or use_new_guesses:
15081509
# Loop over initial guesses of r and TR until find a solution
@@ -1512,7 +1513,7 @@ def run_SS(p, client=None):
15121513
k = 0
15131514
while not SS_solved and k < len(DEV_FACTOR_LIST) - 1:
15141515
for k, v in enumerate(DEV_FACTOR_LIST):
1515-
logging.info(
1516+
logger.info(
15161517
"SS using initial guess factors for r and TR of "
15171518
+ f"{v[0]} and {v[1]} respectively."
15181519
)

ogcore/TPI.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import logging
2222
from distributed import wait
2323

24+
logger = logging.getLogger(__name__)
25+
2426
if not SHOW_RUNTIME:
2527
warnings.simplefilter("ignore", RuntimeWarning)
2628

@@ -597,7 +599,7 @@ def run_TPI(p, client=None):
597599
ubi = p.ubi_nom_array / factor
598600
UBI = aggr.get_L(ubi[: p.T], p, "TPI")
599601

600-
logging.info(
602+
logger.info(
601603
f"Government spending breakpoints are tG1: {p.tG1}; and tG2: {p.tG2}"
602604
)
603605

@@ -828,7 +830,7 @@ def run_TPI(p, client=None):
828830
results = client.gather(futures)
829831
except Exception as e:
830832
# Cancel remaining futures and fall back to serial computation
831-
logging.warning(
833+
logger.warning(
832834
f"Dask computation failed with error: {e}. "
833835
"Falling back to serial computation for this iteration."
834836
)
@@ -1221,27 +1223,27 @@ def run_TPI(p, client=None):
12211223
TR[: p.T] = utils.convex_combo(TR_new[: p.T], TR[: p.T], p.nu)
12221224
guesses_b = utils.convex_combo(b_mat, guesses_b, p.nu)
12231225
guesses_n = utils.convex_combo(n_mat, guesses_n, p.nu)
1224-
logging.info(
1226+
logger.info(
12251227
f"w diff: {(wnew[: p.T] - w[: p.T]).max()}, "
12261228
+ f"{(wnew[: p.T] - w[: p.T]).min()}"
12271229
)
1228-
logging.info(
1230+
logger.info(
12291231
f"r diff: {(rnew[: p.T] - r[: p.T]).max()}, "
12301232
+ f"{(rnew[: p.T] - r[: p.T]).min()}"
12311233
)
1232-
logging.info(
1234+
logger.info(
12331235
f"r_p diff: {(r_p_new[: p.T] - r_p[: p.T]).max()}, "
12341236
+ f"{(r_p_new[: p.T] - r_p[: p.T]).min()}"
12351237
)
1236-
logging.info(
1238+
logger.info(
12371239
f"p_m diff: {(new_p_m[: p.T, :] - p_m[: p.T, :]).max()}, "
12381240
+ f"{(new_p_m[: p.T, :] - p_m[: p.T, :]).min()}"
12391241
)
1240-
logging.info(
1242+
logger.info(
12411243
f"BQ diff: {(BQnew[: p.T] - BQ[: p.T]).max()}, "
12421244
+ f"{(BQnew[: p.T] - BQ[: p.T]).min()}"
12431245
)
1244-
logging.info(
1246+
logger.info(
12451247
f"TR diff: {(TR_new[: p.T] - TR[: p.T]).max()}, "
12461248
+ f"{(TR_new[: p.T] - TR[: p.T]).min()}"
12471249
)
@@ -1266,8 +1268,8 @@ def run_TPI(p, client=None):
12661268
# nu /= 2
12671269
# print 'New Value of nu:', nu
12681270
TPIiter += 1
1269-
logging.info(f"Iteration: {TPIiter}")
1270-
logging.info(f"Distance: {TPIdist}")
1271+
logger.info(f"Iteration: {TPIiter}")
1272+
logger.info(f"Distance: {TPIdist}")
12711273

12721274
# Compute effective and marginal tax rates for all agents
12731275
num_params = len(p.mtrx_params[0][0])
@@ -1405,9 +1407,9 @@ def run_TPI(p, client=None):
14051407

14061408
# Compute resource constraint error
14071409
rce_max = np.amax(np.abs(RC_error))
1408-
logging.info(f"Max absolute value resource constraint error: {rce_max}")
1410+
logger.info(f"Max absolute value resource constraint error: {rce_max}")
14091411

1410-
logging.info("Checking time path for violations of constraints.")
1412+
logger.info("Checking time path for violations of constraints.")
14111413
for t in range(p.T):
14121414
household.constraint_checker_TPI(
14131415
b_mat[t], n_mat[t], c_mat[t], t, p.ltilde
@@ -1416,8 +1418,8 @@ def run_TPI(p, client=None):
14161418
eul_savings = euler_errors[:, : p.S, :]
14171419
eul_laborleisure = euler_errors[:, p.S :, :]
14181420

1419-
logging.info(f"Max Euler error, savings: {np.abs(eul_savings).max()}")
1420-
logging.info(
1421+
logger.info(f"Max Euler error, savings: {np.abs(eul_savings).max()}")
1422+
logger.info(
14211423
f"Max Euler error labor supply: {np.abs(eul_laborleisure).max()}"
14221424
)
14231425

@@ -1520,7 +1522,7 @@ def run_TPI(p, client=None):
15201522
pickle.dump(output, f)
15211523

15221524
if np.any(G) < 0:
1523-
logging.warning(
1525+
logger.warning(
15241526
"Government spending is negative along transition path"
15251527
+ " to satisfy budget"
15261528
)

ogcore/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Specify what is available to import from the ogcore package.
33
"""
44

5+
import ogcore.config # noqa: F401 -- sets up the ogcore logger on first import
56
from ogcore.SS import * # noqa: F403
67
from ogcore.TPI import * # noqa: F403
78
from ogcore.aggregates import * # noqa: F403
@@ -20,4 +21,4 @@
2021
from ogcore.txfunc import * # noqa: F403
2122
from ogcore.utils import * # noqa: F403
2223

23-
__version__ = "0.15.8"
24+
__version__ = "0.15.9"

ogcore/config.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,16 @@ def set_logging_level(verbose=True):
2525
VERBOSE = verbose
2626
level = logging.INFO if verbose else logging.WARNING
2727

28-
# Configure the root logger
29-
logging.basicConfig(level=level, format="%(message)s")
30-
31-
# Also set the ogcore logger specifically
28+
# Configure the ogcore logger with an explicit StreamHandler so it
29+
# works regardless of whether another package (e.g. distributed/dask)
30+
# has already called basicConfig() on the root logger.
3231
logger = logging.getLogger("ogcore")
3332
logger.setLevel(level)
33+
if not logger.handlers:
34+
handler = logging.StreamHandler()
35+
handler.setFormatter(logging.Formatter("%(message)s"))
36+
logger.addHandler(handler)
37+
logger.propagate = False
3438

3539
return level
3640

ogcore/household.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from ogcore import tax, utils
1010
import logging
1111

12+
logger = logging.getLogger(__name__)
13+
1214
"""
1315
------------------------------------------------------------------------
1416
Functions
@@ -829,29 +831,27 @@ def constraint_checker_SS(bssmat, nssmat, cssmat, ltilde):
829831
Warnings: if constraints are violated, warnings printed
830832
831833
"""
832-
logging.info("Checking constraints on capital, labor, and consumption.")
834+
logger.info("Checking constraints on capital, labor, and consumption.")
833835

834836
if (bssmat < 0).any():
835-
logging.info("WARNING: There is negative capital stock")
837+
logger.info("WARNING: There is negative capital stock")
836838
flag2 = False
837839
if (nssmat < 0).any():
838-
logging.info(
840+
logger.info(
839841
"WARNING: Labor supply violates nonnegativity constraints."
840842
)
841843
flag2 = True
842844
if (nssmat > ltilde).any():
843-
logging.info("WARNING: Labor supply violates the ltilde constraint.")
845+
logger.info("WARNING: Labor supply violates the ltilde constraint.")
844846
flag2 = True
845847
if flag2 is False:
846-
logging.info(
848+
logger.info(
847849
"There were no violations of the constraints on labor supply.",
848850
)
849851
if (cssmat < 0).any():
850-
logging.info(
851-
"WARNING: Consumption violates nonnegativity constraints."
852-
)
852+
logger.info("WARNING: Consumption violates nonnegativity constraints.")
853853
else:
854-
logging.info(
854+
logger.info(
855855
"There were no violations of the constraints on consumption."
856856
)
857857

@@ -876,22 +876,22 @@ def constraint_checker_TPI(b_dist, n_dist, c_dist, t, ltilde):
876876
877877
"""
878878
if (b_dist <= 0).any():
879-
logging.info(
879+
logger.info(
880880
"WARNING: Aggregate capital is less than or equal to"
881881
f" zero in period {t}."
882882
)
883883
if (n_dist < 0).any():
884-
logging.info(
884+
logger.info(
885885
"WARNING: Labor supply violates nonnegativity"
886886
f" constraints in period {t}."
887887
)
888888
if (n_dist > ltilde).any():
889-
logging.info(
889+
logger.info(
890890
"\tWARNING: Labor suppy violates the ltilde constraint",
891891
" in period %.f." % t,
892892
)
893893
if (c_dist < 0).any():
894-
logging.info(
894+
logger.info(
895895
"\tWARNING: Consumption violates nonnegativity",
896896
" constraints in period %.f." % t,
897897
)

0 commit comments

Comments
 (0)