smlflg commited on
Commit
d34ac6b
·
verified ·
1 Parent(s): db5d676

Initial public upload from Projekte/PromptBoost (part 3)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/RECORD +28 -0
  3. personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/REQUESTED +0 -0
  4. personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/WHEEL +4 -0
  5. personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/licenses/LICENSE +3 -0
  6. personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/licenses/LICENSE.APACHE +177 -0
  7. personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/licenses/LICENSE.BSD +23 -0
  8. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/INSTALLER +1 -0
  9. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/METADATA +152 -0
  10. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/RECORD +16 -0
  11. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/REQUESTED +0 -0
  12. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/WHEEL +5 -0
  13. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/licenses/LICENSE +21 -0
  14. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/top_level.txt +1 -0
  15. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/__init__.py +30 -0
  16. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_callers.py +169 -0
  17. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_hooks.py +714 -0
  18. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_manager.py +523 -0
  19. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_result.py +107 -0
  20. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_tracing.py +72 -0
  21. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_version.py +21 -0
  22. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_warnings.py +27 -0
  23. personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/py.typed +0 -0
  24. personalPromptBoost/.venv/lib/python3.13/site-packages/py.py +15 -0
  25. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/INSTALLER +1 -0
  26. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/METADATA +0 -0
  27. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/RECORD +113 -0
  28. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/REQUESTED +0 -0
  29. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/WHEEL +4 -0
  30. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/licenses/LICENSE +21 -0
  31. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/__init__.py +456 -0
  32. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/__init__.py +0 -0
  33. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_config.py +386 -0
  34. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_core_metadata.py +97 -0
  35. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_core_utils.py +174 -0
  36. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_dataclasses.py +315 -0
  37. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_decorators.py +873 -0
  38. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_decorators_v1.py +174 -0
  39. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_discriminated_union.py +494 -0
  40. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_docs_extraction.py +113 -0
  41. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_fields.py +729 -0
  42. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_forward_ref.py +23 -0
  43. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py +0 -0
  44. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_generics.py +530 -0
  45. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_git.py +27 -0
  46. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_import_utils.py +20 -0
  47. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_internal_dataclass.py +7 -0
  48. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_known_annotated_metadata.py +403 -0
  49. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_mock_val_ser.py +228 -0
  50. personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_model_construction.py +868 -0
.gitattributes CHANGED
@@ -38,3 +38,4 @@ personalPromptBoost/.venv/bin/python3 filter=lfs diff=lfs merge=lfs -text
38
  personalPromptBoost/.venv/bin/python3.13 filter=lfs diff=lfs merge=lfs -text
39
  personalPromptBoost/.venv/lib/python3.13/site-packages/httptools/parser/parser.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
40
  personalPromptBoost/.venv/lib/python3.13/site-packages/httptools/parser/url_parser.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
 
 
38
  personalPromptBoost/.venv/bin/python3.13 filter=lfs diff=lfs merge=lfs -text
39
  personalPromptBoost/.venv/lib/python3.13/site-packages/httptools/parser/parser.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
40
  personalPromptBoost/.venv/lib/python3.13/site-packages/httptools/parser/url_parser.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
41
+ personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic_core/_pydantic_core.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/RECORD ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ packaging-26.1.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
2
+ packaging-26.1.dist-info/METADATA,sha256=7l9S61gHv-txB4r0GDduSfhr5sLI0m_N6OzcnnPjp5Q,3473
3
+ packaging-26.1.dist-info/RECORD,,
4
+ packaging-26.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ packaging-26.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
6
+ packaging-26.1.dist-info/licenses/LICENSE,sha256=ytHvW9NA1z4HS6YU0m996spceUDD2MNIUuZcSQlobEg,197
7
+ packaging-26.1.dist-info/licenses/LICENSE.APACHE,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174
8
+ packaging-26.1.dist-info/licenses/LICENSE.BSD,sha256=tw5-m3QvHMb5SLNMFqo5_-zpQZY2S8iP8NIYDwAo-sU,1344
9
+ packaging/__init__.py,sha256=VdPTbH5gdO5lDUfejETmJNtXxCpKSrFb15J4xMyje8w,494
10
+ packaging/_elffile.py,sha256=-sKkptYqzYw2-x3QByJa5mB4rfPWu1pxkZHRx1WAFCY,3211
11
+ packaging/_manylinux.py,sha256=Hf6nB0cOrayEs96-p3oIXAgGnFquv20DO5l-o2_Xnv0,9559
12
+ packaging/_musllinux.py,sha256=Z6swjH3MA7XS3qXnmMN7QPhqP3fnoYI0eQ18e9-HgAE,2707
13
+ packaging/_parser.py,sha256=U_DajsEx2VoC_F46fSVV3hDKNCWoQYkPkasO3dld0ig,10518
14
+ packaging/_tokenizer.py,sha256=tFU2Wr-ZZJdAbkXLEJo7qUQDJaIkfft9DqaifiEND7A,5391
15
+ packaging/dependency_groups.py,sha256=XZIAVFK9uHG4RCGprmJn3VInUWMesxha_kytJuMO9eY,10218
16
+ packaging/direct_url.py,sha256=eKmbDiPP1sLV4Mj_kCSZqqknrIyVO9Sr7JpF8KCjp4U,10917
17
+ packaging/errors.py,sha256=6hfEYXAf8v_IF65-lFadJOMIieBP2xIKtyEXjG1nGIs,2680
18
+ packaging/licenses/__init__.py,sha256=_Jx0XRiD_58palsWnyLrLuh59ZpGCPIPXLKdZo9OJvQ,7293
19
+ packaging/licenses/_spdx.py,sha256=WW7DXiyg68up_YND_wpRYlr1SHhiV4FfJLQffghhMxQ,51122
20
+ packaging/markers.py,sha256=8D4eXn7MPfjCOHoM0RHkgWumkokORY21pXiK_XDXnL0,15258
21
+ packaging/metadata.py,sha256=rK19fQhrBNv3nINqurpuo-QsCZQuWnmSEaR4Hp-76Js,38691
22
+ packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ packaging/pylock.py,sha256=G_1gncTmDbRLY1jo4VDI9Uw-b5IErh_Q9V_BbVJTmD8,33890
24
+ packaging/requirements.py,sha256=ttyeCsLD19hoHCUChqixMKkocDGqWmXxzGZWs7IhUSA,2984
25
+ packaging/specifiers.py,sha256=vr9t7nC5VDqapdOqbMa2tDxJcHE_elq5rBtAh3YRwKc,65328
26
+ packaging/tags.py,sha256=nwfsCqWxlB3hZ8kxE9xayLykDnLLbYhAsNbOCENh6GM,32421
27
+ packaging/utils.py,sha256=M7-JMKic2sP1YtV_8aW7eVGB-x3ADuKCiSrsVeCd2Uo,9848
28
+ packaging/version.py,sha256=4XfXTSkh90jQWycNJpwJT4dBs59RSVVvJPeb30s1VnU,35427
personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/REQUESTED ADDED
File without changes
personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: flit 3.12.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ This software is made available under the terms of *either* of the licenses
2
+ found in LICENSE.APACHE or LICENSE.BSD. Contributions to this software is made
3
+ under the terms of *both* these licenses.
personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/licenses/LICENSE.APACHE ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
personalPromptBoost/.venv/lib/python3.13/site-packages/packaging-26.1.dist-info/licenses/LICENSE.BSD ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) Donald Stufft and individual contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ uv
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/METADATA ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: pluggy
3
+ Version: 1.6.0
4
+ Summary: plugin and hook calling mechanisms for python
5
+ Author-email: Holger Krekel <holger@merlinux.eu>
6
+ License: MIT
7
+ Classifier: Development Status :: 6 - Mature
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: POSIX
11
+ Classifier: Operating System :: Microsoft :: Windows
12
+ Classifier: Operating System :: MacOS :: MacOS X
13
+ Classifier: Topic :: Software Development :: Testing
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ Classifier: Topic :: Utilities
16
+ Classifier: Programming Language :: Python :: Implementation :: CPython
17
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.9
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/x-rst
27
+ License-File: LICENSE
28
+ Provides-Extra: dev
29
+ Requires-Dist: pre-commit; extra == "dev"
30
+ Requires-Dist: tox; extra == "dev"
31
+ Provides-Extra: testing
32
+ Requires-Dist: pytest; extra == "testing"
33
+ Requires-Dist: pytest-benchmark; extra == "testing"
34
+ Requires-Dist: coverage; extra == "testing"
35
+ Dynamic: license-file
36
+
37
+ ====================================================
38
+ pluggy - A minimalist production ready plugin system
39
+ ====================================================
40
+
41
+ |pypi| |conda-forge| |versions| |github-actions| |gitter| |black| |codecov|
42
+
43
+ This is the core framework used by the `pytest`_, `tox`_, and `devpi`_ projects.
44
+
45
+ Please `read the docs`_ to learn more!
46
+
47
+ A definitive example
48
+ ====================
49
+ .. code-block:: python
50
+
51
+ import pluggy
52
+
53
+ hookspec = pluggy.HookspecMarker("myproject")
54
+ hookimpl = pluggy.HookimplMarker("myproject")
55
+
56
+
57
+ class MySpec:
58
+ """A hook specification namespace."""
59
+
60
+ @hookspec
61
+ def myhook(self, arg1, arg2):
62
+ """My special little hook that you can customize."""
63
+
64
+
65
+ class Plugin_1:
66
+ """A hook implementation namespace."""
67
+
68
+ @hookimpl
69
+ def myhook(self, arg1, arg2):
70
+ print("inside Plugin_1.myhook()")
71
+ return arg1 + arg2
72
+
73
+
74
+ class Plugin_2:
75
+ """A 2nd hook implementation namespace."""
76
+
77
+ @hookimpl
78
+ def myhook(self, arg1, arg2):
79
+ print("inside Plugin_2.myhook()")
80
+ return arg1 - arg2
81
+
82
+
83
+ # create a manager and add the spec
84
+ pm = pluggy.PluginManager("myproject")
85
+ pm.add_hookspecs(MySpec)
86
+
87
+ # register plugins
88
+ pm.register(Plugin_1())
89
+ pm.register(Plugin_2())
90
+
91
+ # call our ``myhook`` hook
92
+ results = pm.hook.myhook(arg1=1, arg2=2)
93
+ print(results)
94
+
95
+
96
+ Running this directly gets us::
97
+
98
+ $ python docs/examples/toy-example.py
99
+ inside Plugin_2.myhook()
100
+ inside Plugin_1.myhook()
101
+ [-1, 3]
102
+
103
+
104
+ .. badges
105
+
106
+ .. |pypi| image:: https://img.shields.io/pypi/v/pluggy.svg
107
+ :target: https://pypi.org/pypi/pluggy
108
+
109
+ .. |versions| image:: https://img.shields.io/pypi/pyversions/pluggy.svg
110
+ :target: https://pypi.org/pypi/pluggy
111
+
112
+ .. |github-actions| image:: https://github.com/pytest-dev/pluggy/workflows/main/badge.svg
113
+ :target: https://github.com/pytest-dev/pluggy/actions
114
+
115
+ .. |conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pluggy.svg
116
+ :target: https://anaconda.org/conda-forge/pytest
117
+
118
+ .. |gitter| image:: https://badges.gitter.im/pytest-dev/pluggy.svg
119
+ :alt: Join the chat at https://gitter.im/pytest-dev/pluggy
120
+ :target: https://gitter.im/pytest-dev/pluggy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
121
+
122
+ .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
123
+ :target: https://github.com/ambv/black
124
+
125
+ .. |codecov| image:: https://codecov.io/gh/pytest-dev/pluggy/branch/master/graph/badge.svg
126
+ :target: https://codecov.io/gh/pytest-dev/pluggy
127
+ :alt: Code coverage Status
128
+
129
+ .. links
130
+ .. _pytest:
131
+ http://pytest.org
132
+ .. _tox:
133
+ https://tox.readthedocs.org
134
+ .. _devpi:
135
+ http://doc.devpi.net
136
+ .. _read the docs:
137
+ https://pluggy.readthedocs.io/en/latest/
138
+
139
+
140
+ Support pluggy
141
+ --------------
142
+
143
+ `Open Collective`_ is an online funding platform for open and transparent communities.
144
+ It provides tools to raise money and share your finances in full transparency.
145
+
146
+ It is the platform of choice for individuals and companies that want to make one-time or
147
+ monthly donations directly to the project.
148
+
149
+ ``pluggy`` is part of the ``pytest-dev`` project, see more details in the `pytest collective`_.
150
+
151
+ .. _Open Collective: https://opencollective.com
152
+ .. _pytest collective: https://opencollective.com/pytest
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/RECORD ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pluggy-1.6.0.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
2
+ pluggy-1.6.0.dist-info/METADATA,sha256=dDjDXuJaCV63QW-EtGHC10Qlxec0rVTDkSRTxlJE4Bw,4811
3
+ pluggy-1.6.0.dist-info/RECORD,,
4
+ pluggy-1.6.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ pluggy-1.6.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
6
+ pluggy-1.6.0.dist-info/licenses/LICENSE,sha256=1rZebCE6XQtXeRHTTW5ZSbn1nXbCOMUHGi8_wWz7JgY,1110
7
+ pluggy-1.6.0.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7
8
+ pluggy/__init__.py,sha256=D6dp1gmEDjtDp8hAwQc-qrgaulnL4iltrqkLDd-g9tg,811
9
+ pluggy/_callers.py,sha256=gEZllGaSYVssZ2UmpNfmYC0bdVgh2jYbAFeYKvuRMjY,5991
10
+ pluggy/_hooks.py,sha256=E6f3nYcI6dbEuO0Gmy61ozgGU_59_e69kC08a06EBuo,25218
11
+ pluggy/_manager.py,sha256=K4Ip_pkEjvT2oOIfQPp8CwAWoXVnENgQRcy9tlGii0o,20219
12
+ pluggy/_result.py,sha256=3Xfy7DrjXbYb7puRquyY2VbidIWNq6Pp7QnuElMdj8Q,3098
13
+ pluggy/_tracing.py,sha256=nXd2BCmDgf8jJxV-HO3PqxR-WV53eWnF8B4AF1nJGgo,2073
14
+ pluggy/_version.py,sha256=5FGJNp9Lkk9uOxeCjXpoCGBF79Ar6LGPOR7-atBqb_4,511
15
+ pluggy/_warnings.py,sha256=td0AvZBpfamriCC3OqsLwxMh-SzAMjfjmc58T5vP3lw,828
16
+ pluggy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/REQUESTED ADDED
File without changes
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.7.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 holger krekel (rather uses bitbucket/hpk42)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy-1.6.0.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ pluggy
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/__init__.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __all__ = [
2
+ "__version__",
3
+ "PluginManager",
4
+ "PluginValidationError",
5
+ "HookCaller",
6
+ "HookCallError",
7
+ "HookspecOpts",
8
+ "HookimplOpts",
9
+ "HookImpl",
10
+ "HookRelay",
11
+ "HookspecMarker",
12
+ "HookimplMarker",
13
+ "Result",
14
+ "PluggyWarning",
15
+ "PluggyTeardownRaisedWarning",
16
+ ]
17
+ from ._hooks import HookCaller
18
+ from ._hooks import HookImpl
19
+ from ._hooks import HookimplMarker
20
+ from ._hooks import HookimplOpts
21
+ from ._hooks import HookRelay
22
+ from ._hooks import HookspecMarker
23
+ from ._hooks import HookspecOpts
24
+ from ._manager import PluginManager
25
+ from ._manager import PluginValidationError
26
+ from ._result import HookCallError
27
+ from ._result import Result
28
+ from ._version import version as __version__
29
+ from ._warnings import PluggyTeardownRaisedWarning
30
+ from ._warnings import PluggyWarning
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_callers.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Call loop machinery
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from collections.abc import Generator
8
+ from collections.abc import Mapping
9
+ from collections.abc import Sequence
10
+ from typing import cast
11
+ from typing import NoReturn
12
+ import warnings
13
+
14
+ from ._hooks import HookImpl
15
+ from ._result import HookCallError
16
+ from ._result import Result
17
+ from ._warnings import PluggyTeardownRaisedWarning
18
+
19
+
20
+ # Need to distinguish between old- and new-style hook wrappers.
21
+ # Wrapping with a tuple is the fastest type-safe way I found to do it.
22
+ Teardown = Generator[None, object, object]
23
+
24
+
25
+ def run_old_style_hookwrapper(
26
+ hook_impl: HookImpl, hook_name: str, args: Sequence[object]
27
+ ) -> Teardown:
28
+ """
29
+ backward compatibility wrapper to run a old style hookwrapper as a wrapper
30
+ """
31
+
32
+ teardown: Teardown = cast(Teardown, hook_impl.function(*args))
33
+ try:
34
+ next(teardown)
35
+ except StopIteration:
36
+ _raise_wrapfail(teardown, "did not yield")
37
+ try:
38
+ res = yield
39
+ result = Result(res, None)
40
+ except BaseException as exc:
41
+ result = Result(None, exc)
42
+ try:
43
+ teardown.send(result)
44
+ except StopIteration:
45
+ pass
46
+ except BaseException as e:
47
+ _warn_teardown_exception(hook_name, hook_impl, e)
48
+ raise
49
+ else:
50
+ _raise_wrapfail(teardown, "has second yield")
51
+ finally:
52
+ teardown.close()
53
+ return result.get_result()
54
+
55
+
56
+ def _raise_wrapfail(
57
+ wrap_controller: Generator[None, object, object],
58
+ msg: str,
59
+ ) -> NoReturn:
60
+ co = wrap_controller.gi_code # type: ignore[attr-defined]
61
+ raise RuntimeError(
62
+ f"wrap_controller at {co.co_name!r} {co.co_filename}:{co.co_firstlineno} {msg}"
63
+ )
64
+
65
+
66
+ def _warn_teardown_exception(
67
+ hook_name: str, hook_impl: HookImpl, e: BaseException
68
+ ) -> None:
69
+ msg = "A plugin raised an exception during an old-style hookwrapper teardown.\n"
70
+ msg += f"Plugin: {hook_impl.plugin_name}, Hook: {hook_name}\n"
71
+ msg += f"{type(e).__name__}: {e}\n"
72
+ msg += "For more information see https://pluggy.readthedocs.io/en/stable/api_reference.html#pluggy.PluggyTeardownRaisedWarning" # noqa: E501
73
+ warnings.warn(PluggyTeardownRaisedWarning(msg), stacklevel=6)
74
+
75
+
76
+ def _multicall(
77
+ hook_name: str,
78
+ hook_impls: Sequence[HookImpl],
79
+ caller_kwargs: Mapping[str, object],
80
+ firstresult: bool,
81
+ ) -> object | list[object]:
82
+ """Execute a call into multiple python functions/methods and return the
83
+ result(s).
84
+
85
+ ``caller_kwargs`` comes from HookCaller.__call__().
86
+ """
87
+ __tracebackhide__ = True
88
+ results: list[object] = []
89
+ exception = None
90
+ try: # run impl and wrapper setup functions in a loop
91
+ teardowns: list[Teardown] = []
92
+ try:
93
+ for hook_impl in reversed(hook_impls):
94
+ try:
95
+ args = [caller_kwargs[argname] for argname in hook_impl.argnames]
96
+ except KeyError as e:
97
+ # coverage bug - this is tested
98
+ for argname in hook_impl.argnames: # pragma: no cover
99
+ if argname not in caller_kwargs:
100
+ raise HookCallError(
101
+ f"hook call must provide argument {argname!r}"
102
+ ) from e
103
+
104
+ if hook_impl.hookwrapper:
105
+ function_gen = run_old_style_hookwrapper(hook_impl, hook_name, args)
106
+
107
+ next(function_gen) # first yield
108
+ teardowns.append(function_gen)
109
+
110
+ elif hook_impl.wrapper:
111
+ try:
112
+ # If this cast is not valid, a type error is raised below,
113
+ # which is the desired response.
114
+ res = hook_impl.function(*args)
115
+ function_gen = cast(Generator[None, object, object], res)
116
+ next(function_gen) # first yield
117
+ teardowns.append(function_gen)
118
+ except StopIteration:
119
+ _raise_wrapfail(function_gen, "did not yield")
120
+ else:
121
+ res = hook_impl.function(*args)
122
+ if res is not None:
123
+ results.append(res)
124
+ if firstresult: # halt further impl calls
125
+ break
126
+ except BaseException as exc:
127
+ exception = exc
128
+ finally:
129
+ if firstresult: # first result hooks return a single value
130
+ result = results[0] if results else None
131
+ else:
132
+ result = results
133
+
134
+ # run all wrapper post-yield blocks
135
+ for teardown in reversed(teardowns):
136
+ try:
137
+ if exception is not None:
138
+ try:
139
+ teardown.throw(exception)
140
+ except RuntimeError as re:
141
+ # StopIteration from generator causes RuntimeError
142
+ # even for coroutine usage - see #544
143
+ if (
144
+ isinstance(exception, StopIteration)
145
+ and re.__cause__ is exception
146
+ ):
147
+ teardown.close()
148
+ continue
149
+ else:
150
+ raise
151
+ else:
152
+ teardown.send(result)
153
+ # Following is unreachable for a well behaved hook wrapper.
154
+ # Try to force finalizers otherwise postponed till GC action.
155
+ # Note: close() may raise if generator handles GeneratorExit.
156
+ teardown.close()
157
+ except StopIteration as si:
158
+ result = si.value
159
+ exception = None
160
+ continue
161
+ except BaseException as e:
162
+ exception = e
163
+ continue
164
+ _raise_wrapfail(teardown, "has second yield")
165
+
166
+ if exception is not None:
167
+ raise exception
168
+ else:
169
+ return result
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_hooks.py ADDED
@@ -0,0 +1,714 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Internal hook annotation, representation and calling machinery.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from collections.abc import Generator
8
+ from collections.abc import Mapping
9
+ from collections.abc import Sequence
10
+ from collections.abc import Set
11
+ import inspect
12
+ import sys
13
+ from types import ModuleType
14
+ from typing import Any
15
+ from typing import Callable
16
+ from typing import Final
17
+ from typing import final
18
+ from typing import Optional
19
+ from typing import overload
20
+ from typing import TYPE_CHECKING
21
+ from typing import TypedDict
22
+ from typing import TypeVar
23
+ from typing import Union
24
+ import warnings
25
+
26
+ from ._result import Result
27
+
28
+
29
+ _T = TypeVar("_T")
30
+ _F = TypeVar("_F", bound=Callable[..., object])
31
+ _Namespace = Union[ModuleType, type]
32
+ _Plugin = object
33
+ _HookExec = Callable[
34
+ [str, Sequence["HookImpl"], Mapping[str, object], bool],
35
+ Union[object, list[object]],
36
+ ]
37
+ _HookImplFunction = Callable[..., Union[_T, Generator[None, Result[_T], None]]]
38
+
39
+
40
+ class HookspecOpts(TypedDict):
41
+ """Options for a hook specification."""
42
+
43
+ #: Whether the hook is :ref:`first result only <firstresult>`.
44
+ firstresult: bool
45
+ #: Whether the hook is :ref:`historic <historic>`.
46
+ historic: bool
47
+ #: Whether the hook :ref:`warns when implemented <warn_on_impl>`.
48
+ warn_on_impl: Warning | None
49
+ #: Whether the hook warns when :ref:`certain arguments are requested
50
+ #: <warn_on_impl>`.
51
+ #:
52
+ #: .. versionadded:: 1.5
53
+ warn_on_impl_args: Mapping[str, Warning] | None
54
+
55
+
56
+ class HookimplOpts(TypedDict):
57
+ """Options for a hook implementation."""
58
+
59
+ #: Whether the hook implementation is a :ref:`wrapper <hookwrapper>`.
60
+ wrapper: bool
61
+ #: Whether the hook implementation is an :ref:`old-style wrapper
62
+ #: <old_style_hookwrappers>`.
63
+ hookwrapper: bool
64
+ #: Whether validation against a hook specification is :ref:`optional
65
+ #: <optionalhook>`.
66
+ optionalhook: bool
67
+ #: Whether to try to order this hook implementation :ref:`first
68
+ #: <callorder>`.
69
+ tryfirst: bool
70
+ #: Whether to try to order this hook implementation :ref:`last
71
+ #: <callorder>`.
72
+ trylast: bool
73
+ #: The name of the hook specification to match, see :ref:`specname`.
74
+ specname: str | None
75
+
76
+
77
+ @final
78
+ class HookspecMarker:
79
+ """Decorator for marking functions as hook specifications.
80
+
81
+ Instantiate it with a project_name to get a decorator.
82
+ Calling :meth:`PluginManager.add_hookspecs` later will discover all marked
83
+ functions if the :class:`PluginManager` uses the same project name.
84
+ """
85
+
86
+ __slots__ = ("project_name",)
87
+
88
+ def __init__(self, project_name: str) -> None:
89
+ self.project_name: Final = project_name
90
+
91
+ @overload
92
+ def __call__(
93
+ self,
94
+ function: _F,
95
+ firstresult: bool = False,
96
+ historic: bool = False,
97
+ warn_on_impl: Warning | None = None,
98
+ warn_on_impl_args: Mapping[str, Warning] | None = None,
99
+ ) -> _F: ...
100
+
101
+ @overload # noqa: F811
102
+ def __call__( # noqa: F811
103
+ self,
104
+ function: None = ...,
105
+ firstresult: bool = ...,
106
+ historic: bool = ...,
107
+ warn_on_impl: Warning | None = ...,
108
+ warn_on_impl_args: Mapping[str, Warning] | None = ...,
109
+ ) -> Callable[[_F], _F]: ...
110
+
111
+ def __call__( # noqa: F811
112
+ self,
113
+ function: _F | None = None,
114
+ firstresult: bool = False,
115
+ historic: bool = False,
116
+ warn_on_impl: Warning | None = None,
117
+ warn_on_impl_args: Mapping[str, Warning] | None = None,
118
+ ) -> _F | Callable[[_F], _F]:
119
+ """If passed a function, directly sets attributes on the function
120
+ which will make it discoverable to :meth:`PluginManager.add_hookspecs`.
121
+
122
+ If passed no function, returns a decorator which can be applied to a
123
+ function later using the attributes supplied.
124
+
125
+ :param firstresult:
126
+ If ``True``, the 1:N hook call (N being the number of registered
127
+ hook implementation functions) will stop at I<=N when the I'th
128
+ function returns a non-``None`` result. See :ref:`firstresult`.
129
+
130
+ :param historic:
131
+ If ``True``, every call to the hook will be memorized and replayed
132
+ on plugins registered after the call was made. See :ref:`historic`.
133
+
134
+ :param warn_on_impl:
135
+ If given, every implementation of this hook will trigger the given
136
+ warning. See :ref:`warn_on_impl`.
137
+
138
+ :param warn_on_impl_args:
139
+ If given, every implementation of this hook which requests one of
140
+ the arguments in the dict will trigger the corresponding warning.
141
+ See :ref:`warn_on_impl`.
142
+
143
+ .. versionadded:: 1.5
144
+ """
145
+
146
+ def setattr_hookspec_opts(func: _F) -> _F:
147
+ if historic and firstresult:
148
+ raise ValueError("cannot have a historic firstresult hook")
149
+ opts: HookspecOpts = {
150
+ "firstresult": firstresult,
151
+ "historic": historic,
152
+ "warn_on_impl": warn_on_impl,
153
+ "warn_on_impl_args": warn_on_impl_args,
154
+ }
155
+ setattr(func, self.project_name + "_spec", opts)
156
+ return func
157
+
158
+ if function is not None:
159
+ return setattr_hookspec_opts(function)
160
+ else:
161
+ return setattr_hookspec_opts
162
+
163
+
164
+ @final
165
+ class HookimplMarker:
166
+ """Decorator for marking functions as hook implementations.
167
+
168
+ Instantiate it with a ``project_name`` to get a decorator.
169
+ Calling :meth:`PluginManager.register` later will discover all marked
170
+ functions if the :class:`PluginManager` uses the same project name.
171
+ """
172
+
173
+ __slots__ = ("project_name",)
174
+
175
+ def __init__(self, project_name: str) -> None:
176
+ self.project_name: Final = project_name
177
+
178
+ @overload
179
+ def __call__(
180
+ self,
181
+ function: _F,
182
+ hookwrapper: bool = ...,
183
+ optionalhook: bool = ...,
184
+ tryfirst: bool = ...,
185
+ trylast: bool = ...,
186
+ specname: str | None = ...,
187
+ wrapper: bool = ...,
188
+ ) -> _F: ...
189
+
190
+ @overload # noqa: F811
191
+ def __call__( # noqa: F811
192
+ self,
193
+ function: None = ...,
194
+ hookwrapper: bool = ...,
195
+ optionalhook: bool = ...,
196
+ tryfirst: bool = ...,
197
+ trylast: bool = ...,
198
+ specname: str | None = ...,
199
+ wrapper: bool = ...,
200
+ ) -> Callable[[_F], _F]: ...
201
+
202
+ def __call__( # noqa: F811
203
+ self,
204
+ function: _F | None = None,
205
+ hookwrapper: bool = False,
206
+ optionalhook: bool = False,
207
+ tryfirst: bool = False,
208
+ trylast: bool = False,
209
+ specname: str | None = None,
210
+ wrapper: bool = False,
211
+ ) -> _F | Callable[[_F], _F]:
212
+ """If passed a function, directly sets attributes on the function
213
+ which will make it discoverable to :meth:`PluginManager.register`.
214
+
215
+ If passed no function, returns a decorator which can be applied to a
216
+ function later using the attributes supplied.
217
+
218
+ :param optionalhook:
219
+ If ``True``, a missing matching hook specification will not result
220
+ in an error (by default it is an error if no matching spec is
221
+ found). See :ref:`optionalhook`.
222
+
223
+ :param tryfirst:
224
+ If ``True``, this hook implementation will run as early as possible
225
+ in the chain of N hook implementations for a specification. See
226
+ :ref:`callorder`.
227
+
228
+ :param trylast:
229
+ If ``True``, this hook implementation will run as late as possible
230
+ in the chain of N hook implementations for a specification. See
231
+ :ref:`callorder`.
232
+
233
+ :param wrapper:
234
+ If ``True`` ("new-style hook wrapper"), the hook implementation
235
+ needs to execute exactly one ``yield``. The code before the
236
+ ``yield`` is run early before any non-hook-wrapper function is run.
237
+ The code after the ``yield`` is run after all non-hook-wrapper
238
+ functions have run. The ``yield`` receives the result value of the
239
+ inner calls, or raises the exception of inner calls (including
240
+ earlier hook wrapper calls). The return value of the function
241
+ becomes the return value of the hook, and a raised exception becomes
242
+ the exception of the hook. See :ref:`hookwrapper`.
243
+
244
+ :param hookwrapper:
245
+ If ``True`` ("old-style hook wrapper"), the hook implementation
246
+ needs to execute exactly one ``yield``. The code before the
247
+ ``yield`` is run early before any non-hook-wrapper function is run.
248
+ The code after the ``yield`` is run after all non-hook-wrapper
249
+ function have run The ``yield`` receives a :class:`Result` object
250
+ representing the exception or result outcome of the inner calls
251
+ (including earlier hook wrapper calls). This option is mutually
252
+ exclusive with ``wrapper``. See :ref:`old_style_hookwrapper`.
253
+
254
+ :param specname:
255
+ If provided, the given name will be used instead of the function
256
+ name when matching this hook implementation to a hook specification
257
+ during registration. See :ref:`specname`.
258
+
259
+ .. versionadded:: 1.2.0
260
+ The ``wrapper`` parameter.
261
+ """
262
+
263
+ def setattr_hookimpl_opts(func: _F) -> _F:
264
+ opts: HookimplOpts = {
265
+ "wrapper": wrapper,
266
+ "hookwrapper": hookwrapper,
267
+ "optionalhook": optionalhook,
268
+ "tryfirst": tryfirst,
269
+ "trylast": trylast,
270
+ "specname": specname,
271
+ }
272
+ setattr(func, self.project_name + "_impl", opts)
273
+ return func
274
+
275
+ if function is None:
276
+ return setattr_hookimpl_opts
277
+ else:
278
+ return setattr_hookimpl_opts(function)
279
+
280
+
281
+ def normalize_hookimpl_opts(opts: HookimplOpts) -> None:
282
+ opts.setdefault("tryfirst", False)
283
+ opts.setdefault("trylast", False)
284
+ opts.setdefault("wrapper", False)
285
+ opts.setdefault("hookwrapper", False)
286
+ opts.setdefault("optionalhook", False)
287
+ opts.setdefault("specname", None)
288
+
289
+
290
+ _PYPY = hasattr(sys, "pypy_version_info")
291
+
292
+
293
+ def varnames(func: object) -> tuple[tuple[str, ...], tuple[str, ...]]:
294
+ """Return tuple of positional and keywrord argument names for a function,
295
+ method, class or callable.
296
+
297
+ In case of a class, its ``__init__`` method is considered.
298
+ For methods the ``self`` parameter is not included.
299
+ """
300
+ if inspect.isclass(func):
301
+ try:
302
+ func = func.__init__
303
+ except AttributeError: # pragma: no cover - pypy special case
304
+ return (), ()
305
+ elif not inspect.isroutine(func): # callable object?
306
+ try:
307
+ func = getattr(func, "__call__", func)
308
+ except Exception: # pragma: no cover - pypy special case
309
+ return (), ()
310
+
311
+ try:
312
+ # func MUST be a function or method here or we won't parse any args.
313
+ sig = inspect.signature(
314
+ func.__func__ if inspect.ismethod(func) else func # type:ignore[arg-type]
315
+ )
316
+ except TypeError: # pragma: no cover
317
+ return (), ()
318
+
319
+ _valid_param_kinds = (
320
+ inspect.Parameter.POSITIONAL_ONLY,
321
+ inspect.Parameter.POSITIONAL_OR_KEYWORD,
322
+ )
323
+ _valid_params = {
324
+ name: param
325
+ for name, param in sig.parameters.items()
326
+ if param.kind in _valid_param_kinds
327
+ }
328
+ args = tuple(_valid_params)
329
+ defaults = (
330
+ tuple(
331
+ param.default
332
+ for param in _valid_params.values()
333
+ if param.default is not param.empty
334
+ )
335
+ or None
336
+ )
337
+
338
+ if defaults:
339
+ index = -len(defaults)
340
+ args, kwargs = args[:index], tuple(args[index:])
341
+ else:
342
+ kwargs = ()
343
+
344
+ # strip any implicit instance arg
345
+ # pypy3 uses "obj" instead of "self" for default dunder methods
346
+ if not _PYPY:
347
+ implicit_names: tuple[str, ...] = ("self",)
348
+ else: # pragma: no cover
349
+ implicit_names = ("self", "obj")
350
+ if args:
351
+ qualname: str = getattr(func, "__qualname__", "")
352
+ if inspect.ismethod(func) or ("." in qualname and args[0] in implicit_names):
353
+ args = args[1:]
354
+
355
+ return args, kwargs
356
+
357
+
358
+ @final
359
+ class HookRelay:
360
+ """Hook holder object for performing 1:N hook calls where N is the number
361
+ of registered plugins."""
362
+
363
+ __slots__ = ("__dict__",)
364
+
365
+ def __init__(self) -> None:
366
+ """:meta private:"""
367
+
368
+ if TYPE_CHECKING:
369
+
370
+ def __getattr__(self, name: str) -> HookCaller: ...
371
+
372
+
373
+ # Historical name (pluggy<=1.2), kept for backward compatibility.
374
+ _HookRelay = HookRelay
375
+
376
+
377
+ _CallHistory = list[tuple[Mapping[str, object], Optional[Callable[[Any], None]]]]
378
+
379
+
380
+ class HookCaller:
381
+ """A caller of all registered implementations of a hook specification."""
382
+
383
+ __slots__ = (
384
+ "name",
385
+ "spec",
386
+ "_hookexec",
387
+ "_hookimpls",
388
+ "_call_history",
389
+ )
390
+
391
+ def __init__(
392
+ self,
393
+ name: str,
394
+ hook_execute: _HookExec,
395
+ specmodule_or_class: _Namespace | None = None,
396
+ spec_opts: HookspecOpts | None = None,
397
+ ) -> None:
398
+ """:meta private:"""
399
+ #: Name of the hook getting called.
400
+ self.name: Final = name
401
+ self._hookexec: Final = hook_execute
402
+ # The hookimpls list. The caller iterates it *in reverse*. Format:
403
+ # 1. trylast nonwrappers
404
+ # 2. nonwrappers
405
+ # 3. tryfirst nonwrappers
406
+ # 4. trylast wrappers
407
+ # 5. wrappers
408
+ # 6. tryfirst wrappers
409
+ self._hookimpls: Final[list[HookImpl]] = []
410
+ self._call_history: _CallHistory | None = None
411
+ # TODO: Document, or make private.
412
+ self.spec: HookSpec | None = None
413
+ if specmodule_or_class is not None:
414
+ assert spec_opts is not None
415
+ self.set_specification(specmodule_or_class, spec_opts)
416
+
417
+ # TODO: Document, or make private.
418
+ def has_spec(self) -> bool:
419
+ return self.spec is not None
420
+
421
+ # TODO: Document, or make private.
422
+ def set_specification(
423
+ self,
424
+ specmodule_or_class: _Namespace,
425
+ spec_opts: HookspecOpts,
426
+ ) -> None:
427
+ if self.spec is not None:
428
+ raise ValueError(
429
+ f"Hook {self.spec.name!r} is already registered "
430
+ f"within namespace {self.spec.namespace}"
431
+ )
432
+ self.spec = HookSpec(specmodule_or_class, self.name, spec_opts)
433
+ if spec_opts.get("historic"):
434
+ self._call_history = []
435
+
436
+ def is_historic(self) -> bool:
437
+ """Whether this caller is :ref:`historic <historic>`."""
438
+ return self._call_history is not None
439
+
440
+ def _remove_plugin(self, plugin: _Plugin) -> None:
441
+ for i, method in enumerate(self._hookimpls):
442
+ if method.plugin == plugin:
443
+ del self._hookimpls[i]
444
+ return
445
+ raise ValueError(f"plugin {plugin!r} not found")
446
+
447
+ def get_hookimpls(self) -> list[HookImpl]:
448
+ """Get all registered hook implementations for this hook."""
449
+ return self._hookimpls.copy()
450
+
451
+ def _add_hookimpl(self, hookimpl: HookImpl) -> None:
452
+ """Add an implementation to the callback chain."""
453
+ for i, method in enumerate(self._hookimpls):
454
+ if method.hookwrapper or method.wrapper:
455
+ splitpoint = i
456
+ break
457
+ else:
458
+ splitpoint = len(self._hookimpls)
459
+ if hookimpl.hookwrapper or hookimpl.wrapper:
460
+ start, end = splitpoint, len(self._hookimpls)
461
+ else:
462
+ start, end = 0, splitpoint
463
+
464
+ if hookimpl.trylast:
465
+ self._hookimpls.insert(start, hookimpl)
466
+ elif hookimpl.tryfirst:
467
+ self._hookimpls.insert(end, hookimpl)
468
+ else:
469
+ # find last non-tryfirst method
470
+ i = end - 1
471
+ while i >= start and self._hookimpls[i].tryfirst:
472
+ i -= 1
473
+ self._hookimpls.insert(i + 1, hookimpl)
474
+
475
+ def __repr__(self) -> str:
476
+ return f"<HookCaller {self.name!r}>"
477
+
478
+ def _verify_all_args_are_provided(self, kwargs: Mapping[str, object]) -> None:
479
+ # This is written to avoid expensive operations when not needed.
480
+ if self.spec:
481
+ for argname in self.spec.argnames:
482
+ if argname not in kwargs:
483
+ notincall = ", ".join(
484
+ repr(argname)
485
+ for argname in self.spec.argnames
486
+ # Avoid self.spec.argnames - kwargs.keys()
487
+ # it doesn't preserve order.
488
+ if argname not in kwargs.keys()
489
+ )
490
+ warnings.warn(
491
+ f"Argument(s) {notincall} which are declared in the hookspec "
492
+ "cannot be found in this hook call",
493
+ stacklevel=2,
494
+ )
495
+ break
496
+
497
+ def __call__(self, **kwargs: object) -> Any:
498
+ """Call the hook.
499
+
500
+ Only accepts keyword arguments, which should match the hook
501
+ specification.
502
+
503
+ Returns the result(s) of calling all registered plugins, see
504
+ :ref:`calling`.
505
+ """
506
+ assert not self.is_historic(), (
507
+ "Cannot directly call a historic hook - use call_historic instead."
508
+ )
509
+ self._verify_all_args_are_provided(kwargs)
510
+ firstresult = self.spec.opts.get("firstresult", False) if self.spec else False
511
+ # Copy because plugins may register other plugins during iteration (#438).
512
+ return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
513
+
514
+ def call_historic(
515
+ self,
516
+ result_callback: Callable[[Any], None] | None = None,
517
+ kwargs: Mapping[str, object] | None = None,
518
+ ) -> None:
519
+ """Call the hook with given ``kwargs`` for all registered plugins and
520
+ for all plugins which will be registered afterwards, see
521
+ :ref:`historic`.
522
+
523
+ :param result_callback:
524
+ If provided, will be called for each non-``None`` result obtained
525
+ from a hook implementation.
526
+ """
527
+ assert self._call_history is not None
528
+ kwargs = kwargs or {}
529
+ self._verify_all_args_are_provided(kwargs)
530
+ self._call_history.append((kwargs, result_callback))
531
+ # Historizing hooks don't return results.
532
+ # Remember firstresult isn't compatible with historic.
533
+ # Copy because plugins may register other plugins during iteration (#438).
534
+ res = self._hookexec(self.name, self._hookimpls.copy(), kwargs, False)
535
+ if result_callback is None:
536
+ return
537
+ if isinstance(res, list):
538
+ for x in res:
539
+ result_callback(x)
540
+
541
+ def call_extra(
542
+ self, methods: Sequence[Callable[..., object]], kwargs: Mapping[str, object]
543
+ ) -> Any:
544
+ """Call the hook with some additional temporarily participating
545
+ methods using the specified ``kwargs`` as call parameters, see
546
+ :ref:`call_extra`."""
547
+ assert not self.is_historic(), (
548
+ "Cannot directly call a historic hook - use call_historic instead."
549
+ )
550
+ self._verify_all_args_are_provided(kwargs)
551
+ opts: HookimplOpts = {
552
+ "wrapper": False,
553
+ "hookwrapper": False,
554
+ "optionalhook": False,
555
+ "trylast": False,
556
+ "tryfirst": False,
557
+ "specname": None,
558
+ }
559
+ hookimpls = self._hookimpls.copy()
560
+ for method in methods:
561
+ hookimpl = HookImpl(None, "<temp>", method, opts)
562
+ # Find last non-tryfirst nonwrapper method.
563
+ i = len(hookimpls) - 1
564
+ while i >= 0 and (
565
+ # Skip wrappers.
566
+ (hookimpls[i].hookwrapper or hookimpls[i].wrapper)
567
+ # Skip tryfirst nonwrappers.
568
+ or hookimpls[i].tryfirst
569
+ ):
570
+ i -= 1
571
+ hookimpls.insert(i + 1, hookimpl)
572
+ firstresult = self.spec.opts.get("firstresult", False) if self.spec else False
573
+ return self._hookexec(self.name, hookimpls, kwargs, firstresult)
574
+
575
+ def _maybe_apply_history(self, method: HookImpl) -> None:
576
+ """Apply call history to a new hookimpl if it is marked as historic."""
577
+ if self.is_historic():
578
+ assert self._call_history is not None
579
+ for kwargs, result_callback in self._call_history:
580
+ res = self._hookexec(self.name, [method], kwargs, False)
581
+ if res and result_callback is not None:
582
+ # XXX: remember firstresult isn't compat with historic
583
+ assert isinstance(res, list)
584
+ result_callback(res[0])
585
+
586
+
587
+ # Historical name (pluggy<=1.2), kept for backward compatibility.
588
+ _HookCaller = HookCaller
589
+
590
+
591
+ class _SubsetHookCaller(HookCaller):
592
+ """A proxy to another HookCaller which manages calls to all registered
593
+ plugins except the ones from remove_plugins."""
594
+
595
+ # This class is unusual: in inhertits from `HookCaller` so all of
596
+ # the *code* runs in the class, but it delegates all underlying *data*
597
+ # to the original HookCaller.
598
+ # `subset_hook_caller` used to be implemented by creating a full-fledged
599
+ # HookCaller, copying all hookimpls from the original. This had problems
600
+ # with memory leaks (#346) and historic calls (#347), which make a proxy
601
+ # approach better.
602
+ # An alternative implementation is to use a `_getattr__`/`__getattribute__`
603
+ # proxy, however that adds more overhead and is more tricky to implement.
604
+
605
+ __slots__ = (
606
+ "_orig",
607
+ "_remove_plugins",
608
+ )
609
+
610
+ def __init__(self, orig: HookCaller, remove_plugins: Set[_Plugin]) -> None:
611
+ self._orig = orig
612
+ self._remove_plugins = remove_plugins
613
+ self.name = orig.name # type: ignore[misc]
614
+ self._hookexec = orig._hookexec # type: ignore[misc]
615
+
616
+ @property # type: ignore[misc]
617
+ def _hookimpls(self) -> list[HookImpl]:
618
+ return [
619
+ impl
620
+ for impl in self._orig._hookimpls
621
+ if impl.plugin not in self._remove_plugins
622
+ ]
623
+
624
+ @property
625
+ def spec(self) -> HookSpec | None: # type: ignore[override]
626
+ return self._orig.spec
627
+
628
+ @property
629
+ def _call_history(self) -> _CallHistory | None: # type: ignore[override]
630
+ return self._orig._call_history
631
+
632
+ def __repr__(self) -> str:
633
+ return f"<_SubsetHookCaller {self.name!r}>"
634
+
635
+
636
+ @final
637
+ class HookImpl:
638
+ """A hook implementation in a :class:`HookCaller`."""
639
+
640
+ __slots__ = (
641
+ "function",
642
+ "argnames",
643
+ "kwargnames",
644
+ "plugin",
645
+ "opts",
646
+ "plugin_name",
647
+ "wrapper",
648
+ "hookwrapper",
649
+ "optionalhook",
650
+ "tryfirst",
651
+ "trylast",
652
+ )
653
+
654
+ def __init__(
655
+ self,
656
+ plugin: _Plugin,
657
+ plugin_name: str,
658
+ function: _HookImplFunction[object],
659
+ hook_impl_opts: HookimplOpts,
660
+ ) -> None:
661
+ """:meta private:"""
662
+ #: The hook implementation function.
663
+ self.function: Final = function
664
+ argnames, kwargnames = varnames(self.function)
665
+ #: The positional parameter names of ``function```.
666
+ self.argnames: Final = argnames
667
+ #: The keyword parameter names of ``function```.
668
+ self.kwargnames: Final = kwargnames
669
+ #: The plugin which defined this hook implementation.
670
+ self.plugin: Final = plugin
671
+ #: The :class:`HookimplOpts` used to configure this hook implementation.
672
+ self.opts: Final = hook_impl_opts
673
+ #: The name of the plugin which defined this hook implementation.
674
+ self.plugin_name: Final = plugin_name
675
+ #: Whether the hook implementation is a :ref:`wrapper <hookwrapper>`.
676
+ self.wrapper: Final = hook_impl_opts["wrapper"]
677
+ #: Whether the hook implementation is an :ref:`old-style wrapper
678
+ #: <old_style_hookwrappers>`.
679
+ self.hookwrapper: Final = hook_impl_opts["hookwrapper"]
680
+ #: Whether validation against a hook specification is :ref:`optional
681
+ #: <optionalhook>`.
682
+ self.optionalhook: Final = hook_impl_opts["optionalhook"]
683
+ #: Whether to try to order this hook implementation :ref:`first
684
+ #: <callorder>`.
685
+ self.tryfirst: Final = hook_impl_opts["tryfirst"]
686
+ #: Whether to try to order this hook implementation :ref:`last
687
+ #: <callorder>`.
688
+ self.trylast: Final = hook_impl_opts["trylast"]
689
+
690
+ def __repr__(self) -> str:
691
+ return f"<HookImpl plugin_name={self.plugin_name!r}, plugin={self.plugin!r}>"
692
+
693
+
694
+ @final
695
+ class HookSpec:
696
+ __slots__ = (
697
+ "namespace",
698
+ "function",
699
+ "name",
700
+ "argnames",
701
+ "kwargnames",
702
+ "opts",
703
+ "warn_on_impl",
704
+ "warn_on_impl_args",
705
+ )
706
+
707
+ def __init__(self, namespace: _Namespace, name: str, opts: HookspecOpts) -> None:
708
+ self.namespace = namespace
709
+ self.function: Callable[..., object] = getattr(namespace, name)
710
+ self.name = name
711
+ self.argnames, self.kwargnames = varnames(self.function)
712
+ self.opts = opts
713
+ self.warn_on_impl = opts.get("warn_on_impl")
714
+ self.warn_on_impl_args = opts.get("warn_on_impl_args")
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_manager.py ADDED
@@ -0,0 +1,523 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
4
+ from collections.abc import Mapping
5
+ from collections.abc import Sequence
6
+ import inspect
7
+ import types
8
+ from typing import Any
9
+ from typing import Callable
10
+ from typing import cast
11
+ from typing import Final
12
+ from typing import TYPE_CHECKING
13
+ import warnings
14
+
15
+ from . import _tracing
16
+ from ._callers import _multicall
17
+ from ._hooks import _HookImplFunction
18
+ from ._hooks import _Namespace
19
+ from ._hooks import _Plugin
20
+ from ._hooks import _SubsetHookCaller
21
+ from ._hooks import HookCaller
22
+ from ._hooks import HookImpl
23
+ from ._hooks import HookimplOpts
24
+ from ._hooks import HookRelay
25
+ from ._hooks import HookspecOpts
26
+ from ._hooks import normalize_hookimpl_opts
27
+ from ._result import Result
28
+
29
+
30
+ if TYPE_CHECKING:
31
+ # importtlib.metadata import is slow, defer it.
32
+ import importlib.metadata
33
+
34
+
35
+ _BeforeTrace = Callable[[str, Sequence[HookImpl], Mapping[str, Any]], None]
36
+ _AfterTrace = Callable[[Result[Any], str, Sequence[HookImpl], Mapping[str, Any]], None]
37
+
38
+
39
+ def _warn_for_function(warning: Warning, function: Callable[..., object]) -> None:
40
+ func = cast(types.FunctionType, function)
41
+ warnings.warn_explicit(
42
+ warning,
43
+ type(warning),
44
+ lineno=func.__code__.co_firstlineno,
45
+ filename=func.__code__.co_filename,
46
+ )
47
+
48
+
49
+ class PluginValidationError(Exception):
50
+ """Plugin failed validation.
51
+
52
+ :param plugin: The plugin which failed validation.
53
+ :param message: Error message.
54
+ """
55
+
56
+ def __init__(self, plugin: _Plugin, message: str) -> None:
57
+ super().__init__(message)
58
+ #: The plugin which failed validation.
59
+ self.plugin = plugin
60
+
61
+
62
+ class DistFacade:
63
+ """Emulate a pkg_resources Distribution"""
64
+
65
+ def __init__(self, dist: importlib.metadata.Distribution) -> None:
66
+ self._dist = dist
67
+
68
+ @property
69
+ def project_name(self) -> str:
70
+ name: str = self.metadata["name"]
71
+ return name
72
+
73
+ def __getattr__(self, attr: str, default: Any | None = None) -> Any:
74
+ return getattr(self._dist, attr, default)
75
+
76
+ def __dir__(self) -> list[str]:
77
+ return sorted(dir(self._dist) + ["_dist", "project_name"])
78
+
79
+
80
+ class PluginManager:
81
+ """Core class which manages registration of plugin objects and 1:N hook
82
+ calling.
83
+
84
+ You can register new hooks by calling :meth:`add_hookspecs(module_or_class)
85
+ <PluginManager.add_hookspecs>`.
86
+
87
+ You can register plugin objects (which contain hook implementations) by
88
+ calling :meth:`register(plugin) <PluginManager.register>`.
89
+
90
+ For debugging purposes you can call :meth:`PluginManager.enable_tracing`
91
+ which will subsequently send debug information to the trace helper.
92
+
93
+ :param project_name:
94
+ The short project name. Prefer snake case. Make sure it's unique!
95
+ """
96
+
97
+ def __init__(self, project_name: str) -> None:
98
+ #: The project name.
99
+ self.project_name: Final = project_name
100
+ self._name2plugin: Final[dict[str, _Plugin]] = {}
101
+ self._plugin_distinfo: Final[list[tuple[_Plugin, DistFacade]]] = []
102
+ #: The "hook relay", used to call a hook on all registered plugins.
103
+ #: See :ref:`calling`.
104
+ self.hook: Final = HookRelay()
105
+ #: The tracing entry point. See :ref:`tracing`.
106
+ self.trace: Final[_tracing.TagTracerSub] = _tracing.TagTracer().get(
107
+ "pluginmanage"
108
+ )
109
+ self._inner_hookexec = _multicall
110
+
111
+ def _hookexec(
112
+ self,
113
+ hook_name: str,
114
+ methods: Sequence[HookImpl],
115
+ kwargs: Mapping[str, object],
116
+ firstresult: bool,
117
+ ) -> object | list[object]:
118
+ # called from all hookcaller instances.
119
+ # enable_tracing will set its own wrapping function at self._inner_hookexec
120
+ return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
121
+
122
+ def register(self, plugin: _Plugin, name: str | None = None) -> str | None:
123
+ """Register a plugin and return its name.
124
+
125
+ :param name:
126
+ The name under which to register the plugin. If not specified, a
127
+ name is generated using :func:`get_canonical_name`.
128
+
129
+ :returns:
130
+ The plugin name. If the name is blocked from registering, returns
131
+ ``None``.
132
+
133
+ If the plugin is already registered, raises a :exc:`ValueError`.
134
+ """
135
+ plugin_name = name or self.get_canonical_name(plugin)
136
+
137
+ if plugin_name in self._name2plugin:
138
+ if self._name2plugin.get(plugin_name, -1) is None:
139
+ return None # blocked plugin, return None to indicate no registration
140
+ raise ValueError(
141
+ "Plugin name already registered: "
142
+ f"{plugin_name}={plugin}\n{self._name2plugin}"
143
+ )
144
+
145
+ if plugin in self._name2plugin.values():
146
+ raise ValueError(
147
+ "Plugin already registered under a different name: "
148
+ f"{plugin_name}={plugin}\n{self._name2plugin}"
149
+ )
150
+
151
+ # XXX if an error happens we should make sure no state has been
152
+ # changed at point of return
153
+ self._name2plugin[plugin_name] = plugin
154
+
155
+ # register matching hook implementations of the plugin
156
+ for name in dir(plugin):
157
+ hookimpl_opts = self.parse_hookimpl_opts(plugin, name)
158
+ if hookimpl_opts is not None:
159
+ normalize_hookimpl_opts(hookimpl_opts)
160
+ method: _HookImplFunction[object] = getattr(plugin, name)
161
+ hookimpl = HookImpl(plugin, plugin_name, method, hookimpl_opts)
162
+ name = hookimpl_opts.get("specname") or name
163
+ hook: HookCaller | None = getattr(self.hook, name, None)
164
+ if hook is None:
165
+ hook = HookCaller(name, self._hookexec)
166
+ setattr(self.hook, name, hook)
167
+ elif hook.has_spec():
168
+ self._verify_hook(hook, hookimpl)
169
+ hook._maybe_apply_history(hookimpl)
170
+ hook._add_hookimpl(hookimpl)
171
+ return plugin_name
172
+
173
+ def parse_hookimpl_opts(self, plugin: _Plugin, name: str) -> HookimplOpts | None:
174
+ """Try to obtain a hook implementation from an item with the given name
175
+ in the given plugin which is being searched for hook impls.
176
+
177
+ :returns:
178
+ The parsed hookimpl options, or None to skip the given item.
179
+
180
+ This method can be overridden by ``PluginManager`` subclasses to
181
+ customize how hook implementation are picked up. By default, returns the
182
+ options for items decorated with :class:`HookimplMarker`.
183
+ """
184
+ method: object = getattr(plugin, name)
185
+ if not inspect.isroutine(method):
186
+ return None
187
+ try:
188
+ res: HookimplOpts | None = getattr(
189
+ method, self.project_name + "_impl", None
190
+ )
191
+ except Exception: # pragma: no cover
192
+ res = {} # type: ignore[assignment] #pragma: no cover
193
+ if res is not None and not isinstance(res, dict):
194
+ # false positive
195
+ res = None # type:ignore[unreachable] #pragma: no cover
196
+ return res
197
+
198
+ def unregister(
199
+ self, plugin: _Plugin | None = None, name: str | None = None
200
+ ) -> Any | None:
201
+ """Unregister a plugin and all of its hook implementations.
202
+
203
+ The plugin can be specified either by the plugin object or the plugin
204
+ name. If both are specified, they must agree.
205
+
206
+ Returns the unregistered plugin, or ``None`` if not found.
207
+ """
208
+ if name is None:
209
+ assert plugin is not None, "one of name or plugin needs to be specified"
210
+ name = self.get_name(plugin)
211
+ assert name is not None, "plugin is not registered"
212
+
213
+ if plugin is None:
214
+ plugin = self.get_plugin(name)
215
+ if plugin is None:
216
+ return None
217
+
218
+ hookcallers = self.get_hookcallers(plugin)
219
+ if hookcallers:
220
+ for hookcaller in hookcallers:
221
+ hookcaller._remove_plugin(plugin)
222
+
223
+ # if self._name2plugin[name] == None registration was blocked: ignore
224
+ if self._name2plugin.get(name):
225
+ assert name is not None
226
+ del self._name2plugin[name]
227
+
228
+ return plugin
229
+
230
+ def set_blocked(self, name: str) -> None:
231
+ """Block registrations of the given name, unregister if already registered."""
232
+ self.unregister(name=name)
233
+ self._name2plugin[name] = None
234
+
235
+ def is_blocked(self, name: str) -> bool:
236
+ """Return whether the given plugin name is blocked."""
237
+ return name in self._name2plugin and self._name2plugin[name] is None
238
+
239
+ def unblock(self, name: str) -> bool:
240
+ """Unblocks a name.
241
+
242
+ Returns whether the name was actually blocked.
243
+ """
244
+ if self._name2plugin.get(name, -1) is None:
245
+ del self._name2plugin[name]
246
+ return True
247
+ return False
248
+
249
+ def add_hookspecs(self, module_or_class: _Namespace) -> None:
250
+ """Add new hook specifications defined in the given ``module_or_class``.
251
+
252
+ Functions are recognized as hook specifications if they have been
253
+ decorated with a matching :class:`HookspecMarker`.
254
+ """
255
+ names = []
256
+ for name in dir(module_or_class):
257
+ spec_opts = self.parse_hookspec_opts(module_or_class, name)
258
+ if spec_opts is not None:
259
+ hc: HookCaller | None = getattr(self.hook, name, None)
260
+ if hc is None:
261
+ hc = HookCaller(name, self._hookexec, module_or_class, spec_opts)
262
+ setattr(self.hook, name, hc)
263
+ else:
264
+ # Plugins registered this hook without knowing the spec.
265
+ hc.set_specification(module_or_class, spec_opts)
266
+ for hookfunction in hc.get_hookimpls():
267
+ self._verify_hook(hc, hookfunction)
268
+ names.append(name)
269
+
270
+ if not names:
271
+ raise ValueError(
272
+ f"did not find any {self.project_name!r} hooks in {module_or_class!r}"
273
+ )
274
+
275
+ def parse_hookspec_opts(
276
+ self, module_or_class: _Namespace, name: str
277
+ ) -> HookspecOpts | None:
278
+ """Try to obtain a hook specification from an item with the given name
279
+ in the given module or class which is being searched for hook specs.
280
+
281
+ :returns:
282
+ The parsed hookspec options for defining a hook, or None to skip the
283
+ given item.
284
+
285
+ This method can be overridden by ``PluginManager`` subclasses to
286
+ customize how hook specifications are picked up. By default, returns the
287
+ options for items decorated with :class:`HookspecMarker`.
288
+ """
289
+ method = getattr(module_or_class, name)
290
+ opts: HookspecOpts | None = getattr(method, self.project_name + "_spec", None)
291
+ return opts
292
+
293
+ def get_plugins(self) -> set[Any]:
294
+ """Return a set of all registered plugin objects."""
295
+ return {x for x in self._name2plugin.values() if x is not None}
296
+
297
+ def is_registered(self, plugin: _Plugin) -> bool:
298
+ """Return whether the plugin is already registered."""
299
+ return any(plugin == val for val in self._name2plugin.values())
300
+
301
+ def get_canonical_name(self, plugin: _Plugin) -> str:
302
+ """Return a canonical name for a plugin object.
303
+
304
+ Note that a plugin may be registered under a different name
305
+ specified by the caller of :meth:`register(plugin, name) <register>`.
306
+ To obtain the name of a registered plugin use :meth:`get_name(plugin)
307
+ <get_name>` instead.
308
+ """
309
+ name: str | None = getattr(plugin, "__name__", None)
310
+ return name or str(id(plugin))
311
+
312
+ def get_plugin(self, name: str) -> Any | None:
313
+ """Return the plugin registered under the given name, if any."""
314
+ return self._name2plugin.get(name)
315
+
316
+ def has_plugin(self, name: str) -> bool:
317
+ """Return whether a plugin with the given name is registered."""
318
+ return self.get_plugin(name) is not None
319
+
320
+ def get_name(self, plugin: _Plugin) -> str | None:
321
+ """Return the name the plugin is registered under, or ``None`` if
322
+ is isn't."""
323
+ for name, val in self._name2plugin.items():
324
+ if plugin == val:
325
+ return name
326
+ return None
327
+
328
+ def _verify_hook(self, hook: HookCaller, hookimpl: HookImpl) -> None:
329
+ if hook.is_historic() and (hookimpl.hookwrapper or hookimpl.wrapper):
330
+ raise PluginValidationError(
331
+ hookimpl.plugin,
332
+ f"Plugin {hookimpl.plugin_name!r}\nhook {hook.name!r}\n"
333
+ "historic incompatible with yield/wrapper/hookwrapper",
334
+ )
335
+
336
+ assert hook.spec is not None
337
+ if hook.spec.warn_on_impl:
338
+ _warn_for_function(hook.spec.warn_on_impl, hookimpl.function)
339
+
340
+ # positional arg checking
341
+ notinspec = set(hookimpl.argnames) - set(hook.spec.argnames)
342
+ if notinspec:
343
+ raise PluginValidationError(
344
+ hookimpl.plugin,
345
+ f"Plugin {hookimpl.plugin_name!r} for hook {hook.name!r}\n"
346
+ f"hookimpl definition: {_formatdef(hookimpl.function)}\n"
347
+ f"Argument(s) {notinspec} are declared in the hookimpl but "
348
+ "can not be found in the hookspec",
349
+ )
350
+
351
+ if hook.spec.warn_on_impl_args:
352
+ for hookimpl_argname in hookimpl.argnames:
353
+ argname_warning = hook.spec.warn_on_impl_args.get(hookimpl_argname)
354
+ if argname_warning is not None:
355
+ _warn_for_function(argname_warning, hookimpl.function)
356
+
357
+ if (
358
+ hookimpl.wrapper or hookimpl.hookwrapper
359
+ ) and not inspect.isgeneratorfunction(hookimpl.function):
360
+ raise PluginValidationError(
361
+ hookimpl.plugin,
362
+ f"Plugin {hookimpl.plugin_name!r} for hook {hook.name!r}\n"
363
+ f"hookimpl definition: {_formatdef(hookimpl.function)}\n"
364
+ "Declared as wrapper=True or hookwrapper=True "
365
+ "but function is not a generator function",
366
+ )
367
+
368
+ if hookimpl.wrapper and hookimpl.hookwrapper:
369
+ raise PluginValidationError(
370
+ hookimpl.plugin,
371
+ f"Plugin {hookimpl.plugin_name!r} for hook {hook.name!r}\n"
372
+ f"hookimpl definition: {_formatdef(hookimpl.function)}\n"
373
+ "The wrapper=True and hookwrapper=True options are mutually exclusive",
374
+ )
375
+
376
+ def check_pending(self) -> None:
377
+ """Verify that all hooks which have not been verified against a
378
+ hook specification are optional, otherwise raise
379
+ :exc:`PluginValidationError`."""
380
+ for name in self.hook.__dict__:
381
+ if name[0] == "_":
382
+ continue
383
+ hook: HookCaller = getattr(self.hook, name)
384
+ if not hook.has_spec():
385
+ for hookimpl in hook.get_hookimpls():
386
+ if not hookimpl.optionalhook:
387
+ raise PluginValidationError(
388
+ hookimpl.plugin,
389
+ f"unknown hook {name!r} in plugin {hookimpl.plugin!r}",
390
+ )
391
+
392
+ def load_setuptools_entrypoints(self, group: str, name: str | None = None) -> int:
393
+ """Load modules from querying the specified setuptools ``group``.
394
+
395
+ :param group:
396
+ Entry point group to load plugins.
397
+ :param name:
398
+ If given, loads only plugins with the given ``name``.
399
+
400
+ :return:
401
+ The number of plugins loaded by this call.
402
+ """
403
+ import importlib.metadata
404
+
405
+ count = 0
406
+ for dist in list(importlib.metadata.distributions()):
407
+ for ep in dist.entry_points:
408
+ if (
409
+ ep.group != group
410
+ or (name is not None and ep.name != name)
411
+ # already registered
412
+ or self.get_plugin(ep.name)
413
+ or self.is_blocked(ep.name)
414
+ ):
415
+ continue
416
+ plugin = ep.load()
417
+ self.register(plugin, name=ep.name)
418
+ self._plugin_distinfo.append((plugin, DistFacade(dist)))
419
+ count += 1
420
+ return count
421
+
422
+ def list_plugin_distinfo(self) -> list[tuple[_Plugin, DistFacade]]:
423
+ """Return a list of (plugin, distinfo) pairs for all
424
+ setuptools-registered plugins."""
425
+ return list(self._plugin_distinfo)
426
+
427
+ def list_name_plugin(self) -> list[tuple[str, _Plugin]]:
428
+ """Return a list of (name, plugin) pairs for all registered plugins."""
429
+ return list(self._name2plugin.items())
430
+
431
+ def get_hookcallers(self, plugin: _Plugin) -> list[HookCaller] | None:
432
+ """Get all hook callers for the specified plugin.
433
+
434
+ :returns:
435
+ The hook callers, or ``None`` if ``plugin`` is not registered in
436
+ this plugin manager.
437
+ """
438
+ if self.get_name(plugin) is None:
439
+ return None
440
+ hookcallers = []
441
+ for hookcaller in self.hook.__dict__.values():
442
+ for hookimpl in hookcaller.get_hookimpls():
443
+ if hookimpl.plugin is plugin:
444
+ hookcallers.append(hookcaller)
445
+ return hookcallers
446
+
447
+ def add_hookcall_monitoring(
448
+ self, before: _BeforeTrace, after: _AfterTrace
449
+ ) -> Callable[[], None]:
450
+ """Add before/after tracing functions for all hooks.
451
+
452
+ Returns an undo function which, when called, removes the added tracers.
453
+
454
+ ``before(hook_name, hook_impls, kwargs)`` will be called ahead
455
+ of all hook calls and receive a hookcaller instance, a list
456
+ of HookImpl instances and the keyword arguments for the hook call.
457
+
458
+ ``after(outcome, hook_name, hook_impls, kwargs)`` receives the
459
+ same arguments as ``before`` but also a :class:`~pluggy.Result` object
460
+ which represents the result of the overall hook call.
461
+ """
462
+ oldcall = self._inner_hookexec
463
+
464
+ def traced_hookexec(
465
+ hook_name: str,
466
+ hook_impls: Sequence[HookImpl],
467
+ caller_kwargs: Mapping[str, object],
468
+ firstresult: bool,
469
+ ) -> object | list[object]:
470
+ before(hook_name, hook_impls, caller_kwargs)
471
+ outcome = Result.from_call(
472
+ lambda: oldcall(hook_name, hook_impls, caller_kwargs, firstresult)
473
+ )
474
+ after(outcome, hook_name, hook_impls, caller_kwargs)
475
+ return outcome.get_result()
476
+
477
+ self._inner_hookexec = traced_hookexec
478
+
479
+ def undo() -> None:
480
+ self._inner_hookexec = oldcall
481
+
482
+ return undo
483
+
484
+ def enable_tracing(self) -> Callable[[], None]:
485
+ """Enable tracing of hook calls.
486
+
487
+ Returns an undo function which, when called, removes the added tracing.
488
+ """
489
+ hooktrace = self.trace.root.get("hook")
490
+
491
+ def before(
492
+ hook_name: str, methods: Sequence[HookImpl], kwargs: Mapping[str, object]
493
+ ) -> None:
494
+ hooktrace.root.indent += 1
495
+ hooktrace(hook_name, kwargs)
496
+
497
+ def after(
498
+ outcome: Result[object],
499
+ hook_name: str,
500
+ methods: Sequence[HookImpl],
501
+ kwargs: Mapping[str, object],
502
+ ) -> None:
503
+ if outcome.exception is None:
504
+ hooktrace("finish", hook_name, "-->", outcome.get_result())
505
+ hooktrace.root.indent -= 1
506
+
507
+ return self.add_hookcall_monitoring(before, after)
508
+
509
+ def subset_hook_caller(
510
+ self, name: str, remove_plugins: Iterable[_Plugin]
511
+ ) -> HookCaller:
512
+ """Return a proxy :class:`~pluggy.HookCaller` instance for the named
513
+ method which manages calls to all registered plugins except the ones
514
+ from remove_plugins."""
515
+ orig: HookCaller = getattr(self.hook, name)
516
+ plugins_to_remove = {plug for plug in remove_plugins if hasattr(plug, name)}
517
+ if plugins_to_remove:
518
+ return _SubsetHookCaller(orig, plugins_to_remove)
519
+ return orig
520
+
521
+
522
+ def _formatdef(func: Callable[..., object]) -> str:
523
+ return f"{func.__name__}{inspect.signature(func)}"
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_result.py ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Hook wrapper "result" utilities.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from types import TracebackType
8
+ from typing import Callable
9
+ from typing import cast
10
+ from typing import final
11
+ from typing import Generic
12
+ from typing import Optional
13
+ from typing import TypeVar
14
+
15
+
16
+ _ExcInfo = tuple[type[BaseException], BaseException, Optional[TracebackType]]
17
+ ResultType = TypeVar("ResultType")
18
+
19
+
20
+ class HookCallError(Exception):
21
+ """Hook was called incorrectly."""
22
+
23
+
24
+ @final
25
+ class Result(Generic[ResultType]):
26
+ """An object used to inspect and set the result in a :ref:`hook wrapper
27
+ <hookwrappers>`."""
28
+
29
+ __slots__ = ("_result", "_exception", "_traceback")
30
+
31
+ def __init__(
32
+ self,
33
+ result: ResultType | None,
34
+ exception: BaseException | None,
35
+ ) -> None:
36
+ """:meta private:"""
37
+ self._result = result
38
+ self._exception = exception
39
+ # Exception __traceback__ is mutable, this keeps the original.
40
+ self._traceback = exception.__traceback__ if exception is not None else None
41
+
42
+ @property
43
+ def excinfo(self) -> _ExcInfo | None:
44
+ """:meta private:"""
45
+ exc = self._exception
46
+ if exc is None:
47
+ return None
48
+ else:
49
+ return (type(exc), exc, self._traceback)
50
+
51
+ @property
52
+ def exception(self) -> BaseException | None:
53
+ """:meta private:"""
54
+ return self._exception
55
+
56
+ @classmethod
57
+ def from_call(cls, func: Callable[[], ResultType]) -> Result[ResultType]:
58
+ """:meta private:"""
59
+ __tracebackhide__ = True
60
+ result = exception = None
61
+ try:
62
+ result = func()
63
+ except BaseException as exc:
64
+ exception = exc
65
+ return cls(result, exception)
66
+
67
+ def force_result(self, result: ResultType) -> None:
68
+ """Force the result(s) to ``result``.
69
+
70
+ If the hook was marked as a ``firstresult`` a single value should
71
+ be set, otherwise set a (modified) list of results. Any exceptions
72
+ found during invocation will be deleted.
73
+
74
+ This overrides any previous result or exception.
75
+ """
76
+ self._result = result
77
+ self._exception = None
78
+ self._traceback = None
79
+
80
+ def force_exception(self, exception: BaseException) -> None:
81
+ """Force the result to fail with ``exception``.
82
+
83
+ This overrides any previous result or exception.
84
+
85
+ .. versionadded:: 1.1.0
86
+ """
87
+ self._result = None
88
+ self._exception = exception
89
+ self._traceback = exception.__traceback__ if exception is not None else None
90
+
91
+ def get_result(self) -> ResultType:
92
+ """Get the result(s) for this hook call.
93
+
94
+ If the hook was marked as a ``firstresult`` only a single value
95
+ will be returned, otherwise a list of results.
96
+ """
97
+ __tracebackhide__ = True
98
+ exc = self._exception
99
+ tb = self._traceback
100
+ if exc is None:
101
+ return cast(ResultType, self._result)
102
+ else:
103
+ raise exc.with_traceback(tb)
104
+
105
+
106
+ # Historical name (pluggy<=1.2), kept for backward compatibility.
107
+ _Result = Result
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_tracing.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Tracing utils
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from collections.abc import Sequence
8
+ from typing import Any
9
+ from typing import Callable
10
+
11
+
12
+ _Writer = Callable[[str], object]
13
+ _Processor = Callable[[tuple[str, ...], tuple[Any, ...]], object]
14
+
15
+
16
+ class TagTracer:
17
+ def __init__(self) -> None:
18
+ self._tags2proc: dict[tuple[str, ...], _Processor] = {}
19
+ self._writer: _Writer | None = None
20
+ self.indent = 0
21
+
22
+ def get(self, name: str) -> TagTracerSub:
23
+ return TagTracerSub(self, (name,))
24
+
25
+ def _format_message(self, tags: Sequence[str], args: Sequence[object]) -> str:
26
+ if isinstance(args[-1], dict):
27
+ extra = args[-1]
28
+ args = args[:-1]
29
+ else:
30
+ extra = {}
31
+
32
+ content = " ".join(map(str, args))
33
+ indent = " " * self.indent
34
+
35
+ lines = ["{}{} [{}]\n".format(indent, content, ":".join(tags))]
36
+
37
+ for name, value in extra.items():
38
+ lines.append(f"{indent} {name}: {value}\n")
39
+
40
+ return "".join(lines)
41
+
42
+ def _processmessage(self, tags: tuple[str, ...], args: tuple[object, ...]) -> None:
43
+ if self._writer is not None and args:
44
+ self._writer(self._format_message(tags, args))
45
+ try:
46
+ processor = self._tags2proc[tags]
47
+ except KeyError:
48
+ pass
49
+ else:
50
+ processor(tags, args)
51
+
52
+ def setwriter(self, writer: _Writer | None) -> None:
53
+ self._writer = writer
54
+
55
+ def setprocessor(self, tags: str | tuple[str, ...], processor: _Processor) -> None:
56
+ if isinstance(tags, str):
57
+ tags = tuple(tags.split(":"))
58
+ else:
59
+ assert isinstance(tags, tuple)
60
+ self._tags2proc[tags] = processor
61
+
62
+
63
+ class TagTracerSub:
64
+ def __init__(self, root: TagTracer, tags: tuple[str, ...]) -> None:
65
+ self.root = root
66
+ self.tags = tags
67
+
68
+ def __call__(self, *args: object) -> None:
69
+ self.root._processmessage(self.tags, args)
70
+
71
+ def get(self, name: str) -> TagTracerSub:
72
+ return self.__class__(self.root, self.tags + (name,))
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_version.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
5
+
6
+ TYPE_CHECKING = False
7
+ if TYPE_CHECKING:
8
+ from typing import Tuple
9
+ from typing import Union
10
+
11
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
12
+ else:
13
+ VERSION_TUPLE = object
14
+
15
+ version: str
16
+ __version__: str
17
+ __version_tuple__: VERSION_TUPLE
18
+ version_tuple: VERSION_TUPLE
19
+
20
+ __version__ = version = '1.6.0'
21
+ __version_tuple__ = version_tuple = (1, 6, 0)
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/_warnings.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import final
2
+
3
+
4
+ class PluggyWarning(UserWarning):
5
+ """Base class for all warnings emitted by pluggy."""
6
+
7
+ __module__ = "pluggy"
8
+
9
+
10
+ @final
11
+ class PluggyTeardownRaisedWarning(PluggyWarning):
12
+ """A plugin raised an exception during an :ref:`old-style hookwrapper
13
+ <old_style_hookwrappers>` teardown.
14
+
15
+ Such exceptions are not handled by pluggy, and may cause subsequent
16
+ teardowns to be executed at unexpected times, or be skipped entirely.
17
+
18
+ This is an issue in the plugin implementation.
19
+
20
+ If the exception is unintended, fix the underlying cause.
21
+
22
+ If the exception is intended, switch to :ref:`new-style hook wrappers
23
+ <hookwrappers>`, or use :func:`result.force_exception()
24
+ <pluggy.Result.force_exception>` to set the exception instead of raising.
25
+ """
26
+
27
+ __module__ = "pluggy"
personalPromptBoost/.venv/lib/python3.13/site-packages/pluggy/py.typed ADDED
File without changes
personalPromptBoost/.venv/lib/python3.13/site-packages/py.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # shim for pylib going away
2
+ # if pylib is installed this file will get skipped
3
+ # (`py/__init__.py` has higher precedence)
4
+ from __future__ import annotations
5
+
6
+ import sys
7
+
8
+ import _pytest._py.error as error
9
+ import _pytest._py.path as path
10
+
11
+
12
+ sys.modules["py.error"] = error
13
+ sys.modules["py.path"] = path
14
+
15
+ __all__ = ["error", "path"]
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ uv
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/METADATA ADDED
The diff for this file is too large to render. See raw diff
 
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/RECORD ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ pydantic-2.13.3.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
2
+ pydantic-2.13.3.dist-info/METADATA,sha256=dAqUziUUUKWugJ5oi9jnm5ZtqZ9nEZ8gIM45DV2917o,108770
3
+ pydantic-2.13.3.dist-info/RECORD,,
4
+ pydantic-2.13.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ pydantic-2.13.3.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
6
+ pydantic-2.13.3.dist-info/licenses/LICENSE,sha256=qeGG88oWte74QxjnpwFyE1GgDLe4rjpDlLZ7SeNSnvM,1129
7
+ pydantic/__init__.py,sha256=5iEnJ4wHv1OEzdKQPzaKaZKfO4pSQAC65ODrYI6_S8Y,15812
8
+ pydantic/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ pydantic/_internal/_config.py,sha256=Rzys1Joffn4JczElcYDqsZLRgBgHn2lYWqDR55oASPA,14839
10
+ pydantic/_internal/_core_metadata.py,sha256=Y_g2t3i7uluK-wXCZvzJfRFMPUM23aBYLfae4FzBPy0,5162
11
+ pydantic/_internal/_core_utils.py,sha256=1jru4VbJ0x63R6dtVcuOI-dKQTC_d_lSnJWEBQzGNEQ,6487
12
+ pydantic/_internal/_dataclasses.py,sha256=Zgqcm1WaJLBwTQQC5mGKNowjlTgX3mfX_J5e2vd24lM,13188
13
+ pydantic/_internal/_decorators.py,sha256=RDEG_Jau5NiJcfO0xgdT7EOgsU1LgWIYlX7wN5rYtVs,33620
14
+ pydantic/_internal/_decorators_v1.py,sha256=tfdfdpQKY4R2XCOwqHbZeoQMur6VNigRrfhudXBHx38,6185
15
+ pydantic/_internal/_discriminated_union.py,sha256=JLx_MVLep7Mxl1zbpdNZjvHDcz-J3OEW6WcdV184dcM,26255
16
+ pydantic/_internal/_docs_extraction.py,sha256=fyznSAHh5AzohnXZStV0HvH-nRbavNHPyg-knx-S_EE,4127
17
+ pydantic/_internal/_fields.py,sha256=hXeb-zodGwTDvG9OK1um18P64b7cqHb0GOngP4jrgcY,31557
18
+ pydantic/_internal/_forward_ref.py,sha256=5n3Y7-3AKLn8_FS3Yc7KutLiPUhyXmAtkEZOaFnonwM,611
19
+ pydantic/_internal/_generate_schema.py,sha256=lw4y1t5HKIDBosr9QgYtC7-GBu5y0g9qR7ZO3XUufBA,135560
20
+ pydantic/_internal/_generics.py,sha256=CXjcInlvci8VejaWn1f39kv0AcfJL0R523qRLFZVD-s,23393
21
+ pydantic/_internal/_git.py,sha256=IwPh3DPfa2Xq3rBuB9Nx8luR2A1i69QdeTfWWXIuCVg,809
22
+ pydantic/_internal/_import_utils.py,sha256=TRhxD5OuY6CUosioBdBcJUs0om7IIONiZdYAV7zQ8jM,402
23
+ pydantic/_internal/_internal_dataclass.py,sha256=_bedc1XbuuygRGiLZqkUkwwFpQaoR1hKLlR501nyySY,144
24
+ pydantic/_internal/_known_annotated_metadata.py,sha256=PynQIFQ61__4Gcrzn0D5ENllg7jPq_cxoLTmuFQBY88,16805
25
+ pydantic/_internal/_mock_val_ser.py,sha256=wmRRFSBvqfcLbI41PsFliB4u2AZ3mJpZeiERbD3xKTo,8885
26
+ pydantic/_internal/_model_construction.py,sha256=JoKmY4JrDBu3nG_tCIrJgtJJE1uq6v29TvTz5ElHE5g,38928
27
+ pydantic/_internal/_namespace_utils.py,sha256=hl3-TRAr82U2jTyPP3t-QqsvKLirxtkLfNfrN-fp0x8,12878
28
+ pydantic/_internal/_repr.py,sha256=jQfnJuyDxQpSRNhG29II9PX8e4Nv2qWZrEw2lqih3UE,5172
29
+ pydantic/_internal/_schema_gather.py,sha256=8nJ-uM6Y4z6xpasnGonEMubtNVX_mxeeRDFmd_qMVLA,9052
30
+ pydantic/_internal/_schema_generation_shared.py,sha256=F_rbQbrkoomgxsskdHpP0jUJ7TCfe0BADAEkq6CJ4nM,4842
31
+ pydantic/_internal/_serializers.py,sha256=YIWvSmAR5fnbGSWCOQduWt1yB4ZQY42eAruc-enrb6c,1491
32
+ pydantic/_internal/_signature.py,sha256=i_b6wtluiVWZRh1ZY8UvB2UZziP1KjqSXZgC-HxwOT0,6808
33
+ pydantic/_internal/_typing_extra.py,sha256=dDxqF46lzuqCoKLrAH_k95EDbayEeKb2lHjuTJ5OBoY,31574
34
+ pydantic/_internal/_utils.py,sha256=gN48BsR-FDrJDibCmo69ttQg67WbuFrdy_1NQL3cvLI,15959
35
+ pydantic/_internal/_validate_call.py,sha256=OD_BspHaL9FKzZ9XrndhiEuMnjF3SRIJUHtwv6yUffU,5366
36
+ pydantic/_internal/_validators.py,sha256=7GTjXXWFMLib4dxQ-HeaiHlAZiR2B2G8byCYMGrmQ48,20563
37
+ pydantic/_migration.py,sha256=VF73LRCUz3Irb5xVt13jb3NAcXVnEF6T1-J0OLfeZ5A,12160
38
+ pydantic/alias_generators.py,sha256=KM1n3u4JfLSBl1UuYg3hoYHzXJD-yvgrnq8u1ccwh_A,2124
39
+ pydantic/aliases.py,sha256=vhCHyoSWnX-EJ-wWb5qj4xyRssgGWnTQfzQp4GSZ9ug,4937
40
+ pydantic/annotated_handlers.py,sha256=WfyFSqwoEIFXBh7T73PycKloI1DiX45GWi0-JOsCR4Y,4407
41
+ pydantic/class_validators.py,sha256=i_V3j-PYdGLSLmj_IJZekTRjunO8SIVz8LMlquPyP7E,148
42
+ pydantic/color.py,sha256=AzqGfVQHF92_ZctDcue0DM4yTp2P6tekkwRINTWrLIo,21481
43
+ pydantic/config.py,sha256=o1P67FMWIQG-_RfGtKislkHwo4pXm_6jfsR41P88v78,44533
44
+ pydantic/dataclasses.py,sha256=4X9We0jj1KLwBtvYSkAFXNon46zrpBmRZANf4LfwbXg,18963
45
+ pydantic/datetime_parse.py,sha256=QC-WgMxMr_wQ_mNXUS7AVf-2hLEhvvsPY1PQyhSGOdk,150
46
+ pydantic/decorator.py,sha256=YX-jUApu5AKaVWKPoaV-n-4l7UbS69GEt9Ra3hszmKI,145
47
+ pydantic/deprecated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
+ pydantic/deprecated/class_validators.py,sha256=n0jYQOcb5YQiw0b7YXyi7NPiYdV7ujWR4KyZumjTPok,10281
49
+ pydantic/deprecated/config.py,sha256=k_lsVk57paxLJOcBueH07cu1OgEgWdVBxm6lfaC3CCU,2663
50
+ pydantic/deprecated/copy_internals.py,sha256=Ghd-vkMd5EYCCgyCGtPKO58np9cEKBQC6qkBeIEFI2g,7618
51
+ pydantic/deprecated/decorator.py,sha256=TBm6bJ7wJsNih_8Wq5IzDcwP32m9_vfxs96desLuk00,10845
52
+ pydantic/deprecated/json.py,sha256=HlWCG35RRrxyzuTS6LTQiZBwRhmDZWmeqQH8rLW6wA8,4657
53
+ pydantic/deprecated/parse.py,sha256=Gzd6b_g8zJXcuE7QRq5adhx_EMJahXfcpXCF0RgrqqI,2511
54
+ pydantic/deprecated/tools.py,sha256=Nrm9oFRZWp8-jlfvPgJILEsywp4YzZD52XIGPDLxHcI,3330
55
+ pydantic/env_settings.py,sha256=6IHeeWEqlUPRUv3V-AXiF_W91fg2Jw_M3O0l34J_eyA,148
56
+ pydantic/error_wrappers.py,sha256=RK6mqATc9yMD-KBD9IJS9HpKCprWHd8wo84Bnm-3fR8,150
57
+ pydantic/errors.py,sha256=DrECPCWhSYrQ8Ba4O8hKzIAM2i9GBHTXWALzaFDpLf4,6013
58
+ pydantic/experimental/__init__.py,sha256=QT7rKYdDsCiTJ9GEjmsQdWHScwpKrrNkGq6vqONP6RQ,104
59
+ pydantic/experimental/arguments_schema.py,sha256=EFnjX_ulp-tPyUjQX5pmQtug1OFL_Acc8bcMbLd-fVY,1866
60
+ pydantic/experimental/missing_sentinel.py,sha256=hQejgtF00wUuQMni9429evg-eXyIwpKvjsD8ofqfj-w,127
61
+ pydantic/experimental/pipeline.py,sha256=auoW6l6g1FC41LciPmsI1M6ncf00Szde9B3C-yvb9mI,23956
62
+ pydantic/fields.py,sha256=a8ZhJfI8FD6TQDD7-cWMm1ZXlQva0wMdT2Ey5VvVe-M,82023
63
+ pydantic/functional_serializers.py,sha256=zwRAjZusORtEbtxpVU20kg8FpemyZz4Fq6wJk1mpwYQ,18117
64
+ pydantic/functional_validators.py,sha256=7p-4jvP__9jZyvcdXiide5pAa_JlM7fJ1BgkqbjxSWM,31724
65
+ pydantic/generics.py,sha256=0ZqZ9O9annIj_3mGBRqps4htey3b5lV1-d2tUxPMMnA,144
66
+ pydantic/json.py,sha256=ZH8RkI7h4Bz-zp8OdTAxbJUoVvcoU-jhMdRZ0B-k0xc,140
67
+ pydantic/json_schema.py,sha256=ZVJNgaKCcna-M_pcooDQAjFXKvxwO2maKHLKHrs1r3A,126176
68
+ pydantic/main.py,sha256=NbhCz-ku8wDgYLQMBi75Ov7hywdc8LewA3oUNIZ8JVQ,85334
69
+ pydantic/mypy.py,sha256=sYmmZrL_GvoYSLcBuPRRDfSfgQWehkzw_ZvNkwDY2ME,60971
70
+ pydantic/networks.py,sha256=gCB96gt0G7tiVDhVnJfpKr1ARL5qkH-SPZkuNkmG2O4,42102
71
+ pydantic/parse.py,sha256=wkd82dgtvWtD895U_I6E1htqMlGhBSYEV39cuBSeo3A,141
72
+ pydantic/plugin/__init__.py,sha256=a7Tw366U6K3kltCCNZY76nc9ss-7uGGQ40TXad9OypQ,7333
73
+ pydantic/plugin/_loader.py,sha256=hAjgSljoIhGx3AVpIpuqw5SPttBNNeGBSTrqSMnNiJk,2213
74
+ pydantic/plugin/_schema_validator.py,sha256=5M5Ic1bZnjhNDxtRDVKbRPTQ6po6QuKMY7MguMkHeW0,5445
75
+ pydantic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
+ pydantic/root_model.py,sha256=cOMoeWdp536KF85uRIcW-oz1O7d5GRCpx9HTS4-1uf8,6394
77
+ pydantic/schema.py,sha256=Vqqjvq_LnapVknebUd3Bp_J1p2gXZZnZRgL48bVEG7o,142
78
+ pydantic/tools.py,sha256=iHQpd8SJ5DCTtPV5atAV06T89bjSaMFeZZ2LX9lasZY,141
79
+ pydantic/type_adapter.py,sha256=T05g8WQczBsVU_35RdKxgjIi7Y7LIip67pF3NI7X4GE,36123
80
+ pydantic/types.py,sha256=fpYcGnAncK4QjaFm3jZtqYwxJYzB7rJJPfAl89emzyQ,105961
81
+ pydantic/typing.py,sha256=P7feA35MwTcLsR1uL7db0S-oydBxobmXa55YDoBgajQ,138
82
+ pydantic/utils.py,sha256=15nR2QpqTBFlQV4TNtTItMyTJx_fbyV-gPmIEY1Gooc,141
83
+ pydantic/v1/__init__.py,sha256=SxQPklgBs4XHJwE6BZ9qoewYoGiNyYUnmHzEFCZbfnI,2946
84
+ pydantic/v1/_hypothesis_plugin.py,sha256=5ES5xWuw1FQAsymLezy8QgnVz0ZpVfU3jkmT74H27VQ,14847
85
+ pydantic/v1/annotated_types.py,sha256=uk2NAAxqiNELKjiHhyhxKaIOh8F1lYW_LzrW3X7oZBc,3157
86
+ pydantic/v1/class_validators.py,sha256=ULOaIUgYUDBsHL7EEVEarcM-UubKUggoN8hSbDonsFE,14672
87
+ pydantic/v1/color.py,sha256=iZABLYp6OVoo2AFkP9Ipri_wSc6-Kklu8YuhSartd5g,16844
88
+ pydantic/v1/config.py,sha256=a6P0Wer9x4cbwKW7Xv8poSUqM4WP-RLWwX6YMpYq9AA,6532
89
+ pydantic/v1/dataclasses.py,sha256=784cqvInbwIPWr9usfpX3ch7z4t3J2tTK6N067_wk1o,18172
90
+ pydantic/v1/datetime_parse.py,sha256=4Qy1kQpq3rNVZJeIHeSPDpuS2Bvhp1KPtzJG1xu-H00,7724
91
+ pydantic/v1/decorator.py,sha256=zaaxxxoWPCm818D1bs0yhapRjXm32V8G0ZHWCdM1uXA,10339
92
+ pydantic/v1/env_settings.py,sha256=A9VXwtRl02AY-jH0C0ouy5VNw3fi6F_pkzuHDjgAAOM,14105
93
+ pydantic/v1/error_wrappers.py,sha256=6625Mfw9qkC2NwitB_JFAWe8B-Xv6zBU7rL9k28tfyo,5196
94
+ pydantic/v1/errors.py,sha256=mIwPED5vGM5Q5v4C4Z1JPldTRH-omvEylH6ksMhOmPw,17726
95
+ pydantic/v1/fields.py,sha256=VqWJCriUNiEyptXroDVJ501JpVA0en2VANcksqXL2b8,50649
96
+ pydantic/v1/generics.py,sha256=YzyKTZN6x5Q1RGJ3WQ9jN-uwHJxL3W4qoZqwcZXqxWg,17829
97
+ pydantic/v1/json.py,sha256=WQ5Hy_hIpfdR3YS8k6N2E6KMJzsdbBi_ldWOPJaV81M,3390
98
+ pydantic/v1/main.py,sha256=vRB1TbpkzPN3P5ijJlc-cjNuO-HciNOpC4b8K3zZnfc,45697
99
+ pydantic/v1/mypy.py,sha256=Cl8XRfCmIcVE3j5AEU52C8iDh8lcX__D3hz2jIWxMAs,38860
100
+ pydantic/v1/networks.py,sha256=HYNtKAfOmOnKJpsDg1g6SIkj9WPhU_-i8l5e2JKBpG4,22124
101
+ pydantic/v1/parse.py,sha256=BJtdqiZRtav9VRFCmOxoY-KImQmjPy-A_NoojiFUZxY,1821
102
+ pydantic/v1/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
+ pydantic/v1/schema.py,sha256=aqBuA--cq8gAVkim5BJPFASHzOZ8dFtmFX_fNGr6ip4,47801
104
+ pydantic/v1/tools.py,sha256=1lDdXHk0jL5uP3u5RCYAvUAlGClgAO-45lkq9j7fyBA,2881
105
+ pydantic/v1/types.py,sha256=Bzl-RcnitPBHnqwwj9iv7JjHuN1GpnWH24dKkF3l9e8,35455
106
+ pydantic/v1/typing.py,sha256=ovwtLpEZCbnghZaHfSNJupzetzHNkLXjn_66kgTnIV4,20102
107
+ pydantic/v1/utils.py,sha256=1PqOIlz6OVWwGds3HBKlw4Et6asFou0UUpAto7jFOCs,26014
108
+ pydantic/v1/validators.py,sha256=lyUkn1MWhHxlCX5ZfEgFj_CAHojoiPcaQeMdEM9XviU,22187
109
+ pydantic/v1/version.py,sha256=YpHWOQKtGoxfyikzGrcmXJVKUVYB9EBdoCR994QxSnE,1039
110
+ pydantic/validate_call_decorator.py,sha256=VLAi4hoFpjC-1eL0HixYaaWaEFO6htGcDctgsqa5VII,4416
111
+ pydantic/validators.py,sha256=pwbIJXVb1CV2mAE4w_EGfNj7DwzsKaWw_tTL6cviTus,146
112
+ pydantic/version.py,sha256=IZU9hqNGrX_3ZH-zhAb_nWXVDa2MXm5jm7IbAxYxyn4,3985
113
+ pydantic/warnings.py,sha256=3QyQo6lN35cO7OXDbFEXWcNaPlGCRaregVZA-G-lZwI,4822
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/REQUESTED ADDED
File without changes
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic-2.13.3.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 to present Pydantic Services Inc. and individual contributors.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/__init__.py ADDED
@@ -0,0 +1,456 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from importlib import import_module
2
+ from typing import TYPE_CHECKING
3
+ from warnings import warn
4
+
5
+ from ._migration import getattr_migration
6
+ from .version import VERSION, _ensure_pydantic_core_version
7
+
8
+ _ensure_pydantic_core_version()
9
+ del _ensure_pydantic_core_version
10
+
11
+ if TYPE_CHECKING:
12
+ # import of virtually everything is supported via `__getattr__` below,
13
+ # but we need them here for type checking and IDE support
14
+ import pydantic_core
15
+ from pydantic_core.core_schema import (
16
+ FieldSerializationInfo,
17
+ SerializationInfo,
18
+ SerializerFunctionWrapHandler,
19
+ ValidationInfo,
20
+ ValidatorFunctionWrapHandler,
21
+ )
22
+
23
+ from . import dataclasses
24
+ from .aliases import AliasChoices, AliasGenerator, AliasPath
25
+ from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler
26
+ from .config import ConfigDict, with_config
27
+ from .errors import *
28
+ from .fields import Field, PrivateAttr, computed_field
29
+ from .functional_serializers import (
30
+ PlainSerializer,
31
+ SerializeAsAny,
32
+ WrapSerializer,
33
+ field_serializer,
34
+ model_serializer,
35
+ )
36
+ from .functional_validators import (
37
+ AfterValidator,
38
+ BeforeValidator,
39
+ InstanceOf,
40
+ ModelWrapValidatorHandler,
41
+ PlainValidator,
42
+ SkipValidation,
43
+ ValidateAs,
44
+ WrapValidator,
45
+ field_validator,
46
+ model_validator,
47
+ )
48
+ from .json_schema import WithJsonSchema
49
+ from .main import *
50
+ from .networks import *
51
+ from .type_adapter import TypeAdapter
52
+ from .types import *
53
+ from .validate_call_decorator import validate_call
54
+ from .warnings import (
55
+ PydanticDeprecatedSince20,
56
+ PydanticDeprecatedSince26,
57
+ PydanticDeprecatedSince29,
58
+ PydanticDeprecatedSince210,
59
+ PydanticDeprecatedSince211,
60
+ PydanticDeprecatedSince212,
61
+ PydanticDeprecationWarning,
62
+ PydanticExperimentalWarning,
63
+ )
64
+
65
+ # this encourages pycharm to import `ValidationError` from here, not pydantic_core
66
+ ValidationError = pydantic_core.ValidationError
67
+ from .deprecated.class_validators import root_validator, validator
68
+ from .deprecated.config import BaseConfig, Extra
69
+ from .deprecated.tools import *
70
+ from .root_model import RootModel
71
+
72
+ __version__ = VERSION
73
+ __all__ = (
74
+ # dataclasses
75
+ 'dataclasses',
76
+ # functional validators
77
+ 'field_validator',
78
+ 'model_validator',
79
+ 'AfterValidator',
80
+ 'BeforeValidator',
81
+ 'PlainValidator',
82
+ 'WrapValidator',
83
+ 'SkipValidation',
84
+ 'ValidateAs',
85
+ 'InstanceOf',
86
+ 'ModelWrapValidatorHandler',
87
+ # JSON Schema
88
+ 'WithJsonSchema',
89
+ # deprecated V1 functional validators, these are imported via `__getattr__` below
90
+ 'root_validator',
91
+ 'validator',
92
+ # functional serializers
93
+ 'field_serializer',
94
+ 'model_serializer',
95
+ 'PlainSerializer',
96
+ 'SerializeAsAny',
97
+ 'WrapSerializer',
98
+ # config
99
+ 'ConfigDict',
100
+ 'with_config',
101
+ # deprecated V1 config, these are imported via `__getattr__` below
102
+ 'BaseConfig',
103
+ 'Extra',
104
+ # validate_call
105
+ 'validate_call',
106
+ # errors
107
+ 'PydanticErrorCodes',
108
+ 'PydanticUserError',
109
+ 'PydanticSchemaGenerationError',
110
+ 'PydanticImportError',
111
+ 'PydanticUndefinedAnnotation',
112
+ 'PydanticInvalidForJsonSchema',
113
+ 'PydanticForbiddenQualifier',
114
+ # fields
115
+ 'Field',
116
+ 'computed_field',
117
+ 'PrivateAttr',
118
+ # alias
119
+ 'AliasChoices',
120
+ 'AliasGenerator',
121
+ 'AliasPath',
122
+ # main
123
+ 'BaseModel',
124
+ 'create_model',
125
+ # network
126
+ 'AnyUrl',
127
+ 'AnyHttpUrl',
128
+ 'FileUrl',
129
+ 'HttpUrl',
130
+ 'FtpUrl',
131
+ 'WebsocketUrl',
132
+ 'AnyWebsocketUrl',
133
+ 'UrlConstraints',
134
+ 'EmailStr',
135
+ 'NameEmail',
136
+ 'IPvAnyAddress',
137
+ 'IPvAnyInterface',
138
+ 'IPvAnyNetwork',
139
+ 'PostgresDsn',
140
+ 'CockroachDsn',
141
+ 'AmqpDsn',
142
+ 'RedisDsn',
143
+ 'MongoDsn',
144
+ 'KafkaDsn',
145
+ 'NatsDsn',
146
+ 'MySQLDsn',
147
+ 'MariaDBDsn',
148
+ 'ClickHouseDsn',
149
+ 'SnowflakeDsn',
150
+ 'validate_email',
151
+ # root_model
152
+ 'RootModel',
153
+ # deprecated tools, these are imported via `__getattr__` below
154
+ 'parse_obj_as',
155
+ 'schema_of',
156
+ 'schema_json_of',
157
+ # types
158
+ 'Strict',
159
+ 'StrictStr',
160
+ 'conbytes',
161
+ 'conlist',
162
+ 'conset',
163
+ 'confrozenset',
164
+ 'constr',
165
+ 'StringConstraints',
166
+ 'ImportString',
167
+ 'conint',
168
+ 'PositiveInt',
169
+ 'NegativeInt',
170
+ 'NonNegativeInt',
171
+ 'NonPositiveInt',
172
+ 'confloat',
173
+ 'PositiveFloat',
174
+ 'NegativeFloat',
175
+ 'NonNegativeFloat',
176
+ 'NonPositiveFloat',
177
+ 'FiniteFloat',
178
+ 'condecimal',
179
+ 'condate',
180
+ 'UUID1',
181
+ 'UUID3',
182
+ 'UUID4',
183
+ 'UUID5',
184
+ 'UUID6',
185
+ 'UUID7',
186
+ 'UUID8',
187
+ 'FilePath',
188
+ 'DirectoryPath',
189
+ 'NewPath',
190
+ 'Json',
191
+ 'Secret',
192
+ 'SecretStr',
193
+ 'SecretBytes',
194
+ 'SocketPath',
195
+ 'StrictBool',
196
+ 'StrictBytes',
197
+ 'StrictInt',
198
+ 'StrictFloat',
199
+ 'PaymentCardNumber',
200
+ 'ByteSize',
201
+ 'PastDate',
202
+ 'FutureDate',
203
+ 'PastDatetime',
204
+ 'FutureDatetime',
205
+ 'AwareDatetime',
206
+ 'NaiveDatetime',
207
+ 'AllowInfNan',
208
+ 'EncoderProtocol',
209
+ 'EncodedBytes',
210
+ 'EncodedStr',
211
+ 'Base64Encoder',
212
+ 'Base64Bytes',
213
+ 'Base64Str',
214
+ 'Base64UrlBytes',
215
+ 'Base64UrlStr',
216
+ 'GetPydanticSchema',
217
+ 'Tag',
218
+ 'Discriminator',
219
+ 'JsonValue',
220
+ 'FailFast',
221
+ # type_adapter
222
+ 'TypeAdapter',
223
+ # version
224
+ '__version__',
225
+ 'VERSION',
226
+ # warnings
227
+ 'PydanticDeprecatedSince20',
228
+ 'PydanticDeprecatedSince26',
229
+ 'PydanticDeprecatedSince29',
230
+ 'PydanticDeprecatedSince210',
231
+ 'PydanticDeprecatedSince211',
232
+ 'PydanticDeprecatedSince212',
233
+ 'PydanticDeprecationWarning',
234
+ 'PydanticExperimentalWarning',
235
+ # annotated handlers
236
+ 'GetCoreSchemaHandler',
237
+ 'GetJsonSchemaHandler',
238
+ # pydantic_core
239
+ 'ValidationError',
240
+ 'ValidationInfo',
241
+ 'SerializationInfo',
242
+ 'ValidatorFunctionWrapHandler',
243
+ 'FieldSerializationInfo',
244
+ 'SerializerFunctionWrapHandler',
245
+ 'OnErrorOmit',
246
+ )
247
+
248
+ # A mapping of {<member name>: (package, <module name>)} defining dynamic imports
249
+ _dynamic_imports: 'dict[str, tuple[str, str]]' = {
250
+ 'dataclasses': (__spec__.parent, '__module__'),
251
+ # functional validators
252
+ 'field_validator': (__spec__.parent, '.functional_validators'),
253
+ 'model_validator': (__spec__.parent, '.functional_validators'),
254
+ 'AfterValidator': (__spec__.parent, '.functional_validators'),
255
+ 'BeforeValidator': (__spec__.parent, '.functional_validators'),
256
+ 'PlainValidator': (__spec__.parent, '.functional_validators'),
257
+ 'WrapValidator': (__spec__.parent, '.functional_validators'),
258
+ 'SkipValidation': (__spec__.parent, '.functional_validators'),
259
+ 'InstanceOf': (__spec__.parent, '.functional_validators'),
260
+ 'ValidateAs': (__spec__.parent, '.functional_validators'),
261
+ 'ModelWrapValidatorHandler': (__spec__.parent, '.functional_validators'),
262
+ # JSON Schema
263
+ 'WithJsonSchema': (__spec__.parent, '.json_schema'),
264
+ # functional serializers
265
+ 'field_serializer': (__spec__.parent, '.functional_serializers'),
266
+ 'model_serializer': (__spec__.parent, '.functional_serializers'),
267
+ 'PlainSerializer': (__spec__.parent, '.functional_serializers'),
268
+ 'SerializeAsAny': (__spec__.parent, '.functional_serializers'),
269
+ 'WrapSerializer': (__spec__.parent, '.functional_serializers'),
270
+ # config
271
+ 'ConfigDict': (__spec__.parent, '.config'),
272
+ 'with_config': (__spec__.parent, '.config'),
273
+ # validate call
274
+ 'validate_call': (__spec__.parent, '.validate_call_decorator'),
275
+ # errors
276
+ 'PydanticErrorCodes': (__spec__.parent, '.errors'),
277
+ 'PydanticUserError': (__spec__.parent, '.errors'),
278
+ 'PydanticSchemaGenerationError': (__spec__.parent, '.errors'),
279
+ 'PydanticImportError': (__spec__.parent, '.errors'),
280
+ 'PydanticUndefinedAnnotation': (__spec__.parent, '.errors'),
281
+ 'PydanticInvalidForJsonSchema': (__spec__.parent, '.errors'),
282
+ 'PydanticForbiddenQualifier': (__spec__.parent, '.errors'),
283
+ # fields
284
+ 'Field': (__spec__.parent, '.fields'),
285
+ 'computed_field': (__spec__.parent, '.fields'),
286
+ 'PrivateAttr': (__spec__.parent, '.fields'),
287
+ # alias
288
+ 'AliasChoices': (__spec__.parent, '.aliases'),
289
+ 'AliasGenerator': (__spec__.parent, '.aliases'),
290
+ 'AliasPath': (__spec__.parent, '.aliases'),
291
+ # main
292
+ 'BaseModel': (__spec__.parent, '.main'),
293
+ 'create_model': (__spec__.parent, '.main'),
294
+ # network
295
+ 'AnyUrl': (__spec__.parent, '.networks'),
296
+ 'AnyHttpUrl': (__spec__.parent, '.networks'),
297
+ 'FileUrl': (__spec__.parent, '.networks'),
298
+ 'HttpUrl': (__spec__.parent, '.networks'),
299
+ 'FtpUrl': (__spec__.parent, '.networks'),
300
+ 'WebsocketUrl': (__spec__.parent, '.networks'),
301
+ 'AnyWebsocketUrl': (__spec__.parent, '.networks'),
302
+ 'UrlConstraints': (__spec__.parent, '.networks'),
303
+ 'EmailStr': (__spec__.parent, '.networks'),
304
+ 'NameEmail': (__spec__.parent, '.networks'),
305
+ 'IPvAnyAddress': (__spec__.parent, '.networks'),
306
+ 'IPvAnyInterface': (__spec__.parent, '.networks'),
307
+ 'IPvAnyNetwork': (__spec__.parent, '.networks'),
308
+ 'PostgresDsn': (__spec__.parent, '.networks'),
309
+ 'CockroachDsn': (__spec__.parent, '.networks'),
310
+ 'AmqpDsn': (__spec__.parent, '.networks'),
311
+ 'RedisDsn': (__spec__.parent, '.networks'),
312
+ 'MongoDsn': (__spec__.parent, '.networks'),
313
+ 'KafkaDsn': (__spec__.parent, '.networks'),
314
+ 'NatsDsn': (__spec__.parent, '.networks'),
315
+ 'MySQLDsn': (__spec__.parent, '.networks'),
316
+ 'MariaDBDsn': (__spec__.parent, '.networks'),
317
+ 'ClickHouseDsn': (__spec__.parent, '.networks'),
318
+ 'SnowflakeDsn': (__spec__.parent, '.networks'),
319
+ 'validate_email': (__spec__.parent, '.networks'),
320
+ # root_model
321
+ 'RootModel': (__spec__.parent, '.root_model'),
322
+ # types
323
+ 'Strict': (__spec__.parent, '.types'),
324
+ 'StrictStr': (__spec__.parent, '.types'),
325
+ 'conbytes': (__spec__.parent, '.types'),
326
+ 'conlist': (__spec__.parent, '.types'),
327
+ 'conset': (__spec__.parent, '.types'),
328
+ 'confrozenset': (__spec__.parent, '.types'),
329
+ 'constr': (__spec__.parent, '.types'),
330
+ 'StringConstraints': (__spec__.parent, '.types'),
331
+ 'ImportString': (__spec__.parent, '.types'),
332
+ 'conint': (__spec__.parent, '.types'),
333
+ 'PositiveInt': (__spec__.parent, '.types'),
334
+ 'NegativeInt': (__spec__.parent, '.types'),
335
+ 'NonNegativeInt': (__spec__.parent, '.types'),
336
+ 'NonPositiveInt': (__spec__.parent, '.types'),
337
+ 'confloat': (__spec__.parent, '.types'),
338
+ 'PositiveFloat': (__spec__.parent, '.types'),
339
+ 'NegativeFloat': (__spec__.parent, '.types'),
340
+ 'NonNegativeFloat': (__spec__.parent, '.types'),
341
+ 'NonPositiveFloat': (__spec__.parent, '.types'),
342
+ 'FiniteFloat': (__spec__.parent, '.types'),
343
+ 'condecimal': (__spec__.parent, '.types'),
344
+ 'condate': (__spec__.parent, '.types'),
345
+ 'UUID1': (__spec__.parent, '.types'),
346
+ 'UUID3': (__spec__.parent, '.types'),
347
+ 'UUID4': (__spec__.parent, '.types'),
348
+ 'UUID5': (__spec__.parent, '.types'),
349
+ 'UUID6': (__spec__.parent, '.types'),
350
+ 'UUID7': (__spec__.parent, '.types'),
351
+ 'UUID8': (__spec__.parent, '.types'),
352
+ 'FilePath': (__spec__.parent, '.types'),
353
+ 'DirectoryPath': (__spec__.parent, '.types'),
354
+ 'NewPath': (__spec__.parent, '.types'),
355
+ 'Json': (__spec__.parent, '.types'),
356
+ 'Secret': (__spec__.parent, '.types'),
357
+ 'SecretStr': (__spec__.parent, '.types'),
358
+ 'SecretBytes': (__spec__.parent, '.types'),
359
+ 'StrictBool': (__spec__.parent, '.types'),
360
+ 'StrictBytes': (__spec__.parent, '.types'),
361
+ 'StrictInt': (__spec__.parent, '.types'),
362
+ 'StrictFloat': (__spec__.parent, '.types'),
363
+ 'PaymentCardNumber': (__spec__.parent, '.types'),
364
+ 'ByteSize': (__spec__.parent, '.types'),
365
+ 'PastDate': (__spec__.parent, '.types'),
366
+ 'SocketPath': (__spec__.parent, '.types'),
367
+ 'FutureDate': (__spec__.parent, '.types'),
368
+ 'PastDatetime': (__spec__.parent, '.types'),
369
+ 'FutureDatetime': (__spec__.parent, '.types'),
370
+ 'AwareDatetime': (__spec__.parent, '.types'),
371
+ 'NaiveDatetime': (__spec__.parent, '.types'),
372
+ 'AllowInfNan': (__spec__.parent, '.types'),
373
+ 'EncoderProtocol': (__spec__.parent, '.types'),
374
+ 'EncodedBytes': (__spec__.parent, '.types'),
375
+ 'EncodedStr': (__spec__.parent, '.types'),
376
+ 'Base64Encoder': (__spec__.parent, '.types'),
377
+ 'Base64Bytes': (__spec__.parent, '.types'),
378
+ 'Base64Str': (__spec__.parent, '.types'),
379
+ 'Base64UrlBytes': (__spec__.parent, '.types'),
380
+ 'Base64UrlStr': (__spec__.parent, '.types'),
381
+ 'GetPydanticSchema': (__spec__.parent, '.types'),
382
+ 'Tag': (__spec__.parent, '.types'),
383
+ 'Discriminator': (__spec__.parent, '.types'),
384
+ 'JsonValue': (__spec__.parent, '.types'),
385
+ 'OnErrorOmit': (__spec__.parent, '.types'),
386
+ 'FailFast': (__spec__.parent, '.types'),
387
+ # type_adapter
388
+ 'TypeAdapter': (__spec__.parent, '.type_adapter'),
389
+ # warnings
390
+ 'PydanticDeprecatedSince20': (__spec__.parent, '.warnings'),
391
+ 'PydanticDeprecatedSince26': (__spec__.parent, '.warnings'),
392
+ 'PydanticDeprecatedSince29': (__spec__.parent, '.warnings'),
393
+ 'PydanticDeprecatedSince210': (__spec__.parent, '.warnings'),
394
+ 'PydanticDeprecatedSince211': (__spec__.parent, '.warnings'),
395
+ 'PydanticDeprecatedSince212': (__spec__.parent, '.warnings'),
396
+ 'PydanticDeprecationWarning': (__spec__.parent, '.warnings'),
397
+ 'PydanticExperimentalWarning': (__spec__.parent, '.warnings'),
398
+ # annotated handlers
399
+ 'GetCoreSchemaHandler': (__spec__.parent, '.annotated_handlers'),
400
+ 'GetJsonSchemaHandler': (__spec__.parent, '.annotated_handlers'),
401
+ # pydantic_core stuff
402
+ 'ValidationError': ('pydantic_core', '.'),
403
+ 'ValidationInfo': ('pydantic_core', '.core_schema'),
404
+ 'SerializationInfo': ('pydantic_core', '.core_schema'),
405
+ 'ValidatorFunctionWrapHandler': ('pydantic_core', '.core_schema'),
406
+ 'FieldSerializationInfo': ('pydantic_core', '.core_schema'),
407
+ 'SerializerFunctionWrapHandler': ('pydantic_core', '.core_schema'),
408
+ # deprecated, mostly not included in __all__
409
+ 'root_validator': (__spec__.parent, '.deprecated.class_validators'),
410
+ 'validator': (__spec__.parent, '.deprecated.class_validators'),
411
+ 'BaseConfig': (__spec__.parent, '.deprecated.config'),
412
+ 'Extra': (__spec__.parent, '.deprecated.config'),
413
+ 'parse_obj_as': (__spec__.parent, '.deprecated.tools'),
414
+ 'schema_of': (__spec__.parent, '.deprecated.tools'),
415
+ 'schema_json_of': (__spec__.parent, '.deprecated.tools'),
416
+ # deprecated dynamic imports
417
+ 'FieldValidationInfo': ('pydantic_core', '.core_schema'),
418
+ 'GenerateSchema': (__spec__.parent, '._internal._generate_schema'),
419
+ }
420
+ _deprecated_dynamic_imports = {'FieldValidationInfo', 'GenerateSchema'}
421
+
422
+ _getattr_migration = getattr_migration(__name__)
423
+
424
+
425
+ def __getattr__(attr_name: str) -> object:
426
+ if attr_name in _deprecated_dynamic_imports:
427
+ from pydantic.warnings import PydanticDeprecatedSince20
428
+
429
+ warn(
430
+ f'Importing {attr_name} from `pydantic` is deprecated. This feature is either no longer supported, or is not public.',
431
+ PydanticDeprecatedSince20,
432
+ stacklevel=2,
433
+ )
434
+
435
+ dynamic_attr = _dynamic_imports.get(attr_name)
436
+ if dynamic_attr is None:
437
+ return _getattr_migration(attr_name)
438
+
439
+ package, module_name = dynamic_attr
440
+
441
+ if module_name == '__module__':
442
+ result = import_module(f'.{attr_name}', package=package)
443
+ globals()[attr_name] = result
444
+ return result
445
+ else:
446
+ module = import_module(module_name, package=package)
447
+ result = getattr(module, attr_name)
448
+ g = globals()
449
+ for k, (_, v_module_name) in _dynamic_imports.items():
450
+ if v_module_name == module_name and k not in _deprecated_dynamic_imports:
451
+ g[k] = getattr(module, k)
452
+ return result
453
+
454
+
455
+ def __dir__() -> list[str]:
456
+ return list(__all__)
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/__init__.py ADDED
File without changes
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_config.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations as _annotations
2
+
3
+ import warnings
4
+ from contextlib import contextmanager
5
+ from re import Pattern
6
+ from typing import (
7
+ TYPE_CHECKING,
8
+ Any,
9
+ Callable,
10
+ Literal,
11
+ cast,
12
+ )
13
+
14
+ from pydantic_core import core_schema
15
+ from typing_extensions import Self
16
+
17
+ from ..aliases import AliasGenerator
18
+ from ..config import ConfigDict, ExtraValues, JsonDict, JsonEncoder, JsonSchemaExtraCallable
19
+ from ..errors import PydanticUserError
20
+ from ..warnings import PydanticDeprecatedSince20, PydanticDeprecatedSince210
21
+
22
+ if TYPE_CHECKING:
23
+ from .._internal._schema_generation_shared import GenerateSchema
24
+ from ..fields import ComputedFieldInfo, FieldInfo
25
+
26
+ DEPRECATION_MESSAGE = 'Support for class-based `config` is deprecated, use ConfigDict instead.'
27
+
28
+
29
+ class ConfigWrapper:
30
+ """Internal wrapper for Config which exposes ConfigDict items as attributes."""
31
+
32
+ __slots__ = ('config_dict',)
33
+
34
+ config_dict: ConfigDict
35
+
36
+ # all annotations are copied directly from ConfigDict, and should be kept up to date, a test will fail if they
37
+ # stop matching
38
+ title: str | None
39
+ str_to_lower: bool
40
+ str_to_upper: bool
41
+ str_strip_whitespace: bool
42
+ str_min_length: int
43
+ str_max_length: int | None
44
+ extra: ExtraValues | None
45
+ frozen: bool
46
+ populate_by_name: bool
47
+ use_enum_values: bool
48
+ validate_assignment: bool
49
+ arbitrary_types_allowed: bool
50
+ from_attributes: bool
51
+ # whether to use the actual key provided in the data (e.g. alias or first alias for "field required" errors) instead of field_names
52
+ # to construct error `loc`s, default `True`
53
+ loc_by_alias: bool
54
+ alias_generator: Callable[[str], str] | AliasGenerator | None
55
+ model_title_generator: Callable[[type], str] | None
56
+ field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None
57
+ ignored_types: tuple[type, ...]
58
+ allow_inf_nan: bool
59
+ json_schema_extra: JsonDict | JsonSchemaExtraCallable | None
60
+ json_encoders: dict[type[object], JsonEncoder] | None
61
+
62
+ # new in V2
63
+ strict: bool
64
+ # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never'
65
+ revalidate_instances: Literal['always', 'never', 'subclass-instances']
66
+ ser_json_timedelta: Literal['iso8601', 'float']
67
+ ser_json_temporal: Literal['iso8601', 'seconds', 'milliseconds']
68
+ val_temporal_unit: Literal['seconds', 'milliseconds', 'infer']
69
+ ser_json_bytes: Literal['utf8', 'base64', 'hex']
70
+ val_json_bytes: Literal['utf8', 'base64', 'hex']
71
+ ser_json_inf_nan: Literal['null', 'constants', 'strings']
72
+ # whether to validate default values during validation, default False
73
+ validate_default: bool
74
+ validate_return: bool
75
+ protected_namespaces: tuple[str | Pattern[str], ...]
76
+ hide_input_in_errors: bool
77
+ defer_build: bool
78
+ plugin_settings: dict[str, object] | None
79
+ schema_generator: type[GenerateSchema] | None
80
+ json_schema_serialization_defaults_required: bool
81
+ json_schema_mode_override: Literal['validation', 'serialization', None]
82
+ coerce_numbers_to_str: bool
83
+ regex_engine: Literal['rust-regex', 'python-re']
84
+ validation_error_cause: bool
85
+ use_attribute_docstrings: bool
86
+ cache_strings: bool | Literal['all', 'keys', 'none']
87
+ validate_by_alias: bool
88
+ validate_by_name: bool
89
+ serialize_by_alias: bool
90
+ url_preserve_empty_path: bool
91
+ polymorphic_serialization: bool
92
+
93
+ def __init__(self, config: ConfigDict | dict[str, Any] | type[Any] | None, *, check: bool = True):
94
+ if check:
95
+ self.config_dict = prepare_config(config)
96
+ else:
97
+ self.config_dict = cast(ConfigDict, config)
98
+
99
+ @classmethod
100
+ def for_model(
101
+ cls,
102
+ bases: tuple[type[Any], ...],
103
+ namespace: dict[str, Any],
104
+ raw_annotations: dict[str, Any],
105
+ kwargs: dict[str, Any],
106
+ ) -> Self:
107
+ """Build a new `ConfigWrapper` instance for a `BaseModel`.
108
+
109
+ The config wrapper built based on (in descending order of priority):
110
+ - options from `kwargs`
111
+ - options from the `namespace`
112
+ - options from the base classes (`bases`)
113
+
114
+ Args:
115
+ bases: A tuple of base classes.
116
+ namespace: The namespace of the class being created.
117
+ raw_annotations: The (non-evaluated) annotations of the model.
118
+ kwargs: The kwargs passed to the class being created.
119
+
120
+ Returns:
121
+ A `ConfigWrapper` instance for `BaseModel`.
122
+ """
123
+ config_new = ConfigDict()
124
+ for base in bases:
125
+ config = getattr(base, 'model_config', None)
126
+ if config:
127
+ config_new.update(config.copy())
128
+
129
+ config_class_from_namespace = namespace.get('Config')
130
+ config_dict_from_namespace = namespace.get('model_config')
131
+
132
+ if raw_annotations.get('model_config') and config_dict_from_namespace is None:
133
+ raise PydanticUserError(
134
+ '`model_config` cannot be used as a model field name. Use `model_config` for model configuration.',
135
+ code='model-config-invalid-field-name',
136
+ )
137
+
138
+ if config_class_from_namespace and config_dict_from_namespace:
139
+ raise PydanticUserError('"Config" and "model_config" cannot be used together', code='config-both')
140
+
141
+ config_from_namespace = config_dict_from_namespace or prepare_config(config_class_from_namespace)
142
+
143
+ config_new.update(config_from_namespace)
144
+
145
+ for k in list(kwargs.keys()):
146
+ if k in config_keys:
147
+ config_new[k] = kwargs.pop(k)
148
+
149
+ return cls(config_new)
150
+
151
+ # we don't show `__getattr__` to type checkers so missing attributes cause errors
152
+ if not TYPE_CHECKING: # pragma: no branch
153
+
154
+ def __getattr__(self, name: str) -> Any:
155
+ try:
156
+ return self.config_dict[name]
157
+ except KeyError:
158
+ try:
159
+ return config_defaults[name]
160
+ except KeyError:
161
+ raise AttributeError(f'Config has no attribute {name!r}') from None
162
+
163
+ def core_config(self, title: str | None) -> core_schema.CoreConfig:
164
+ """Create a pydantic-core config.
165
+
166
+ We don't use getattr here since we don't want to populate with defaults.
167
+
168
+ Args:
169
+ title: The title to use if not set in config.
170
+
171
+ Returns:
172
+ A `CoreConfig` object created from config.
173
+ """
174
+ config = self.config_dict
175
+
176
+ if config.get('schema_generator') is not None:
177
+ warnings.warn(
178
+ 'The `schema_generator` setting has been deprecated since v2.10. This setting no longer has any effect.',
179
+ PydanticDeprecatedSince210,
180
+ stacklevel=2,
181
+ )
182
+
183
+ if (populate_by_name := config.get('populate_by_name')) is not None:
184
+ # We include this patch for backwards compatibility purposes, but this config setting will be deprecated in v3.0, and likely removed in v4.0.
185
+ # Thus, the above warning and this patch can be removed then as well.
186
+ if config.get('validate_by_name') is None:
187
+ config['validate_by_alias'] = True
188
+ config['validate_by_name'] = populate_by_name
189
+
190
+ # We dynamically patch validate_by_name to be True if validate_by_alias is set to False
191
+ # and validate_by_name is not explicitly set.
192
+ if config.get('validate_by_alias') is False and config.get('validate_by_name') is None:
193
+ config['validate_by_name'] = True
194
+
195
+ if (not config.get('validate_by_alias', True)) and (not config.get('validate_by_name', False)):
196
+ raise PydanticUserError(
197
+ 'At least one of `validate_by_alias` or `validate_by_name` must be set to True.',
198
+ code='validate-by-alias-and-name-false',
199
+ )
200
+
201
+ return core_schema.CoreConfig(
202
+ **{ # pyright: ignore[reportArgumentType]
203
+ k: v
204
+ for k, v in (
205
+ ('title', config.get('title') or title or None),
206
+ ('extra_fields_behavior', config.get('extra')),
207
+ ('allow_inf_nan', config.get('allow_inf_nan')),
208
+ ('str_strip_whitespace', config.get('str_strip_whitespace')),
209
+ ('str_to_lower', config.get('str_to_lower')),
210
+ ('str_to_upper', config.get('str_to_upper')),
211
+ ('strict', config.get('strict')),
212
+ ('ser_json_timedelta', config.get('ser_json_timedelta')),
213
+ ('ser_json_temporal', config.get('ser_json_temporal')),
214
+ ('val_temporal_unit', config.get('val_temporal_unit')),
215
+ ('ser_json_bytes', config.get('ser_json_bytes')),
216
+ ('val_json_bytes', config.get('val_json_bytes')),
217
+ ('ser_json_inf_nan', config.get('ser_json_inf_nan')),
218
+ ('from_attributes', config.get('from_attributes')),
219
+ ('loc_by_alias', config.get('loc_by_alias')),
220
+ ('revalidate_instances', config.get('revalidate_instances')),
221
+ ('validate_default', config.get('validate_default')),
222
+ ('str_max_length', config.get('str_max_length')),
223
+ ('str_min_length', config.get('str_min_length')),
224
+ ('hide_input_in_errors', config.get('hide_input_in_errors')),
225
+ ('coerce_numbers_to_str', config.get('coerce_numbers_to_str')),
226
+ ('regex_engine', config.get('regex_engine')),
227
+ ('validation_error_cause', config.get('validation_error_cause')),
228
+ ('cache_strings', config.get('cache_strings')),
229
+ ('validate_by_alias', config.get('validate_by_alias')),
230
+ ('validate_by_name', config.get('validate_by_name')),
231
+ ('serialize_by_alias', config.get('serialize_by_alias')),
232
+ ('url_preserve_empty_path', config.get('url_preserve_empty_path')),
233
+ ('polymorphic_serialization', config.get('polymorphic_serialization')),
234
+ )
235
+ if v is not None
236
+ }
237
+ )
238
+
239
+ def __repr__(self):
240
+ c = ', '.join(f'{k}={v!r}' for k, v in self.config_dict.items())
241
+ return f'ConfigWrapper({c})'
242
+
243
+
244
+ class ConfigWrapperStack:
245
+ """A stack of `ConfigWrapper` instances."""
246
+
247
+ def __init__(self, config_wrapper: ConfigWrapper):
248
+ self._config_wrapper_stack: list[ConfigWrapper] = [config_wrapper]
249
+
250
+ @property
251
+ def tail(self) -> ConfigWrapper:
252
+ return self._config_wrapper_stack[-1]
253
+
254
+ @contextmanager
255
+ def push(self, config_wrapper: ConfigWrapper | ConfigDict | None):
256
+ if config_wrapper is None:
257
+ yield
258
+ return
259
+
260
+ if not isinstance(config_wrapper, ConfigWrapper):
261
+ config_wrapper = ConfigWrapper(config_wrapper, check=False)
262
+
263
+ self._config_wrapper_stack.append(config_wrapper)
264
+ try:
265
+ yield
266
+ finally:
267
+ self._config_wrapper_stack.pop()
268
+
269
+
270
+ config_defaults = ConfigDict(
271
+ title=None,
272
+ str_to_lower=False,
273
+ str_to_upper=False,
274
+ str_strip_whitespace=False,
275
+ str_min_length=0,
276
+ str_max_length=None,
277
+ # let the model / dataclass decide how to handle it
278
+ extra=None,
279
+ frozen=False,
280
+ populate_by_name=False,
281
+ use_enum_values=False,
282
+ validate_assignment=False,
283
+ arbitrary_types_allowed=False,
284
+ from_attributes=False,
285
+ loc_by_alias=True,
286
+ alias_generator=None,
287
+ model_title_generator=None,
288
+ field_title_generator=None,
289
+ ignored_types=(),
290
+ allow_inf_nan=True,
291
+ json_schema_extra=None,
292
+ strict=False,
293
+ revalidate_instances='never',
294
+ ser_json_timedelta='iso8601',
295
+ ser_json_temporal='iso8601',
296
+ val_temporal_unit='infer',
297
+ ser_json_bytes='utf8',
298
+ val_json_bytes='utf8',
299
+ ser_json_inf_nan='null',
300
+ validate_default=False,
301
+ validate_return=False,
302
+ protected_namespaces=('model_validate', 'model_dump'),
303
+ hide_input_in_errors=False,
304
+ json_encoders=None,
305
+ defer_build=False,
306
+ schema_generator=None,
307
+ plugin_settings=None,
308
+ json_schema_serialization_defaults_required=False,
309
+ json_schema_mode_override=None,
310
+ coerce_numbers_to_str=False,
311
+ regex_engine='rust-regex',
312
+ validation_error_cause=False,
313
+ use_attribute_docstrings=False,
314
+ cache_strings=True,
315
+ validate_by_alias=True,
316
+ validate_by_name=False,
317
+ serialize_by_alias=False,
318
+ url_preserve_empty_path=False,
319
+ polymorphic_serialization=False,
320
+ )
321
+
322
+
323
+ def prepare_config(config: ConfigDict | dict[str, Any] | type[Any] | None) -> ConfigDict:
324
+ """Create a `ConfigDict` instance from an existing dict, a class (e.g. old class-based config) or None.
325
+
326
+ Args:
327
+ config: The input config.
328
+
329
+ Returns:
330
+ A ConfigDict object created from config.
331
+ """
332
+ if config is None:
333
+ return ConfigDict()
334
+
335
+ if not isinstance(config, dict):
336
+ warnings.warn(DEPRECATION_MESSAGE, PydanticDeprecatedSince20, stacklevel=4)
337
+ config = {k: getattr(config, k) for k in dir(config) if not k.startswith('__')}
338
+
339
+ config_dict = cast(ConfigDict, config)
340
+ check_deprecated(config_dict)
341
+ return config_dict
342
+
343
+
344
+ config_keys = set(ConfigDict.__annotations__.keys())
345
+
346
+
347
+ V2_REMOVED_KEYS = {
348
+ 'allow_mutation',
349
+ 'error_msg_templates',
350
+ 'fields',
351
+ 'getter_dict',
352
+ 'smart_union',
353
+ 'underscore_attrs_are_private',
354
+ 'json_loads',
355
+ 'json_dumps',
356
+ 'copy_on_model_validation',
357
+ 'post_init_call',
358
+ }
359
+ V2_RENAMED_KEYS = {
360
+ 'allow_population_by_field_name': 'validate_by_name',
361
+ 'anystr_lower': 'str_to_lower',
362
+ 'anystr_strip_whitespace': 'str_strip_whitespace',
363
+ 'anystr_upper': 'str_to_upper',
364
+ 'keep_untouched': 'ignored_types',
365
+ 'max_anystr_length': 'str_max_length',
366
+ 'min_anystr_length': 'str_min_length',
367
+ 'orm_mode': 'from_attributes',
368
+ 'schema_extra': 'json_schema_extra',
369
+ 'validate_all': 'validate_default',
370
+ }
371
+
372
+
373
+ def check_deprecated(config_dict: ConfigDict) -> None:
374
+ """Check for deprecated config keys and warn the user.
375
+
376
+ Args:
377
+ config_dict: The input config.
378
+ """
379
+ deprecated_removed_keys = V2_REMOVED_KEYS & config_dict.keys()
380
+ deprecated_renamed_keys = V2_RENAMED_KEYS.keys() & config_dict.keys()
381
+ if deprecated_removed_keys or deprecated_renamed_keys:
382
+ renamings = {k: V2_RENAMED_KEYS[k] for k in sorted(deprecated_renamed_keys)}
383
+ renamed_bullets = [f'* {k!r} has been renamed to {v!r}' for k, v in renamings.items()]
384
+ removed_bullets = [f'* {k!r} has been removed' for k in sorted(deprecated_removed_keys)]
385
+ message = '\n'.join(['Valid config keys have changed in V2:'] + renamed_bullets + removed_bullets)
386
+ warnings.warn(message, UserWarning)
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_core_metadata.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations as _annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, TypedDict, cast
4
+ from warnings import warn
5
+
6
+ if TYPE_CHECKING:
7
+ from ..config import JsonDict, JsonSchemaExtraCallable
8
+ from ._schema_generation_shared import (
9
+ GetJsonSchemaFunction,
10
+ )
11
+
12
+
13
+ class CoreMetadata(TypedDict, total=False):
14
+ """A `TypedDict` for holding the metadata dict of the schema.
15
+
16
+ Attributes:
17
+ pydantic_js_functions: List of JSON schema functions that resolve refs during application.
18
+ pydantic_js_annotation_functions: List of JSON schema functions that don't resolve refs during application.
19
+ pydantic_js_prefer_positional_arguments: Whether JSON schema generator will
20
+ prefer positional over keyword arguments for an 'arguments' schema.
21
+ custom validation function. Only applies to before, plain, and wrap validators.
22
+ pydantic_js_updates: key / value pair updates to apply to the JSON schema for a type.
23
+ pydantic_js_extra: WIP, either key/value pair updates to apply to the JSON schema, or a custom callable.
24
+ pydantic_internal_union_tag_key: Used internally by the `Tag` metadata to specify the tag used for a discriminated union.
25
+ pydantic_internal_union_discriminator: Used internally to specify the discriminator value for a discriminated union
26
+ when the discriminator was applied to a `'definition-ref'` schema, and that reference was missing at the time
27
+ of the annotation application.
28
+
29
+ TODO: Perhaps we should move this structure to pydantic-core. At the moment, though,
30
+ it's easier to iterate on if we leave it in pydantic until we feel there is a semi-stable API.
31
+
32
+ TODO: It's unfortunate how functionally oriented JSON schema generation is, especially that which occurs during
33
+ the core schema generation process. It's inevitable that we need to store some json schema related information
34
+ on core schemas, given that we generate JSON schemas directly from core schemas. That being said, debugging related
35
+ issues is quite difficult when JSON schema information is disguised via dynamically defined functions.
36
+ """
37
+
38
+ pydantic_js_functions: list[GetJsonSchemaFunction]
39
+ pydantic_js_annotation_functions: list[GetJsonSchemaFunction]
40
+ pydantic_js_prefer_positional_arguments: bool
41
+ pydantic_js_updates: JsonDict
42
+ pydantic_js_extra: JsonDict | JsonSchemaExtraCallable
43
+ pydantic_internal_union_tag_key: str
44
+ pydantic_internal_union_discriminator: str
45
+
46
+
47
+ def update_core_metadata(
48
+ core_metadata: Any,
49
+ /,
50
+ *,
51
+ pydantic_js_functions: list[GetJsonSchemaFunction] | None = None,
52
+ pydantic_js_annotation_functions: list[GetJsonSchemaFunction] | None = None,
53
+ pydantic_js_updates: JsonDict | None = None,
54
+ pydantic_js_extra: JsonDict | JsonSchemaExtraCallable | None = None,
55
+ ) -> None:
56
+ from ..json_schema import PydanticJsonSchemaWarning
57
+
58
+ """Update CoreMetadata instance in place. When we make modifications in this function, they
59
+ take effect on the `core_metadata` reference passed in as the first (and only) positional argument.
60
+
61
+ First, cast to `CoreMetadata`, then finish with a cast to `dict[str, Any]` for core schema compatibility.
62
+ We do this here, instead of before / after each call to this function so that this typing hack
63
+ can be easily removed if/when we move `CoreMetadata` to `pydantic-core`.
64
+
65
+ For parameter descriptions, see `CoreMetadata` above.
66
+ """
67
+ core_metadata = cast(CoreMetadata, core_metadata)
68
+
69
+ if pydantic_js_functions:
70
+ core_metadata.setdefault('pydantic_js_functions', []).extend(pydantic_js_functions)
71
+
72
+ if pydantic_js_annotation_functions:
73
+ core_metadata.setdefault('pydantic_js_annotation_functions', []).extend(pydantic_js_annotation_functions)
74
+
75
+ if pydantic_js_updates:
76
+ if (existing_updates := core_metadata.get('pydantic_js_updates')) is not None:
77
+ core_metadata['pydantic_js_updates'] = {**existing_updates, **pydantic_js_updates}
78
+ else:
79
+ core_metadata['pydantic_js_updates'] = pydantic_js_updates
80
+
81
+ if pydantic_js_extra is not None:
82
+ existing_pydantic_js_extra = core_metadata.get('pydantic_js_extra')
83
+ if existing_pydantic_js_extra is None:
84
+ core_metadata['pydantic_js_extra'] = pydantic_js_extra
85
+ if isinstance(existing_pydantic_js_extra, dict):
86
+ if isinstance(pydantic_js_extra, dict):
87
+ core_metadata['pydantic_js_extra'] = {**existing_pydantic_js_extra, **pydantic_js_extra}
88
+ if callable(pydantic_js_extra):
89
+ warn(
90
+ 'Composing `dict` and `callable` type `json_schema_extra` is not supported.'
91
+ 'The `callable` type is being ignored.'
92
+ "If you'd like support for this behavior, please open an issue on pydantic.",
93
+ PydanticJsonSchemaWarning,
94
+ )
95
+ if callable(existing_pydantic_js_extra):
96
+ # if ever there's a case of a callable, we'll just keep the last json schema extra spec
97
+ core_metadata['pydantic_js_extra'] = pydantic_js_extra
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_core_utils.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ from collections.abc import Mapping, Sequence
5
+ from typing import TYPE_CHECKING, Any, Union
6
+
7
+ from pydantic_core import CoreSchema, core_schema
8
+ from typing_extensions import TypeGuard, get_args, get_origin
9
+ from typing_inspection import typing_objects
10
+
11
+ from . import _repr
12
+ from ._typing_extra import is_generic_alias
13
+
14
+ if TYPE_CHECKING:
15
+ from rich.console import Console
16
+
17
+ AnyFunctionSchema = Union[
18
+ core_schema.AfterValidatorFunctionSchema,
19
+ core_schema.BeforeValidatorFunctionSchema,
20
+ core_schema.WrapValidatorFunctionSchema,
21
+ core_schema.PlainValidatorFunctionSchema,
22
+ ]
23
+
24
+
25
+ FunctionSchemaWithInnerSchema = Union[
26
+ core_schema.AfterValidatorFunctionSchema,
27
+ core_schema.BeforeValidatorFunctionSchema,
28
+ core_schema.WrapValidatorFunctionSchema,
29
+ ]
30
+
31
+ CoreSchemaField = Union[
32
+ core_schema.ModelField, core_schema.DataclassField, core_schema.TypedDictField, core_schema.ComputedField
33
+ ]
34
+ CoreSchemaOrField = Union[core_schema.CoreSchema, CoreSchemaField]
35
+
36
+ _CORE_SCHEMA_FIELD_TYPES = {'typed-dict-field', 'dataclass-field', 'model-field', 'computed-field'}
37
+ _FUNCTION_WITH_INNER_SCHEMA_TYPES = {'function-before', 'function-after', 'function-wrap'}
38
+ _LIST_LIKE_SCHEMA_WITH_ITEMS_TYPES = {'list', 'set', 'frozenset'}
39
+
40
+
41
+ def is_core_schema(
42
+ schema: CoreSchemaOrField,
43
+ ) -> TypeGuard[CoreSchema]:
44
+ return schema['type'] not in _CORE_SCHEMA_FIELD_TYPES
45
+
46
+
47
+ def is_core_schema_field(
48
+ schema: CoreSchemaOrField,
49
+ ) -> TypeGuard[CoreSchemaField]:
50
+ return schema['type'] in _CORE_SCHEMA_FIELD_TYPES
51
+
52
+
53
+ def is_function_with_inner_schema(
54
+ schema: CoreSchemaOrField,
55
+ ) -> TypeGuard[FunctionSchemaWithInnerSchema]:
56
+ return schema['type'] in _FUNCTION_WITH_INNER_SCHEMA_TYPES
57
+
58
+
59
+ def is_list_like_schema_with_items_schema(
60
+ schema: CoreSchema,
61
+ ) -> TypeGuard[core_schema.ListSchema | core_schema.SetSchema | core_schema.FrozenSetSchema]:
62
+ return schema['type'] in _LIST_LIKE_SCHEMA_WITH_ITEMS_TYPES
63
+
64
+
65
+ def get_type_ref(type_: Any, args_override: tuple[type[Any], ...] | None = None) -> str:
66
+ """Produces the ref to be used for this type by pydantic_core's core schemas.
67
+
68
+ This `args_override` argument was added for the purpose of creating valid recursive references
69
+ when creating generic models without needing to create a concrete class.
70
+ """
71
+ origin = get_origin(type_) or type_
72
+
73
+ args = get_args(type_) if is_generic_alias(type_) else (args_override or ())
74
+ generic_metadata = getattr(type_, '__pydantic_generic_metadata__', None)
75
+ if generic_metadata:
76
+ origin = generic_metadata['origin'] or origin
77
+ args = generic_metadata['args'] or args
78
+
79
+ module_name = getattr(origin, '__module__', '<No __module__>')
80
+ if typing_objects.is_typealiastype(origin):
81
+ type_ref = f'{module_name}.{origin.__name__}:{id(origin)}'
82
+ else:
83
+ try:
84
+ qualname = getattr(origin, '__qualname__', f'<No __qualname__: {origin}>')
85
+ except Exception:
86
+ qualname = getattr(origin, '__qualname__', '<No __qualname__>')
87
+ type_ref = f'{module_name}.{qualname}:{id(origin)}'
88
+
89
+ arg_refs: list[str] = []
90
+ for arg in args:
91
+ if isinstance(arg, str):
92
+ # Handle string literals as a special case; we may be able to remove this special handling if we
93
+ # wrap them in a ForwardRef at some point.
94
+ arg_ref = f'{arg}:str-{id(arg)}'
95
+ else:
96
+ arg_ref = f'{_repr.display_as_type(arg)}:{id(arg)}'
97
+ arg_refs.append(arg_ref)
98
+ if arg_refs:
99
+ type_ref = f'{type_ref}[{",".join(arg_refs)}]'
100
+ return type_ref
101
+
102
+
103
+ def get_ref(s: core_schema.CoreSchema) -> None | str:
104
+ """Get the ref from the schema if it has one.
105
+ This exists just for type checking to work correctly.
106
+ """
107
+ return s.get('ref', None)
108
+
109
+
110
+ def _clean_schema_for_pretty_print(obj: Any, strip_metadata: bool = True) -> Any: # pragma: no cover
111
+ """A utility function to remove irrelevant information from a core schema."""
112
+ if isinstance(obj, Mapping):
113
+ new_dct = {}
114
+ for k, v in obj.items():
115
+ if k == 'metadata' and strip_metadata:
116
+ new_metadata = {}
117
+
118
+ for meta_k, meta_v in v.items():
119
+ if meta_k in ('pydantic_js_functions', 'pydantic_js_annotation_functions'):
120
+ new_metadata['js_metadata'] = '<stripped>'
121
+ else:
122
+ new_metadata[meta_k] = _clean_schema_for_pretty_print(meta_v, strip_metadata=strip_metadata)
123
+
124
+ if list(new_metadata.keys()) == ['js_metadata']:
125
+ new_metadata = {'<stripped>'}
126
+
127
+ new_dct[k] = new_metadata
128
+ # Remove some defaults:
129
+ elif k in ('custom_init', 'root_model') and not v:
130
+ continue
131
+ else:
132
+ new_dct[k] = _clean_schema_for_pretty_print(v, strip_metadata=strip_metadata)
133
+
134
+ return new_dct
135
+ elif isinstance(obj, Sequence) and not isinstance(obj, str):
136
+ return [_clean_schema_for_pretty_print(v, strip_metadata=strip_metadata) for v in obj]
137
+ else:
138
+ return obj
139
+
140
+
141
+ def pretty_print_core_schema(
142
+ val: Any,
143
+ *,
144
+ console: Console | None = None,
145
+ max_depth: int | None = None,
146
+ strip_metadata: bool = True,
147
+ ) -> None: # pragma: no cover
148
+ """Pretty-print a core schema using the `rich` library.
149
+
150
+ Args:
151
+ val: The core schema to print, or a Pydantic model/dataclass/type adapter
152
+ (in which case the cached core schema is fetched and printed).
153
+ console: A rich console to use when printing. Defaults to the global rich console instance.
154
+ max_depth: The number of nesting levels which may be printed.
155
+ strip_metadata: Whether to strip metadata in the output. If `True` any known core metadata
156
+ attributes will be stripped (but custom attributes are kept). Defaults to `True`.
157
+ """
158
+ # lazy import:
159
+ from rich.pretty import pprint
160
+
161
+ # circ. imports:
162
+ from pydantic import BaseModel, TypeAdapter
163
+ from pydantic.dataclasses import is_pydantic_dataclass
164
+
165
+ if (inspect.isclass(val) and issubclass(val, BaseModel)) or is_pydantic_dataclass(val):
166
+ val = val.__pydantic_core_schema__
167
+ if isinstance(val, TypeAdapter):
168
+ val = val.core_schema
169
+ cleaned_schema = _clean_schema_for_pretty_print(val, strip_metadata=strip_metadata)
170
+
171
+ pprint(cleaned_schema, console=console, max_depth=max_depth)
172
+
173
+
174
+ pps = pretty_print_core_schema
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_dataclasses.py ADDED
@@ -0,0 +1,315 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Private logic for creating pydantic dataclasses."""
2
+
3
+ from __future__ import annotations as _annotations
4
+
5
+ import copy
6
+ import dataclasses
7
+ import sys
8
+ import warnings
9
+ from collections.abc import Generator
10
+ from contextlib import contextmanager
11
+ from functools import partial
12
+ from typing import TYPE_CHECKING, Any, ClassVar, Protocol, cast
13
+
14
+ from pydantic_core import (
15
+ ArgsKwargs,
16
+ SchemaSerializer,
17
+ SchemaValidator,
18
+ core_schema,
19
+ )
20
+ from typing_extensions import TypeAlias, TypeIs
21
+
22
+ from ..errors import PydanticUndefinedAnnotation
23
+ from ..fields import FieldInfo
24
+ from ..plugin._schema_validator import PluggableSchemaValidator, create_schema_validator
25
+ from ..warnings import PydanticDeprecatedSince20
26
+ from . import _config, _decorators
27
+ from ._fields import collect_dataclass_fields
28
+ from ._generate_schema import GenerateSchema, InvalidSchemaError
29
+ from ._generics import get_standard_typevars_map
30
+ from ._mock_val_ser import set_dataclass_mocks
31
+ from ._namespace_utils import NsResolver
32
+ from ._signature import generate_pydantic_signature
33
+ from ._utils import LazyClassAttribute
34
+
35
+ if TYPE_CHECKING:
36
+ from _typeshed import DataclassInstance as StandardDataclass
37
+
38
+ from ..config import ConfigDict
39
+
40
+ class PydanticDataclass(StandardDataclass, Protocol):
41
+ """A protocol containing attributes only available once a class has been decorated as a Pydantic dataclass.
42
+
43
+ Attributes:
44
+ __pydantic_config__: Pydantic-specific configuration settings for the dataclass.
45
+ __pydantic_complete__: Whether dataclass building is completed, or if there are still undefined fields.
46
+ __pydantic_core_schema__: The pydantic-core schema used to build the SchemaValidator and SchemaSerializer.
47
+ __pydantic_decorators__: Metadata containing the decorators defined on the dataclass.
48
+ __pydantic_fields__: Metadata about the fields defined on the dataclass.
49
+ __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the dataclass.
50
+ __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the dataclass.
51
+ """
52
+
53
+ __pydantic_config__: ClassVar[ConfigDict]
54
+ __pydantic_complete__: ClassVar[bool]
55
+ __pydantic_core_schema__: ClassVar[core_schema.CoreSchema]
56
+ __pydantic_decorators__: ClassVar[_decorators.DecoratorInfos]
57
+ __pydantic_fields__: ClassVar[dict[str, FieldInfo]]
58
+ __pydantic_serializer__: ClassVar[SchemaSerializer]
59
+ __pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator]
60
+
61
+ @classmethod
62
+ def __pydantic_fields_complete__(cls) -> bool: ...
63
+
64
+
65
+ def set_dataclass_fields(
66
+ cls: type[StandardDataclass],
67
+ config_wrapper: _config.ConfigWrapper,
68
+ ns_resolver: NsResolver | None = None,
69
+ ) -> None:
70
+ """Collect and set `cls.__pydantic_fields__`.
71
+
72
+ Args:
73
+ cls: The class.
74
+ config_wrapper: The config wrapper instance.
75
+ ns_resolver: Namespace resolver to use when getting dataclass annotations.
76
+ """
77
+ typevars_map = get_standard_typevars_map(cls)
78
+ fields = collect_dataclass_fields(
79
+ cls, ns_resolver=ns_resolver, typevars_map=typevars_map, config_wrapper=config_wrapper
80
+ )
81
+
82
+ cls.__pydantic_fields__ = fields # type: ignore
83
+
84
+
85
+ def complete_dataclass(
86
+ cls: type[Any],
87
+ config_wrapper: _config.ConfigWrapper,
88
+ *,
89
+ raise_errors: bool = True,
90
+ ns_resolver: NsResolver | None = None,
91
+ _force_build: bool = False,
92
+ ) -> bool:
93
+ """Finish building a pydantic dataclass.
94
+
95
+ This logic is called on a class which has already been wrapped in `dataclasses.dataclass()`.
96
+
97
+ This is somewhat analogous to `pydantic._internal._model_construction.complete_model_class`.
98
+
99
+ Args:
100
+ cls: The class.
101
+ config_wrapper: The config wrapper instance.
102
+ raise_errors: Whether to raise errors, defaults to `True`.
103
+ ns_resolver: The namespace resolver instance to use when collecting dataclass fields
104
+ and during schema building.
105
+ _force_build: Whether to force building the dataclass, no matter if
106
+ [`defer_build`][pydantic.config.ConfigDict.defer_build] is set.
107
+
108
+ Returns:
109
+ `True` if building a pydantic dataclass is successfully completed, `False` otherwise.
110
+
111
+ Raises:
112
+ PydanticUndefinedAnnotation: If `raise_error` is `True` and there is an undefined annotations.
113
+ """
114
+ original_init = cls.__init__
115
+
116
+ # dataclass.__init__ must be defined here so its `__qualname__` can be changed since functions can't be copied,
117
+ # and so that the mock validator is used if building was deferred:
118
+ def __init__(__dataclass_self__: PydanticDataclass, *args: Any, **kwargs: Any) -> None:
119
+ __tracebackhide__ = True
120
+ s = __dataclass_self__
121
+ s.__pydantic_validator__.validate_python(ArgsKwargs(args, kwargs), self_instance=s)
122
+
123
+ __init__.__qualname__ = f'{cls.__qualname__}.__init__'
124
+
125
+ cls.__init__ = __init__ # type: ignore
126
+ cls.__pydantic_config__ = config_wrapper.config_dict # type: ignore
127
+
128
+ set_dataclass_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver)
129
+
130
+ if not _force_build and config_wrapper.defer_build:
131
+ set_dataclass_mocks(cls)
132
+ return False
133
+
134
+ if hasattr(cls, '__post_init_post_parse__'):
135
+ warnings.warn(
136
+ 'Support for `__post_init_post_parse__` has been dropped, the method will not be called',
137
+ PydanticDeprecatedSince20,
138
+ )
139
+
140
+ typevars_map = get_standard_typevars_map(cls)
141
+ gen_schema = GenerateSchema(
142
+ config_wrapper,
143
+ ns_resolver=ns_resolver,
144
+ typevars_map=typevars_map,
145
+ )
146
+
147
+ # set __signature__ attr only for the class, but not for its instances
148
+ # (because instances can define `__call__`, and `inspect.signature` shouldn't
149
+ # use the `__signature__` attribute and instead generate from `__call__`).
150
+ cls.__signature__ = LazyClassAttribute(
151
+ '__signature__',
152
+ partial(
153
+ generate_pydantic_signature,
154
+ # It's important that we reference the `original_init` here,
155
+ # as it is the one synthesized by the stdlib `dataclass` module:
156
+ init=original_init,
157
+ fields=cls.__pydantic_fields__, # type: ignore
158
+ validate_by_name=config_wrapper.validate_by_name,
159
+ extra=config_wrapper.extra,
160
+ is_dataclass=True,
161
+ ),
162
+ )
163
+
164
+ try:
165
+ schema = gen_schema.generate_schema(cls)
166
+ except PydanticUndefinedAnnotation as e:
167
+ if raise_errors:
168
+ raise
169
+ set_dataclass_mocks(cls, f'`{e.name}`')
170
+ return False
171
+
172
+ core_config = config_wrapper.core_config(title=cls.__name__)
173
+
174
+ try:
175
+ schema = gen_schema.clean_schema(schema)
176
+ except InvalidSchemaError:
177
+ set_dataclass_mocks(cls)
178
+ return False
179
+
180
+ # We are about to set all the remaining required properties expected for this cast;
181
+ # __pydantic_decorators__ and __pydantic_fields__ should already be set
182
+ cls = cast('type[PydanticDataclass]', cls)
183
+
184
+ cls.__pydantic_core_schema__ = schema
185
+ cls.__pydantic_validator__ = create_schema_validator(
186
+ schema, cls, cls.__module__, cls.__qualname__, 'dataclass', core_config, config_wrapper.plugin_settings
187
+ )
188
+ cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config)
189
+ cls.__pydantic_complete__ = True
190
+ return True
191
+
192
+
193
+ def is_stdlib_dataclass(cls: type[Any], /) -> TypeIs[type[StandardDataclass]]:
194
+ """Returns `True` if the class is a stdlib dataclass and *not* a Pydantic dataclass.
195
+
196
+ Unlike the stdlib `dataclasses.is_dataclass()` function, this does *not* include subclasses
197
+ of a dataclass that are themselves not dataclasses.
198
+
199
+ Args:
200
+ cls: The class.
201
+
202
+ Returns:
203
+ `True` if the class is a stdlib dataclass, `False` otherwise.
204
+ """
205
+ return '__dataclass_fields__' in cls.__dict__ and not hasattr(cls, '__pydantic_validator__')
206
+
207
+
208
+ def as_dataclass_field(pydantic_field: FieldInfo) -> dataclasses.Field[Any]:
209
+ field_args: dict[str, Any] = {'default': pydantic_field}
210
+
211
+ # Needed because if `doc` is set, the dataclass slots will be a dict (field name -> doc) instead of a tuple:
212
+ if sys.version_info >= (3, 14) and pydantic_field.description is not None:
213
+ field_args['doc'] = pydantic_field.description
214
+
215
+ # Needed as the stdlib dataclass module processes kw_only in a specific way during class construction:
216
+ if sys.version_info >= (3, 10) and pydantic_field.kw_only is not None:
217
+ field_args['kw_only'] = pydantic_field.kw_only
218
+
219
+ # Needed as the stdlib dataclass modules generates `__repr__()` during class construction:
220
+ if pydantic_field.repr is not True:
221
+ field_args['repr'] = pydantic_field.repr
222
+
223
+ return dataclasses.field(**field_args)
224
+
225
+
226
+ DcFields: TypeAlias = dict[str, dataclasses.Field[Any]]
227
+
228
+
229
+ @contextmanager
230
+ def patch_base_fields(cls: type[Any]) -> Generator[None]:
231
+ """Temporarily patch the stdlib dataclasses bases of `cls` if the Pydantic `Field()` function is used.
232
+
233
+ When creating a Pydantic dataclass, it is possible to inherit from stdlib dataclasses, where
234
+ the Pydantic `Field()` function is used. To create this Pydantic dataclass, we first apply
235
+ the stdlib `@dataclass` decorator on it. During the construction of the stdlib dataclass,
236
+ the `kw_only` and `repr` field arguments need to be understood by the stdlib *during* the
237
+ dataclass construction. To do so, we temporarily patch the fields dictionary of the affected
238
+ bases.
239
+
240
+ For instance, with the following example:
241
+
242
+ ```python {test="skip" lint="skip"}
243
+ import dataclasses as stdlib_dc
244
+
245
+ import pydantic
246
+ import pydantic.dataclasses as pydantic_dc
247
+
248
+ @stdlib_dc.dataclass
249
+ class A:
250
+ a: int = pydantic.Field(repr=False)
251
+
252
+ # Notice that the `repr` attribute of the dataclass field is `True`:
253
+ A.__dataclass_fields__['a']
254
+ #> dataclass.Field(default=FieldInfo(repr=False), repr=True, ...)
255
+
256
+ @pydantic_dc.dataclass
257
+ class B(A):
258
+ b: int = pydantic.Field(repr=False)
259
+ ```
260
+
261
+ When passing `B` to the stdlib `@dataclass` decorator, it will look for fields in the parent classes
262
+ and reuse them directly. When this context manager is active, `A` will be temporarily patched to be
263
+ equivalent to:
264
+
265
+ ```python {test="skip" lint="skip"}
266
+ @stdlib_dc.dataclass
267
+ class A:
268
+ a: int = stdlib_dc.field(default=Field(repr=False), repr=False)
269
+ ```
270
+
271
+ !!! note
272
+ This is only applied to the bases of `cls`, and not `cls` itself. The reason is that the Pydantic
273
+ dataclass decorator "owns" `cls` (in the previous example, `B`). As such, we instead modify the fields
274
+ directly (in the previous example, we simply do `setattr(B, 'b', as_dataclass_field(pydantic_field))`).
275
+
276
+ !!! note
277
+ This approach is far from ideal, and can probably be the source of unwanted side effects/race conditions.
278
+ The previous implemented approach was mutating the `__annotations__` dict of `cls`, which is no longer a
279
+ safe operation in Python 3.14+, and resulted in unexpected behavior with field ordering anyway.
280
+ """
281
+ # A list of two-tuples, the first element being a reference to the
282
+ # dataclass fields dictionary, the second element being a mapping between
283
+ # the field names that were modified, and their original `Field`:
284
+ original_fields_list: list[tuple[DcFields, DcFields]] = []
285
+
286
+ for base in cls.__mro__[1:]:
287
+ dc_fields: dict[str, dataclasses.Field[Any]] = base.__dict__.get('__dataclass_fields__', {})
288
+ dc_fields_with_pydantic_field_defaults = {
289
+ field_name: field
290
+ for field_name, field in dc_fields.items()
291
+ if isinstance(field.default, FieldInfo)
292
+ # Only do the patching if one of the affected attributes is set:
293
+ and (field.default.description is not None or field.default.kw_only or field.default.repr is not True)
294
+ }
295
+ if dc_fields_with_pydantic_field_defaults:
296
+ original_fields_list.append((dc_fields, dc_fields_with_pydantic_field_defaults))
297
+ for field_name, field in dc_fields_with_pydantic_field_defaults.items():
298
+ default = cast(FieldInfo, field.default)
299
+ # `dataclasses.Field` isn't documented as working with `copy.copy()`.
300
+ # It is a class with `__slots__`, so should work (and we hope for the best):
301
+ new_dc_field = copy.copy(field)
302
+ # For base fields, no need to set `doc` from `FieldInfo.description`, this is only relevant
303
+ # for the class under construction and handled in `as_dataclass_field()`.
304
+ if sys.version_info >= (3, 10) and default.kw_only:
305
+ new_dc_field.kw_only = True
306
+ if default.repr is not True:
307
+ new_dc_field.repr = default.repr
308
+ dc_fields[field_name] = new_dc_field
309
+
310
+ try:
311
+ yield
312
+ finally:
313
+ for fields, original_fields in original_fields_list:
314
+ for field_name, original_field in original_fields.items():
315
+ fields[field_name] = original_field
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_decorators.py ADDED
@@ -0,0 +1,873 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Logic related to validators applied to models etc. via the `@field_validator` and `@model_validator` decorators."""
2
+
3
+ from __future__ import annotations as _annotations
4
+
5
+ import types
6
+ from collections import deque
7
+ from collections.abc import Iterable
8
+ from copy import copy
9
+ from dataclasses import dataclass, field
10
+ from functools import cached_property, partial, partialmethod
11
+ from inspect import Parameter, Signature, isdatadescriptor, ismethoddescriptor
12
+ from itertools import islice
13
+ from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generic, Literal, TypeVar, Union
14
+
15
+ from pydantic_core import PydanticUndefined, PydanticUndefinedType, core_schema
16
+ from typing_extensions import Self, TypeAlias, is_typeddict
17
+
18
+ from ..errors import PydanticUserError
19
+ from ._core_utils import get_type_ref
20
+ from ._internal_dataclass import slots_true
21
+ from ._namespace_utils import GlobalsNamespace, MappingNamespace
22
+ from ._typing_extra import get_function_type_hints, signature_no_eval
23
+ from ._utils import can_be_positional
24
+
25
+ if TYPE_CHECKING:
26
+ from ..fields import ComputedFieldInfo
27
+ from ..functional_validators import FieldValidatorModes
28
+ from ._config import ConfigWrapper
29
+
30
+
31
+ @dataclass(**slots_true)
32
+ class ValidatorDecoratorInfo:
33
+ """A container for data from `@validator` so that we can access it
34
+ while building the pydantic-core schema.
35
+
36
+ Attributes:
37
+ decorator_repr: A class variable representing the decorator string, '@validator'.
38
+ fields: A tuple of field names the validator should be called on.
39
+ mode: The proposed validator mode.
40
+ each_item: For complex objects (sets, lists etc.) whether to validate individual
41
+ elements rather than the whole object.
42
+ always: Whether this method and other validators should be called even if the value is missing.
43
+ check_fields: Whether to check that the fields actually exist on the model.
44
+ """
45
+
46
+ decorator_repr: ClassVar[str] = '@validator'
47
+
48
+ fields: tuple[str, ...]
49
+ mode: Literal['before', 'after']
50
+ each_item: bool
51
+ always: bool
52
+ check_fields: bool | None
53
+
54
+
55
+ @dataclass(**slots_true)
56
+ class FieldValidatorDecoratorInfo:
57
+ """A container for data from `@field_validator` so that we can access it
58
+ while building the pydantic-core schema.
59
+
60
+ Attributes:
61
+ decorator_repr: A class variable representing the decorator string, '@field_validator'.
62
+ fields: A tuple of field names the validator should be called on.
63
+ mode: The proposed validator mode.
64
+ check_fields: Whether to check that the fields actually exist on the model.
65
+ json_schema_input_type: The input type of the function. This is only used to generate
66
+ the appropriate JSON Schema (in validation mode) and can only specified
67
+ when `mode` is either `'before'`, `'plain'` or `'wrap'`.
68
+ """
69
+
70
+ decorator_repr: ClassVar[str] = '@field_validator'
71
+
72
+ fields: tuple[str, ...]
73
+ mode: FieldValidatorModes
74
+ check_fields: bool | None
75
+ json_schema_input_type: Any
76
+
77
+
78
+ @dataclass(**slots_true)
79
+ class RootValidatorDecoratorInfo:
80
+ """A container for data from `@root_validator` so that we can access it
81
+ while building the pydantic-core schema.
82
+
83
+ Attributes:
84
+ decorator_repr: A class variable representing the decorator string, '@root_validator'.
85
+ mode: The proposed validator mode.
86
+ """
87
+
88
+ decorator_repr: ClassVar[str] = '@root_validator'
89
+ mode: Literal['before', 'after']
90
+
91
+
92
+ @dataclass(**slots_true)
93
+ class FieldSerializerDecoratorInfo:
94
+ """A container for data from `@field_serializer` so that we can access it
95
+ while building the pydantic-core schema.
96
+
97
+ Attributes:
98
+ decorator_repr: A class variable representing the decorator string, '@field_serializer'.
99
+ fields: A tuple of field names the serializer should be called on.
100
+ mode: The proposed serializer mode.
101
+ return_type: The type of the serializer's return value.
102
+ when_used: The serialization condition. Accepts a string with values `'always'`, `'unless-none'`, `'json'`,
103
+ and `'json-unless-none'`.
104
+ check_fields: Whether to check that the fields actually exist on the model.
105
+ """
106
+
107
+ decorator_repr: ClassVar[str] = '@field_serializer'
108
+ fields: tuple[str, ...]
109
+ mode: Literal['plain', 'wrap']
110
+ return_type: Any
111
+ when_used: core_schema.WhenUsed
112
+ check_fields: bool | None
113
+
114
+
115
+ @dataclass(**slots_true)
116
+ class ModelSerializerDecoratorInfo:
117
+ """A container for data from `@model_serializer` so that we can access it
118
+ while building the pydantic-core schema.
119
+
120
+ Attributes:
121
+ decorator_repr: A class variable representing the decorator string, '@model_serializer'.
122
+ mode: The proposed serializer mode.
123
+ return_type: The type of the serializer's return value.
124
+ when_used: The serialization condition. Accepts a string with values `'always'`, `'unless-none'`, `'json'`,
125
+ and `'json-unless-none'`.
126
+ """
127
+
128
+ decorator_repr: ClassVar[str] = '@model_serializer'
129
+ mode: Literal['plain', 'wrap']
130
+ return_type: Any
131
+ when_used: core_schema.WhenUsed
132
+
133
+
134
+ @dataclass(**slots_true)
135
+ class ModelValidatorDecoratorInfo:
136
+ """A container for data from `@model_validator` so that we can access it
137
+ while building the pydantic-core schema.
138
+
139
+ Attributes:
140
+ decorator_repr: A class variable representing the decorator string, '@model_validator'.
141
+ mode: The proposed serializer mode.
142
+ """
143
+
144
+ decorator_repr: ClassVar[str] = '@model_validator'
145
+ mode: Literal['wrap', 'before', 'after']
146
+
147
+
148
+ DecoratorInfo: TypeAlias = """Union[
149
+ ValidatorDecoratorInfo,
150
+ FieldValidatorDecoratorInfo,
151
+ RootValidatorDecoratorInfo,
152
+ FieldSerializerDecoratorInfo,
153
+ ModelSerializerDecoratorInfo,
154
+ ModelValidatorDecoratorInfo,
155
+ ComputedFieldInfo,
156
+ ]"""
157
+
158
+ ReturnType = TypeVar('ReturnType')
159
+ DecoratedType: TypeAlias = (
160
+ 'Union[classmethod[Any, Any, ReturnType], staticmethod[Any, ReturnType], Callable[..., ReturnType], property]'
161
+ )
162
+
163
+
164
+ @dataclass # can't use slots here since we set attributes on `__post_init__`
165
+ class PydanticDescriptorProxy(Generic[ReturnType]):
166
+ """Wrap a classmethod, staticmethod, property or unbound function
167
+ and act as a descriptor that allows us to detect decorated items
168
+ from the class' attributes.
169
+
170
+ This class' __get__ returns the wrapped item's __get__ result,
171
+ which makes it transparent for classmethods and staticmethods.
172
+
173
+ Attributes:
174
+ wrapped: The decorator that has to be wrapped.
175
+ decorator_info: The decorator info.
176
+ shim: A wrapper function to wrap V1 style function.
177
+ """
178
+
179
+ wrapped: DecoratedType[ReturnType]
180
+ decorator_info: DecoratorInfo
181
+ shim: Callable[[Callable[..., Any]], Callable[..., Any]] | None = None
182
+
183
+ def __post_init__(self):
184
+ for attr in 'setter', 'deleter':
185
+ if hasattr(self.wrapped, attr):
186
+ f = partial(self._call_wrapped_attr, name=attr)
187
+ setattr(self, attr, f)
188
+
189
+ def _call_wrapped_attr(self, func: Callable[[Any], None], *, name: str) -> PydanticDescriptorProxy[ReturnType]:
190
+ self.wrapped = getattr(self.wrapped, name)(func)
191
+ if isinstance(self.wrapped, property):
192
+ # update ComputedFieldInfo.wrapped_property
193
+ from ..fields import ComputedFieldInfo
194
+
195
+ if isinstance(self.decorator_info, ComputedFieldInfo):
196
+ self.decorator_info.wrapped_property = self.wrapped
197
+ return self
198
+
199
+ def __get__(self, obj: object | None, obj_type: type[object] | None = None) -> PydanticDescriptorProxy[ReturnType]:
200
+ try:
201
+ return self.wrapped.__get__(obj, obj_type) # pyright: ignore[reportReturnType]
202
+ except AttributeError:
203
+ # not a descriptor, e.g. a partial object
204
+ return self.wrapped # type: ignore[return-value]
205
+
206
+ def __set_name__(self, instance: Any, name: str) -> None:
207
+ if hasattr(self.wrapped, '__set_name__'):
208
+ self.wrapped.__set_name__(instance, name) # pyright: ignore[reportFunctionMemberAccess]
209
+
210
+ def __getattr__(self, name: str, /) -> Any:
211
+ """Forward checks for __isabstractmethod__ and such."""
212
+ return getattr(self.wrapped, name)
213
+
214
+
215
+ DecoratorInfoType = TypeVar('DecoratorInfoType', bound=DecoratorInfo)
216
+
217
+
218
+ @dataclass(**slots_true)
219
+ class Decorator(Generic[DecoratorInfoType]):
220
+ """A generic container class to join together the decorator metadata
221
+ (metadata from decorator itself, which we have when the
222
+ decorator is called but not when we are building the core-schema)
223
+ and the bound function (which we have after the class itself is created).
224
+
225
+ Attributes:
226
+ cls_ref: The class ref.
227
+ cls_var_name: The decorated function name.
228
+ func: The decorated function.
229
+ shim: A wrapper function to wrap V1 style function.
230
+ info: The decorator info.
231
+ """
232
+
233
+ cls_ref: str
234
+ cls_var_name: str
235
+ func: Callable[..., Any]
236
+ shim: Callable[[Any], Any] | None
237
+ info: DecoratorInfoType
238
+
239
+ @staticmethod
240
+ def build(
241
+ cls_: Any,
242
+ *,
243
+ cls_var_name: str,
244
+ shim: Callable[[Any], Any] | None,
245
+ info: DecoratorInfoType,
246
+ ) -> Decorator[DecoratorInfoType]:
247
+ """Build a new decorator.
248
+
249
+ Args:
250
+ cls_: The class.
251
+ cls_var_name: The decorated function name.
252
+ shim: A wrapper function to wrap V1 style function.
253
+ info: The decorator info.
254
+
255
+ Returns:
256
+ The new decorator instance.
257
+ """
258
+ func = get_attribute_from_bases(cls_, cls_var_name)
259
+ if shim is not None:
260
+ func = shim(func)
261
+ func = unwrap_wrapped_function(func, unwrap_partial=False)
262
+ if not callable(func):
263
+ # TODO most likely this branch can be removed when we drop support for Python 3.12:
264
+ # This branch will get hit for classmethod properties
265
+ attribute = get_attribute_from_base_dicts(cls_, cls_var_name) # prevents the binding call to `__get__`
266
+ if isinstance(attribute, PydanticDescriptorProxy):
267
+ func = unwrap_wrapped_function(attribute.wrapped)
268
+ return Decorator(
269
+ cls_ref=get_type_ref(cls_),
270
+ cls_var_name=cls_var_name,
271
+ func=func,
272
+ shim=shim,
273
+ info=info,
274
+ )
275
+
276
+ def bind_to_cls(self, cls: Any) -> Decorator[DecoratorInfoType]:
277
+ """Bind the decorator to a class.
278
+
279
+ Args:
280
+ cls: the class.
281
+
282
+ Returns:
283
+ The new decorator instance.
284
+ """
285
+ return self.build(
286
+ cls,
287
+ cls_var_name=self.cls_var_name,
288
+ shim=self.shim,
289
+ info=copy(self.info),
290
+ )
291
+
292
+
293
+ def get_bases(tp: type[Any]) -> tuple[type[Any], ...]:
294
+ """Get the base classes of a class or typeddict.
295
+
296
+ Args:
297
+ tp: The type or class to get the bases.
298
+
299
+ Returns:
300
+ The base classes.
301
+ """
302
+ if is_typeddict(tp):
303
+ return tp.__orig_bases__ # type: ignore
304
+ try:
305
+ return tp.__bases__
306
+ except AttributeError:
307
+ return ()
308
+
309
+
310
+ def mro(tp: type[Any]) -> tuple[type[Any], ...]:
311
+ """Calculate the Method Resolution Order of bases using the C3 algorithm.
312
+
313
+ See https://www.python.org/download/releases/2.3/mro/
314
+ """
315
+ # try to use the existing mro, for performance mainly
316
+ # but also because it helps verify the implementation below
317
+ if not is_typeddict(tp):
318
+ try:
319
+ return tp.__mro__
320
+ except AttributeError:
321
+ # GenericAlias and some other cases
322
+ pass
323
+
324
+ bases = get_bases(tp)
325
+ return (tp,) + mro_for_bases(bases)
326
+
327
+
328
+ def mro_for_bases(bases: tuple[type[Any], ...]) -> tuple[type[Any], ...]:
329
+ def merge_seqs(seqs: list[deque[type[Any]]]) -> Iterable[type[Any]]:
330
+ while True:
331
+ non_empty = [seq for seq in seqs if seq]
332
+ if not non_empty:
333
+ # Nothing left to process, we're done.
334
+ return
335
+ candidate: type[Any] | None = None
336
+ for seq in non_empty: # Find merge candidates among seq heads.
337
+ candidate = seq[0]
338
+ not_head = [s for s in non_empty if candidate in islice(s, 1, None)]
339
+ if not_head:
340
+ # Reject the candidate.
341
+ candidate = None
342
+ else:
343
+ break
344
+ if not candidate:
345
+ raise TypeError('Inconsistent hierarchy, no C3 MRO is possible')
346
+ yield candidate
347
+ for seq in non_empty:
348
+ # Remove candidate.
349
+ if seq[0] == candidate:
350
+ seq.popleft()
351
+
352
+ seqs = [deque(mro(base)) for base in bases] + [deque(bases)]
353
+ return tuple(merge_seqs(seqs))
354
+
355
+
356
+ _sentinel = object()
357
+
358
+
359
+ def get_attribute_from_bases(tp: type[Any] | tuple[type[Any], ...], name: str) -> Any:
360
+ """Get the attribute from the next class in the MRO that has it,
361
+ aiming to simulate calling the method on the actual class.
362
+
363
+ The reason for iterating over the mro instead of just getting
364
+ the attribute (which would do that for us) is to support TypedDict,
365
+ which lacks a real __mro__, but can have a virtual one constructed
366
+ from its bases (as done here).
367
+
368
+ Args:
369
+ tp: The type or class to search for the attribute. If a tuple, this is treated as a set of base classes.
370
+ name: The name of the attribute to retrieve.
371
+
372
+ Returns:
373
+ Any: The attribute value, if found.
374
+
375
+ Raises:
376
+ AttributeError: If the attribute is not found in any class in the MRO.
377
+ """
378
+ if isinstance(tp, tuple):
379
+ for base in mro_for_bases(tp):
380
+ attribute = base.__dict__.get(name, _sentinel)
381
+ if attribute is not _sentinel:
382
+ attribute_get = getattr(attribute, '__get__', None)
383
+ if attribute_get is not None:
384
+ return attribute_get(None, tp)
385
+ return attribute
386
+ raise AttributeError(f'{name} not found in {tp}')
387
+ else:
388
+ try:
389
+ return getattr(tp, name)
390
+ except AttributeError:
391
+ return get_attribute_from_bases(mro(tp), name)
392
+
393
+
394
+ def get_attribute_from_base_dicts(tp: type[Any], name: str) -> Any:
395
+ """Get an attribute out of the `__dict__` following the MRO.
396
+ This prevents the call to `__get__` on the descriptor, and allows
397
+ us to get the original function for classmethod properties.
398
+
399
+ Args:
400
+ tp: The type or class to search for the attribute.
401
+ name: The name of the attribute to retrieve.
402
+
403
+ Returns:
404
+ Any: The attribute value, if found.
405
+
406
+ Raises:
407
+ KeyError: If the attribute is not found in any class's `__dict__` in the MRO.
408
+ """
409
+ for base in reversed(mro(tp)):
410
+ if name in base.__dict__:
411
+ return base.__dict__[name]
412
+ return tp.__dict__[name] # raise the error
413
+
414
+
415
+ @dataclass(**slots_true)
416
+ class DecoratorInfos:
417
+ """Mapping of name in the class namespace to decorator info.
418
+
419
+ note that the name in the class namespace is the function or attribute name
420
+ not the field name!
421
+ """
422
+
423
+ validators: dict[str, Decorator[ValidatorDecoratorInfo]] = field(default_factory=dict)
424
+ field_validators: dict[str, Decorator[FieldValidatorDecoratorInfo]] = field(default_factory=dict)
425
+ root_validators: dict[str, Decorator[RootValidatorDecoratorInfo]] = field(default_factory=dict)
426
+ field_serializers: dict[str, Decorator[FieldSerializerDecoratorInfo]] = field(default_factory=dict)
427
+ model_serializers: dict[str, Decorator[ModelSerializerDecoratorInfo]] = field(default_factory=dict)
428
+ model_validators: dict[str, Decorator[ModelValidatorDecoratorInfo]] = field(default_factory=dict)
429
+ computed_fields: dict[str, Decorator[ComputedFieldInfo]] = field(default_factory=dict)
430
+
431
+ @classmethod
432
+ def build(
433
+ cls,
434
+ typ: type[Any],
435
+ # Default to `True` for backwards compatibility:
436
+ replace_wrapped_methods: bool = True,
437
+ ) -> Self:
438
+ """Build a `DecoratorInfos` instance for the given model, dataclass or `TypedDict` type.
439
+
440
+ Decorators from parent classes are included, including "bare" classes (e.g. if `typ`
441
+ is a Pydantic model, non Pydantic parent model classes are also taken into account).
442
+ The collection of the decorators happens by respecting the MRO.
443
+
444
+ If one of the bases has an `__pydantic_decorators__` attribute set, it is assumed to be
445
+ a `DecoratorInfos` instance and is used as-is. The `__pydantic_decorators__` attribute
446
+ is *not* being set on the provided `typ`.
447
+
448
+ Args:
449
+ typ: The model, dataclass or `TypedDict` type to use when building the `DecoratorInfos` instance.
450
+ replace_wrapped_methods: Whether to replace the decorator's wrapped methods on `typ`.
451
+ This is useful e.g. for field validators which are initially class methods. This should
452
+ only be set to `True` if `typ` is a Pydantic model or dataclass (otherwise this results
453
+ in mutations of classes Pydantic doesn't "own").
454
+ """
455
+ # reminder: dicts are ordered and replacement does not alter the order
456
+ res = cls()
457
+ # Iterate over the bases, without the actual `typ`.
458
+ # `1:-1` because we don't need to include `object`/`TypedDict`:
459
+ for base in reversed(mro(typ)[1:-1]):
460
+ existing: DecoratorInfos | None = base.__dict__.get('__pydantic_decorators__')
461
+ if existing is None:
462
+ existing, _ = _decorator_infos_for_class(base, collect_to_replace=False)
463
+ res.validators.update({k: v.bind_to_cls(typ) for k, v in existing.validators.items()})
464
+ res.field_validators.update({k: v.bind_to_cls(typ) for k, v in existing.field_validators.items()})
465
+ res.root_validators.update({k: v.bind_to_cls(typ) for k, v in existing.root_validators.items()})
466
+ res.field_serializers.update({k: v.bind_to_cls(typ) for k, v in existing.field_serializers.items()})
467
+ res.model_serializers.update({k: v.bind_to_cls(typ) for k, v in existing.model_serializers.items()})
468
+ res.model_validators.update({k: v.bind_to_cls(typ) for k, v in existing.model_validators.items()})
469
+ res.computed_fields.update({k: v.bind_to_cls(typ) for k, v in existing.computed_fields.items()})
470
+
471
+ decorator_infos, to_replace = _decorator_infos_for_class(typ, collect_to_replace=True)
472
+
473
+ res.validators.update(decorator_infos.validators)
474
+ res.field_validators.update(decorator_infos.field_validators)
475
+ res.root_validators.update(decorator_infos.root_validators)
476
+ res.field_serializers.update(decorator_infos.field_serializers)
477
+ res.model_serializers.update(decorator_infos.model_serializers)
478
+ res.model_validators.update(decorator_infos.model_validators)
479
+ res.computed_fields.update(decorator_infos.computed_fields)
480
+
481
+ if replace_wrapped_methods and to_replace:
482
+ for name, value in to_replace:
483
+ setattr(typ, name, value)
484
+
485
+ res._validate()
486
+ return res
487
+
488
+ def _validate(self) -> None:
489
+ seen: set[str] = set()
490
+ for field_ser in self.field_serializers.values():
491
+ for f_name in field_ser.info.fields:
492
+ if f_name in seen:
493
+ raise PydanticUserError(
494
+ f'Multiple field serializer functions were defined for field {f_name!r}, this is not allowed.',
495
+ code='multiple-field-serializers',
496
+ )
497
+ seen.add(f_name)
498
+
499
+ def update_from_config(self, config_wrapper: ConfigWrapper) -> None:
500
+ """Update the decorator infos from the configuration of the class they are attached to."""
501
+ for name, computed_field_dec in self.computed_fields.items():
502
+ computed_field_dec.info._update_from_config(config_wrapper, name)
503
+
504
+
505
+ def _decorator_infos_for_class(
506
+ typ: type[Any],
507
+ *,
508
+ collect_to_replace: bool,
509
+ ) -> tuple[DecoratorInfos, list[tuple[str, Any]]]:
510
+ """Collect a `DecoratorInfos` for class, without looking into bases."""
511
+ res = DecoratorInfos()
512
+ to_replace: list[tuple[str, Any]] = []
513
+
514
+ for var_name, var_value in vars(typ).items():
515
+ if isinstance(var_value, PydanticDescriptorProxy):
516
+ info = var_value.decorator_info
517
+ if isinstance(info, ValidatorDecoratorInfo):
518
+ res.validators[var_name] = Decorator.build(typ, cls_var_name=var_name, shim=var_value.shim, info=info)
519
+ elif isinstance(info, FieldValidatorDecoratorInfo):
520
+ res.field_validators[var_name] = Decorator.build(
521
+ typ, cls_var_name=var_name, shim=var_value.shim, info=info
522
+ )
523
+ elif isinstance(info, RootValidatorDecoratorInfo):
524
+ res.root_validators[var_name] = Decorator.build(
525
+ typ, cls_var_name=var_name, shim=var_value.shim, info=info
526
+ )
527
+ elif isinstance(info, FieldSerializerDecoratorInfo):
528
+ res.field_serializers[var_name] = Decorator.build(
529
+ typ, cls_var_name=var_name, shim=var_value.shim, info=info
530
+ )
531
+ elif isinstance(info, ModelValidatorDecoratorInfo):
532
+ res.model_validators[var_name] = Decorator.build(
533
+ typ, cls_var_name=var_name, shim=var_value.shim, info=info
534
+ )
535
+ elif isinstance(info, ModelSerializerDecoratorInfo):
536
+ res.model_serializers[var_name] = Decorator.build(
537
+ typ, cls_var_name=var_name, shim=var_value.shim, info=info
538
+ )
539
+ else:
540
+ from ..fields import ComputedFieldInfo
541
+
542
+ isinstance(var_value, ComputedFieldInfo)
543
+ res.computed_fields[var_name] = Decorator.build(typ, cls_var_name=var_name, shim=None, info=info)
544
+ if collect_to_replace:
545
+ to_replace.append((var_name, var_value.wrapped))
546
+
547
+ return res, to_replace
548
+
549
+
550
+ def inspect_validator(
551
+ validator: Callable[..., Any], *, mode: FieldValidatorModes, type: Literal['field', 'model']
552
+ ) -> bool:
553
+ """Look at a field or model validator function and determine whether it takes an info argument.
554
+
555
+ An error is raised if the function has an invalid signature.
556
+
557
+ Args:
558
+ validator: The validator function to inspect.
559
+ mode: The proposed validator mode.
560
+ type: The type of validator, either 'field' or 'model'.
561
+
562
+ Returns:
563
+ Whether the validator takes an info argument.
564
+ """
565
+ try:
566
+ sig = signature_no_eval(validator)
567
+ except (ValueError, TypeError):
568
+ # `inspect.signature` might not be able to infer a signature, e.g. with C objects.
569
+ # In this case, we assume no info argument is present:
570
+ return False
571
+ n_positional = count_positional_required_params(sig)
572
+ if mode == 'wrap':
573
+ if n_positional == 3:
574
+ return True
575
+ elif n_positional == 2:
576
+ return False
577
+ else:
578
+ assert mode in {'before', 'after', 'plain'}, f"invalid mode: {mode!r}, expected 'before', 'after' or 'plain"
579
+ if n_positional == 2:
580
+ return True
581
+ elif n_positional == 1:
582
+ return False
583
+
584
+ raise PydanticUserError(
585
+ f'Unrecognized {type} validator function signature for {validator} with `mode={mode}`: {sig}',
586
+ code='validator-signature',
587
+ )
588
+
589
+
590
+ def inspect_field_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> tuple[bool, bool]:
591
+ """Look at a field serializer function and determine if it is a field serializer,
592
+ and whether it takes an info argument.
593
+
594
+ An error is raised if the function has an invalid signature.
595
+
596
+ Args:
597
+ serializer: The serializer function to inspect.
598
+ mode: The serializer mode, either 'plain' or 'wrap'.
599
+
600
+ Returns:
601
+ Tuple of (is_field_serializer, info_arg).
602
+ """
603
+ try:
604
+ sig = signature_no_eval(serializer)
605
+ except (ValueError, TypeError):
606
+ # `inspect.signature` might not be able to infer a signature, e.g. with C objects.
607
+ # In this case, we assume no info argument is present and this is not a method:
608
+ return (False, False)
609
+
610
+ first = next(iter(sig.parameters.values()), None)
611
+ is_field_serializer = first is not None and first.name == 'self'
612
+
613
+ n_positional = count_positional_required_params(sig)
614
+ if is_field_serializer:
615
+ # -1 to correct for self parameter
616
+ info_arg = _serializer_info_arg(mode, n_positional - 1)
617
+ else:
618
+ info_arg = _serializer_info_arg(mode, n_positional)
619
+
620
+ if info_arg is None:
621
+ raise PydanticUserError(
622
+ f'Unrecognized field_serializer function signature for {serializer} with `mode={mode}`:{sig}',
623
+ code='field-serializer-signature',
624
+ )
625
+
626
+ return is_field_serializer, info_arg
627
+
628
+
629
+ def inspect_annotated_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> bool:
630
+ """Look at a serializer function used via `Annotated` and determine whether it takes an info argument.
631
+
632
+ An error is raised if the function has an invalid signature.
633
+
634
+ Args:
635
+ serializer: The serializer function to check.
636
+ mode: The serializer mode, either 'plain' or 'wrap'.
637
+
638
+ Returns:
639
+ info_arg
640
+ """
641
+ try:
642
+ sig = signature_no_eval(serializer)
643
+ except (ValueError, TypeError):
644
+ # `inspect.signature` might not be able to infer a signature, e.g. with C objects.
645
+ # In this case, we assume no info argument is present:
646
+ return False
647
+ info_arg = _serializer_info_arg(mode, count_positional_required_params(sig))
648
+ if info_arg is None:
649
+ raise PydanticUserError(
650
+ f'Unrecognized field_serializer function signature for {serializer} with `mode={mode}`:{sig}',
651
+ code='field-serializer-signature',
652
+ )
653
+ else:
654
+ return info_arg
655
+
656
+
657
+ def inspect_model_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> bool:
658
+ """Look at a model serializer function and determine whether it takes an info argument.
659
+
660
+ An error is raised if the function has an invalid signature.
661
+
662
+ Args:
663
+ serializer: The serializer function to check.
664
+ mode: The serializer mode, either 'plain' or 'wrap'.
665
+
666
+ Returns:
667
+ `info_arg` - whether the function expects an info argument.
668
+ """
669
+ if isinstance(serializer, (staticmethod, classmethod)) or not is_instance_method_from_sig(serializer):
670
+ raise PydanticUserError(
671
+ '`@model_serializer` must be applied to instance methods', code='model-serializer-instance-method'
672
+ )
673
+
674
+ sig = signature_no_eval(serializer)
675
+ info_arg = _serializer_info_arg(mode, count_positional_required_params(sig))
676
+ if info_arg is None:
677
+ raise PydanticUserError(
678
+ f'Unrecognized model_serializer function signature for {serializer} with `mode={mode}`:{sig}',
679
+ code='model-serializer-signature',
680
+ )
681
+ else:
682
+ return info_arg
683
+
684
+
685
+ def _serializer_info_arg(mode: Literal['plain', 'wrap'], n_positional: int) -> bool | None:
686
+ if mode == 'plain':
687
+ if n_positional == 1:
688
+ # (input_value: Any, /) -> Any
689
+ return False
690
+ elif n_positional == 2:
691
+ # (model: Any, input_value: Any, /) -> Any
692
+ return True
693
+ else:
694
+ assert mode == 'wrap', f"invalid mode: {mode!r}, expected 'plain' or 'wrap'"
695
+ if n_positional == 2:
696
+ # (input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any
697
+ return False
698
+ elif n_positional == 3:
699
+ # (input_value: Any, serializer: SerializerFunctionWrapHandler, info: SerializationInfo, /) -> Any
700
+ return True
701
+
702
+ return None
703
+
704
+
705
+ AnyDecoratorCallable: TypeAlias = (
706
+ 'Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any], Callable[..., Any]]'
707
+ )
708
+
709
+
710
+ def is_instance_method_from_sig(function: AnyDecoratorCallable) -> bool:
711
+ """Whether the function is an instance method.
712
+
713
+ It will consider a function as instance method if the first parameter of
714
+ function is `self`.
715
+
716
+ Args:
717
+ function: The function to check.
718
+
719
+ Returns:
720
+ `True` if the function is an instance method, `False` otherwise.
721
+ """
722
+ sig = signature_no_eval(unwrap_wrapped_function(function))
723
+ first = next(iter(sig.parameters.values()), None)
724
+ if first and first.name == 'self':
725
+ return True
726
+ return False
727
+
728
+
729
+ def ensure_classmethod_based_on_signature(function: AnyDecoratorCallable) -> Any:
730
+ """Apply the `@classmethod` decorator on the function.
731
+
732
+ Args:
733
+ function: The function to apply the decorator on.
734
+
735
+ Return:
736
+ The `@classmethod` decorator applied function.
737
+ """
738
+ if not isinstance(
739
+ unwrap_wrapped_function(function, unwrap_class_static_method=False), classmethod
740
+ ) and _is_classmethod_from_sig(function):
741
+ return classmethod(function) # type: ignore[arg-type]
742
+ return function
743
+
744
+
745
+ def _is_classmethod_from_sig(function: AnyDecoratorCallable) -> bool:
746
+ sig = signature_no_eval(unwrap_wrapped_function(function))
747
+ first = next(iter(sig.parameters.values()), None)
748
+ if first and first.name == 'cls':
749
+ return True
750
+ return False
751
+
752
+
753
+ def unwrap_wrapped_function(
754
+ func: Any,
755
+ *,
756
+ unwrap_partial: bool = True,
757
+ unwrap_class_static_method: bool = True,
758
+ ) -> Any:
759
+ """Recursively unwraps a wrapped function until the underlying function is reached.
760
+ This handles property, functools.partial, functools.partialmethod, staticmethod, and classmethod.
761
+
762
+ Args:
763
+ func: The function to unwrap.
764
+ unwrap_partial: If True (default), unwrap partial and partialmethod decorators.
765
+ unwrap_class_static_method: If True (default), also unwrap classmethod and staticmethod
766
+ decorators. If False, only unwrap partial and partialmethod decorators.
767
+
768
+ Returns:
769
+ The underlying function of the wrapped function.
770
+ """
771
+ # Define the types we want to check against as a single tuple.
772
+ unwrap_types = (
773
+ (property, cached_property)
774
+ + ((partial, partialmethod) if unwrap_partial else ())
775
+ + ((staticmethod, classmethod) if unwrap_class_static_method else ())
776
+ )
777
+
778
+ while isinstance(func, unwrap_types):
779
+ if unwrap_class_static_method and isinstance(func, (classmethod, staticmethod)):
780
+ func = func.__func__
781
+ elif isinstance(func, (partial, partialmethod)):
782
+ func = func.func
783
+ elif isinstance(func, property):
784
+ func = func.fget # arbitrary choice, convenient for computed fields
785
+ else:
786
+ # Make coverage happy as it can only get here in the last possible case
787
+ assert isinstance(func, cached_property)
788
+ func = func.func # type: ignore
789
+
790
+ return func
791
+
792
+
793
+ _function_like = (
794
+ partial,
795
+ partialmethod,
796
+ types.FunctionType,
797
+ types.BuiltinFunctionType,
798
+ types.MethodType,
799
+ types.WrapperDescriptorType,
800
+ types.MethodWrapperType,
801
+ types.MemberDescriptorType,
802
+ )
803
+
804
+
805
+ def get_callable_return_type(
806
+ callable_obj: Any,
807
+ globalns: GlobalsNamespace | None = None,
808
+ localns: MappingNamespace | None = None,
809
+ ) -> Any | PydanticUndefinedType:
810
+ """Get the callable return type.
811
+
812
+ Args:
813
+ callable_obj: The callable to analyze.
814
+ globalns: The globals namespace to use during type annotation evaluation.
815
+ localns: The locals namespace to use during type annotation evaluation.
816
+
817
+ Returns:
818
+ The function return type.
819
+ """
820
+ if isinstance(callable_obj, type):
821
+ # types are callables, and we assume the return type
822
+ # is the type itself (e.g. `int()` results in an instance of `int`).
823
+ return callable_obj
824
+
825
+ if not isinstance(callable_obj, _function_like):
826
+ call_func = getattr(type(callable_obj), '__call__', None) # noqa: B004
827
+ if call_func is not None:
828
+ callable_obj = call_func
829
+
830
+ hints = get_function_type_hints(
831
+ unwrap_wrapped_function(callable_obj),
832
+ include_keys={'return'},
833
+ globalns=globalns,
834
+ localns=localns,
835
+ )
836
+ return hints.get('return', PydanticUndefined)
837
+
838
+
839
+ def count_positional_required_params(sig: Signature) -> int:
840
+ """Get the number of positional (required) arguments of a signature.
841
+
842
+ This function should only be used to inspect signatures of validation and serialization functions.
843
+ The first argument (the value being serialized or validated) is counted as a required argument
844
+ even if a default value exists.
845
+
846
+ Returns:
847
+ The number of positional arguments of a signature.
848
+ """
849
+ parameters = list(sig.parameters.values())
850
+ return sum(
851
+ 1
852
+ for param in parameters
853
+ if can_be_positional(param)
854
+ # First argument is the value being validated/serialized, and can have a default value
855
+ # (e.g. `float`, which has signature `(x=0, /)`). We assume other parameters (the info arg
856
+ # for instance) should be required, and thus without any default value.
857
+ and (param.default is Parameter.empty or param is parameters[0])
858
+ )
859
+
860
+
861
+ def ensure_property(f: Any) -> Any:
862
+ """Ensure that a function is a `property` or `cached_property`, or is a valid descriptor.
863
+
864
+ Args:
865
+ f: The function to check.
866
+
867
+ Returns:
868
+ The function, or a `property` or `cached_property` instance wrapping the function.
869
+ """
870
+ if ismethoddescriptor(f) or isdatadescriptor(f):
871
+ return f
872
+ else:
873
+ return property(f)
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_decorators_v1.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Logic for V1 validators, e.g. `@validator` and `@root_validator`."""
2
+
3
+ from __future__ import annotations as _annotations
4
+
5
+ from inspect import Parameter, signature
6
+ from typing import Any, Union, cast
7
+
8
+ from pydantic_core import core_schema
9
+ from typing_extensions import Protocol
10
+
11
+ from ..errors import PydanticUserError
12
+ from ._utils import can_be_positional
13
+
14
+
15
+ class V1OnlyValueValidator(Protocol):
16
+ """A simple validator, supported for V1 validators and V2 validators."""
17
+
18
+ def __call__(self, __value: Any) -> Any: ...
19
+
20
+
21
+ class V1ValidatorWithValues(Protocol):
22
+ """A validator with `values` argument, supported for V1 validators and V2 validators."""
23
+
24
+ def __call__(self, __value: Any, values: dict[str, Any]) -> Any: ...
25
+
26
+
27
+ class V1ValidatorWithValuesKwOnly(Protocol):
28
+ """A validator with keyword only `values` argument, supported for V1 validators and V2 validators."""
29
+
30
+ def __call__(self, __value: Any, *, values: dict[str, Any]) -> Any: ...
31
+
32
+
33
+ class V1ValidatorWithKwargs(Protocol):
34
+ """A validator with `kwargs` argument, supported for V1 validators and V2 validators."""
35
+
36
+ def __call__(self, __value: Any, **kwargs: Any) -> Any: ...
37
+
38
+
39
+ class V1ValidatorWithValuesAndKwargs(Protocol):
40
+ """A validator with `values` and `kwargs` arguments, supported for V1 validators and V2 validators."""
41
+
42
+ def __call__(self, __value: Any, values: dict[str, Any], **kwargs: Any) -> Any: ...
43
+
44
+
45
+ V1Validator = Union[
46
+ V1ValidatorWithValues, V1ValidatorWithValuesKwOnly, V1ValidatorWithKwargs, V1ValidatorWithValuesAndKwargs
47
+ ]
48
+
49
+
50
+ def can_be_keyword(param: Parameter) -> bool:
51
+ return param.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY)
52
+
53
+
54
+ def make_generic_v1_field_validator(validator: V1Validator) -> core_schema.WithInfoValidatorFunction:
55
+ """Wrap a V1 style field validator for V2 compatibility.
56
+
57
+ Args:
58
+ validator: The V1 style field validator.
59
+
60
+ Returns:
61
+ A wrapped V2 style field validator.
62
+
63
+ Raises:
64
+ PydanticUserError: If the signature is not supported or the parameters are
65
+ not available in Pydantic V2.
66
+ """
67
+ sig = signature(validator)
68
+
69
+ needs_values_kw = False
70
+
71
+ for param_num, (param_name, parameter) in enumerate(sig.parameters.items()):
72
+ if can_be_keyword(parameter) and param_name in ('field', 'config'):
73
+ raise PydanticUserError(
74
+ 'The `field` and `config` parameters are not available in Pydantic V2, '
75
+ 'please use the `info` parameter instead.',
76
+ code='validator-field-config-info',
77
+ )
78
+ if parameter.kind is Parameter.VAR_KEYWORD:
79
+ needs_values_kw = True
80
+ elif can_be_keyword(parameter) and param_name == 'values':
81
+ needs_values_kw = True
82
+ elif can_be_positional(parameter) and param_num == 0:
83
+ # value
84
+ continue
85
+ elif parameter.default is Parameter.empty: # ignore params with defaults e.g. bound by functools.partial
86
+ raise PydanticUserError(
87
+ f'Unsupported signature for V1 style validator {validator}: {sig} is not supported.',
88
+ code='validator-v1-signature',
89
+ )
90
+
91
+ if needs_values_kw:
92
+ # (v, **kwargs), (v, values, **kwargs), (v, *, values, **kwargs) or (v, *, values)
93
+ val1 = cast(V1ValidatorWithValues, validator)
94
+
95
+ def wrapper1(value: Any, info: core_schema.ValidationInfo) -> Any:
96
+ return val1(value, values=info.data)
97
+
98
+ return wrapper1
99
+ else:
100
+ val2 = cast(V1OnlyValueValidator, validator)
101
+
102
+ def wrapper2(value: Any, _: core_schema.ValidationInfo) -> Any:
103
+ return val2(value)
104
+
105
+ return wrapper2
106
+
107
+
108
+ RootValidatorValues = dict[str, Any]
109
+ # technically tuple[model_dict, model_extra, fields_set] | tuple[dataclass_dict, init_vars]
110
+ RootValidatorFieldsTuple = tuple[Any, ...]
111
+
112
+
113
+ class V1RootValidatorFunction(Protocol):
114
+ """A simple root validator, supported for V1 validators and V2 validators."""
115
+
116
+ def __call__(self, __values: RootValidatorValues) -> RootValidatorValues: ...
117
+
118
+
119
+ class V2CoreBeforeRootValidator(Protocol):
120
+ """V2 validator with mode='before'."""
121
+
122
+ def __call__(self, __values: RootValidatorValues, __info: core_schema.ValidationInfo) -> RootValidatorValues: ...
123
+
124
+
125
+ class V2CoreAfterRootValidator(Protocol):
126
+ """V2 validator with mode='after'."""
127
+
128
+ def __call__(
129
+ self, __fields_tuple: RootValidatorFieldsTuple, __info: core_schema.ValidationInfo
130
+ ) -> RootValidatorFieldsTuple: ...
131
+
132
+
133
+ def make_v1_generic_root_validator(
134
+ validator: V1RootValidatorFunction, pre: bool
135
+ ) -> V2CoreBeforeRootValidator | V2CoreAfterRootValidator:
136
+ """Wrap a V1 style root validator for V2 compatibility.
137
+
138
+ Args:
139
+ validator: The V1 style field validator.
140
+ pre: Whether the validator is a pre validator.
141
+
142
+ Returns:
143
+ A wrapped V2 style validator.
144
+ """
145
+ if pre is True:
146
+ # mode='before' for pydantic-core
147
+ def _wrapper1(values: RootValidatorValues, _: core_schema.ValidationInfo) -> RootValidatorValues:
148
+ return validator(values)
149
+
150
+ return _wrapper1
151
+
152
+ # mode='after' for pydantic-core
153
+ def _wrapper2(fields_tuple: RootValidatorFieldsTuple, _: core_schema.ValidationInfo) -> RootValidatorFieldsTuple:
154
+ if len(fields_tuple) == 2:
155
+ # dataclass, this is easy
156
+ values, init_vars = fields_tuple
157
+ values = validator(values)
158
+ return values, init_vars
159
+ else:
160
+ # ugly hack: to match v1 behaviour, we merge values and model_extra, then split them up based on fields
161
+ # afterwards
162
+ model_dict, model_extra, fields_set = fields_tuple
163
+ if model_extra:
164
+ fields = set(model_dict.keys())
165
+ model_dict.update(model_extra)
166
+ model_dict_new = validator(model_dict)
167
+ for k in list(model_dict_new.keys()):
168
+ if k not in fields:
169
+ model_extra[k] = model_dict_new.pop(k)
170
+ else:
171
+ model_dict_new = validator(model_dict)
172
+ return model_dict_new, model_extra, fields_set
173
+
174
+ return _wrapper2
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_discriminated_union.py ADDED
@@ -0,0 +1,494 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations as _annotations
2
+
3
+ from collections.abc import Hashable, Sequence
4
+ from typing import TYPE_CHECKING, Any, cast
5
+
6
+ from pydantic_core import CoreSchema, core_schema
7
+
8
+ from ..errors import PydanticUserError
9
+ from . import _core_utils
10
+ from ._core_utils import (
11
+ CoreSchemaField,
12
+ )
13
+
14
+ if TYPE_CHECKING:
15
+ from ..types import Discriminator
16
+ from ._core_metadata import CoreMetadata
17
+
18
+
19
+ class MissingDefinitionForUnionRef(Exception):
20
+ """Raised when applying a discriminated union discriminator to a schema
21
+ requires a definition that is not yet defined
22
+ """
23
+
24
+ def __init__(self, ref: str) -> None:
25
+ self.ref = ref
26
+ super().__init__(f'Missing definition for ref {self.ref!r}')
27
+
28
+
29
+ def set_discriminator_in_metadata(schema: CoreSchema, discriminator: Any) -> None:
30
+ metadata = cast('CoreMetadata', schema.setdefault('metadata', {}))
31
+ metadata['pydantic_internal_union_discriminator'] = discriminator
32
+
33
+
34
+ def apply_discriminator(
35
+ schema: core_schema.CoreSchema,
36
+ discriminator: str | Discriminator,
37
+ definitions: dict[str, core_schema.CoreSchema] | None = None,
38
+ ) -> core_schema.CoreSchema:
39
+ """Applies the discriminator and returns a new core schema.
40
+
41
+ Args:
42
+ schema: The input schema.
43
+ discriminator: The name of the field which will serve as the discriminator.
44
+ definitions: A mapping of schema ref to schema.
45
+
46
+ Returns:
47
+ The new core schema.
48
+
49
+ Raises:
50
+ TypeError:
51
+ - If `discriminator` is used with invalid union variant.
52
+ - If `discriminator` is used with `Union` type with one variant.
53
+ - If `discriminator` value mapped to multiple choices.
54
+ MissingDefinitionForUnionRef:
55
+ If the definition for ref is missing.
56
+ PydanticUserError:
57
+ - If a model in union doesn't have a discriminator field.
58
+ - If discriminator field has a non-string alias.
59
+ - If discriminator fields have different aliases.
60
+ - If discriminator field not of type `Literal`.
61
+ """
62
+ from ..types import Discriminator
63
+
64
+ if isinstance(discriminator, Discriminator):
65
+ if isinstance(discriminator.discriminator, str):
66
+ discriminator = discriminator.discriminator
67
+ else:
68
+ return discriminator._convert_schema(schema)
69
+
70
+ return _ApplyInferredDiscriminator(discriminator, definitions or {}).apply(schema)
71
+
72
+
73
+ class _ApplyInferredDiscriminator:
74
+ """This class is used to convert an input schema containing a union schema into one where that union is
75
+ replaced with a tagged-union, with all the associated debugging and performance benefits.
76
+
77
+ This is done by:
78
+ * Validating that the input schema is compatible with the provided discriminator
79
+ * Introspecting the schema to determine which discriminator values should map to which union choices
80
+ * Handling various edge cases such as 'definitions', 'default', 'nullable' schemas, and more
81
+
82
+ I have chosen to implement the conversion algorithm in this class, rather than a function,
83
+ to make it easier to maintain state while recursively walking the provided CoreSchema.
84
+ """
85
+
86
+ def __init__(self, discriminator: str, definitions: dict[str, core_schema.CoreSchema]):
87
+ # `discriminator` should be the name of the field which will serve as the discriminator.
88
+ # It must be the python name of the field, and *not* the field's alias. Note that as of now,
89
+ # all members of a discriminated union _must_ use a field with the same name as the discriminator.
90
+ # This may change if/when we expose a way to manually specify the TaggedUnionSchema's choices.
91
+ self.discriminator = discriminator
92
+
93
+ # `definitions` should contain a mapping of schema ref to schema for all schemas which might
94
+ # be referenced by some choice
95
+ self.definitions = definitions
96
+
97
+ # `_discriminator_alias` will hold the value, if present, of the alias for the discriminator
98
+ #
99
+ # Note: following the v1 implementation, we currently disallow the use of different aliases
100
+ # for different choices. This is not a limitation of pydantic_core, but if we try to handle
101
+ # this, the inference logic gets complicated very quickly, and could result in confusing
102
+ # debugging challenges for users making subtle mistakes.
103
+ #
104
+ # Rather than trying to do the most powerful inference possible, I think we should eventually
105
+ # expose a way to more-manually control the way the TaggedUnionSchema is constructed through
106
+ # the use of a new type which would be placed as an Annotation on the Union type. This would
107
+ # provide the full flexibility/power of pydantic_core's TaggedUnionSchema where necessary for
108
+ # more complex cases, without over-complicating the inference logic for the common cases.
109
+ self._discriminator_alias: str | None = None
110
+
111
+ # `_should_be_nullable` indicates whether the converted union has `None` as an allowed value.
112
+ # If `None` is an acceptable value of the (possibly-wrapped) union, we ignore it while
113
+ # constructing the TaggedUnionSchema, but set the `_should_be_nullable` attribute to True.
114
+ # Once we have constructed the TaggedUnionSchema, if `_should_be_nullable` is True, we ensure
115
+ # that the final schema gets wrapped as a NullableSchema. This has the same semantics on the
116
+ # python side, but resolves the issue that `None` cannot correspond to any discriminator values.
117
+ self._should_be_nullable = False
118
+
119
+ # `_is_nullable` is used to track if the final produced schema will definitely be nullable;
120
+ # we set it to True if the input schema is wrapped in a nullable schema that we know will be preserved
121
+ # as an indication that, even if None is discovered as one of the union choices, we will not need to wrap
122
+ # the final value in another nullable schema.
123
+ #
124
+ # This is more complicated than just checking for the final outermost schema having type 'nullable' thanks
125
+ # to the possible presence of other wrapper schemas such as DefinitionsSchema, WithDefaultSchema, etc.
126
+ self._is_nullable = False
127
+
128
+ # `_choices_to_handle` serves as a stack of choices to add to the tagged union. Initially, choices
129
+ # from the union in the wrapped schema will be appended to this list, and the recursive choice-handling
130
+ # algorithm may add more choices to this stack as (nested) unions are encountered.
131
+ self._choices_to_handle: list[core_schema.CoreSchema] = []
132
+
133
+ # `_tagged_union_choices` is built during the call to `apply`, and will hold the choices to be included
134
+ # in the output TaggedUnionSchema that will replace the union from the input schema
135
+ self._tagged_union_choices: dict[Hashable, core_schema.CoreSchema] = {}
136
+
137
+ # `_used` is changed to True after applying the discriminator to prevent accidental reuse
138
+ self._used = False
139
+
140
+ def apply(self, schema: core_schema.CoreSchema) -> core_schema.CoreSchema:
141
+ """Return a new CoreSchema based on `schema` that uses a tagged-union with the discriminator provided
142
+ to this class.
143
+
144
+ Args:
145
+ schema: The input schema.
146
+
147
+ Returns:
148
+ The new core schema.
149
+
150
+ Raises:
151
+ TypeError:
152
+ - If `discriminator` is used with invalid union variant.
153
+ - If `discriminator` is used with `Union` type with one variant.
154
+ - If `discriminator` value mapped to multiple choices.
155
+ ValueError:
156
+ If the definition for ref is missing.
157
+ PydanticUserError:
158
+ - If a model in union doesn't have a discriminator field.
159
+ - If discriminator field has a non-string alias.
160
+ - If discriminator fields have different aliases.
161
+ - If discriminator field not of type `Literal`.
162
+ """
163
+ assert not self._used
164
+ schema = self._apply_to_root(schema)
165
+ if self._should_be_nullable and not self._is_nullable:
166
+ schema = core_schema.nullable_schema(schema)
167
+ self._used = True
168
+ return schema
169
+
170
+ def _apply_to_root(self, schema: core_schema.CoreSchema) -> core_schema.CoreSchema:
171
+ """This method handles the outer-most stage of recursion over the input schema:
172
+ unwrapping nullable or definitions schemas, and calling the `_handle_choice`
173
+ method iteratively on the choices extracted (recursively) from the possibly-wrapped union.
174
+ """
175
+ if schema['type'] == 'nullable':
176
+ self._is_nullable = True
177
+ wrapped = self._apply_to_root(schema['schema'])
178
+ nullable_wrapper = schema.copy()
179
+ nullable_wrapper['schema'] = wrapped
180
+ return nullable_wrapper
181
+
182
+ if schema['type'] == 'definitions':
183
+ wrapped = self._apply_to_root(schema['schema'])
184
+ definitions_wrapper = schema.copy()
185
+ definitions_wrapper['schema'] = wrapped
186
+ return definitions_wrapper
187
+
188
+ if schema['type'] == 'definition-ref':
189
+ schema_ref = schema['schema_ref']
190
+ if schema_ref not in self.definitions: # pragma: no cover
191
+ raise MissingDefinitionForUnionRef(schema_ref)
192
+
193
+ def_schema = self.definitions[schema_ref]
194
+ # If using a referenceable union as discriminated (e.g. `type Pet = Cat | Dog; field: Pet = Field(discriminator=...)`):
195
+ if def_schema['type'] == 'union':
196
+ schema = def_schema.copy()
197
+ schema.pop('ref')
198
+
199
+ if schema['type'] != 'union':
200
+ # If the schema is not a union, it probably means it just had a single member and
201
+ # was flattened by pydantic_core.
202
+ # However, it still may make sense to apply the discriminator to this schema,
203
+ # as a way to get discriminated-union-style error messages, so we allow this here.
204
+ schema = core_schema.union_schema([schema])
205
+
206
+ # Reverse the choices list before extending the stack so that they get handled in the order they occur
207
+ choices_schemas = [v[0] if isinstance(v, tuple) else v for v in schema['choices'][::-1]]
208
+ self._choices_to_handle.extend(choices_schemas)
209
+ while self._choices_to_handle:
210
+ choice = self._choices_to_handle.pop()
211
+ self._handle_choice(choice)
212
+
213
+ if self._discriminator_alias is not None and self._discriminator_alias != self.discriminator:
214
+ # * We need to annotate `discriminator` as a union here to handle both branches of this conditional
215
+ # * We need to annotate `discriminator` as list[list[str | int]] and not list[list[str]] due to the
216
+ # invariance of list, and because list[list[str | int]] is the type of the discriminator argument
217
+ # to tagged_union_schema below
218
+ # * See the docstring of pydantic_core.core_schema.tagged_union_schema for more details about how to
219
+ # interpret the value of the discriminator argument to tagged_union_schema. (The list[list[str]] here
220
+ # is the appropriate way to provide a list of fallback attributes to check for a discriminator value.)
221
+ discriminator: str | list[list[str | int]] = [[self.discriminator], [self._discriminator_alias]]
222
+ else:
223
+ discriminator = self.discriminator
224
+ return core_schema.tagged_union_schema(
225
+ choices=self._tagged_union_choices,
226
+ discriminator=discriminator,
227
+ custom_error_type=schema.get('custom_error_type'),
228
+ custom_error_message=schema.get('custom_error_message'),
229
+ custom_error_context=schema.get('custom_error_context'),
230
+ strict=False,
231
+ from_attributes=True,
232
+ ref=schema.get('ref'),
233
+ metadata=schema.get('metadata'),
234
+ serialization=schema.get('serialization'),
235
+ )
236
+
237
+ def _handle_choice(self, choice: core_schema.CoreSchema) -> None:
238
+ """This method handles the "middle" stage of recursion over the input schema.
239
+ Specifically, it is responsible for handling each choice of the outermost union
240
+ (and any "coalesced" choices obtained from inner unions).
241
+
242
+ Here, "handling" entails:
243
+ * Coalescing nested unions and compatible tagged-unions
244
+ * Tracking the presence of 'none' and 'nullable' schemas occurring as choices
245
+ * Validating that each allowed discriminator value maps to a unique choice
246
+ * Updating the _tagged_union_choices mapping that will ultimately be used to build the TaggedUnionSchema.
247
+ """
248
+ if choice['type'] == 'definition-ref':
249
+ if choice['schema_ref'] not in self.definitions:
250
+ raise MissingDefinitionForUnionRef(choice['schema_ref'])
251
+
252
+ if choice['type'] == 'none':
253
+ self._should_be_nullable = True
254
+ elif choice['type'] == 'definitions':
255
+ self._handle_choice(choice['schema'])
256
+ elif choice['type'] == 'nullable':
257
+ self._should_be_nullable = True
258
+ self._handle_choice(choice['schema']) # unwrap the nullable schema
259
+ elif choice['type'] == 'union':
260
+ # Reverse the choices list before extending the stack so that they get handled in the order they occur
261
+ choices_schemas = [v[0] if isinstance(v, tuple) else v for v in choice['choices'][::-1]]
262
+ self._choices_to_handle.extend(choices_schemas)
263
+ elif choice['type'] not in {
264
+ 'model',
265
+ 'typed-dict',
266
+ 'tagged-union',
267
+ 'lax-or-strict',
268
+ 'dataclass',
269
+ 'dataclass-args',
270
+ 'definition-ref',
271
+ } and not _core_utils.is_function_with_inner_schema(choice):
272
+ # We should eventually handle 'definition-ref' as well
273
+ err_str = f'The core schema type {choice["type"]!r} is not a valid discriminated union variant.'
274
+ if choice['type'] == 'list':
275
+ err_str += (
276
+ ' If you are making use of a list of union types, make sure the discriminator is applied to the '
277
+ 'union type and not the list (e.g. `list[Annotated[<T> | <U>, Field(discriminator=...)]]`).'
278
+ )
279
+ raise TypeError(err_str)
280
+ else:
281
+ if choice['type'] == 'tagged-union' and self._is_discriminator_shared(choice):
282
+ # In this case, this inner tagged-union is compatible with the outer tagged-union,
283
+ # and its choices can be coalesced into the outer TaggedUnionSchema.
284
+ subchoices = [x for x in choice['choices'].values() if not isinstance(x, (str, int))]
285
+ # Reverse the choices list before extending the stack so that they get handled in the order they occur
286
+ self._choices_to_handle.extend(subchoices[::-1])
287
+ return
288
+
289
+ inferred_discriminator_values = self._infer_discriminator_values_for_choice(choice, source_name=None)
290
+ self._set_unique_choice_for_values(choice, inferred_discriminator_values)
291
+
292
+ def _is_discriminator_shared(self, choice: core_schema.TaggedUnionSchema) -> bool:
293
+ """This method returns a boolean indicating whether the discriminator for the `choice`
294
+ is the same as that being used for the outermost tagged union. This is used to
295
+ determine whether this TaggedUnionSchema choice should be "coalesced" into the top level,
296
+ or whether it should be treated as a separate (nested) choice.
297
+ """
298
+ inner_discriminator = choice['discriminator']
299
+ return inner_discriminator == self.discriminator or (
300
+ isinstance(inner_discriminator, list)
301
+ and (self.discriminator in inner_discriminator or [self.discriminator] in inner_discriminator)
302
+ )
303
+
304
+ def _infer_discriminator_values_for_choice( # noqa C901
305
+ self, choice: core_schema.CoreSchema, source_name: str | None
306
+ ) -> list[str | int]:
307
+ """This function recurses over `choice`, extracting all discriminator values that should map to this choice.
308
+
309
+ `model_name` is accepted for the purpose of producing useful error messages.
310
+ """
311
+ if choice['type'] == 'definitions':
312
+ return self._infer_discriminator_values_for_choice(choice['schema'], source_name=source_name)
313
+
314
+ elif _core_utils.is_function_with_inner_schema(choice):
315
+ return self._infer_discriminator_values_for_choice(choice['schema'], source_name=source_name)
316
+
317
+ elif choice['type'] == 'lax-or-strict':
318
+ return sorted(
319
+ set(
320
+ self._infer_discriminator_values_for_choice(choice['lax_schema'], source_name=None)
321
+ + self._infer_discriminator_values_for_choice(choice['strict_schema'], source_name=None)
322
+ )
323
+ )
324
+
325
+ elif choice['type'] == 'tagged-union':
326
+ values: list[str | int] = []
327
+ # Ignore str/int "choices" since these are just references to other choices
328
+ subchoices = [x for x in choice['choices'].values() if not isinstance(x, (str, int))]
329
+ for subchoice in subchoices:
330
+ subchoice_values = self._infer_discriminator_values_for_choice(subchoice, source_name=None)
331
+ values.extend(subchoice_values)
332
+ return values
333
+
334
+ elif choice['type'] == 'union':
335
+ values = []
336
+ for subchoice in choice['choices']:
337
+ subchoice_schema = subchoice[0] if isinstance(subchoice, tuple) else subchoice
338
+ subchoice_values = self._infer_discriminator_values_for_choice(subchoice_schema, source_name=None)
339
+ values.extend(subchoice_values)
340
+ return values
341
+
342
+ elif choice['type'] == 'nullable':
343
+ self._should_be_nullable = True
344
+ return self._infer_discriminator_values_for_choice(choice['schema'], source_name=None)
345
+
346
+ elif choice['type'] == 'model':
347
+ return self._infer_discriminator_values_for_choice(choice['schema'], source_name=choice['cls'].__name__)
348
+
349
+ elif choice['type'] == 'dataclass':
350
+ return self._infer_discriminator_values_for_choice(choice['schema'], source_name=choice['cls'].__name__)
351
+
352
+ elif choice['type'] == 'model-fields':
353
+ return self._infer_discriminator_values_for_model_choice(choice, source_name=source_name)
354
+
355
+ elif choice['type'] == 'dataclass-args':
356
+ return self._infer_discriminator_values_for_dataclass_choice(choice, source_name=source_name)
357
+
358
+ elif choice['type'] == 'typed-dict':
359
+ return self._infer_discriminator_values_for_typed_dict_choice(choice, source_name=source_name)
360
+
361
+ elif choice['type'] == 'definition-ref':
362
+ schema_ref = choice['schema_ref']
363
+ if schema_ref not in self.definitions:
364
+ raise MissingDefinitionForUnionRef(schema_ref)
365
+ return self._infer_discriminator_values_for_choice(self.definitions[schema_ref], source_name=source_name)
366
+ else:
367
+ err_str = f'The core schema type {choice["type"]!r} is not a valid discriminated union variant.'
368
+ if choice['type'] == 'list':
369
+ err_str += (
370
+ ' If you are making use of a list of union types, make sure the discriminator is applied to the '
371
+ 'union type and not the list (e.g. `list[Annotated[<T> | <U>, Field(discriminator=...)]]`).'
372
+ )
373
+ raise TypeError(err_str)
374
+
375
+ def _infer_discriminator_values_for_typed_dict_choice(
376
+ self, choice: core_schema.TypedDictSchema, source_name: str | None = None
377
+ ) -> list[str | int]:
378
+ """This method just extracts the _infer_discriminator_values_for_choice logic specific to TypedDictSchema
379
+ for the sake of readability.
380
+ """
381
+ source = 'TypedDict' if source_name is None else f'TypedDict {source_name!r}'
382
+ field = choice['fields'].get(self.discriminator)
383
+ if field is None:
384
+ raise PydanticUserError(
385
+ f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field'
386
+ )
387
+ return self._infer_discriminator_values_for_field(field, source)
388
+
389
+ def _infer_discriminator_values_for_model_choice(
390
+ self, choice: core_schema.ModelFieldsSchema, source_name: str | None = None
391
+ ) -> list[str | int]:
392
+ source = 'ModelFields' if source_name is None else f'Model {source_name!r}'
393
+ field = choice['fields'].get(self.discriminator)
394
+ if field is None:
395
+ raise PydanticUserError(
396
+ f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field'
397
+ )
398
+ return self._infer_discriminator_values_for_field(field, source)
399
+
400
+ def _infer_discriminator_values_for_dataclass_choice(
401
+ self, choice: core_schema.DataclassArgsSchema, source_name: str | None = None
402
+ ) -> list[str | int]:
403
+ source = 'DataclassArgs' if source_name is None else f'Dataclass {source_name!r}'
404
+ for field in choice['fields']:
405
+ if field['name'] == self.discriminator:
406
+ break
407
+ else:
408
+ raise PydanticUserError(
409
+ f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field'
410
+ )
411
+ return self._infer_discriminator_values_for_field(field, source)
412
+
413
+ def _infer_discriminator_values_for_field(self, field: CoreSchemaField, source: str) -> list[str | int]:
414
+ if field['type'] == 'computed-field':
415
+ # This should never occur as a discriminator, as it is only relevant to serialization
416
+ return []
417
+ alias = field.get('validation_alias', self.discriminator)
418
+ if not isinstance(alias, str):
419
+ raise PydanticUserError(
420
+ f'Alias {alias!r} is not supported in a discriminated union', code='discriminator-alias-type'
421
+ )
422
+ if self._discriminator_alias is None:
423
+ self._discriminator_alias = alias
424
+ elif self._discriminator_alias != alias:
425
+ raise PydanticUserError(
426
+ f'Aliases for discriminator {self.discriminator!r} must be the same '
427
+ f'(got {alias}, {self._discriminator_alias})',
428
+ code='discriminator-alias',
429
+ )
430
+ return self._infer_discriminator_values_for_inner_schema(field['schema'], source)
431
+
432
+ def _infer_discriminator_values_for_inner_schema(
433
+ self, schema: core_schema.CoreSchema, source: str
434
+ ) -> list[str | int]:
435
+ """When inferring discriminator values for a field, we typically extract the expected values from a literal
436
+ schema. This function does that, but also handles nested unions and defaults.
437
+ """
438
+ if schema['type'] == 'literal':
439
+ return schema['expected']
440
+
441
+ elif schema['type'] == 'union':
442
+ # Generally when multiple values are allowed they should be placed in a single `Literal`, but
443
+ # we add this case to handle the situation where a field is annotated as a `Union` of `Literal`s.
444
+ # For example, this lets us handle `Union[Literal['key'], Union[Literal['Key'], Literal['KEY']]]`
445
+ values: list[Any] = []
446
+ for choice in schema['choices']:
447
+ choice_schema = choice[0] if isinstance(choice, tuple) else choice
448
+ choice_values = self._infer_discriminator_values_for_inner_schema(choice_schema, source)
449
+ values.extend(choice_values)
450
+ return values
451
+
452
+ elif schema['type'] == 'default':
453
+ # This will happen if the field has a default value; we ignore it while extracting the discriminator values
454
+ return self._infer_discriminator_values_for_inner_schema(schema['schema'], source)
455
+
456
+ elif schema['type'] == 'function-after':
457
+ # After validators don't affect the discriminator values
458
+ return self._infer_discriminator_values_for_inner_schema(schema['schema'], source)
459
+
460
+ elif schema['type'] == 'model' and schema.get('root_model'):
461
+ # Support RootModel[Literal[...]] as discriminator field type
462
+ return self._infer_discriminator_values_for_inner_schema(schema['schema'], source)
463
+
464
+ elif schema['type'] in {'function-before', 'function-wrap', 'function-plain'}:
465
+ validator_type = repr(schema['type'].split('-')[1])
466
+ raise PydanticUserError(
467
+ f'Cannot use a mode={validator_type} validator in the'
468
+ f' discriminator field {self.discriminator!r} of {source}',
469
+ code='discriminator-validator',
470
+ )
471
+
472
+ else:
473
+ raise PydanticUserError(
474
+ f'{source} needs field {self.discriminator!r} to be of type `Literal`',
475
+ code='discriminator-needs-literal',
476
+ )
477
+
478
+ def _set_unique_choice_for_values(self, choice: core_schema.CoreSchema, values: Sequence[str | int]) -> None:
479
+ """This method updates `self.tagged_union_choices` so that all provided (discriminator) `values` map to the
480
+ provided `choice`, validating that none of these values already map to another (different) choice.
481
+ """
482
+ for discriminator_value in values:
483
+ if discriminator_value in self._tagged_union_choices:
484
+ # It is okay if `value` is already in tagged_union_choices as long as it maps to the same value.
485
+ # Because tagged_union_choices may map values to other values, we need to walk the choices dict
486
+ # until we get to a "real" choice, and confirm that is equal to the one assigned.
487
+ existing_choice = self._tagged_union_choices[discriminator_value]
488
+ if existing_choice != choice:
489
+ raise TypeError(
490
+ f'Value {discriminator_value!r} for discriminator '
491
+ f'{self.discriminator!r} mapped to multiple choices'
492
+ )
493
+ else:
494
+ self._tagged_union_choices[discriminator_value] = choice
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_docs_extraction.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Utilities related to attribute docstring extraction."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ast
6
+ import inspect
7
+ import sys
8
+ import textwrap
9
+ from typing import Any
10
+
11
+
12
+ class DocstringVisitor(ast.NodeVisitor):
13
+ def __init__(self) -> None:
14
+ super().__init__()
15
+
16
+ self.target: str | None = None
17
+ self.attrs: dict[str, str] = {}
18
+ self.previous_node_type: type[ast.AST] | None = None
19
+
20
+ def visit(self, node: ast.AST) -> Any:
21
+ node_result = super().visit(node)
22
+ self.previous_node_type = type(node)
23
+ return node_result
24
+
25
+ def visit_AnnAssign(self, node: ast.AnnAssign) -> Any:
26
+ if isinstance(node.target, ast.Name):
27
+ self.target = node.target.id
28
+
29
+ def visit_Expr(self, node: ast.Expr) -> Any:
30
+ if (
31
+ isinstance(node.value, ast.Constant)
32
+ and isinstance(node.value.value, str)
33
+ and self.previous_node_type is ast.AnnAssign
34
+ ):
35
+ docstring = inspect.cleandoc(node.value.value)
36
+ if self.target:
37
+ self.attrs[self.target] = docstring
38
+ self.target = None
39
+
40
+
41
+ def _dedent_source_lines(source: list[str]) -> str:
42
+ # Required for nested class definitions, e.g. in a function block
43
+ dedent_source = textwrap.dedent(''.join(source))
44
+ if dedent_source.startswith((' ', '\t')):
45
+ # We are in the case where there's a dedented (usually multiline) string
46
+ # at a lower indentation level than the class itself. We wrap our class
47
+ # in a function as a workaround.
48
+ dedent_source = f'def dedent_workaround():\n{dedent_source}'
49
+ return dedent_source
50
+
51
+
52
+ def _extract_source_from_frame(cls: type[Any]) -> list[str] | None:
53
+ frame = inspect.currentframe()
54
+
55
+ while frame:
56
+ if inspect.getmodule(frame) is inspect.getmodule(cls):
57
+ lnum = frame.f_lineno
58
+ try:
59
+ lines, _ = inspect.findsource(frame)
60
+ except OSError: # pragma: no cover
61
+ # Source can't be retrieved (maybe because running in an interactive terminal),
62
+ # we don't want to error here.
63
+ pass
64
+ else:
65
+ block_lines = inspect.getblock(lines[lnum - 1 :])
66
+ dedent_source = _dedent_source_lines(block_lines)
67
+ try:
68
+ block_tree = ast.parse(dedent_source)
69
+ except SyntaxError:
70
+ pass
71
+ else:
72
+ stmt = block_tree.body[0]
73
+ if isinstance(stmt, ast.FunctionDef) and stmt.name == 'dedent_workaround':
74
+ # `_dedent_source_lines` wrapped the class around the workaround function
75
+ stmt = stmt.body[0]
76
+ if isinstance(stmt, ast.ClassDef) and stmt.name == cls.__name__:
77
+ return block_lines
78
+
79
+ frame = frame.f_back
80
+
81
+
82
+ def extract_docstrings_from_cls(cls: type[Any], use_inspect: bool = False) -> dict[str, str]:
83
+ """Map model attributes and their corresponding docstring.
84
+
85
+ Args:
86
+ cls: The class of the Pydantic model to inspect.
87
+ use_inspect: Whether to skip usage of frames to find the object and use
88
+ the `inspect` module instead.
89
+
90
+ Returns:
91
+ A mapping containing attribute names and their corresponding docstring.
92
+ """
93
+ if use_inspect or sys.version_info >= (3, 13):
94
+ # On Python < 3.13, `inspect.getsourcelines()` might not work as expected
95
+ # if two classes have the same name in the same source file.
96
+ # On Python 3.13+, it will use the new `__firstlineno__` class attribute,
97
+ # making it way more robust.
98
+ try:
99
+ source, _ = inspect.getsourcelines(cls)
100
+ except OSError: # pragma: no cover
101
+ return {}
102
+ else:
103
+ # TODO remove this implementation when we drop support for Python 3.12:
104
+ source = _extract_source_from_frame(cls)
105
+
106
+ if not source:
107
+ return {}
108
+
109
+ dedent_source = _dedent_source_lines(source)
110
+
111
+ visitor = DocstringVisitor()
112
+ visitor.visit(ast.parse(dedent_source))
113
+ return visitor.attrs
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_fields.py ADDED
@@ -0,0 +1,729 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Private logic related to fields (the `Field()` function and `FieldInfo` class), and arguments to `Annotated`."""
2
+
3
+ from __future__ import annotations as _annotations
4
+
5
+ import dataclasses
6
+ import warnings
7
+ from collections.abc import Mapping
8
+ from functools import cache
9
+ from inspect import Parameter, ismethoddescriptor
10
+ from re import Pattern
11
+ from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast
12
+
13
+ from pydantic_core import PydanticUndefined
14
+ from typing_extensions import TypeIs
15
+ from typing_inspection.introspection import AnnotationSource
16
+
17
+ from pydantic import PydanticDeprecatedSince211
18
+ from pydantic.errors import PydanticUserError
19
+
20
+ from ..aliases import AliasGenerator
21
+ from . import _generics, _typing_extra
22
+ from ._config import ConfigWrapper
23
+ from ._docs_extraction import extract_docstrings_from_cls
24
+ from ._import_utils import import_cached_base_model, import_cached_field_info
25
+ from ._internal_dataclass import slots_true
26
+ from ._namespace_utils import NsResolver
27
+ from ._repr import Representation
28
+ from ._utils import can_be_positional, get_first_not_none
29
+
30
+ if TYPE_CHECKING:
31
+ from annotated_types import BaseMetadata
32
+
33
+ from ..fields import FieldInfo
34
+ from ..main import BaseModel
35
+ from ._dataclasses import PydanticDataclass, StandardDataclass
36
+ from ._decorators import DecoratorInfos
37
+
38
+
39
+ class PydanticMetadata(Representation):
40
+ """Base class for annotation markers like `Strict`."""
41
+
42
+ __slots__ = ()
43
+
44
+
45
+ @dataclasses.dataclass(**slots_true) # TODO: make kw_only when we drop support for 3.9.
46
+ class PydanticExtraInfo:
47
+ # TODO: make use of PEP 747:
48
+ annotation: Any
49
+ complete: bool
50
+
51
+
52
+ def pydantic_general_metadata(**metadata: Any) -> BaseMetadata:
53
+ """Create a new `_PydanticGeneralMetadata` class with the given metadata.
54
+
55
+ Args:
56
+ **metadata: The metadata to add.
57
+
58
+ Returns:
59
+ The new `_PydanticGeneralMetadata` class.
60
+ """
61
+ return _general_metadata_cls()(metadata) # type: ignore
62
+
63
+
64
+ @cache
65
+ def _general_metadata_cls() -> type[BaseMetadata]:
66
+ """Do it this way to avoid importing `annotated_types` at import time."""
67
+ from annotated_types import BaseMetadata
68
+
69
+ class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata):
70
+ """Pydantic general metadata like `max_digits`."""
71
+
72
+ def __init__(self, metadata: Any):
73
+ self.__dict__ = metadata
74
+
75
+ return _PydanticGeneralMetadata # type: ignore
76
+
77
+
78
+ def _check_protected_namespaces(
79
+ protected_namespaces: tuple[str | Pattern[str], ...],
80
+ ann_name: str,
81
+ bases: tuple[type[Any], ...],
82
+ cls_name: str,
83
+ ) -> None:
84
+ BaseModel = import_cached_base_model()
85
+
86
+ for protected_namespace in protected_namespaces:
87
+ ns_violation = False
88
+ if isinstance(protected_namespace, Pattern):
89
+ ns_violation = protected_namespace.match(ann_name) is not None
90
+ elif isinstance(protected_namespace, str):
91
+ ns_violation = ann_name.startswith(protected_namespace)
92
+
93
+ if ns_violation:
94
+ for b in bases:
95
+ if hasattr(b, ann_name):
96
+ if not (issubclass(b, BaseModel) and ann_name in getattr(b, '__pydantic_fields__', {})):
97
+ raise ValueError(
98
+ f'Field {ann_name!r} conflicts with member {getattr(b, ann_name)}'
99
+ f' of protected namespace {protected_namespace!r}.'
100
+ )
101
+ else:
102
+ valid_namespaces: list[str] = []
103
+ for pn in protected_namespaces:
104
+ if isinstance(pn, Pattern):
105
+ if not pn.match(ann_name):
106
+ valid_namespaces.append(f're.compile({pn.pattern!r})')
107
+ else:
108
+ if not ann_name.startswith(pn):
109
+ valid_namespaces.append(f"'{pn}'")
110
+
111
+ valid_namespaces_str = f'({", ".join(valid_namespaces)}{",)" if len(valid_namespaces) == 1 else ")"}'
112
+
113
+ warnings.warn(
114
+ f'Field {ann_name!r} in {cls_name!r} conflicts with protected namespace {protected_namespace!r}.\n\n'
115
+ f"You may be able to solve this by setting the 'protected_namespaces' configuration to {valid_namespaces_str}.",
116
+ UserWarning,
117
+ stacklevel=5,
118
+ )
119
+
120
+
121
+ def _update_fields_from_docstrings(cls: type[Any], fields: dict[str, FieldInfo], use_inspect: bool = False) -> None:
122
+ fields_docs = extract_docstrings_from_cls(cls, use_inspect=use_inspect)
123
+ for ann_name, field_info in fields.items():
124
+ if field_info.description is None and ann_name in fields_docs:
125
+ field_info.description = fields_docs[ann_name]
126
+
127
+
128
+ def _apply_field_title_generator_to_field_info(
129
+ title_generator: Callable[[str, FieldInfo], str],
130
+ field_name: str,
131
+ field_info: FieldInfo,
132
+ ):
133
+ if field_info.title is None:
134
+ title = title_generator(field_name, field_info)
135
+ if not isinstance(title, str):
136
+ raise TypeError(f'field_title_generator {title_generator} must return str, not {title.__class__}')
137
+
138
+ field_info.title = title
139
+
140
+
141
+ def _apply_alias_generator_to_field_info(
142
+ alias_generator: Callable[[str], str] | AliasGenerator, field_name: str, field_info: FieldInfo
143
+ ):
144
+ """Apply an alias generator to aliases on a `FieldInfo` instance if appropriate.
145
+
146
+ Args:
147
+ alias_generator: A callable that takes a string and returns a string, or an `AliasGenerator` instance.
148
+ field_name: The name of the field from which to generate the alias.
149
+ field_info: The `FieldInfo` instance to which the alias generator is (maybe) applied.
150
+ """
151
+ # Apply an alias_generator if
152
+ # 1. An alias is not specified
153
+ # 2. An alias is specified, but the priority is <= 1
154
+ if (
155
+ field_info.alias_priority is None
156
+ or field_info.alias_priority <= 1
157
+ or field_info.alias is None
158
+ or field_info.validation_alias is None
159
+ or field_info.serialization_alias is None
160
+ ):
161
+ alias, validation_alias, serialization_alias = None, None, None
162
+
163
+ if isinstance(alias_generator, AliasGenerator):
164
+ alias, validation_alias, serialization_alias = alias_generator.generate_aliases(field_name)
165
+ elif callable(alias_generator):
166
+ alias = alias_generator(field_name)
167
+ if not isinstance(alias, str):
168
+ raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}')
169
+
170
+ # if priority is not set, we set to 1
171
+ # which supports the case where the alias_generator from a child class is used
172
+ # to generate an alias for a field in a parent class
173
+ if field_info.alias_priority is None or field_info.alias_priority <= 1:
174
+ field_info.alias_priority = 1
175
+
176
+ # if the priority is 1, then we set the aliases to the generated alias
177
+ if field_info.alias_priority == 1:
178
+ field_info.serialization_alias = get_first_not_none(serialization_alias, alias)
179
+ field_info.validation_alias = get_first_not_none(validation_alias, alias)
180
+ field_info.alias = alias
181
+
182
+ # if any of the aliases are not set, then we set them to the corresponding generated alias
183
+ if field_info.alias is None:
184
+ field_info.alias = alias
185
+ if field_info.serialization_alias is None:
186
+ field_info.serialization_alias = get_first_not_none(serialization_alias, alias)
187
+ if field_info.validation_alias is None:
188
+ field_info.validation_alias = get_first_not_none(validation_alias, alias)
189
+
190
+
191
+ def update_field_from_config(config_wrapper: ConfigWrapper, field_name: str, field_info: FieldInfo) -> None:
192
+ """Update the `FieldInfo` instance from the configuration set on the model it belongs to.
193
+
194
+ This will apply the title and alias generators from the configuration.
195
+
196
+ Args:
197
+ config_wrapper: The configuration from the model.
198
+ field_name: The field name the `FieldInfo` instance is attached to.
199
+ field_info: The `FieldInfo` instance to update.
200
+ """
201
+ field_title_generator = field_info.field_title_generator or config_wrapper.field_title_generator
202
+ if field_title_generator is not None:
203
+ _apply_field_title_generator_to_field_info(field_title_generator, field_name, field_info)
204
+ if config_wrapper.alias_generator is not None:
205
+ _apply_alias_generator_to_field_info(config_wrapper.alias_generator, field_name, field_info)
206
+
207
+
208
+ _deprecated_method_names = {'dict', 'json', 'copy', '_iter', '_copy_and_set_values', '_calculate_keys'}
209
+
210
+ _deprecated_classmethod_names = {
211
+ 'parse_obj',
212
+ 'parse_raw',
213
+ 'parse_file',
214
+ 'from_orm',
215
+ 'construct',
216
+ 'schema',
217
+ 'schema_json',
218
+ 'validate',
219
+ 'update_forward_refs',
220
+ '_get_value',
221
+ }
222
+
223
+
224
+ def collect_model_fields( # noqa: C901
225
+ cls: type[BaseModel],
226
+ config_wrapper: ConfigWrapper,
227
+ ns_resolver: NsResolver,
228
+ *,
229
+ typevars_map: Mapping[TypeVar, Any] | None = None,
230
+ ) -> tuple[dict[str, FieldInfo], PydanticExtraInfo | None, set[str]]:
231
+ """Collect the fields and class variables names of a nascent Pydantic model.
232
+
233
+ The fields collection process is *lenient*, meaning it won't error if string annotations
234
+ fail to evaluate. If this happens, the original annotation (and assigned value, if any)
235
+ is stored on the created `FieldInfo` instance.
236
+
237
+ The `rebuild_model_fields()` should be called at a later point (e.g. when rebuilding the model),
238
+ and will make use of these stored attributes.
239
+
240
+ Args:
241
+ cls: BaseModel or dataclass.
242
+ config_wrapper: The config wrapper instance.
243
+ ns_resolver: Namespace resolver to use when getting model annotations.
244
+ typevars_map: A dictionary mapping type variables to their concrete types.
245
+
246
+ Returns:
247
+ A three-tuple containing the model fields, the `PydanticExtraInfo` instance if the `__pydantic_extra__` annotation is set,
248
+ and class variables names.
249
+
250
+ Raises:
251
+ NameError:
252
+ - If there is a conflict between a field name and protected namespaces.
253
+ - If there is a field other than `root` in `RootModel`.
254
+ - If a field shadows an attribute in the parent model.
255
+ """
256
+ FieldInfo_ = import_cached_field_info()
257
+ BaseModel_ = import_cached_base_model()
258
+
259
+ bases = cls.__bases__
260
+ parent_fields_lookup: dict[str, FieldInfo] = {}
261
+ for base in reversed(bases):
262
+ if model_fields := getattr(base, '__pydantic_fields__', None):
263
+ parent_fields_lookup.update(model_fields)
264
+
265
+ type_hints = _typing_extra.get_model_type_hints(cls, ns_resolver=ns_resolver)
266
+
267
+ # `cls_annotations` is only used to determine if an annotation comes from a parent class
268
+ cls_annotations = _typing_extra.safe_get_annotations(cls)
269
+
270
+ fields: dict[str, FieldInfo] = {}
271
+
272
+ class_vars: set[str] = set()
273
+ for ann_name, (ann_type, evaluated) in type_hints.items():
274
+ if ann_name == 'model_config':
275
+ # We never want to treat `model_config` as a field
276
+ # Note: we may need to change this logic if/when we introduce a `BareModel` class with no
277
+ # protected namespaces (where `model_config` might be allowed as a field name)
278
+ continue
279
+
280
+ _check_protected_namespaces(
281
+ protected_namespaces=config_wrapper.protected_namespaces,
282
+ ann_name=ann_name,
283
+ bases=bases,
284
+ cls_name=cls.__name__,
285
+ )
286
+
287
+ if _typing_extra.is_classvar_annotation(ann_type):
288
+ class_vars.add(ann_name)
289
+ continue
290
+
291
+ assigned_value = getattr(cls, ann_name, PydanticUndefined)
292
+ if assigned_value is not PydanticUndefined and (
293
+ # One of the deprecated instance methods was used as a field name (e.g. `dict()`):
294
+ any(getattr(BaseModel_, depr_name, None) is assigned_value for depr_name in _deprecated_method_names)
295
+ # One of the deprecated class methods was used as a field name (e.g. `schema()`):
296
+ or (
297
+ hasattr(assigned_value, '__func__')
298
+ and any(
299
+ getattr(getattr(BaseModel_, depr_name, None), '__func__', None) is assigned_value.__func__ # pyright: ignore[reportAttributeAccessIssue]
300
+ for depr_name in _deprecated_classmethod_names
301
+ )
302
+ )
303
+ ):
304
+ # Then `assigned_value` would be the method, even though no default was specified:
305
+ assigned_value = PydanticUndefined
306
+
307
+ if not is_valid_field_name(ann_name):
308
+ continue
309
+ if cls.__pydantic_root_model__ and ann_name != 'root':
310
+ raise NameError(
311
+ f"Unexpected field with name {ann_name!r}; only 'root' is allowed as a field of a `RootModel`"
312
+ )
313
+
314
+ for base in bases:
315
+ if hasattr(base, ann_name):
316
+ if ann_name not in cls_annotations:
317
+ # Don't warn when a field exists in a parent class but has not been defined in the current class
318
+ continue
319
+
320
+ # when building a generic model with `MyModel[int]`, the generic_origin check makes sure we don't get
321
+ # "... shadows an attribute" warnings
322
+ generic_origin = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin')
323
+ if base is generic_origin:
324
+ # Don't warn when "shadowing" of attributes in parametrized generics
325
+ continue
326
+
327
+ dataclass_fields = {
328
+ field.name for field in (dataclasses.fields(base) if dataclasses.is_dataclass(base) else ())
329
+ }
330
+ if ann_name in dataclass_fields:
331
+ # Don't warn when inheriting stdlib dataclasses whose fields are "shadowed" by defaults being set
332
+ # on the class instance.
333
+ continue
334
+
335
+ warnings.warn(
336
+ f'Field name "{ann_name}" in "{cls.__qualname__}" shadows an attribute in parent '
337
+ f'"{base.__qualname__}"',
338
+ UserWarning,
339
+ stacklevel=4,
340
+ )
341
+
342
+ if assigned_value is PydanticUndefined: # no assignment, just a plain annotation
343
+ if ann_name in cls_annotations or ann_name not in parent_fields_lookup:
344
+ # field is either:
345
+ # - present in the current model's annotations (and *not* from parent classes)
346
+ # - not found on any base classes; this seems to be caused by fields not getting
347
+ # generated due to models not being fully defined while initializing recursive models.
348
+ # Nothing stops us from just creating a `FieldInfo` for this type hint, so we do this.
349
+ field_info = FieldInfo_.from_annotation(ann_type, _source=AnnotationSource.CLASS)
350
+ field_info._original_annotation = ann_type
351
+ if not evaluated:
352
+ field_info._complete = False
353
+ # Store the original annotation that should be used to rebuild
354
+ # the field info later:
355
+ else:
356
+ # The field was present on one of the (possibly multiple) base classes, we make a copy directly from it.
357
+ parent_field_info = parent_fields_lookup[ann_name]._copy()
358
+
359
+ # The only case where substituting the type variables is relevant (i.e. when `typevars_map` is not empty)
360
+ # is when a generic class is parameterized (e.g. `MyGenericModel[int, str]`), which creates a new class object
361
+ # (unlike the stdlib genercis that create a generic alias). In this case, we are guaranteed to only have to copy
362
+ # from the origin/parent model (e.g. `MyGenericModel`).
363
+ if typevars_map:
364
+ field_info = _recreate_field_info(
365
+ parent_field_info, ns_resolver=ns_resolver, typevars_map=typevars_map, lenient=True
366
+ )
367
+ else:
368
+ field_info = parent_field_info
369
+
370
+ else: # An assigned value is present (either the default value, or a `Field()` function)
371
+ if isinstance(assigned_value, FieldInfo_) and ismethoddescriptor(assigned_value.default):
372
+ # `assigned_value` was fetched using `getattr`, which triggers a call to `__get__`
373
+ # for descriptors, so we do the same if the `= field(default=...)` form is used.
374
+ # Note that we only do this for method descriptors for now, we might want to
375
+ # extend this to any descriptor in the future (by simply checking for
376
+ # `hasattr(assigned_value.default, '__get__')`).
377
+ default = assigned_value.default.__get__(None, cls)
378
+ assigned_value.default = default
379
+ assigned_value._attributes_set['default'] = default
380
+
381
+ field_info = FieldInfo_.from_annotated_attribute(ann_type, assigned_value, _source=AnnotationSource.CLASS)
382
+
383
+ # Store the original annotation and assignment value that could be used to rebuild the field info later.
384
+ field_info._original_assignment = assigned_value
385
+ field_info._original_annotation = ann_type
386
+ if not evaluated:
387
+ field_info._complete = False
388
+ elif 'final' in field_info._qualifiers and not field_info.is_required():
389
+ warnings.warn(
390
+ f'Annotation {ann_name!r} is marked as final and has a default value. Pydantic treats {ann_name!r} as a '
391
+ 'class variable, but it will be considered as a normal field in V3 to be aligned with dataclasses. If you '
392
+ f'still want {ann_name!r} to be considered as a class variable, annotate it as: `ClassVar[<type>] = <default>.`',
393
+ category=PydanticDeprecatedSince211,
394
+ # Incorrect when `create_model` is used, but the chance that final with a default is used is low in that case:
395
+ stacklevel=4,
396
+ )
397
+ class_vars.add(ann_name)
398
+ continue
399
+
400
+ # attributes which are fields are removed from the class namespace:
401
+ # 1. To match the behaviour of annotation-only fields
402
+ # 2. To avoid false positives in the NameError check above
403
+ try:
404
+ delattr(cls, ann_name)
405
+ except AttributeError:
406
+ pass # indicates the attribute was on a parent class
407
+
408
+ # Use cls.__dict__['__pydantic_decorators__'] instead of cls.__pydantic_decorators__
409
+ # to make sure the decorators have already been built for this exact class
410
+ decorators: DecoratorInfos = cls.__dict__['__pydantic_decorators__']
411
+ if ann_name in decorators.computed_fields:
412
+ raise TypeError(
413
+ f'Field {ann_name!r} of class {cls.__name__!r} overrides symbol of same name in a parent class. '
414
+ 'This override with a computed_field is incompatible.'
415
+ )
416
+ fields[ann_name] = field_info
417
+
418
+ if field_info._complete:
419
+ # If not complete, this will be called in `rebuild_model_fields()`:
420
+ update_field_from_config(config_wrapper, ann_name, field_info)
421
+
422
+ if config_wrapper.use_attribute_docstrings:
423
+ _update_fields_from_docstrings(cls, fields)
424
+
425
+ pydantic_extra_info: PydanticExtraInfo | None = None
426
+ if '__pydantic_extra__' in type_hints:
427
+ ann, complete = type_hints['__pydantic_extra__']
428
+ pydantic_extra_info = PydanticExtraInfo(
429
+ annotation=ann,
430
+ complete=complete,
431
+ )
432
+
433
+ return fields, pydantic_extra_info, class_vars
434
+
435
+
436
+ def rebuild_model_fields(
437
+ cls: type[BaseModel],
438
+ *,
439
+ config_wrapper: ConfigWrapper,
440
+ ns_resolver: NsResolver,
441
+ typevars_map: Mapping[TypeVar, Any],
442
+ ) -> tuple[dict[str, FieldInfo], PydanticExtraInfo | None]:
443
+ """Rebuild the (already present) model fields by trying to reevaluate annotations.
444
+
445
+ This function should be called whenever a model with incomplete fields is encountered.
446
+
447
+ Returns:
448
+ A two-tuple, the first element being the rebuilt fields, the second element being
449
+ the rebuild `PydanticExtraInfo` instance, if available.
450
+
451
+ Raises:
452
+ NameError: If one of the annotations failed to evaluate.
453
+
454
+ Note:
455
+ This function *doesn't* mutate the model fields in place, as it can be called during
456
+ schema generation, where you don't want to mutate other model's fields.
457
+ """
458
+ rebuilt_fields: dict[str, FieldInfo] = {}
459
+ with ns_resolver.push(cls):
460
+ for f_name, field_info in cls.__pydantic_fields__.items():
461
+ if field_info._complete:
462
+ rebuilt_fields[f_name] = field_info
463
+ else:
464
+ new_field = _recreate_field_info(
465
+ field_info, ns_resolver=ns_resolver, typevars_map=typevars_map, lenient=False
466
+ )
467
+ update_field_from_config(config_wrapper, f_name, new_field)
468
+ rebuilt_fields[f_name] = new_field
469
+
470
+ if cls.__pydantic_extra_info__ is not None and not cls.__pydantic_extra_info__.complete:
471
+ rebuilt_extra_info = PydanticExtraInfo(
472
+ annotation=_typing_extra.eval_type(
473
+ cls.__pydantic_extra_info__.annotation, *ns_resolver.types_namespace
474
+ ),
475
+ complete=True,
476
+ )
477
+ else:
478
+ rebuilt_extra_info = cls.__pydantic_extra_info__
479
+
480
+ return rebuilt_fields, rebuilt_extra_info
481
+
482
+
483
+ def _recreate_field_info(
484
+ field_info: FieldInfo,
485
+ ns_resolver: NsResolver,
486
+ typevars_map: Mapping[TypeVar, Any],
487
+ *,
488
+ lenient: bool,
489
+ ) -> FieldInfo:
490
+ FieldInfo_ = import_cached_field_info()
491
+
492
+ existing_desc = field_info.description
493
+ if lenient:
494
+ ann = _generics.replace_types(field_info._original_annotation, typevars_map)
495
+ ann, evaluated = _typing_extra.try_eval_type(
496
+ ann,
497
+ *ns_resolver.types_namespace,
498
+ )
499
+ else:
500
+ # Not the best pattern, maybe we could ship our own `eval_type()`,
501
+ # that would replace the type variables on the fly during evaluation.
502
+ ann = _typing_extra.eval_type(
503
+ field_info._original_annotation,
504
+ *ns_resolver.types_namespace,
505
+ )
506
+ ann = _generics.replace_types(ann, typevars_map)
507
+ ann = _typing_extra.eval_type(
508
+ ann,
509
+ *ns_resolver.types_namespace,
510
+ )
511
+ evaluated = True
512
+
513
+ if (assign := field_info._original_assignment) is PydanticUndefined:
514
+ new_field = FieldInfo_.from_annotation(ann, _source=AnnotationSource.CLASS)
515
+ else:
516
+ new_field = FieldInfo_.from_annotated_attribute(ann, assign, _source=AnnotationSource.CLASS)
517
+ new_field._original_assignment = assign
518
+ new_field._original_annotation = ann
519
+ # The description might come from the docstring if `use_attribute_docstrings` was `True`:
520
+ new_field.description = new_field.description if new_field.description is not None else existing_desc
521
+ if not evaluated:
522
+ new_field._complete = False
523
+
524
+ return new_field
525
+
526
+
527
+ def collect_dataclass_fields(
528
+ cls: type[StandardDataclass],
529
+ *,
530
+ config_wrapper: ConfigWrapper,
531
+ ns_resolver: NsResolver | None = None,
532
+ typevars_map: dict[Any, Any] | None = None,
533
+ ) -> dict[str, FieldInfo]:
534
+ """Collect the fields of a dataclass.
535
+
536
+ Args:
537
+ cls: dataclass.
538
+ config_wrapper: The config wrapper instance.
539
+ ns_resolver: Namespace resolver to use when getting dataclass annotations.
540
+ Defaults to an empty instance.
541
+ typevars_map: A dictionary mapping type variables to their concrete types.
542
+
543
+ Returns:
544
+ The dataclass fields.
545
+ """
546
+ FieldInfo_ = import_cached_field_info()
547
+
548
+ fields: dict[str, FieldInfo] = {}
549
+ ns_resolver = ns_resolver or NsResolver()
550
+ dataclass_fields = cls.__dataclass_fields__
551
+
552
+ # The logic here is similar to `_typing_extra.get_cls_type_hints`,
553
+ # although we do it manually as stdlib dataclasses already have annotations
554
+ # collected in each class:
555
+ for base in reversed(cls.__mro__):
556
+ if not dataclasses.is_dataclass(base):
557
+ continue
558
+
559
+ with ns_resolver.push(base):
560
+ for ann_name, dataclass_field in dataclass_fields.items():
561
+ base_anns = _typing_extra.safe_get_annotations(base)
562
+
563
+ if ann_name not in base_anns:
564
+ # `__dataclass_fields__`contains every field, even the ones from base classes.
565
+ # Only collect the ones defined on `base`.
566
+ continue
567
+
568
+ globalns, localns = ns_resolver.types_namespace
569
+ ann_type, evaluated = _typing_extra.try_eval_type(dataclass_field.type, globalns, localns)
570
+
571
+ if _typing_extra.is_classvar_annotation(ann_type):
572
+ continue
573
+
574
+ if (
575
+ not dataclass_field.init
576
+ and dataclass_field.default is dataclasses.MISSING
577
+ and dataclass_field.default_factory is dataclasses.MISSING
578
+ ):
579
+ # TODO: We should probably do something with this so that validate_assignment behaves properly
580
+ # Issue: https://github.com/pydantic/pydantic/issues/5470
581
+ continue
582
+
583
+ if isinstance(dataclass_field.default, FieldInfo_):
584
+ if dataclass_field.default.init_var:
585
+ if dataclass_field.default.init is False:
586
+ raise PydanticUserError(
587
+ f'Dataclass field {ann_name} has init=False and init_var=True, but these are mutually exclusive.',
588
+ code='clashing-init-and-init-var',
589
+ )
590
+
591
+ # TODO: same note as above re validate_assignment
592
+ continue
593
+ field_info = FieldInfo_.from_annotated_attribute(
594
+ ann_type, dataclass_field.default, _source=AnnotationSource.DATACLASS
595
+ )
596
+ field_info._original_assignment = dataclass_field.default
597
+ else:
598
+ field_info = FieldInfo_.from_annotated_attribute(
599
+ ann_type, dataclass_field, _source=AnnotationSource.DATACLASS
600
+ )
601
+ field_info._original_assignment = dataclass_field
602
+
603
+ if not evaluated:
604
+ field_info._complete = False
605
+ field_info._original_annotation = ann_type
606
+
607
+ fields[ann_name] = field_info
608
+ update_field_from_config(config_wrapper, ann_name, field_info)
609
+
610
+ if field_info.default is not PydanticUndefined and isinstance(
611
+ getattr(cls, ann_name, field_info), FieldInfo_
612
+ ):
613
+ # We need this to fix the default when the "default" from __dataclass_fields__ is a pydantic.FieldInfo
614
+ setattr(cls, ann_name, field_info.default)
615
+
616
+ if typevars_map:
617
+ for field in fields.values():
618
+ # We don't pass any ns, as `field.annotation`
619
+ # was already evaluated. TODO: is this method relevant?
620
+ # Can't we juste use `_generics.replace_types`?
621
+ field.apply_typevars_map(typevars_map)
622
+
623
+ if config_wrapper.use_attribute_docstrings:
624
+ _update_fields_from_docstrings(
625
+ cls,
626
+ fields,
627
+ # We can't rely on the (more reliable) frame inspection method
628
+ # for stdlib dataclasses:
629
+ use_inspect=not hasattr(cls, '__is_pydantic_dataclass__'),
630
+ )
631
+
632
+ return fields
633
+
634
+
635
+ def rebuild_dataclass_fields(
636
+ cls: type[PydanticDataclass],
637
+ *,
638
+ config_wrapper: ConfigWrapper,
639
+ ns_resolver: NsResolver,
640
+ typevars_map: Mapping[TypeVar, Any],
641
+ ) -> dict[str, FieldInfo]:
642
+ """Rebuild the (already present) dataclass fields by trying to reevaluate annotations.
643
+
644
+ This function should be called whenever a dataclass with incomplete fields is encountered.
645
+
646
+ Raises:
647
+ NameError: If one of the annotations failed to evaluate.
648
+
649
+ Note:
650
+ This function *doesn't* mutate the dataclass fields in place, as it can be called during
651
+ schema generation, where you don't want to mutate other dataclass's fields.
652
+ """
653
+ FieldInfo_ = import_cached_field_info()
654
+
655
+ rebuilt_fields: dict[str, FieldInfo] = {}
656
+ with ns_resolver.push(cls):
657
+ for f_name, field_info in cls.__pydantic_fields__.items():
658
+ if field_info._complete:
659
+ rebuilt_fields[f_name] = field_info
660
+ else:
661
+ existing_desc = field_info.description
662
+ ann = _typing_extra.eval_type(
663
+ field_info._original_annotation,
664
+ *ns_resolver.types_namespace,
665
+ )
666
+ ann = _generics.replace_types(ann, typevars_map)
667
+ new_field = FieldInfo_.from_annotated_attribute(
668
+ ann,
669
+ field_info._original_assignment,
670
+ _source=AnnotationSource.DATACLASS,
671
+ )
672
+
673
+ # The description might come from the docstring if `use_attribute_docstrings` was `True`:
674
+ new_field.description = new_field.description if new_field.description is not None else existing_desc
675
+ update_field_from_config(config_wrapper, f_name, new_field)
676
+ rebuilt_fields[f_name] = new_field
677
+
678
+ return rebuilt_fields
679
+
680
+
681
+ def is_valid_field_name(name: str) -> bool:
682
+ return not name.startswith('_')
683
+
684
+
685
+ def is_valid_privateattr_name(name: str) -> bool:
686
+ return name.startswith('_') and not name.startswith('__')
687
+
688
+
689
+ def takes_validated_data_argument(
690
+ default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any],
691
+ ) -> TypeIs[Callable[[dict[str, Any]], Any]]:
692
+ """Whether the provided default factory callable has a validated data parameter."""
693
+ try:
694
+ sig = _typing_extra.signature_no_eval(default_factory)
695
+ except (ValueError, TypeError):
696
+ # `inspect.signature` might not be able to infer a signature, e.g. with C objects.
697
+ # In this case, we assume no data argument is present:
698
+ return False
699
+
700
+ parameters = list(sig.parameters.values())
701
+
702
+ return len(parameters) == 1 and can_be_positional(parameters[0]) and parameters[0].default is Parameter.empty
703
+
704
+
705
+ def resolve_default_value(
706
+ default: Any,
707
+ default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None,
708
+ *,
709
+ validated_data: dict[str, Any] | None = None,
710
+ call_default_factory: bool = False,
711
+ ) -> Any:
712
+ """Resolve the default value using either a static default or a default_factory."""
713
+ from ._utils import smart_deepcopy
714
+
715
+ if default_factory is None:
716
+ return smart_deepcopy(default)
717
+ if call_default_factory:
718
+ if takes_validated_data_argument(default_factory=default_factory):
719
+ fac = cast('Callable[[dict[str, Any]], Any]', default_factory)
720
+ if validated_data is None:
721
+ raise ValueError(
722
+ "The default factory requires the 'validated_data' argument, which was not provided when calling 'get_default()'."
723
+ )
724
+ return fac(validated_data)
725
+ else:
726
+ fac = cast('Callable[[], Any]', default_factory)
727
+ return fac()
728
+
729
+ return PydanticUndefined
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_forward_ref.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations as _annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Union
5
+
6
+
7
+ @dataclass
8
+ class PydanticRecursiveRef:
9
+ type_ref: str
10
+
11
+ __name__ = 'PydanticRecursiveRef'
12
+ __hash__ = object.__hash__
13
+
14
+ def __call__(self) -> None:
15
+ """Defining __call__ is necessary for the `typing` module to let you use an instance of
16
+ this class as the result of resolving a standard ForwardRef.
17
+ """
18
+
19
+ def __or__(self, other):
20
+ return Union[self, other] # type: ignore
21
+
22
+ def __ror__(self, other):
23
+ return Union[other, self] # type: ignore
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_generate_schema.py ADDED
The diff for this file is too large to render. See raw diff
 
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_generics.py ADDED
@@ -0,0 +1,530 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import operator
4
+ import sys
5
+ import types
6
+ import typing
7
+ from collections import ChainMap
8
+ from collections.abc import Iterator, Mapping
9
+ from contextlib import contextmanager
10
+ from contextvars import ContextVar
11
+ from functools import reduce
12
+ from itertools import zip_longest
13
+ from types import prepare_class
14
+ from typing import TYPE_CHECKING, Annotated, Any, TypedDict, TypeVar, cast
15
+ from weakref import WeakValueDictionary
16
+
17
+ import typing_extensions
18
+ from typing_inspection import typing_objects
19
+ from typing_inspection.introspection import is_union_origin
20
+
21
+ from . import _typing_extra
22
+ from ._core_utils import get_type_ref
23
+ from ._forward_ref import PydanticRecursiveRef
24
+ from ._utils import all_identical, is_model_class
25
+
26
+ if TYPE_CHECKING:
27
+ from ..main import BaseModel
28
+
29
+ GenericTypesCacheKey = tuple[Any, Any, tuple[Any, ...]]
30
+
31
+ # Note: We want to remove LimitedDict, but to do this, we'd need to improve the handling of generics caching.
32
+ # Right now, to handle recursive generics, we some types must remain cached for brief periods without references.
33
+ # By chaining the WeakValuesDict with a LimitedDict, we have a way to retain caching for all types with references,
34
+ # while also retaining a limited number of types even without references. This is generally enough to build
35
+ # specific recursive generic models without losing required items out of the cache.
36
+
37
+ KT = TypeVar('KT')
38
+ VT = TypeVar('VT')
39
+ _LIMITED_DICT_SIZE = 100
40
+
41
+
42
+ class LimitedDict(dict[KT, VT]):
43
+ def __init__(self, size_limit: int = _LIMITED_DICT_SIZE) -> None:
44
+ self.size_limit = size_limit
45
+ super().__init__()
46
+
47
+ def __setitem__(self, key: KT, value: VT, /) -> None:
48
+ super().__setitem__(key, value)
49
+ if len(self) > self.size_limit:
50
+ excess = len(self) - self.size_limit + self.size_limit // 10
51
+ to_remove = list(self.keys())[:excess]
52
+ for k in to_remove:
53
+ del self[k]
54
+
55
+
56
+ # weak dictionaries allow the dynamically created parametrized versions of generic models to get collected
57
+ # once they are no longer referenced by the caller.
58
+ GenericTypesCache = WeakValueDictionary[GenericTypesCacheKey, 'type[BaseModel]']
59
+
60
+ if TYPE_CHECKING:
61
+
62
+ class DeepChainMap(ChainMap[KT, VT]): # type: ignore
63
+ ...
64
+
65
+ else:
66
+
67
+ class DeepChainMap(ChainMap):
68
+ """Variant of ChainMap that allows direct updates to inner scopes.
69
+
70
+ Taken from https://docs.python.org/3/library/collections.html#collections.ChainMap,
71
+ with some light modifications for this use case.
72
+ """
73
+
74
+ def clear(self) -> None:
75
+ for mapping in self.maps:
76
+ mapping.clear()
77
+
78
+ def __setitem__(self, key: KT, value: VT) -> None:
79
+ for mapping in self.maps:
80
+ mapping[key] = value
81
+
82
+ def __delitem__(self, key: KT) -> None:
83
+ hit = False
84
+ for mapping in self.maps:
85
+ if key in mapping:
86
+ del mapping[key]
87
+ hit = True
88
+ if not hit:
89
+ raise KeyError(key)
90
+
91
+
92
+ # Despite the fact that LimitedDict _seems_ no longer necessary, I'm very nervous to actually remove it
93
+ # and discover later on that we need to re-add all this infrastructure...
94
+ # _GENERIC_TYPES_CACHE = DeepChainMap(GenericTypesCache(), LimitedDict())
95
+
96
+ _GENERIC_TYPES_CACHE = GenericTypesCache()
97
+
98
+
99
+ class PydanticGenericMetadata(TypedDict):
100
+ origin: type[BaseModel] | None # analogous to typing._GenericAlias.__origin__
101
+ args: tuple[Any, ...] # analogous to typing._GenericAlias.__args__
102
+ parameters: tuple[TypeVar, ...] # analogous to typing.Generic.__parameters__
103
+
104
+
105
+ def create_generic_submodel(
106
+ model_name: str, origin: type[BaseModel], args: tuple[Any, ...], params: tuple[Any, ...]
107
+ ) -> type[BaseModel]:
108
+ """Dynamically create a submodel of a provided (generic) BaseModel.
109
+
110
+ This is used when producing concrete parametrizations of generic models. This function
111
+ only *creates* the new subclass; the schema/validators/serialization must be updated to
112
+ reflect a concrete parametrization elsewhere.
113
+
114
+ Args:
115
+ model_name: The name of the newly created model.
116
+ origin: The base class for the new model to inherit from.
117
+ args: A tuple of generic metadata arguments.
118
+ params: A tuple of generic metadata parameters.
119
+
120
+ Returns:
121
+ The created submodel.
122
+ """
123
+ namespace: dict[str, Any] = {'__module__': origin.__module__}
124
+ bases = (origin,)
125
+ meta, ns, kwds = prepare_class(model_name, bases)
126
+ namespace.update(ns)
127
+ created_model = meta(
128
+ model_name,
129
+ bases,
130
+ namespace,
131
+ __pydantic_generic_metadata__={
132
+ 'origin': origin,
133
+ 'args': args,
134
+ 'parameters': params,
135
+ },
136
+ __pydantic_reset_parent_namespace__=False,
137
+ **kwds,
138
+ )
139
+
140
+ model_module, called_globally = _get_caller_frame_info(depth=3)
141
+ if called_globally: # create global reference and therefore allow pickling
142
+ object_by_reference = None
143
+ reference_name = model_name
144
+ reference_module_globals = sys.modules[created_model.__module__].__dict__
145
+ while object_by_reference is not created_model:
146
+ object_by_reference = reference_module_globals.setdefault(reference_name, created_model)
147
+ reference_name += '_'
148
+
149
+ return created_model
150
+
151
+
152
+ def _get_caller_frame_info(depth: int = 2) -> tuple[str | None, bool]:
153
+ """Used inside a function to check whether it was called globally.
154
+
155
+ Args:
156
+ depth: The depth to get the frame.
157
+
158
+ Returns:
159
+ A tuple contains `module_name` and `called_globally`.
160
+
161
+ Raises:
162
+ RuntimeError: If the function is not called inside a function.
163
+ """
164
+ try:
165
+ previous_caller_frame = sys._getframe(depth)
166
+ except ValueError as e:
167
+ raise RuntimeError('This function must be used inside another function') from e
168
+ except AttributeError: # sys module does not have _getframe function, so there's nothing we can do about it
169
+ return None, False
170
+ frame_globals = previous_caller_frame.f_globals
171
+ return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals
172
+
173
+
174
+ DictValues: type[Any] = {}.values().__class__
175
+
176
+
177
+ def iter_contained_typevars(v: Any) -> Iterator[TypeVar]:
178
+ """Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found.
179
+
180
+ This is inspired as an alternative to directly accessing the `__parameters__` attribute of a GenericAlias,
181
+ since __parameters__ of (nested) generic BaseModel subclasses won't show up in that list.
182
+ """
183
+ if isinstance(v, TypeVar):
184
+ yield v
185
+ elif is_model_class(v):
186
+ yield from v.__pydantic_generic_metadata__['parameters']
187
+ elif isinstance(v, (DictValues, list)):
188
+ for var in v:
189
+ yield from iter_contained_typevars(var)
190
+ else:
191
+ args = get_args(v)
192
+ for arg in args:
193
+ yield from iter_contained_typevars(arg)
194
+
195
+
196
+ def get_args(v: Any) -> Any:
197
+ pydantic_generic_metadata: PydanticGenericMetadata | None = getattr(v, '__pydantic_generic_metadata__', None)
198
+ if pydantic_generic_metadata:
199
+ return pydantic_generic_metadata.get('args')
200
+ return typing_extensions.get_args(v)
201
+
202
+
203
+ def get_origin(v: Any) -> Any:
204
+ pydantic_generic_metadata: PydanticGenericMetadata | None = getattr(v, '__pydantic_generic_metadata__', None)
205
+ if pydantic_generic_metadata:
206
+ return pydantic_generic_metadata.get('origin')
207
+ return typing_extensions.get_origin(v)
208
+
209
+
210
+ def get_standard_typevars_map(cls: Any) -> dict[TypeVar, Any] | None:
211
+ """Package a generic type's typevars and parametrization (if present) into a dictionary compatible with the
212
+ `replace_types` function. Specifically, this works with standard typing generics and typing._GenericAlias.
213
+ """
214
+ origin = get_origin(cls)
215
+ if origin is None:
216
+ return None
217
+ if not hasattr(origin, '__parameters__'):
218
+ return None
219
+
220
+ # In this case, we know that cls is a _GenericAlias, and origin is the generic type
221
+ # So it is safe to access cls.__args__ and origin.__parameters__
222
+ args: tuple[Any, ...] = cls.__args__ # type: ignore
223
+ parameters: tuple[TypeVar, ...] = origin.__parameters__
224
+ return dict(zip(parameters, args))
225
+
226
+
227
+ def get_model_typevars_map(cls: type[BaseModel]) -> dict[TypeVar, Any]:
228
+ """Package a generic BaseModel's typevars and concrete parametrization (if present) into a dictionary compatible
229
+ with the `replace_types` function.
230
+
231
+ Since BaseModel.__class_getitem__ does not produce a typing._GenericAlias, and the BaseModel generic info is
232
+ stored in the __pydantic_generic_metadata__ attribute, we need special handling here.
233
+ """
234
+ # TODO: This could be unified with `get_standard_typevars_map` if we stored the generic metadata
235
+ # in the __origin__, __args__, and __parameters__ attributes of the model.
236
+ generic_metadata = cls.__pydantic_generic_metadata__
237
+ origin = generic_metadata['origin']
238
+ args = generic_metadata['args']
239
+ if not args:
240
+ # No need to go into `iter_contained_typevars`:
241
+ return {}
242
+ return dict(zip(iter_contained_typevars(origin), args))
243
+
244
+
245
+ def replace_types(type_: Any, type_map: Mapping[TypeVar, Any] | None) -> Any:
246
+ """Return type with all occurrences of `type_map` keys recursively replaced with their values.
247
+
248
+ Args:
249
+ type_: The class or generic alias.
250
+ type_map: Mapping from `TypeVar` instance to concrete types.
251
+
252
+ Returns:
253
+ A new type representing the basic structure of `type_` with all
254
+ `typevar_map` keys recursively replaced.
255
+
256
+ Example:
257
+ ```python
258
+ from typing import Union
259
+
260
+ from pydantic._internal._generics import replace_types
261
+
262
+ replace_types(tuple[str, Union[list[str], float]], {str: int})
263
+ #> tuple[int, Union[list[int], float]]
264
+ ```
265
+ """
266
+ if not type_map:
267
+ return type_
268
+
269
+ type_args = get_args(type_)
270
+ origin_type = get_origin(type_)
271
+
272
+ if typing_objects.is_annotated(origin_type):
273
+ annotated_type, *annotations = type_args
274
+ annotated_type = replace_types(annotated_type, type_map)
275
+ # TODO remove parentheses when we drop support for Python 3.10:
276
+ return Annotated[(annotated_type, *annotations)]
277
+
278
+ # Having type args is a good indicator that this is a typing special form
279
+ # instance or a generic alias of some sort.
280
+ if type_args:
281
+ resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args)
282
+ if all_identical(type_args, resolved_type_args):
283
+ # If all arguments are the same, there is no need to modify the
284
+ # type or create a new object at all
285
+ return type_
286
+
287
+ if (
288
+ origin_type is not None
289
+ and isinstance(type_, _typing_extra.typing_base)
290
+ and not isinstance(origin_type, _typing_extra.typing_base)
291
+ and getattr(type_, '_name', None) is not None
292
+ ):
293
+ # In python < 3.9 generic aliases don't exist so any of these like `list`,
294
+ # `type` or `collections.abc.Callable` need to be translated.
295
+ # See: https://www.python.org/dev/peps/pep-0585
296
+ origin_type = getattr(typing, type_._name)
297
+ assert origin_type is not None
298
+
299
+ if is_union_origin(origin_type):
300
+ if any(typing_objects.is_any(arg) for arg in resolved_type_args):
301
+ # `Any | T` ~ `Any`:
302
+ resolved_type_args = (Any,)
303
+ # `Never | T` ~ `T`:
304
+ resolved_type_args = tuple(
305
+ arg
306
+ for arg in resolved_type_args
307
+ if not (typing_objects.is_noreturn(arg) or typing_objects.is_never(arg))
308
+ )
309
+
310
+ # PEP-604 syntax (e.g. `list | str`) is represented with a types.UnionType object that does not
311
+ # implement `__getitem__()`. In Python 3.14+, `typing.Union` and `types.UnionType` are the same,
312
+ # and we instead rely on `typing.Union` as it implicitly converts string annotations to `ForwardRef`
313
+ # instances (this is to avoid type errors as per https://github.com/python/cpython/pull/105366).
314
+ # TODO remove type ignore comment when we drop support for Python 3.9 (https://github.com/microsoft/pyright/issues/11241):
315
+ if (3, 10) <= sys.version_info < (3, 14) and origin_type is types.UnionType: # pyright: ignore[reportAttributeAccessIssue]
316
+ return reduce(operator.or_, resolved_type_args)
317
+ # NotRequired[T] and Required[T] don't support tuple type resolved_type_args, hence the condition below
318
+ return origin_type[resolved_type_args[0] if len(resolved_type_args) == 1 else resolved_type_args]
319
+
320
+ # We handle pydantic generic models separately as they don't have the same
321
+ # semantics as "typing" classes or generic aliases
322
+
323
+ if not origin_type and is_model_class(type_):
324
+ parameters = type_.__pydantic_generic_metadata__['parameters']
325
+ if not parameters:
326
+ return type_
327
+ resolved_type_args = tuple(replace_types(t, type_map) for t in parameters)
328
+ if all_identical(parameters, resolved_type_args):
329
+ return type_
330
+ return type_[resolved_type_args]
331
+
332
+ # Handle special case for typehints that can have lists as arguments.
333
+ # `typing.Callable[[int, str], int]` is an example for this.
334
+ if isinstance(type_, list):
335
+ resolved_list = [replace_types(element, type_map) for element in type_]
336
+ if all_identical(type_, resolved_list):
337
+ return type_
338
+ return resolved_list
339
+
340
+ # If all else fails, we try to resolve the type directly and otherwise just
341
+ # return the input with no modifications.
342
+ return type_map.get(type_, type_)
343
+
344
+
345
+ def map_generic_model_arguments(cls: type[BaseModel], args: tuple[Any, ...]) -> dict[TypeVar, Any]:
346
+ """Return a mapping between the parameters of a generic model and the provided arguments during parameterization.
347
+
348
+ Raises:
349
+ TypeError: If the number of arguments does not match the parameters (i.e. if providing too few or too many arguments).
350
+
351
+ Example:
352
+ ```python {test="skip" lint="skip"}
353
+ class Model[T, U, V = int](BaseModel): ...
354
+
355
+ map_generic_model_arguments(Model, (str, bytes))
356
+ #> {T: str, U: bytes, V: int}
357
+
358
+ map_generic_model_arguments(Model, (str,))
359
+ #> TypeError: Too few arguments for <class '__main__.Model'>; actual 1, expected at least 2
360
+
361
+ map_generic_model_arguments(Model, (str, bytes, int, complex))
362
+ #> TypeError: Too many arguments for <class '__main__.Model'>; actual 4, expected 3
363
+ ```
364
+
365
+ Note:
366
+ This function is analogous to the private `typing._check_generic_specialization` function.
367
+ """
368
+ parameters = cls.__pydantic_generic_metadata__['parameters']
369
+ expected_len = len(parameters)
370
+ typevars_map: dict[TypeVar, Any] = {}
371
+
372
+ _missing = object()
373
+ for parameter, argument in zip_longest(parameters, args, fillvalue=_missing):
374
+ if parameter is _missing:
375
+ raise TypeError(f'Too many arguments for {cls}; actual {len(args)}, expected {expected_len}')
376
+
377
+ if argument is _missing:
378
+ param = cast(TypeVar, parameter)
379
+ try:
380
+ has_default = param.has_default() # pyright: ignore[reportAttributeAccessIssue]
381
+ except AttributeError:
382
+ # Happens if using `typing.TypeVar` (and not `typing_extensions`) on Python < 3.13.
383
+ has_default = False
384
+ if has_default:
385
+ # The default might refer to other type parameters. For an example, see:
386
+ # https://typing.python.org/en/latest/spec/generics.html#type-parameters-as-parameters-to-generics
387
+ typevars_map[param] = replace_types(param.__default__, typevars_map) # pyright: ignore[reportAttributeAccessIssue]
388
+ else:
389
+ expected_len -= sum(hasattr(p, 'has_default') and p.has_default() for p in parameters) # pyright: ignore[reportAttributeAccessIssue]
390
+ raise TypeError(f'Too few arguments for {cls}; actual {len(args)}, expected at least {expected_len}')
391
+ else:
392
+ param = cast(TypeVar, parameter)
393
+ typevars_map[param] = argument
394
+
395
+ return typevars_map
396
+
397
+
398
+ _generic_recursion_cache: ContextVar[set[str] | None] = ContextVar('_generic_recursion_cache', default=None)
399
+
400
+
401
+ @contextmanager
402
+ def generic_recursion_self_type(
403
+ origin: type[BaseModel], args: tuple[Any, ...]
404
+ ) -> Iterator[PydanticRecursiveRef | None]:
405
+ """This contextmanager should be placed around the recursive calls used to build a generic type,
406
+ and accept as arguments the generic origin type and the type arguments being passed to it.
407
+
408
+ If the same origin and arguments are observed twice, it implies that a self-reference placeholder
409
+ can be used while building the core schema, and will produce a schema_ref that will be valid in the
410
+ final parent schema.
411
+ """
412
+ previously_seen_type_refs = _generic_recursion_cache.get()
413
+ if previously_seen_type_refs is None:
414
+ previously_seen_type_refs = set()
415
+ token = _generic_recursion_cache.set(previously_seen_type_refs)
416
+ else:
417
+ token = None
418
+
419
+ try:
420
+ type_ref = get_type_ref(origin, args_override=args)
421
+ if type_ref in previously_seen_type_refs:
422
+ self_type = PydanticRecursiveRef(type_ref=type_ref)
423
+ yield self_type
424
+ else:
425
+ previously_seen_type_refs.add(type_ref)
426
+ yield
427
+ previously_seen_type_refs.remove(type_ref)
428
+ finally:
429
+ if token:
430
+ _generic_recursion_cache.reset(token)
431
+
432
+
433
+ def recursively_defined_type_refs() -> set[str]:
434
+ visited = _generic_recursion_cache.get()
435
+ if not visited:
436
+ return set() # not in a generic recursion, so there are no types
437
+
438
+ return visited.copy() # don't allow modifications
439
+
440
+
441
+ def get_cached_generic_type_early(parent: type[BaseModel], typevar_values: Any) -> type[BaseModel] | None:
442
+ """The use of a two-stage cache lookup approach was necessary to have the highest performance possible for
443
+ repeated calls to `__class_getitem__` on generic types (which may happen in tighter loops during runtime),
444
+ while still ensuring that certain alternative parametrizations ultimately resolve to the same type.
445
+
446
+ As a concrete example, this approach was necessary to make Model[List[T]][int] equal to Model[List[int]].
447
+ The approach could be modified to not use two different cache keys at different points, but the
448
+ _early_cache_key is optimized to be as quick to compute as possible (for repeated-access speed), and the
449
+ _late_cache_key is optimized to be as "correct" as possible, so that two types that will ultimately be the
450
+ same after resolving the type arguments will always produce cache hits.
451
+
452
+ If we wanted to move to only using a single cache key per type, we would either need to always use the
453
+ slower/more computationally intensive logic associated with _late_cache_key, or would need to accept
454
+ that Model[List[T]][int] is a different type than Model[List[T]][int]. Because we rely on subclass relationships
455
+ during validation, I think it is worthwhile to ensure that types that are functionally equivalent are actually
456
+ equal.
457
+ """
458
+ return _GENERIC_TYPES_CACHE.get(_early_cache_key(parent, typevar_values))
459
+
460
+
461
+ def get_cached_generic_type_late(
462
+ parent: type[BaseModel], typevar_values: Any, origin: type[BaseModel], args: tuple[Any, ...]
463
+ ) -> type[BaseModel] | None:
464
+ """See the docstring of `get_cached_generic_type_early` for more information about the two-stage cache lookup."""
465
+ cached = _GENERIC_TYPES_CACHE.get(_late_cache_key(origin, args, typevar_values))
466
+ if cached is not None:
467
+ set_cached_generic_type(parent, typevar_values, cached, origin, args)
468
+ return cached
469
+
470
+
471
+ def set_cached_generic_type(
472
+ parent: type[BaseModel],
473
+ typevar_values: tuple[Any, ...],
474
+ type_: type[BaseModel],
475
+ origin: type[BaseModel] | None = None,
476
+ args: tuple[Any, ...] | None = None,
477
+ ) -> None:
478
+ """See the docstring of `get_cached_generic_type_early` for more information about why items are cached with
479
+ two different keys.
480
+ """
481
+ _GENERIC_TYPES_CACHE[_early_cache_key(parent, typevar_values)] = type_
482
+ if len(typevar_values) == 1:
483
+ _GENERIC_TYPES_CACHE[_early_cache_key(parent, typevar_values[0])] = type_
484
+ if origin and args:
485
+ _GENERIC_TYPES_CACHE[_late_cache_key(origin, args, typevar_values)] = type_
486
+
487
+
488
+ def _union_orderings_key(typevar_values: Any) -> Any:
489
+ """This is intended to help differentiate between Union types with the same arguments in different order.
490
+
491
+ Thanks to caching internal to the `typing` module, it is not possible to distinguish between
492
+ List[Union[int, float]] and List[Union[float, int]] (and similarly for other "parent" origins besides List)
493
+ because `typing` considers Union[int, float] to be equal to Union[float, int].
494
+
495
+ However, you _can_ distinguish between (top-level) Union[int, float] vs. Union[float, int].
496
+ Because we parse items as the first Union type that is successful, we get slightly more consistent behavior
497
+ if we make an effort to distinguish the ordering of items in a union. It would be best if we could _always_
498
+ get the exact-correct order of items in the union, but that would require a change to the `typing` module itself.
499
+ (See https://github.com/python/cpython/issues/86483 for reference.)
500
+ """
501
+ if isinstance(typevar_values, tuple):
502
+ return tuple(_union_orderings_key(value) for value in typevar_values)
503
+ elif typing_objects.is_union(typing_extensions.get_origin(typevar_values)):
504
+ return get_args(typevar_values)
505
+ else:
506
+ return ()
507
+
508
+
509
+ def _early_cache_key(cls: type[BaseModel], typevar_values: Any) -> GenericTypesCacheKey:
510
+ """This is intended for minimal computational overhead during lookups of cached types.
511
+
512
+ Note that this is overly simplistic, and it's possible that two different cls/typevar_values
513
+ inputs would ultimately result in the same type being created in BaseModel.__class_getitem__.
514
+ To handle this, we have a fallback _late_cache_key that is checked later if the _early_cache_key
515
+ lookup fails, and should result in a cache hit _precisely_ when the inputs to __class_getitem__
516
+ would result in the same type.
517
+ """
518
+ return cls, typevar_values, _union_orderings_key(typevar_values)
519
+
520
+
521
+ def _late_cache_key(origin: type[BaseModel], args: tuple[Any, ...], typevar_values: Any) -> GenericTypesCacheKey:
522
+ """This is intended for use later in the process of creating a new type, when we have more information
523
+ about the exact args that will be passed. If it turns out that a different set of inputs to
524
+ __class_getitem__ resulted in the same inputs to the generic type creation process, we can still
525
+ return the cached type, and update the cache with the _early_cache_key as well.
526
+ """
527
+ # The _union_orderings_key is placed at the start here to ensure there cannot be a collision with an
528
+ # _early_cache_key, as that function will always produce a BaseModel subclass as the first item in the key,
529
+ # whereas this function will always produce a tuple as the first item in the key.
530
+ return _union_orderings_key(typevar_values), origin, args
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_git.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Git utilities, adopted from mypy's git utilities (https://github.com/python/mypy/blob/master/mypy/git.py)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+
9
+ def is_git_repo(dir: Path) -> bool:
10
+ """Is the given directory version-controlled with git?"""
11
+ return dir.joinpath('.git').exists()
12
+
13
+
14
+ def have_git() -> bool: # pragma: no cover
15
+ """Can we run the git executable?"""
16
+ try:
17
+ subprocess.check_output(['git', '--help'])
18
+ return True
19
+ except subprocess.CalledProcessError:
20
+ return False
21
+ except OSError:
22
+ return False
23
+
24
+
25
+ def git_revision(dir: Path) -> str:
26
+ """Get the SHA-1 of the HEAD of a git repository."""
27
+ return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=dir).decode('utf-8').strip()
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_import_utils.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from functools import cache
2
+ from typing import TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from pydantic import BaseModel
6
+ from pydantic.fields import FieldInfo
7
+
8
+
9
+ @cache
10
+ def import_cached_base_model() -> type['BaseModel']:
11
+ from pydantic import BaseModel
12
+
13
+ return BaseModel
14
+
15
+
16
+ @cache
17
+ def import_cached_field_info() -> type['FieldInfo']:
18
+ from pydantic.fields import FieldInfo
19
+
20
+ return FieldInfo
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_internal_dataclass.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import sys
2
+
3
+ # `slots` is available on Python >= 3.10
4
+ if sys.version_info >= (3, 10):
5
+ slots_true = {'slots': True}
6
+ else:
7
+ slots_true = {}
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_known_annotated_metadata.py ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections import defaultdict
4
+ from collections.abc import Iterable
5
+ from copy import copy
6
+ from functools import lru_cache, partial
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ from pydantic_core import CoreSchema, PydanticCustomError, ValidationError, to_jsonable_python
10
+ from pydantic_core import core_schema as cs
11
+
12
+ from ._fields import PydanticMetadata
13
+ from ._import_utils import import_cached_field_info
14
+
15
+ if TYPE_CHECKING:
16
+ pass
17
+
18
+ STRICT = {'strict'}
19
+ FAIL_FAST = {'fail_fast'}
20
+ LENGTH_CONSTRAINTS = {'min_length', 'max_length'}
21
+ INEQUALITY = {'le', 'ge', 'lt', 'gt'}
22
+ NUMERIC_CONSTRAINTS = {'multiple_of', *INEQUALITY}
23
+ ALLOW_INF_NAN = {'allow_inf_nan'}
24
+
25
+ STR_CONSTRAINTS = {
26
+ *LENGTH_CONSTRAINTS,
27
+ *STRICT,
28
+ 'strip_whitespace',
29
+ 'to_lower',
30
+ 'to_upper',
31
+ 'pattern',
32
+ 'coerce_numbers_to_str',
33
+ 'ascii_only',
34
+ }
35
+ BYTES_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT}
36
+
37
+ LIST_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST}
38
+ TUPLE_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST}
39
+ SET_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST}
40
+ DICT_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT}
41
+ GENERATOR_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT}
42
+ SEQUENCE_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *FAIL_FAST}
43
+
44
+ FLOAT_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *ALLOW_INF_NAN, *STRICT}
45
+ DECIMAL_CONSTRAINTS = {'max_digits', 'decimal_places', *FLOAT_CONSTRAINTS}
46
+ INT_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *ALLOW_INF_NAN, *STRICT}
47
+ BOOL_CONSTRAINTS = STRICT
48
+ UUID_CONSTRAINTS = STRICT
49
+
50
+ DATE_TIME_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT}
51
+ TIMEDELTA_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT}
52
+ TIME_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT}
53
+ LAX_OR_STRICT_CONSTRAINTS = STRICT
54
+ ENUM_CONSTRAINTS = STRICT
55
+ COMPLEX_CONSTRAINTS = STRICT
56
+
57
+ UNION_CONSTRAINTS = {'union_mode'}
58
+ URL_CONSTRAINTS = {
59
+ 'max_length',
60
+ 'allowed_schemes',
61
+ 'host_required',
62
+ 'default_host',
63
+ 'default_port',
64
+ 'default_path',
65
+ }
66
+
67
+ TEXT_SCHEMA_TYPES = ('str', 'bytes', 'url', 'multi-host-url')
68
+ SEQUENCE_SCHEMA_TYPES = ('list', 'tuple', 'set', 'frozenset', 'generator', *TEXT_SCHEMA_TYPES)
69
+ NUMERIC_SCHEMA_TYPES = ('float', 'int', 'date', 'time', 'timedelta', 'datetime')
70
+
71
+ CONSTRAINTS_TO_ALLOWED_SCHEMAS: dict[str, set[str]] = defaultdict(set)
72
+
73
+ constraint_schema_pairings: list[tuple[set[str], tuple[str, ...]]] = [
74
+ (STR_CONSTRAINTS, TEXT_SCHEMA_TYPES),
75
+ (BYTES_CONSTRAINTS, ('bytes',)),
76
+ (LIST_CONSTRAINTS, ('list',)),
77
+ (TUPLE_CONSTRAINTS, ('tuple',)),
78
+ (SET_CONSTRAINTS, ('set', 'frozenset')),
79
+ (DICT_CONSTRAINTS, ('dict',)),
80
+ (GENERATOR_CONSTRAINTS, ('generator',)),
81
+ (FLOAT_CONSTRAINTS, ('float',)),
82
+ (INT_CONSTRAINTS, ('int',)),
83
+ (DATE_TIME_CONSTRAINTS, ('date', 'time', 'datetime', 'timedelta')),
84
+ # TODO: this is a bit redundant, we could probably avoid some of these
85
+ (STRICT, (*TEXT_SCHEMA_TYPES, *SEQUENCE_SCHEMA_TYPES, *NUMERIC_SCHEMA_TYPES, 'typed-dict', 'model')),
86
+ (UNION_CONSTRAINTS, ('union',)),
87
+ (URL_CONSTRAINTS, ('url', 'multi-host-url')),
88
+ (BOOL_CONSTRAINTS, ('bool',)),
89
+ (UUID_CONSTRAINTS, ('uuid',)),
90
+ (LAX_OR_STRICT_CONSTRAINTS, ('lax-or-strict',)),
91
+ (ENUM_CONSTRAINTS, ('enum',)),
92
+ (DECIMAL_CONSTRAINTS, ('decimal',)),
93
+ (COMPLEX_CONSTRAINTS, ('complex',)),
94
+ ]
95
+
96
+ for constraints, schemas in constraint_schema_pairings:
97
+ for c in constraints:
98
+ CONSTRAINTS_TO_ALLOWED_SCHEMAS[c].update(schemas)
99
+
100
+
101
+ def as_jsonable_value(v: Any) -> Any:
102
+ if type(v) not in (int, str, float, bytes, bool, type(None)):
103
+ return to_jsonable_python(v)
104
+ return v
105
+
106
+
107
+ def expand_grouped_metadata(annotations: Iterable[Any]) -> Iterable[Any]:
108
+ """Expand the annotations.
109
+
110
+ Args:
111
+ annotations: An iterable of annotations.
112
+
113
+ Returns:
114
+ An iterable of expanded annotations.
115
+
116
+ Example:
117
+ ```python
118
+ from annotated_types import Ge, Len
119
+
120
+ from pydantic._internal._known_annotated_metadata import expand_grouped_metadata
121
+
122
+ print(list(expand_grouped_metadata([Ge(4), Len(5)])))
123
+ #> [Ge(ge=4), MinLen(min_length=5)]
124
+ ```
125
+ """
126
+ import annotated_types as at
127
+
128
+ FieldInfo = import_cached_field_info()
129
+
130
+ for annotation in annotations:
131
+ if isinstance(annotation, at.GroupedMetadata):
132
+ yield from annotation
133
+ elif isinstance(annotation, FieldInfo):
134
+ yield from annotation.metadata
135
+ # this is a bit problematic in that it results in duplicate metadata
136
+ # all of our "consumers" can handle it, but it is not ideal
137
+ # we probably should split up FieldInfo into:
138
+ # - annotated types metadata
139
+ # - individual metadata known only to Pydantic
140
+ annotation = copy(annotation)
141
+ annotation.metadata = []
142
+ yield annotation
143
+ else:
144
+ yield annotation
145
+
146
+
147
+ @lru_cache
148
+ def _get_at_to_constraint_map() -> dict[type, str]:
149
+ """Return a mapping of annotated types to constraints.
150
+
151
+ Normally, we would define a mapping like this in the module scope, but we can't do that
152
+ because we don't permit module level imports of `annotated_types`, in an attempt to speed up
153
+ the import time of `pydantic`. We still only want to have this dictionary defined in one place,
154
+ so we use this function to cache the result.
155
+ """
156
+ import annotated_types as at
157
+
158
+ return {
159
+ at.Gt: 'gt',
160
+ at.Ge: 'ge',
161
+ at.Lt: 'lt',
162
+ at.Le: 'le',
163
+ at.MultipleOf: 'multiple_of',
164
+ at.MinLen: 'min_length',
165
+ at.MaxLen: 'max_length',
166
+ }
167
+
168
+
169
+ def apply_known_metadata(annotation: Any, schema: CoreSchema) -> CoreSchema | None: # noqa: C901
170
+ """Apply `annotation` to `schema` if it is an annotation we know about (Gt, Le, etc.).
171
+ Otherwise return `None`.
172
+
173
+ This does not handle all known annotations. If / when it does, it can always
174
+ return a CoreSchema and return the unmodified schema if the annotation should be ignored.
175
+
176
+ Assumes that GroupedMetadata has already been expanded via `expand_grouped_metadata`.
177
+
178
+ Args:
179
+ annotation: The annotation.
180
+ schema: The schema.
181
+
182
+ Returns:
183
+ An updated schema with annotation if it is an annotation we know about, `None` otherwise.
184
+
185
+ Raises:
186
+ RuntimeError: If a constraint can't be applied to a specific schema type.
187
+ ValueError: If an unknown constraint is encountered.
188
+ """
189
+ import annotated_types as at
190
+
191
+ from ._validators import NUMERIC_VALIDATOR_LOOKUP, forbid_inf_nan_check
192
+
193
+ schema = schema.copy()
194
+ schema_update, other_metadata = collect_known_metadata([annotation])
195
+ schema_type = schema['type']
196
+
197
+ chain_schema_constraints: set[str] = {
198
+ 'pattern',
199
+ 'strip_whitespace',
200
+ 'to_lower',
201
+ 'to_upper',
202
+ 'coerce_numbers_to_str',
203
+ 'ascii_only',
204
+ }
205
+ chain_schema_steps: list[CoreSchema] = []
206
+
207
+ for constraint, value in schema_update.items():
208
+ if constraint not in CONSTRAINTS_TO_ALLOWED_SCHEMAS:
209
+ raise ValueError(f'Unknown constraint {constraint}')
210
+ allowed_schemas = CONSTRAINTS_TO_ALLOWED_SCHEMAS[constraint]
211
+
212
+ # if it becomes necessary to handle more than one constraint
213
+ # in this recursive case with function-after or function-wrap, we should refactor
214
+ # this is a bit challenging because we sometimes want to apply constraints to the inner schema,
215
+ # whereas other times we want to wrap the existing schema with a new one that enforces a new constraint.
216
+ if schema_type in {'function-before', 'function-wrap', 'function-after'} and constraint == 'strict':
217
+ schema['schema'] = apply_known_metadata(annotation, schema['schema']) # type: ignore # schema is function schema
218
+ return schema
219
+
220
+ # if we're allowed to apply constraint directly to the schema, like le to int, do that
221
+ if schema_type in allowed_schemas:
222
+ if constraint == 'union_mode' and schema_type == 'union':
223
+ schema['mode'] = value # type: ignore # schema is UnionSchema
224
+ else:
225
+ schema[constraint] = value
226
+ continue
227
+
228
+ # else, apply a function after validator to the schema to enforce the corresponding constraint
229
+ if constraint in chain_schema_constraints:
230
+
231
+ def _apply_constraint_with_incompatibility_info(
232
+ value: Any, handler: cs.ValidatorFunctionWrapHandler
233
+ ) -> Any:
234
+ try:
235
+ x = handler(value)
236
+ except ValidationError as ve:
237
+ # if the error is about the type, it's likely that the constraint is incompatible the type of the field
238
+ # for example, the following invalid schema wouldn't be caught during schema build, but rather at this point
239
+ # with a cryptic 'string_type' error coming from the string validator,
240
+ # that we'd rather express as a constraint incompatibility error (TypeError)
241
+ # Annotated[list[int], Field(pattern='abc')]
242
+ if 'type' in ve.errors()[0]['type']:
243
+ raise TypeError(
244
+ f"Unable to apply constraint '{constraint}' to supplied value {value} for schema of type '{schema_type}'" # noqa: B023
245
+ )
246
+ raise ve
247
+ return x
248
+
249
+ chain_schema_steps.append(
250
+ cs.no_info_wrap_validator_function(
251
+ _apply_constraint_with_incompatibility_info, cs.str_schema(**{constraint: value})
252
+ )
253
+ )
254
+ elif constraint in NUMERIC_VALIDATOR_LOOKUP:
255
+ if constraint in LENGTH_CONSTRAINTS:
256
+ inner_schema = schema
257
+ while inner_schema['type'] in {'function-before', 'function-wrap', 'function-after'}:
258
+ inner_schema = inner_schema['schema'] # type: ignore
259
+ inner_schema_type = inner_schema['type']
260
+ if inner_schema_type == 'list' or (
261
+ inner_schema_type == 'json-or-python' and inner_schema['json_schema']['type'] == 'list' # type: ignore
262
+ ):
263
+ js_constraint_key = 'minItems' if constraint == 'min_length' else 'maxItems'
264
+ else:
265
+ js_constraint_key = 'minLength' if constraint == 'min_length' else 'maxLength'
266
+ else:
267
+ js_constraint_key = constraint
268
+
269
+ schema = cs.no_info_after_validator_function(
270
+ partial(NUMERIC_VALIDATOR_LOOKUP[constraint], **{constraint: value}), schema
271
+ )
272
+ metadata = schema.get('metadata', {})
273
+ if (existing_json_schema_updates := metadata.get('pydantic_js_updates')) is not None:
274
+ metadata['pydantic_js_updates'] = {
275
+ **existing_json_schema_updates,
276
+ **{js_constraint_key: as_jsonable_value(value)},
277
+ }
278
+ else:
279
+ metadata['pydantic_js_updates'] = {js_constraint_key: as_jsonable_value(value)}
280
+ schema['metadata'] = metadata
281
+ elif constraint == 'allow_inf_nan' and value is False:
282
+ schema = cs.no_info_after_validator_function(
283
+ forbid_inf_nan_check,
284
+ schema,
285
+ )
286
+ else:
287
+ # It's rare that we'd get here, but it's possible if we add a new constraint and forget to handle it
288
+ # Most constraint errors are caught at runtime during attempted application
289
+ raise RuntimeError(f"Unable to apply constraint '{constraint}' to schema of type '{schema_type}'")
290
+
291
+ for annotation in other_metadata:
292
+ if (annotation_type := type(annotation)) in (at_to_constraint_map := _get_at_to_constraint_map()):
293
+ constraint = at_to_constraint_map[annotation_type]
294
+ validator = NUMERIC_VALIDATOR_LOOKUP.get(constraint)
295
+ if validator is None:
296
+ raise ValueError(f'Unknown constraint {constraint}')
297
+ schema = cs.no_info_after_validator_function(
298
+ partial(validator, {constraint: getattr(annotation, constraint)}), schema
299
+ )
300
+ continue
301
+ elif isinstance(annotation, (at.Predicate, at.Not)):
302
+ predicate_name = f'{annotation.func.__qualname__!r} ' if hasattr(annotation.func, '__qualname__') else ''
303
+
304
+ # Note: B023 is ignored because even though we iterate over `other_metadata`, it is guaranteed
305
+ # to be of length 1. `apply_known_metadata()` is called from `GenerateSchema`, where annotations
306
+ # were already expanded via `expand_grouped_metadata()`. Confusing, but this falls into the annotations
307
+ # refactor.
308
+ if isinstance(annotation, at.Predicate):
309
+
310
+ def val_func(v: Any) -> Any:
311
+ predicate_satisfied = annotation.func(v) # noqa: B023
312
+ if not predicate_satisfied:
313
+ raise PydanticCustomError(
314
+ 'predicate_failed',
315
+ f'Predicate {predicate_name}failed', # pyright: ignore[reportArgumentType] # noqa: B023
316
+ )
317
+ return v
318
+
319
+ else:
320
+
321
+ def val_func(v: Any) -> Any:
322
+ predicate_satisfied = annotation.func(v) # noqa: B023
323
+ if predicate_satisfied:
324
+ raise PydanticCustomError(
325
+ 'not_operation_failed',
326
+ f'Not of {predicate_name}failed', # pyright: ignore[reportArgumentType] # noqa: B023
327
+ )
328
+ return v
329
+
330
+ schema = cs.no_info_after_validator_function(val_func, schema)
331
+ else:
332
+ # ignore any other unknown metadata
333
+ return None
334
+
335
+ if chain_schema_steps:
336
+ chain_schema_steps = [schema] + chain_schema_steps
337
+ return cs.chain_schema(chain_schema_steps)
338
+
339
+ return schema
340
+
341
+
342
+ def collect_known_metadata(annotations: Iterable[Any]) -> tuple[dict[str, Any], list[Any]]:
343
+ """Split `annotations` into known metadata and unknown annotations.
344
+
345
+ Args:
346
+ annotations: An iterable of annotations.
347
+
348
+ Returns:
349
+ A tuple contains a dict of known metadata and a list of unknown annotations.
350
+
351
+ Example:
352
+ ```python
353
+ from annotated_types import Gt, Len
354
+
355
+ from pydantic._internal._known_annotated_metadata import collect_known_metadata
356
+
357
+ print(collect_known_metadata([Gt(1), Len(42), ...]))
358
+ #> ({'gt': 1, 'min_length': 42}, [Ellipsis])
359
+ ```
360
+ """
361
+ annotations = expand_grouped_metadata(annotations)
362
+
363
+ res: dict[str, Any] = {}
364
+ remaining: list[Any] = []
365
+
366
+ for annotation in annotations:
367
+ # isinstance(annotation, PydanticMetadata) also covers ._fields:_PydanticGeneralMetadata
368
+ if isinstance(annotation, PydanticMetadata):
369
+ res.update(annotation.__dict__)
370
+ # we don't use dataclasses.asdict because that recursively calls asdict on the field values
371
+ elif (annotation_type := type(annotation)) in (at_to_constraint_map := _get_at_to_constraint_map()):
372
+ constraint = at_to_constraint_map[annotation_type]
373
+ res[constraint] = getattr(annotation, constraint)
374
+ elif isinstance(annotation, type) and issubclass(annotation, PydanticMetadata):
375
+ # also support PydanticMetadata classes being used without initialisation,
376
+ # e.g. `Annotated[int, Strict]` as well as `Annotated[int, Strict()]`
377
+ res.update({k: v for k, v in vars(annotation).items() if not k.startswith('_')})
378
+ else:
379
+ remaining.append(annotation)
380
+ # Nones can sneak in but pydantic-core will reject them
381
+ # it'd be nice to clean things up so we don't put in None (we probably don't _need_ to, it was just easier)
382
+ # but this is simple enough to kick that can down the road
383
+ res = {k: v for k, v in res.items() if v is not None}
384
+ return res, remaining
385
+
386
+
387
+ def check_metadata(metadata: dict[str, Any], allowed: Iterable[str], source_type: Any) -> None:
388
+ """A small utility function to validate that the given metadata can be applied to the target.
389
+ More than saving lines of code, this gives us a consistent error message for all of our internal implementations.
390
+
391
+ Args:
392
+ metadata: A dict of metadata.
393
+ allowed: An iterable of allowed metadata.
394
+ source_type: The source type.
395
+
396
+ Raises:
397
+ TypeError: If there is metadatas that can't be applied on source type.
398
+ """
399
+ unknown = metadata.keys() - set(allowed)
400
+ if unknown:
401
+ raise TypeError(
402
+ f'The following constraints cannot be applied to {source_type!r}: {", ".join([f"{k!r}" for k in unknown])}'
403
+ )
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_mock_val_ser.py ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterator, Mapping
4
+ from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, TypeVar, Union
5
+
6
+ from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator
7
+
8
+ from ..errors import PydanticErrorCodes, PydanticUserError
9
+ from ..plugin._schema_validator import PluggableSchemaValidator
10
+
11
+ if TYPE_CHECKING:
12
+ from ..dataclasses import PydanticDataclass
13
+ from ..main import BaseModel
14
+ from ..type_adapter import TypeAdapter
15
+
16
+
17
+ ValSer = TypeVar('ValSer', bound=Union[SchemaValidator, PluggableSchemaValidator, SchemaSerializer])
18
+ T = TypeVar('T')
19
+
20
+
21
+ class MockCoreSchema(Mapping[str, Any]):
22
+ """Mocker for `pydantic_core.CoreSchema` which optionally attempts to
23
+ rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails.
24
+ """
25
+
26
+ __slots__ = '_error_message', '_code', '_attempt_rebuild', '_built_memo'
27
+
28
+ def __init__(
29
+ self,
30
+ error_message: str,
31
+ *,
32
+ code: PydanticErrorCodes,
33
+ attempt_rebuild: Callable[[], CoreSchema | None] | None = None,
34
+ ) -> None:
35
+ self._error_message = error_message
36
+ self._code: PydanticErrorCodes = code
37
+ self._attempt_rebuild = attempt_rebuild
38
+ self._built_memo: CoreSchema | None = None
39
+
40
+ def __getitem__(self, key: str) -> Any:
41
+ return self._get_built().__getitem__(key)
42
+
43
+ def __len__(self) -> int:
44
+ return self._get_built().__len__()
45
+
46
+ def __iter__(self) -> Iterator[str]:
47
+ return self._get_built().__iter__()
48
+
49
+ def _get_built(self) -> CoreSchema:
50
+ if self._built_memo is not None:
51
+ return self._built_memo
52
+
53
+ if self._attempt_rebuild:
54
+ schema = self._attempt_rebuild()
55
+ if schema is not None:
56
+ self._built_memo = schema
57
+ return schema
58
+ raise PydanticUserError(self._error_message, code=self._code)
59
+
60
+ def rebuild(self) -> CoreSchema | None:
61
+ self._built_memo = None
62
+ if self._attempt_rebuild:
63
+ schema = self._attempt_rebuild()
64
+ if schema is not None:
65
+ return schema
66
+ else:
67
+ raise PydanticUserError(self._error_message, code=self._code)
68
+ return None
69
+
70
+
71
+ class MockValSer(Generic[ValSer]):
72
+ """Mocker for `pydantic_core.SchemaValidator` or `pydantic_core.SchemaSerializer` which optionally attempts to
73
+ rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails.
74
+ """
75
+
76
+ __slots__ = '_error_message', '_code', '_val_or_ser', '_attempt_rebuild'
77
+
78
+ def __init__(
79
+ self,
80
+ error_message: str,
81
+ *,
82
+ code: PydanticErrorCodes,
83
+ val_or_ser: Literal['validator', 'serializer'],
84
+ attempt_rebuild: Callable[[], ValSer | None] | None = None,
85
+ ) -> None:
86
+ self._error_message = error_message
87
+ self._val_or_ser = SchemaValidator if val_or_ser == 'validator' else SchemaSerializer
88
+ self._code: PydanticErrorCodes = code
89
+ self._attempt_rebuild = attempt_rebuild
90
+
91
+ def __getattr__(self, item: str) -> None:
92
+ __tracebackhide__ = True
93
+ if self._attempt_rebuild:
94
+ val_ser = self._attempt_rebuild()
95
+ if val_ser is not None:
96
+ return getattr(val_ser, item)
97
+
98
+ # raise an AttributeError if `item` doesn't exist
99
+ getattr(self._val_or_ser, item)
100
+ raise PydanticUserError(self._error_message, code=self._code)
101
+
102
+ def rebuild(self) -> ValSer | None:
103
+ if self._attempt_rebuild:
104
+ val_ser = self._attempt_rebuild()
105
+ if val_ser is not None:
106
+ return val_ser
107
+ else:
108
+ raise PydanticUserError(self._error_message, code=self._code)
109
+ return None
110
+
111
+
112
+ def set_type_adapter_mocks(adapter: TypeAdapter) -> None:
113
+ """Set `core_schema`, `validator` and `serializer` to mock core types on a type adapter instance.
114
+
115
+ Args:
116
+ adapter: The type adapter instance to set the mocks on
117
+ """
118
+ type_repr = str(adapter._type)
119
+ undefined_type_error_message = (
120
+ f'`TypeAdapter[{type_repr}]` is not fully defined; you should define `{type_repr}` and all referenced types,'
121
+ f' then call `.rebuild()` on the instance.'
122
+ )
123
+
124
+ def attempt_rebuild_fn(attr_fn: Callable[[TypeAdapter], T]) -> Callable[[], T | None]:
125
+ def handler() -> T | None:
126
+ if adapter.rebuild(raise_errors=False, _parent_namespace_depth=5) is not False:
127
+ return attr_fn(adapter)
128
+ return None
129
+
130
+ return handler
131
+
132
+ adapter.core_schema = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue]
133
+ undefined_type_error_message,
134
+ code='class-not-fully-defined',
135
+ attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.core_schema),
136
+ )
137
+ adapter.validator = MockValSer( # pyright: ignore[reportAttributeAccessIssue]
138
+ undefined_type_error_message,
139
+ code='class-not-fully-defined',
140
+ val_or_ser='validator',
141
+ attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.validator),
142
+ )
143
+ adapter.serializer = MockValSer( # pyright: ignore[reportAttributeAccessIssue]
144
+ undefined_type_error_message,
145
+ code='class-not-fully-defined',
146
+ val_or_ser='serializer',
147
+ attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.serializer),
148
+ )
149
+
150
+
151
+ def set_model_mocks(cls: type[BaseModel], undefined_name: str = 'all referenced types') -> None:
152
+ """Set `__pydantic_core_schema__`, `__pydantic_validator__` and `__pydantic_serializer__` to mock core types on a model.
153
+
154
+ Args:
155
+ cls: The model class to set the mocks on
156
+ undefined_name: Name of the undefined thing, used in error messages
157
+ """
158
+ undefined_type_error_message = (
159
+ f'`{cls.__name__}` is not fully defined; you should define {undefined_name},'
160
+ f' then call `{cls.__name__}.model_rebuild()`.'
161
+ )
162
+
163
+ def attempt_rebuild_fn(attr_fn: Callable[[type[BaseModel]], T]) -> Callable[[], T | None]:
164
+ def handler() -> T | None:
165
+ if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5) is not False:
166
+ return attr_fn(cls)
167
+ return None
168
+
169
+ return handler
170
+
171
+ cls.__pydantic_core_schema__ = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue]
172
+ undefined_type_error_message,
173
+ code='class-not-fully-defined',
174
+ attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__),
175
+ )
176
+ cls.__pydantic_validator__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue]
177
+ undefined_type_error_message,
178
+ code='class-not-fully-defined',
179
+ val_or_ser='validator',
180
+ attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__),
181
+ )
182
+ cls.__pydantic_serializer__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue]
183
+ undefined_type_error_message,
184
+ code='class-not-fully-defined',
185
+ val_or_ser='serializer',
186
+ attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__),
187
+ )
188
+
189
+
190
+ def set_dataclass_mocks(cls: type[PydanticDataclass], undefined_name: str = 'all referenced types') -> None:
191
+ """Set `__pydantic_validator__` and `__pydantic_serializer__` to `MockValSer`s on a dataclass.
192
+
193
+ Args:
194
+ cls: The model class to set the mocks on
195
+ undefined_name: Name of the undefined thing, used in error messages
196
+ """
197
+ from ..dataclasses import rebuild_dataclass
198
+
199
+ undefined_type_error_message = (
200
+ f'`{cls.__name__}` is not fully defined; you should define {undefined_name},'
201
+ f' then call `pydantic.dataclasses.rebuild_dataclass({cls.__name__})`.'
202
+ )
203
+
204
+ def attempt_rebuild_fn(attr_fn: Callable[[type[PydanticDataclass]], T]) -> Callable[[], T | None]:
205
+ def handler() -> T | None:
206
+ if rebuild_dataclass(cls, raise_errors=False, _parent_namespace_depth=5) is not False:
207
+ return attr_fn(cls)
208
+ return None
209
+
210
+ return handler
211
+
212
+ cls.__pydantic_core_schema__ = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue]
213
+ undefined_type_error_message,
214
+ code='class-not-fully-defined',
215
+ attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__),
216
+ )
217
+ cls.__pydantic_validator__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue]
218
+ undefined_type_error_message,
219
+ code='class-not-fully-defined',
220
+ val_or_ser='validator',
221
+ attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__),
222
+ )
223
+ cls.__pydantic_serializer__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue]
224
+ undefined_type_error_message,
225
+ code='class-not-fully-defined',
226
+ val_or_ser='serializer',
227
+ attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__),
228
+ )
personalPromptBoost/.venv/lib/python3.13/site-packages/pydantic/_internal/_model_construction.py ADDED
@@ -0,0 +1,868 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Private logic for creating models."""
2
+
3
+ from __future__ import annotations as _annotations
4
+
5
+ import operator
6
+ import sys
7
+ import typing
8
+ import warnings
9
+ import weakref
10
+ from abc import ABCMeta
11
+ from functools import cache, partial, wraps
12
+ from types import FunctionType
13
+ from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, NoReturn, TypeVar, cast
14
+
15
+ from pydantic_core import PydanticUndefined, SchemaSerializer
16
+ from typing_extensions import TypeAliasType, dataclass_transform, deprecated, get_args, get_origin
17
+ from typing_inspection import typing_objects
18
+
19
+ from ..errors import PydanticUndefinedAnnotation, PydanticUserError
20
+ from ..plugin._schema_validator import create_schema_validator
21
+ from ..warnings import GenericBeforeBaseModelWarning, PydanticDeprecatedSince20
22
+ from ._config import ConfigWrapper
23
+ from ._decorators import DecoratorInfos, PydanticDescriptorProxy, get_attribute_from_bases, unwrap_wrapped_function
24
+ from ._fields import collect_model_fields, is_valid_field_name, is_valid_privateattr_name, rebuild_model_fields
25
+ from ._generate_schema import GenerateSchema, InvalidSchemaError
26
+ from ._generics import PydanticGenericMetadata, get_model_typevars_map
27
+ from ._import_utils import import_cached_base_model, import_cached_field_info
28
+ from ._mock_val_ser import set_model_mocks
29
+ from ._namespace_utils import NsResolver
30
+ from ._signature import generate_pydantic_signature
31
+ from ._typing_extra import (
32
+ _make_forward_ref,
33
+ eval_type_backport,
34
+ is_classvar_annotation,
35
+ parent_frame_namespace,
36
+ )
37
+ from ._utils import LazyClassAttribute, SafeGetItemProxy
38
+
39
+ if TYPE_CHECKING:
40
+ from ..fields import Field as PydanticModelField
41
+ from ..fields import FieldInfo, ModelPrivateAttr
42
+ from ..fields import PrivateAttr as PydanticModelPrivateAttr
43
+ from ..main import BaseModel
44
+ from ._fields import PydanticExtraInfo
45
+ else:
46
+ PydanticModelField = object()
47
+ PydanticModelPrivateAttr = object()
48
+
49
+ object_setattr = object.__setattr__
50
+
51
+
52
+ class _ModelNamespaceDict(dict):
53
+ """A dictionary subclass that intercepts attribute setting on model classes and
54
+ warns about overriding of decorators.
55
+ """
56
+
57
+ def __setitem__(self, k: str, v: object) -> None:
58
+ existing: Any = self.get(k, None)
59
+ if existing and v is not existing and isinstance(existing, PydanticDescriptorProxy):
60
+ warnings.warn(
61
+ f'`{k}` overrides an existing Pydantic `{existing.decorator_info.decorator_repr}` decorator',
62
+ stacklevel=2,
63
+ )
64
+
65
+ return super().__setitem__(k, v)
66
+
67
+
68
+ def NoInitField(
69
+ *,
70
+ init: Literal[False] = False,
71
+ ) -> Any:
72
+ """Only for typing purposes. Used as default value of `__pydantic_fields_set__`,
73
+ `__pydantic_extra__`, `__pydantic_private__`, so they could be ignored when
74
+ synthesizing the `__init__` signature.
75
+ """
76
+
77
+
78
+ # For ModelMetaclass.register():
79
+ _T = TypeVar('_T')
80
+
81
+
82
+ @dataclass_transform(kw_only_default=True, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr, NoInitField))
83
+ class ModelMetaclass(ABCMeta):
84
+ def __new__(
85
+ mcs,
86
+ cls_name: str,
87
+ bases: tuple[type[Any], ...],
88
+ namespace: dict[str, Any],
89
+ __pydantic_generic_metadata__: PydanticGenericMetadata | None = None,
90
+ __pydantic_reset_parent_namespace__: bool = True,
91
+ _create_model_module: str | None = None,
92
+ **kwargs: Any,
93
+ ) -> type:
94
+ """Metaclass for creating Pydantic models.
95
+
96
+ Args:
97
+ cls_name: The name of the class to be created.
98
+ bases: The base classes of the class to be created.
99
+ namespace: The attribute dictionary of the class to be created.
100
+ __pydantic_generic_metadata__: Metadata for generic models.
101
+ __pydantic_reset_parent_namespace__: Reset parent namespace.
102
+ _create_model_module: The module of the class to be created, if created by `create_model`.
103
+ **kwargs: Catch-all for any other keyword arguments.
104
+
105
+ Returns:
106
+ The new class created by the metaclass.
107
+ """
108
+ # Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we rely on the fact
109
+ # that `BaseModel` itself won't have any bases, but any subclass of it will, to determine whether the `__new__`
110
+ # call we're in the middle of is for the `BaseModel` class.
111
+ if bases:
112
+ raw_annotations: dict[str, Any]
113
+ if sys.version_info >= (3, 14):
114
+ if (
115
+ '__annotations__' in namespace
116
+ ): # `from __future__ import annotations` was used in the model's module
117
+ raw_annotations = namespace['__annotations__']
118
+ else:
119
+ # See https://docs.python.org/3.14/library/annotationlib.html#using-annotations-in-a-metaclass:
120
+ from annotationlib import Format, call_annotate_function, get_annotate_from_class_namespace
121
+
122
+ if annotate := get_annotate_from_class_namespace(namespace):
123
+ raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF)
124
+ else:
125
+ raw_annotations = {}
126
+ else:
127
+ raw_annotations = namespace.get('__annotations__', {})
128
+
129
+ base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases)
130
+
131
+ config_wrapper = ConfigWrapper.for_model(bases, namespace, raw_annotations, kwargs)
132
+ namespace['model_config'] = config_wrapper.config_dict
133
+ private_attributes = inspect_namespace(
134
+ namespace, raw_annotations, config_wrapper.ignored_types, class_vars, base_field_names
135
+ )
136
+ if private_attributes or base_private_attributes:
137
+ original_model_post_init = get_model_post_init(namespace, bases)
138
+ if original_model_post_init is not None:
139
+ # if there are private attributes and a model_post_init function, we handle both
140
+
141
+ @wraps(original_model_post_init)
142
+ def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None:
143
+ """We need to both initialize private attributes and call the user-defined model_post_init
144
+ method.
145
+ """
146
+ init_private_attributes(self, context)
147
+ original_model_post_init(self, context)
148
+
149
+ namespace['model_post_init'] = wrapped_model_post_init
150
+ else:
151
+ namespace['model_post_init'] = init_private_attributes
152
+
153
+ namespace['__class_vars__'] = class_vars
154
+ namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes}
155
+
156
+ cls = cast('type[BaseModel]', super().__new__(mcs, cls_name, bases, namespace, **kwargs))
157
+ BaseModel_ = import_cached_base_model()
158
+
159
+ mro = cls.__mro__
160
+ if Generic in mro and mro.index(Generic) < mro.index(BaseModel_):
161
+ warnings.warn(
162
+ GenericBeforeBaseModelWarning(
163
+ 'Classes should inherit from `BaseModel` before generic classes (e.g. `typing.Generic[T]`) '
164
+ 'for pydantic generics to work properly.'
165
+ ),
166
+ stacklevel=2,
167
+ )
168
+
169
+ cls.__pydantic_custom_init__ = not getattr(cls.__init__, '__pydantic_base_init__', False)
170
+ cls.__pydantic_post_init__ = (
171
+ None if cls.model_post_init is BaseModel_.model_post_init else 'model_post_init'
172
+ )
173
+
174
+ cls.__pydantic_setattr_handlers__ = {}
175
+
176
+ cls.__pydantic_decorators__ = DecoratorInfos.build(cls, replace_wrapped_methods=True)
177
+ cls.__pydantic_decorators__.update_from_config(config_wrapper)
178
+
179
+ # Use the getattr below to grab the __parameters__ from the `typing.Generic` parent class
180
+ if __pydantic_generic_metadata__:
181
+ cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__
182
+ else:
183
+ parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ())
184
+ parameters = getattr(cls, '__parameters__', None) or parent_parameters
185
+ if parameters and parent_parameters and not all(x in parameters for x in parent_parameters):
186
+ from ..root_model import RootModelRootType
187
+
188
+ missing_parameters = tuple(x for x in parameters if x not in parent_parameters)
189
+ if RootModelRootType in parent_parameters and RootModelRootType not in parameters:
190
+ # This is a special case where the user has subclassed RootModel, but has not parameterized
191
+ # RootModel with the generic type identifiers being used. Ex:
192
+ # class MyModel(RootModel, Generic[T]):
193
+ # root: T
194
+ # Should instead just be:
195
+ # class MyModel(RootModel[T]):
196
+ # root: T
197
+ parameters_str = ', '.join([x.__name__ for x in missing_parameters])
198
+ error_message = (
199
+ f'{cls.__name__} is a subclass of `RootModel`, but does not include the generic type identifier(s) '
200
+ f'{parameters_str} in its parameters. '
201
+ f'You should parametrize RootModel directly, e.g., `class {cls.__name__}(RootModel[{parameters_str}]): ...`.'
202
+ )
203
+ else:
204
+ combined_parameters = parent_parameters + missing_parameters
205
+ parameters_str = ', '.join([str(x) for x in combined_parameters])
206
+ generic_type_label = f'typing.Generic[{parameters_str}]'
207
+ error_message = (
208
+ f'All parameters must be present on typing.Generic;'
209
+ f' you should inherit from {generic_type_label}.'
210
+ )
211
+ if Generic not in bases: # pragma: no cover
212
+ # We raise an error here not because it is desirable, but because some cases are mishandled.
213
+ # It would be nice to remove this error and still have things behave as expected, it's just
214
+ # challenging because we are using a custom `__class_getitem__` to parametrize generic models,
215
+ # and not returning a typing._GenericAlias from it.
216
+ bases_str = ', '.join([x.__name__ for x in bases] + [generic_type_label])
217
+ error_message += (
218
+ f' Note: `typing.Generic` must go last: `class {cls.__name__}({bases_str}): ...`)'
219
+ )
220
+ raise TypeError(error_message)
221
+
222
+ cls.__pydantic_generic_metadata__ = {
223
+ 'origin': None,
224
+ 'args': (),
225
+ 'parameters': parameters,
226
+ }
227
+
228
+ cls.__pydantic_complete__ = False # Ensure this specific class gets completed
229
+
230
+ # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487
231
+ # for attributes not in `new_namespace` (e.g. private attributes)
232
+ for name, obj in private_attributes.items():
233
+ obj.__set_name__(cls, name)
234
+
235
+ if __pydantic_reset_parent_namespace__:
236
+ cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace())
237
+ parent_namespace: dict[str, Any] | None = getattr(cls, '__pydantic_parent_namespace__', None)
238
+ if isinstance(parent_namespace, dict):
239
+ parent_namespace = unpack_lenient_weakvaluedict(parent_namespace)
240
+
241
+ ns_resolver = NsResolver(parent_namespace=parent_namespace)
242
+
243
+ set_model_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver)
244
+
245
+ # This is also set in `complete_model_class()`, after schema gen because they are recreated.
246
+ # We set them here as well for backwards compatibility:
247
+ cls.__pydantic_computed_fields__ = {
248
+ k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()
249
+ }
250
+
251
+ if config_wrapper.defer_build:
252
+ set_model_mocks(cls)
253
+ else:
254
+ # Any operation that requires accessing the field infos instances should be put inside
255
+ # `complete_model_class()`:
256
+ complete_model_class(
257
+ cls,
258
+ config_wrapper,
259
+ ns_resolver,
260
+ raise_errors=False,
261
+ create_model_module=_create_model_module,
262
+ )
263
+
264
+ if config_wrapper.frozen and '__hash__' not in namespace:
265
+ set_default_hash_func(cls, bases)
266
+
267
+ # using super(cls, cls) on the next line ensures we only call the parent class's __pydantic_init_subclass__
268
+ # I believe the `type: ignore` is only necessary because mypy doesn't realize that this code branch is
269
+ # only hit for _proper_ subclasses of BaseModel
270
+ super(cls, cls).__pydantic_init_subclass__(**kwargs) # type: ignore[misc]
271
+ return cls
272
+ else:
273
+ # These are instance variables, but have been assigned to `NoInitField` to trick the type checker.
274
+ for instance_slot in '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__':
275
+ namespace.pop(
276
+ instance_slot,
277
+ None, # In case the metaclass is used with a class other than `BaseModel`.
278
+ )
279
+ namespace.get('__annotations__', {}).clear()
280
+ return super().__new__(mcs, cls_name, bases, namespace, **kwargs)
281
+
282
+ if not TYPE_CHECKING: # pragma: no branch
283
+ # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access
284
+
285
+ def __getattr__(self, item: str) -> Any:
286
+ """This is necessary to keep attribute access working for class attribute access."""
287
+ private_attributes = self.__dict__.get('__private_attributes__')
288
+ if private_attributes and item in private_attributes:
289
+ return private_attributes[item]
290
+ raise AttributeError(item)
291
+
292
+ @classmethod
293
+ def __prepare__(cls, *args: Any, **kwargs: Any) -> dict[str, object]:
294
+ return _ModelNamespaceDict()
295
+
296
+ # Due to performance and memory issues, in the ABCMeta.__subclasscheck__ implementation, we don't support
297
+ # registered virtual subclasses. See https://github.com/python/cpython/issues/92810#issuecomment-2762454345.
298
+ # This may change once CPython is fixed (possibly in 3.15), in which case we should conditionally
299
+ # define `register()`.
300
+ def register(self, subclass: type[_T]) -> type[_T]:
301
+ warnings.warn(
302
+ f"For performance reasons, virtual subclasses registered using '{self.__qualname__}.register()' "
303
+ "are not supported in 'isinstance()' and 'issubclass()' checks.",
304
+ stacklevel=2,
305
+ )
306
+ return super().register(subclass)
307
+
308
+ __instancecheck__ = type.__instancecheck__ # pyright: ignore[reportAssignmentType]
309
+ __subclasscheck__ = type.__subclasscheck__ # pyright: ignore[reportAssignmentType]
310
+
311
+ @staticmethod
312
+ def _collect_bases_data(bases: tuple[type[Any], ...]) -> tuple[set[str], set[str], dict[str, ModelPrivateAttr]]:
313
+ BaseModel = import_cached_base_model()
314
+
315
+ field_names: set[str] = set()
316
+ class_vars: set[str] = set()
317
+ private_attributes: dict[str, ModelPrivateAttr] = {}
318
+ for base in bases:
319
+ if issubclass(base, BaseModel) and base is not BaseModel:
320
+ # model_fields might not be defined yet in the case of generics, so we use getattr here:
321
+ field_names.update(getattr(base, '__pydantic_fields__', {}).keys())
322
+ class_vars.update(base.__class_vars__)
323
+ private_attributes.update(base.__private_attributes__)
324
+ return field_names, class_vars, private_attributes
325
+
326
+ @property
327
+ @deprecated(
328
+ 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', category=None
329
+ )
330
+ def __fields__(self) -> dict[str, FieldInfo]:
331
+ warnings.warn(
332
+ 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.',
333
+ PydanticDeprecatedSince20,
334
+ stacklevel=2,
335
+ )
336
+ return getattr(self, '__pydantic_fields__', {})
337
+
338
+ @property
339
+ def __pydantic_fields_complete__(self) -> bool:
340
+ """Whether the fields were successfully collected (i.e. type hints were successfully resolved).
341
+
342
+ This is a private attribute, not meant to be used outside Pydantic.
343
+ """
344
+ if '__pydantic_fields__' not in self.__dict__:
345
+ return False
346
+
347
+ field_infos = cast('dict[str, FieldInfo]', self.__pydantic_fields__) # pyright: ignore[reportAttributeAccessIssue]
348
+
349
+ pydantic_extra_info = cast('PydanticExtraInfo | None', self.__pydantic_extra_info__) # pyright: ignore[reportAttributeAccessIssue]
350
+ if pydantic_extra_info is not None:
351
+ extra_complete = pydantic_extra_info.complete
352
+ else:
353
+ extra_complete = True
354
+
355
+ return all(field_info._complete for field_info in field_infos.values()) and extra_complete
356
+
357
+ def __dir__(self) -> list[str]:
358
+ attributes = list(super().__dir__())
359
+ if '__fields__' in attributes:
360
+ attributes.remove('__fields__')
361
+ return attributes
362
+
363
+
364
+ def init_private_attributes(self: BaseModel, context: Any, /) -> None:
365
+ """This function is meant to behave like a BaseModel method to initialize private attributes.
366
+
367
+ It takes context as an argument since that's what pydantic-core passes when calling it.
368
+
369
+ Args:
370
+ self: The BaseModel instance.
371
+ context: The context.
372
+ """
373
+ if getattr(self, '__pydantic_private__', None) is None:
374
+ pydantic_private = {}
375
+ for name, private_attr in self.__private_attributes__.items():
376
+ # Avoid needlessly creating a new dict for the validated data:
377
+ if private_attr.default_factory_takes_validated_data:
378
+ default = private_attr.get_default(
379
+ call_default_factory=True, validated_data={**self.__dict__, **pydantic_private}
380
+ )
381
+ else:
382
+ default = private_attr.get_default(call_default_factory=True)
383
+ if default is not PydanticUndefined:
384
+ pydantic_private[name] = default
385
+ object_setattr(self, '__pydantic_private__', pydantic_private)
386
+
387
+
388
+ def get_model_post_init(namespace: dict[str, Any], bases: tuple[type[Any], ...]) -> Callable[..., Any] | None:
389
+ """Get the `model_post_init` method from the namespace or the class bases, or `None` if not defined."""
390
+ if 'model_post_init' in namespace:
391
+ return namespace['model_post_init']
392
+
393
+ BaseModel = import_cached_base_model()
394
+
395
+ model_post_init = get_attribute_from_bases(bases, 'model_post_init')
396
+ if model_post_init is not BaseModel.model_post_init:
397
+ return model_post_init
398
+
399
+
400
+ def inspect_namespace( # noqa C901
401
+ namespace: dict[str, Any],
402
+ raw_annotations: dict[str, Any],
403
+ ignored_types: tuple[type[Any], ...],
404
+ base_class_vars: set[str],
405
+ base_class_fields: set[str],
406
+ ) -> dict[str, ModelPrivateAttr]:
407
+ """Iterate over the namespace and:
408
+ * gather private attributes
409
+ * check for items which look like fields but are not (e.g. have no annotation) and warn.
410
+
411
+ Args:
412
+ namespace: The attribute dictionary of the class to be created.
413
+ raw_annotations: The (non-evaluated) annotations of the model.
414
+ ignored_types: A tuple of ignore types.
415
+ base_class_vars: A set of base class class variables.
416
+ base_class_fields: A set of base class fields.
417
+
418
+ Returns:
419
+ A dict containing private attributes info.
420
+
421
+ Raises:
422
+ TypeError: If there is a `__root__` field in model.
423
+ NameError: If private attribute name is invalid.
424
+ PydanticUserError:
425
+ - If a field does not have a type annotation.
426
+ - If a field on base class was overridden by a non-annotated attribute.
427
+ """
428
+ from ..fields import ModelPrivateAttr, PrivateAttr
429
+
430
+ FieldInfo = import_cached_field_info()
431
+
432
+ all_ignored_types = ignored_types + default_ignored_types()
433
+
434
+ private_attributes: dict[str, ModelPrivateAttr] = {}
435
+
436
+ if '__root__' in raw_annotations or '__root__' in namespace:
437
+ raise TypeError("To define root models, use `pydantic.RootModel` rather than a field called '__root__'")
438
+
439
+ ignored_names: set[str] = set()
440
+ for var_name, value in list(namespace.items()):
441
+ if var_name == 'model_config' or var_name == '__pydantic_extra__':
442
+ continue
443
+ elif (
444
+ isinstance(value, type)
445
+ and value.__module__ == namespace['__module__']
446
+ and '__qualname__' in namespace
447
+ and value.__qualname__.startswith(f'{namespace["__qualname__"]}.')
448
+ ):
449
+ # `value` is a nested type defined in this namespace; don't error
450
+ continue
451
+ elif isinstance(value, all_ignored_types) or value.__class__.__module__ == 'functools':
452
+ ignored_names.add(var_name)
453
+ continue
454
+ elif isinstance(value, ModelPrivateAttr):
455
+ if var_name.startswith('__'):
456
+ raise NameError(
457
+ 'Private attributes must not use dunder names;'
458
+ f' use a single underscore prefix instead of {var_name!r}.'
459
+ )
460
+ elif is_valid_field_name(var_name):
461
+ raise NameError(
462
+ 'Private attributes must not use valid field names;'
463
+ f' use sunder names, e.g. {"_" + var_name!r} instead of {var_name!r}.'
464
+ )
465
+ private_attributes[var_name] = value
466
+ del namespace[var_name]
467
+ elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name):
468
+ suggested_name = var_name.lstrip('_') or 'my_field' # don't suggest '' for all-underscore name
469
+ raise NameError(
470
+ f'Fields must not use names with leading underscores;'
471
+ f' e.g., use {suggested_name!r} instead of {var_name!r}.'
472
+ )
473
+
474
+ elif var_name.startswith('__'):
475
+ continue
476
+ elif is_valid_privateattr_name(var_name):
477
+ if var_name not in raw_annotations or not is_classvar_annotation(raw_annotations[var_name]):
478
+ private_attributes[var_name] = cast(ModelPrivateAttr, PrivateAttr(default=value))
479
+ del namespace[var_name]
480
+ elif var_name in base_class_vars:
481
+ continue
482
+ elif var_name not in raw_annotations:
483
+ if var_name in base_class_fields:
484
+ raise PydanticUserError(
485
+ f'Field {var_name!r} defined on a base class was overridden by a non-annotated attribute. '
486
+ f'All field definitions, including overrides, require a type annotation.',
487
+ code='model-field-overridden',
488
+ )
489
+ elif isinstance(value, FieldInfo):
490
+ raise PydanticUserError(
491
+ f'Field {var_name!r} requires a type annotation', code='model-field-missing-annotation'
492
+ )
493
+ else:
494
+ raise PydanticUserError(
495
+ f'A non-annotated attribute was detected: `{var_name} = {value!r}`. All model fields require a '
496
+ f'type annotation; if `{var_name}` is not meant to be a field, you may be able to resolve this '
497
+ f"error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.",
498
+ code='model-field-missing-annotation',
499
+ )
500
+
501
+ for ann_name, ann_type in raw_annotations.items():
502
+ if (
503
+ is_valid_privateattr_name(ann_name)
504
+ and ann_name not in private_attributes
505
+ and ann_name not in ignored_names
506
+ # This condition can be a false negative when `ann_type` is stringified,
507
+ # but it is handled in most cases in `set_model_fields`:
508
+ and not is_classvar_annotation(ann_type)
509
+ and ann_type not in all_ignored_types
510
+ and getattr(ann_type, '__module__', None) != 'functools'
511
+ ):
512
+ if isinstance(ann_type, str):
513
+ # Walking up the frames to get the module namespace where the model is defined
514
+ # (as the model class wasn't created yet, we unfortunately can't use `cls.__module__`):
515
+ frame = sys._getframe(2)
516
+ if frame is not None:
517
+ try:
518
+ ann_type = eval_type_backport(
519
+ _make_forward_ref(ann_type, is_argument=False, is_class=True),
520
+ globalns=frame.f_globals,
521
+ localns=frame.f_locals,
522
+ )
523
+ except (NameError, TypeError):
524
+ pass
525
+
526
+ if typing_objects.is_annotated(get_origin(ann_type)):
527
+ _, *metadata = get_args(ann_type)
528
+ private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None)
529
+ if private_attr is not None:
530
+ private_attributes[ann_name] = private_attr
531
+ continue
532
+ private_attributes[ann_name] = PrivateAttr()
533
+
534
+ return private_attributes
535
+
536
+
537
+ def set_default_hash_func(cls: type[BaseModel], bases: tuple[type[Any], ...]) -> None:
538
+ base_hash_func = get_attribute_from_bases(bases, '__hash__')
539
+ new_hash_func = make_hash_func(cls)
540
+ if base_hash_func in {None, object.__hash__} or getattr(base_hash_func, '__code__', None) == new_hash_func.__code__:
541
+ # If `__hash__` is some default, we generate a hash function.
542
+ # It will be `None` if not overridden from BaseModel.
543
+ # It may be `object.__hash__` if there is another
544
+ # parent class earlier in the bases which doesn't override `__hash__` (e.g. `typing.Generic`).
545
+ # It may be a value set by `set_default_hash_func` if `cls` is a subclass of another frozen model.
546
+ # In the last case we still need a new hash function to account for new `model_fields`.
547
+ cls.__hash__ = new_hash_func
548
+
549
+
550
+ def make_hash_func(cls: type[BaseModel]) -> Any:
551
+ getter = operator.itemgetter(*cls.__pydantic_fields__.keys()) if cls.__pydantic_fields__ else lambda _: 0
552
+
553
+ def hash_func(self: Any) -> int:
554
+ try:
555
+ return hash(getter(self.__dict__))
556
+ except KeyError:
557
+ # In rare cases (such as when using the deprecated copy method), the __dict__ may not contain
558
+ # all model fields, which is how we can get here.
559
+ # getter(self.__dict__) is much faster than any 'safe' method that accounts for missing keys,
560
+ # and wrapping it in a `try` doesn't slow things down much in the common case.
561
+ return hash(getter(SafeGetItemProxy(self.__dict__)))
562
+
563
+ return hash_func
564
+
565
+
566
+ def set_model_fields(
567
+ cls: type[BaseModel],
568
+ config_wrapper: ConfigWrapper,
569
+ ns_resolver: NsResolver,
570
+ ) -> None:
571
+ """Collect and set `cls.__pydantic_fields__` and `cls.__class_vars__`.
572
+
573
+ Args:
574
+ cls: BaseModel or dataclass.
575
+ config_wrapper: The config wrapper instance.
576
+ ns_resolver: Namespace resolver to use when getting model annotations.
577
+ """
578
+ typevars_map = get_model_typevars_map(cls)
579
+ fields, pydantic_extra_info, class_vars = collect_model_fields(
580
+ cls, config_wrapper, ns_resolver, typevars_map=typevars_map
581
+ )
582
+
583
+ cls.__pydantic_fields__ = fields
584
+ cls.__pydantic_extra_info__ = pydantic_extra_info
585
+ cls.__class_vars__.update(class_vars)
586
+
587
+ for k in class_vars:
588
+ # Class vars should not be private attributes
589
+ # We remove them _here_ and not earlier because we rely on inspecting the class to determine its classvars,
590
+ # but private attributes are determined by inspecting the namespace _prior_ to class creation.
591
+ # In the case that a classvar with a leading-'_' is defined via a ForwardRef (e.g., when using
592
+ # `__future__.annotations`), we want to remove the private attribute which was detected _before_ we knew it
593
+ # evaluated to a classvar
594
+
595
+ value = cls.__private_attributes__.pop(k, None)
596
+ if value is not None and value.default is not PydanticUndefined:
597
+ setattr(cls, k, value.default)
598
+
599
+
600
+ def complete_model_class(
601
+ cls: type[BaseModel],
602
+ config_wrapper: ConfigWrapper,
603
+ ns_resolver: NsResolver,
604
+ *,
605
+ raise_errors: bool = True,
606
+ call_on_complete_hook: bool = True,
607
+ create_model_module: str | None = None,
608
+ is_force_rebuild: bool = False,
609
+ ) -> bool:
610
+ """Finish building a model class.
611
+
612
+ This logic must be called after class has been created since validation functions must be bound
613
+ and `get_type_hints` requires a class object.
614
+
615
+ Args:
616
+ cls: BaseModel or dataclass.
617
+ config_wrapper: The config wrapper instance.
618
+ ns_resolver: The namespace resolver instance to use during schema building.
619
+ raise_errors: Whether to raise errors.
620
+ call_on_complete_hook: Whether to call the `__pydantic_on_complete__` hook.
621
+ create_model_module: The module of the class to be created, if created by `create_model`.
622
+ is_force_rebuild: Whether the model is being force-rebuilt (if True, pre-built serializers and
623
+ validators are not used, to avoid stale references).
624
+
625
+ Returns:
626
+ `True` if the model is successfully completed, else `False`.
627
+
628
+ Raises:
629
+ PydanticUndefinedAnnotation: If PydanticUndefinedAnnotation occurs in __get_pydantic_core_schema__
630
+ and `raise_errors=True`.
631
+ """
632
+ typevars_map = get_model_typevars_map(cls)
633
+
634
+ if not cls.__pydantic_fields_complete__:
635
+ # Note: when coming from `ModelMetaclass.__new__()`, this results in fields being built twice.
636
+ # We do so a second time here so that we can get the ``NameError`` for the specific undefined annotation.
637
+ # Alternatively, we could let `GenerateSchema()` raise the error, but there are cases where incomplete
638
+ # fields are inherited in `collect_model_fields()` and can actually have their annotation resolved in the
639
+ # generate schema process. As we want to avoid having `__pydantic_fields_complete__` set to `False`
640
+ # when `__pydantic_complete__` is `True`, we rebuild here:
641
+ try:
642
+ cls.__pydantic_fields__, cls.__pydantic_extra_info__ = rebuild_model_fields(
643
+ cls,
644
+ config_wrapper=config_wrapper,
645
+ ns_resolver=ns_resolver,
646
+ typevars_map=typevars_map,
647
+ )
648
+ except NameError as e:
649
+ exc = PydanticUndefinedAnnotation.from_name_error(e)
650
+ set_model_mocks(cls, f'`{exc.name}`')
651
+ if raise_errors:
652
+ raise exc from e
653
+
654
+ if not raise_errors and not cls.__pydantic_fields_complete__:
655
+ # No need to continue with schema gen, it is guaranteed to fail
656
+ return False
657
+
658
+ assert cls.__pydantic_fields_complete__
659
+
660
+ gen_schema = GenerateSchema(
661
+ config_wrapper,
662
+ ns_resolver,
663
+ typevars_map,
664
+ )
665
+
666
+ try:
667
+ schema = gen_schema.generate_schema(cls)
668
+ except PydanticUndefinedAnnotation as e:
669
+ if raise_errors:
670
+ raise
671
+ set_model_mocks(cls, f'`{e.name}`')
672
+ return False
673
+
674
+ core_config = config_wrapper.core_config(title=cls.__name__)
675
+
676
+ try:
677
+ schema = gen_schema.clean_schema(schema)
678
+ except InvalidSchemaError:
679
+ set_model_mocks(cls)
680
+ return False
681
+
682
+ # This needs to happen *after* model schema generation, as the return types
683
+ # of the properties are evaluated and the `ComputedFieldInfo` are recreated:
684
+ cls.__pydantic_computed_fields__ = {k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()}
685
+
686
+ set_deprecated_descriptors(cls)
687
+
688
+ cls.__pydantic_core_schema__ = schema
689
+
690
+ cls.__pydantic_validator__ = create_schema_validator(
691
+ schema,
692
+ cls,
693
+ create_model_module or cls.__module__,
694
+ cls.__qualname__,
695
+ 'create_model' if create_model_module else 'BaseModel',
696
+ core_config,
697
+ config_wrapper.plugin_settings,
698
+ _use_prebuilt=not is_force_rebuild,
699
+ )
700
+ cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config, _use_prebuilt=not is_force_rebuild)
701
+
702
+ # set __signature__ attr only for model class, but not for its instances
703
+ # (because instances can define `__call__`, and `inspect.signature` shouldn't
704
+ # use the `__signature__` attribute and instead generate from `__call__`).
705
+ cls.__signature__ = LazyClassAttribute(
706
+ '__signature__',
707
+ partial(
708
+ generate_pydantic_signature,
709
+ init=cls.__init__,
710
+ fields=cls.__pydantic_fields__,
711
+ validate_by_name=config_wrapper.validate_by_name,
712
+ extra=config_wrapper.extra,
713
+ ),
714
+ )
715
+
716
+ cls.__pydantic_complete__ = True
717
+
718
+ if call_on_complete_hook:
719
+ cls.__pydantic_on_complete__()
720
+
721
+ return True
722
+
723
+
724
+ def set_deprecated_descriptors(cls: type[BaseModel]) -> None:
725
+ """Set data descriptors on the class for deprecated fields."""
726
+ for field, field_info in cls.__pydantic_fields__.items():
727
+ if (msg := field_info.deprecation_message) is not None:
728
+ desc = _DeprecatedFieldDescriptor(msg)
729
+ desc.__set_name__(cls, field)
730
+ setattr(cls, field, desc)
731
+
732
+ for field, computed_field_info in cls.__pydantic_computed_fields__.items():
733
+ if (
734
+ (msg := computed_field_info.deprecation_message) is not None
735
+ # Avoid having two warnings emitted:
736
+ and not hasattr(unwrap_wrapped_function(computed_field_info.wrapped_property), '__deprecated__')
737
+ ):
738
+ desc = _DeprecatedFieldDescriptor(msg, computed_field_info.wrapped_property)
739
+ desc.__set_name__(cls, field)
740
+ setattr(cls, field, desc)
741
+
742
+
743
+ class _DeprecatedFieldDescriptor:
744
+ """Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field.
745
+
746
+ Attributes:
747
+ msg: The deprecation message to be emitted.
748
+ wrapped_property: The property instance if the deprecated field is a computed field, or `None`.
749
+ field_name: The name of the field being deprecated.
750
+ """
751
+
752
+ field_name: str
753
+
754
+ def __init__(self, msg: str, wrapped_property: property | None = None) -> None:
755
+ self.msg = msg
756
+ self.wrapped_property = wrapped_property
757
+
758
+ def __set_name__(self, cls: type[BaseModel], name: str) -> None:
759
+ self.field_name = name
760
+
761
+ def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any:
762
+ if obj is None:
763
+ if self.wrapped_property is not None:
764
+ return self.wrapped_property.__get__(None, obj_type)
765
+ raise AttributeError(self.field_name)
766
+
767
+ warnings.warn(self.msg, DeprecationWarning, stacklevel=2)
768
+
769
+ if self.wrapped_property is not None:
770
+ return self.wrapped_property.__get__(obj, obj_type)
771
+ return obj.__dict__[self.field_name]
772
+
773
+ # Defined to make it a data descriptor and take precedence over the instance's dictionary.
774
+ # Note that it will not be called when setting a value on a model instance
775
+ # as `BaseModel.__setattr__` is defined and takes priority.
776
+ def __set__(self, obj: Any, value: Any) -> NoReturn:
777
+ raise AttributeError(self.field_name)
778
+
779
+
780
+ class _PydanticWeakRef:
781
+ """Wrapper for `weakref.ref` that enables `pickle` serialization.
782
+
783
+ Cloudpickle fails to serialize weakref.ref objects due to an arcane error related to
784
+ to abstract base classes (`abc.ABC`). This class works around the issue by wrapping
785
+ `weakref.ref` instead of subclassing it.
786
+
787
+ See https://github.com/pydantic/pydantic/issues/6763 for context.
788
+
789
+ Semantics:
790
+ - If not pickled, behaves the same as a `weakref.ref`.
791
+ - If pickled along with the referenced object, the same `weakref.ref` behavior
792
+ will be maintained between them after unpickling.
793
+ - If pickled without the referenced object, after unpickling the underlying
794
+ reference will be cleared (`__call__` will always return `None`).
795
+ """
796
+
797
+ def __init__(self, obj: Any):
798
+ if obj is None:
799
+ # The object will be `None` upon deserialization if the serialized weakref
800
+ # had lost its underlying object.
801
+ self._wr = None
802
+ else:
803
+ self._wr = weakref.ref(obj)
804
+
805
+ def __call__(self) -> Any:
806
+ if self._wr is None:
807
+ return None
808
+ else:
809
+ return self._wr()
810
+
811
+ def __reduce__(self) -> tuple[Callable, tuple[weakref.ReferenceType | None]]:
812
+ return _PydanticWeakRef, (self(),)
813
+
814
+
815
+ def build_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None:
816
+ """Takes an input dictionary, and produces a new value that (invertibly) replaces the values with weakrefs.
817
+
818
+ We can't just use a WeakValueDictionary because many types (including int, str, etc.) can't be stored as values
819
+ in a WeakValueDictionary.
820
+
821
+ The `unpack_lenient_weakvaluedict` function can be used to reverse this operation.
822
+ """
823
+ if d is None:
824
+ return None
825
+ result = {}
826
+ for k, v in d.items():
827
+ try:
828
+ proxy = _PydanticWeakRef(v)
829
+ except TypeError:
830
+ proxy = v
831
+ result[k] = proxy
832
+ return result
833
+
834
+
835
+ def unpack_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None:
836
+ """Inverts the transform performed by `build_lenient_weakvaluedict`."""
837
+ if d is None:
838
+ return None
839
+
840
+ result = {}
841
+ for k, v in d.items():
842
+ if isinstance(v, _PydanticWeakRef):
843
+ v = v()
844
+ if v is not None:
845
+ result[k] = v
846
+ else:
847
+ result[k] = v
848
+ return result
849
+
850
+
851
+ @cache
852
+ def default_ignored_types() -> tuple[type[Any], ...]:
853
+ from ..fields import ComputedFieldInfo
854
+
855
+ ignored_types = [
856
+ FunctionType,
857
+ property,
858
+ classmethod,
859
+ staticmethod,
860
+ PydanticDescriptorProxy,
861
+ ComputedFieldInfo,
862
+ TypeAliasType, # from `typing_extensions`
863
+ ]
864
+
865
+ if sys.version_info >= (3, 12):
866
+ ignored_types.append(typing.TypeAliasType)
867
+
868
+ return tuple(ignored_types)