[{"data":1,"prerenderedAt":3704},["ShallowReactive",2],{"navigation":3,"api-navigation":184,"\u002Flearn\u002Ftutorials\u002Floading-saving-cli":206,"docyard:crossref-index":3703},[4,8,155,174,180],{"title":5,"path":6,"stem":7},"Getting Started","\u002Fgetting-started","1.getting-started",{"title":9,"path":10,"stem":11,"children":12},"Learn","\u002Flearn","2.learn",[13,15,66,99,133],{"title":9,"path":10,"stem":14},"2.learn\u002Findex",{"title":16,"path":17,"stem":18,"children":19},"Tutorials","\u002Flearn\u002Ftutorials","2.learn\u002F1.tutorials\u002Findex",[20,21,26,30,34,38,42,46,50,54,58,62],{"title":16,"path":17,"stem":18},{"title":22,"path":23,"stem":24,"icon":25},"Why Laco?","\u002Flearn\u002Ftutorials\u002Fwhy-laco","2.learn\u002F1.tutorials\u002F01.why-laco","i-lucide-notebook",{"title":27,"path":28,"stem":29,"icon":25},"First Steps with Laco","\u002Flearn\u002Ftutorials\u002Ffirst-steps","2.learn\u002F1.tutorials\u002F02.first-steps",{"title":31,"path":32,"stem":33,"icon":25},"Lazy Call and Partial","\u002Flearn\u002Ftutorials\u002Flazy-call-and-partial","2.learn\u002F1.tutorials\u002F03.lazy-call-and-partial",{"title":35,"path":36,"stem":37,"icon":25},"Hyperparameters and Interpolation","\u002Flearn\u002Ftutorials\u002Fhyperparameters-and-interpolation","2.learn\u002F1.tutorials\u002F04.hyperparameters-and-interpolation",{"title":39,"path":40,"stem":41,"icon":25},"Loading, Saving, and the CLI","\u002Flearn\u002Ftutorials\u002Floading-saving-cli","2.learn\u002F1.tutorials\u002F05.loading-saving-cli",{"title":43,"path":44,"stem":45,"icon":25},"Nested Configs and Containers","\u002Flearn\u002Ftutorials\u002Fnested-configs-and-containers","2.learn\u002F1.tutorials\u002F06.nested-configs-and-containers",{"title":47,"path":48,"stem":49,"icon":25},"Typed Groups and Schemas","\u002Flearn\u002Ftutorials\u002Ftyped-groups-and-schemas","2.learn\u002F1.tutorials\u002F07.typed-groups-and-schemas",{"title":51,"path":52,"stem":53,"icon":25},"Pipeline Configs","\u002Flearn\u002Ftutorials\u002Fpipeline-configs","2.learn\u002F1.tutorials\u002F08.pipeline-configs",{"title":55,"path":56,"stem":57,"icon":25},"Tasks and the App Loop","\u002Flearn\u002Ftutorials\u002Ftasks-and-app-loop","2.learn\u002F1.tutorials\u002F09.tasks-and-app-loop",{"title":59,"path":60,"stem":61,"icon":25},"Tracing","\u002Flearn\u002Ftutorials\u002Ftracing","2.learn\u002F1.tutorials\u002F10.tracing",{"title":63,"path":64,"stem":65,"icon":25},"Production Patterns","\u002Flearn\u002Ftutorials\u002Fproduction-patterns","2.learn\u002F1.tutorials\u002F11.production-patterns",{"title":67,"path":68,"stem":69,"children":70},"Concepts","\u002Flearn\u002Fconcepts","2.learn\u002F2.concepts\u002Findex",[71,72,76,80,84,88,92,95],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75},"Config as Python","\u002Flearn\u002Fconcepts\u002Fconfig-as-python","2.learn\u002F2.concepts\u002F1.config-as-python",{"title":77,"path":78,"stem":79},"Lazy Construction","\u002Flearn\u002Fconcepts\u002Flazy-construction","2.learn\u002F2.concepts\u002F2.lazy-construction",{"title":81,"path":82,"stem":83},"Lie-Typing","\u002Flearn\u002Fconcepts\u002Flie-typing","2.learn\u002F2.concepts\u002F3.lie-typing",{"title":85,"path":86,"stem":87},"Interpolation","\u002Flearn\u002Fconcepts\u002Finterpolation","2.learn\u002F2.concepts\u002F4.interpolation",{"title":89,"path":90,"stem":91},"Typed Groups","\u002Flearn\u002Fconcepts\u002Ftyped-groups","2.learn\u002F2.concepts\u002F5.typed-groups",{"title":59,"path":93,"stem":94},"\u002Flearn\u002Fconcepts\u002Ftracing","2.learn\u002F2.concepts\u002F6.tracing",{"title":96,"path":97,"stem":98},"App Loop","\u002Flearn\u002Fconcepts\u002Fapp-loop","2.learn\u002F2.concepts\u002F7.app-loop",{"title":100,"path":101,"stem":102,"children":103},"How-To Guides","\u002Flearn\u002Fhow-to","2.learn\u002F3.how-to\u002Findex",[104,105,109,113,117,121,125,129],{"title":100,"path":101,"stem":102},{"title":106,"path":107,"stem":108},"Override Configs","\u002Flearn\u002Fhow-to\u002Foverride-configs","2.learn\u002F3.how-to\u002F1.override-configs",{"title":110,"path":111,"stem":112},"Safe Loading","\u002Flearn\u002Fhow-to\u002Fsafe-loading","2.learn\u002F3.how-to\u002F2.safe-loading",{"title":114,"path":115,"stem":116},"Custom Resolvers","\u002Flearn\u002Fhow-to\u002Fcustom-resolvers","2.learn\u002F3.how-to\u002F3.custom-resolvers",{"title":118,"path":119,"stem":120},"Lint and Strict Mode","\u002Flearn\u002Fhow-to\u002Flint-and-strict","2.learn\u002F3.how-to\u002F4.lint-and-strict",{"title":122,"path":123,"stem":124},"Publishing a reproducible app with laco app","\u002Flearn\u002Fhow-to\u002Flaco-app","2.learn\u002F3.how-to\u002F5.laco-app",{"title":126,"path":127,"stem":128},"Reproduce an Experiment","\u002Flearn\u002Fhow-to\u002Freproduce-experiment","2.learn\u002F3.how-to\u002F6.reproduce-experiment",{"title":130,"path":131,"stem":132},"Migrate from argparse","\u002Flearn\u002Fhow-to\u002Fmigrate-from-argparse","2.learn\u002F3.how-to\u002F7.migrate-from-argparse",{"title":134,"path":135,"stem":136,"children":137},"Examples Curriculum","\u002Flearn\u002Fexamples","2.learn\u002F4.examples\u002Findex",[138,139,143,147,151],{"title":134,"path":135,"stem":136},{"title":140,"path":141,"stem":142},"Foundation Examples","\u002Flearn\u002Fexamples\u002Ffoundations","2.learn\u002F4.examples\u002F1.foundations",{"title":144,"path":145,"stem":146},"Building Blocks","\u002Flearn\u002Fexamples\u002Fbuilding-blocks","2.learn\u002F4.examples\u002F2.building-blocks",{"title":148,"path":149,"stem":150},"Typed-Group Variants","\u002Flearn\u002Fexamples\u002Ftyped-variants","2.learn\u002F4.examples\u002F3.typed-variants",{"title":152,"path":153,"stem":154},"End-to-End Pipelines","\u002Flearn\u002Fexamples\u002Fpipelines","2.learn\u002F4.examples\u002F4.pipelines",{"title":156,"path":157,"stem":158,"children":159},"Resources","\u002Fresources","3.resources",[160,162,166,170],{"title":156,"path":157,"stem":161},"3.resources\u002Findex",{"title":163,"path":164,"stem":165},"Integrations","\u002Fresources\u002Fintegrations","3.resources\u002F1.integrations",{"title":167,"path":168,"stem":169},"Migration guide: Laco 0.x → 1.0","\u002Fresources\u002Fmigration-0.x-to-1.0","3.resources\u002F2.migration-0.x-to-1.0",{"title":171,"path":172,"stem":173},"Laco vs hydra-zen","\u002Fresources\u002Flaco-vs-hydra-zen","3.resources\u002F3.laco-vs-hydra-zen",{"title":175,"path":176,"stem":177,"children":178},"API Reference","\u002Fapi","4.api\u002Findex",[179],{"title":175,"path":176,"stem":177},{"title":181,"path":182,"stem":183},"Lazy Configuration for Python","\u002F","index",[185,188,191,194,197,200,203],{"title":186,"path":187},"cli","\u002Fapi\u002Fcli",{"title":189,"path":190},"compat","\u002Fapi\u002Fcompat",{"title":192,"path":193},"handler","\u002Fapi\u002Fhandler",{"title":195,"path":196},"keys","\u002Fapi\u002Fkeys",{"title":198,"path":199},"language","\u002Fapi\u002Flanguage",{"title":201,"path":202},"ops","\u002Fapi\u002Fops",{"title":204,"path":205},"utils","\u002Fapi\u002Futils",{"id":207,"title":39,"body":208,"description":3697,"extension":3698,"meta":3699,"navigation":3700,"path":40,"seo":3701,"stem":41,"__hash__":3702},"content\u002F2.learn\u002F1.tutorials\u002F05.loading-saving-cli.md",{"type":209,"value":210,"toc":3684},"minimark",[211,215,240,245,300,309,448,453,456,461,471,479,511,516,592,599,601,608,611,700,703,883,886,985,988,993,1041,1043,1047,1053,1071,1077,1221,1224,1236,1247,1518,1521,1737,1740,1745,1751,1758,1760,1767,1789,1795,1843,1852,1859,1921,2041,2044,2175,2178,2180,2184,2187,2239,2259,2270,2312,2315,2359,2361,2393,2396,2628,2631,2792,2795,2797,2803,2817,2827,2864,2870,2919,2922,3012,3015,3141,3144,3462,3465,3473,3483,3485,3489,3501,3506,3607,3609,3613,3661,3680],[212,213,39],"h1",{"id":214},"loading-saving-and-the-cli",[216,217,218,222,223,227,228,231,232,235,236,239],"p",{},[219,220,221],"strong",{},"Prerequisites:"," ",[224,225,226],"code",{},"01.why-laco.ipynb"," through ",[224,229,230],{},"04.hyperparameters-and-interpolation.ipynb"," (laco basics, ",[224,233,234],{},"L.call",", ",[224,237,238],{},"L.params",", instantiation).",[216,241,242],{},[219,243,244],{},"What you will learn:",[246,247,248,256,261,272,279,291,297],"ul",{},[249,250,251,252,255],"li",{},"The URL grammar for ",[224,253,254],{},"laco.load",": path, query-string overrides, and fragments",[249,257,258,259],{},"All three forms of ",[224,260,254],{},[249,262,263,264,267,268,271],{},"Saving configs to YAML with ",[224,265,266],{},"laco.dump"," \u002F ",[224,269,270],{},"laco.save"," and round-tripping back",[249,273,274,275,278],{},"The ",[224,276,277],{},"configs:\u002F\u002F"," protocol and how it resolves to real file paths",[249,280,281,282,235,285,235,288],{},"The three CLI sub-commands: ",[224,283,284],{},"laco compose",[224,286,287],{},"laco show",[224,289,290],{},"laco run",[249,292,293,296],{},[224,294,295],{},"LoadMode.SAFE"," for loading untrusted config files",[249,298,299],{},"A visual overview of the file-format pipeline",[216,301,302,222,305,308],{},[219,303,304],{},"Dependencies:",[224,306,307],{},"laco"," (torch is optional for CLI cells).",[310,311,316],"pre",{"className":312,"code":313,"language":314,"meta":315,"style":315},"language-python shiki shiki-themes material-theme-lighter github-light github-dark","import laco\nimport laco.language as L\nfrom omegaconf import OmegaConf\n\nprint(f\"laco version: {laco.__version__ if hasattr(laco, '__version__') else 'installed'}\")\n","python","",[224,317,318,331,352,366,373],{"__ignoreMap":315},[319,320,323,327],"span",{"class":321,"line":322},"line",1,[319,324,326],{"class":325},"sVHd0","import",[319,328,330],{"class":329},"su5hD"," laco\n",[319,332,334,336,339,343,346,349],{"class":321,"line":333},2,[319,335,326],{"class":325},[319,337,338],{"class":329}," laco",[319,340,342],{"class":341},"sP7_E",".",[319,344,198],{"class":345},"skxfh",[319,347,348],{"class":325}," as",[319,350,351],{"class":329}," L\n",[319,353,355,358,361,363],{"class":321,"line":354},3,[319,356,357],{"class":325},"from",[319,359,360],{"class":329}," omegaconf ",[319,362,326],{"class":325},[319,364,365],{"class":329}," OmegaConf\n",[319,367,369],{"class":321,"line":368},4,[319,370,372],{"emptyLinePlaceholder":371},true,"\n",[319,374,376,380,383,387,391,395,398,400,404,407,410,412,414,417,421,423,426,429,432,434,437,439,442,445],{"class":321,"line":375},5,[319,377,379],{"class":378},"sptTA","print",[319,381,382],{"class":341},"(",[319,384,386],{"class":385},"sbsja","f",[319,388,390],{"class":389},"s_sjI","\"laco version: ",[319,392,394],{"class":393},"srdBf","{",[319,396,307],{"class":397},"slqww",[319,399,342],{"class":341},[319,401,403],{"class":402},"s_hVV","__version__",[319,405,406],{"class":325}," if",[319,408,409],{"class":378}," hasattr",[319,411,382],{"class":341},[319,413,307],{"class":397},[319,415,416],{"class":341},",",[319,418,420],{"class":419},"sjJ54"," '",[319,422,403],{"class":389},[319,424,425],{"class":419},"'",[319,427,428],{"class":341},")",[319,430,431],{"class":325}," else",[319,433,420],{"class":419},[319,435,436],{"class":389},"installed",[319,438,425],{"class":419},[319,440,441],{"class":393},"}",[319,443,444],{"class":389},"\"",[319,446,447],{"class":341},")\n",[449,450],"docyard-notebook-output",{"data":451,"kind":452},"bGFjbyB2ZXJzaW9uOiAxLjAuMAo=","stream",[454,455],"hr",{},[457,458,460],"h2",{"id":459},"section-1-the-url-grammar","Section 1: The URL Grammar",[216,462,463,465,466,470],{},[224,464,254],{}," accepts a ",[467,468,469],"em",{},"URL-like"," path string that packs three pieces of information into one argument:",[310,472,477],{"className":473,"code":475,"language":476},[474],"language-text","configs:\u002F\u002Fexamples\u002Fmlp.py ? hps.dim_hidden=512 & hps.num_layers=4 # model\n└─── file path ──────────┘ └────── overrides (query string) ──────┘ └ key ┘\n","text",[224,478,475],{"__ignoreMap":315},[246,480,481,489,499],{},[249,482,483,486,487,428],{},[219,484,485],{},"Path",": the config file, optionally prefixed by a registered URI scheme (e.g. ",[224,488,277],{},[249,490,491,494,495,498],{},[219,492,493],{},"Query string"," (",[224,496,497],{},"?key=value&...","): Hydra-style override strings applied after loading",[249,500,501,494,504,507,508],{},[219,502,503],{},"Fragment",[224,505,506],{},"#key","): a dotted key to select from the loaded top-level ",[224,509,510],{},"DictConfig",[216,512,513],{},[219,514,515],{},"Key points:",[517,518,519,535],"table",{},[520,521,522],"thead",{},[523,524,525,529,532],"tr",{},[526,527,528],"th",{},"Part",[526,530,531],{},"Syntax",[526,533,534],{},"Effect",[536,537,538,559,576],"tbody",{},[523,539,540,543,548],{},[541,542,485],"td",{},[541,544,545],{},[224,546,547],{},"configs:\u002F\u002Fexamples\u002Fmlp.py",[541,549,550,551,554,555,558],{},"Resolved via ",[224,552,553],{},"expath"," using the ",[224,556,557],{},"configs"," entry-point",[523,560,561,564,569],{},[541,562,563],{},"Overrides",[541,565,566],{},[224,567,568],{},"?hps.dim_hidden=512&hps.num_layers=4",[541,570,571,572,575],{},"Applied with ",[224,573,574],{},"apply_overrides"," after loading",[523,577,578,581,586],{},[541,579,580],{},"Key \u002F fragment",[541,582,583],{},[224,584,585],{},"#model",[541,587,588,589],{},"Equivalent to passing ",[224,590,591],{},"key=\"model\"",[216,593,594,595,598],{},"All three parts are ",[219,596,597],{},"optional",": a bare path is also valid.",[454,600],{},[457,602,604,605,607],{"id":603},"section-2-lacoload-variants","Section 2: ",[224,606,254],{}," Variants",[216,609,610],{},"There are three equivalent calling forms. Choose whichever reads most clearly in your code.",[310,612,614],{"className":312,"code":613,"language":314,"meta":315,"style":315},"# Form 1: URL with query string and fragment — everything in one string.\n# The query string becomes override strings; the fragment becomes the key.\ncfg1 = laco.load(\n    \"configs:\u002F\u002Fexamples\u002Flinear_regression.py?hps.in_features=16#model\"\n)\nprint(\"Form 1 — cfg1 (model node, in_features=16):\")\nprint(OmegaConf.to_yaml(cfg1))\n",[224,615,616,622,627,646,657,661,677],{"__ignoreMap":315},[319,617,618],{"class":321,"line":322},[319,619,621],{"class":620},"sutJx","# Form 1: URL with query string and fragment — everything in one string.\n",[319,623,624],{"class":321,"line":333},[319,625,626],{"class":620},"# The query string becomes override strings; the fragment becomes the key.\n",[319,628,629,632,636,638,640,643],{"class":321,"line":354},[319,630,631],{"class":329},"cfg1 ",[319,633,635],{"class":634},"smGrS","=",[319,637,338],{"class":329},[319,639,342],{"class":341},[319,641,642],{"class":397},"load",[319,644,645],{"class":341},"(\n",[319,647,648,651,654],{"class":321,"line":368},[319,649,650],{"class":419},"    \"",[319,652,653],{"class":389},"configs:\u002F\u002Fexamples\u002Flinear_regression.py?hps.in_features=16#model",[319,655,656],{"class":419},"\"\n",[319,658,659],{"class":321,"line":375},[319,660,447],{"class":341},[319,662,664,666,668,670,673,675],{"class":321,"line":663},6,[319,665,379],{"class":378},[319,667,382],{"class":341},[319,669,444],{"class":419},[319,671,672],{"class":389},"Form 1 — cfg1 (model node, in_features=16):",[319,674,444],{"class":419},[319,676,447],{"class":341},[319,678,680,682,684,687,689,692,694,697],{"class":321,"line":679},7,[319,681,379],{"class":378},[319,683,382],{"class":341},[319,685,686],{"class":397},"OmegaConf",[319,688,342],{"class":341},[319,690,691],{"class":397},"to_yaml",[319,693,382],{"class":341},[319,695,696],{"class":397},"cfg1",[319,698,699],{"class":341},"))\n",[449,701],{"data":702,"kind":452},"Rm9ybSAxIOKAlCBjZmcxIChtb2RlbCBub2RlLCBpbl9mZWF0dXJlcz0xNik6Cl90YXJnZXRfOiB0b3JjaC5ubi5MaW5lYXIKX2NvbnZlcnRfOiBhbGwKaW5fZmVhdHVyZXM6ICR7aHBzLmluX2ZlYXR1cmVzfQpvdXRfZmVhdHVyZXM6ICR7aHBzLm91dF9mZWF0dXJlc30KYmlhczogJHtocHMuYmlhc30KCg==",[310,704,706],{"className":312,"code":705,"language":314,"meta":315,"style":315},"# Form 2: path + positional override strings + keyword key.\n# Cleaner when you need to compute overrides dynamically.\ncfg2 = laco.load(\n    \"configs:\u002F\u002Fexamples\u002Flinear_regression.py\",\n    \"hps.in_features=16\",\n    key=\"model\",\n)\nprint(\"Form 2 — cfg2 (identical to cfg1):\")\nprint(OmegaConf.to_yaml(cfg2))\n\n# Sanity-check: both forms produce the same config\nassert OmegaConf.to_yaml(cfg1) == OmegaConf.to_yaml(cfg2), \"Mismatch!\"\nprint(\"Forms 1 and 2 are identical.\")\n",[224,707,708,713,718,733,745,756,773,777,793,813,818,824,867],{"__ignoreMap":315},[319,709,710],{"class":321,"line":322},[319,711,712],{"class":620},"# Form 2: path + positional override strings + keyword key.\n",[319,714,715],{"class":321,"line":333},[319,716,717],{"class":620},"# Cleaner when you need to compute overrides dynamically.\n",[319,719,720,723,725,727,729,731],{"class":321,"line":354},[319,721,722],{"class":329},"cfg2 ",[319,724,635],{"class":634},[319,726,338],{"class":329},[319,728,342],{"class":341},[319,730,642],{"class":397},[319,732,645],{"class":341},[319,734,735,737,740,742],{"class":321,"line":368},[319,736,650],{"class":419},[319,738,739],{"class":389},"configs:\u002F\u002Fexamples\u002Flinear_regression.py",[319,741,444],{"class":419},[319,743,744],{"class":341},",\n",[319,746,747,749,752,754],{"class":321,"line":375},[319,748,650],{"class":419},[319,750,751],{"class":389},"hps.in_features=16",[319,753,444],{"class":419},[319,755,744],{"class":341},[319,757,758,762,764,766,769,771],{"class":321,"line":663},[319,759,761],{"class":760},"s99_P","    key",[319,763,635],{"class":634},[319,765,444],{"class":419},[319,767,768],{"class":389},"model",[319,770,444],{"class":419},[319,772,744],{"class":341},[319,774,775],{"class":321,"line":679},[319,776,447],{"class":341},[319,778,780,782,784,786,789,791],{"class":321,"line":779},8,[319,781,379],{"class":378},[319,783,382],{"class":341},[319,785,444],{"class":419},[319,787,788],{"class":389},"Form 2 — cfg2 (identical to cfg1):",[319,790,444],{"class":419},[319,792,447],{"class":341},[319,794,796,798,800,802,804,806,808,811],{"class":321,"line":795},9,[319,797,379],{"class":378},[319,799,382],{"class":341},[319,801,686],{"class":397},[319,803,342],{"class":341},[319,805,691],{"class":397},[319,807,382],{"class":341},[319,809,810],{"class":397},"cfg2",[319,812,699],{"class":341},[319,814,816],{"class":321,"line":815},10,[319,817,372],{"emptyLinePlaceholder":371},[319,819,821],{"class":321,"line":820},11,[319,822,823],{"class":620},"# Sanity-check: both forms produce the same config\n",[319,825,827,830,833,835,837,839,841,843,846,848,850,852,854,856,859,862,865],{"class":321,"line":826},12,[319,828,829],{"class":325},"assert",[319,831,832],{"class":329}," OmegaConf",[319,834,342],{"class":341},[319,836,691],{"class":397},[319,838,382],{"class":341},[319,840,696],{"class":397},[319,842,428],{"class":341},[319,844,845],{"class":634}," ==",[319,847,832],{"class":329},[319,849,342],{"class":341},[319,851,691],{"class":397},[319,853,382],{"class":341},[319,855,810],{"class":397},[319,857,858],{"class":341},"),",[319,860,861],{"class":419}," \"",[319,863,864],{"class":389},"Mismatch!",[319,866,656],{"class":419},[319,868,870,872,874,876,879,881],{"class":321,"line":869},13,[319,871,379],{"class":378},[319,873,382],{"class":341},[319,875,444],{"class":419},[319,877,878],{"class":389},"Forms 1 and 2 are identical.",[319,880,444],{"class":419},[319,882,447],{"class":341},[449,884],{"data":885,"kind":452},"Rm9ybSAyIOKAlCBjZmcyIChpZGVudGljYWwgdG8gY2ZnMSk6Cl90YXJnZXRfOiB0b3JjaC5ubi5MaW5lYXIKX2NvbnZlcnRfOiBhbGwKaW5fZmVhdHVyZXM6ICR7aHBzLmluX2ZlYXR1cmVzfQpvdXRfZmVhdHVyZXM6ICR7aHBzLm91dF9mZWF0dXJlc30KYmlhczogJHtocHMuYmlhc30KCkZvcm1zIDEgYW5kIDIgYXJlIGlkZW50aWNhbC4K",[310,887,889],{"className":312,"code":888,"language":314,"meta":315,"style":315},"# Form 3: bare path — loads the entire module namespace.\n# The result is a DictConfig with .model, .optimizer, .hps keys\n# (whatever is listed in __all__ of the config file).\ncfg3 = laco.load(\"configs:\u002F\u002Fexamples\u002Flinear_regression.py\")\nprint(\"Form 3 — top-level keys:\", list(cfg3.keys()))\nprint()\nprint(OmegaConf.to_yaml(cfg3))\n",[224,890,891,896,901,906,929,960,967],{"__ignoreMap":315},[319,892,893],{"class":321,"line":322},[319,894,895],{"class":620},"# Form 3: bare path — loads the entire module namespace.\n",[319,897,898],{"class":321,"line":333},[319,899,900],{"class":620},"# The result is a DictConfig with .model, .optimizer, .hps keys\n",[319,902,903],{"class":321,"line":354},[319,904,905],{"class":620},"# (whatever is listed in __all__ of the config file).\n",[319,907,908,911,913,915,917,919,921,923,925,927],{"class":321,"line":368},[319,909,910],{"class":329},"cfg3 ",[319,912,635],{"class":634},[319,914,338],{"class":329},[319,916,342],{"class":341},[319,918,642],{"class":397},[319,920,382],{"class":341},[319,922,444],{"class":419},[319,924,739],{"class":389},[319,926,444],{"class":419},[319,928,447],{"class":341},[319,930,931,933,935,937,940,942,944,948,950,953,955,957],{"class":321,"line":375},[319,932,379],{"class":378},[319,934,382],{"class":341},[319,936,444],{"class":419},[319,938,939],{"class":389},"Form 3 — top-level keys:",[319,941,444],{"class":419},[319,943,416],{"class":341},[319,945,947],{"class":946},"sZMiF"," list",[319,949,382],{"class":341},[319,951,952],{"class":397},"cfg3",[319,954,342],{"class":341},[319,956,195],{"class":397},[319,958,959],{"class":341},"()))\n",[319,961,962,964],{"class":321,"line":663},[319,963,379],{"class":378},[319,965,966],{"class":341},"()\n",[319,968,969,971,973,975,977,979,981,983],{"class":321,"line":679},[319,970,379],{"class":378},[319,972,382],{"class":341},[319,974,686],{"class":397},[319,976,342],{"class":341},[319,978,691],{"class":397},[319,980,382],{"class":341},[319,982,952],{"class":397},[319,984,699],{"class":341},[449,986],{"data":987,"kind":452},"Rm9ybSAzIOKAlCB0b3AtbGV2ZWwga2V5czogWydocHMnLCAnbW9kZWwnLCAnb3B0aW1pemVyJ10KCmhwczoKICBpbl9mZWF0dXJlczogOAogIG91dF9mZWF0dXJlczogMQogIGJpYXM6IHRydWUKICBsZWFybmluZ19yYXRlOiAwLjAxCiAgbW9tZW50dW06IDAuOQptb2RlbDoKICBfdGFyZ2V0XzogdG9yY2gubm4uTGluZWFyCiAgX2NvbnZlcnRfOiBhbGwKICBpbl9mZWF0dXJlczogJHtocHMuaW5fZmVhdHVyZXN9CiAgb3V0X2ZlYXR1cmVzOiAke2hwcy5vdXRfZmVhdHVyZXN9CiAgYmlhczogJHtocHMuYmlhc30Kb3B0aW1pemVyOgogIF90YXJnZXRfOiB0b3JjaC5vcHRpbS5TR0QKICBfY29udmVydF86IGFsbAogIGxyOiAke2hwcy5sZWFybmluZ19yYXRlfQogIG1vbWVudHVtOiAke2hwcy5tb21lbnR1bX0KICBfcGFydGlhbF86IHRydWUKCg==",[216,989,990],{},[219,991,992],{},"Summary of the three forms:",[517,994,995,1005],{},[520,996,997],{},[523,998,999,1002],{},[526,1000,1001],{},"Form",[526,1003,1004],{},"When to use",[536,1006,1007,1015,1030],{},[523,1008,1009,1012],{},[541,1010,1011],{},"URL string",[541,1013,1014],{},"Compact; good for hardcoded one-liners or CLI-style usage",[523,1016,1017,1027],{},[541,1018,1019,1020,1023,1024],{},"path + ",[224,1021,1022],{},"*args"," + ",[224,1025,1026],{},"key=",[541,1028,1029],{},"When building overrides programmatically",[523,1031,1032,1035],{},[541,1033,1034],{},"bare path",[541,1036,1037,1038,428],{},"When you want the whole module namespace (e.g. to inspect ",[224,1039,1040],{},"hps",[454,1042],{},[457,1044,1046],{"id":1045},"section-3-saving-and-round-tripping","Section 3: Saving and Round-Tripping",[216,1048,1049,1050,1052],{},"Once you have a ",[224,1051,510],{}," you can:",[246,1054,1055,1063],{},[249,1056,1057,1062],{},[219,1058,1059],{},[224,1060,1061],{},"laco.dump(cfg)",": serialize to a YAML string",[249,1064,1065,1070],{},[219,1066,1067],{},[224,1068,1069],{},"laco.save(cfg, path)",": write YAML to a file and return the re-loaded config",[216,1072,1073,1074,1076],{},"Both write standard YAML that can be reloaded by ",[224,1075,254],{}," or any YAML reader.",[310,1078,1080],{"className":312,"code":1079,"language":314,"meta":315,"style":315},"import pathlib\nimport tempfile\n\n# 1. Load the model sub-config from the linear_regression example.\ncfg = laco.load(\"configs:\u002F\u002Fexamples\u002Flinear_regression.py#model\")\nprint(\"Loaded config type:\", type(cfg).__name__)\nprint()\n\n# 2. Serialise to a YAML string.\nyaml_str = laco.dump(cfg)\nprint(\"YAML output:\")\nprint(yaml_str)\n",[224,1081,1082,1089,1096,1100,1105,1129,1160,1166,1170,1175,1195,1210],{"__ignoreMap":315},[319,1083,1084,1086],{"class":321,"line":322},[319,1085,326],{"class":325},[319,1087,1088],{"class":329}," pathlib\n",[319,1090,1091,1093],{"class":321,"line":333},[319,1092,326],{"class":325},[319,1094,1095],{"class":329}," tempfile\n",[319,1097,1098],{"class":321,"line":354},[319,1099,372],{"emptyLinePlaceholder":371},[319,1101,1102],{"class":321,"line":368},[319,1103,1104],{"class":620},"# 1. Load the model sub-config from the linear_regression example.\n",[319,1106,1107,1110,1112,1114,1116,1118,1120,1122,1125,1127],{"class":321,"line":375},[319,1108,1109],{"class":329},"cfg ",[319,1111,635],{"class":634},[319,1113,338],{"class":329},[319,1115,342],{"class":341},[319,1117,642],{"class":397},[319,1119,382],{"class":341},[319,1121,444],{"class":419},[319,1123,1124],{"class":389},"configs:\u002F\u002Fexamples\u002Flinear_regression.py#model",[319,1126,444],{"class":419},[319,1128,447],{"class":341},[319,1130,1131,1133,1135,1137,1140,1142,1144,1147,1149,1152,1155,1158],{"class":321,"line":663},[319,1132,379],{"class":378},[319,1134,382],{"class":341},[319,1136,444],{"class":419},[319,1138,1139],{"class":389},"Loaded config type:",[319,1141,444],{"class":419},[319,1143,416],{"class":341},[319,1145,1146],{"class":946}," type",[319,1148,382],{"class":341},[319,1150,1151],{"class":397},"cfg",[319,1153,1154],{"class":341},").",[319,1156,1157],{"class":402},"__name__",[319,1159,447],{"class":341},[319,1161,1162,1164],{"class":321,"line":679},[319,1163,379],{"class":378},[319,1165,966],{"class":341},[319,1167,1168],{"class":321,"line":779},[319,1169,372],{"emptyLinePlaceholder":371},[319,1171,1172],{"class":321,"line":795},[319,1173,1174],{"class":620},"# 2. Serialise to a YAML string.\n",[319,1176,1177,1180,1182,1184,1186,1189,1191,1193],{"class":321,"line":815},[319,1178,1179],{"class":329},"yaml_str ",[319,1181,635],{"class":634},[319,1183,338],{"class":329},[319,1185,342],{"class":341},[319,1187,1188],{"class":397},"dump",[319,1190,382],{"class":341},[319,1192,1151],{"class":397},[319,1194,447],{"class":341},[319,1196,1197,1199,1201,1203,1206,1208],{"class":321,"line":820},[319,1198,379],{"class":378},[319,1200,382],{"class":341},[319,1202,444],{"class":419},[319,1204,1205],{"class":389},"YAML output:",[319,1207,444],{"class":419},[319,1209,447],{"class":341},[319,1211,1212,1214,1216,1219],{"class":321,"line":826},[319,1213,379],{"class":378},[319,1215,382],{"class":341},[319,1217,1218],{"class":397},"yaml_str",[319,1220,447],{"class":341},[449,1222],{"data":1223,"kind":452},"TG9hZGVkIGNvbmZpZyB0eXBlOiBEaWN0Q29uZmlnCgpZQU1MIG91dHB1dDoKe19jb252ZXJ0XzogYWxsLCBfbGFjb186IDEsIF90YXJnZXRfOiB0b3JjaC5ubi5MaW5lYXIsIGJpYXM6ICcke2hwcy5iaWFzfScsIGluX2ZlYXR1cmVzOiAnJHtocHMuaW5fZmVhdHVyZXN9JywKICBvdXRfZmVhdHVyZXM6ICcke2hwcy5vdXRfZmVhdHVyZXN9J30KCg==",[216,1225,1226,1227,1230,1231,1233,1234,342],{},"Notice the ",[224,1228,1229],{},"_laco_: 1"," key at the top: this is a schema-version marker that ",[224,1232,254],{}," strips on reload so it never appears as a user-domain key in the resulting ",[224,1235,510],{},[216,1237,1238,1239,1242,1243,1246],{},"Class references (like ",[224,1240,1241],{},"torch.nn.Linear",") are serialized as ",[224,1244,1245],{},"!!python\u002Fname:torch.nn.modules.linear.Linear",". When you reload the YAML, laco's custom YAML loader resolves this tag back to the actual class object.",[310,1248,1250],{"className":312,"code":1249,"language":314,"meta":315,"style":315},"# 3. Write to a temp file and reload — the round-trip.\nwith tempfile.NamedTemporaryFile(suffix=\".yaml\", mode=\"w\", delete=False) as f:\n    f.write(yaml_str)\n    tmp_path = f.name\n\nprint(f\"Saved to: {tmp_path}\")\n\n# Reload from the .yaml file — laco detects the extension automatically.\ncfg_reloaded = laco.load(tmp_path)\nprint(\"Reloaded config type:\", type(cfg_reloaded).__name__)\nprint()\nprint(\"Round-tripped YAML:\")\nprint(OmegaConf.to_yaml(cfg_reloaded))\n\n# Cleanup\npathlib.Path(tmp_path).unlink()\nprint(\"Temp file removed.\")\n",[224,1251,1252,1257,1319,1335,1349,1353,1375,1379,1384,1403,1431,1437,1452,1470,1475,1481,1502],{"__ignoreMap":315},[319,1253,1254],{"class":321,"line":322},[319,1255,1256],{"class":620},"# 3. Write to a temp file and reload — the round-trip.\n",[319,1258,1259,1262,1265,1267,1270,1272,1275,1277,1279,1282,1284,1286,1289,1291,1293,1296,1298,1300,1303,1305,1309,1311,1313,1316],{"class":321,"line":333},[319,1260,1261],{"class":325},"with",[319,1263,1264],{"class":329}," tempfile",[319,1266,342],{"class":341},[319,1268,1269],{"class":397},"NamedTemporaryFile",[319,1271,382],{"class":341},[319,1273,1274],{"class":760},"suffix",[319,1276,635],{"class":634},[319,1278,444],{"class":419},[319,1280,1281],{"class":389},".yaml",[319,1283,444],{"class":419},[319,1285,416],{"class":341},[319,1287,1288],{"class":760}," mode",[319,1290,635],{"class":634},[319,1292,444],{"class":419},[319,1294,1295],{"class":389},"w",[319,1297,444],{"class":419},[319,1299,416],{"class":341},[319,1301,1302],{"class":760}," delete",[319,1304,635],{"class":634},[319,1306,1308],{"class":1307},"s39Yj","False",[319,1310,428],{"class":341},[319,1312,348],{"class":325},[319,1314,1315],{"class":329}," f",[319,1317,1318],{"class":341},":\n",[319,1320,1321,1324,1326,1329,1331,1333],{"class":321,"line":354},[319,1322,1323],{"class":329},"    f",[319,1325,342],{"class":341},[319,1327,1328],{"class":397},"write",[319,1330,382],{"class":341},[319,1332,1218],{"class":397},[319,1334,447],{"class":341},[319,1336,1337,1340,1342,1344,1346],{"class":321,"line":368},[319,1338,1339],{"class":329},"    tmp_path ",[319,1341,635],{"class":634},[319,1343,1315],{"class":329},[319,1345,342],{"class":341},[319,1347,1348],{"class":345},"name\n",[319,1350,1351],{"class":321,"line":375},[319,1352,372],{"emptyLinePlaceholder":371},[319,1354,1355,1357,1359,1361,1364,1366,1369,1371,1373],{"class":321,"line":663},[319,1356,379],{"class":378},[319,1358,382],{"class":341},[319,1360,386],{"class":385},[319,1362,1363],{"class":389},"\"Saved to: ",[319,1365,394],{"class":393},[319,1367,1368],{"class":397},"tmp_path",[319,1370,441],{"class":393},[319,1372,444],{"class":389},[319,1374,447],{"class":341},[319,1376,1377],{"class":321,"line":679},[319,1378,372],{"emptyLinePlaceholder":371},[319,1380,1381],{"class":321,"line":779},[319,1382,1383],{"class":620},"# Reload from the .yaml file — laco detects the extension automatically.\n",[319,1385,1386,1389,1391,1393,1395,1397,1399,1401],{"class":321,"line":795},[319,1387,1388],{"class":329},"cfg_reloaded ",[319,1390,635],{"class":634},[319,1392,338],{"class":329},[319,1394,342],{"class":341},[319,1396,642],{"class":397},[319,1398,382],{"class":341},[319,1400,1368],{"class":397},[319,1402,447],{"class":341},[319,1404,1405,1407,1409,1411,1414,1416,1418,1420,1422,1425,1427,1429],{"class":321,"line":815},[319,1406,379],{"class":378},[319,1408,382],{"class":341},[319,1410,444],{"class":419},[319,1412,1413],{"class":389},"Reloaded config type:",[319,1415,444],{"class":419},[319,1417,416],{"class":341},[319,1419,1146],{"class":946},[319,1421,382],{"class":341},[319,1423,1424],{"class":397},"cfg_reloaded",[319,1426,1154],{"class":341},[319,1428,1157],{"class":402},[319,1430,447],{"class":341},[319,1432,1433,1435],{"class":321,"line":820},[319,1434,379],{"class":378},[319,1436,966],{"class":341},[319,1438,1439,1441,1443,1445,1448,1450],{"class":321,"line":826},[319,1440,379],{"class":378},[319,1442,382],{"class":341},[319,1444,444],{"class":419},[319,1446,1447],{"class":389},"Round-tripped YAML:",[319,1449,444],{"class":419},[319,1451,447],{"class":341},[319,1453,1454,1456,1458,1460,1462,1464,1466,1468],{"class":321,"line":869},[319,1455,379],{"class":378},[319,1457,382],{"class":341},[319,1459,686],{"class":397},[319,1461,342],{"class":341},[319,1463,691],{"class":397},[319,1465,382],{"class":341},[319,1467,1424],{"class":397},[319,1469,699],{"class":341},[319,1471,1473],{"class":321,"line":1472},14,[319,1474,372],{"emptyLinePlaceholder":371},[319,1476,1478],{"class":321,"line":1477},15,[319,1479,1480],{"class":620},"# Cleanup\n",[319,1482,1484,1487,1489,1491,1493,1495,1497,1500],{"class":321,"line":1483},16,[319,1485,1486],{"class":329},"pathlib",[319,1488,342],{"class":341},[319,1490,485],{"class":397},[319,1492,382],{"class":341},[319,1494,1368],{"class":397},[319,1496,1154],{"class":341},[319,1498,1499],{"class":397},"unlink",[319,1501,966],{"class":341},[319,1503,1505,1507,1509,1511,1514,1516],{"class":321,"line":1504},17,[319,1506,379],{"class":378},[319,1508,382],{"class":341},[319,1510,444],{"class":419},[319,1512,1513],{"class":389},"Temp file removed.",[319,1515,444],{"class":419},[319,1517,447],{"class":341},[449,1519],{"data":1520,"kind":452},"U2F2ZWQgdG86IC90bXAvbml4LXNoZWxsLnhNQlh5VS90bXB1YXljd2FkZS55YW1sClJlbG9hZGVkIGNvbmZpZyB0eXBlOiBEaWN0Q29uZmlnCgpSb3VuZC10cmlwcGVkIFlBTUw6Cl9jb252ZXJ0XzogYWxsCl90YXJnZXRfOiB0b3JjaC5ubi5MaW5lYXIKYmlhczogJHtocHMuYmlhc30KaW5fZmVhdHVyZXM6ICR7aHBzLmluX2ZlYXR1cmVzfQpvdXRfZmVhdHVyZXM6ICR7aHBzLm91dF9mZWF0dXJlc30KClRlbXAgZmlsZSByZW1vdmVkLgo=",[310,1522,1524],{"className":312,"code":1523,"language":314,"meta":315,"style":315},"# laco.save is a thin convenience wrapper:\n# it calls dump(), writes the file, then reloads it (unless mode=SaveMode.NO_RELOAD).\n# The returned object is the freshly loaded DictConfig.\n\nfrom laco._io import SaveMode\n\nwith tempfile.NamedTemporaryFile(suffix=\".yaml\", delete=False) as f:\n    save_path = f.name\n\ncfg_from_save = laco.save(cfg, save_path)\nprint(\"laco.save() returned type:\", type(cfg_from_save).__name__)\nprint(\"Keys:\", list(cfg_from_save.keys()))\n\npathlib.Path(save_path).unlink()\nprint(\"Temp file removed.\")\n",[224,1525,1526,1531,1536,1541,1545,1561,1565,1603,1616,1620,1645,1673,1700,1704,1723],{"__ignoreMap":315},[319,1527,1528],{"class":321,"line":322},[319,1529,1530],{"class":620},"# laco.save is a thin convenience wrapper:\n",[319,1532,1533],{"class":321,"line":333},[319,1534,1535],{"class":620},"# it calls dump(), writes the file, then reloads it (unless mode=SaveMode.NO_RELOAD).\n",[319,1537,1538],{"class":321,"line":354},[319,1539,1540],{"class":620},"# The returned object is the freshly loaded DictConfig.\n",[319,1542,1543],{"class":321,"line":368},[319,1544,372],{"emptyLinePlaceholder":371},[319,1546,1547,1549,1551,1553,1556,1558],{"class":321,"line":375},[319,1548,357],{"class":325},[319,1550,338],{"class":329},[319,1552,342],{"class":341},[319,1554,1555],{"class":329},"_io ",[319,1557,326],{"class":325},[319,1559,1560],{"class":329}," SaveMode\n",[319,1562,1563],{"class":321,"line":663},[319,1564,372],{"emptyLinePlaceholder":371},[319,1566,1567,1569,1571,1573,1575,1577,1579,1581,1583,1585,1587,1589,1591,1593,1595,1597,1599,1601],{"class":321,"line":679},[319,1568,1261],{"class":325},[319,1570,1264],{"class":329},[319,1572,342],{"class":341},[319,1574,1269],{"class":397},[319,1576,382],{"class":341},[319,1578,1274],{"class":760},[319,1580,635],{"class":634},[319,1582,444],{"class":419},[319,1584,1281],{"class":389},[319,1586,444],{"class":419},[319,1588,416],{"class":341},[319,1590,1302],{"class":760},[319,1592,635],{"class":634},[319,1594,1308],{"class":1307},[319,1596,428],{"class":341},[319,1598,348],{"class":325},[319,1600,1315],{"class":329},[319,1602,1318],{"class":341},[319,1604,1605,1608,1610,1612,1614],{"class":321,"line":779},[319,1606,1607],{"class":329},"    save_path ",[319,1609,635],{"class":634},[319,1611,1315],{"class":329},[319,1613,342],{"class":341},[319,1615,1348],{"class":345},[319,1617,1618],{"class":321,"line":795},[319,1619,372],{"emptyLinePlaceholder":371},[319,1621,1622,1625,1627,1629,1631,1634,1636,1638,1640,1643],{"class":321,"line":815},[319,1623,1624],{"class":329},"cfg_from_save ",[319,1626,635],{"class":634},[319,1628,338],{"class":329},[319,1630,342],{"class":341},[319,1632,1633],{"class":397},"save",[319,1635,382],{"class":341},[319,1637,1151],{"class":397},[319,1639,416],{"class":341},[319,1641,1642],{"class":397}," save_path",[319,1644,447],{"class":341},[319,1646,1647,1649,1651,1653,1656,1658,1660,1662,1664,1667,1669,1671],{"class":321,"line":820},[319,1648,379],{"class":378},[319,1650,382],{"class":341},[319,1652,444],{"class":419},[319,1654,1655],{"class":389},"laco.save() returned type:",[319,1657,444],{"class":419},[319,1659,416],{"class":341},[319,1661,1146],{"class":946},[319,1663,382],{"class":341},[319,1665,1666],{"class":397},"cfg_from_save",[319,1668,1154],{"class":341},[319,1670,1157],{"class":402},[319,1672,447],{"class":341},[319,1674,1675,1677,1679,1681,1684,1686,1688,1690,1692,1694,1696,1698],{"class":321,"line":826},[319,1676,379],{"class":378},[319,1678,382],{"class":341},[319,1680,444],{"class":419},[319,1682,1683],{"class":389},"Keys:",[319,1685,444],{"class":419},[319,1687,416],{"class":341},[319,1689,947],{"class":946},[319,1691,382],{"class":341},[319,1693,1666],{"class":397},[319,1695,342],{"class":341},[319,1697,195],{"class":397},[319,1699,959],{"class":341},[319,1701,1702],{"class":321,"line":869},[319,1703,372],{"emptyLinePlaceholder":371},[319,1705,1706,1708,1710,1712,1714,1717,1719,1721],{"class":321,"line":1472},[319,1707,1486],{"class":329},[319,1709,342],{"class":341},[319,1711,485],{"class":397},[319,1713,382],{"class":341},[319,1715,1716],{"class":397},"save_path",[319,1718,1154],{"class":341},[319,1720,1499],{"class":397},[319,1722,966],{"class":341},[319,1724,1725,1727,1729,1731,1733,1735],{"class":321,"line":1477},[319,1726,379],{"class":378},[319,1728,382],{"class":341},[319,1730,444],{"class":419},[319,1732,1513],{"class":389},[319,1734,444],{"class":419},[319,1736,447],{"class":341},[449,1738],{"data":1739,"kind":452},"bGFjby5zYXZlKCkgcmV0dXJuZWQgdHlwZTogRGljdENvbmZpZwpLZXlzOiBbJ19jb252ZXJ0XycsICdfdGFyZ2V0XycsICdiaWFzJywgJ2luX2ZlYXR1cmVzJywgJ291dF9mZWF0dXJlcyddClRlbXAgZmlsZSByZW1vdmVkLgo=",[216,1741,1742],{},[219,1743,1744],{},"Round-trip guarantee:",[310,1746,1749],{"className":1747,"code":1748,"language":476},[474],"laco.load(path)  -->  DictConfig  --laco.dump()-->  YAML string\n                                                         |\n                          \u003C-------- laco.load() ---------+\n",[224,1750,1748],{"__ignoreMap":315},[216,1752,1753,1754,1757],{},"The reloaded config is structurally identical to the original (same keys, same values, same ",[224,1755,1756],{},"_target_"," pointers).",[454,1759],{},[457,1761,1763,1764,1766],{"id":1762},"section-4-the-configs-protocol","Section 4: The ",[224,1765,277],{}," Protocol",[216,1768,274,1769,1771,1772,1774,1775,1782,1783,1785,1786,342],{},[224,1770,277],{}," prefix is resolved by ",[224,1773,553],{},", a path-resolution library that reads ",[1776,1777,1781],"a",{"href":1778,"rel":1779},"https:\u002F\u002Fpackaging.python.org\u002Fen\u002Flatest\u002Fspecifications\u002Fentry-points\u002F",[1780],"nofollow","entry points"," registered under the ",[224,1784,557],{}," group in ",[224,1787,1788],{},"pyproject.toml",[216,1790,1791,1792,1794],{},"For the bundled laco examples, ",[224,1793,1788],{}," registers:",[310,1796,1800],{"className":1797,"code":1798,"language":1799,"meta":315,"style":315},"language-toml shiki shiki-themes material-theme-lighter github-light github-dark","[project.entry-points.\"expath.protocols\"]\nconfigs = \"laco.examples:__path__[0]\"\n","toml",[224,1801,1802,1829],{"__ignoreMap":315},[319,1803,1804,1807,1811,1813,1816,1818,1821,1823,1826],{"class":321,"line":322},[319,1805,1806],{"class":341},"[",[319,1808,1810],{"class":1809},"sbgvK","project",[319,1812,342],{"class":329},[319,1814,1815],{"class":1809},"entry-points",[319,1817,342],{"class":329},[319,1819,1820],{"class":1809},"\"expath",[319,1822,342],{"class":329},[319,1824,1825],{"class":1809},"protocols\"",[319,1827,1828],{"class":341},"]\n",[319,1830,1831,1834,1836,1838,1841],{"class":321,"line":333},[319,1832,1833],{"class":329},"configs ",[319,1835,635],{"class":341},[319,1837,861],{"class":419},[319,1839,1840],{"class":389},"laco.examples:__path__[0]",[319,1842,656],{"class":419},[216,1844,1845,1846,1848,1849,342],{},"This means ",[224,1847,547],{}," is shorthand for the file at ",[224,1850,1851],{},"\u003Claco_install>\u002Fexamples\u002Fmlp.py",[216,1853,1854,1855,1858],{},"You can use ",[219,1856,1857],{},"plain filesystem paths"," too: relative or absolute:",[310,1860,1862],{"className":312,"code":1861,"language":314,"meta":315,"style":315},"laco.load(\"path\u002Fto\u002Fmy_config.py\")\nlaco.load(\"\u002Fabsolute\u002Fpath\u002Fto\u002Fconfig.py\")\nlaco.load(\"\u002Fabsolute\u002Fpath\u002Fto\u002Fsaved.yaml\")\n",[224,1863,1864,1883,1902],{"__ignoreMap":315},[319,1865,1866,1868,1870,1872,1874,1876,1879,1881],{"class":321,"line":322},[319,1867,307],{"class":329},[319,1869,342],{"class":341},[319,1871,642],{"class":397},[319,1873,382],{"class":341},[319,1875,444],{"class":419},[319,1877,1878],{"class":389},"path\u002Fto\u002Fmy_config.py",[319,1880,444],{"class":419},[319,1882,447],{"class":341},[319,1884,1885,1887,1889,1891,1893,1895,1898,1900],{"class":321,"line":333},[319,1886,307],{"class":329},[319,1888,342],{"class":341},[319,1890,642],{"class":397},[319,1892,382],{"class":341},[319,1894,444],{"class":419},[319,1896,1897],{"class":389},"\u002Fabsolute\u002Fpath\u002Fto\u002Fconfig.py",[319,1899,444],{"class":419},[319,1901,447],{"class":341},[319,1903,1904,1906,1908,1910,1912,1914,1917,1919],{"class":321,"line":354},[319,1905,307],{"class":329},[319,1907,342],{"class":341},[319,1909,642],{"class":397},[319,1911,382],{"class":341},[319,1913,444],{"class":419},[319,1915,1916],{"class":389},"\u002Fabsolute\u002Fpath\u002Fto\u002Fsaved.yaml",[319,1918,444],{"class":419},[319,1920,447],{"class":341},[310,1922,1924],{"className":312,"code":1923,"language":314,"meta":315,"style":315},"# Resolve the actual path on disk using expath.\ntry:\n    import expath\n    resolved = expath.resolve(\"configs:\u002F\u002Fexamples\u002Fmlp.py\")\n    print(\"configs:\u002F\u002Fexamples\u002Fmlp.py  resolves to:\")\n    print(\" \", resolved)\nexcept Exception as e:\n    print(f\"expath not available or resolution failed: {e}\")\n",[224,1925,1926,1931,1938,1946,1971,1987,2004,2019],{"__ignoreMap":315},[319,1927,1928],{"class":321,"line":322},[319,1929,1930],{"class":620},"# Resolve the actual path on disk using expath.\n",[319,1932,1933,1936],{"class":321,"line":333},[319,1934,1935],{"class":325},"try",[319,1937,1318],{"class":341},[319,1939,1940,1943],{"class":321,"line":354},[319,1941,1942],{"class":325},"    import",[319,1944,1945],{"class":329}," expath\n",[319,1947,1948,1951,1953,1956,1958,1961,1963,1965,1967,1969],{"class":321,"line":368},[319,1949,1950],{"class":329},"    resolved ",[319,1952,635],{"class":634},[319,1954,1955],{"class":329}," expath",[319,1957,342],{"class":341},[319,1959,1960],{"class":397},"resolve",[319,1962,382],{"class":341},[319,1964,444],{"class":419},[319,1966,547],{"class":389},[319,1968,444],{"class":419},[319,1970,447],{"class":341},[319,1972,1973,1976,1978,1980,1983,1985],{"class":321,"line":375},[319,1974,1975],{"class":378},"    print",[319,1977,382],{"class":341},[319,1979,444],{"class":419},[319,1981,1982],{"class":389},"configs:\u002F\u002Fexamples\u002Fmlp.py  resolves to:",[319,1984,444],{"class":419},[319,1986,447],{"class":341},[319,1988,1989,1991,1993,1995,1997,1999,2002],{"class":321,"line":663},[319,1990,1975],{"class":378},[319,1992,382],{"class":341},[319,1994,444],{"class":419},[319,1996,861],{"class":419},[319,1998,416],{"class":341},[319,2000,2001],{"class":397}," resolved",[319,2003,447],{"class":341},[319,2005,2006,2009,2012,2014,2017],{"class":321,"line":679},[319,2007,2008],{"class":325},"except",[319,2010,2011],{"class":946}," Exception",[319,2013,348],{"class":325},[319,2015,2016],{"class":329}," e",[319,2018,1318],{"class":341},[319,2020,2021,2023,2025,2027,2030,2032,2035,2037,2039],{"class":321,"line":779},[319,2022,1975],{"class":378},[319,2024,382],{"class":341},[319,2026,386],{"class":385},[319,2028,2029],{"class":389},"\"expath not available or resolution failed: ",[319,2031,394],{"class":393},[319,2033,2034],{"class":397},"e",[319,2036,441],{"class":393},[319,2038,444],{"class":389},[319,2040,447],{"class":341},[449,2042],{"data":2043,"kind":452},"ZXhwYXRoIG5vdCBhdmFpbGFibGUgb3IgcmVzb2x1dGlvbiBmYWlsZWQ6IG1vZHVsZSAnZXhwYXRoJyBoYXMgbm8gYXR0cmlidXRlICdyZXNvbHZlJwo=",[310,2045,2047],{"className":312,"code":2046,"language":314,"meta":315,"style":315},"# Demonstrate loading from an absolute filesystem path.\ntry:\n    import expath\n    abs_path = expath.resolve(\"configs:\u002F\u002Fexamples\u002Flinear_regression.py\")\n    cfg_from_abs = laco.load(str(abs_path))\n    print(\"Loaded from absolute path — top-level keys:\", list(cfg_from_abs.keys()))\nexcept Exception as e:\n    print(f\"Could not demonstrate absolute path loading: {e}\")\n",[224,2048,2049,2054,2060,2066,2089,2114,2142,2154],{"__ignoreMap":315},[319,2050,2051],{"class":321,"line":322},[319,2052,2053],{"class":620},"# Demonstrate loading from an absolute filesystem path.\n",[319,2055,2056,2058],{"class":321,"line":333},[319,2057,1935],{"class":325},[319,2059,1318],{"class":341},[319,2061,2062,2064],{"class":321,"line":354},[319,2063,1942],{"class":325},[319,2065,1945],{"class":329},[319,2067,2068,2071,2073,2075,2077,2079,2081,2083,2085,2087],{"class":321,"line":368},[319,2069,2070],{"class":329},"    abs_path ",[319,2072,635],{"class":634},[319,2074,1955],{"class":329},[319,2076,342],{"class":341},[319,2078,1960],{"class":397},[319,2080,382],{"class":341},[319,2082,444],{"class":419},[319,2084,739],{"class":389},[319,2086,444],{"class":419},[319,2088,447],{"class":341},[319,2090,2091,2094,2096,2098,2100,2102,2104,2107,2109,2112],{"class":321,"line":375},[319,2092,2093],{"class":329},"    cfg_from_abs ",[319,2095,635],{"class":634},[319,2097,338],{"class":329},[319,2099,342],{"class":341},[319,2101,642],{"class":397},[319,2103,382],{"class":341},[319,2105,2106],{"class":946},"str",[319,2108,382],{"class":341},[319,2110,2111],{"class":397},"abs_path",[319,2113,699],{"class":341},[319,2115,2116,2118,2120,2122,2125,2127,2129,2131,2133,2136,2138,2140],{"class":321,"line":663},[319,2117,1975],{"class":378},[319,2119,382],{"class":341},[319,2121,444],{"class":419},[319,2123,2124],{"class":389},"Loaded from absolute path — top-level keys:",[319,2126,444],{"class":419},[319,2128,416],{"class":341},[319,2130,947],{"class":946},[319,2132,382],{"class":341},[319,2134,2135],{"class":397},"cfg_from_abs",[319,2137,342],{"class":341},[319,2139,195],{"class":397},[319,2141,959],{"class":341},[319,2143,2144,2146,2148,2150,2152],{"class":321,"line":679},[319,2145,2008],{"class":325},[319,2147,2011],{"class":946},[319,2149,348],{"class":325},[319,2151,2016],{"class":329},[319,2153,1318],{"class":341},[319,2155,2156,2158,2160,2162,2165,2167,2169,2171,2173],{"class":321,"line":779},[319,2157,1975],{"class":378},[319,2159,382],{"class":341},[319,2161,386],{"class":385},[319,2163,2164],{"class":389},"\"Could not demonstrate absolute path loading: ",[319,2166,394],{"class":393},[319,2168,2034],{"class":397},[319,2170,441],{"class":393},[319,2172,444],{"class":389},[319,2174,447],{"class":341},[449,2176],{"data":2177,"kind":452},"Q291bGQgbm90IGRlbW9uc3RyYXRlIGFic29sdXRlIHBhdGggbG9hZGluZzogbW9kdWxlICdleHBhdGgnIGhhcyBubyBhdHRyaWJ1dGUgJ3Jlc29sdmUnCg==",[454,2179],{},[457,2181,2183],{"id":2182},"section-5-the-cli","Section 5: The CLI",[216,2185,2186],{},"laco ships a command-line interface with three sub-commands:",[517,2188,2189,2199],{},[520,2190,2191],{},[523,2192,2193,2196],{},[526,2194,2195],{},"Sub-command",[526,2197,2198],{},"What it does",[536,2200,2201,2211,2221],{},[523,2202,2203,2208],{},[541,2204,2205],{},[224,2206,2207],{},"laco compose \u003Cconfig> [overrides...]",[541,2209,2210],{},"Load config, apply overrides, print YAML to stdout",[523,2212,2213,2218],{},[541,2214,2215],{},[224,2216,2217],{},"laco show \u003Cconfig> [--groups] [--schema] [--defaults]",[541,2219,2220],{},"Inspect a config without instantiating",[523,2222,2223,2228],{},[541,2224,2225],{},[224,2226,2227],{},"laco run \u003Cconfig> [overrides...]",[541,2229,2230,2231,2234,2235,2238],{},"Load config and call the ",[224,2232,2233],{},"@L.task","-decorated ",[224,2236,2237],{},"task"," entry point",[2240,2241,2242],"blockquote",{},[216,2243,2244,2247,2248,2250,2251,2254,2255,2258],{},[219,2245,2246],{},"Note:"," If ",[224,2249,307],{}," is not on your ",[224,2252,2253],{},"PATH",", use ",[224,2256,2257],{},"python -m laco.cli"," as a drop-in replacement.",[216,2260,2261,2262,2265,2266,2269],{},"The cells below use ",[224,2263,2264],{},"!"," (shell execution) and ",[224,2267,2268],{},"subprocess.run"," to demonstrate both styles.",[310,2271,2273],{"className":312,"code":2272,"language":314,"meta":315,"style":315},"# Compose: load and dump the entire linear_regression config as YAML.\n# The output is identical to laco.dump(laco.load(...)).\n!laco compose configs:\u002F\u002Fexamples\u002Flinear_regression.py\n",[224,2274,2275,2280,2285],{"__ignoreMap":315},[319,2276,2277],{"class":321,"line":322},[319,2278,2279],{"class":620},"# Compose: load and dump the entire linear_regression config as YAML.\n",[319,2281,2282],{"class":321,"line":333},[319,2283,2284],{"class":620},"# The output is identical to laco.dump(laco.load(...)).\n",[319,2286,2287,2290,2293,2296,2299,2302,2304,2307,2309],{"class":321,"line":354},[319,2288,2264],{"class":2289},"srjyR",[319,2291,2292],{"class":329},"laco compose configs",[319,2294,2295],{"class":341},":",[319,2297,2298],{"class":634},"\u002F\u002F",[319,2300,2301],{"class":329},"examples",[319,2303,182],{"class":634},[319,2305,2306],{"class":329},"linear_regression",[319,2308,342],{"class":341},[319,2310,2311],{"class":345},"py\n",[449,2313],{"data":2314,"kind":452},"VHJhY2ViYWNrIChtb3N0IHJlY2VudCBjYWxsIGxhc3QpOgogIEZpbGUgIi9uaXgvc3RvcmUvMTE3OHltZDc4ODN2aDRmbTcwYnFxbjU3MGFnMmlrZHktbGFjby1lbnYvYmluL2xhY28iLCBsaW5lIDEwLCBpbiA8bW9kdWxlPgogICAgc3lzLmV4aXQobWFpbigpKQogICAgICAgICAgICAgfn5+fl5eCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vY2xpLnB5IiwgbGluZSA4NjcsIGluIG1haW4KICAgIF9jbWRfY29tcG9zZShhcmdzKQogICAgfn5+fn5+fn5+fn5+Xl5eXl5eCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vY2xpLnB5IiwgbGluZSAyMTMsIGluIF9jbWRfY29tcG9zZQogICAgY2ZnID0gbGFjby5sb2FkKGFyZ3MuaW5wdXQpCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vX2lvLnB5IiwgbGluZSA0NjMsIGluIGxvYWQKICAgIGV4dCA9IG9zLnBhdGguc3BsaXRleHQocGF0aClbMV0gICMgbm9xYTogUFRIMTIyCiAgICAgICAgICB+fn5+fn5+fn5+fn5+fn5+Xl5eXl5eCiAgRmlsZSAiPGZyb3plbiBwb3NpeHBhdGg+IiwgbGluZSAxMTgsIGluIHNwbGl0ZXh0ClR5cGVFcnJvcjogZXhwZWN0ZWQgc3RyLCBieXRlcyBvciBvcy5QYXRoTGlrZSBvYmplY3QsIG5vdCBOb25lVHlwZQo=",[310,2316,2318],{"className":312,"code":2317,"language":314,"meta":315,"style":315},"# Compose with an override — same as laco.load(..., \"hps.in_features=16\").\n!laco compose configs:\u002F\u002Fexamples\u002Flinear_regression.py hps.in_features=16\n",[224,2319,2320,2325],{"__ignoreMap":315},[319,2321,2322],{"class":321,"line":322},[319,2323,2324],{"class":620},"# Compose with an override — same as laco.load(..., \"hps.in_features=16\").\n",[319,2326,2327,2329,2331,2333,2335,2337,2339,2341,2343,2346,2349,2351,2354,2356],{"class":321,"line":333},[319,2328,2264],{"class":2289},[319,2330,2292],{"class":329},[319,2332,2295],{"class":341},[319,2334,2298],{"class":634},[319,2336,2301],{"class":329},[319,2338,182],{"class":634},[319,2340,2306],{"class":329},[319,2342,342],{"class":341},[319,2344,2345],{"class":345},"py",[319,2347,2348],{"class":329}," hps",[319,2350,342],{"class":341},[319,2352,2353],{"class":345},"in_features",[319,2355,635],{"class":634},[319,2357,2358],{"class":393},"16\n",[449,2360],{"data":2314,"kind":452},[310,2362,2364],{"className":312,"code":2363,"language":314,"meta":315,"style":315},"# Show: pretty-print the config (equivalent to compose with no overrides).\n!laco show configs:\u002F\u002Fexamples\u002Fmlp.py\n",[224,2365,2366,2371],{"__ignoreMap":315},[319,2367,2368],{"class":321,"line":322},[319,2369,2370],{"class":620},"# Show: pretty-print the config (equivalent to compose with no overrides).\n",[319,2372,2373,2375,2378,2380,2382,2384,2386,2389,2391],{"class":321,"line":333},[319,2374,2264],{"class":2289},[319,2376,2377],{"class":329},"laco show configs",[319,2379,2295],{"class":341},[319,2381,2298],{"class":634},[319,2383,2301],{"class":329},[319,2385,182],{"class":634},[319,2387,2388],{"class":329},"mlp",[319,2390,342],{"class":341},[319,2392,2311],{"class":345},[449,2394],{"data":2395,"kind":452},"VHJhY2ViYWNrIChtb3N0IHJlY2VudCBjYWxsIGxhc3QpOgogIEZpbGUgIi9uaXgvc3RvcmUvMTE3OHltZDc4ODN2aDRmbTcwYnFxbjU3MGFnMmlrZHktbGFjby1lbnYvYmluL2xhY28iLCBsaW5lIDEwLCBpbiA8bW9kdWxlPgogICAgc3lzLmV4aXQobWFpbigpKQogICAgICAgICAgICAgfn5+fl5eCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vY2xpLnB5IiwgbGluZSA4NzMsIGluIG1haW4KICAgIF9jbWRfc2hvdyhhcmdzKQogICAgfn5+fn5+fn5+Xl5eXl5eCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vY2xpLnB5IiwgbGluZSA4MjksIGluIF9jbWRfc2hvdwogICAgY2ZnID0gbGFjby5sb2FkKGFyZ3MuaW5wdXQpCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vX2lvLnB5IiwgbGluZSA0NjMsIGluIGxvYWQKICAgIGV4dCA9IG9zLnBhdGguc3BsaXRleHQocGF0aClbMV0gICMgbm9xYTogUFRIMTIyCiAgICAgICAgICB+fn5+fn5+fn5+fn5+fn5+Xl5eXl5eCiAgRmlsZSAiPGZyb3plbiBwb3NpeHBhdGg+IiwgbGluZSAxMTgsIGluIHNwbGl0ZXh0ClR5cGVFcnJvcjogZXhwZWN0ZWQgc3RyLCBieXRlcyBvciBvcy5QYXRoTGlrZSBvYmplY3QsIG5vdCBOb25lVHlwZQo=",[310,2397,2399],{"className":312,"code":2398,"language":314,"meta":315,"style":315},"# Alternative: subprocess.run — useful when you want to capture the output\n# in Python code without relying on shell magic.\nimport subprocess\n\nresult = subprocess.run(\n    [\"laco\", \"compose\", \"configs:\u002F\u002Fexamples\u002Flinear_regression.py\"],\n    capture_output=True,\n    text=True,\n)\n\nif result.returncode == 0:\n    print(\"Exit code: 0 (success)\")\n    print(\"First 500 characters of output:\")\n    print(result.stdout[:500])\nelse:\n    print(\"Exit code:\", result.returncode)\n    print(\"stderr:\", result.stderr)\n",[224,2400,2401,2406,2411,2418,2422,2439,2470,2482,2493,2497,2501,2521,2536,2551,2574,2581,2604],{"__ignoreMap":315},[319,2402,2403],{"class":321,"line":322},[319,2404,2405],{"class":620},"# Alternative: subprocess.run — useful when you want to capture the output\n",[319,2407,2408],{"class":321,"line":333},[319,2409,2410],{"class":620},"# in Python code without relying on shell magic.\n",[319,2412,2413,2415],{"class":321,"line":354},[319,2414,326],{"class":325},[319,2416,2417],{"class":329}," subprocess\n",[319,2419,2420],{"class":321,"line":368},[319,2421,372],{"emptyLinePlaceholder":371},[319,2423,2424,2427,2429,2432,2434,2437],{"class":321,"line":375},[319,2425,2426],{"class":329},"result ",[319,2428,635],{"class":634},[319,2430,2431],{"class":329}," subprocess",[319,2433,342],{"class":341},[319,2435,2436],{"class":397},"run",[319,2438,645],{"class":341},[319,2440,2441,2444,2446,2448,2450,2452,2454,2457,2459,2461,2463,2465,2467],{"class":321,"line":663},[319,2442,2443],{"class":341},"    [",[319,2445,444],{"class":419},[319,2447,307],{"class":389},[319,2449,444],{"class":419},[319,2451,416],{"class":341},[319,2453,861],{"class":419},[319,2455,2456],{"class":389},"compose",[319,2458,444],{"class":419},[319,2460,416],{"class":341},[319,2462,861],{"class":419},[319,2464,739],{"class":389},[319,2466,444],{"class":419},[319,2468,2469],{"class":341},"],\n",[319,2471,2472,2475,2477,2480],{"class":321,"line":679},[319,2473,2474],{"class":760},"    capture_output",[319,2476,635],{"class":634},[319,2478,2479],{"class":1307},"True",[319,2481,744],{"class":341},[319,2483,2484,2487,2489,2491],{"class":321,"line":779},[319,2485,2486],{"class":760},"    text",[319,2488,635],{"class":634},[319,2490,2479],{"class":1307},[319,2492,744],{"class":341},[319,2494,2495],{"class":321,"line":795},[319,2496,447],{"class":341},[319,2498,2499],{"class":321,"line":815},[319,2500,372],{"emptyLinePlaceholder":371},[319,2502,2503,2506,2509,2511,2514,2516,2519],{"class":321,"line":820},[319,2504,2505],{"class":325},"if",[319,2507,2508],{"class":329}," result",[319,2510,342],{"class":341},[319,2512,2513],{"class":345},"returncode",[319,2515,845],{"class":634},[319,2517,2518],{"class":393}," 0",[319,2520,1318],{"class":341},[319,2522,2523,2525,2527,2529,2532,2534],{"class":321,"line":826},[319,2524,1975],{"class":378},[319,2526,382],{"class":341},[319,2528,444],{"class":419},[319,2530,2531],{"class":389},"Exit code: 0 (success)",[319,2533,444],{"class":419},[319,2535,447],{"class":341},[319,2537,2538,2540,2542,2544,2547,2549],{"class":321,"line":869},[319,2539,1975],{"class":378},[319,2541,382],{"class":341},[319,2543,444],{"class":419},[319,2545,2546],{"class":389},"First 500 characters of output:",[319,2548,444],{"class":419},[319,2550,447],{"class":341},[319,2552,2553,2555,2557,2560,2562,2565,2568,2571],{"class":321,"line":1472},[319,2554,1975],{"class":378},[319,2556,382],{"class":341},[319,2558,2559],{"class":397},"result",[319,2561,342],{"class":341},[319,2563,2564],{"class":345},"stdout",[319,2566,2567],{"class":341},"[:",[319,2569,2570],{"class":393},"500",[319,2572,2573],{"class":341},"])\n",[319,2575,2576,2579],{"class":321,"line":1477},[319,2577,2578],{"class":325},"else",[319,2580,1318],{"class":341},[319,2582,2583,2585,2587,2589,2592,2594,2596,2598,2600,2602],{"class":321,"line":1483},[319,2584,1975],{"class":378},[319,2586,382],{"class":341},[319,2588,444],{"class":419},[319,2590,2591],{"class":389},"Exit code:",[319,2593,444],{"class":419},[319,2595,416],{"class":341},[319,2597,2508],{"class":397},[319,2599,342],{"class":341},[319,2601,2513],{"class":345},[319,2603,447],{"class":341},[319,2605,2606,2608,2610,2612,2615,2617,2619,2621,2623,2626],{"class":321,"line":1504},[319,2607,1975],{"class":378},[319,2609,382],{"class":341},[319,2611,444],{"class":419},[319,2613,2614],{"class":389},"stderr:",[319,2616,444],{"class":419},[319,2618,416],{"class":341},[319,2620,2508],{"class":397},[319,2622,342],{"class":341},[319,2624,2625],{"class":345},"stderr",[319,2627,447],{"class":341},[449,2629],{"data":2630,"kind":452},"RXhpdCBjb2RlOiAxCnN0ZGVycjogVHJhY2ViYWNrIChtb3N0IHJlY2VudCBjYWxsIGxhc3QpOgogIEZpbGUgIi9uaXgvc3RvcmUvMTE3OHltZDc4ODN2aDRmbTcwYnFxbjU3MGFnMmlrZHktbGFjby1lbnYvYmluL2xhY28iLCBsaW5lIDEwLCBpbiA8bW9kdWxlPgogICAgc3lzLmV4aXQobWFpbigpKQogICAgICAgICAgICAgfn5+fl5eCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vY2xpLnB5IiwgbGluZSA4NjcsIGluIG1haW4KICAgIF9jbWRfY29tcG9zZShhcmdzKQogICAgfn5+fn5+fn5+fn5+Xl5eXl5eCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vY2xpLnB5IiwgbGluZSAyMTMsIGluIF9jbWRfY29tcG9zZQogICAgY2ZnID0gbGFjby5sb2FkKGFyZ3MuaW5wdXQpCiAgRmlsZSAiL25peC9zdG9yZS8xMTc4eW1kNzg4M3ZoNGZtNzBicXFuNTcwYWcyaWtkeS1sYWNvLWVudi9saWIvcHl0aG9uMy4xMy9zaXRlLXBhY2thZ2VzL2xhY28vX2lvLnB5IiwgbGluZSA0NjMsIGluIGxvYWQKICAgIGV4dCA9IG9zLnBhdGguc3BsaXRleHQocGF0aClbMV0gICMgbm9xYTogUFRIMTIyCiAgICAgICAgICB+fn5+fn5+fn5+fn5+fn5+Xl5eXl5eCiAgRmlsZSAiPGZyb3plbiBwb3NpeHBhdGg+IiwgbGluZSAxMTgsIGluIHNwbGl0ZXh0ClR5cGVFcnJvcjogZXhwZWN0ZWQgc3RyLCBieXRlcyBvciBvcy5QYXRoTGlrZSBvYmplY3QsIG5vdCBOb25lVHlwZQoK",[310,2632,2634],{"className":312,"code":2633,"language":314,"meta":315,"style":315},"# python -m laco.cli is available when the laco CLI is not on PATH.\nresult2 = subprocess.run(\n    [\"python\", \"-m\", \"laco.cli\", \"compose\", \"configs:\u002F\u002Fexamples\u002Flinear_regression.py\"],\n    capture_output=True,\n    text=True,\n)\nprint(\"python -m laco.cli exit code:\", result2.returncode)\nassert result2.stdout == result.stdout, \"Output differs!\"\nprint(\"Output is identical to the laco CLI.\")\n",[224,2635,2636,2641,2656,2702,2712,2722,2726,2750,2777],{"__ignoreMap":315},[319,2637,2638],{"class":321,"line":322},[319,2639,2640],{"class":620},"# python -m laco.cli is available when the laco CLI is not on PATH.\n",[319,2642,2643,2646,2648,2650,2652,2654],{"class":321,"line":333},[319,2644,2645],{"class":329},"result2 ",[319,2647,635],{"class":634},[319,2649,2431],{"class":329},[319,2651,342],{"class":341},[319,2653,2436],{"class":397},[319,2655,645],{"class":341},[319,2657,2658,2660,2662,2664,2666,2668,2670,2673,2675,2677,2679,2682,2684,2686,2688,2690,2692,2694,2696,2698,2700],{"class":321,"line":354},[319,2659,2443],{"class":341},[319,2661,444],{"class":419},[319,2663,314],{"class":389},[319,2665,444],{"class":419},[319,2667,416],{"class":341},[319,2669,861],{"class":419},[319,2671,2672],{"class":389},"-m",[319,2674,444],{"class":419},[319,2676,416],{"class":341},[319,2678,861],{"class":419},[319,2680,2681],{"class":389},"laco.cli",[319,2683,444],{"class":419},[319,2685,416],{"class":341},[319,2687,861],{"class":419},[319,2689,2456],{"class":389},[319,2691,444],{"class":419},[319,2693,416],{"class":341},[319,2695,861],{"class":419},[319,2697,739],{"class":389},[319,2699,444],{"class":419},[319,2701,2469],{"class":341},[319,2703,2704,2706,2708,2710],{"class":321,"line":368},[319,2705,2474],{"class":760},[319,2707,635],{"class":634},[319,2709,2479],{"class":1307},[319,2711,744],{"class":341},[319,2713,2714,2716,2718,2720],{"class":321,"line":375},[319,2715,2486],{"class":760},[319,2717,635],{"class":634},[319,2719,2479],{"class":1307},[319,2721,744],{"class":341},[319,2723,2724],{"class":321,"line":663},[319,2725,447],{"class":341},[319,2727,2728,2730,2732,2734,2737,2739,2741,2744,2746,2748],{"class":321,"line":679},[319,2729,379],{"class":378},[319,2731,382],{"class":341},[319,2733,444],{"class":419},[319,2735,2736],{"class":389},"python -m laco.cli exit code:",[319,2738,444],{"class":419},[319,2740,416],{"class":341},[319,2742,2743],{"class":397}," result2",[319,2745,342],{"class":341},[319,2747,2513],{"class":345},[319,2749,447],{"class":341},[319,2751,2752,2754,2756,2758,2760,2762,2764,2766,2768,2770,2772,2775],{"class":321,"line":779},[319,2753,829],{"class":325},[319,2755,2743],{"class":329},[319,2757,342],{"class":341},[319,2759,2564],{"class":345},[319,2761,845],{"class":634},[319,2763,2508],{"class":329},[319,2765,342],{"class":341},[319,2767,2564],{"class":345},[319,2769,416],{"class":341},[319,2771,861],{"class":419},[319,2773,2774],{"class":389},"Output differs!",[319,2776,656],{"class":419},[319,2778,2779,2781,2783,2785,2788,2790],{"class":321,"line":795},[319,2780,379],{"class":378},[319,2782,382],{"class":341},[319,2784,444],{"class":419},[319,2786,2787],{"class":389},"Output is identical to the laco CLI.",[319,2789,444],{"class":419},[319,2791,447],{"class":341},[449,2793],{"data":2794,"kind":452},"cHl0aG9uIC1tIGxhY28uY2xpIGV4aXQgY29kZTogMQpPdXRwdXQgaXMgaWRlbnRpY2FsIHRvIHRoZSBsYWNvIENMSS4K",[454,2796],{},[457,2798,2800,2801],{"id":2799},"section-6-loadmodesafe","Section 6: ",[224,2802,295],{},[216,2804,2805,2806,2808,2809,2812,2813,2816],{},"By default, ",[224,2807,254],{}," executes ",[224,2810,2811],{},".py"," config files with ",[219,2814,2815],{},"full Python privileges",": it trusts the file like any other Python module. This is fine for your own configs.",[216,2818,2819,2820,2823,2824,2826],{},"When you load config files from ",[219,2821,2822],{},"external contributors"," (e.g. received via email, downloaded from a registry), ",[224,2825,295],{}," provides a defense-in-depth layer:",[2828,2829,2830,2858],"ol",{},[249,2831,2832,2835,2836,235,2839,235,2842,235,2845,235,2848,235,2851,235,2854,2857],{},[219,2833,2834],{},"Restricted builtins",": ",[224,2837,2838],{},"open",[224,2840,2841],{},"eval",[224,2843,2844],{},"exec",[224,2846,2847],{},"compile",[224,2849,2850],{},"globals",[224,2852,2853],{},"locals",[224,2855,2856],{},"breakpoint"," are removed from the config file's namespace.",[249,2859,2860,2863],{},[219,2861,2862],{},"Import allowlist",": only modules whose names start with an allowed prefix can be imported from within the config file.",[216,2865,2866,2867,2295],{},"The default allowlist is ",[224,2868,2869],{},"DEFAULT_SAFE_ALLOWED_MODULES",[310,2871,2873],{"className":312,"code":2872,"language":314,"meta":315,"style":315},"from laco._io import LoadMode, DEFAULT_SAFE_ALLOWED_MODULES\n\nprint(\"DEFAULT_SAFE_ALLOWED_MODULES:\", DEFAULT_SAFE_ALLOWED_MODULES)\n",[224,2874,2875,2895,2899],{"__ignoreMap":315},[319,2876,2877,2879,2881,2883,2885,2887,2890,2892],{"class":321,"line":322},[319,2878,357],{"class":325},[319,2880,338],{"class":329},[319,2882,342],{"class":341},[319,2884,1555],{"class":329},[319,2886,326],{"class":325},[319,2888,2889],{"class":329}," LoadMode",[319,2891,416],{"class":341},[319,2893,2894],{"class":402}," DEFAULT_SAFE_ALLOWED_MODULES\n",[319,2896,2897],{"class":321,"line":333},[319,2898,372],{"emptyLinePlaceholder":371},[319,2900,2901,2903,2905,2907,2910,2912,2914,2917],{"class":321,"line":354},[319,2902,379],{"class":378},[319,2904,382],{"class":341},[319,2906,444],{"class":419},[319,2908,2909],{"class":389},"DEFAULT_SAFE_ALLOWED_MODULES:",[319,2911,444],{"class":419},[319,2913,416],{"class":341},[319,2915,2916],{"class":378}," DEFAULT_SAFE_ALLOWED_MODULES",[319,2918,447],{"class":341},[449,2920],{"data":2921,"kind":452},"REVGQVVMVF9TQUZFX0FMTE9XRURfTU9EVUxFUzogKCdsYWNvJywgJ29tZWdhY29uZicsICd0b3JjaCcsICd0b3JjaC5ubicpCg==",[310,2923,2925],{"className":312,"code":2924,"language":314,"meta":315,"style":315},"# Load in SAFE mode — the linear_regression example only imports laco and torch,\n# so it is fully compatible with the default allowlist.\ncfg_safe = laco.load(\n    \"configs:\u002F\u002Fexamples\u002Flinear_regression.py\",\n    mode=LoadMode.SAFE,\n)\nprint(\"SAFE mode loaded successfully. Keys:\", list(cfg_safe.keys()))\n",[224,2926,2927,2932,2937,2952,2962,2980,2984],{"__ignoreMap":315},[319,2928,2929],{"class":321,"line":322},[319,2930,2931],{"class":620},"# Load in SAFE mode — the linear_regression example only imports laco and torch,\n",[319,2933,2934],{"class":321,"line":333},[319,2935,2936],{"class":620},"# so it is fully compatible with the default allowlist.\n",[319,2938,2939,2942,2944,2946,2948,2950],{"class":321,"line":354},[319,2940,2941],{"class":329},"cfg_safe ",[319,2943,635],{"class":634},[319,2945,338],{"class":329},[319,2947,342],{"class":341},[319,2949,642],{"class":397},[319,2951,645],{"class":341},[319,2953,2954,2956,2958,2960],{"class":321,"line":368},[319,2955,650],{"class":419},[319,2957,739],{"class":389},[319,2959,444],{"class":419},[319,2961,744],{"class":341},[319,2963,2964,2967,2969,2972,2974,2978],{"class":321,"line":375},[319,2965,2966],{"class":760},"    mode",[319,2968,635],{"class":634},[319,2970,2971],{"class":397},"LoadMode",[319,2973,342],{"class":341},[319,2975,2977],{"class":2976},"swQdS","SAFE",[319,2979,744],{"class":341},[319,2981,2982],{"class":321,"line":663},[319,2983,447],{"class":341},[319,2985,2986,2988,2990,2992,2995,2997,2999,3001,3003,3006,3008,3010],{"class":321,"line":679},[319,2987,379],{"class":378},[319,2989,382],{"class":341},[319,2991,444],{"class":419},[319,2993,2994],{"class":389},"SAFE mode loaded successfully. Keys:",[319,2996,444],{"class":419},[319,2998,416],{"class":341},[319,3000,947],{"class":946},[319,3002,382],{"class":341},[319,3004,3005],{"class":397},"cfg_safe",[319,3007,342],{"class":341},[319,3009,195],{"class":397},[319,3011,959],{"class":341},[449,3013],{"data":3014,"kind":452},"U0FGRSBtb2RlIGxvYWRlZCBzdWNjZXNzZnVsbHkuIEtleXM6IFsnaHBzJywgJ21vZGVsJywgJ29wdGltaXplciddCg==",[310,3016,3018],{"className":312,"code":3017,"language":314,"meta":315,"style":315},"# You can widen (or narrow) the allowlist with allowed_modules=.\n# Example: also allow 'numpy' in addition to the defaults.\ncfg_safe_wide = laco.load(\n    \"configs:\u002F\u002Fexamples\u002Flinear_regression.py\",\n    mode=LoadMode.SAFE,\n    allowed_modules=[\"laco\", \"omegaconf\", \"torch\", \"torch.nn\", \"numpy\"],\n)\nprint(\"Wide-allowlist SAFE mode loaded successfully.\")\n",[224,3019,3020,3025,3030,3045,3055,3069,3122,3126],{"__ignoreMap":315},[319,3021,3022],{"class":321,"line":322},[319,3023,3024],{"class":620},"# You can widen (or narrow) the allowlist with allowed_modules=.\n",[319,3026,3027],{"class":321,"line":333},[319,3028,3029],{"class":620},"# Example: also allow 'numpy' in addition to the defaults.\n",[319,3031,3032,3035,3037,3039,3041,3043],{"class":321,"line":354},[319,3033,3034],{"class":329},"cfg_safe_wide ",[319,3036,635],{"class":634},[319,3038,338],{"class":329},[319,3040,342],{"class":341},[319,3042,642],{"class":397},[319,3044,645],{"class":341},[319,3046,3047,3049,3051,3053],{"class":321,"line":368},[319,3048,650],{"class":419},[319,3050,739],{"class":389},[319,3052,444],{"class":419},[319,3054,744],{"class":341},[319,3056,3057,3059,3061,3063,3065,3067],{"class":321,"line":375},[319,3058,2966],{"class":760},[319,3060,635],{"class":634},[319,3062,2971],{"class":397},[319,3064,342],{"class":341},[319,3066,2977],{"class":2976},[319,3068,744],{"class":341},[319,3070,3071,3074,3076,3078,3080,3082,3084,3086,3088,3091,3093,3095,3097,3100,3102,3104,3106,3109,3111,3113,3115,3118,3120],{"class":321,"line":663},[319,3072,3073],{"class":760},"    allowed_modules",[319,3075,635],{"class":634},[319,3077,1806],{"class":341},[319,3079,444],{"class":419},[319,3081,307],{"class":389},[319,3083,444],{"class":419},[319,3085,416],{"class":341},[319,3087,861],{"class":419},[319,3089,3090],{"class":389},"omegaconf",[319,3092,444],{"class":419},[319,3094,416],{"class":341},[319,3096,861],{"class":419},[319,3098,3099],{"class":389},"torch",[319,3101,444],{"class":419},[319,3103,416],{"class":341},[319,3105,861],{"class":419},[319,3107,3108],{"class":389},"torch.nn",[319,3110,444],{"class":419},[319,3112,416],{"class":341},[319,3114,861],{"class":419},[319,3116,3117],{"class":389},"numpy",[319,3119,444],{"class":419},[319,3121,2469],{"class":341},[319,3123,3124],{"class":321,"line":679},[319,3125,447],{"class":341},[319,3127,3128,3130,3132,3134,3137,3139],{"class":321,"line":779},[319,3129,379],{"class":378},[319,3131,382],{"class":341},[319,3133,444],{"class":419},[319,3135,3136],{"class":389},"Wide-allowlist SAFE mode loaded successfully.",[319,3138,444],{"class":419},[319,3140,447],{"class":341},[449,3142],{"data":3143,"kind":452},"V2lkZS1hbGxvd2xpc3QgU0FGRSBtb2RlIGxvYWRlZCBzdWNjZXNzZnVsbHkuCg==",[310,3145,3147],{"className":312,"code":3146,"language":314,"meta":315,"style":315},"# Demonstrate that SAFE mode rejects disallowed imports.\nimport textwrap\nimport pathlib\nimport tempfile\n\n# Write a config that tries to import 'os' — not in the allowlist.\nevil_config = textwrap.dedent(\"\"\"\n    import os\n    import laco.language as L\n    from torch import nn\n\n    model = L.call(nn.Linear)(in_features=8, out_features=1)\n\"\"\")\n\nwith tempfile.NamedTemporaryFile(suffix=\".py\", mode=\"w\", delete=False) as f:\n    f.write(evil_config)\n    evil_path = f.name\n\ntry:\n    laco.load(evil_path, mode=LoadMode.SAFE)\n    print(\"ERROR: should have raised a LacoLoadError!\")\nexcept laco.LacoLoadError as e:\n    print(\"SAFE mode correctly blocked the import:\")\n    print(\" \", str(e)[:120])\nfinally:\n    pathlib.Path(evil_path).unlink()\n",[224,3148,3149,3154,3161,3167,3173,3177,3182,3202,3207,3212,3217,3221,3226,3233,3237,3287,3302,3315,3320,3327,3356,3372,3390,3406,3434,3442],{"__ignoreMap":315},[319,3150,3151],{"class":321,"line":322},[319,3152,3153],{"class":620},"# Demonstrate that SAFE mode rejects disallowed imports.\n",[319,3155,3156,3158],{"class":321,"line":333},[319,3157,326],{"class":325},[319,3159,3160],{"class":329}," textwrap\n",[319,3162,3163,3165],{"class":321,"line":354},[319,3164,326],{"class":325},[319,3166,1088],{"class":329},[319,3168,3169,3171],{"class":321,"line":368},[319,3170,326],{"class":325},[319,3172,1095],{"class":329},[319,3174,3175],{"class":321,"line":375},[319,3176,372],{"emptyLinePlaceholder":371},[319,3178,3179],{"class":321,"line":663},[319,3180,3181],{"class":620},"# Write a config that tries to import 'os' — not in the allowlist.\n",[319,3183,3184,3187,3189,3192,3194,3197,3199],{"class":321,"line":679},[319,3185,3186],{"class":329},"evil_config ",[319,3188,635],{"class":634},[319,3190,3191],{"class":329}," textwrap",[319,3193,342],{"class":341},[319,3195,3196],{"class":397},"dedent",[319,3198,382],{"class":341},[319,3200,3201],{"class":419},"\"\"\"\n",[319,3203,3204],{"class":321,"line":779},[319,3205,3206],{"class":389},"    import os\n",[319,3208,3209],{"class":321,"line":795},[319,3210,3211],{"class":389},"    import laco.language as L\n",[319,3213,3214],{"class":321,"line":815},[319,3215,3216],{"class":389},"    from torch import nn\n",[319,3218,3219],{"class":321,"line":820},[319,3220,372],{"emptyLinePlaceholder":371},[319,3222,3223],{"class":321,"line":826},[319,3224,3225],{"class":389},"    model = L.call(nn.Linear)(in_features=8, out_features=1)\n",[319,3227,3228,3231],{"class":321,"line":869},[319,3229,3230],{"class":419},"\"\"\"",[319,3232,447],{"class":341},[319,3234,3235],{"class":321,"line":1472},[319,3236,372],{"emptyLinePlaceholder":371},[319,3238,3239,3241,3243,3245,3247,3249,3251,3253,3255,3257,3259,3261,3263,3265,3267,3269,3271,3273,3275,3277,3279,3281,3283,3285],{"class":321,"line":1477},[319,3240,1261],{"class":325},[319,3242,1264],{"class":329},[319,3244,342],{"class":341},[319,3246,1269],{"class":397},[319,3248,382],{"class":341},[319,3250,1274],{"class":760},[319,3252,635],{"class":634},[319,3254,444],{"class":419},[319,3256,2811],{"class":389},[319,3258,444],{"class":419},[319,3260,416],{"class":341},[319,3262,1288],{"class":760},[319,3264,635],{"class":634},[319,3266,444],{"class":419},[319,3268,1295],{"class":389},[319,3270,444],{"class":419},[319,3272,416],{"class":341},[319,3274,1302],{"class":760},[319,3276,635],{"class":634},[319,3278,1308],{"class":1307},[319,3280,428],{"class":341},[319,3282,348],{"class":325},[319,3284,1315],{"class":329},[319,3286,1318],{"class":341},[319,3288,3289,3291,3293,3295,3297,3300],{"class":321,"line":1483},[319,3290,1323],{"class":329},[319,3292,342],{"class":341},[319,3294,1328],{"class":397},[319,3296,382],{"class":341},[319,3298,3299],{"class":397},"evil_config",[319,3301,447],{"class":341},[319,3303,3304,3307,3309,3311,3313],{"class":321,"line":1504},[319,3305,3306],{"class":329},"    evil_path ",[319,3308,635],{"class":634},[319,3310,1315],{"class":329},[319,3312,342],{"class":341},[319,3314,1348],{"class":345},[319,3316,3318],{"class":321,"line":3317},18,[319,3319,372],{"emptyLinePlaceholder":371},[319,3321,3323,3325],{"class":321,"line":3322},19,[319,3324,1935],{"class":325},[319,3326,1318],{"class":341},[319,3328,3330,3333,3335,3337,3339,3342,3344,3346,3348,3350,3352,3354],{"class":321,"line":3329},20,[319,3331,3332],{"class":329},"    laco",[319,3334,342],{"class":341},[319,3336,642],{"class":397},[319,3338,382],{"class":341},[319,3340,3341],{"class":397},"evil_path",[319,3343,416],{"class":341},[319,3345,1288],{"class":760},[319,3347,635],{"class":634},[319,3349,2971],{"class":397},[319,3351,342],{"class":341},[319,3353,2977],{"class":2976},[319,3355,447],{"class":341},[319,3357,3359,3361,3363,3365,3368,3370],{"class":321,"line":3358},21,[319,3360,1975],{"class":378},[319,3362,382],{"class":341},[319,3364,444],{"class":419},[319,3366,3367],{"class":389},"ERROR: should have raised a LacoLoadError!",[319,3369,444],{"class":419},[319,3371,447],{"class":341},[319,3373,3375,3377,3379,3381,3384,3386,3388],{"class":321,"line":3374},22,[319,3376,2008],{"class":325},[319,3378,338],{"class":329},[319,3380,342],{"class":341},[319,3382,3383],{"class":345},"LacoLoadError",[319,3385,348],{"class":325},[319,3387,2016],{"class":329},[319,3389,1318],{"class":341},[319,3391,3393,3395,3397,3399,3402,3404],{"class":321,"line":3392},23,[319,3394,1975],{"class":378},[319,3396,382],{"class":341},[319,3398,444],{"class":419},[319,3400,3401],{"class":389},"SAFE mode correctly blocked the import:",[319,3403,444],{"class":419},[319,3405,447],{"class":341},[319,3407,3409,3411,3413,3415,3417,3419,3422,3424,3426,3429,3432],{"class":321,"line":3408},24,[319,3410,1975],{"class":378},[319,3412,382],{"class":341},[319,3414,444],{"class":419},[319,3416,861],{"class":419},[319,3418,416],{"class":341},[319,3420,3421],{"class":946}," str",[319,3423,382],{"class":341},[319,3425,2034],{"class":397},[319,3427,3428],{"class":341},")[:",[319,3430,3431],{"class":393},"120",[319,3433,2573],{"class":341},[319,3435,3437,3440],{"class":321,"line":3436},25,[319,3438,3439],{"class":325},"finally",[319,3441,1318],{"class":341},[319,3443,3445,3448,3450,3452,3454,3456,3458,3460],{"class":321,"line":3444},26,[319,3446,3447],{"class":329},"    pathlib",[319,3449,342],{"class":341},[319,3451,485],{"class":397},[319,3453,382],{"class":341},[319,3455,3341],{"class":397},[319,3457,1154],{"class":341},[319,3459,1499],{"class":397},[319,3461,966],{"class":341},[449,3463],{"data":3464,"kind":452},"U0FGRSBtb2RlIGNvcnJlY3RseSBibG9ja2VkIHRoZSBpbXBvcnQ6CiAgRmFpbGVkIHRvIGxvYWQgY29uZmlnICcvdG1wL25peC1zaGVsbC54TUJYeVUvdG1wc2tscXpvOTAucHknOiBTQUZFIG1vZGU6IGltcG9ydCBvZiAnb3MnIGlzIG5vdCBpbiB0aGUgYWxsb3dsaXN0LiBBbGxvd2VkCg==",[216,3466,3467,222,3470,3472],{},[219,3468,3469],{},"Important caveat:",[224,3471,295],{}," is a defense-in-depth layer, not a sandbox. It blocks common attack vectors (filesystem access, arbitrary exec, uncontrolled imports) but does not prevent all possible malicious behavior. Use it to raise the bar when loading configs from untrusted sources, not as a complete security guarantee.",[216,3474,3475,3476,3478,3479,3482],{},"The same allowlist is enforced for ",[224,3477,1281],{}," files: the ",[224,3480,3481],{},"!!python\u002Fname:"," tag resolver only resolves names whose module prefix is in the allowlist.",[454,3484],{},[457,3486,3488],{"id":3487},"section-7-the-file-format-pipeline","Section 7: The File-Format Pipeline",[216,3490,3491,3492,3494,3495,3497,3498,3500],{},"Putting it all together: laco's IO model forms a closed loop between ",[224,3493,2811],{}," configs, ",[224,3496,510],{}," objects, and ",[224,3499,1281],{}," files.",[216,3502,3503],{},[219,3504,3505],{},"Recap:",[517,3507,3508,3518],{},[520,3509,3510],{},[523,3511,3512,3515],{},[526,3513,3514],{},"Operation",[526,3516,3517],{},"API",[536,3519,3520,3534,3547,3558,3571,3581,3593],{},[523,3521,3522,3529],{},[541,3523,3524,3526,3527],{},[224,3525,2811],{}," → ",[224,3528,510],{},[541,3530,3531],{},[224,3532,3533],{},"laco.load(\"path.py\")",[523,3535,3536,3542],{},[541,3537,3538,3526,3540],{},[224,3539,1281],{},[224,3541,510],{},[541,3543,3544],{},[224,3545,3546],{},"laco.load(\"path.yaml\")",[523,3548,3549,3554],{},[541,3550,3551,3553],{},[224,3552,510],{}," → YAML string",[541,3555,3556],{},[224,3557,1061],{},[523,3559,3560,3567],{},[541,3561,3562,3526,3564,3566],{},[224,3563,510],{},[224,3565,1281],{}," file",[541,3568,3569],{},[224,3570,1069],{},[523,3572,3573,3576],{},[541,3574,3575],{},"Load with restrictions",[541,3577,3578],{},[224,3579,3580],{},"laco.load(path, mode=LoadMode.SAFE)",[523,3582,3583,3586],{},[541,3584,3585],{},"Apply overrides",[541,3587,3588,3589,3592],{},"pass as positional strings or use the ",[224,3590,3591],{},"?query"," URL syntax",[523,3594,3595,3598],{},[541,3596,3597],{},"Select sub-config",[541,3599,3600,3601,3603,3604,3592],{},"pass ",[224,3602,1026],{}," or use the ",[224,3605,3606],{},"#fragment",[454,3608],{},[457,3610,3612],{"id":3611},"summary","Summary",[246,3614,3615,3621,3632,3639,3651],{},[249,3616,3617,3620],{},[219,3618,3619],{},"URL grammar"," packs path, overrides, and key into one string; separate arguments work equally well.",[249,3622,3623,3629,3630,342],{},[219,3624,3625,267,3627],{},[224,3626,266],{},[224,3628,270],{}," produce valid YAML that round-trips back through ",[224,3631,254],{},[249,3633,3634,3638],{},[219,3635,3636],{},[224,3637,277],{}," is a registered URI scheme that maps short names to installed package paths.",[249,3640,274,3641,494,3644,235,3646,235,3648,3650],{},[219,3642,3643],{},"CLI",[224,3645,284],{},[224,3647,287],{},[224,3649,290],{},") wraps the same Python API for shell use.",[249,3652,3653,3657,3658,3660],{},[219,3654,3655],{},[224,3656,295],{}," restricts builtins and imports when executing untrusted ",[224,3659,2811],{}," configs.",[216,3662,3663,222,3666,3669,3670,235,3673,235,3676,3679],{},[219,3664,3665],{},"Next:",[224,3667,3668],{},"06.nested-configs-and-containers.ipynb"," covers ",[224,3671,3672],{},"L.OrderedDict",[224,3674,3675],{},"L.repeat",[224,3677,3678],{},"expand_args",", and all five container macros.",[3681,3682,3683],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sptTA, html code.shiki .sptTA{--shiki-light:#6182B8;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .slqww, html code.shiki .slqww{--shiki-light:#6182B8;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .sZMiF, html code.shiki .sZMiF{--shiki-light:#E2931D;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srjyR, html code.shiki .srjyR{--shiki-light:#90A4AE;--shiki-light-font-style:inherit;--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html pre.shiki code .swQdS, html code.shiki .swQdS{--shiki-light:#E53935;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":315,"searchDepth":354,"depth":354,"links":3685},[3686,3687,3689,3690,3692,3693,3695,3696],{"id":459,"depth":333,"text":460},{"id":603,"depth":333,"text":3688},"Section 2: laco.load Variants",{"id":1045,"depth":333,"text":1046},{"id":1762,"depth":333,"text":3691},"Section 4: The configs:\u002F\u002F Protocol",{"id":2182,"depth":333,"text":2183},{"id":2799,"depth":333,"text":3694},"Section 6: LoadMode.SAFE",{"id":3487,"depth":333,"text":3488},{"id":3611,"depth":333,"text":3612},"Prerequisites: 01.why-laco.ipynb through 04.hyperparameters-and-interpolation.ipynb (laco basics, L.call, L.params, instantiation).","md",{"notebook":371},{"icon":25},{"title":39,"description":3697},"SDLi_syiRGl9OZcP8v0fxZVpyeumUEp-HE0C4KpkTCQ",{},1785687301971]