diff --git a/.asv/results/ci-linux/06c89cf9-virtualenv-py3.13-django5.1-djc-core-html-parser.json b/.asv/results/ci-linux/06c89cf9-virtualenv-py3.13-django5.1-djc-core-html-parser.json new file mode 100644 index 00000000..edbf55d8 --- /dev/null +++ b/.asv/results/ci-linux/06c89cf9-virtualenv-py3.13-django5.1-djc-core-html-parser.json @@ -0,0 +1 @@ +{"commit_hash": "06c89cf9e89a432197a4cabb5a1d6864dd6089ac", "env_name": "virtualenv-py3.13-django5.1-djc-core-html-parser", "date": 1749546769000, "params": {"machine": "ci-linux", "python": "3.13", "django": "5.1", "djc-core-html-parser": ""}, "python": "3.13", "requirements": {"django": "5.1", "djc-core-html-parser": ""}, "env_vars": {}, "result_columns": ["result", "params", "version", "started_at", "duration", "stats_ci_99_a", "stats_ci_99_b", "stats_q_25", "stats_q_75", "stats_number", "stats_repeat", "samples", "profile"], "results": {"Components vs Django.timeraw_render_lg_first": [[0.08026317200000221, 0.26819844099998136], [["'django'", "'django-components'"]], "be3bf6236960046a028b6ea007aad28b2337fc2b906b8ce317a09a5d4f1a6193", 1749547226154, 31.969, [0.079592, 0.26712], [0.081627, 0.27054], [0.079806, 0.26758], [0.080908, 0.27014], [1, 1], [25, 25]], "Components vs Django.timeraw_render_lg_subsequent": [[0.04349111400000538, 0.15453611999998884], [["'django'", "'django-components'"]], "b98221c11a0ee6e9de0778d416d31b9dd514a674d9017a2bb9b2fc1cd0f01920", 1749547232510, 37.93, [0.043083, 0.15395], [0.044645, 0.15628], [0.04313, 0.15396], [0.044614, 0.15596], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_first": [[0.0036145729999930154, 0.004811176000004025], [["'django'", "'django-components'"]], "f1fc17e4a31c71f4d9265f1122da52e7cf57addb4dfa02606e303b33d6431b9b", 1749547240091, 17.086, [0.0035701, 0.0047897], [0.0036399, 0.0048885], [0.0035736, 0.004795], [0.0036371, 0.0048827], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_subsequent": [[0.00012332000000014887, 0.0005915369999911491], [["'django'", "'django-components'"]], "6fce1cd85a9344fee383b40a22f27862120b9488a628420625592dc14e0307d3", 1749547243508, 17.13, [0.00012078, 0.0005805], [0.00013759, 0.00060184], [0.00012127, 0.00058107], [0.00012742, 0.00059879], [1, 1], [25, 25]], "Components vs Django.timeraw_startup_lg": [[0.2252378419999843, 0.2247263650000093], [["'django'", "'django-components'"]], "53151821c128ad0ecfb0707fff3146e1abd8d0bcfa301aa056b5d3fae3d793e2", 1749547246927, 19.999, [0.22441, 0.22363], [0.22729, 0.22686], [0.22452, 0.22369], [0.22639, 0.22556], [1, 1], [25, 25]], "Other.timeraw_import_time": [[0.20468290799999522], [], "a0a1c1c0db22509410b946d0d4384b52ea4a09b47b6048d7d1cfb89b0c7fe5c3", 1749547250936, 8.1567, [0.20338], [0.20624], [0.20374], [0.20582], [1], [25]], "isolated vs django modes.timeraw_render_lg_first": [[0.26819597400000816, 0.2740507329999957], [["'isolated'", "'django'"]], "f94af83427c6346f88f8785a3cd2fc42415ac5a9fbbdb7de71d27e22e6a81699", 1749547255664, 37.318, [0.26688, 0.27234], [0.26941, 0.28032], [0.26702, 0.2725], [0.26926, 0.279], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_lg_subsequent": [[0.15396625699997912, 0.16023626799997714], [["'isolated'", "'django'"]], "9f7c2fde6b33f0451a1794ed903c48d96cd7822f67da502cec36fe8e977c2414", 1749547263180, 47.125, [0.15282, 0.15877], [0.15647, 0.16443], [0.15297, 0.15902], [0.15588, 0.16441], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_first": [[0.004825538000005736, 0.0047952310000027865], [["'isolated'", "'django'"]], "d15ca68909d7f1f43ff16863befb6f42681f17461417fc0069eefd6db3569296", 1749547272622, 17.085, [0.0048028, 0.0047649], [0.0048467, 0.0048197], [0.0048091, 0.0047651], [0.0048402, 0.0048192], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_subsequent": [[0.0005953940000154034, 0.0005933700000468889], [["'isolated'", "'django'"]], "7444bc9516dd087e3f420349345eae991ad6941bbd22fce45265b18034b7cf77", 1749547276032, 17.147, [0.0005815, 0.00058741], [0.00060108, 0.00059832], [0.00058285, 0.0005878], [0.0006001, 0.00059759], [1, 1], [25, 25]], "isolated vs django modes.timeraw_startup_lg": [[0.22564571399999522, 0.22598634599995648], [["'isolated'", "'django'"]], "eabe311ebee4a15c5816617be12f00ec30376f7506bd668219e1c50bc897c134", 1749547279452, 19.816, [0.22324, 0.22336], [0.22965, 0.22994], [0.22384, 0.22382], [0.22963, 0.22889], [1, 1], [25, 25]], "Components vs Django.peakmem_render_lg_first": [[52932608, 55693312], [["'django'", "'django-components'"]], "301c396f017f45a5b3f71e85df58d15f54153fcfd951af7ef424641d4b31b528", 1749547223611, 0.79781], "Components vs Django.peakmem_render_lg_subsequent": [[53063680, 56180736], [["'django'", "'django-components'"]], "9a44e9999ef3ef42ea7e01323727490244febb43d66a87a4d8f88c6b8a133b8b", 1749547224409, 0.99222], "Components vs Django.peakmem_render_sm_first": [[44716032, 44834816], [["'django'", "'django-components'"]], "e93b7a5193681c883edf85bdb30b1bc0821263bf51033fdcee215b155085e036", 1749547225402, 0.37525], "Components vs Django.peakmem_render_sm_subsequent": [[44716032, 44838912], [["'django'", "'django-components'"]], "b46e0820b18950aa7cc5e61306ff3425b76b4da9dca42d64fae5b1d25c6c9026", 1749547225778, 0.37627], "isolated vs django modes.peakmem_render_lg_first": [[55263232, 54693888], [["'isolated'", "'django'"]], "c4bf0016d48d210f08b8db733b57c7dcba1cebbf548c458b93b86ace387067e9", 1749547252571, 1.0035], "isolated vs django modes.peakmem_render_lg_subsequent": [[55783424, 56160256], [["'isolated'", "'django'"]], "65bb1b8586487197a79bb6073e4c71642877b845b6eb42d1bd32398299daffbf", 1749547253575, 1.3187], "isolated vs django modes.peakmem_render_sm_first": [[44838912, 44838912], [["'isolated'", "'django'"]], "c51b91fc583295776062822225e720b5ed71aef9c9288217c401c54283c62840", 1749547254894, 0.38522], "isolated vs django modes.peakmem_render_sm_subsequent": [[44965888, 44834816], [["'isolated'", "'django'"]], "54d747fb8f40179b7ff3d2fc49eb195909ad1c880b5ef7b82f82742b27b67260", 1749547255279, 0.38471]}, "durations": {}, "version": 2} \ No newline at end of file diff --git a/.asv/results/ci-linux/5d7e2357-virtualenv-py3.13-django5.1-djc-core-html-parser.json b/.asv/results/ci-linux/5d7e2357-virtualenv-py3.13-django5.1-djc-core-html-parser.json new file mode 100644 index 00000000..5f591b2f --- /dev/null +++ b/.asv/results/ci-linux/5d7e2357-virtualenv-py3.13-django5.1-djc-core-html-parser.json @@ -0,0 +1 @@ +{"commit_hash": "5d7e235725449181f6b65b7bf97e43ea0e0f8552", "env_name": "virtualenv-py3.13-django5.1-djc-core-html-parser", "date": 1753049108000, "params": {"machine": "ci-linux", "python": "3.13", "django": "5.1", "djc-core-html-parser": ""}, "python": "3.13", "requirements": {"django": "5.1", "djc-core-html-parser": ""}, "env_vars": {}, "result_columns": ["result", "params", "version", "started_at", "duration", "stats_ci_99_a", "stats_ci_99_b", "stats_q_25", "stats_q_75", "stats_number", "stats_repeat", "samples", "profile"], "results": {"Components vs Django.timeraw_render_lg_first": [[0.08105427499998541, 0.29477426600001877], [["'django'", "'django-components'"]], "be3bf6236960046a028b6ea007aad28b2337fc2b906b8ce317a09a5d4f1a6193", 1753049851954, 33.615, [0.079961, 0.29197], [0.082291, 0.29933], [0.080014, 0.29202], [0.08217, 0.29917], [1, 1], [25, 25]], "Components vs Django.timeraw_render_lg_subsequent": [[0.043648402000002307, 0.17461173199995983], [["'django'", "'django-components'"]], "b98221c11a0ee6e9de0778d416d31b9dd514a674d9017a2bb9b2fc1cd0f01920", 1753049858567, 39.742, [0.043109, 0.17344], [0.044493, 0.17591], [0.043193, 0.17344], [0.044363, 0.17568], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_first": [[0.0037106409999978496, 0.004899473999955717], [["'django'", "'django-components'"]], "f1fc17e4a31c71f4d9265f1122da52e7cf57addb4dfa02606e303b33d6431b9b", 1753049866520, 17.599, [0.0036469, 0.0048514], [0.003775, 0.0049767], [0.0036506, 0.0048584], [0.0037527, 0.0049267], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_subsequent": [[0.00012706900002967814, 0.0006100459999629493], [["'django'", "'django-components'"]], "6fce1cd85a9344fee383b40a22f27862120b9488a628420625592dc14e0307d3", 1753049870045, 17.527, [0.00012441, 0.0005963], [0.00012848, 0.00063084], [0.00012455, 0.00059677], [0.00012835, 0.0006285], [1, 1], [25, 25]], "Components vs Django.timeraw_startup_lg": [[0.22799248500001568, 0.22723498599998493], [["'django'", "'django-components'"]], "53151821c128ad0ecfb0707fff3146e1abd8d0bcfa301aa056b5d3fae3d793e2", 1753049873538, 20.449, [0.22611, 0.22628], [0.22958, 0.22866], [0.22612, 0.2263], [0.22904, 0.22847], [1, 1], [25, 25]], "Other.timeraw_import_time": [[0.2056691309999792], [], "a0a1c1c0db22509410b946d0d4384b52ea4a09b47b6048d7d1cfb89b0c7fe5c3", 1753049877623, 8.3423, [0.20476], [0.20838], [0.20478], [0.20831], [1], [25]], "isolated vs django modes.timeraw_render_lg_first": [[0.2920349000000044, 0.2976166970000236], [["'isolated'", "'django'"]], "f94af83427c6346f88f8785a3cd2fc42415ac5a9fbbdb7de71d27e22e6a81699", 1753049882577, 39.421, [0.29051, 0.29507], [0.29462, 0.2996], [0.29057, 0.29561], [0.29428, 0.29935], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_lg_subsequent": [[0.17414895399997476, 0.178393189000019], [["'isolated'", "'django'"]], "9f7c2fde6b33f0451a1794ed903c48d96cd7822f67da502cec36fe8e977c2414", 1753049890450, 50.139, [0.17304, 0.17805], [0.17616, 0.17928], [0.17314, 0.17806], [0.17595, 0.17923], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_first": [[0.004897051999989799, 0.004863266000029398], [["'isolated'", "'django'"]], "d15ca68909d7f1f43ff16863befb6f42681f17461417fc0069eefd6db3569296", 1753049900457, 17.558, [0.0048512, 0.004838], [0.0049693, 0.0049278], [0.0048517, 0.0048435], [0.0049605, 0.0049223], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_subsequent": [[0.0006159270000125616, 0.0006080119999865019], [["'isolated'", "'django'"]], "7444bc9516dd087e3f420349345eae991ad6941bbd22fce45265b18034b7cf77", 1753049903955, 17.521, [0.00060693, 0.0005956], [0.00062901, 0.00061672], [0.00060764, 0.00059691], [0.00062683, 0.00061634], [1, 1], [25, 25]], "isolated vs django modes.timeraw_startup_lg": [[0.22777395400004252, 0.2292747939999913], [["'isolated'", "'django'"]], "eabe311ebee4a15c5816617be12f00ec30376f7506bd668219e1c50bc897c134", 1753049907456, 20.282, [0.22683, 0.22736], [0.2295, 0.23339], [0.22692, 0.22764], [0.22924, 0.23178], [1, 1], [25, 25]], "Components vs Django.peakmem_render_lg_first": [[52715520, 56090624], [["'django'", "'django-components'"]], "301c396f017f45a5b3f71e85df58d15f54153fcfd951af7ef424641d4b31b528", 1753049849303, 0.82982], "Components vs Django.peakmem_render_lg_subsequent": [[52736000, 56791040], [["'django'", "'django-components'"]], "9a44e9999ef3ef42ea7e01323727490244febb43d66a87a4d8f88c6b8a133b8b", 1753049850134, 1.0513], "Components vs Django.peakmem_render_sm_first": [[44871680, 44912640], [["'django'", "'django-components'"]], "e93b7a5193681c883edf85bdb30b1bc0821263bf51033fdcee215b155085e036", 1753049851185, 0.38233], "Components vs Django.peakmem_render_sm_subsequent": [[44617728, 44986368], [["'django'", "'django-components'"]], "b46e0820b18950aa7cc5e61306ff3425b76b4da9dca42d64fae5b1d25c6c9026", 1753049851568, 0.38596], "isolated vs django modes.peakmem_render_lg_first": [[56090624, 55582720], [["'isolated'", "'django'"]], "c4bf0016d48d210f08b8db733b57c7dcba1cebbf548c458b93b86ace387067e9", 1753049879302, 1.0575], "isolated vs django modes.peakmem_render_lg_subsequent": [[56786944, 56778752], [["'isolated'", "'django'"]], "65bb1b8586487197a79bb6073e4c71642877b845b6eb42d1bd32398299daffbf", 1753049880360, 1.4396], "isolated vs django modes.peakmem_render_sm_first": [[44843008, 44851200], [["'isolated'", "'django'"]], "c51b91fc583295776062822225e720b5ed71aef9c9288217c401c54283c62840", 1753049881800, 0.38828], "isolated vs django modes.peakmem_render_sm_subsequent": [[44982272, 44986368], [["'isolated'", "'django'"]], "54d747fb8f40179b7ff3d2fc49eb195909ad1c880b5ef7b82f82742b27b67260", 1753049882189, 0.38775]}, "durations": {}, "version": 2} \ No newline at end of file diff --git a/.asv/results/ci-linux/7b24b86f-virtualenv-py3.13-django5.1-djc-core-html-parser.json b/.asv/results/ci-linux/7b24b86f-virtualenv-py3.13-django5.1-djc-core-html-parser.json new file mode 100644 index 00000000..3acec4f5 --- /dev/null +++ b/.asv/results/ci-linux/7b24b86f-virtualenv-py3.13-django5.1-djc-core-html-parser.json @@ -0,0 +1 @@ +{"commit_hash": "7b24b86f4a836c697acba926d9d6602afa45418d", "env_name": "virtualenv-py3.13-django5.1-djc-core-html-parser", "date": 1749076521000, "params": {"machine": "ci-linux", "python": "3.13", "django": "5.1", "djc-core-html-parser": ""}, "python": "3.13", "requirements": {"django": "5.1", "djc-core-html-parser": ""}, "env_vars": {}, "result_columns": ["result", "params", "version", "started_at", "duration", "stats_ci_99_a", "stats_ci_99_b", "stats_q_25", "stats_q_75", "stats_number", "stats_repeat", "samples", "profile"], "results": {"Components vs Django.timeraw_render_lg_first": [[0.07941284200001064, 0.26779402600004687], [["'django'", "'django-components'"]], "be3bf6236960046a028b6ea007aad28b2337fc2b906b8ce317a09a5d4f1a6193", 1749076875010, 33.29, [0.078956, 0.26662], [0.081186, 0.27149], [0.079001, 0.26705], [0.080936, 0.27135], [1, 1], [25, 25]], "Components vs Django.timeraw_render_lg_subsequent": [[0.043317416999911984, 0.15457556900003055], [["'django'", "'django-components'"]], "b98221c11a0ee6e9de0778d416d31b9dd514a674d9017a2bb9b2fc1cd0f01920", 1749076881523, 38.751, [0.042862, 0.15282], [0.044278, 0.15833], [0.042896, 0.15289], [0.044184, 0.15671], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_first": [[0.0036632869999948525, 0.00493345400002454], [["'django'", "'django-components'"]], "f1fc17e4a31c71f4d9265f1122da52e7cf57addb4dfa02606e303b33d6431b9b", 1749076889315, 17.497, [0.0036441, 0.0048964], [0.0037017, 0.0050018], [0.0036475, 0.0049028], [0.0037007, 0.0049814], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_subsequent": [[0.00012153600005149201, 0.0005999570000199128], [["'django'", "'django-components'"]], "6fce1cd85a9344fee383b40a22f27862120b9488a628420625592dc14e0307d3", 1749076892858, 17.52, [0.00012055, 0.00057981], [0.00012289, 0.00061584], [0.00012056, 0.00058243], [0.00012282, 0.00061301], [1, 1], [25, 25]], "Components vs Django.timeraw_startup_lg": [[0.22743783699991127, 0.226070988999993], [["'django'", "'django-components'"]], "53151821c128ad0ecfb0707fff3146e1abd8d0bcfa301aa056b5d3fae3d793e2", 1749076896345, 20.618, [0.22567, 0.22411], [0.22912, 0.22959], [0.22581, 0.22418], [0.22858, 0.22815], [1, 1], [25, 25]], "Other.timeraw_import_time": [[0.2063091950000171], [], "a0a1c1c0db22509410b946d0d4384b52ea4a09b47b6048d7d1cfb89b0c7fe5c3", 1749076900468, 8.3563, [0.20413], [0.20858], [0.20424], [0.20774], [1], [25]], "isolated vs django modes.timeraw_render_lg_first": [[0.2675778039999841, 0.2724974679999832], [["'isolated'", "'django'"]], "f94af83427c6346f88f8785a3cd2fc42415ac5a9fbbdb7de71d27e22e6a81699", 1749076905243, 38.085, [0.26574, 0.27164], [0.27197, 0.27673], [0.26585, 0.27165], [0.27065, 0.27581], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_lg_subsequent": [[0.15459265900005903, 0.15926110200007315], [["'isolated'", "'django'"]], "9f7c2fde6b33f0451a1794ed903c48d96cd7822f67da502cec36fe8e977c2414", 1749076912924, 47.983, [0.15333, 0.15793], [0.15993, 0.16206], [0.1535, 0.15845], [0.15979, 0.16152], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_first": [[0.004923484000073586, 0.004925836999973399], [["'isolated'", "'django'"]], "d15ca68909d7f1f43ff16863befb6f42681f17461417fc0069eefd6db3569296", 1749076922561, 17.577, [0.0048564, 0.0048656], [0.0050014, 0.004982], [0.0048761, 0.0048661], [0.004997, 0.004977], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_subsequent": [[0.0005969709999362749, 0.0005864510000037626], [["'isolated'", "'django'"]], "7444bc9516dd087e3f420349345eae991ad6941bbd22fce45265b18034b7cf77", 1749076926091, 17.606, [0.00058144, 0.00058324], [0.00060954, 0.00059625], [0.00058749, 0.00058422], [0.00060768, 0.00059614], [1, 1], [25, 25]], "isolated vs django modes.timeraw_startup_lg": [[0.22545313400001987, 0.22602228000005198], [["'isolated'", "'django'"]], "eabe311ebee4a15c5816617be12f00ec30376f7506bd668219e1c50bc897c134", 1749076929634, 20.393, [0.22445, 0.22472], [0.22834, 0.22927], [0.2245, 0.22475], [0.22781, 0.22878], [1, 1], [25, 25]], "Components vs Django.peakmem_render_lg_first": [[52957184, 55177216], [["'django'", "'django-components'"]], "301c396f017f45a5b3f71e85df58d15f54153fcfd951af7ef424641d4b31b528", 1749076872421, 0.81152], "Components vs Django.peakmem_render_lg_subsequent": [[52822016, 56242176], [["'django'", "'django-components'"]], "9a44e9999ef3ef42ea7e01323727490244febb43d66a87a4d8f88c6b8a133b8b", 1749076873233, 1.0095], "Components vs Django.peakmem_render_sm_first": [[44756992, 44744704], [["'django'", "'django-components'"]], "e93b7a5193681c883edf85bdb30b1bc0821263bf51033fdcee215b155085e036", 1749076874243, 0.37927], "Components vs Django.peakmem_render_sm_subsequent": [[44527616, 44744704], [["'django'", "'django-components'"]], "b46e0820b18950aa7cc5e61306ff3425b76b4da9dca42d64fae5b1d25c6c9026", 1749076874622, 0.38717], "isolated vs django modes.peakmem_render_lg_first": [[55222272, 54722560], [["'isolated'", "'django'"]], "c4bf0016d48d210f08b8db733b57c7dcba1cebbf548c458b93b86ace387067e9", 1749076902121, 1.0091], "isolated vs django modes.peakmem_render_lg_subsequent": [[56008704, 56143872], [["'isolated'", "'django'"]], "65bb1b8586487197a79bb6073e4c71642877b845b6eb42d1bd32398299daffbf", 1749076903130, 1.3368], "isolated vs django modes.peakmem_render_sm_first": [[44744704, 44744704], [["'isolated'", "'django'"]], "c51b91fc583295776062822225e720b5ed71aef9c9288217c401c54283c62840", 1749076904467, 0.38687], "isolated vs django modes.peakmem_render_sm_subsequent": [[44744704, 44744704], [["'isolated'", "'django'"]], "54d747fb8f40179b7ff3d2fc49eb195909ad1c880b5ef7b82f82742b27b67260", 1749076904855, 0.38848]}, "durations": {}, "version": 2} \ No newline at end of file diff --git a/.asv/results/ci-linux/c692b7a3-virtualenv-py3.13-django5.1-djc-core-html-parser.json b/.asv/results/ci-linux/c692b7a3-virtualenv-py3.13-django5.1-djc-core-html-parser.json new file mode 100644 index 00000000..14392b99 --- /dev/null +++ b/.asv/results/ci-linux/c692b7a3-virtualenv-py3.13-django5.1-djc-core-html-parser.json @@ -0,0 +1 @@ +{"commit_hash": "c692b7a3105c65414d2c23c357ffed9debdbf6e9", "env_name": "virtualenv-py3.13-django5.1-djc-core-html-parser", "date": 1751538441000, "params": {"machine": "ci-linux", "python": "3.13", "django": "5.1", "djc-core-html-parser": ""}, "python": "3.13", "requirements": {"django": "5.1", "djc-core-html-parser": ""}, "env_vars": {}, "result_columns": ["result", "params", "version", "started_at", "duration", "stats_ci_99_a", "stats_ci_99_b", "stats_q_25", "stats_q_75", "stats_number", "stats_repeat", "samples", "profile"], "results": {"Components vs Django.timeraw_render_lg_first": [[0.0814841690000776, 0.28364495499999975], [["'django'", "'django-components'"]], "be3bf6236960046a028b6ea007aad28b2337fc2b906b8ce317a09a5d4f1a6193", 1751538832752, 34.343, [0.079655, 0.2763], [0.083151, 0.28972], [0.079684, 0.27776], [0.082952, 0.28852], [1, 1], [25, 25]], "Components vs Django.timeraw_render_lg_subsequent": [[0.04362213900003553, 0.16551773399999092], [["'django'", "'django-components'"]], "b98221c11a0ee6e9de0778d416d31b9dd514a674d9017a2bb9b2fc1cd0f01920", 1751538839695, 39.947, [0.042835, 0.16259], [0.044314, 0.1709], [0.04289, 0.16268], [0.044297, 0.17072], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_first": [[0.00375721499995052, 0.0049729269999261305], [["'django'", "'django-components'"]], "f1fc17e4a31c71f4d9265f1122da52e7cf57addb4dfa02606e303b33d6431b9b", 1751538847853, 18.382, [0.0036459, 0.0048221], [0.0038196, 0.0051737], [0.0036541, 0.0048489], [0.0038098, 0.0051177], [1, 1], [25, 25]], "Components vs Django.timeraw_render_sm_subsequent": [[0.00012686900004155177, 0.0006182140000419167], [["'django'", "'django-components'"]], "6fce1cd85a9344fee383b40a22f27862120b9488a628420625592dc14e0307d3", 1751538851498, 18.239, [0.00012524, 0.00060676], [0.00013161, 0.0006405], [0.00012579, 0.00060829], [0.00012952, 0.00063066], [1, 1], [25, 25]], "Components vs Django.timeraw_startup_lg": [[0.23076480500003527, 0.23163660399995933], [["'django'", "'django-components'"]], "53151821c128ad0ecfb0707fff3146e1abd8d0bcfa301aa056b5d3fae3d793e2", 1751538855102, 21.331, [0.228, 0.22934], [0.24129, 0.23958], [0.22861, 0.23032], [0.23462, 0.23903], [1, 1], [25, 25]], "Other.timeraw_import_time": [[0.21042045099989082], [], "a0a1c1c0db22509410b946d0d4384b52ea4a09b47b6048d7d1cfb89b0c7fe5c3", 1751538859357, 8.7502, [0.20296], [0.21809], [0.20498], [0.21758], [1], [25]], "isolated vs django modes.timeraw_render_lg_first": [[0.2794132599999557, 0.28440619299999526], [["'isolated'", "'django'"]], "f94af83427c6346f88f8785a3cd2fc42415ac5a9fbbdb7de71d27e22e6a81699", 1751538864363, 39.572, [0.27575, 0.28135], [0.28414, 0.29307], [0.2763, 0.28173], [0.2821, 0.29138], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_lg_subsequent": [[0.16650312799993117, 0.17177308600003016], [["'isolated'", "'django'"]], "9f7c2fde6b33f0451a1794ed903c48d96cd7822f67da502cec36fe8e977c2414", 1751538872327, 50.556, [0.1622, 0.16821], [0.16877, 0.17739], [0.16257, 0.16909], [0.16869, 0.17637], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_first": [[0.005049280000093859, 0.004947880000145233], [["'isolated'", "'django'"]], "d15ca68909d7f1f43ff16863befb6f42681f17461417fc0069eefd6db3569296", 1751538882427, 18.336, [0.0048311, 0.0047979], [0.0051732, 0.0051086], [0.0048842, 0.0047995], [0.005169, 0.0050803], [1, 1], [25, 25]], "isolated vs django modes.timeraw_render_sm_subsequent": [[0.0006160310000495883, 0.0006166809999967882], [["'isolated'", "'django'"]], "7444bc9516dd087e3f420349345eae991ad6941bbd22fce45265b18034b7cf77", 1751538886046, 18.232, [0.00060088, 0.00060389], [0.00063506, 0.00063793], [0.00060598, 0.00060406], [0.00063334, 0.00063127], [1, 1], [25, 25]], "isolated vs django modes.timeraw_startup_lg": [[0.2295973340000046, 0.23030742100002044], [["'isolated'", "'django'"]], "eabe311ebee4a15c5816617be12f00ec30376f7506bd668219e1c50bc897c134", 1751538889806, 21.076, [0.22658, 0.22629], [0.24075, 0.2421], [0.22709, 0.22647], [0.23956, 0.2393], [1, 1], [25, 25]], "Components vs Django.peakmem_render_lg_first": [[53096448, 55484416], [["'django'", "'django-components'"]], "301c396f017f45a5b3f71e85df58d15f54153fcfd951af7ef424641d4b31b528", 1751538830129, 0.81232], "Components vs Django.peakmem_render_lg_subsequent": [[53018624, 56389632], [["'django'", "'django-components'"]], "9a44e9999ef3ef42ea7e01323727490244febb43d66a87a4d8f88c6b8a133b8b", 1751538830942, 1.0287], "Components vs Django.peakmem_render_sm_first": [[44716032, 44969984], [["'django'", "'django-components'"]], "e93b7a5193681c883edf85bdb30b1bc0821263bf51033fdcee215b155085e036", 1751538831971, 0.39208], "Components vs Django.peakmem_render_sm_subsequent": [[44724224, 44969984], [["'django'", "'django-components'"]], "b46e0820b18950aa7cc5e61306ff3425b76b4da9dca42d64fae5b1d25c6c9026", 1751538832363, 0.38781], "isolated vs django modes.peakmem_render_lg_first": [[55476224, 54968320], [["'isolated'", "'django'"]], "c4bf0016d48d210f08b8db733b57c7dcba1cebbf548c458b93b86ace387067e9", 1751538861133, 1.051], "isolated vs django modes.peakmem_render_lg_subsequent": [[56352768, 56516608], [["'isolated'", "'django'"]], "65bb1b8586487197a79bb6073e4c71642877b845b6eb42d1bd32398299daffbf", 1751538862185, 1.3815], "isolated vs django modes.peakmem_render_sm_first": [[44969984, 44969984], [["'isolated'", "'django'"]], "c51b91fc583295776062822225e720b5ed71aef9c9288217c401c54283c62840", 1751538863566, 0.38739], "isolated vs django modes.peakmem_render_sm_subsequent": [[44974080, 44974080], [["'isolated'", "'django'"]], "54d747fb8f40179b7ff3d2fc49eb195909ad1c880b5ef7b82f82742b27b67260", 1751538863954, 0.40929]}, "durations": {}, "version": 2} \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..9558bffd --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.0/containers/python-3 +{ + // Uncomment to run Python 3.13 or other specific version + // "image": "mcr.microsoft.com/devcontainers/python:3.13-bullseye", + + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "python.defaultInterpreterPath": "/usr/local/bin/python", + "python.linting.enabled": true + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "ms-python.vscode-python-envs", + "jurooravec.python-inline-source-2" + ] + } + } + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + //"postCreateCommand": "" +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6615dc98..9cabbd37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,71 @@ # Release notes +## v0.141.2 + +#### Fix + +- Fix bug where JS and CSS were missing when `{% component %}` tag was inside `{% include %}` tag ([#1296](https://github.com/django-components/django-components/issues/1296)) + +## v0.141.1 + +#### Fix + +- Components' JS and CSS scripts (e.g. from `Component.js` or `Component.js_file`) are now cached at class creation time. + + This means that when you now restart the server while having a page opened in the browser, + the JS / CSS files are immediately available. + + Previously, the JS/CSS were cached only after the components were rendered. So you had to reload + the page to trigger the rendering, in order to make the JS/CSS files available. + +- Fix the default cache for JS / CSS scripts to be unbounded. + + Previously, the default cache for the JS/CSS scripts (`LocMemCache`) was accidentally limited to 300 entries (~150 components). + +- Do not send `template_rendered` signal when rendering a component with no template. ([#1277](https://github.com/django-components/django-components/issues/1277)) + +## v0.141.0 + +#### Feat + +- New extension hooks `on_template_loaded`, `on_js_loaded`, `on_css_loaded`, and `on_template_compiled` + + The first 3 hooks are called when Component's template / JS / CSS is loaded as a string. + + The `on_template_compiled` hook is called when Component's template is compiled to a Template. + + The `on_xx_loaded` hooks can modify the content by returning the new value. + + ```py + class MyExtension(ComponentExtension): + def on_template_loaded(self, ctx: OnTemplateLoadedContext) -> Optional[str]: + return ctx.content + "" + + def on_js_loaded(self, ctx: OnJsLoadedContext) -> Optional[str]: + return ctx.content + "// Hello!" + + def on_css_loaded(self, ctx: OnCssLoadedContext) -> Optional[str]: + return ctx.content + "/* Hello! */" + ``` + + See all [Extension hooks](https://django-components.github.io/django-components/0.141.0/reference/extension_hooks/). + +#### Fix + +- Subclassing - Previously, if a parent component defined `Component.template` or `Component.template_file`, it's subclass would use the same `Template` instance. + + This could lead to unexpected behavior, where a change to the template of the subclass would also change the template of the parent class. + + Now, each subclass has it's own `Template` instance, and changes to the template of the subclass do not affect the template of the parent class. + +- Fix Django failing to restart due to "TypeError: 'Dynamic' object is not iterable" ([#1232](https://github.com/django-components/django-components/issues/1232)) + +- Fix bug when error formatting failed when error value was not a string. + +#### Refactor + +- `components ext run` CLI command now allows to call only those extensions that actually have subcommands. + ## v0.140.1 #### Fix @@ -70,7 +136,7 @@ Summary: - `"append"` - `"ignore"` - See [Dependencies rendering](https://django-components.github.io/django-components/0.140/concepts/advanced/rendering_js_css/) for more info. + See [Dependencies rendering](https://django-components.github.io/django-components/0.140.1/concepts/advanced/rendering_js_css/) for more info. **Typing** @@ -94,8 +160,8 @@ Summary: text: str ``` - See [Migrating from generics to class attributes](https://django-components.github.io/django-components/0.140/concepts/fundamentals/typing_and_validation/#migrating-from-generics-to-class-attributes) for more info. + See [Migrating from generics to class attributes](https://django-components.github.io/django-components/0.140.1/concepts/fundamentals/typing_and_validation/#migrating-from-generics-to-class-attributes) for more info. - Removed `EmptyTuple` and `EmptyDict` types. Instead, there is now a single `Empty` type. ```py @@ -983,7 +1049,7 @@ Summary: - Rendered HTML is left as-is. You can still process it with a different strategy later with `render_dependencies()`. - Used for inserting rendered HTML into other components. - See [Dependencies rendering](https://django-components.github.io/django-components/0.140/concepts/advanced/rendering_js_css/) for more info. + See [Dependencies rendering](https://django-components.github.io/django-components/0.140.1/concepts/advanced/rendering_js_css/) for more info. - New `Component.args`, `Component.kwargs`, `Component.slots` attributes available on the component class itself. @@ -1063,7 +1129,7 @@ Summary: - Modify the rendered output after it has been rendered - Handle errors - See [on_render](https://django-components.github.io/django-components/0.140/concepts/advanced/hooks/#on_render) for more info. + See [on_render](https://django-components.github.io/django-components/0.140.1/concepts/advanced/hooks/#on_render) for more info. - `get_component_url()` now optionally accepts `query` and `fragment` arguments. @@ -1131,7 +1197,7 @@ Summary: - `ComponentNode` instance if the slot was created as a default slot from a `{% component %}` tag. - `None` if the slot was created from a string, function, or `Slot` instance. - See [Slot metadata](https://django-components.github.io/django-components/0.140/concepts/fundamentals/slots/#slot-metadata). + See [Slot metadata](https://django-components.github.io/django-components/0.140.1/concepts/fundamentals/slots/#slot-metadata). - `{% fill %}` tag now accepts `body` kwarg to pass a Slot instance to fill. @@ -1230,13 +1296,13 @@ Summary: ) ``` - Read more on [Component caching](https://django-components.github.io/django-components/0.140/concepts/advanced/component_caching/). + Read more on [Component caching](https://django-components.github.io/django-components/0.140.1/concepts/advanced/component_caching/). - New extension hook `on_slot_rendered()` This hook is called when a slot is rendered, and allows you to access and/or modify the rendered result. - This is used by the ["debug highlight" feature](https://django-components.github.io/django-components/0.140/guides/other/troubleshooting/#component-and-slot-highlighting). + This is used by the ["debug highlight" feature](https://django-components.github.io/django-components/0.140.1/guides/other/troubleshooting/#component-and-slot-highlighting). To modify the rendered result, return the new value: @@ -1248,7 +1314,7 @@ Summary: If you don't want to modify the rendered result, return `None`. - See all [Extension hooks](https://django-components.github.io/django-components/0.140/reference/extension_hooks/). + See all [Extension hooks](https://django-components.github.io/django-components/0.140.1/reference/extension_hooks/). - When creating extensions, the previous syntax with `ComponentExtension.ExtensionClass` was causing Mypy errors, because Mypy doesn't allow using class attributes as bases: diff --git a/README.md b/README.md index 241f939e..8df3262e 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,9 @@ A component in django-components can be as simple as a Django template and Pytho ```py # components/calendar/calendar.py -from django_components import Component +from django_components import Component, register +@register("calendar") class Calendar(Component): template_file = "calendar.html" ``` @@ -56,8 +57,9 @@ document.querySelector(".calendar").onclick = () => { ```py # components/calendar/calendar.py -from django_components import Component +from django_components import Component, register +@register("calendar") class Calendar(Component): template_file = "calendar.html" js_file = "calendar.js" @@ -552,7 +554,7 @@ to see the latest features and fixes. One of our goals with `django-components` is to make it easy to share components between projects. If you have a set of components that you think would be useful to others, please open a pull request to add them to the list below. -- [django-htmx-components](https://github.com/iwanalabs/django-htmx-components): A set of components for use with [htmx](https://htmx.org/). Try out the [live demo](https://dhc.iwanalabs.com/). +- [django-htmx-components](https://github.com/iwanalabs/django-htmx-components): A set of components for use with [htmx](https://htmx.org/). - [djc-heroicons](https://pypi.org/project/djc-heroicons/): A component that renders icons from [Heroicons.com](https://heroicons.com/). diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_first.json index 39721433..97e6d62b 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_first.json @@ -1 +1 @@ -[[1662, [52920320.0, 54566912.0]], [1672, [52350976.0, 54599680.0]], [1687, [52109312.0, 54779904.0]], [1691, [52899840.0, 54730752.0]], [1709, [52936704.0, 55009280.0]], [1726, [52379648.0, 54992896.0]], [1766, [53084160.0, 55382016.0]], [1770, [53047296.0, 55373824.0]], [1776, [52490240.0, 55361536.0]], [1801, [53153792.0, 55410688.0]]] \ No newline at end of file +[[1662, [52920320.0, 54566912.0]], [1672, [52350976.0, 54599680.0]], [1687, [52109312.0, 54779904.0]], [1691, [52899840.0, 54730752.0]], [1709, [52936704.0, 55009280.0]], [1726, [52379648.0, 54992896.0]], [1766, [53084160.0, 55382016.0]], [1770, [53047296.0, 55373824.0]], [1776, [52490240.0, 55361536.0]], [1801, [53153792.0, 55410688.0]], [1937, [52957184.0, 55177216.0]], [1960, [52932608.0, 55693312.0]], [1996, [53096448.0, 55484416.0]], [2029, [52715520.0, 56090624.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_subsequent.json index 6917a1b2..a16e0075 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, [53800960.0, 54734848.0]], [1672, [52289536.0, 55099392.0]], [1687, [52142080.0, 55255040.0]], [1691, [53796864.0, 55238656.0]], [1709, [53768192.0, 55455744.0]], [1726, [51998720.0, 55451648.0]], [1766, [53739520.0, 55812096.0]], [1770, [53948416.0, 55824384.0]], [1776, [52097024.0, 55791616.0]], [1801, [53919744.0, 55799808.0]]] \ No newline at end of file +[[1662, [53800960.0, 54734848.0]], [1672, [52289536.0, 55099392.0]], [1687, [52142080.0, 55255040.0]], [1691, [53796864.0, 55238656.0]], [1709, [53768192.0, 55455744.0]], [1726, [51998720.0, 55451648.0]], [1766, [53739520.0, 55812096.0]], [1770, [53948416.0, 55824384.0]], [1776, [52097024.0, 55791616.0]], [1801, [53919744.0, 55799808.0]], [1937, [52822016.0, 56242176.0]], [1960, [53063680.0, 56180736.0]], [1996, [53018624.0, 56389632.0]], [2029, [52736000.0, 56791040.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_first.json index 9e1592de..6f16f68b 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_first.json @@ -1 +1 @@ -[[1662, [44191744.0, 44191744.0]], [1672, [44056576.0, 44048384.0]], [1687, [44191744.0, 44310528.0]], [1691, [44183552.0, 44175360.0]], [1709, [44191744.0, 44314624.0]], [1726, [44195840.0, 44314624.0]], [1766, [44322816.0, 44314624.0]], [1770, [44326912.0, 44322816.0]], [1776, [44183552.0, 44306432.0]], [1801, [44195840.0, 44453888.0]]] \ No newline at end of file +[[1662, [44191744.0, 44191744.0]], [1672, [44056576.0, 44048384.0]], [1687, [44191744.0, 44310528.0]], [1691, [44183552.0, 44175360.0]], [1709, [44191744.0, 44314624.0]], [1726, [44195840.0, 44314624.0]], [1766, [44322816.0, 44314624.0]], [1770, [44326912.0, 44322816.0]], [1776, [44183552.0, 44306432.0]], [1801, [44195840.0, 44453888.0]], [1937, [44756992.0, 44744704.0]], [1960, [44716032.0, 44834816.0]], [1996, [44716032.0, 44969984.0]], [2029, [44871680.0, 44912640.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_subsequent.json index c47dcd11..76bd2928 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.peakmem_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, [44195840.0, 44187648.0]], [1672, [44060672.0, 43917312.0]], [1687, [44105728.0, 44310528.0]], [1691, [44187648.0, 44183552.0]], [1709, [44191744.0, 44437504.0]], [1726, [44322816.0, 44314624.0]], [1766, [44322816.0, 44310528.0]], [1770, [44101632.0, 44310528.0]], [1776, [44314624.0, 44437504.0]], [1801, [44191744.0, 44453888.0]]] \ No newline at end of file +[[1662, [44195840.0, 44187648.0]], [1672, [44060672.0, 43917312.0]], [1687, [44105728.0, 44310528.0]], [1691, [44187648.0, 44183552.0]], [1709, [44191744.0, 44437504.0]], [1726, [44322816.0, 44314624.0]], [1766, [44322816.0, 44310528.0]], [1770, [44101632.0, 44310528.0]], [1776, [44314624.0, 44437504.0]], [1801, [44191744.0, 44453888.0]], [1937, [44527616.0, 44744704.0]], [1960, [44716032.0, 44838912.0]], [1996, [44724224.0, 44969984.0]], [2029, [44617728.0, 44986368.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_first.json index 57e279e2..e53588c7 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_first.json @@ -1 +1 @@ -[[1662, [0.06960565700001098, 0.25608221199996706]], [1672, [0.07114163800000028, 0.26389872900000455]], [1687, [0.06910802600003763, 0.25746033199999374]], [1691, [0.07048037500001669, 0.2598985070000026]], [1709, [0.07402671400001282, 0.26584690599997884]], [1726, [0.07297276199997782, 0.2569234329999972]], [1766, [0.07308550800001967, 0.26274096600002395]], [1770, [0.0749189080000292, 0.26436952000000247]], [1776, [0.07303507899999317, 0.2628890319999755]], [1801, [0.07360306399999672, 0.2678246009999725]]] \ No newline at end of file +[[1662, [0.06960565700001098, 0.25608221199996706]], [1672, [0.07114163800000028, 0.26389872900000455]], [1687, [0.06910802600003763, 0.25746033199999374]], [1691, [0.07048037500001669, 0.2598985070000026]], [1709, [0.07402671400001282, 0.26584690599997884]], [1726, [0.07297276199997782, 0.2569234329999972]], [1766, [0.07308550800001967, 0.26274096600002395]], [1770, [0.0749189080000292, 0.26436952000000247]], [1776, [0.07303507899999317, 0.2628890319999755]], [1801, [0.07360306399999672, 0.2678246009999725]], [1937, [0.07941284200001064, 0.26779402600004687]], [1960, [0.08026317200000221, 0.26819844099998136]], [1996, [0.0814841690000776, 0.28364495499999975]], [2029, [0.08105427499998541, 0.29477426600001877]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_subsequent.json index 2af46910..72d384fe 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, [0.03327357099999517, 0.1421111020000012]], [1672, [0.033918617999972867, 0.14395761299999776]], [1687, [0.03317536700001256, 0.14245594600001255]], [1691, [0.034316510999985894, 0.1444248799999741]], [1709, [0.03742426899998463, 0.14901454800002512]], [1726, [0.03658580800001232, 0.1459621130000528]], [1766, [0.03723830100000214, 0.15196534300002895]], [1770, [0.03752758399997447, 0.15356457899997622]], [1776, [0.03678920999999491, 0.14955294699998944]], [1801, [0.037022983000014165, 0.15138703899998518]]] \ No newline at end of file +[[1662, [0.03327357099999517, 0.1421111020000012]], [1672, [0.033918617999972867, 0.14395761299999776]], [1687, [0.03317536700001256, 0.14245594600001255]], [1691, [0.034316510999985894, 0.1444248799999741]], [1709, [0.03742426899998463, 0.14901454800002512]], [1726, [0.03658580800001232, 0.1459621130000528]], [1766, [0.03723830100000214, 0.15196534300002895]], [1770, [0.03752758399997447, 0.15356457899997622]], [1776, [0.03678920999999491, 0.14955294699998944]], [1801, [0.037022983000014165, 0.15138703899998518]], [1937, [0.043317416999911984, 0.15457556900003055]], [1960, [0.04349111400000538, 0.15453611999998884]], [1996, [0.04362213900003553, 0.16551773399999092]], [2029, [0.043648402000002307, 0.17461173199995983]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_first.json index b433e0c9..ffd21cc0 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_first.json @@ -1 +1 @@ -[[1662, [0.0035443229999998493, 0.00467639600003622]], [1672, [0.0036137869999777195, 0.004807943000002979]], [1687, [0.0035223549999727766, 0.004706463999980315]], [1691, [0.00364059099999281, 0.004926952999994683]], [1709, [0.003602947999979733, 0.004853936999950292]], [1726, [0.0035008030000085455, 0.004695608999981005]], [1766, [0.003566315000000486, 0.004791812000007667]], [1770, [0.0036766670000361046, 0.004929383999979109]], [1776, [0.0035613420000117912, 0.004760385999986738]], [1801, [0.003639607999986083, 0.004848561000017071]]] \ No newline at end of file +[[1662, [0.0035443229999998493, 0.00467639600003622]], [1672, [0.0036137869999777195, 0.004807943000002979]], [1687, [0.0035223549999727766, 0.004706463999980315]], [1691, [0.00364059099999281, 0.004926952999994683]], [1709, [0.003602947999979733, 0.004853936999950292]], [1726, [0.0035008030000085455, 0.004695608999981005]], [1766, [0.003566315000000486, 0.004791812000007667]], [1770, [0.0036766670000361046, 0.004929383999979109]], [1776, [0.0035613420000117912, 0.004760385999986738]], [1801, [0.003639607999986083, 0.004848561000017071]], [1937, [0.0036632869999948525, 0.00493345400002454]], [1960, [0.0036145729999930154, 0.004811176000004025]], [1996, [0.00375721499995052, 0.0049729269999261305]], [2029, [0.0037106409999978496, 0.004899473999955717]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_subsequent.json index f8d1736a..7e2dcfd6 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, [0.00010400499999718704, 0.0005328339999977061]], [1672, [0.00010086800000408402, 0.0005549249999887707]], [1687, [9.818199998790078e-05, 0.0005511469999817109]], [1691, [0.0001005780000014056, 0.0005555879999974422]], [1709, [0.00012266099997759738, 0.0005711430000019391]], [1726, [0.00011641800000461444, 0.0005489540000098714]], [1766, [0.00011609900002440554, 0.0005779780000239043]], [1770, [0.0001176700000087294, 0.0005864990000077341]], [1776, [0.00011622699999236374, 0.0005842630000074678]], [1801, [0.00011665800002447213, 0.000582710000003317]]] \ No newline at end of file +[[1662, [0.00010400499999718704, 0.0005328339999977061]], [1672, [0.00010086800000408402, 0.0005549249999887707]], [1687, [9.818199998790078e-05, 0.0005511469999817109]], [1691, [0.0001005780000014056, 0.0005555879999974422]], [1709, [0.00012266099997759738, 0.0005711430000019391]], [1726, [0.00011641800000461444, 0.0005489540000098714]], [1766, [0.00011609900002440554, 0.0005779780000239043]], [1770, [0.0001176700000087294, 0.0005864990000077341]], [1776, [0.00011622699999236374, 0.0005842630000074678]], [1801, [0.00011665800002447213, 0.000582710000003317]], [1937, [0.00012153600005149201, 0.0005999570000199128]], [1960, [0.00012332000000014887, 0.0005915369999911491]], [1996, [0.00012686900004155177, 0.0006182140000419167]], [2029, [0.00012706900002967814, 0.0006100459999629493]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_startup_lg.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_startup_lg.json index 12a9f8f8..028b02cc 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_startup_lg.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_startup_lg.json @@ -1 +1 @@ -[[1662, [0.21775109000003567, 0.21398552899995593]], [1672, [0.22476057199997967, 0.22048105400000395]], [1687, [0.21809406599999193, 0.2131839880000257]], [1691, [0.22356123500000535, 0.22167734499998915]], [1709, [0.22133603999998286, 0.21805855799999563]], [1726, [0.2166100470000174, 0.21420494400001644]], [1766, [0.22339861599999722, 0.22020213500002228]], [1770, [0.22985272800002576, 0.22544496099999378]], [1776, [0.22073260000001937, 0.2182690520000392]], [1801, [0.224061646999985, 0.2246476189999953]]] \ No newline at end of file +[[1662, [0.21775109000003567, 0.21398552899995593]], [1672, [0.22476057199997967, 0.22048105400000395]], [1687, [0.21809406599999193, 0.2131839880000257]], [1691, [0.22356123500000535, 0.22167734499998915]], [1709, [0.22133603999998286, 0.21805855799999563]], [1726, [0.2166100470000174, 0.21420494400001644]], [1766, [0.22339861599999722, 0.22020213500002228]], [1770, [0.22985272800002576, 0.22544496099999378]], [1776, [0.22073260000001937, 0.2182690520000392]], [1801, [0.224061646999985, 0.2246476189999953]], [1937, [0.22743783699991127, 0.226070988999993]], [1960, [0.2252378419999843, 0.2247263650000093]], [1996, [0.23076480500003527, 0.23163660399995933]], [2029, [0.22799248500001568, 0.22723498599998493]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Other.timeraw_import_time.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Other.timeraw_import_time.json index 3c9dc75e..eb01068a 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Other.timeraw_import_time.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Other.timeraw_import_time.json @@ -1 +1 @@ -[[1662, 0.19832900800003017], [1672, 0.20217585500000723], [1687, 0.19726691500000015], [1691, 0.20350580199999513], [1709, 0.19950735400001918], [1726, 0.19625152499997967], [1766, 0.20073733000003813], [1770, 0.20376683500001036], [1776, 0.19919827600000417], [1801, 0.2053688209999791]] \ No newline at end of file +[[1662, 0.19832900800003017], [1672, 0.20217585500000723], [1687, 0.19726691500000015], [1691, 0.20350580199999513], [1709, 0.19950735400001918], [1726, 0.19625152499997967], [1766, 0.20073733000003813], [1770, 0.20376683500001036], [1776, 0.19919827600000417], [1801, 0.2053688209999791], [1937, 0.2063091950000171], [1960, 0.20468290799999522], [1996, 0.21042045099989082], [2029, 0.2056691309999792]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_first.json index 0fa6a923..e5e24d49 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_first.json @@ -1 +1 @@ -[[1662, [54439936.0, 53968896.0]], [1672, [54616064.0, 54140928.0]], [1687, [54767616.0, 54296576.0]], [1691, [54743040.0, 54087680.0]], [1709, [55001088.0, 54312960.0]], [1726, [54992896.0, 54345728.0]], [1766, [55373824.0, 54894592.0]], [1770, [55246848.0, 54898688.0]], [1776, [55357440.0, 54874112.0]], [1801, [55382016.0, 54882304.0]]] \ No newline at end of file +[[1662, [54439936.0, 53968896.0]], [1672, [54616064.0, 54140928.0]], [1687, [54767616.0, 54296576.0]], [1691, [54743040.0, 54087680.0]], [1709, [55001088.0, 54312960.0]], [1726, [54992896.0, 54345728.0]], [1766, [55373824.0, 54894592.0]], [1770, [55246848.0, 54898688.0]], [1776, [55357440.0, 54874112.0]], [1801, [55382016.0, 54882304.0]], [1937, [55222272.0, 54722560.0]], [1960, [55263232.0, 54693888.0]], [1996, [55476224.0, 54968320.0]], [2029, [56090624.0, 55582720.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_subsequent.json index 20615ac5..0606c7d9 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, [54968320.0, 54792192.0]], [1672, [54849536.0, 54841344.0]], [1687, [55271424.0, 55304192.0]], [1691, [54984704.0, 54964224.0]], [1709, [55439360.0, 55369728.0]], [1726, [55455744.0, 55177216.0]], [1766, [55545856.0, 55631872.0]], [1770, [55812096.0, 55611392.0]], [1776, [55640064.0, 55631872.0]], [1801, [55812096.0, 55902208.0]]] \ No newline at end of file +[[1662, [54968320.0, 54792192.0]], [1672, [54849536.0, 54841344.0]], [1687, [55271424.0, 55304192.0]], [1691, [54984704.0, 54964224.0]], [1709, [55439360.0, 55369728.0]], [1726, [55455744.0, 55177216.0]], [1766, [55545856.0, 55631872.0]], [1770, [55812096.0, 55611392.0]], [1776, [55640064.0, 55631872.0]], [1801, [55812096.0, 55902208.0]], [1937, [56008704.0, 56143872.0]], [1960, [55783424.0, 56160256.0]], [1996, [56352768.0, 56516608.0]], [2029, [56786944.0, 56778752.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_first.json index 583828bf..bdcfccea 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_first.json @@ -1 +1 @@ -[[1662, [44187648.0, 44183552.0]], [1672, [44048384.0, 44048384.0]], [1687, [44314624.0, 44310528.0]], [1691, [44179456.0, 44175360.0]], [1709, [44314624.0, 44310528.0]], [1726, [44314624.0, 44314624.0]], [1766, [44318720.0, 44314624.0]], [1770, [44322816.0, 44314624.0]], [1776, [44306432.0, 44240896.0]], [1801, [44453888.0, 44453888.0]]] \ No newline at end of file +[[1662, [44187648.0, 44183552.0]], [1672, [44048384.0, 44048384.0]], [1687, [44314624.0, 44310528.0]], [1691, [44179456.0, 44175360.0]], [1709, [44314624.0, 44310528.0]], [1726, [44314624.0, 44314624.0]], [1766, [44318720.0, 44314624.0]], [1770, [44322816.0, 44314624.0]], [1776, [44306432.0, 44240896.0]], [1801, [44453888.0, 44453888.0]], [1937, [44744704.0, 44744704.0]], [1960, [44838912.0, 44838912.0]], [1996, [44969984.0, 44969984.0]], [2029, [44843008.0, 44851200.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_subsequent.json index dad71c83..e93df054 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.peakmem_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, [44187648.0, 44187648.0]], [1672, [44052480.0, 44052480.0]], [1687, [44314624.0, 44310528.0]], [1691, [44179456.0, 44179456.0]], [1709, [44310528.0, 44314624.0]], [1726, [44314624.0, 44314624.0]], [1766, [44310528.0, 44314624.0]], [1770, [44314624.0, 44318720.0]], [1776, [44437504.0, 44437504.0]], [1801, [44449792.0, 44449792.0]]] \ No newline at end of file +[[1662, [44187648.0, 44187648.0]], [1672, [44052480.0, 44052480.0]], [1687, [44314624.0, 44310528.0]], [1691, [44179456.0, 44179456.0]], [1709, [44310528.0, 44314624.0]], [1726, [44314624.0, 44314624.0]], [1766, [44310528.0, 44314624.0]], [1770, [44314624.0, 44318720.0]], [1776, [44437504.0, 44437504.0]], [1801, [44449792.0, 44449792.0]], [1937, [44744704.0, 44744704.0]], [1960, [44965888.0, 44834816.0]], [1996, [44974080.0, 44974080.0]], [2029, [44982272.0, 44986368.0]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_first.json index d7dc1632..47b453a9 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_first.json @@ -1 +1 @@ -[[1662, [0.2574955810000006, 0.2591010970000127]], [1672, [0.2600247560000071, 0.26185358800000813]], [1687, [0.2567828300000201, 0.2602957870000182]], [1691, [0.259077934000004, 0.2619792840000059]], [1709, [0.2646600410000133, 0.2676605120000204]], [1726, [0.2570519909999689, 0.2606809000000112]], [1766, [0.262679922000018, 0.2686107789999994]], [1770, [0.265977821000007, 0.26914772099999595]], [1776, [0.2626667089999728, 0.2663110299999971]], [1801, [0.2658582709999848, 0.2712929850000023]]] \ No newline at end of file +[[1662, [0.2574955810000006, 0.2591010970000127]], [1672, [0.2600247560000071, 0.26185358800000813]], [1687, [0.2567828300000201, 0.2602957870000182]], [1691, [0.259077934000004, 0.2619792840000059]], [1709, [0.2646600410000133, 0.2676605120000204]], [1726, [0.2570519909999689, 0.2606809000000112]], [1766, [0.262679922000018, 0.2686107789999994]], [1770, [0.265977821000007, 0.26914772099999595]], [1776, [0.2626667089999728, 0.2663110299999971]], [1801, [0.2658582709999848, 0.2712929850000023]], [1937, [0.2675778039999841, 0.2724974679999832]], [1960, [0.26819597400000816, 0.2740507329999957]], [1996, [0.2794132599999557, 0.28440619299999526]], [2029, [0.2920349000000044, 0.2976166970000236]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_subsequent.json index fc2abbd2..2c7b894a 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, [0.14273938200000202, 0.1464969190000147]], [1672, [0.14515931700000806, 0.14909453600000688]], [1687, [0.1423055980000072, 0.14642362500001127]], [1691, [0.1436571560000175, 0.14915657599999577]], [1709, [0.14860135300000366, 0.15305296299999327]], [1726, [0.14520097999997006, 0.14991973799999414]], [1766, [0.15071133700001837, 0.15540660900001058]], [1770, [0.15150350199996865, 0.1558047899999906]], [1776, [0.14876902899999322, 0.15549233400000162]], [1801, [0.15248822700002052, 0.15465820200000735]]] \ No newline at end of file +[[1662, [0.14273938200000202, 0.1464969190000147]], [1672, [0.14515931700000806, 0.14909453600000688]], [1687, [0.1423055980000072, 0.14642362500001127]], [1691, [0.1436571560000175, 0.14915657599999577]], [1709, [0.14860135300000366, 0.15305296299999327]], [1726, [0.14520097999997006, 0.14991973799999414]], [1766, [0.15071133700001837, 0.15540660900001058]], [1770, [0.15150350199996865, 0.1558047899999906]], [1776, [0.14876902899999322, 0.15549233400000162]], [1801, [0.15248822700002052, 0.15465820200000735]], [1937, [0.15459265900005903, 0.15926110200007315]], [1960, [0.15396625699997912, 0.16023626799997714]], [1996, [0.16650312799993117, 0.17177308600003016]], [2029, [0.17414895399997476, 0.178393189000019]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_first.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_first.json index 8ad32812..36aecfd8 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_first.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_first.json @@ -1 +1 @@ -[[1662, [0.004720848000005162, 0.004705489000002672]], [1672, [0.004856270999994194, 0.00490694800001279]], [1687, [0.00473016699999107, 0.004734037999980956]], [1691, [0.004871503999993365, 0.0048899079999955575]], [1709, [0.0048215560000244295, 0.004858458999990489]], [1726, [0.004671787999996013, 0.004672599999992144]], [1766, [0.00478528000002143, 0.0047485900000197034]], [1770, [0.004901490999998259, 0.004895917999988342]], [1776, [0.00480728600001612, 0.00472804499997892]], [1801, [0.004847185000016907, 0.004857667999999649]]] \ No newline at end of file +[[1662, [0.004720848000005162, 0.004705489000002672]], [1672, [0.004856270999994194, 0.00490694800001279]], [1687, [0.00473016699999107, 0.004734037999980956]], [1691, [0.004871503999993365, 0.0048899079999955575]], [1709, [0.0048215560000244295, 0.004858458999990489]], [1726, [0.004671787999996013, 0.004672599999992144]], [1766, [0.00478528000002143, 0.0047485900000197034]], [1770, [0.004901490999998259, 0.004895917999988342]], [1776, [0.00480728600001612, 0.00472804499997892]], [1801, [0.004847185000016907, 0.004857667999999649]], [1937, [0.004923484000073586, 0.004925836999973399]], [1960, [0.004825538000005736, 0.0047952310000027865]], [1996, [0.005049280000093859, 0.004947880000145233]], [2029, [0.004897051999989799, 0.004863266000029398]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_subsequent.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_subsequent.json index 0034605f..a12a8dd8 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, [0.0005377129999999397, 0.0005395769999836375]], [1672, [0.000547750000009728, 0.0005677989999810507]], [1687, [0.0005471899999918151, 0.0005447550000212686]], [1691, [0.0005559489999882317, 0.0005480739999939033]], [1709, [0.0005736080000247057, 0.0005720849999875099]], [1726, [0.000542692999999872, 0.0005430530000012368]], [1766, [0.0005853119999983392, 0.000582014999963576]], [1770, [0.0005929909999622396, 0.000583071999983531]], [1776, [0.0005810670000130358, 0.000576186999978745]], [1801, [0.0005717709999828458, 0.0005785939999896073]]] \ No newline at end of file +[[1662, [0.0005377129999999397, 0.0005395769999836375]], [1672, [0.000547750000009728, 0.0005677989999810507]], [1687, [0.0005471899999918151, 0.0005447550000212686]], [1691, [0.0005559489999882317, 0.0005480739999939033]], [1709, [0.0005736080000247057, 0.0005720849999875099]], [1726, [0.000542692999999872, 0.0005430530000012368]], [1766, [0.0005853119999983392, 0.000582014999963576]], [1770, [0.0005929909999622396, 0.000583071999983531]], [1776, [0.0005810670000130358, 0.000576186999978745]], [1801, [0.0005717709999828458, 0.0005785939999896073]], [1937, [0.0005969709999362749, 0.0005864510000037626]], [1960, [0.0005953940000154034, 0.0005933700000468889]], [1996, [0.0006160310000495883, 0.0006166809999967882]], [2029, [0.0006159270000125616, 0.0006080119999865019]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_startup_lg.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_startup_lg.json index 2f2ec0b0..520c7cbf 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_startup_lg.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/isolated vs django modes.timeraw_startup_lg.json @@ -1 +1 @@ -[[1662, [0.21402431699999624, 0.21364062999998623]], [1672, [0.2221746719999942, 0.2222580240000127]], [1687, [0.2142312400000037, 0.21397752699999728]], [1691, [0.22129613300000983, 0.21942976399998315]], [1709, [0.2199001029999863, 0.22046102699999892]], [1726, [0.2147675530000015, 0.21506381099999317]], [1766, [0.22056839900000114, 0.21916191200000412]], [1770, [0.22394285699999728, 0.22330144500000415]], [1776, [0.21867883100003382, 0.21859779499999377]], [1801, [0.22378945699995256, 0.22211803700002974]]] \ No newline at end of file +[[1662, [0.21402431699999624, 0.21364062999998623]], [1672, [0.2221746719999942, 0.2222580240000127]], [1687, [0.2142312400000037, 0.21397752699999728]], [1691, [0.22129613300000983, 0.21942976399998315]], [1709, [0.2199001029999863, 0.22046102699999892]], [1726, [0.2147675530000015, 0.21506381099999317]], [1766, [0.22056839900000114, 0.21916191200000412]], [1770, [0.22394285699999728, 0.22330144500000415]], [1776, [0.21867883100003382, 0.21859779499999377]], [1801, [0.22378945699995256, 0.22211803700002974]], [1937, [0.22545313400001987, 0.22602228000005198]], [1960, [0.22564571399999522, 0.22598634599995648]], [1996, [0.2295973340000046, 0.23030742100002044]], [2029, [0.22777395400004252, 0.2292747939999913]]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/summary.json b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/summary.json index e1eaa8c6..5cfe9e2e 100644 --- a/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/summary.json +++ b/docs/benchmarks/graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/summary.json @@ -1 +1 @@ -[{"name": "Components vs Django.peakmem_render_lg_first", "idx": 0, "pretty_name": "render - large - first render (mem)('django')", "last_rev": 1801, "last_value": 52910080.0, "last_err": 291225.6, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_lg_first", "idx": 1, "pretty_name": "render - large - first render (mem)('django-components')", "last_rev": 1801, "last_value": 55001088.0, "last_err": 286720.0, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render (mem)('django')", "last_rev": 1801, "last_value": 53753856.0, "last_err": 696729.6, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render (mem)('django-components')", "last_rev": 1801, "last_value": 55453696.0, "last_err": 290406.4, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_sm_first", "idx": 0, "pretty_name": "render - small - first render (mem)('django')", "last_rev": 1801, "last_value": 44191744.0, "last_err": 42598.4, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_sm_first", "idx": 1, "pretty_name": "render - small - first render (mem)('django-components')", "last_rev": 1801, "last_value": 44453888.0, "last_err": 0.0, "prev_value": 44306432.0, "change_rev": [1776, 1801]}, {"name": "Components vs Django.peakmem_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render (mem)('django')", "last_rev": 1801, "last_value": 44191744.0, "last_err": 70041.6, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render (mem)('django-components')", "last_rev": 1801, "last_value": 44310528.0, "last_err": 104448.0, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_lg_first", "idx": 0, "pretty_name": "render - large - first render('django')", "last_rev": 1801, "last_value": 0.07303507899999317, "last_err": 0.0015079635926781693, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_lg_first", "idx": 1, "pretty_name": "render - large - first render('django-components')", "last_rev": 1801, "last_value": 0.26274096600002395, "last_err": 0.0030797882742699726, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render('django')", "last_rev": 1801, "last_value": 0.03723830100000214, "last_err": 0.00030398760529811336, "prev_value": 0.03327357099999517, "change_rev": [1691, 1709]}, {"name": "Components vs Django.timeraw_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render('django-components')", "last_rev": 1801, "last_value": 0.14901454800002512, "last_err": 0.0034185043586025974, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_sm_first", "idx": 0, "pretty_name": "render - small - first render('django')", "last_rev": 1801, "last_value": 0.0035613420000117912, "last_err": 4.282955140889142e-05, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_sm_first", "idx": 1, "pretty_name": "render - small - first render('django-components')", "last_rev": 1801, "last_value": 0.004791812000007667, "last_err": 7.393313127925657e-05, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render('django')", "last_rev": 1801, "last_value": 0.00011641800000461444, "last_err": 1.0240076479630366e-06, "prev_value": 0.0001005780000014056, "change_rev": [1691, 1709]}, {"name": "Components vs Django.timeraw_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render('django-components')", "last_rev": 1801, "last_value": 0.0005549249999887707, "last_err": 1.689840424952132e-05, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_startup_lg", "idx": 0, "pretty_name": "startup - large('django')", "last_rev": 1801, "last_value": 0.22073260000001937, "last_err": 0.0033423623770026715, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_startup_lg", "idx": 1, "pretty_name": "startup - large('django-components')", "last_rev": 1801, "last_value": 0.2182690520000392, "last_err": 0.0038591938736867977, "prev_value": null, "change_rev": null}, {"name": "Other.timeraw_import_time", "idx": null, "pretty_name": "import time", "last_rev": 1801, "last_value": 0.19919827600000417, "last_err": 0.0030941523965093633, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_first", "idx": 0, "pretty_name": "render - large - first render (mem)('isolated')", "last_rev": 1801, "last_value": 54996992.0, "last_err": 280166.4, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_first", "idx": 1, "pretty_name": "render - large - first render (mem)('django')", "last_rev": 1801, "last_value": 54329344.0, "last_err": 308838.4, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render (mem)('isolated')", "last_rev": 1801, "last_value": 55447552.0, "last_err": 275251.2, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render (mem)('django')", "last_rev": 1801, "last_value": 55336960.0, "last_err": 306790.4, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_first", "idx": 0, "pretty_name": "render - small - first render (mem)('isolated')", "last_rev": 1801, "last_value": 44314624.0, "last_err": 68812.8, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_first", "idx": 1, "pretty_name": "render - small - first render (mem)('django')", "last_rev": 1801, "last_value": 44310528.0, "last_err": 74956.8, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render (mem)('isolated')", "last_rev": 1801, "last_value": 44312576.0, "last_err": 79052.8, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render (mem)('django')", "last_rev": 1801, "last_value": 44314624.0, "last_err": 79052.8, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_first", "idx": 0, "pretty_name": "render - large - first render('isolated')", "last_rev": 1801, "last_value": 0.2600247560000071, "last_err": 0.0032147405172077217, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_first", "idx": 1, "pretty_name": "render - large - first render('django')", "last_rev": 1801, "last_value": 0.2619792840000059, "last_err": 0.003903341080694231, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render('isolated')", "last_rev": 1801, "last_value": 0.14520097999997006, "last_err": 0.0033867810433681326, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render('django')", "last_rev": 1801, "last_value": 0.14991973799999414, "last_err": 0.0035610771318715317, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_first", "idx": 0, "pretty_name": "render - small - first render('isolated')", "last_rev": 1801, "last_value": 0.00480728600001612, "last_err": 5.8194676056223595e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_first", "idx": 1, "pretty_name": "render - small - first render('django')", "last_rev": 1801, "last_value": 0.0047485900000197034, "last_err": 6.830220604588864e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render('isolated')", "last_rev": 1801, "last_value": 0.0005559489999882317, "last_err": 1.5941242766015683e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render('django')", "last_rev": 1801, "last_value": 0.0005720849999875099, "last_err": 1.5267871206365328e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_startup_lg", "idx": 0, "pretty_name": "startup - large('isolated')", "last_rev": 1801, "last_value": 0.2199001029999863, "last_err": 0.003117201156386737, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_startup_lg", "idx": 1, "pretty_name": "startup - large('django')", "last_rev": 1801, "last_value": 0.21859779499999377, "last_err": 0.0030780461178069223, "prev_value": null, "change_rev": null}] \ No newline at end of file +[{"name": "Components vs Django.peakmem_render_lg_first", "idx": 0, "pretty_name": "render - large - first render (mem)('django')", "last_rev": 2029, "last_value": 52926464.0, "last_err": 238738.2857142857, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_lg_first", "idx": 1, "pretty_name": "render - large - first render (mem)('django-components')", "last_rev": 2029, "last_value": 55269376.0, "last_err": 352841.14285714284, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render (mem)('django')", "last_rev": 2029, "last_value": 53041152.0, "last_err": 638098.2857142857, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render (mem)('django-components')", "last_rev": 2029, "last_value": 55795712.0, "last_err": 429494.85714285716, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_sm_first", "idx": 0, "pretty_name": "render - small - first render (mem)('django')", "last_rev": 2029, "last_value": 44195840.0, "last_err": 193682.2857142857, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_sm_first", "idx": 1, "pretty_name": "render - small - first render (mem)('django-components')", "last_rev": 2029, "last_value": 44314624.0, "last_err": 206555.42857142858, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render (mem)('django')", "last_rev": 2029, "last_value": 44255232.0, "last_err": 179346.2857142857, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.peakmem_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render (mem)('django-components')", "last_rev": 2029, "last_value": 44376064.0, "last_err": 238153.14285714287, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_lg_first", "idx": 0, "pretty_name": "render - large - first render('django')", "last_rev": 2029, "last_value": 0.07308550800001967, "last_err": 0.002970056988688463, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_lg_first", "idx": 1, "pretty_name": "render - large - first render('django-components')", "last_rev": 2029, "last_value": 0.26436952000000247, "last_err": 0.005644097774403133, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render('django')", "last_rev": 2029, "last_value": 0.04362213900003553, "last_err": 0.00010141391999156615, "prev_value": 0.03723830100000214, "change_rev": [1801, 1937]}, {"name": "Components vs Django.timeraw_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render('django-components')", "last_rev": 2029, "last_value": 0.15138703899998518, "last_err": 0.006705386360797588, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_sm_first", "idx": 0, "pretty_name": "render - small - first render('django')", "last_rev": 2029, "last_value": 0.003602947999979733, "last_err": 5.419141048740966e-05, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_sm_first", "idx": 1, "pretty_name": "render - small - first render('django-components')", "last_rev": 2029, "last_value": 0.004811176000004025, "last_err": 7.476107336392598e-05, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render('django')", "last_rev": 2029, "last_value": 0.00011641800000461444, "last_err": 6.71568788300834e-06, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render('django-components')", "last_rev": 2029, "last_value": 0.0005711430000019391, "last_err": 2.3656907602254418e-05, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_startup_lg", "idx": 0, "pretty_name": "startup - large('django')", "last_rev": 2029, "last_value": 0.22356123500000535, "last_err": 0.003663370721264278, "prev_value": null, "change_rev": null}, {"name": "Components vs Django.timeraw_startup_lg", "idx": 1, "pretty_name": "startup - large('django-components')", "last_rev": 2029, "last_value": 0.22048105400000395, "last_err": 0.005292030830577897, "prev_value": null, "change_rev": null}, {"name": "Other.timeraw_import_time", "idx": null, "pretty_name": "import time", "last_rev": 2029, "last_value": 0.19919827600000417, "last_err": 0.0040859881894921846, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_first", "idx": 0, "pretty_name": "render - large - first render (mem)('isolated')", "last_rev": 2029, "last_value": 55234560.0, "last_err": 314806.85714285716, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_first", "idx": 1, "pretty_name": "render - large - first render (mem)('django')", "last_rev": 2029, "last_value": 54708224.0, "last_err": 355474.28571428574, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render (mem)('isolated')", "last_rev": 2029, "last_value": 55592960.0, "last_err": 405796.5714285714, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render (mem)('django')", "last_rev": 2029, "last_value": 55621632.0, "last_err": 478939.4285714286, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_first", "idx": 0, "pretty_name": "render - small - first render (mem)('isolated')", "last_rev": 2029, "last_value": 44316672.0, "last_err": 201874.2857142857, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_first", "idx": 1, "pretty_name": "render - small - first render (mem)('django')", "last_rev": 2029, "last_value": 44314624.0, "last_err": 207433.14285714287, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render (mem)('isolated')", "last_rev": 2029, "last_value": 44314624.0, "last_err": 228498.2857142857, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.peakmem_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render (mem)('django')", "last_rev": 2029, "last_value": 44316672.0, "last_err": 219428.57142857142, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_first", "idx": 0, "pretty_name": "render - large - first render('isolated')", "last_rev": 2029, "last_value": 0.2646600410000133, "last_err": 0.007677844017113229, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_first", "idx": 1, "pretty_name": "render - large - first render('django')", "last_rev": 2029, "last_value": 0.2676605120000204, "last_err": 0.00784939843762128, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_subsequent", "idx": 0, "pretty_name": "render - large - second render('isolated')", "last_rev": 2029, "last_value": 0.15071133700001837, "last_err": 0.006184059019873227, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_lg_subsequent", "idx": 1, "pretty_name": "render - large - second render('django')", "last_rev": 2029, "last_value": 0.15540660900001058, "last_err": 0.009898742429098032, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_first", "idx": 0, "pretty_name": "render - small - first render('isolated')", "last_rev": 2029, "last_value": 0.004825538000005736, "last_err": 5.909934210844408e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_first", "idx": 1, "pretty_name": "render - small - first render('django')", "last_rev": 2029, "last_value": 0.0047952310000027865, "last_err": 7.102011245001072e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_subsequent", "idx": 0, "pretty_name": "render - small - second render('isolated')", "last_rev": 2029, "last_value": 0.0005736080000247057, "last_err": 2.103986485491359e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_render_sm_subsequent", "idx": 1, "pretty_name": "render - small - second render('django')", "last_rev": 2029, "last_value": 0.000582014999963576, "last_err": 1.7671096085730627e-05, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_startup_lg", "idx": 0, "pretty_name": "startup - large('isolated')", "last_rev": 2029, "last_value": 0.22129613300000983, "last_err": 0.003939909589791106, "prev_value": null, "change_rev": null}, {"name": "isolated vs django modes.timeraw_startup_lg", "idx": 1, "pretty_name": "startup - large('django')", "last_rev": 2029, "last_value": 0.21916191200000412, "last_err": 0.00459183551388232, "prev_value": null, "change_rev": null}] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_first.json b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_first.json index f93d9312..9b9d166a 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_first.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_first.json @@ -1 +1 @@ -[[1662, 53737309.613078326], [1672, 53463506.59363525], [1687, 53427924.42970294], [1691, 53807508.99158667], [1709, 53963042.655257314], [1726, 53670369.245800875], [1766, 54220916.6140389], [1770, 54198077.75539557], [1776, 53906774.26269022], [1801, 54270509.344660625]] \ No newline at end of file +[[1662, 53737309.613078326], [1672, 53463506.59363525], [1687, 53427924.42970294], [1691, 53807508.99158667], [1709, 53963042.655257314], [1726, 53670369.245800875], [1766, 54220916.6140389], [1770, 54198077.75539557], [1776, 53906774.26269022], [1801, 54270509.344660625], [1937, 54055804.31664803], [1960, 54295416.494559616], [1996, 54277301.04707094], [2029, 54376892.25474807]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_subsequent.json b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_subsequent.json index e66c7875..16c667e1 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, 54265895.0709751], [1672, 53676080.7209516], [1687, 53675997.57883592], [1691, 54512993.537089705], [1709, 54605449.27839023], [1726, 53697436.790693834], [1766, 54766004.5031032], [1770, 54878384.55144014], [1776, 53912680.86221259], [1801, 54851721.60114168]] \ No newline at end of file +[[1662, 54265895.0709751], [1672, 53676080.7209516], [1687, 53675997.57883592], [1691, 54512993.537089705], [1709, 54605449.27839023], [1726, 53697436.790693834], [1766, 54766004.5031032], [1770, 54878384.55144014], [1776, 53912680.86221259], [1801, 54851721.60114168], [1937, 54505276.07990639], [1960, 54599968.83944605], [1996, 54678155.56971878], [2029, 54725974.50425164]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_first.json b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_first.json index ae819aef..b5b77f9d 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_first.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_first.json @@ -1 +1 @@ -[[1662, 44191743.99999999], [1672, 44052479.80957694], [1687, 44251096.14326895], [1691, 44179455.81012423], [1709, 44253141.3491094], [1726, 44255192.14695785], [1766, 44318719.81072088], [1770, 44324863.95268679], [1776, 44244949.34121254], [1801, 44324676.21343578]] \ No newline at end of file +[[1662, 44191743.99999999], [1672, 44052479.80957694], [1687, 44251096.14326895], [1691, 44179455.81012423], [1709, 44253141.3491094], [1726, 44255192.14695785], [1766, 44318719.81072088], [1770, 44324863.95268679], [1776, 44244949.34121254], [1801, 44324676.21343578], [1937, 44750847.578234404], [1960, 44775384.609963], [1996, 44842828.229087956], [2029, 44892155.328466915]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_subsequent.json b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_subsequent.json index d2dff9cf..764451a5 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.peakmem_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, 44191743.81017703], [1672, 43988933.59873213], [1687, 44208009.40445502], [1691, 44185599.95253766], [1709, 44314453.63272547], [1726, 44318719.81072088], [1766, 44316671.57410231], [1770, 44205956.60747199], [1776, 44376021.4672124], [1801, 44322622.19567646]] \ No newline at end of file +[[1662, 44191743.81017703], [1672, 43988933.59873213], [1687, 44208009.40445502], [1691, 44185599.95253766], [1709, 44314453.63272547], [1726, 44318719.81072088], [1766, 44316671.57410231], [1770, 44205956.60747199], [1776, 44376021.4672124], [1801, 44322622.19567646], [1937, 44636028.0238471], [1960, 44777429.84849827], [1996, 44846935.655543014], [2029, 44801668.84315699]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_first.json b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_first.json index e27dd178..d7a7b9c6 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_first.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_first.json @@ -1 +1 @@ -[[1662, 0.13350944016163727], [1672, 0.1370189324406613], [1687, 0.13338881256624893], [1691, 0.13534306127506], [1709, 0.14028461383291016], [1726, 0.1369248426273554], [1766, 0.13857329097819557], [1770, 0.14073477092350728], [1776, 0.1385645020210802], [1801, 0.14040196312080028]] \ No newline at end of file +[[1662, 0.13350944016163727], [1672, 0.1370189324406613], [1687, 0.13338881256624893], [1691, 0.13534306127506], [1709, 0.14028461383291016], [1726, 0.1369248426273554], [1766, 0.13857329097819557], [1770, 0.14073477092350728], [1776, 0.1385645020210802], [1801, 0.14040196312080028], [1937, 0.14582964264952603], [1960, 0.14671897491501892], [1996, 0.15202819951982394], [2029, 0.15457268328939747]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_subsequent.json b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_subsequent.json index 783555c7..807386ec 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, 0.0687644082522681], [1672, 0.06987734456556612], [1687, 0.06874611472573841], [1691, 0.07039998567606925], [1709, 0.07467771106069107], [1726, 0.07307627413528986], [1766, 0.0752258677863117], [1770, 0.07591381717343901], [1776, 0.0741750279629251], [1801, 0.07486521068773488]] \ No newline at end of file +[[1662, 0.0687644082522681], [1672, 0.06987734456556612], [1687, 0.06874611472573841], [1691, 0.07039998567606925], [1709, 0.07467771106069107], [1726, 0.07307627413528986], [1766, 0.0752258677863117], [1770, 0.07591381717343901], [1776, 0.0741750279629251], [1801, 0.07486521068773488], [1937, 0.08182795598310513], [1960, 0.08198138820511656], [1996, 0.08497198126158123], [2029, 0.08730133488241124]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_first.json b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_first.json index f5e8aacd..bd943ad3 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_first.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_first.json @@ -1 +1 @@ -[[1662, 0.004071198582731586], [1672, 0.004168318834979474], [1687, 0.004071589002161507], [1691, 0.004235212007582172], [1709, 0.004181923314217816], [1726, 0.004054429932062044], [1766, 0.004133897799028137], [1770, 0.004257194320585938], [1776, 0.004117446125697445], [1801, 0.004200816754404154]] \ No newline at end of file +[[1662, 0.004071198582731586], [1672, 0.004168318834979474], [1687, 0.004071589002161507], [1691, 0.004235212007582172], [1709, 0.004181923314217816], [1726, 0.004054429932062044], [1766, 0.004133897799028137], [1770, 0.004257194320585938], [1776, 0.004117446125697445], [1801, 0.004200816754404154], [1937, 0.004251194879485355], [1960, 0.0041701734817425696], [1996, 0.004322540447211732], [2029, 0.004263823296369016]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_subsequent.json b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_subsequent.json index fafee4ea..8d882c01 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, 0.00023540900613243872], [1672, 0.0002365886195511814], [1687, 0.0002326213978668684], [1691, 0.0002363893607261623], [1709, 0.0002646827752432008], [1726, 0.00025280056719810247], [1766, 0.00025904182642747317], [1770, 0.0002627038966898471], [1776, 0.00026058997620285855], [1801, 0.000260725493948419]] \ No newline at end of file +[[1662, 0.00023540900613243872], [1672, 0.0002365886195511814], [1687, 0.0002326213978668684], [1691, 0.0002363893607261623], [1709, 0.0002646827752432008], [1726, 0.00025280056719810247], [1766, 0.00025904182642747317], [1770, 0.0002627038966898471], [1776, 0.00026058997620285855], [1801, 0.000260725493948419], [1937, 0.0002700303204925571], [1960, 0.00027008950893915996], [1996, 0.0002800574798090668], [2029, 0.000278420428825539]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_startup_lg.json b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_startup_lg.json index 4ae2493b..a58dd726 100644 --- a/docs/benchmarks/graphs/summary/Components vs Django.timeraw_startup_lg.json +++ b/docs/benchmarks/graphs/summary/Components vs Django.timeraw_startup_lg.json @@ -1 +1 @@ -[[1662, 0.21586009863792485], [1672, 0.22261052942796597], [1687, 0.21562505130206716], [1691, 0.2226172972159168], [1709, 0.21969118716012626], [1726, 0.21540413874268913], [1766, 0.2217946171557135], [1770, 0.22763817627917332], [1776, 0.21949736979633283], [1801, 0.22435444169386096]] \ No newline at end of file +[[1662, 0.21586009863792485], [1672, 0.22261052942796597], [1687, 0.21562505130206716], [1691, 0.2226172972159168], [1709, 0.21969118716012626], [1726, 0.21540413874268913], [1766, 0.2217946171557135], [1770, 0.22763817627917332], [1776, 0.21949736979633283], [1801, 0.22435444169386096], [1937, 0.22675338309844276], [1960, 0.22498195815021013], [1996, 0.23120029358312028], [2029, 0.22761342037999505]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/Other.timeraw_import_time.json b/docs/benchmarks/graphs/summary/Other.timeraw_import_time.json index 3c9dc75e..eb01068a 100644 --- a/docs/benchmarks/graphs/summary/Other.timeraw_import_time.json +++ b/docs/benchmarks/graphs/summary/Other.timeraw_import_time.json @@ -1 +1 @@ -[[1662, 0.19832900800003017], [1672, 0.20217585500000723], [1687, 0.19726691500000015], [1691, 0.20350580199999513], [1709, 0.19950735400001918], [1726, 0.19625152499997967], [1766, 0.20073733000003813], [1770, 0.20376683500001036], [1776, 0.19919827600000417], [1801, 0.2053688209999791]] \ No newline at end of file +[[1662, 0.19832900800003017], [1672, 0.20217585500000723], [1687, 0.19726691500000015], [1691, 0.20350580199999513], [1709, 0.19950735400001918], [1726, 0.19625152499997967], [1766, 0.20073733000003813], [1770, 0.20376683500001036], [1776, 0.19919827600000417], [1801, 0.2053688209999791], [1937, 0.2063091950000171], [1960, 0.20468290799999522], [1996, 0.21042045099989082], [2029, 0.2056691309999792]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_first.json b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_first.json index 6bb13555..4429f303 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_first.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_first.json @@ -1 +1 @@ -[[1662, 54203904.32644733], [1672, 54377977.05567385], [1687, 54531587.401090905], [1691, 54414373.37457081], [1709, 54655941.05401974], [1726, 54668354.35558938], [1766, 55133687.30603648], [1770, 55072492.873806104], [1776, 55115246.19008138], [1801, 55131593.83007953]] \ No newline at end of file +[[1662, 54203904.32644733], [1672, 54377977.05567385], [1687, 54531587.401090905], [1691, 54414373.37457081], [1709, 54655941.05401974], [1726, 54668354.35558938], [1766, 55133687.30603648], [1770, 55072492.873806104], [1776, 55115246.19008138], [1801, 55131593.83007953], [1937, 54971848.18483294], [1960, 54977822.99733244], [1996, 55221688.06930552], [2029, 55836094.494666085]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_subsequent.json b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_subsequent.json index 4d7a2293..bed4ea23 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, 54880185.34368702], [1672, 54845439.84705003], [1687, 55287805.57238104], [1691, 54974463.04630629], [1709, 55404533.06087942], [1726, 55316304.695168346], [1766, 55588847.36277981], [1770, 55711653.6193069], [1776, 55635967.849223286], [1801, 55857133.82825839]] \ No newline at end of file +[[1662, 54880185.34368702], [1672, 54845439.84705003], [1687, 55287805.57238104], [1691, 54974463.04630629], [1709, 55404533.06087942], [1726, 55316304.695168346], [1766, 55588847.36277981], [1770, 55711653.6193069], [1776, 55635967.849223286], [1801, 55857133.82825839], [1937, 56076247.273349956], [1960, 55971522.87008585], [1996, 56434628.542863145], [2029, 56782847.85226863]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_first.json b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_first.json index 8d0b2b2e..d6903d84 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_first.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_first.json @@ -1 +1 @@ -[[1662, 44185599.95253766], [1672, 44048383.99999999], [1687, 44312575.95267366], [1691, 44177407.95252886], [1709, 44312575.95267366], [1726, 44314624.0], [1766, 44316671.95267803], [1770, 44318719.81072088], [1776, 44273651.87380721], [1801, 44453888.0]] \ No newline at end of file +[[1662, 44185599.95253766], [1672, 44048383.99999999], [1687, 44312575.95267366], [1691, 44177407.95252886], [1709, 44312575.95267366], [1726, 44314624.0], [1766, 44316671.95267803], [1770, 44318719.81072088], [1776, 44273651.87380721], [1801, 44453888.0], [1937, 44744704.0], [1960, 44838912.00000001], [1996, 44969983.99999999], [2029, 44847103.812950954]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_subsequent.json b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_subsequent.json index 0a514fe4..1f44ef9f 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.peakmem_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, 44187648.0], [1672, 44052479.99999999], [1687, 44312575.95267366], [1691, 44179455.99999999], [1709, 44312575.95267366], [1726, 44314624.0], [1766, 44312575.95267366], [1770, 44316671.95267803], [1776, 44437504.0], [1801, 44449792.0]] \ No newline at end of file +[[1662, 44187648.0], [1672, 44052479.99999999], [1687, 44312575.95267366], [1691, 44179455.99999999], [1709, 44312575.95267366], [1726, 44314624.0], [1766, 44312575.95267366], [1770, 44316671.95267803], [1776, 44437504.0], [1801, 44449792.0], [1937, 44744704.0], [1960, 44900304.17220587], [1996, 44974080.0], [2029, 44984319.953380376]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_first.json b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_first.json index ba1cfb26..58c7bd0b 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_first.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_first.json @@ -1 +1 @@ -[[1662, 0.2582970915627115], [1672, 0.2609375697890752], [1687, 0.2585333418012986], [1691, 0.2605245701455466], [1709, 0.26615604836262874], [1726, 0.25886008645727265], [1766, 0.2656287982807661], [1770, 0.2675580766089799], [1776, 0.2644825926606367], [1801, 0.26856188100049755]] \ No newline at end of file +[[1662, 0.2582970915627115], [1672, 0.2609375697890752], [1687, 0.2585333418012986], [1691, 0.2605245701455466], [1709, 0.26615604836262874], [1726, 0.25886008645727265], [1766, 0.2656287982807661], [1770, 0.2675580766089799], [1776, 0.2644825926606367], [1801, 0.26856188100049755], [1937, 0.2700264321932048], [1960, 0.2711075492537049], [1996, 0.28189867248766043], [2029, 0.29481258851469266]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_subsequent.json b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_subsequent.json index b4039ef7..56f4bd5d 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_subsequent.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_lg_subsequent.json @@ -1 +1 @@ -[[1662, 0.144605946222714], [1672, 0.14711376894836906], [1687, 0.14434992731884352], [1691, 0.14638104217028877], [1709, 0.1508107336447194], [1726, 0.14754149544768042], [1766, 0.15304096778650703], [1770, 0.1536390943522132], [1776, 0.15209353551720362], [1801, 0.15356938175949056]] \ No newline at end of file +[[1662, 0.144605946222714], [1672, 0.14711376894836906], [1687, 0.14434992731884352], [1691, 0.14638104217028877], [1709, 0.1508107336447194], [1726, 0.14754149544768042], [1766, 0.15304096778650703], [1770, 0.1536390943522132], [1776, 0.15209353551720362], [1801, 0.15356938175949056], [1937, 0.15690951925702573], [1960, 0.15706997937098616], [1996, 0.16911758076913888], [2029, 0.17625829701058932]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_first.json b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_first.json index 31d99ef0..5ba7c936 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_first.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_first.json @@ -1 +1 @@ -[[1662, 0.004713162243622524], [1672, 0.004881543738505435], [1687, 0.004732102104161917], [1691, 0.00488069732533968], [1709, 0.004839972328668506], [1726, 0.004672193982353972], [1766, 0.004766899700580667], [1770, 0.004898703707479391], [1776, 0.004767500868992566], [1801, 0.004852423669122516]] \ No newline at end of file +[[1662, 0.004713162243622524], [1672, 0.004881543738505435], [1687, 0.004732102104161917], [1691, 0.00488069732533968], [1709, 0.004839972328668506], [1726, 0.004672193982353972], [1766, 0.004766899700580667], [1770, 0.004898703707479391], [1776, 0.004767500868992566], [1801, 0.004852423669122516], [1937, 0.004924660359490744], [1960, 0.004810360631940079], [1996, 0.004998322871483767], [2029, 0.004880129761791827]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_subsequent.json b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_subsequent.json index f50d1376..dec783d0 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_subsequent.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_render_sm_subsequent.json @@ -1 +1 @@ -[[1662, 0.0005386441936864901], [1672, 0.0005576844109755481], [1687, 0.0005459711425132094], [1691, 0.0005519974567116778], [1709, 0.0005728459938648165], [1726, 0.0005428729701593198], [1766, 0.0005836611719634209], [1770, 0.0005880105852110292], [1776, 0.0005786218553806627], [1801, 0.0005751723828193878]] \ No newline at end of file +[[1662, 0.0005386441936864901], [1672, 0.0005576844109755481], [1687, 0.0005459711425132094], [1691, 0.0005519974567116778], [1709, 0.0005728459938648165], [1726, 0.0005428729701593198], [1766, 0.0005836611719634209], [1770, 0.0005880105852110292], [1776, 0.0005786218553806627], [1801, 0.0005751723828193878], [1937, 0.0005916876201898046], [1960, 0.000594381138510516], [1996, 0.0006163559143381376], [2029, 0.0006119567036345985]] \ No newline at end of file diff --git a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_startup_lg.json b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_startup_lg.json index e4dee048..2b8c756c 100644 --- a/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_startup_lg.json +++ b/docs/benchmarks/graphs/summary/isolated vs django modes.timeraw_startup_lg.json @@ -1 +1 @@ -[[1662, 0.21383238744211777], [1672, 0.22221634409189991], [1687, 0.21410434591886193], [1691, 0.2203609725843055], [1709, 0.22018038637622225], [1726, 0.2149156309515977], [1766, 0.2198640308272821], [1770, 0.22362192103085216], [1776, 0.21863830924562072], [1801, 0.22295218072522197]] \ No newline at end of file +[[1662, 0.21383238744211777], [1672, 0.22221634409189991], [1687, 0.21410434591886193], [1691, 0.2203609725843055], [1709, 0.22018038637622225], [1726, 0.2149156309515977], [1766, 0.2198640308272821], [1770, 0.22362192103085216], [1776, 0.21863830924562072], [1801, 0.22295218072522197], [1937, 0.22573752762853083], [1960, 0.22581596577171012], [1996, 0.22995210340856065], [2029, 0.2285231418957897]] \ No newline at end of file diff --git a/docs/benchmarks/index.json b/docs/benchmarks/index.json index 86c1d84f..d98e1855 100644 --- a/docs/benchmarks/index.json +++ b/docs/benchmarks/index.json @@ -1 +1 @@ -{"project": "django-components", "project_url": "/django-components/", "show_commit_url": "#", "hash_length": 8, "revision_to_hash": {"250": "45a18626d74b280aa05498aa380eba687010cc0f", "268": "c9f0068741871b24756045805aaab8fbf368601a", "343": "ed2cd57bdcc12bf390f42058061a6ed077e558b0", "359": "501a055fe21abb4c7ad9af1a3a1b42eea24afacf", "369": "1937d594100d0651b151c8edbe1189b5a88b358f", "380": "1d091f50999cca0fa8c7852da2ea71684eadda6d", "388": "f5c3f64c866d06dfa2435d1d18b936dddb9eb67c", "427": "24d9db39c3c55f5eb91c9ce2112ad22507ccdd60", "457": "9103eda2f4ed80f46ff03d215491009c5476b410", "487": "384ff79e0875ac3a64a2755010ef86ec09a090b5", "500": "c102019811586f40cb11952f283797ddee96de3c", "503": "a350ad1a869bb46c6bac093f54ac40ea85d8cd8f", "508": "16022429da16e459b8a1e6e9cd8ab41d95dcb59d", "536": "ea7beb518c435389d9daff7ea557eec9ddc2464e", "550": "2cfc7285e12677a54247e9998967081c0e031efc", "552": "fcbfae3c5f0611519636290ef99b25bc0a319825", "564": "316310e842f276fd43436b432781430bd255410b", "575": "e0a5c2a4bcf5e8f577e19333e3b719440c37b10b", "577": "c174aa9802cc73b5d8fef4b0c704de3fb68b1cbb", "598": "979781012532f18c147a570ff4441c65c7503b6f", "612": "9d7d0b40b9d3bbd8e5b754e3b1b20df982cdd184", "622": "24032ac2ea80627f0fdde88058a2c3fbcae0d3fe", "646": "4f1a8184465fc472995bc226bebd66c250d501f6", "651": "8ce649498ff63a64761c83cf713983b7e2f24b81", "663": "93facba53e050619a477fa214da89fccf118ec13", "675": "ea33e0db6c54486b67e2fa496ec1c3ec3de06ec7", "681": "6874b1531df0e8836000bbc76fcca5a3de42724a", "691": "9f4243232018708fdf330f0e922a09317c60234c", "704": "188a9dc7eef4c45ee4f87efa8a0d6728e94f210d", "724": "76a0cde3af7b3061127d149c138fbc78462a07fe", "729": "c932f28cb4840dc45d2d26b4d927c1480459272f", "742": "7058f05e0415965ddd162d0ba663c5106e7ffb66", "748": "95d6eacb5c03a611f92cd9a6e254cea7e0ce57eb", "752": "d512cfb0fec8a42ab58d2f106047fc4c0ec65427", "757": "04160f4e0b2ec4d901d6724c34ed8df883363064", "773": "20847b978b3ddb5979489fbb4bd8e971b9b16fbf", "775": "ae5cda9f727454a077ab16c51a237fec076bd442", "779": "cd791caa572c9acd6d56445c04d6c9b55a50c602", "787": "274be104789e31955f88e26f14c89ed648f25448", "806": "c3a80b729049b5ea1b4799e742e4100a7640efab", "845": "0abb5aa63ff0396328ef4dfdc2e78e872671f135", "855": "e4e787b29dc9cd2cf35ad02f22bad6fa15a7211c", "867": "e346c07298b268d9212fcf93d132968e69824730", "884": "2316f79dff66260b7a9fe91effb55c74524deca0", "887": "085c60a8c96442d9fd4f72d66a7eb295e7cfb2d9", "889": "ba86cee578490df944ad167674db32182b8bbf7b", "891": "dd292b03508b7c03b2ad4f9fb9c17dec747845ba", "898": "badffdda3538a8082137453c757509ed4f035a3e", "902": "c07f0e634121ced0119bb665ed544ca4447c416b", "904": "8bbe81d7171ec3512f250927653d8454c7ff005e", "908": "881c36219a45581086da35a17d3715ee0698ca88", "910": "9bfb50b8f27f7ff521226109ab30426633f6b514", "912": "3a7d5355cfa5d37641a4c80ee9fd2423cea10c1b", "930": "09a720009767f45bebcfa48f3587219c03082601", "935": "a4b4905bee778a51f9a99a042ce14ed2424cc9fb", "940": "31257a475dcfdacaaeb408f59ea92b736a668815", "942": "d47927054c820ecf3f9f97a62f03dfbb5496a11b", "956": "fbbbf6c694b8213832fc127ee8a3e31872308aff", "958": "d819f3ff491866abaeb9a7dbba6a6ca3c21da9f8", "960": "c202c5a901106392ccdde49100211182c986eca5", "965": "7bbfcf7565159d92de41bb0d738b7878d78f4533", "978": "b89c09aa5f13903b1d056c70afbfd327f0ed6362", "980": "03af25aad6841b6edb56c925d2599817e08ceb44", "982": "5cb649fae62a42e525c1ea9fb74d7838886cc1a8", "986": "f97717cdb35eaadb78b1f468728b1bd386e742d8", "1056": "b26a2011380c959bfc98043821f6b4aa337a281d", "1058": "8c5b088c31b7166932e18739f882c2eef632f3a4", "1060": "682bfc42397c0bdbeb1a2b6ccabb8aca89686d4f", "1089": "8f13a641ac096e93a0464f048a4fa53e591bb8db", "1098": "30d04fe1b053e6c5de0b6f34a7758a627517be8c", "1125": "f7846b9c0ae7a8fd0b7f6edf664316e485455e76", "1132": "a3d66586b19b7e2aacbf793edfba20bcd9858f4a", "1179": "0064de9c78db5eccc7c498e2a6d4c3c5ffa745ec", "1252": "d093bfb05212555e14c5cd46c94b0ba057cbeceb", "1270": "c0a4fd5f685d694218b583b2d0a3e8417925d53a", "1277": "2a4b0f52894d5d0bb8d325d6096a3950286db541", "1282": "5a23101038d7085959087b2352e71590eafe9529", "1287": "ce3305a5fff095e990707de851f85bc27120596c", "1312": "cdc830fca3bdd98669e0510841536be14d1bd728", "1328": "468a593a472c35379fe7567918e8a534b2d53748", "1337": "2f14e8e0908657459909c6338106e561edc5d0f4", "1352": "a5659691d0f947643ce6542b7f09075e3f931646", "1361": "aaeba99f54b206baed072ffd0572035ddf5118a7", "1366": "6813c9d7aa4acfb04df9665651a2864d04bbe8ba", "1381": "6681fc0085fdb4b76cb74c1bbf20d44fa22f40fe", "1387": "6bb73bd8afd350db84889efc09b74255cea08979", "1392": "c76f8198dd497b34735fc17a0f7a678bdd811a3f", "1447": "3bbd4326e6c1bfb4a02039e16021a3f720910308", "1488": "914576e68133bc6ec356f3918016c45691ed3534", "1505": "3d187d7abad80f8464bd70dfba847d27a8e173db", "1514": "e105500350a320dfccf36fc19cad7421d38c3736", "1546": "61515b34540d27311fc3286b50212c1e314ce39e", "1571": "691443a0a821eb1a02f9b42ad0e32bcd71d94943", "1591": "dcd4203eeadafc5d500b4b72c5cf04f1fe7317e7", "1662": "d0a42a2698f2ba21e7ab2dec750c5dbadeda0db5", "1672": "2037ed20b7252cc52008e69bdd3d8e095ad6ea08", "1687": "2472c2ad338a23fba015d4d9816cb62d1325455f", "1691": "42818ad6ffb47bd650d8a379b84c3d48394f9f77", "1709": "a6455d70f6c28ddbd4be8e58902f6cbc101e5ff3", "1726": "fdd29baa65e9ef78eb24a0ad2ca0b5d7c624dad3", "1766": "1319a95627493fc0745b5af0600af2dc8c5117f9", "1770": "07f747d70500bbe3e135725b0e1b102815ab9416", "1776": "ad402fc619922b6d2edf1e99b7082d2a58632076", "1801": "4c909486069f3c3c8ee7915239174f820f081da4"}, "revision_to_date": {"250": 1630912817000, "268": 1631273531000, "343": 1654029104000, "359": 1657786741000, "369": 1657798498000, "380": 1658057264000, "388": 1658128984000, "427": 1670931380000, "457": 1673095465000, "487": 1675977478000, "500": 1678833725000, "503": 1678834812000, "508": 1679329468000, "536": 1680808865000, "550": 1681214445000, "552": 1681388770000, "564": 1682351069000, "575": 1684433482000, "577": 1684760359000, "598": 1693734426000, "612": 1695996512000, "622": 1696883504000, "646": 1702127213000, "651": 1702852887000, "663": 1705268832000, "675": 1705701480000, "681": 1706343740000, "691": 1706393538000, "704": 1707467055000, "724": 1708588716000, "729": 1708984309000, "742": 1709796107000, "748": 1710542375000, "752": 1711216985000, "757": 1711278671000, "773": 1711752109000, "775": 1711786713000, "779": 1712212506000, "787": 1712872453000, "806": 1713128940000, "845": 1713390260000, "855": 1713901297000, "867": 1714590581000, "884": 1714912319000, "887": 1715087715000, "889": 1715111097000, "891": 1715505986000, "898": 1716105516000, "902": 1716441018000, "904": 1716488913000, "908": 1717051130000, "910": 1717227227000, "912": 1717232115000, "930": 1718176374000, "935": 1718991590000, "940": 1720427258000, "942": 1720429478000, "956": 1722279535000, "958": 1722325182000, "960": 1722666822000, "965": 1722890429000, "978": 1723843975000, "980": 1723993321000, "982": 1724243667000, "986": 1724363119000, "1056": 1724732902000, "1058": 1724824521000, "1060": 1724924003000, "1089": 1725480929000, "1098": 1725655525000, "1125": 1726084755000, "1132": 1726347108000, "1179": 1728564427000, "1252": 1732525062000, "1270": 1732629701000, "1277": 1732644681000, "1282": 1732658332000, "1287": 1732726640000, "1312": 1733164405000, "1328": 1733471329000, "1337": 1733644953000, "1352": 1733834654000, "1361": 1734080521000, "1366": 1734245122000, "1381": 1734464187000, "1387": 1734600366000, "1392": 1734955786000, "1447": 1736287315000, "1488": 1737558545000, "1505": 1738157680000, "1514": 1738404847000, "1546": 1738662755000, "1571": 1739736734000, "1591": 1740050674000, "1662": 1742502414000, "1672": 1742645505000, "1687": 1742720064000, "1691": 1742765538000, "1709": 1743430242000, "1726": 1743837055000, "1766": 1744204166000, "1770": 1744216267000, "1776": 1744443333000, "1801": 1745143092000}, "params": {"machine": ["ci-linux"], "python": ["3.13"], "django": ["5.1"], "djc-core-html-parser": [""], "branch": ["master"]}, "graph_param_list": [{"machine": "ci-linux", "python": "3.13", "django": "5.1", "djc-core-html-parser": "", "branch": "master"}], "benchmarks": {"Components vs Django.peakmem_render_lg_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - first render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"first\", \"isolated\"),\n )\n def peakmem_render_lg_first(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"first\", \"isolated\"),", "name": "Components vs Django.peakmem_render_lg_first", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "301c396f017f45a5b3f71e85df58d15f54153fcfd951af7ef424641d4b31b528"}, "Components vs Django.peakmem_render_lg_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - second render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"subsequent\", \"isolated\"),\n )\n def peakmem_render_lg_subsequent(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"subsequent\", \"isolated\"),", "name": "Components vs Django.peakmem_render_lg_subsequent", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "9a44e9999ef3ef42ea7e01323727490244febb43d66a87a4d8f88c6b8a133b8b"}, "Components vs Django.peakmem_render_sm_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - first render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"first\", \"isolated\"),\n )\n def peakmem_render_sm_first(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"first\", \"isolated\"),", "name": "Components vs Django.peakmem_render_sm_first", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "e93b7a5193681c883edf85bdb30b1bc0821263bf51033fdcee215b155085e036"}, "Components vs Django.peakmem_render_sm_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - second render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"subsequent\", \"isolated\"),\n )\n def peakmem_render_sm_subsequent(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"subsequent\", \"isolated\"),", "name": "Components vs Django.peakmem_render_sm_subsequent", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "b46e0820b18950aa7cc5e61306ff3425b76b4da9dca42d64fae5b1d25c6c9026"}, "Components vs Django.timeraw_render_lg_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - first render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n include_in_quick_benchmark=True,\n )\n def timeraw_render_lg_first(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"lg\", \"first\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_lg_first", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "be3bf6236960046a028b6ea007aad28b2337fc2b906b8ce317a09a5d4f1a6193", "warmup_time": -1}, "Components vs Django.timeraw_render_lg_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - second render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_render_lg_subsequent(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"lg\", \"subsequent\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_lg_subsequent", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "b98221c11a0ee6e9de0778d416d31b9dd514a674d9017a2bb9b2fc1cd0f01920", "warmup_time": -1}, "Components vs Django.timeraw_render_sm_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - first render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_render_sm_first(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"sm\", \"first\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_sm_first", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "f1fc17e4a31c71f4d9265f1122da52e7cf57addb4dfa02606e303b33d6431b9b", "warmup_time": -1}, "Components vs Django.timeraw_render_sm_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - second render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_render_sm_subsequent(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"sm\", \"subsequent\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_sm_subsequent", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "6fce1cd85a9344fee383b40a22f27862120b9488a628420625592dc14e0307d3", "warmup_time": -1}, "Components vs Django.timeraw_startup_lg": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"startup - large\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_startup_lg(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"lg\", \"startup\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_startup_lg", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "startup - large", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "53151821c128ad0ecfb0707fff3146e1abd8d0bcfa301aa056b5d3fae3d793e2", "warmup_time": -1}, "Other.timeraw_import_time": {"code": "class OtherTests:\n @benchmark(\n pretty_name=\"import time\",\n group_name=OTHER_GROUP,\n number=1,\n rounds=5,\n )\n def timeraw_import_time(self):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"startup\", \"isolated\", imports_only=True)", "min_run_count": 2, "name": "Other.timeraw_import_time", "number": 1, "param_names": [], "params": [], "pretty_name": "import time", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "a0a1c1c0db22509410b946d0d4384b52ea4a09b47b6048d7d1cfb89b0c7fe5c3", "warmup_time": -1}, "isolated vs django modes.peakmem_render_lg_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - first render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"first\",\n context_mode,\n ),\n )\n def peakmem_render_lg_first(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"first\",\n context_mode,\n),", "name": "isolated vs django modes.peakmem_render_lg_first", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "c4bf0016d48d210f08b8db733b57c7dcba1cebbf548c458b93b86ace387067e9"}, "isolated vs django modes.peakmem_render_lg_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - second render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"subsequent\",\n context_mode,\n ),\n )\n def peakmem_render_lg_subsequent(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"subsequent\",\n context_mode,\n),", "name": "isolated vs django modes.peakmem_render_lg_subsequent", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "65bb1b8586487197a79bb6073e4c71642877b845b6eb42d1bd32398299daffbf"}, "isolated vs django modes.peakmem_render_sm_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - first render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\"django-components\", \"sm\", \"first\", context_mode),\n )\n def peakmem_render_sm_first(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\"django-components\", \"sm\", \"first\", context_mode),", "name": "isolated vs django modes.peakmem_render_sm_first", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "c51b91fc583295776062822225e720b5ed71aef9c9288217c401c54283c62840"}, "isolated vs django modes.peakmem_render_sm_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - second render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"sm\",\n \"subsequent\",\n context_mode,\n ),\n )\n def peakmem_render_sm_subsequent(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"sm\",\n \"subsequent\",\n context_mode,\n),", "name": "isolated vs django modes.peakmem_render_sm_subsequent", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "54d747fb8f40179b7ff3d2fc49eb195909ad1c880b5ef7b82f82742b27b67260"}, "isolated vs django modes.timeraw_render_lg_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - first render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_lg_first(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"first\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_lg_first", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "f94af83427c6346f88f8785a3cd2fc42415ac5a9fbbdb7de71d27e22e6a81699", "warmup_time": -1}, "isolated vs django modes.timeraw_render_lg_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - second render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_lg_subsequent(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"subsequent\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_lg_subsequent", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "9f7c2fde6b33f0451a1794ed903c48d96cd7822f67da502cec36fe8e977c2414", "warmup_time": -1}, "isolated vs django modes.timeraw_render_sm_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - first render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_sm_first(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"sm\", \"first\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_sm_first", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "d15ca68909d7f1f43ff16863befb6f42681f17461417fc0069eefd6db3569296", "warmup_time": -1}, "isolated vs django modes.timeraw_render_sm_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - second render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_sm_subsequent(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"sm\", \"subsequent\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_sm_subsequent", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "7444bc9516dd087e3f420349345eae991ad6941bbd22fce45265b18034b7cf77", "warmup_time": -1}, "isolated vs django modes.timeraw_startup_lg": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"startup - large\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_startup_lg(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"startup\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_startup_lg", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "startup - large", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "eabe311ebee4a15c5816617be12f00ec30376f7506bd668219e1c50bc897c134", "warmup_time": -1}}, "machines": {"ci-linux": {"machine": "ci-linux", "version": 1}}, "tags": {"0.100": 1125, "0.101": 1132, "0.102": 1179, "0.110": 1252, "0.111": 1270, "0.112": 1277, "0.113": 1282, "0.114": 1287, "0.115": 1312, "0.116": 1328, "0.117": 1337, "0.118": 1352, "0.119": 1361, "0.120": 1366, "0.121": 1381, "0.122": 1387, "0.123": 1392, "0.124": 1447, "0.125": 1488, "0.126": 1505, "0.127": 1514, "0.128": 1546, "0.129": 1571, "0.130": 1591, "0.131": 1662, "0.132": 1672, "0.133": 1687, "0.134": 1691, "0.135": 1709, "0.136": 1726, "0.137": 1766, "0.138": 1770, "0.139": 1776, "0.139.1": 1801, "0.16": 250, "0.17": 268, "0.26.2": 508, "0.27": 550, "0.27.1": 552, "0.27.2": 564, "0.28.0": 575, "0.28.1": 577, "0.67": 845, "0.68": 855, "0.70": 867, "0.71": 884, "0.72": 887, "0.73": 889, "0.74": 891, "0.75": 898, "0.76": 902, "0.77": 904, "0.78": 908, "0.79": 910, "0.80": 912, "0.81": 930, "0.82": 935, "0.83": 940, "0.84": 942, "0.85": 956, "0.86": 958, "0.87": 960, "0.88": 965, "0.89": 978, "0.90": 980, "0.91": 982, "0.92": 986, "0.93": 1056, "0.94": 1058, "0.95": 1060, "0.96": 1089, "0.97": 1098, "0.18": 343, "0.22": 388, "0.21": 380, "0.20": 369, "0.19": 359, "0.24": 457, "0.23": 427, "0.25": 487, "0.26": 500, "0.26.1": 503, "0.26.3": 536, "0.28.2": 598, "0.28.3": 612, "0.29": 622, "0.30": 646, "0.31": 651, "0.32": 663, "0.33": 675, "0.34": 681, "0.34.1": 691, "0.35": 704, "0.37": 724, "0.50": 729, "0.51": 742, "0.52": 748, "0.60": 752, "0.61": 757, "0.62": 773, "0.63": 775, "0.64": 779, "0.65": 787, "0.66": 806}, "pages": [["", "Grid view", "Display as a agrid"], ["summarylist", "List view", "Display as a list"], ["regressions", "Show regressions", "Display information about recent regressions"]]} \ No newline at end of file +{"project": "django-components", "project_url": "/django-components/", "show_commit_url": "#", "hash_length": 8, "revision_to_hash": {"250": "45a18626d74b280aa05498aa380eba687010cc0f", "268": "c9f0068741871b24756045805aaab8fbf368601a", "343": "ed2cd57bdcc12bf390f42058061a6ed077e558b0", "359": "501a055fe21abb4c7ad9af1a3a1b42eea24afacf", "369": "1937d594100d0651b151c8edbe1189b5a88b358f", "380": "1d091f50999cca0fa8c7852da2ea71684eadda6d", "388": "f5c3f64c866d06dfa2435d1d18b936dddb9eb67c", "427": "24d9db39c3c55f5eb91c9ce2112ad22507ccdd60", "457": "9103eda2f4ed80f46ff03d215491009c5476b410", "487": "384ff79e0875ac3a64a2755010ef86ec09a090b5", "500": "c102019811586f40cb11952f283797ddee96de3c", "503": "a350ad1a869bb46c6bac093f54ac40ea85d8cd8f", "508": "16022429da16e459b8a1e6e9cd8ab41d95dcb59d", "536": "ea7beb518c435389d9daff7ea557eec9ddc2464e", "550": "2cfc7285e12677a54247e9998967081c0e031efc", "552": "fcbfae3c5f0611519636290ef99b25bc0a319825", "564": "316310e842f276fd43436b432781430bd255410b", "575": "e0a5c2a4bcf5e8f577e19333e3b719440c37b10b", "577": "c174aa9802cc73b5d8fef4b0c704de3fb68b1cbb", "598": "979781012532f18c147a570ff4441c65c7503b6f", "612": "9d7d0b40b9d3bbd8e5b754e3b1b20df982cdd184", "622": "24032ac2ea80627f0fdde88058a2c3fbcae0d3fe", "646": "4f1a8184465fc472995bc226bebd66c250d501f6", "651": "8ce649498ff63a64761c83cf713983b7e2f24b81", "663": "93facba53e050619a477fa214da89fccf118ec13", "675": "ea33e0db6c54486b67e2fa496ec1c3ec3de06ec7", "681": "6874b1531df0e8836000bbc76fcca5a3de42724a", "691": "9f4243232018708fdf330f0e922a09317c60234c", "704": "188a9dc7eef4c45ee4f87efa8a0d6728e94f210d", "724": "76a0cde3af7b3061127d149c138fbc78462a07fe", "729": "c932f28cb4840dc45d2d26b4d927c1480459272f", "742": "7058f05e0415965ddd162d0ba663c5106e7ffb66", "748": "95d6eacb5c03a611f92cd9a6e254cea7e0ce57eb", "752": "d512cfb0fec8a42ab58d2f106047fc4c0ec65427", "757": "04160f4e0b2ec4d901d6724c34ed8df883363064", "773": "20847b978b3ddb5979489fbb4bd8e971b9b16fbf", "775": "ae5cda9f727454a077ab16c51a237fec076bd442", "779": "cd791caa572c9acd6d56445c04d6c9b55a50c602", "787": "274be104789e31955f88e26f14c89ed648f25448", "806": "c3a80b729049b5ea1b4799e742e4100a7640efab", "845": "0abb5aa63ff0396328ef4dfdc2e78e872671f135", "855": "e4e787b29dc9cd2cf35ad02f22bad6fa15a7211c", "867": "e346c07298b268d9212fcf93d132968e69824730", "884": "2316f79dff66260b7a9fe91effb55c74524deca0", "887": "085c60a8c96442d9fd4f72d66a7eb295e7cfb2d9", "889": "ba86cee578490df944ad167674db32182b8bbf7b", "891": "dd292b03508b7c03b2ad4f9fb9c17dec747845ba", "898": "badffdda3538a8082137453c757509ed4f035a3e", "902": "c07f0e634121ced0119bb665ed544ca4447c416b", "904": "8bbe81d7171ec3512f250927653d8454c7ff005e", "908": "881c36219a45581086da35a17d3715ee0698ca88", "910": "9bfb50b8f27f7ff521226109ab30426633f6b514", "912": "3a7d5355cfa5d37641a4c80ee9fd2423cea10c1b", "930": "09a720009767f45bebcfa48f3587219c03082601", "935": "a4b4905bee778a51f9a99a042ce14ed2424cc9fb", "940": "31257a475dcfdacaaeb408f59ea92b736a668815", "942": "d47927054c820ecf3f9f97a62f03dfbb5496a11b", "956": "fbbbf6c694b8213832fc127ee8a3e31872308aff", "958": "d819f3ff491866abaeb9a7dbba6a6ca3c21da9f8", "960": "c202c5a901106392ccdde49100211182c986eca5", "965": "7bbfcf7565159d92de41bb0d738b7878d78f4533", "978": "b89c09aa5f13903b1d056c70afbfd327f0ed6362", "980": "03af25aad6841b6edb56c925d2599817e08ceb44", "982": "5cb649fae62a42e525c1ea9fb74d7838886cc1a8", "986": "f97717cdb35eaadb78b1f468728b1bd386e742d8", "1056": "b26a2011380c959bfc98043821f6b4aa337a281d", "1058": "8c5b088c31b7166932e18739f882c2eef632f3a4", "1060": "682bfc42397c0bdbeb1a2b6ccabb8aca89686d4f", "1089": "8f13a641ac096e93a0464f048a4fa53e591bb8db", "1098": "30d04fe1b053e6c5de0b6f34a7758a627517be8c", "1125": "f7846b9c0ae7a8fd0b7f6edf664316e485455e76", "1132": "a3d66586b19b7e2aacbf793edfba20bcd9858f4a", "1179": "0064de9c78db5eccc7c498e2a6d4c3c5ffa745ec", "1252": "d093bfb05212555e14c5cd46c94b0ba057cbeceb", "1270": "c0a4fd5f685d694218b583b2d0a3e8417925d53a", "1277": "2a4b0f52894d5d0bb8d325d6096a3950286db541", "1282": "5a23101038d7085959087b2352e71590eafe9529", "1287": "ce3305a5fff095e990707de851f85bc27120596c", "1312": "cdc830fca3bdd98669e0510841536be14d1bd728", "1328": "468a593a472c35379fe7567918e8a534b2d53748", "1337": "2f14e8e0908657459909c6338106e561edc5d0f4", "1352": "a5659691d0f947643ce6542b7f09075e3f931646", "1361": "aaeba99f54b206baed072ffd0572035ddf5118a7", "1366": "6813c9d7aa4acfb04df9665651a2864d04bbe8ba", "1381": "6681fc0085fdb4b76cb74c1bbf20d44fa22f40fe", "1387": "6bb73bd8afd350db84889efc09b74255cea08979", "1392": "c76f8198dd497b34735fc17a0f7a678bdd811a3f", "1447": "3bbd4326e6c1bfb4a02039e16021a3f720910308", "1488": "914576e68133bc6ec356f3918016c45691ed3534", "1505": "3d187d7abad80f8464bd70dfba847d27a8e173db", "1514": "e105500350a320dfccf36fc19cad7421d38c3736", "1546": "61515b34540d27311fc3286b50212c1e314ce39e", "1571": "691443a0a821eb1a02f9b42ad0e32bcd71d94943", "1591": "dcd4203eeadafc5d500b4b72c5cf04f1fe7317e7", "1662": "d0a42a2698f2ba21e7ab2dec750c5dbadeda0db5", "1672": "2037ed20b7252cc52008e69bdd3d8e095ad6ea08", "1687": "2472c2ad338a23fba015d4d9816cb62d1325455f", "1691": "42818ad6ffb47bd650d8a379b84c3d48394f9f77", "1709": "a6455d70f6c28ddbd4be8e58902f6cbc101e5ff3", "1726": "fdd29baa65e9ef78eb24a0ad2ca0b5d7c624dad3", "1766": "1319a95627493fc0745b5af0600af2dc8c5117f9", "1770": "07f747d70500bbe3e135725b0e1b102815ab9416", "1776": "ad402fc619922b6d2edf1e99b7082d2a58632076", "1801": "4c909486069f3c3c8ee7915239174f820f081da4", "1933": "593c66db7fce8f7d0e45768f516d1920e53d0967", "1937": "7b24b86f4a836c697acba926d9d6602afa45418d", "1960": "06c89cf9e89a432197a4cabb5a1d6864dd6089ac", "1996": "c692b7a3105c65414d2c23c357ffed9debdbf6e9", "2029": "5d7e235725449181f6b65b7bf97e43ea0e0f8552"}, "revision_to_date": {"250": 1630912817000, "268": 1631273531000, "343": 1654029104000, "359": 1657786741000, "369": 1657798498000, "380": 1658057264000, "388": 1658128984000, "427": 1670931380000, "457": 1673095465000, "487": 1675977478000, "500": 1678833725000, "503": 1678834812000, "508": 1679329468000, "536": 1680808865000, "550": 1681214445000, "552": 1681388770000, "564": 1682351069000, "575": 1684433482000, "577": 1684760359000, "598": 1693734426000, "612": 1695996512000, "622": 1696883504000, "646": 1702127213000, "651": 1702852887000, "663": 1705268832000, "675": 1705701480000, "681": 1706343740000, "691": 1706393538000, "704": 1707467055000, "724": 1708588716000, "729": 1708984309000, "742": 1709796107000, "748": 1710542375000, "752": 1711216985000, "757": 1711278671000, "773": 1711752109000, "775": 1711786713000, "779": 1712212506000, "787": 1712872453000, "806": 1713128940000, "845": 1713390260000, "855": 1713901297000, "867": 1714590581000, "884": 1714912319000, "887": 1715087715000, "889": 1715111097000, "891": 1715505986000, "898": 1716105516000, "902": 1716441018000, "904": 1716488913000, "908": 1717051130000, "910": 1717227227000, "912": 1717232115000, "930": 1718176374000, "935": 1718991590000, "940": 1720427258000, "942": 1720429478000, "956": 1722279535000, "958": 1722325182000, "960": 1722666822000, "965": 1722890429000, "978": 1723843975000, "980": 1723993321000, "982": 1724243667000, "986": 1724363119000, "1056": 1724732902000, "1058": 1724824521000, "1060": 1724924003000, "1089": 1725480929000, "1098": 1725655525000, "1125": 1726084755000, "1132": 1726347108000, "1179": 1728564427000, "1252": 1732525062000, "1270": 1732629701000, "1277": 1732644681000, "1282": 1732658332000, "1287": 1732726640000, "1312": 1733164405000, "1328": 1733471329000, "1337": 1733644953000, "1352": 1733834654000, "1361": 1734080521000, "1366": 1734245122000, "1381": 1734464187000, "1387": 1734600366000, "1392": 1734955786000, "1447": 1736287315000, "1488": 1737558545000, "1505": 1738157680000, "1514": 1738404847000, "1546": 1738662755000, "1571": 1739736734000, "1591": 1740050674000, "1662": 1742502414000, "1672": 1742645505000, "1687": 1742720064000, "1691": 1742765538000, "1709": 1743430242000, "1726": 1743837055000, "1766": 1744204166000, "1770": 1744216267000, "1776": 1744443333000, "1801": 1745143092000, "1933": 1749073294000, "1937": 1749076521000, "1960": 1749546769000, "1996": 1751538441000, "2029": 1753049108000}, "params": {"machine": ["ci-linux"], "python": ["3.13"], "django": ["5.1"], "djc-core-html-parser": [""], "branch": ["master"]}, "graph_param_list": [{"machine": "ci-linux", "python": "3.13", "django": "5.1", "djc-core-html-parser": "", "branch": "master"}], "benchmarks": {"Components vs Django.peakmem_render_lg_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - first render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"first\", \"isolated\"),\n )\n def peakmem_render_lg_first(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"first\", \"isolated\"),", "name": "Components vs Django.peakmem_render_lg_first", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "301c396f017f45a5b3f71e85df58d15f54153fcfd951af7ef424641d4b31b528"}, "Components vs Django.peakmem_render_lg_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - second render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"subsequent\", \"isolated\"),\n )\n def peakmem_render_lg_subsequent(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"lg\", \"subsequent\", \"isolated\"),", "name": "Components vs Django.peakmem_render_lg_subsequent", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "9a44e9999ef3ef42ea7e01323727490244febb43d66a87a4d8f88c6b8a133b8b"}, "Components vs Django.peakmem_render_sm_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - first render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"first\", \"isolated\"),\n )\n def peakmem_render_sm_first(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"first\", \"isolated\"),", "name": "Components vs Django.peakmem_render_sm_first", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "e93b7a5193681c883edf85bdb30b1bc0821263bf51033fdcee215b155085e036"}, "Components vs Django.peakmem_render_sm_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - second render (mem)\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n setup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"subsequent\", \"isolated\"),\n )\n def peakmem_render_sm_subsequent(self, renderer: TemplatingRenderer):\n do_render()\n\nsetup=lambda renderer: setup_templating_memory_benchmark(renderer, \"sm\", \"subsequent\", \"isolated\"),", "name": "Components vs Django.peakmem_render_sm_subsequent", "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "b46e0820b18950aa7cc5e61306ff3425b76b4da9dca42d64fae5b1d25c6c9026"}, "Components vs Django.timeraw_render_lg_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - first render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n include_in_quick_benchmark=True,\n )\n def timeraw_render_lg_first(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"lg\", \"first\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_lg_first", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "be3bf6236960046a028b6ea007aad28b2337fc2b906b8ce317a09a5d4f1a6193", "warmup_time": -1}, "Components vs Django.timeraw_render_lg_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - large - second render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_render_lg_subsequent(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"lg\", \"subsequent\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_lg_subsequent", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - large - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "b98221c11a0ee6e9de0778d416d31b9dd514a674d9017a2bb9b2fc1cd0f01920", "warmup_time": -1}, "Components vs Django.timeraw_render_sm_first": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - first render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_render_sm_first(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"sm\", \"first\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_sm_first", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "f1fc17e4a31c71f4d9265f1122da52e7cf57addb4dfa02606e303b33d6431b9b", "warmup_time": -1}, "Components vs Django.timeraw_render_sm_subsequent": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"render - small - second render\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_render_sm_subsequent(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"sm\", \"subsequent\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_render_sm_subsequent", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "render - small - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "6fce1cd85a9344fee383b40a22f27862120b9488a628420625592dc14e0307d3", "warmup_time": -1}, "Components vs Django.timeraw_startup_lg": {"code": "class DjangoComponentsVsDjangoTests:\n @benchmark(\n pretty_name=\"startup - large\",\n group_name=DJC_VS_DJ_GROUP,\n number=1,\n rounds=5,\n params={\n \"renderer\": [\"django\", \"django-components\"],\n },\n )\n def timeraw_startup_lg(self, renderer: TemplatingRenderer):\n return prepare_templating_benchmark(renderer, \"lg\", \"startup\", \"isolated\")", "min_run_count": 2, "name": "Components vs Django.timeraw_startup_lg", "number": 1, "param_names": ["renderer"], "params": [["'django'", "'django-components'"]], "pretty_name": "startup - large", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "53151821c128ad0ecfb0707fff3146e1abd8d0bcfa301aa056b5d3fae3d793e2", "warmup_time": -1}, "Other.timeraw_import_time": {"code": "class OtherTests:\n @benchmark(\n pretty_name=\"import time\",\n group_name=OTHER_GROUP,\n number=1,\n rounds=5,\n )\n def timeraw_import_time(self):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"startup\", \"isolated\", imports_only=True)", "min_run_count": 2, "name": "Other.timeraw_import_time", "number": 1, "param_names": [], "params": [], "pretty_name": "import time", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "a0a1c1c0db22509410b946d0d4384b52ea4a09b47b6048d7d1cfb89b0c7fe5c3", "warmup_time": -1}, "isolated vs django modes.peakmem_render_lg_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - first render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"first\",\n context_mode,\n ),\n )\n def peakmem_render_lg_first(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"first\",\n context_mode,\n),", "name": "isolated vs django modes.peakmem_render_lg_first", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "c4bf0016d48d210f08b8db733b57c7dcba1cebbf548c458b93b86ace387067e9"}, "isolated vs django modes.peakmem_render_lg_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - second render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"subsequent\",\n context_mode,\n ),\n )\n def peakmem_render_lg_subsequent(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"lg\",\n \"subsequent\",\n context_mode,\n),", "name": "isolated vs django modes.peakmem_render_lg_subsequent", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "65bb1b8586487197a79bb6073e4c71642877b845b6eb42d1bd32398299daffbf"}, "isolated vs django modes.peakmem_render_sm_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - first render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\"django-components\", \"sm\", \"first\", context_mode),\n )\n def peakmem_render_sm_first(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\"django-components\", \"sm\", \"first\", context_mode),", "name": "isolated vs django modes.peakmem_render_sm_first", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - first render (mem)", "type": "peakmemory", "unit": "bytes", "version": "c51b91fc583295776062822225e720b5ed71aef9c9288217c401c54283c62840"}, "isolated vs django modes.peakmem_render_sm_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - second render (mem)\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n setup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"sm\",\n \"subsequent\",\n context_mode,\n ),\n )\n def peakmem_render_sm_subsequent(self, context_mode: DjcContextMode):\n do_render()\n\nsetup=lambda context_mode: setup_templating_memory_benchmark(\n \"django-components\",\n \"sm\",\n \"subsequent\",\n context_mode,\n),", "name": "isolated vs django modes.peakmem_render_sm_subsequent", "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - second render (mem)", "type": "peakmemory", "unit": "bytes", "version": "54d747fb8f40179b7ff3d2fc49eb195909ad1c880b5ef7b82f82742b27b67260"}, "isolated vs django modes.timeraw_render_lg_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - first render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_lg_first(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"first\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_lg_first", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "f94af83427c6346f88f8785a3cd2fc42415ac5a9fbbdb7de71d27e22e6a81699", "warmup_time": -1}, "isolated vs django modes.timeraw_render_lg_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - large - second render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_lg_subsequent(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"subsequent\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_lg_subsequent", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - large - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "9f7c2fde6b33f0451a1794ed903c48d96cd7822f67da502cec36fe8e977c2414", "warmup_time": -1}, "isolated vs django modes.timeraw_render_sm_first": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - first render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_sm_first(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"sm\", \"first\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_sm_first", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - first render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "d15ca68909d7f1f43ff16863befb6f42681f17461417fc0069eefd6db3569296", "warmup_time": -1}, "isolated vs django modes.timeraw_render_sm_subsequent": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"render - small - second render\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_render_sm_subsequent(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"sm\", \"subsequent\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_render_sm_subsequent", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "render - small - second render", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "7444bc9516dd087e3f420349345eae991ad6941bbd22fce45265b18034b7cf77", "warmup_time": -1}, "isolated vs django modes.timeraw_startup_lg": {"code": "class IsolatedVsDjangoContextModesTests:\n @benchmark(\n pretty_name=\"startup - large\",\n group_name=DJC_ISOLATED_VS_NON_GROUP,\n number=1,\n rounds=5,\n params={\n \"context_mode\": [\"isolated\", \"django\"],\n },\n )\n def timeraw_startup_lg(self, context_mode: DjcContextMode):\n return prepare_templating_benchmark(\"django-components\", \"lg\", \"startup\", context_mode)", "min_run_count": 2, "name": "isolated vs django modes.timeraw_startup_lg", "number": 1, "param_names": ["context_mode"], "params": [["'isolated'", "'django'"]], "pretty_name": "startup - large", "repeat": 0, "rounds": 5, "sample_time": 0.01, "type": "time", "unit": "seconds", "version": "eabe311ebee4a15c5816617be12f00ec30376f7506bd668219e1c50bc897c134", "warmup_time": -1}}, "machines": {"ci-linux": {"machine": "ci-linux", "version": 1}}, "tags": {"0.100": 1125, "0.101": 1132, "0.102": 1179, "0.110": 1252, "0.111": 1270, "0.112": 1277, "0.113": 1282, "0.114": 1287, "0.115": 1312, "0.116": 1328, "0.117": 1337, "0.118": 1352, "0.119": 1361, "0.120": 1366, "0.121": 1381, "0.122": 1387, "0.123": 1392, "0.124": 1447, "0.125": 1488, "0.126": 1505, "0.127": 1514, "0.128": 1546, "0.129": 1571, "0.130": 1591, "0.131": 1662, "0.132": 1672, "0.133": 1687, "0.134": 1691, "0.135": 1709, "0.136": 1726, "0.137": 1766, "0.138": 1770, "0.139": 1776, "0.139.1": 1801, "0.140.0": 1933, "0.140.1": 1937, "0.141.0": 1960, "0.141.1": 1996, "0.141.2": 2029, "0.16": 250, "0.17": 268, "0.26.2": 508, "0.27": 550, "0.27.1": 552, "0.27.2": 564, "0.28.0": 575, "0.28.1": 577, "0.67": 845, "0.68": 855, "0.70": 867, "0.71": 884, "0.72": 887, "0.73": 889, "0.74": 891, "0.75": 898, "0.76": 902, "0.77": 904, "0.78": 908, "0.79": 910, "0.80": 912, "0.81": 930, "0.82": 935, "0.83": 940, "0.84": 942, "0.85": 956, "0.86": 958, "0.87": 960, "0.88": 965, "0.89": 978, "0.90": 980, "0.91": 982, "0.92": 986, "0.93": 1056, "0.94": 1058, "0.95": 1060, "0.96": 1089, "0.97": 1098, "0.18": 343, "0.22": 388, "0.21": 380, "0.20": 369, "0.19": 359, "0.24": 457, "0.23": 427, "0.25": 487, "0.26": 500, "0.26.1": 503, "0.26.3": 536, "0.28.2": 598, "0.28.3": 612, "0.29": 622, "0.30": 646, "0.31": 651, "0.32": 663, "0.33": 675, "0.34": 681, "0.34.1": 691, "0.35": 704, "0.37": 724, "0.50": 729, "0.51": 742, "0.52": 748, "0.60": 752, "0.61": 757, "0.62": 773, "0.63": 775, "0.64": 779, "0.65": 787, "0.66": 806}, "pages": [["", "Grid view", "Display as a agrid"], ["summarylist", "List view", "Display as a list"], ["regressions", "Show regressions", "Display information about recent regressions"]]} \ No newline at end of file diff --git a/docs/benchmarks/info.json b/docs/benchmarks/info.json index cc536bb4..032015bd 100644 --- a/docs/benchmarks/info.json +++ b/docs/benchmarks/info.json @@ -1,4 +1,4 @@ { "asv-version": "0.6.4", - "timestamp": 1745143636166 + "timestamp": 1753049912703 } \ No newline at end of file diff --git a/docs/benchmarks/regressions.json b/docs/benchmarks/regressions.json index ddd12532..0203f18b 100644 --- a/docs/benchmarks/regressions.json +++ b/docs/benchmarks/regressions.json @@ -1 +1 @@ -{"regressions": [["Components vs Django.timeraw_render_lg_subsequent('django')", "graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_subsequent.json", {}, 0, 0.03723830100000214, 0.03327357099999517, [[1691, 1709, 0.03327357099999517, 0.03723830100000214]]], ["Components vs Django.timeraw_render_sm_subsequent('django')", "graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_sm_subsequent.json", {}, 0, 0.00011641800000461444, 0.0001005780000014056, [[1691, 1709, 0.0001005780000014056, 0.00011641800000461444]]]]} \ No newline at end of file +{"regressions": [["Components vs Django.timeraw_render_lg_subsequent('django')", "graphs/branch-master/django-5.1/djc-core-html-parser/machine-ci-linux/python-3.13/Components vs Django.timeraw_render_lg_subsequent.json", {}, 0, 0.04362213900003553, 0.03327357099999517, [[1691, 1709, 0.03327357099999517, 0.03723830100000214], [1801, 1937, 0.03723830100000214, 0.04362213900003553]]]]} \ No newline at end of file diff --git a/docs/benchmarks/regressions.xml b/docs/benchmarks/regressions.xml index 3469b682..3e718e7e 100644 --- a/docs/benchmarks/regressions.xml +++ b/docs/benchmarks/regressions.xml @@ -1,8 +1,8 @@ -tag:django-components.asv,1970-01-01:/cddbdcca8b398afd301fbfc73cc4d51103d4e3059c0e6b938d4c467ad3d1aa25Airspeed Velocitydjango-components performance regressions2025-03-31T14:17:04Ztag:django-components.asv,2025-03-31:/3489e338e3aeb103ea646e0f8aee41043fa61c99d14c7b57d874c9ebc1c79b2215.75% Components vs Django.timeraw_render_sm_subsequent('django')2025-03-31T14:17:04Z<a href="index.html#Components vs Django.timeraw_render_sm_subsequent?p-renderer=%27django%27&commits=42818ad6ffb47bd650d8a379b84c3d48394f9f77-a6455d70f6c28ddbd4be8e58902f6cbc101e5ff3">15.75% regression</a> on 2025-03-31 14:10:42 in commits <a href="#42818ad6ffb47bd650d8a379b84c3d48394f9f77">42818ad6...a6455d70</a>.<br> - New value: 116μs, old value: 101μs.<br> - Latest value: 116μs (15.75% worse - than best value 101μs).tag:django-components.asv,2025-03-31:/7a13128cbc4d175ca09ebda40e8a303789275bd84b00a5d496cfa08a26ad2f8b11.92% Components vs Django.timeraw_render_lg_subsequent('django')2025-03-31T14:16:53Z<a href="index.html#Components vs Django.timeraw_render_lg_subsequent?p-renderer=%27django%27&commits=42818ad6ffb47bd650d8a379b84c3d48394f9f77-a6455d70f6c28ddbd4be8e58902f6cbc101e5ff3">11.92% regression</a> on 2025-03-31 14:10:42 in commits <a href="#42818ad6ffb47bd650d8a379b84c3d48394f9f77">42818ad6...a6455d70</a>.<br> +tag:django-components.asv,1970-01-01:/cddbdcca8b398afd301fbfc73cc4d51103d4e3059c0e6b938d4c467ad3d1aa25Airspeed Velocitydjango-components performance regressions2025-06-04T22:41:21Ztag:django-components.asv,2025-06-04:/38b868a38890eb5bccfd51983abf3a15cedf2846ef6cf2452e941122dbde2bde17.14% Components vs Django.timeraw_render_lg_subsequent('django')2025-06-04T22:41:21Z<a href="index.html#Components vs Django.timeraw_render_lg_subsequent?p-renderer=%27django%27&commits=4c909486069f3c3c8ee7915239174f820f081da4-7b24b86f4a836c697acba926d9d6602afa45418d">17.14% regression</a> on 2025-06-04 22:35:21 in commits <a href="#4c909486069f3c3c8ee7915239174f820f081da4">4c909486...7b24b86f</a>.<br> + New value: 43.6ms, old value: 37.2ms.<br> + Latest value: 43.6ms (31.10% worse + than best value 33.3ms).tag:django-components.asv,2025-03-31:/7a13128cbc4d175ca09ebda40e8a303789275bd84b00a5d496cfa08a26ad2f8b11.92% Components vs Django.timeraw_render_lg_subsequent('django')2025-03-31T14:16:53Z<a href="index.html#Components vs Django.timeraw_render_lg_subsequent?p-renderer=%27django%27&commits=42818ad6ffb47bd650d8a379b84c3d48394f9f77-a6455d70f6c28ddbd4be8e58902f6cbc101e5ff3">11.92% regression</a> on 2025-03-31 14:10:42 in commits <a href="#42818ad6ffb47bd650d8a379b84c3d48394f9f77">42818ad6...a6455d70</a>.<br> New value: 37.2ms, old value: 33.3ms.<br> - Latest value: 37.2ms (11.92% worse + Latest value: 43.6ms (31.10% worse than best value 33.3ms). \ No newline at end of file diff --git a/docs/getting_started/adding_slots.md b/docs/getting_started/adding_slots.md index 19687a79..9081e5c1 100644 --- a/docs/getting_started/adding_slots.md +++ b/docs/getting_started/adding_slots.md @@ -134,7 +134,7 @@ Which will render as: {% endcomponent %} ``` -### 5. Wait, there's a bug +### 4. Wait, there's a bug There is a mistake in our code! `2024-12-13` is Friday, so that's fine. But if we updated the to `2024-12-14`, which is Saturday, our template from previous step would render this: @@ -289,3 +289,8 @@ each time: Moreover, slots are treated as part of the template - for example the CSS scoping (work in progress) is applied to the slot content too. + +--- + +So far we've rendered components using template tag. [Next, let’s explore other ways to render components ➡️] +(./rendering_components.md) diff --git a/docs/getting_started/components_in_templates.md b/docs/getting_started/components_in_templates.md index cca78909..ae798a8d 100644 --- a/docs/getting_started/components_in_templates.md +++ b/docs/getting_started/components_in_templates.md @@ -55,7 +55,7 @@ by calling `{% load component_tags %}` inside the template. like `{% component "calendar" / %}`. `ComponentRegistries` also make it possible to group and share components as standalone packages. - [Learn more here](../../concepts/advanced/authoring_component_libraries). + [Learn more here](../../concepts/advanced/component_libraries). !!! note diff --git a/docs/getting_started/parametrising_components.md b/docs/getting_started/parametrising_components.md index f0cab85d..7ebc3c0d 100644 --- a/docs/getting_started/parametrising_components.md +++ b/docs/getting_started/parametrising_components.md @@ -220,10 +220,6 @@ the parametrized version of the component: ``` ---- - -Next, you will learn [how to use slots give your components even more flexibility ➡️](./adding_slots.md) - ### 5. Add defaults In our example, we've set the `extra_class` to default to `"text-blue"` by setting it in the @@ -258,3 +254,7 @@ class Calendar(Component): "extra_class": kwargs["extra_class"], # <--- changed } ``` + +--- + +Next, you will learn [how to use slots give your components even more flexibility ➡️](./adding_slots.md) diff --git a/docs/getting_started/rendering_components.md b/docs/getting_started/rendering_components.md index 1232ff30..72205149 100644 --- a/docs/getting_started/rendering_components.md +++ b/docs/getting_started/rendering_components.md @@ -160,7 +160,7 @@ def my_view(request): response_class = MyCustomResponse ``` -### Rendering slots +### 4. Rendering slots Slots content are automatically escaped by default to prevent XSS attacks. @@ -203,7 +203,7 @@ Calendar.render( [`format_html`](https://docs.djangoproject.com/en/5.2/ref/utils/#django.utils.html.format_html) and [`mark_safe`](https://docs.djangoproject.com/en/5.2/ref/utils/#django.utils.safestring.mark_safe). -### Component views and URLs +### 5. Component views and URLs For web applications, it's common to define endpoints that serve HTML content (AKA views). diff --git a/docs/getting_started/your_first_component.md b/docs/getting_started/your_first_component.md index 21b403af..328c8737 100644 --- a/docs/getting_started/your_first_component.md +++ b/docs/getting_started/your_first_component.md @@ -35,8 +35,9 @@ document.querySelector(".calendar").onclick = function () { ``` ```py title="calendar.py" -from django_components import Component +from django_components import Component, register +@register("calendar") class Calendar(Component): template_file = "calendar.html" js_file = "calendar.js" diff --git a/docs/overview/community.md b/docs/overview/community.md index 75fe49a9..38a28394 100644 --- a/docs/overview/community.md +++ b/docs/overview/community.md @@ -7,9 +7,9 @@ Please, before opening a new discussion, [check if similar discussion wasn't ope ## Community examples One of our goals with `django-components` is to make it easy to share components between projects -([see how to package components](../concepts/advanced/authoring_component_libraries.md)). +([see how to package components](../concepts/advanced/component_libraries.md)). If you have a set of components that you think would be useful to others, please open a pull request to add them to the list below. -- [django-htmx-components](https://github.com/iwanalabs/django-htmx-components): A set of components for use with [htmx](https://htmx.org/). Try out the [live demo](https://dhc.iwanalabs.com/). +- [django-htmx-components](https://github.com/iwanalabs/django-htmx-components): A set of components for use with [htmx](https://htmx.org/). - [djc-heroicons](https://pypi.org/project/djc-heroicons/): A component that renders icons from [Heroicons.com](https://heroicons.com/). diff --git a/docs/overview/welcome.md b/docs/overview/welcome.md index 6c16cbc6..d703b048 100644 --- a/docs/overview/welcome.md +++ b/docs/overview/welcome.md @@ -18,8 +18,9 @@ A component in django-components can be as simple as a Django template and Pytho ``` ```py title="components/calendar/calendar.py" -from django_components import Component +from django_components import Component, register +@register("calendar") class Calendar(Component): template_file = "calendar.html" ``` @@ -46,8 +47,9 @@ document.querySelector(".calendar").onclick = () => { ``` ```py title="components/calendar/calendar.py" -from django_components import Component +from django_components import Component, register +@register("calendar") class Calendar(Component): template_file = "calendar.html" js_file = "calendar.js" diff --git a/docs/reference/.nav.yml b/docs/reference/.nav.yml index dbea3cb1..42aab39b 100644 --- a/docs/reference/.nav.yml +++ b/docs/reference/.nav.yml @@ -1,16 +1,16 @@ # `.nav.yml` is provided by https://lukasgeiter.github.io/mkdocs-awesome-nav nav: - API: api.md - - Commands: commands.md + - CLI commands: commands.md - Components: components.md - Exceptions: exceptions.md - - Extension commands: extension_commands.md - Extension hooks: extension_hooks.md - - Extension URLs: extension_urls.md + - Extension commands API: extension_commands.md + - Extension URLs API: extension_urls.md - Settings: settings.md - Signals: signals.md - Tag formatters: tag_formatters.md - Template tags: template_tags.md - - Template vars: template_vars.md + - Template variables: template_variables.md - URLs: urls.md - Testing API: testing_api.md diff --git a/docs/reference/extension_commands.md b/docs/reference/extension_commands.md index ba29d401..40a18b83 100644 --- a/docs/reference/extension_commands.md +++ b/docs/reference/extension_commands.md @@ -1,6 +1,6 @@ -# Extension commands +# Extension commands API Overview of all classes, functions, and other objects related to defining extension commands. diff --git a/docs/reference/extension_hooks.md b/docs/reference/extension_hooks.md index 43090eb0..e9f95c07 100644 --- a/docs/reference/extension_hooks.md +++ b/docs/reference/extension_hooks.md @@ -148,6 +148,42 @@ name | type | description `name` | `str` | The name the component was registered under `registry` | [`ComponentRegistry`](../api#django_components.ComponentRegistry) | The registry the component was unregistered from +::: django_components.extension.ComponentExtension.on_css_loaded + options: + heading_level: 3 + show_root_heading: true + show_signature: true + separate_signature: true + show_symbol_type_heading: false + show_symbol_type_toc: false + show_if_no_docstring: true + show_labels: false + +**Available data:** + +name | type | description +--|--|-- +`component_cls` | [`Type[Component]`](../api#django_components.Component) | The Component class whose CSS was loaded +`content` | `str` | The CSS content (string) + +::: django_components.extension.ComponentExtension.on_js_loaded + options: + heading_level: 3 + show_root_heading: true + show_signature: true + separate_signature: true + show_symbol_type_heading: false + show_symbol_type_toc: false + show_if_no_docstring: true + show_labels: false + +**Available data:** + +name | type | description +--|--|-- +`component_cls` | [`Type[Component]`](../api#django_components.Component) | The Component class whose JS was loaded +`content` | `str` | The JS content (string) + ::: django_components.extension.ComponentExtension.on_registry_created options: heading_level: 3 @@ -207,6 +243,44 @@ name | type | description `slot_name` | `str` | The name of the `{% slot %}` tag `slot_node` | `SlotNode` | The node instance of the `{% slot %}` tag +::: django_components.extension.ComponentExtension.on_template_compiled + options: + heading_level: 3 + show_root_heading: true + show_signature: true + separate_signature: true + show_symbol_type_heading: false + show_symbol_type_toc: false + show_if_no_docstring: true + show_labels: false + +**Available data:** + +name | type | description +--|--|-- +`component_cls` | [`Type[Component]`](../api#django_components.Component) | The Component class whose template was loaded +`template` | `django.template.base.Template` | The compiled template object + +::: django_components.extension.ComponentExtension.on_template_loaded + options: + heading_level: 3 + show_root_heading: true + show_signature: true + separate_signature: true + show_symbol_type_heading: false + show_symbol_type_toc: false + show_if_no_docstring: true + show_labels: false + +**Available data:** + +name | type | description +--|--|-- +`component_cls` | [`Type[Component]`](../api#django_components.Component) | The Component class whose template was loaded +`content` | `str` | The template string +`name` | `Optional[str]` | The name of the template +`origin` | `Optional[django.template.base.Origin]` | The origin of the template + ## Objects ::: django_components.extension.OnComponentClassCreatedContext diff --git a/docs/reference/extension_urls.md b/docs/reference/extension_urls.md index f651ceb7..10570d2e 100644 --- a/docs/reference/extension_urls.md +++ b/docs/reference/extension_urls.md @@ -1,6 +1,6 @@ -# Extension URLs +# Extension URLs API Overview of all classes, functions, and other objects related to defining extension URLs. diff --git a/docs/reference/template_tags.md b/docs/reference/template_tags.md index b0fd167b..d5c9145f 100644 --- a/docs/reference/template_tags.md +++ b/docs/reference/template_tags.md @@ -67,7 +67,7 @@ If you insert this tag multiple times, ALL JS scripts will be duplicately insert -See source code +See source code diff --git a/docs/reference/template_vars.md b/docs/reference/template_variables.md similarity index 100% rename from docs/reference/template_vars.md rename to docs/reference/template_variables.md diff --git a/docs/scripts/reference.py b/docs/scripts/reference.py index 6f1ee7da..28963a22 100644 --- a/docs/scripts/reference.py +++ b/docs/scripts/reference.py @@ -44,6 +44,7 @@ from pathlib import Path from textwrap import dedent from typing import Any, Dict, List, NamedTuple, Optional, Sequence, Tuple, Type, Union +from django.conf import settings from django.core.management.base import BaseCommand from django.urls import URLPattern, URLResolver @@ -465,7 +466,13 @@ def gen_reference_commands(): # Add link to source code module_abs_path = import_module(cmd_def_cls.__module__).__file__ module_rel_path = Path(module_abs_path).relative_to(Path.cwd()).as_posix() # type: ignore[arg-type] - obj_lineno = inspect.findsource(cmd_def_cls)[1] + + # NOTE: Raises `OSError` if the file is not found. + try: + obj_lineno = inspect.findsource(cmd_def_cls)[1] + except Exception: + obj_lineno = None + source_code_link = _format_source_code_html(module_rel_path, obj_lineno) # NOTE: For the commands we have to generate the markdown entries ourselves, @@ -524,7 +531,7 @@ def gen_reference_commands(): ) -def gen_reference_templatetags(): +def gen_reference_template_tags(): """ Generate documentation for all Django template tags defined by django-components, like `{% slot %}`, `{% component %}`, etc. @@ -537,7 +544,7 @@ def gen_reference_templatetags(): ] preface = "\n\n" - preface += (root / "docs/templates/reference_templatetags.md").read_text() + preface += (root / "docs/templates/reference_template_tags.md").read_text() out_file = root / "docs/reference/template_tags.md" out_file.parent.mkdir(parents=True, exist_ok=True) @@ -585,14 +592,14 @@ def gen_reference_templatetags(): ) -def gen_reference_templatevars(): +def gen_reference_template_variables(): """ Generate documentation for all variables that are available inside the component templates under the `{{ component_vars }}` variable, as defined by `ComponentVars`. """ preface = "\n\n" - preface += (root / "docs/templates/reference_templatevars.md").read_text() - out_file = root / "docs/reference/template_vars.md" + preface += (root / "docs/templates/reference_template_variables.md").read_text() + out_file = root / "docs/reference/template_variables.md" out_file.parent.mkdir(parents=True, exist_ok=True) with out_file.open("w", encoding="utf-8") as f: @@ -1099,6 +1106,13 @@ def _is_extension_url_api(obj: Any) -> bool: def gen_reference(): """The entrypoint to generate all the reference documentation.""" + + # Set up Django settings so we can import `extensions` + if not settings.configured: + settings.configure( + BASE_DIR=Path(__file__).parent.parent.parent, + ) + gen_reference_api() gen_reference_exceptions() gen_reference_components() @@ -1106,8 +1120,8 @@ def gen_reference(): gen_reference_tagformatters() gen_reference_urls() gen_reference_commands() - gen_reference_templatetags() - gen_reference_templatevars() + gen_reference_template_tags() + gen_reference_template_variables() gen_reference_signals() gen_reference_testing_api() gen_reference_extension_hooks() diff --git a/docs/templates/reference_extension_commands.md b/docs/templates/reference_extension_commands.md index 0df90645..9d9c51ea 100644 --- a/docs/templates/reference_extension_commands.md +++ b/docs/templates/reference_extension_commands.md @@ -1,4 +1,4 @@ -# Extension commands +# Extension commands API Overview of all classes, functions, and other objects related to defining extension commands. diff --git a/docs/templates/reference_extension_urls.md b/docs/templates/reference_extension_urls.md index 10692b23..eaa55135 100644 --- a/docs/templates/reference_extension_urls.md +++ b/docs/templates/reference_extension_urls.md @@ -1,4 +1,4 @@ -# Extension URLs +# Extension URLs API Overview of all classes, functions, and other objects related to defining extension URLs. diff --git a/docs/templates/reference_templatetags.md b/docs/templates/reference_template_tags.md similarity index 100% rename from docs/templates/reference_templatetags.md rename to docs/templates/reference_template_tags.md diff --git a/docs/templates/reference_templatevars.md b/docs/templates/reference_template_variables.md similarity index 100% rename from docs/templates/reference_templatevars.md rename to docs/templates/reference_template_variables.md diff --git a/pyproject.toml b/pyproject.toml index 45e6918d..452cf567 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "django_components" -version = "0.140.1" +version = "0.141.2" requires-python = ">=3.8, <4.0" description = "A way to create simple reusable template components in Django." keywords = ["django", "components", "css", "js", "html"] diff --git a/requirements-ci.in b/requirements-ci.in index 7b5e9b79..77b7ef03 100644 --- a/requirements-ci.in +++ b/requirements-ci.in @@ -7,7 +7,7 @@ whitenoise asv # NOTE: pin virtualenv to <20.31 until asv fixes integration # See https://github.com/airspeed-velocity/asv/issues/1484 -virtualenv==20.31.2 +virtualenv==20.32.0 pytest-asyncio pytest-django typing-extensions>=4.12.2 diff --git a/requirements-ci.txt b/requirements-ci.txt index 26fa6317..aab43e1a 100644 --- a/requirements-ci.txt +++ b/requirements-ci.txt @@ -104,7 +104,7 @@ urllib3==2.2.3 # via # requests # types-requests -virtualenv==20.31.2 +virtualenv==20.32.0 # via # -r requirements-ci.in # asv diff --git a/requirements-dev.in b/requirements-dev.in index 4bff8d14..b6034208 100644 --- a/requirements-dev.in +++ b/requirements-dev.in @@ -20,6 +20,6 @@ pygments-djc asv # NOTE: pin virtualenv to <20.31 until asv fixes integration # See https://github.com/airspeed-velocity/asv/issues/1484 -virtualenv==20.31.2 +virtualenv==20.32.0 typing-extensions>=4.12.2 pathspec \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt index a728065e..09db29b6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -30,7 +30,7 @@ colorama==0.4.6 # via tox distlib==0.3.9 # via virtualenv -django==4.2.21 +django==4.2.23 # via -r requirements-dev.in djc-core-html-parser==1.0.2 # via -r requirements-dev.in @@ -40,7 +40,7 @@ filelock==3.16.1 # via # tox # virtualenv -flake8==7.2.0 +flake8==7.3.0 # via # -r requirements-dev.in # flake8-pyproject @@ -64,7 +64,7 @@ json5==0.10.0 # via asv mccabe==0.7.0 # via flake8 -mypy==1.16.0 +mypy==1.17.0 # via -r requirements-dev.in mypy-extensions==1.0.0 # via @@ -97,11 +97,11 @@ pluggy==1.5.0 # tox pre-commit==4.2.0 # via -r requirements-dev.in -pycodestyle==2.13.0 +pycodestyle==2.14.0 # via flake8 pyee==12.0.0 # via playwright -pyflakes==3.3.2 +pyflakes==3.4.0 # via flake8 pygments==2.19.1 # via @@ -163,7 +163,7 @@ urllib3==2.2.3 # via # requests # types-requests -virtualenv==20.31.2 +virtualenv==20.32.0 # via # -r requirements-dev.in # asv diff --git a/requirements-docs.txt b/requirements-docs.txt index e3dca646..c7ae2086 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -24,7 +24,7 @@ # - djc-core-html-parser>=1.0 # -asgiref==3.8.1 +asgiref==3.9.1 # via django babel==2.17.0 # via @@ -32,13 +32,13 @@ babel==2.17.0 # mkdocs-material black==25.1.0 # via hatch.envs.docs -bracex==2.5.post1 +bracex==2.6 # via wcmatch cairocffi==1.7.1 # via cairosvg cairosvg==2.8.2 # via mkdocs-material -certifi==2025.4.26 +certifi==2025.7.14 # via requests cffi==1.17.1 # via cairocffi @@ -58,7 +58,7 @@ cssselect2==0.8.0 # via cairosvg defusedxml==0.7.1 # via cairosvg -django==4.2.21 +django==4.2.23 # via hatch.envs.docs djc-core-html-parser==1.0.2 # via hatch.envs.docs @@ -66,9 +66,9 @@ ghp-import==2.1.0 # via mkdocs gitdb==4.0.12 # via gitpython -gitpython==3.1.44 +gitpython==3.1.45 # via mkdocs-git-revision-date-localized-plugin -griffe==1.7.3 +griffe==1.9.0 # via mkdocstrings-python htmlmin2==0.1.13 # via mkdocs-minify-plugin @@ -86,14 +86,14 @@ jinja2==3.1.6 # mkdocstrings jsmin==3.0.1 # via mkdocs-minify-plugin -markdown==3.8 +markdown==3.8.2 # via # mkdocs # mkdocs-autorefs # mkdocs-material # mkdocstrings # pymdown-extensions -markdown-exec==1.10.3 +markdown-exec==1.11.0 # via hatch.envs.docs markupsafe==3.0.2 # via @@ -134,13 +134,13 @@ mkdocs-get-deps==0.2.0 # via # mkdocs # mkdocstrings -mkdocs-git-authors-plugin==0.9.5 +mkdocs-git-authors-plugin==0.10.0 # via hatch.envs.docs mkdocs-git-revision-date-localized-plugin==1.4.7 # via hatch.envs.docs -mkdocs-include-markdown-plugin==7.1.5 +mkdocs-include-markdown-plugin==7.1.6 # via hatch.envs.docs -mkdocs-material==9.6.14 +mkdocs-material==9.6.15 # via hatch.envs.docs mkdocs-material-extensions==1.3.1 # via mkdocs-material @@ -148,11 +148,11 @@ mkdocs-minify-plugin==0.8.0 # via hatch.envs.docs mkdocs-redirects==1.2.2 # via hatch.envs.docs -mkdocstrings==0.29.1 +mkdocstrings==0.30.0 # via # hatch.envs.docs # mkdocstrings-python -mkdocstrings-python==1.16.11 +mkdocstrings-python==1.16.12 # via hatch.envs.docs mypy-extensions==1.1.0 # via black @@ -166,7 +166,7 @@ pathspec==0.12.1 # via # black # mkdocs -pillow==11.2.1 +pillow==11.3.0 # via # cairosvg # mkdocs-material @@ -176,14 +176,14 @@ platformdirs==4.3.8 # mkdocs-get-deps pycparser==2.22 # via cffi -pygments==2.19.1 +pygments==2.19.2 # via # hatch.envs.docs # mkdocs-material # pygments-djc pygments-djc==1.0.1 # via hatch.envs.docs -pymdown-extensions==10.15 +pymdown-extensions==10.16.1 # via # hatch.envs.docs # markdown-exec @@ -208,7 +208,7 @@ pyyaml-env-tag==1.1 # mkdocs regex==2024.11.6 # via mkdocs-material -requests==2.32.3 +requests==2.32.4 # via mkdocs-material six==1.17.0 # via python-dateutil @@ -220,17 +220,17 @@ tinycss2==1.4.0 # via # cairosvg # cssselect2 -urllib3==2.4.0 +urllib3==2.5.0 # via requests verspec==0.1.0 # via mike watchdog==6.0.0 # via mkdocs -wcmatch==10.0 +wcmatch==10.1 # via mkdocs-include-markdown-plugin webencodings==0.5.1 # via # cssselect2 # tinycss2 -zipp==3.22.0 +zipp==3.23.0 # via importlib-metadata diff --git a/src/django_components/app_settings.py b/src/django_components/app_settings.py index 53bfacc8..aa1a2d9f 100644 --- a/src/django_components/app_settings.py +++ b/src/django_components/app_settings.py @@ -746,8 +746,8 @@ defaults = ComponentsSettings( # # Settings are loaded from Django settings only once, at `apps.py` in `ready()`. class InternalSettings: - def __init__(self, settings: Optional[Dict[str, Any]] = None): - self._settings = ComponentsSettings(**settings) if settings else defaults + def __init__(self) -> None: + self._settings: Optional[ComponentsSettings] = None def _load_settings(self) -> None: data = getattr(settings, "COMPONENTS", {}) @@ -786,6 +786,11 @@ class InternalSettings: tag_formatter=default(components_settings.tag_formatter, defaults.tag_formatter), # type: ignore[arg-type] ) + def _get_settings(self) -> ComponentsSettings: + if self._settings is None: + self._load_settings() + return cast(ComponentsSettings, self._settings) + def _prepare_extensions(self, new_settings: ComponentsSettings) -> List["ComponentExtension"]: extensions: Sequence[Union[Type["ComponentExtension"], str]] = default( new_settings.extensions, cast(List[str], defaults.extensions) @@ -795,6 +800,7 @@ class InternalSettings: from django_components.extensions.cache import CacheExtension from django_components.extensions.debug_highlight import DebugHighlightExtension from django_components.extensions.defaults import DefaultsExtension + from django_components.extensions.dependencies import DependenciesExtension from django_components.extensions.view import ViewExtension extensions = cast( @@ -802,6 +808,7 @@ class InternalSettings: [ CacheExtension, DefaultsExtension, + DependenciesExtension, ViewExtension, DebugHighlightExtension, ], @@ -853,70 +860,73 @@ class InternalSettings: return raw_value - # TODO REMOVE THE PROPERTIES BELOW? THEY NO LONGER SERVE ANY PURPOSE @property def AUTODISCOVER(self) -> bool: - return self._settings.autodiscover # type: ignore[return-value] + return self._get_settings().autodiscover # type: ignore[return-value] @property def CACHE(self) -> Optional[str]: - return self._settings.cache + return self._get_settings().cache @property def DIRS(self) -> Sequence[Union[str, PathLike, Tuple[str, str], Tuple[str, PathLike]]]: - return self._settings.dirs # type: ignore[return-value] + return self._get_settings().dirs # type: ignore[return-value] @property def APP_DIRS(self) -> Sequence[str]: - return self._settings.app_dirs # type: ignore[return-value] + return self._get_settings().app_dirs # type: ignore[return-value] @property def DEBUG_HIGHLIGHT_COMPONENTS(self) -> bool: - return self._settings.debug_highlight_components # type: ignore[return-value] + return self._get_settings().debug_highlight_components # type: ignore[return-value] @property def DEBUG_HIGHLIGHT_SLOTS(self) -> bool: - return self._settings.debug_highlight_slots # type: ignore[return-value] + return self._get_settings().debug_highlight_slots # type: ignore[return-value] @property def DYNAMIC_COMPONENT_NAME(self) -> str: - return self._settings.dynamic_component_name # type: ignore[return-value] + return self._get_settings().dynamic_component_name # type: ignore[return-value] @property def LIBRARIES(self) -> List[str]: - return self._settings.libraries # type: ignore[return-value] + return self._get_settings().libraries # type: ignore[return-value] @property def EXTENSIONS(self) -> List["ComponentExtension"]: - return self._settings.extensions # type: ignore[return-value] + return self._get_settings().extensions # type: ignore[return-value] + + @property + def EXTENSIONS_DEFAULTS(self) -> Dict[str, Any]: + return self._get_settings().extensions_defaults # type: ignore[return-value] @property def MULTILINE_TAGS(self) -> bool: - return self._settings.multiline_tags # type: ignore[return-value] + return self._get_settings().multiline_tags # type: ignore[return-value] @property def RELOAD_ON_FILE_CHANGE(self) -> bool: - return self._settings.reload_on_file_change # type: ignore[return-value] + return self._get_settings().reload_on_file_change # type: ignore[return-value] @property def TEMPLATE_CACHE_SIZE(self) -> int: - return self._settings.template_cache_size # type: ignore[return-value] + return self._get_settings().template_cache_size # type: ignore[return-value] @property def STATIC_FILES_ALLOWED(self) -> Sequence[Union[str, re.Pattern]]: - return self._settings.static_files_allowed # type: ignore[return-value] + return self._get_settings().static_files_allowed # type: ignore[return-value] @property def STATIC_FILES_FORBIDDEN(self) -> Sequence[Union[str, re.Pattern]]: - return self._settings.static_files_forbidden # type: ignore[return-value] + return self._get_settings().static_files_forbidden # type: ignore[return-value] @property def CONTEXT_BEHAVIOR(self) -> ContextBehavior: - return ContextBehavior(self._settings.context_behavior) + return ContextBehavior(self._get_settings().context_behavior) @property def TAG_FORMATTER(self) -> Union["TagFormatterABC", str]: - return self._settings.tag_formatter # type: ignore[return-value] + return self._get_settings().tag_formatter # type: ignore[return-value] app_settings = InternalSettings() diff --git a/src/django_components/apps.py b/src/django_components/apps.py index 3a5e4a91..15217168 100644 --- a/src/django_components/apps.py +++ b/src/django_components/apps.py @@ -4,6 +4,7 @@ from typing import Any from django.apps import AppConfig from django.template import Template +from django.template.loader_tags import IncludeNode from django.utils.autoreload import file_changed, trigger_reload @@ -18,14 +19,13 @@ class ComponentsConfig(AppConfig): from django_components.component_registry import registry from django_components.components.dynamic import DynamicComponent from django_components.extension import extensions - from django_components.util.django_monkeypatch import monkeypatch_template_cls - - app_settings._load_settings() + from django_components.util.django_monkeypatch import monkeypatch_include_node, monkeypatch_template_cls # NOTE: This monkeypatch is applied here, before Django processes any requests. # To make django-components work with django-debug-toolbar-template-profiler # See https://github.com/django-components/django-components/discussions/819 monkeypatch_template_cls(Template) + monkeypatch_include_node(IncludeNode) # Import modules set in `COMPONENTS.libraries` setting import_libraries() diff --git a/src/django_components/cache.py b/src/django_components/cache.py index a14954ed..0b4c443d 100644 --- a/src/django_components/cache.py +++ b/src/django_components/cache.py @@ -1,3 +1,4 @@ +import sys from typing import Optional from django.core.cache import BaseCache, caches @@ -36,9 +37,14 @@ def get_component_media_cache() -> BaseCache: component_media_cache = LocMemCache( "django-components-media", { - "TIMEOUT": None, # No timeout - "MAX_ENTRIES": None, # No max size - "CULL_FREQUENCY": 3, + # No max size nor timeout + # NOTE: Implementation of `BaseCache` coerces the `MAX_ENTRIES` value + # to `int()` so we use exact max size instead of `inf` or `None`. + # See https://github.com/django/django/blob/94ebcf8366d62f6360851b40e9c4dfe3f71d202f/django/core/cache/backends/base.py#L73 # noqa: E501 + "TIMEOUT": None, + "OPTIONS": { + "MAX_ENTRIES": sys.maxsize, + }, }, ) diff --git a/src/django_components/commands/ext_run.py b/src/django_components/commands/ext_run.py index af2825cf..d1dd0a8a 100644 --- a/src/django_components/commands/ext_run.py +++ b/src/django_components/commands/ext_run.py @@ -19,8 +19,11 @@ from django_components.util.command import ComponentCommand def _gen_subcommands() -> List[Type[ComponentCommand]]: commands: List[Type[ComponentCommand]] = [] for extension in extensions.extensions: + if not extension.commands: + continue + ExtCommand = type( - "ExtCommand", + "ExtRunSubcommand_" + extension.name, (ComponentCommand,), { "name": extension.name, diff --git a/src/django_components/component.py b/src/django_components/component.py index 7caee9da..b7245a1d 100644 --- a/src/django_components/component.py +++ b/src/django_components/component.py @@ -32,7 +32,7 @@ from django_components.component_media import ComponentMediaInput, ComponentMedi from django_components.component_registry import ComponentRegistry from django_components.component_registry import registry as registry_ from django_components.constants import COMP_ID_PREFIX -from django_components.context import _COMPONENT_CONTEXT_KEY, make_isolated_context_copy +from django_components.context import _COMPONENT_CONTEXT_KEY, COMPONENT_IS_NESTED_KEY, make_isolated_context_copy from django_components.dependencies import ( DependenciesStrategy, cache_component_css, @@ -2277,7 +2277,7 @@ class Component(metaclass=ComponentMeta): deps_strategy = cast(DependenciesStrategy, default(deps_strategy, "document")) - self.id = default(id, _gen_component_id, factory=True) + self.id = default(id, _gen_component_id, factory=True) # type: ignore[arg-type] self.name = _get_component_name(self.__class__, registered_name) self.registered_name: Optional[str] = registered_name self.args = default(args, []) @@ -2314,9 +2314,6 @@ class Component(metaclass=ComponentMeta): cls.class_id = hash_comp_cls(cls) comp_cls_id_mapping[cls.class_id] = cls - # Make sure that subclassed component will store it's own template, not the parent's. - cls._template = None - ALL_COMPONENTS.append(cached_ref(cls)) # type: ignore[arg-type] extensions._init_component_class(cls) extensions.on_component_class_created(OnComponentClassCreatedContext(cls)) @@ -3489,11 +3486,12 @@ class Component(metaclass=ComponentMeta): ) ) - # Process Component's JS and CSS - cache_component_js(comp_cls) - js_input_hash = cache_component_js_vars(comp_cls, js_data) if js_data else None + # Cache component's JS and CSS scripts, in case they have been evicted from the cache. + cache_component_js(comp_cls, force=False) + cache_component_css(comp_cls, force=False) - cache_component_css(comp_cls) + # Create JS/CSS scripts that will load the JS/CSS variables into the page. + js_input_hash = cache_component_js_vars(comp_cls, js_data) if js_data else None css_input_hash = cache_component_css_vars(comp_cls, css_data) if css_data else None ############################################################################# @@ -3517,14 +3515,14 @@ class Component(metaclass=ComponentMeta): # Then we can simply apply `template_data` to the context in the same layer # where we apply `context_processor_data` and `component_vars`. with prepare_component_template(component, template_data) as template: - # Set `Template._djc_is_component_nested` based on whether we're currently INSIDE + # Set `_DJC_COMPONENT_IS_NESTED` based on whether we're currently INSIDE # the `{% extends %}` tag. # Part of fix for https://github.com/django-components/django-components/issues/508 # See django_monkeypatch.py if template is not None: - template._djc_is_component_nested = bool( - context.render_context.get(BLOCK_CONTEXT_KEY) # type: ignore[union-attr] - ) + comp_is_nested = bool(context.render_context.get(BLOCK_CONTEXT_KEY)) # type: ignore[union-attr] + else: + comp_is_nested = False # Capture the template name so we can print better error messages (currently used in slots) component_ctx.template_name = template.name if template else None @@ -3535,6 +3533,7 @@ class Component(metaclass=ComponentMeta): **component.context_processors_data, # Private context fields _COMPONENT_CONTEXT_KEY: render_id, + COMPONENT_IS_NESTED_KEY: comp_is_nested, # NOTE: Public API for variables accessible from within a component's template # See https://github.com/django-components/django-components/issues/280#issuecomment-2081180940 "component_vars": ComponentVars( @@ -3672,7 +3671,7 @@ class Component(metaclass=ComponentMeta): # ``` def _gen_component_renderer( self, - template: Template, + template: Optional[Template], context: Context, component_path: List[str], css_input_hash: Optional[str], @@ -3697,7 +3696,8 @@ class Component(metaclass=ComponentMeta): component.on_render_before(context, template) # Emit signal that the template is about to be rendered - template_rendered.send(sender=template, template=template, context=context) + if template is not None: + template_rendered.send(sender=template, template=template, context=context) # Get the component's HTML # To access the *final* output (with all its children rendered) from within `Component.on_render()`, diff --git a/src/django_components/component_media.py b/src/django_components/component_media.py index 42442d83..d3957c78 100644 --- a/src/django_components/component_media.py +++ b/src/django_components/component_media.py @@ -27,10 +27,12 @@ from weakref import WeakKeyDictionary from django.contrib.staticfiles import finders from django.core.exceptions import ImproperlyConfigured from django.forms.widgets import Media as MediaCls +from django.template import Template from django.utils.safestring import SafeData from typing_extensions import TypeGuard -from django_components.template import load_component_template +from django_components.extension import OnCssLoadedContext, OnJsLoadedContext, extensions +from django_components.template import ensure_unique_template, load_component_template from django_components.util.loader import get_component_dirs, resolve_file from django_components.util.logger import logger from django_components.util.misc import flatten, get_import_path, get_module_info, is_glob @@ -43,7 +45,7 @@ T = TypeVar("T") # These are all the attributes that are handled by ComponentMedia and lazily-resolved -COMP_MEDIA_LAZY_ATTRS = ("media", "template", "template_file", "js", "js_file", "css", "css_file") +COMP_MEDIA_LAZY_ATTRS = ("media", "template", "template_file", "js", "js_file", "css", "css_file", "_template") # Sentinel value to indicate that a media attribute is not set. @@ -267,6 +269,8 @@ class ComponentMedia: js_file: Union[str, Unset, None] = UNSET css: Union[str, Unset, None] = UNSET css_file: Union[str, Unset, None] = UNSET + # Template instance that was loaded for this component + _template: Union[Template, Unset, None] = UNSET def __post_init__(self) -> None: for inlined_attr in ("template", "js", "css"): @@ -299,6 +303,7 @@ class ComponentMedia: def reset(self) -> None: self.__dict__.update(self._original.__dict__) self.resolved = False + self.resolved_relative_files = False # This metaclass is all about one thing - lazily resolving the media files. @@ -487,6 +492,10 @@ def _get_comp_cls_media(comp_cls: Type["Component"]) -> Any: if curr_cls in media_cache: continue + comp_media: Optional[ComponentMedia] = getattr(curr_cls, "_component_media", None) + if comp_media is not None and not comp_media.resolved: + _resolve_media(curr_cls, comp_media) + # Prepare base classes # NOTE: If the `Component.Media` class is explicitly set to `None`, then we should not inherit # from any parent classes. @@ -611,20 +620,39 @@ def _resolve_media(comp_cls: Type["Component"], comp_media: ComponentMedia) -> N # Effectively, even if the Component class defined `js_file` (or others), at "runtime" the `js` attribute # will be set to the content of the file. # So users can access `Component.js` even if they defined `Component.js_file`. - comp_media.template = _get_asset( + template_str, template_obj = _get_asset( comp_cls, comp_media, inlined_attr="template", file_attr="template_file", comp_dirs=comp_dirs, - type="template", - ) - comp_media.js = _get_asset( - comp_cls, comp_media, inlined_attr="js", file_attr="js_file", comp_dirs=comp_dirs, type="static" - ) - comp_media.css = _get_asset( - comp_cls, comp_media, inlined_attr="css", file_attr="css_file", comp_dirs=comp_dirs, type="static" ) + comp_media.template = template_str + + js_str, _ = _get_asset(comp_cls, comp_media, inlined_attr="js", file_attr="js_file", comp_dirs=comp_dirs) + comp_media.js = js_str + + css_str, _ = _get_asset(comp_cls, comp_media, inlined_attr="css", file_attr="css_file", comp_dirs=comp_dirs) + comp_media.css = css_str + + # If `Component.template` or `Component.template_file` were explicitly set on this class, + # then Template instance was already created. + # + # Otherwise, search for Template instance in parent classes, and make a copy of it. + if not isinstance(template_obj, Unset): + comp_media._template = template_obj + else: + parent_template = _get_comp_cls_attr(comp_cls, "_template") + + # One of base classes has set `template` or `template_file` to `None`, + # or none of the base classes had set `template` or `template_file` + if parent_template is None: + comp_media._template = parent_template + + # One of base classes has set `template` or `template_file` to string. + # Make a copy of the Template instance. + else: + comp_media._template = ensure_unique_template(comp_cls, parent_template) def _normalize_media(media: Type[ComponentMediaInput]) -> None: @@ -973,11 +1001,10 @@ def _find_component_dir_containing_file( def _get_asset( comp_cls: Type["Component"], comp_media: ComponentMedia, - inlined_attr: str, - file_attr: str, + inlined_attr: Literal["template", "js", "css"], + file_attr: Literal["template_file", "js_file", "css_file"], comp_dirs: List[Path], - type: Literal["template", "static"], -) -> Union[str, Unset, None]: +) -> Tuple[Union[str, Unset, None], Union[Template, Unset, None]]: # Tuple of (content, Template) """ In case of Component's JS or CSS, one can either define that as "inlined" or as a file. @@ -1010,7 +1037,7 @@ def _get_asset( # pass # ``` if asset_content is UNSET and asset_file is UNSET: - return UNSET + return UNSET, UNSET # Either file or content attr was set to `None` # ```py @@ -1031,7 +1058,7 @@ def _get_asset( if (asset_content in (UNSET, None) and asset_file is None) or ( asset_content is None and asset_file in (UNSET, None) ): - return None + return None, None # Received both inlined content and file name # ```py @@ -1061,42 +1088,68 @@ def _get_asset( # At this point we can tell that only EITHER `asset_content` OR `asset_file` is set. # If the content was inlined into the component (e.g. `Component.template = "..."`) - # then there's nothing to resolve. Return as is. - if asset_content is not UNSET: - return asset_content + # then there's nothing to resolve. Use it as is. + if not isinstance(asset_content, Unset): + if asset_content is None: + return None, None - if asset_file is None: - return None + content: str = asset_content - # The rest of the code assumes that we were given only a file name - asset_file = cast(str, asset_file) + # If we got inlined `Component.template`, then create a Template instance from it + # to trigger the extension hooks that may modify the template string. + if inlined_attr == "template": + # NOTE: `load_component_template()` applies `on_template_loaded()` and `on_template_compiled()` hooks. + template = load_component_template(comp_cls, filepath=None, content=content) + return template.source, template - if type == "template": - # NOTE: While we return on the "source" (plain string) of the template, - # by calling `load_component_template()`, we also cache the Template instance. - # So later in Component's `render_impl()`, we don't have to re-compile the Template. - template = load_component_template(comp_cls, asset_file) - return template.source + # This else branch assumes that we were given a file name (possibly None) + # Load the contents of the file. + else: + if asset_file is None: + return None, None - # For static files, we have a few options: - # 1. Check if the file is in one of the components' directories - full_path = resolve_file(asset_file, comp_dirs) + asset_file = cast(str, asset_file) - # 2. If not, check if it's in the static files - if full_path is None: - full_path = finders.find(asset_file) + if inlined_attr == "template": + # NOTE: `load_component_template()` applies `on_template_loaded()` and `on_template_compiled()` hooks. + template = load_component_template(comp_cls, filepath=asset_file, content=None) + return template.source, template - if full_path is None: - # NOTE: The short name, e.g. `js` or `css` is used in the error message for convenience - raise ValueError(f"Could not find {inlined_attr} file {asset_file}") + # Following code concerns with loading JS / CSS files. + # Here we have a few options: + # + # 1. Check if the file is in one of the components' directories + full_path = resolve_file(asset_file, comp_dirs) - # NOTE: Use explicit encoding for compat with Windows, see #1074 - asset_content = Path(full_path).read_text(encoding="utf8") + # 2. If not, check if it's in the static files + if full_path is None: + full_path = finders.find(asset_file) - # TODO: Apply `extensions.on_js_preprocess()` and `extensions.on_css_preprocess()` - # NOTE: `on_template_preprocess()` is already applied inside `load_component_template()` + if full_path is None: + # NOTE: The short name, e.g. `js` or `css` is used in the error message for convenience + raise ValueError(f"Could not find {inlined_attr} file {asset_file}") - return asset_content + # NOTE: Use explicit encoding for compat with Windows, see #1074 + content = Path(full_path).read_text(encoding="utf8") + + # NOTE: `on_template_loaded()` is already applied inside `load_component_template()` + # but we still need to call extension hooks for JS / CSS content (whether inlined or not). + if inlined_attr == "js": + content = extensions.on_js_loaded( + OnJsLoadedContext( + component_cls=comp_cls, + content=content, + ) + ) + elif inlined_attr == "css": + content = extensions.on_css_loaded( + OnCssLoadedContext( + component_cls=comp_cls, + content=content, + ) + ) + + return content, None def is_set(value: Union[T, Unset, None]) -> TypeGuard[T]: diff --git a/src/django_components/context.py b/src/django_components/context.py index 6dfe7cf6..71cb0c61 100644 --- a/src/django_components/context.py +++ b/src/django_components/context.py @@ -11,6 +11,7 @@ from django.template import Context from django_components.util.misc import get_last_index _COMPONENT_CONTEXT_KEY = "_DJC_COMPONENT_CTX" +COMPONENT_IS_NESTED_KEY = "_DJC_COMPONENT_IS_NESTED" _STRATEGY_CONTEXT_KEY = "DJC_DEPS_STRATEGY" _INJECT_CONTEXT_KEY_PREFIX = "_DJC_INJECT__" diff --git a/src/django_components/dependencies.py b/src/django_components/dependencies.py index ffa06e7a..4f4a8830 100644 --- a/src/django_components/dependencies.py +++ b/src/django_components/dependencies.py @@ -107,13 +107,16 @@ def _cache_script( cache.set(cache_key, script.strip()) -def cache_component_js(comp_cls: Type["Component"]) -> None: +def cache_component_js(comp_cls: Type["Component"], force: bool) -> None: """ Cache the content from `Component.js`. This is the common JS that's shared among all instances of the same component. So even if the component is rendered multiple times, this JS is loaded only once. """ - if not comp_cls.js or not is_nonempty_str(comp_cls.js) or _is_script_in_cache(comp_cls, "js", None): + if not comp_cls.js or not is_nonempty_str(comp_cls.js): + return None + + if not force and _is_script_in_cache(comp_cls, "js", None): return None _cache_script( @@ -167,13 +170,16 @@ def wrap_component_js(comp_cls: Type["Component"], content: str) -> str: return f"" -def cache_component_css(comp_cls: Type["Component"]) -> None: +def cache_component_css(comp_cls: Type["Component"], force: bool) -> None: """ Cache the content from `Component.css`. This is the common CSS that's shared among all instances of the same component. So even if the component is rendered multiple times, this CSS is loaded only once. """ - if not comp_cls.css or not is_nonempty_str(comp_cls.css) or _is_script_in_cache(comp_cls, "css", None): + if not comp_cls.css or not is_nonempty_str(comp_cls.css): + return None + + if not force and _is_script_in_cache(comp_cls, "css", None): return None _cache_script( diff --git a/src/django_components/extension.py b/src/django_components/extension.py index 17750218..a95d9755 100644 --- a/src/django_components/extension.py +++ b/src/django_components/extension.py @@ -16,7 +16,7 @@ from typing import ( ) import django.urls -from django.template import Context +from django.template import Context, Origin, Template from django.urls import URLPattern, URLResolver, get_resolver, get_urlconf from django_components.app_settings import app_settings @@ -168,6 +168,42 @@ class OnSlotRenderedContext(NamedTuple): """The rendered result of the slot""" +@mark_extension_hook_api +class OnTemplateLoadedContext(NamedTuple): + component_cls: Type["Component"] + """The Component class whose template was loaded""" + content: str + """The template string""" + origin: Optional[Origin] + """The origin of the template""" + name: Optional[str] + """The name of the template""" + + +@mark_extension_hook_api +class OnTemplateCompiledContext(NamedTuple): + component_cls: Type["Component"] + """The Component class whose template was loaded""" + template: Template + """The compiled template object""" + + +@mark_extension_hook_api +class OnCssLoadedContext(NamedTuple): + component_cls: Type["Component"] + """The Component class whose CSS was loaded""" + content: str + """The CSS content (string)""" + + +@mark_extension_hook_api +class OnJsLoadedContext(NamedTuple): + component_cls: Type["Component"] + """The Component class whose JS was loaded""" + content: str + """The JS content (string)""" + + ################################################ # EXTENSIONS CORE ################################################ @@ -763,6 +799,108 @@ class ComponentExtension(metaclass=ExtensionMeta): """ pass + ########################## + # Template / JS / CSS hooks + ########################## + + def on_template_loaded(self, ctx: OnTemplateLoadedContext) -> Optional[str]: + """ + Called when a Component's template is loaded as a string. + + This hook runs only once per [`Component`](../api#django_components.Component) class and works for both + [`Component.template`](../api#django_components.Component.template) and + [`Component.template_file`](../api#django_components.Component.template_file). + + Use this hook to read or modify the template before it's compiled. + + To modify the template, return a new string from this hook. + + **Example:** + + ```python + from django_components import ComponentExtension, OnTemplateLoadedContext + + class MyExtension(ComponentExtension): + def on_template_loaded(self, ctx: OnTemplateLoadedContext) -> Optional[str]: + # Modify the template + return ctx.content.replace("Hello", "Hi") + ``` + """ + pass + + def on_template_compiled(self, ctx: OnTemplateCompiledContext) -> None: + """ + Called when a Component's template is compiled + into a [`Template`](https://docs.djangoproject.com/en/5.2/ref/templates/api/#django.template.Template) object. + + This hook runs only once per [`Component`](../api#django_components.Component) class and works for both + [`Component.template`](../api#django_components.Component.template) and + [`Component.template_file`](../api#django_components.Component.template_file). + + Use this hook to read or modify the template (in-place) after it's compiled. + + **Example:** + + ```python + from django_components import ComponentExtension, OnTemplateCompiledContext + + class MyExtension(ComponentExtension): + def on_template_compiled(self, ctx: OnTemplateCompiledContext) -> None: + print(f"Template origin: {ctx.template.origin.name}") + ``` + """ + pass + + def on_css_loaded(self, ctx: OnCssLoadedContext) -> Optional[str]: + """ + Called when a Component's CSS is loaded as a string. + + This hook runs only once per [`Component`](../api#django_components.Component) class and works for both + [`Component.css`](../api#django_components.Component.css) and + [`Component.css_file`](../api#django_components.Component.css_file). + + Use this hook to read or modify the CSS. + + To modify the CSS, return a new string from this hook. + + **Example:** + + ```python + from django_components import ComponentExtension, OnCssLoadedContext + + class MyExtension(ComponentExtension): + def on_css_loaded(self, ctx: OnCssLoadedContext) -> Optional[str]: + # Modify the CSS + return ctx.content.replace("Hello", "Hi") + ``` + """ + pass + + def on_js_loaded(self, ctx: OnJsLoadedContext) -> Optional[str]: + """ + Called when a Component's JS is loaded as a string. + + This hook runs only once per [`Component`](../api#django_components.Component) class and works for both + [`Component.js`](../api#django_components.Component.js) and + [`Component.js_file`](../api#django_components.Component.js_file). + + Use this hook to read or modify the JS. + + To modify the JS, return a new string from this hook. + + **Example:** + + ```python + from django_components import ComponentExtension, OnCssLoadedContext + + class MyExtension(ComponentExtension): + def on_js_loaded(self, ctx: OnJsLoadedContext) -> Optional[str]: + # Modify the JS + return ctx.content.replace("Hello", "Hi") + ``` + """ + pass + ########################## # Tags lifecycle hooks ########################## @@ -909,7 +1047,7 @@ class ExtensionManager: # - `MyExtensionBase` is the base class that the extension class inherits from. bases_list = [ext_base_class] - all_extensions_defaults = app_settings._settings.extensions_defaults or {} + all_extensions_defaults = app_settings.EXTENSIONS_DEFAULTS or {} extension_defaults = all_extensions_defaults.get(extension.name, None) if extension_defaults: # Create dummy class that holds the extension defaults @@ -1169,9 +1307,34 @@ class ExtensionManager: return ctx.result, ctx.error ########################## - # Tags lifecycle hooks + # Template / JS / CSS hooks ########################## + def on_template_loaded(self, ctx: OnTemplateLoadedContext) -> str: + for extension in self.extensions: + content = extension.on_template_loaded(ctx) + if content is not None: + ctx = ctx._replace(content=content) + return ctx.content + + def on_template_compiled(self, ctx: OnTemplateCompiledContext) -> None: + for extension in self.extensions: + extension.on_template_compiled(ctx) + + def on_css_loaded(self, ctx: OnCssLoadedContext) -> str: + for extension in self.extensions: + content = extension.on_css_loaded(ctx) + if content is not None: + ctx = ctx._replace(content=content) + return ctx.content + + def on_js_loaded(self, ctx: OnJsLoadedContext) -> str: + for extension in self.extensions: + content = extension.on_js_loaded(ctx) + if content is not None: + ctx = ctx._replace(content=content) + return ctx.content + def on_slot_rendered(self, ctx: OnSlotRenderedContext) -> Optional[str]: for extension in self.extensions: result = extension.on_slot_rendered(ctx) diff --git a/src/django_components/extensions/dependencies.py b/src/django_components/extensions/dependencies.py new file mode 100644 index 00000000..20c4d444 --- /dev/null +++ b/src/django_components/extensions/dependencies.py @@ -0,0 +1,21 @@ +from django_components.dependencies import cache_component_css, cache_component_js +from django_components.extension import ( + ComponentExtension, + OnComponentClassCreatedContext, +) + + +class DependenciesExtension(ComponentExtension): + """ + This extension adds a nested `Dependencies` class to each `Component`. + + This extension is automatically added to all components. + """ + + name = "dependencies" + + # Cache the component's JS and CSS scripts when the class is created, so that + # components' JS/CSS files are accessible even before having to render the component first. + def on_component_class_created(self, ctx: OnComponentClassCreatedContext) -> None: + cache_component_js(ctx.component_cls, force=True) + cache_component_css(ctx.component_cls, force=True) diff --git a/src/django_components/slots.py b/src/django_components/slots.py index dfc653f0..69c60b10 100644 --- a/src/django_components/slots.py +++ b/src/django_components/slots.py @@ -28,7 +28,7 @@ from django.utils.html import conditional_escape from django.utils.safestring import SafeString, mark_safe from django_components.app_settings import ContextBehavior -from django_components.context import _COMPONENT_CONTEXT_KEY, _INJECT_CONTEXT_KEY_PREFIX +from django_components.context import _COMPONENT_CONTEXT_KEY, _INJECT_CONTEXT_KEY_PREFIX, COMPONENT_IS_NESTED_KEY from django_components.extension import OnSlotRenderedContext, extensions from django_components.node import BaseNode from django_components.perfutil.component import component_context_cache @@ -1585,8 +1585,6 @@ def _nodelist_to_slot( # and binds the context. template = Template("") template.nodelist = nodelist - # This allows the template to access current RenderContext layer. - template._djc_is_component_nested = True def render_func(ctx: SlotContext) -> SlotResult: context = ctx.context or Context() @@ -1639,10 +1637,12 @@ def _nodelist_to_slot( trace_component_msg("RENDER_NODELIST", component_name, component_id=None, slot_name=slot_name) - # We wrap the slot nodelist in Template. However, we also override Django's `Template.render()` - # to call `render_dependencies()` on the results. So we need to set the strategy to `ignore` - # so that the dependencies are processed only once the whole component tree is rendered. - with context.push({"DJC_DEPS_STRATEGY": "ignore"}): + # NOTE 1: We wrap the slot nodelist in Template. However, we also override Django's `Template.render()` + # to call `render_dependencies()` on the results. So we need to set the strategy to `ignore` + # so that the dependencies are processed only once the whole component tree is rendered. + # NOTE 2: We also set `_DJC_COMPONENT_IS_NESTED` to `True` so that the template can access + # current RenderContext layer. + with context.push({"DJC_DEPS_STRATEGY": "ignore", COMPONENT_IS_NESTED_KEY: True}): rendered = template.render(context) # After the rendering is done, remove the `extra_context` from the context stack diff --git a/src/django_components/template.py b/src/django_components/template.py index 24abce6d..6b6ebb24 100644 --- a/src/django_components/template.py +++ b/src/django_components/template.py @@ -1,6 +1,6 @@ import sys from contextlib import contextmanager -from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Type, Union, cast +from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Type, Union from weakref import ReferenceType, ref from django.core.exceptions import ImproperlyConfigured @@ -8,7 +8,7 @@ from django.template import Context, Origin, Template from django.template.loader import get_template as django_get_template from django_components.cache import get_template_cache -from django_components.util.django_monkeypatch import is_template_cls_patched +from django_components.util.django_monkeypatch import is_cls_patched from django_components.util.loader import get_component_dirs from django_components.util.logger import trace_component_msg from django_components.util.misc import get_import_path, get_module_info @@ -98,7 +98,7 @@ def prepare_component_template( yield template return - if not is_template_cls_patched(template): + if not is_cls_patched(template): raise RuntimeError( "Django-components received a Template instance which was not patched." "If you are using Django's Template class, check if you added django-components" @@ -170,30 +170,45 @@ def _maybe_bind_template(context: Context, template: Template) -> Generator[None loading_components: List["ComponentRef"] = [] -def load_component_template(component_cls: Type["Component"], filepath: str) -> Template: - if component_cls._template is not None: - return component_cls._template +def load_component_template( + component_cls: Type["Component"], + filepath: Optional[str] = None, + content: Optional[str] = None, +) -> Template: + if filepath is None and content is None: + raise ValueError("Either `filepath` or `content` must be provided.") loading_components.append(ref(component_cls)) - # Use Django's `get_template()` to load the template - template = _load_django_template(filepath) + if filepath is not None: + # Use Django's `get_template()` to load the template file + template = _load_django_template(filepath) + template = ensure_unique_template(component_cls, template) - # If template.origin.component_cls is already set, then this - # Template instance was cached by Django / template loaders. - # In that case we want to make a copy of the template which would - # be owned by the current Component class. - # Thus each Component has it's own Template instance with their own Origins - # pointing to the correct Component class. - if get_component_from_origin(template.origin) is not None: + elif content is not None: + template = _create_template_from_string(component_cls, content, is_component_template=True) + else: + raise ValueError("Received both `filepath` and `content`. These are mutually exclusive.") + + loading_components.pop() + + return template + + +# When loading a Template instance, it may be cached by Django / template loaders. +# In that case we want to make a copy of the template which would +# be owned by the current Component class. +# Thus each Component has it's own Template instance with their own Origins +# pointing to the correct Component class. +def ensure_unique_template(component_cls: Type["Component"], template: Template) -> Template: + # Use `template.origin.component_cls` to check if the template was cached by Django / template loaders. + if get_component_from_origin(template.origin) is None: + set_component_to_origin(template.origin, component_cls) + else: origin_copy = Origin(template.origin.name, template.origin.template_name, template.origin.loader) set_component_to_origin(origin_copy, component_cls) template = Template(template.source, origin=origin_copy, name=template.name, engine=template.engine) - component_cls._template = template - - loading_components.pop() - return template @@ -250,24 +265,13 @@ def _get_component_template(component: "Component") -> Optional[Template]: template = None template_string = template_sources["get_template"] elif component.template or component.template_file: - # If the template was loaded from `Component.template_file`, then the Template - # instance was already created and cached in `Component._template`. + # If the template was loaded from `Component.template` or `Component.template_file`, + # then the Template instance was already created and cached in `Component._template`. # # NOTE: This is important to keep in mind, because the implication is that we should # treat Templates AND their nodelists as IMMUTABLE. - if component.__class__._template is not None: - template = component.__class__._template - template_string = None - # Otherwise user have set `Component.template` as string and we still need to - # create the instance. - else: - template = _create_template_from_string( - component, - # NOTE: We can't reach this branch if `Component.template` is None - cast(str, component.template), - is_component_template=True, - ) - template_string = None + template = component.__class__._component_media._template # type: ignore[attr-defined] + template_string = None # No template else: template = None @@ -278,7 +282,7 @@ def _get_component_template(component: "Component") -> Optional[Template]: return template # Create the template from the string elif template_string is not None: - return _create_template_from_string(component, template_string) + return _create_template_from_string(component.__class__, template_string) # Otherwise, Component has no template - this is valid, as it may be instead rendered # via `Component.on_render()` @@ -286,7 +290,7 @@ def _get_component_template(component: "Component") -> Optional[Template]: def _create_template_from_string( - component: "Component", + component: Type["Component"], template_string: str, is_component_template: bool = False, ) -> Template: @@ -307,18 +311,17 @@ def _create_template_from_string( # ``` # # See https://docs.djangoproject.com/en/5.2/howto/custom-template-backend/#template-origin-api - _, _, module_filepath = get_module_info(component.__class__) + _, _, module_filepath = get_module_info(component) origin = Origin( - name=f"{module_filepath}::{component.__class__.__name__}", + name=f"{module_filepath}::{component.__name__}", template_name=None, loader=None, ) - set_component_to_origin(origin, component.__class__) + set_component_to_origin(origin, component) if is_component_template: template = Template(template_string, name=origin.template_name, origin=origin) - component.__class__._template = template else: # TODO_V1 - `cached_template()` won't be needed as there will be only 1 template per component # so we will be able to instead use `template_cache` to store the template diff --git a/src/django_components/util/django_monkeypatch.py b/src/django_components/util/django_monkeypatch.py index 6ee295b0..722eba02 100644 --- a/src/django_components/util/django_monkeypatch.py +++ b/src/django_components/util/django_monkeypatch.py @@ -1,23 +1,28 @@ from typing import Any, Optional, Type from django.template import Context, NodeList, Template -from django.template.base import Origin, Parser +from django.template.base import Node, Origin, Parser +from django.template.loader_tags import IncludeNode -from django_components.context import _COMPONENT_CONTEXT_KEY, _STRATEGY_CONTEXT_KEY +from django_components.context import _COMPONENT_CONTEXT_KEY, _STRATEGY_CONTEXT_KEY, COMPONENT_IS_NESTED_KEY from django_components.dependencies import COMPONENT_COMMENT_REGEX, render_dependencies +from django_components.extension import OnTemplateCompiledContext, OnTemplateLoadedContext, extensions from django_components.util.template_parser import parse_template # In some cases we can't work around Django's design, and need to patch the template class. def monkeypatch_template_cls(template_cls: Type[Template]) -> None: + if is_cls_patched(template_cls): + return + monkeypatch_template_init(template_cls) monkeypatch_template_compile_nodelist(template_cls) monkeypatch_template_render(template_cls) template_cls._djc_patched = True -# Patch `Template.__init__` to apply `extensions.on_template_preprocess()` if the template -# belongs to a Component. +# Patch `Template.__init__` to apply `on_template_loaded()` and `on_template_compiled()` +# extension hooks if the template belongs to a Component. def monkeypatch_template_init(template_cls: Type[Template]) -> None: original_init = template_cls.__init__ @@ -27,6 +32,7 @@ def monkeypatch_template_init(template_cls: Type[Template]) -> None: self: Template, template_string: Any, origin: Optional[Origin] = None, + name: Optional[str] = None, *args: Any, **kwargs: Any, ) -> None: @@ -56,11 +62,27 @@ def monkeypatch_template_init(template_cls: Type[Template]) -> None: component_cls = None if component_cls is not None: - # TODO - Apply extensions.on_template_preprocess() here. - # Then also test both cases when template as `template` or `template_file`. - pass + template_string = str(template_string) + template_string = extensions.on_template_loaded( + OnTemplateLoadedContext( + component_cls=component_cls, + content=template_string, + origin=origin, + name=name, + ) + ) - original_init(self, template_string, origin, *args, **kwargs) # type: ignore[misc] + # Calling original `Template.__init__` should also compile the template into a Nodelist + # via `Template.compile_nodelist()`. + original_init(self, template_string, origin, name, *args, **kwargs) # type: ignore[misc] + + if component_cls is not None: + extensions.on_template_compiled( + OnTemplateCompiledContext( + component_cls=component_cls, + template=self, + ) + ) template_cls.__init__ = __init__ @@ -110,7 +132,7 @@ def monkeypatch_template_compile_nodelist(template_cls: Type[Template]) -> None: def monkeypatch_template_render(template_cls: Type[Template]) -> None: # Modify `Template.render` to set `isolated_context` kwarg of `push_state` - # based on our custom `Template._djc_is_component_nested`. + # based on our custom `_DJC_COMPONENT_IS_NESTED`. # # Part of fix for https://github.com/django-components/django-components/issues/508 # @@ -125,11 +147,11 @@ def monkeypatch_template_render(template_cls: Type[Template]) -> None: # doesn't require the source to be parsed multiple times. User can pass extra args/kwargs, # and can modify the rendering behavior by overriding the `_render` method. # - # NOTE 2: Instead of setting `Template._djc_is_component_nested`, alternatively we could + # NOTE 2: Instead of setting `_DJC_COMPONENT_IS_NESTED` context key, alternatively we could # have passed the value to `monkeypatch_template_render` directly. However, we intentionally # did NOT do that, so the monkey-patched method is more robust, and can be e.g. copied # to other. - if is_template_cls_patched(template_cls): + if is_cls_patched(template_cls): # Do not patch if done so already. This helps us avoid RecursionError return @@ -137,12 +159,12 @@ def monkeypatch_template_render(template_cls: Type[Template]) -> None: def _template_render(self: Template, context: Context, *args: Any, **kwargs: Any) -> str: "Display stage -- can be called many times" # We parametrized `isolated_context`, which was `True` in the original method. - if not hasattr(self, "_djc_is_component_nested"): + if COMPONENT_IS_NESTED_KEY not in context: isolated_context = True else: # MUST be `True` for templates that are NOT import with `{% extends %}` tag, # and `False` otherwise. - isolated_context = not self._djc_is_component_nested + isolated_context = not context[COMPONENT_IS_NESTED_KEY] # This is original implementation, except we override `isolated_context`, # and we post-process the result with `render_dependencies()`. @@ -189,5 +211,37 @@ def monkeypatch_template_render(template_cls: Type[Template]) -> None: template_cls.render = _template_render -def is_template_cls_patched(template_cls: Type[Template]) -> bool: - return getattr(template_cls, "_djc_patched", False) +def monkeypatch_include_node(include_node_cls: Type[Node]) -> None: + if is_cls_patched(include_node_cls): + return + + monkeypatch_include_render(include_node_cls) + include_node_cls._djc_patched = True + + +def monkeypatch_include_render(include_node_cls: Type[Node]) -> None: + # Modify `IncludeNode.render()` (what renders `{% include %}` tag) so that the included + # template does NOT render the JS/CSS by itself. + # + # Instead, we want the parent template + # (which contains the `{% component %}` tag) to decide whether to render the JS/CSS. + # + # We achieve this by setting `DJC_DEPS_STRATEGY` to `ignore` in the context. + # + # Fix for https://github.com/django-components/django-components/issues/1296 + if is_cls_patched(include_node_cls): + # Do not patch if done so already. This helps us avoid RecursionError + return + + orig_include_render = include_node_cls.render + + # NOTE: This implementation is based on Django v5.1.3) + def _include_render(self: IncludeNode, context: Context, *args: Any, **kwargs: Any) -> str: + with context.update({_STRATEGY_CONTEXT_KEY: "ignore"}): + return orig_include_render(self, context, *args, **kwargs) + + include_node_cls.render = _include_render + + +def is_cls_patched(cls: Type[Any]) -> bool: + return getattr(cls, "_djc_patched", False) diff --git a/src/django_components/util/exception.py b/src/django_components/util/exception.py index b7dbb97b..dc57b7c3 100644 --- a/src/django_components/util/exception.py +++ b/src/django_components/util/exception.py @@ -25,7 +25,7 @@ def component_error_message(component_path: List[str]) -> Generator[None, None, if not components: orig_msg = str(err.args[0]) else: - orig_msg = err.args[0].split("\n", 1)[-1] + orig_msg = str(err.args[0]).split("\n", 1)[-1] else: orig_msg = str(err) diff --git a/tests/templates/test_cached_component_inside_include_base.html b/tests/templates/component_inside_include_base.html similarity index 58% rename from tests/templates/test_cached_component_inside_include_base.html rename to tests/templates/component_inside_include_base.html index 260d3df5..2711df5f 100644 --- a/tests/templates/test_cached_component_inside_include_base.html +++ b/tests/templates/component_inside_include_base.html @@ -1,4 +1,4 @@ -{% include "test_cached_component_inside_include_sub.html" %} +{% include "component_inside_include_sub.html" %} {% block content %} THIS_IS_IN_BASE_TEMPLATE_SO_SHOULD_BE_OVERRIDDEN {% endblock %} \ No newline at end of file diff --git a/tests/templates/test_cached_component_inside_include_sub.html b/tests/templates/component_inside_include_sub.html similarity index 100% rename from tests/templates/test_cached_component_inside_include_sub.html rename to tests/templates/component_inside_include_sub.html diff --git a/tests/test_autodiscover.py b/tests/test_autodiscover.py index 142a0552..03aee405 100644 --- a/tests/test_autodiscover.py +++ b/tests/test_autodiscover.py @@ -50,8 +50,6 @@ class TestImportLibraries: } ) def test_import_libraries(self): - # Ensure we start with a clean state - registry.clear() all_components = registry.all().copy() assert "single_file_component" not in all_components assert "multi_file_component" not in all_components @@ -80,8 +78,6 @@ class TestImportLibraries: } ) def test_import_libraries_map_modules(self): - # Ensure we start with a clean state - registry.clear() all_components = registry.all().copy() assert "single_file_component" not in all_components assert "multi_file_component" not in all_components diff --git a/tests/test_cache.py b/tests/test_cache.py index 8a7b7bdd..58630a93 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -1,5 +1,3 @@ -from django.core.cache.backends.locmem import LocMemCache - from django_components import Component, register from django_components.testing import djc_test from django_components.util.cache import LRUCache @@ -68,16 +66,26 @@ class TestCache: @djc_test class TestComponentMediaCache: - @djc_test(components_settings={"cache": "test-cache"}) - def test_component_media_caching(self): - test_cache = LocMemCache( - "test-cache", - { - "TIMEOUT": None, # No timeout - "MAX_ENTRIES": None, # No max size - "CULL_FREQUENCY": 3, + @djc_test( + components_settings={"cache": "test-cache"}, + django_settings={ + "CACHES": { + # See https://docs.djangoproject.com/en/5.2/topics/cache/#local-memory-caching + "test-cache": { + "BACKEND": "django.core.cache.backends.locmem.LocMemCache", + "LOCATION": "test-cache", + "TIMEOUT": None, # No timeout + "OPTIONS": { + "MAX_ENTRIES": 10_000, + }, + }, }, - ) + }, + ) + def test_component_media_caching(self): + from django.core.cache import caches + + test_cache = caches["test-cache"] @register("test_simple") class TestSimpleComponent(Component): @@ -108,14 +116,6 @@ class TestComponentMediaCache: def get_css_data(self, args, kwargs, slots, context): return {"color": "blue"} - # Register our test cache - from django.core.cache import caches - - caches["test-cache"] = test_cache - - # Render the components to trigger caching - TestMediaAndVarsComponent.render() - # Check that JS/CSS is cached for components that have them assert test_cache.has_key(f"__components:{TestMediaAndVarsComponent.class_id}:js") assert test_cache.has_key(f"__components:{TestMediaAndVarsComponent.class_id}:css") @@ -128,6 +128,9 @@ class TestComponentMediaCache: assert test_cache.get(f"__components:{TestMediaNoVarsComponent.class_id}:js").strip() == "console.log('Hello from JS');" # noqa: E501 assert test_cache.get(f"__components:{TestMediaNoVarsComponent.class_id}:css").strip() == ".novars-component { color: blue; }" # noqa: E501 + # Render the components to trigger caching of JS/CSS variables from `get_js_data` / `get_css_data` + TestMediaAndVarsComponent.render() + # Check that we cache JS / CSS scripts generated from `get_js_data` / `get_css_data` # NOTE: The hashes is generated from the data. js_vars_hash = "216ecc" diff --git a/tests/test_command_ext.py b/tests/test_command_ext.py index 9c461bed..c43dc54a 100644 --- a/tests/test_command_ext.py +++ b/tests/test_command_ext.py @@ -103,6 +103,7 @@ class TestExtensionsListCommand: "===============\n" "cache \n" "defaults \n" + "dependencies \n" "view \n" "debug_highlight" ) @@ -121,6 +122,7 @@ class TestExtensionsListCommand: "===============\n" "cache \n" "defaults \n" + "dependencies \n" "view \n" "debug_highlight\n" "empty \n" @@ -141,6 +143,7 @@ class TestExtensionsListCommand: "===============\n" "cache \n" "defaults \n" + "dependencies \n" "view \n" "debug_highlight\n" "empty \n" @@ -161,6 +164,7 @@ class TestExtensionsListCommand: "===============\n" "cache \n" "defaults \n" + "dependencies \n" "view \n" "debug_highlight\n" "empty \n" @@ -179,6 +183,7 @@ class TestExtensionsListCommand: assert output.strip() == ( "cache \n" "defaults \n" + "dependencies \n" "view \n" "debug_highlight\n" "empty \n" @@ -206,21 +211,16 @@ class TestExtensionsRunCommand: output == dedent( f""" - usage: components ext run [-h] {{cache,defaults,view,debug_highlight,empty,dummy}} ... + usage: components ext run [-h] {{dummy}} ... Run a command added by an extension. {OPTIONS_TITLE}: - -h, --help show this help message and exit + -h, --help show this help message and exit subcommands: - {{cache,defaults,view,debug_highlight,empty,dummy}} - cache Run commands added by the 'cache' extension. - defaults Run commands added by the 'defaults' extension. - view Run commands added by the 'view' extension. - debug_highlight Run commands added by the 'debug_highlight' extension. - empty Run commands added by the 'empty' extension. - dummy Run commands added by the 'dummy' extension. + {{dummy}} + dummy Run commands added by the 'dummy' extension. """ ).lstrip() ) @@ -231,19 +231,23 @@ class TestExtensionsRunCommand: def test_run_command_ext_empty(self): out = StringIO() with patch("sys.stdout", new=out): - call_command("components", "ext", "run", "empty") + call_command("components", "ext", "run", "dummy") output = out.getvalue() assert ( output == dedent( f""" - usage: components ext run empty [-h] + usage: components ext run dummy [-h] {{dummy_cmd}} ... - Run commands added by the 'empty' extension. + Run commands added by the 'dummy' extension. {OPTIONS_TITLE}: - -h, --help show this help message and exit + -h, --help show this help message and exit + + subcommands: + {{dummy_cmd}} + dummy_cmd Dummy command description. """ ).lstrip() ) diff --git a/tests/test_component_cache.py b/tests/test_component_cache.py index 9e2c3fb3..b2ec2dc3 100644 --- a/tests/test_component_cache.py +++ b/tests/test_component_cache.py @@ -219,7 +219,7 @@ class TestComponentCache: template = Template( """ - {% extends "test_cached_component_inside_include_base.html" %} + {% extends "component_inside_include_base.html" %} {% block content %} THIS_IS_IN_ACTUAL_TEMPLATE_SO_SHOULD_NOT_BE_OVERRIDDEN {% endblock %} diff --git a/tests/test_component_media.py b/tests/test_component_media.py index 7b3dd3a2..3bce7716 100644 --- a/tests/test_component_media.py +++ b/tests/test_component_media.py @@ -15,7 +15,6 @@ from django.utils.safestring import mark_safe from pytest_django.asserts import assertHTMLEqual, assertInHTML from django_components import Component, autodiscover, registry, render_dependencies, types -from django_components.component_media import UNSET from django_components.testing import djc_test from .testutils import setup_test_config @@ -46,7 +45,7 @@ class TestMainMedia: rendered = TestComponent.render() assertInHTML( - '
Content
', + '
Content
', rendered, ) assertInHTML( @@ -70,6 +69,9 @@ class TestMainMedia: assert TestComponent.css == ".html-css-only { color: blue; }" assert TestComponent.js == "console.log('HTML and JS only');" + assert isinstance(TestComponent._template, Template) + assert TestComponent._template.origin.component_cls is TestComponent + @djc_test( django_settings={ "STATICFILES_DIRS": [ @@ -127,6 +129,9 @@ class TestMainMedia: assert TestComponent.css == ".html-css-only {\n color: blue;\n}\n" assert TestComponent.js == 'console.log("JS file");\n' + assert isinstance(TestComponent._template, Template) + assert TestComponent._template.origin.component_cls is TestComponent + @djc_test( django_settings={ "STATICFILES_DIRS": [ @@ -151,6 +156,9 @@ class TestMainMedia: assert ".html-css-only {\n color: blue;\n}" in TestComponent.css # type: ignore[operator] assert 'console.log("HTML and JS only");' in TestComponent.js # type: ignore[operator] + assert isinstance(TestComponent._template, Template) + assert TestComponent._template.origin.component_cls is TestComponent + rendered = Template( """ {% load component_tags %} @@ -195,13 +203,18 @@ class TestMainMedia: class TestComponent(AppLvlCompComponent): pass - # NOTE: Since this is a subclass, actual CSS is defined on the parent class, and thus - # the corresponding ComponentMedia instance is also on the parent class. - assert AppLvlCompComponent._component_media.css is UNSET # type: ignore[attr-defined] - assert AppLvlCompComponent._component_media.css_file == "app_lvl_comp.css" # type: ignore[attr-defined] - - # Access the property to load the CSS - _ = TestComponent.css + # NOTE: Currently the components' JS/CSS are loaded eagerly, to make the JS/CSS + # files available via endpoints. If that is no longer true, uncomment the + # following lines to test the lazy loading of the CSS. + # + # # Since this is a subclass, actual CSS is defined on the parent class, and thus + # # the corresponding ComponentMedia instance is also on the parent class. + # assert AppLvlCompComponent._component_media.css is UNSET # type: ignore[attr-defined] + # assert AppLvlCompComponent._component_media.css_file == "app_lvl_comp.css" # type: ignore[attr-defined] + # assert AppLvlCompComponent._component_media._template is UNSET # type: ignore[attr-defined] + # + # # Access the property to load the CSS + # _ = TestComponent.css assert AppLvlCompComponent._component_media.css == (".html-css-only {\n" " color: blue;\n" "}\n") # type: ignore[attr-defined] assert AppLvlCompComponent._component_media.css_file == "app_lvl_comp/app_lvl_comp.css" # type: ignore[attr-defined] @@ -218,6 +231,9 @@ class TestMainMedia: assert AppLvlCompComponent._component_media.js == 'console.log("JS file");\n' # type: ignore[attr-defined] assert AppLvlCompComponent._component_media.js_file == "app_lvl_comp/app_lvl_comp.js" # type: ignore[attr-defined] + assert isinstance(AppLvlCompComponent._component_media._template, Template) # type: ignore[attr-defined] + assert AppLvlCompComponent._component_media._template.origin.component_cls is AppLvlCompComponent # type: ignore[attr-defined] + def test_html_variable_filtered(self): class FilteredComponent(Component): template: types.django_html = """ @@ -1037,73 +1053,121 @@ class TestSubclassingAttributes: class TestComp(Component): js = None js_file = None + template = None + template_file = None assert TestComp.js is None assert TestComp.js_file is None + assert TestComp.template is None + assert TestComp.template_file is None def test_mixing_none_and_non_none_raises(self): with pytest.raises( ImproperlyConfigured, - match=re.escape("Received non-empty value from both 'js' and 'js_file' in Component TestComp"), + match=re.escape("Received non-empty value from both 'template' and 'template_file' in Component TestComp"), ): class TestComp(Component): js = "console.log('hi')" js_file = None + template = "

hi

" + template_file = None def test_both_non_none_raises(self): with pytest.raises( ImproperlyConfigured, - match=re.escape("Received non-empty value from both 'js' and 'js_file' in Component TestComp"), + match=re.escape("Received non-empty value from both 'template' and 'template_file' in Component TestComp"), ): class TestComp(Component): js = "console.log('hi')" js_file = "file.js" + template = "

hi

" + template_file = "file.html" def test_parent_non_null_child_non_null(self): class ParentComp(Component): js = "console.log('parent')" + template = "

parent

" class TestComp(ParentComp): js = "console.log('child')" + template = "

child

" assert TestComp.js == "console.log('child')" assert TestComp.js_file is None + assert TestComp.template == "

child

" + assert TestComp.template_file is None + + assert isinstance(ParentComp._template, Template) + assert ParentComp._template.source == "

parent

" + assert ParentComp._template.origin.component_cls == ParentComp + + assert isinstance(TestComp._template, Template) + assert TestComp._template.source == "

child

" + assert TestComp._template.origin.component_cls == TestComp def test_parent_null_child_non_null(self): class ParentComp(Component): js = None + template = None class TestComp(ParentComp): js = "console.log('child')" + template = "

child

" assert TestComp.js == "console.log('child')" assert TestComp.js_file is None + assert TestComp.template == "

child

" + assert TestComp.template_file is None + + assert ParentComp._template is None + + assert isinstance(TestComp._template, Template) + assert TestComp._template.source == "

child

" + assert TestComp._template.origin.component_cls == TestComp def test_parent_non_null_child_null(self): class ParentComp(Component): js: Optional[str] = "console.log('parent')" + template: Optional[str] = "

parent

" class TestComp(ParentComp): js = None + template = None assert TestComp.js is None assert TestComp.js_file is None + assert TestComp.template is None + assert TestComp.template_file is None + + assert TestComp._template is None + + assert isinstance(ParentComp._template, Template) + assert ParentComp._template.source == "

parent

" + assert ParentComp._template.origin.component_cls == ParentComp def test_parent_null_child_null(self): class ParentComp(Component): js = None + template = None class TestComp(ParentComp): js = None + template = None assert TestComp.js is None assert TestComp.js_file is None + assert TestComp.template is None + assert TestComp.template_file is None + + assert TestComp._template is None + assert ParentComp._template is None def test_grandparent_non_null_parent_pass_child_pass(self): class GrandParentComp(Component): js = "console.log('grandparent')" + template = "

grandparent

" class ParentComp(GrandParentComp): pass @@ -1113,45 +1177,97 @@ class TestSubclassingAttributes: assert TestComp.js == "console.log('grandparent')" assert TestComp.js_file is None + assert TestComp.template == "

grandparent

" + assert TestComp.template_file is None + + assert isinstance(GrandParentComp._template, Template) + assert GrandParentComp._template.source == "

grandparent

" + assert GrandParentComp._template.origin.component_cls == GrandParentComp + + assert isinstance(ParentComp._template, Template) + assert ParentComp._template.source == "

grandparent

" + assert ParentComp._template.origin.component_cls == ParentComp + + assert isinstance(TestComp._template, Template) + assert TestComp._template.source == "

grandparent

" + assert TestComp._template.origin.component_cls == TestComp def test_grandparent_non_null_parent_null_child_pass(self): class GrandParentComp(Component): js: Optional[str] = "console.log('grandparent')" + template: Optional[str] = "

grandparent

" class ParentComp(GrandParentComp): js = None + template = None class TestComp(ParentComp): pass assert TestComp.js is None assert TestComp.js_file is None + assert TestComp.template is None + assert TestComp.template_file is None + + assert isinstance(GrandParentComp._template, Template) + assert GrandParentComp._template.source == "

grandparent

" + assert GrandParentComp._template.origin.component_cls == GrandParentComp + + assert ParentComp._template is None + assert TestComp._template is None def test_grandparent_non_null_parent_pass_child_non_null(self): class GrandParentComp(Component): js = "console.log('grandparent')" + template = "

grandparent

" class ParentComp(GrandParentComp): pass class TestComp(ParentComp): js = "console.log('child')" + template = "

child

" assert TestComp.js == "console.log('child')" assert TestComp.js_file is None + assert TestComp.template == "

child

" + assert TestComp.template_file is None + + assert isinstance(GrandParentComp._template, Template) + assert GrandParentComp._template.source == "

grandparent

" + assert GrandParentComp._template.origin.component_cls == GrandParentComp + + assert isinstance(ParentComp._template, Template) + assert ParentComp._template.source == "

grandparent

" + assert ParentComp._template.origin.component_cls == ParentComp + + assert isinstance(TestComp._template, Template) + assert TestComp._template.source == "

child

" + assert TestComp._template.origin.component_cls == TestComp def test_grandparent_null_parent_pass_child_non_null(self): class GrandParentComp(Component): js = None + template = None class ParentComp(GrandParentComp): pass class TestComp(ParentComp): js = "console.log('child')" + template = "

child

" assert TestComp.js == "console.log('child')" assert TestComp.js_file is None + assert TestComp.template == "

child

" + assert TestComp.template_file is None + + assert GrandParentComp._template is None + assert ParentComp._template is None + + assert isinstance(TestComp._template, Template) + assert TestComp._template.source == "

child

" + assert TestComp._template.origin.component_cls == TestComp @djc_test diff --git a/tests/test_extension.py b/tests/test_extension.py index 0f7da373..cfd1c1cc 100644 --- a/tests/test_extension.py +++ b/tests/test_extension.py @@ -3,7 +3,7 @@ from typing import Any, Callable, Dict, List, cast import pytest from django.http import HttpRequest, HttpResponse -from django.template import Context +from django.template import Context, Origin, Template from django.test import Client from django_components import Component, Slot, SlotNode, register, registry @@ -23,10 +23,15 @@ from django_components.extension import ( OnComponentDataContext, OnComponentRenderedContext, OnSlotRenderedContext, + OnTemplateLoadedContext, + OnTemplateCompiledContext, + OnJsLoadedContext, + OnCssLoadedContext, ) from django_components.extensions.cache import CacheExtension from django_components.extensions.debug_highlight import DebugHighlightExtension from django_components.extensions.defaults import DefaultsExtension +from django_components.extensions.dependencies import DependenciesExtension from django_components.extensions.view import ViewExtension from django_components.testing import djc_test @@ -85,6 +90,10 @@ class DummyExtension(ComponentExtension): "on_component_data": [], "on_component_rendered": [], "on_slot_rendered": [], + "on_template_loaded": [], + "on_template_compiled": [], + "on_js_loaded": [], + "on_css_loaded": [], } urls = [ @@ -126,6 +135,18 @@ class DummyExtension(ComponentExtension): def on_slot_rendered(self, ctx: OnSlotRenderedContext) -> None: self.calls["on_slot_rendered"].append(ctx) + def on_template_loaded(self, ctx): + self.calls["on_template_loaded"].append(ctx) + + def on_template_compiled(self, ctx): + self.calls["on_template_compiled"].append(ctx) + + def on_js_loaded(self, ctx): + self.calls["on_js_loaded"].append(ctx) + + def on_css_loaded(self, ctx): + self.calls["on_css_loaded"].append(ctx) + class DummyNestedExtension(ComponentExtension): name = "test_nested_extension" @@ -182,16 +203,30 @@ def with_registry(on_created: Callable): on_created(registry) +class OverrideAssetExtension(ComponentExtension): + name = "override_asset_extension" + + def on_template_loaded(self, ctx): + return "OVERRIDDEN TEMPLATE" + + def on_js_loaded(self, ctx): + return "OVERRIDDEN JS" + + def on_css_loaded(self, ctx): + return "OVERRIDDEN CSS" + + @djc_test class TestExtension: @djc_test(components_settings={"extensions": [DummyExtension]}) def test_extensions_setting(self): - assert len(app_settings.EXTENSIONS) == 5 + assert len(app_settings.EXTENSIONS) == 6 assert isinstance(app_settings.EXTENSIONS[0], CacheExtension) assert isinstance(app_settings.EXTENSIONS[1], DefaultsExtension) - assert isinstance(app_settings.EXTENSIONS[2], ViewExtension) - assert isinstance(app_settings.EXTENSIONS[3], DebugHighlightExtension) - assert isinstance(app_settings.EXTENSIONS[4], DummyExtension) + assert isinstance(app_settings.EXTENSIONS[2], DependenciesExtension) + assert isinstance(app_settings.EXTENSIONS[3], ViewExtension) + assert isinstance(app_settings.EXTENSIONS[4], DebugHighlightExtension) + assert isinstance(app_settings.EXTENSIONS[5], DummyExtension) @djc_test(components_settings={"extensions": [DummyExtension]}) def test_access_component_from_extension(self): @@ -230,7 +265,7 @@ class TestExtension: class TestExtensionHooks: @djc_test(components_settings={"extensions": [DummyExtension]}) def test_component_class_lifecycle_hooks(self): - extension = cast(DummyExtension, app_settings.EXTENSIONS[4]) + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) assert len(extension.calls["on_component_class_created"]) == 0 assert len(extension.calls["on_component_class_deleted"]) == 0 @@ -262,7 +297,7 @@ class TestExtensionHooks: @djc_test(components_settings={"extensions": [DummyExtension]}) def test_registry_lifecycle_hooks(self): - extension = cast(DummyExtension, app_settings.EXTENSIONS[4]) + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) assert len(extension.calls["on_registry_created"]) == 0 assert len(extension.calls["on_registry_deleted"]) == 0 @@ -299,7 +334,7 @@ class TestExtensionHooks: return {"name": kwargs.get("name", "World")} registry.register("test_comp", TestComponent) - extension = cast(DummyExtension, app_settings.EXTENSIONS[4]) + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) # Verify on_component_registered was called assert len(extension.calls["on_component_registered"]) == 1 @@ -337,7 +372,7 @@ class TestExtensionHooks: test_slots = {"content": "Some content"} TestComponent.render(context=test_context, args=("arg1", "arg2"), kwargs={"name": "Test"}, slots=test_slots) - extension = cast(DummyExtension, app_settings.EXTENSIONS[4]) + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) # Verify on_component_input was called with correct args assert len(extension.calls["on_component_input"]) == 1 @@ -386,7 +421,7 @@ class TestExtensionHooks: slots={"content": "Some content"}, ) - extension = cast(DummyExtension, app_settings.EXTENSIONS[4]) + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) # Verify on_component_rendered was called with correct args assert len(extension.calls["on_component_rendered"]) == 1 @@ -415,7 +450,7 @@ class TestExtensionHooks: assert rendered == "Hello Some content!" - extension = cast(DummyExtension, app_settings.EXTENSIONS[4]) + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) # Verify on_slot_rendered was called with correct args assert len(extension.calls["on_slot_rendered"]) == 1 @@ -469,6 +504,120 @@ class TestExtensionHooks: rendered = TestComponent.render(args=(), kwargs={"name": "Test"}) assert rendered == "
OVERRIDDEN: Hello Test!
" + @djc_test(components_settings={"extensions": [DummyExtension]}) + def test_asset_hooks__inlined(self): + @register("test_comp_hooks") + class TestComponent(Component): + template = "Hello {{ name }}!" + js = "console.log('hi');" + css = "body { color: red; }" + + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs.get("name", "World")} + + # Render the component to trigger all hooks + TestComponent.render(args=(), kwargs={"name": "Test"}) + + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) + + # on_template_loaded + assert len(extension.calls["on_template_loaded"]) == 1 + ctx1: OnTemplateLoadedContext = extension.calls["on_template_loaded"][0] + assert ctx1.component_cls == TestComponent + assert ctx1.content == "Hello {{ name }}!" + assert isinstance(ctx1.origin, Origin) + assert ctx1.origin.name.endswith("test_extension.py::TestComponent") + assert ctx1.name is None + + # on_template_compiled + assert len(extension.calls["on_template_compiled"]) == 1 + ctx2: OnTemplateCompiledContext = extension.calls["on_template_compiled"][0] + assert ctx2.component_cls == TestComponent + assert isinstance(ctx2.template, Template) + + # on_js_loaded + assert len(extension.calls["on_js_loaded"]) == 1 + ctx3: OnJsLoadedContext = extension.calls["on_js_loaded"][0] + assert ctx3.component_cls == TestComponent + assert ctx3.content == "console.log('hi');" + + # on_css_loaded + assert len(extension.calls["on_css_loaded"]) == 1 + ctx4: OnCssLoadedContext = extension.calls["on_css_loaded"][0] + assert ctx4.component_cls == TestComponent + assert ctx4.content == "body { color: red; }" + + @djc_test(components_settings={"extensions": [DummyExtension]}) + def test_asset_hooks__file(self): + @register("test_comp_hooks") + class TestComponent(Component): + template_file = "relative_file/relative_file.html" + js_file = "relative_file/relative_file.js" + css_file = "relative_file/relative_file.css" + + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs.get("name", "World")} + + # Render the component to trigger all hooks + TestComponent.render(args=(), kwargs={"name": "Test"}) + + extension = cast(DummyExtension, app_settings.EXTENSIONS[5]) + + # on_template_loaded + # NOTE: The template file gets picked up by 'django.template.loaders.filesystem.Loader', + # as well as our own loader, so we get two calls here. + assert len(extension.calls["on_template_loaded"]) == 2 + ctx1: OnTemplateLoadedContext = extension.calls["on_template_loaded"][0] + assert ctx1.component_cls == TestComponent + assert ctx1.content == ( + '
\n' + ' {% csrf_token %}\n' + ' \n' + ' \n' + '
\n' + ) + assert isinstance(ctx1.origin, Origin) + assert ctx1.origin.name.endswith("relative_file.html") + assert ctx1.name == "relative_file/relative_file.html" + + # on_template_compiled + assert len(extension.calls["on_template_compiled"]) == 2 + ctx2: OnTemplateCompiledContext = extension.calls["on_template_compiled"][0] + assert ctx2.component_cls == TestComponent + assert isinstance(ctx2.template, Template) + + # on_js_loaded + assert len(extension.calls["on_js_loaded"]) == 1 + ctx3: OnJsLoadedContext = extension.calls["on_js_loaded"][0] + assert ctx3.component_cls == TestComponent + assert ctx3.content == 'console.log("JS file");\n' + + # on_css_loaded + assert len(extension.calls["on_css_loaded"]) == 1 + ctx4: OnCssLoadedContext = extension.calls["on_css_loaded"][0] + assert ctx4.component_cls == TestComponent + assert ctx4.content == ( + '.html-css-only {\n' + ' color: blue;\n' + '}\n' + ) + + @djc_test(components_settings={"extensions": [OverrideAssetExtension]}) + def test_asset_hooks_override(self): + @register("test_comp_override") + class TestComponent(Component): + template = "Hello {{ name }}!" + js = "console.log('hi');" + css = "body { color: red; }" + + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs.get("name", "World")} + + # No need to render, accessing the attributes should trigger the hooks + assert TestComponent.template == "OVERRIDDEN TEMPLATE" + assert TestComponent.js == "OVERRIDDEN JS" + assert TestComponent.css == "OVERRIDDEN CSS" + @djc_test class TestExtensionViews: diff --git a/tests/test_signals.py b/tests/test_signals.py index ef629bad..6dcabfe9 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -96,3 +96,19 @@ class TestTemplateSignal: templates_used = _get_templates_used_to_render(template) assert "slotted_template.html" in templates_used assert "simple_template.html" in templates_used + + @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) + @with_template_signal + def test_template_rendered_skipped_when_no_template(self, components_settings): + class EmptyComponent(Component): + pass + + registry.register("empty", EmptyComponent) + + template_str: types.django_html = """ + {% load component_tags %} + {% component 'empty' / %} + """ + template = Template(template_str, name="root") + templates_used = _get_templates_used_to_render(template) + assert templates_used == ["root"] diff --git a/tests/test_templatetags_extends.py b/tests/test_templatetags_extends.py index 74f2abe1..d668f1f3 100644 --- a/tests/test_templatetags_extends.py +++ b/tests/test_templatetags_extends.py @@ -25,6 +25,17 @@ def gen_blocked_and_slotted_component(): return BlockedAndSlottedComponent +def gen_component_inside_include(): + class ComponentInsideInclude(Component): + template: types.django_html = """
Hello
""" + + class Media: + css = "style.css" + js = "script.js" + + return ComponentInsideInclude + + ####################### # TESTS ####################### @@ -536,6 +547,112 @@ class TestExtendsCompat: """ assertHTMLEqual(rendered, expected) + # In this case, `{% include %}` is NOT nested inside a `{% component %}` tag. + # We need to ensure that the component inside the `{% include %}` is rendered as if with deps_strategy="ignore", + # so the parent template decides how to render the JS/CSS. + # See https://github.com/django-components/django-components/issues/1296 + @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) + def test_component_with_media_inside_include(self, components_settings): + registry.register("test_component", gen_component_inside_include()) + + template: types.django_html = """ + {% load component_tags %} + + + {% include "component_inside_include_sub.html" %} + + + """ + + rendered_raw = Template(template).render(Context({"DJC_DEPS_STRATEGY": "ignore"})) + expected_raw = """ + + +
Hello
+
+ + """ + assertHTMLEqual(rendered_raw, expected_raw) + + template_obj = Template(template) + context = Context() + rendered = template_obj.render(context) + + # NOTE: It's important that the + + + + """ + assertHTMLEqual(rendered, expected) + + # In this case, because `{% include %}` is rendered inside a `{% component %}` tag, + # then the component inside the `{% include %}` knows it's inside another component. + # So it's always rendered as if with deps_strategy="ignore". + # See https://github.com/django-components/django-components/issues/1296 + @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) + def test_component_with_media_inside_include_inside_component(self, components_settings): + registry.register("test_component", gen_component_inside_include()) + + @register("component_inside_include") + class CompInsideIncludeComponent(Component): + template: types.django_html = """ + + + {% include "component_inside_include_sub.html" %} + + + """ + + template: types.django_html = """ + {% load component_tags %} + + {% component "component_inside_include" / %} + + """ + + rendered_raw = Template(template).render(Context({"DJC_DEPS_STRATEGY": "ignore"})) + expected_raw = """ + + + +
Hello
+
+ + + """ + assertHTMLEqual(rendered_raw, expected_raw) + + template_obj = Template(template) + context = Context() + rendered = template_obj.render(context) + expected = """ + + + +
Hello
+
+ + + + + + """ + assertHTMLEqual(rendered, expected) + @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_component_inside_block(self, components_settings): registry.register("slotted_component", gen_slotted_component())