ashlr-plugin 1.36.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (499) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +39 -0
  3. package/.claude-plugin/plugin.json +36 -0
  4. package/.codex/agents/README.md +9 -0
  5. package/.codex/agents/ashlr-explorer.md +36 -0
  6. package/.codex/agents/ashlr-worker.md +38 -0
  7. package/.codex-plugin/plugin.json +45 -0
  8. package/.mcp.json +14 -0
  9. package/LICENSE +21 -0
  10. package/README.md +311 -0
  11. package/agents/ashlr-code.md +69 -0
  12. package/agents/ashlr-explore.md +44 -0
  13. package/agents/ashlr-plan.md +54 -0
  14. package/bench/fixtures/notebook-large.ipynb +660 -0
  15. package/bench/fixtures/notebook-small.ipynb +39 -0
  16. package/bench/fixtures/tasklist-closed.json +62 -0
  17. package/bench/fixtures/tasklist-large-mixed.json +27 -0
  18. package/bench/fixtures/tasklist-sprint-open.json +79 -0
  19. package/bench/fixtures/websearch-bun-runtime.json +32 -0
  20. package/bench/fixtures/websearch-react-hooks-patterns.json +32 -0
  21. package/bench/fixtures/websearch-typescript-generics.json +38 -0
  22. package/bench/refs/node-sdk/.refrev +1 -0
  23. package/bench/refs/node-sdk/README.md +17 -0
  24. package/bench/refs/node-sdk/src/agent/agent.ts +163 -0
  25. package/bench/refs/node-sdk/src/agent/create-agent-ui-stream.ts +83 -0
  26. package/bench/refs/node-sdk/src/agent/tool-loop-agent.ts +238 -0
  27. package/bench/refs/node-sdk/src/embed/embed-many.ts +409 -0
  28. package/bench/refs/node-sdk/src/embed/embed-result.ts +50 -0
  29. package/bench/refs/node-sdk/src/embed/embed.ts +257 -0
  30. package/bench/refs/node-sdk/src/error/invalid-argument-error.ts +34 -0
  31. package/bench/refs/node-sdk/src/error/invalid-tool-input-error.ts +33 -0
  32. package/bench/refs/node-sdk/src/error/no-object-generated-error.ts +70 -0
  33. package/bench/refs/node-sdk/src/generate-image/generate-image-result.ts +42 -0
  34. package/bench/refs/node-sdk/src/generate-image/generate-image.ts +362 -0
  35. package/bench/refs/node-sdk/src/generate-object/generate-object-result.ts +67 -0
  36. package/bench/refs/node-sdk/src/generate-object/generate-object.ts +501 -0
  37. package/bench/refs/node-sdk/src/generate-object/inject-json-instruction.ts +30 -0
  38. package/bench/refs/node-sdk/src/generate-object/output-strategy.ts +415 -0
  39. package/bench/refs/node-sdk/src/generate-object/repair-text.ts +12 -0
  40. package/bench/refs/node-sdk/src/generate-object/stream-object.ts +960 -0
  41. package/bench/refs/node-sdk/src/generate-speech/generate-speech.ts +191 -0
  42. package/bench/refs/node-sdk/src/generate-text/generate-text.ts +1484 -0
  43. package/bench/refs/node-sdk/src/generate-text/stream-text.ts +2708 -0
  44. package/bench/refs/node-sdk/src/generate-text/tool-call.ts +59 -0
  45. package/bench/refs/node-sdk/src/generate-text/tool-result.ts +36 -0
  46. package/bench/refs/node-sdk/src/telemetry/create-telemetry-dispatcher.ts +146 -0
  47. package/bench/refs/node-sdk/src/telemetry/telemetry-registry.ts +15 -0
  48. package/bench/refs/node-sdk/src/telemetry/telemetry.ts +223 -0
  49. package/bench/refs/node-sdk/src/util/async-iterable-stream.ts +94 -0
  50. package/bench/refs/node-sdk/src/util/consume-stream.ts +31 -0
  51. package/bench/refs/node-sdk/src/util/create-stitchable-stream.ts +112 -0
  52. package/bench/refs/node-sdk/src/util/download/download.ts +74 -0
  53. package/bench/refs/node-sdk/src/util/error-handler.ts +1 -0
  54. package/bench/refs/node-sdk/src/util/fix-json.ts +401 -0
  55. package/bench/refs/node-sdk/src/util/merge-objects.ts +79 -0
  56. package/bench/refs/python-lib/.refrev +1 -0
  57. package/bench/refs/python-lib/README.md +18 -0
  58. package/bench/refs/python-lib/pandas/core/_numba/executor.py +249 -0
  59. package/bench/refs/python-lib/pandas/core/_numba/extensions.py +586 -0
  60. package/bench/refs/python-lib/pandas/core/_numba/kernels/mean_.py +198 -0
  61. package/bench/refs/python-lib/pandas/core/_numba/kernels/min_max_.py +178 -0
  62. package/bench/refs/python-lib/pandas/core/_numba/kernels/sum_.py +255 -0
  63. package/bench/refs/python-lib/pandas/core/_numba/kernels/var_.py +251 -0
  64. package/bench/refs/python-lib/pandas/core/accessor.py +520 -0
  65. package/bench/refs/python-lib/pandas/core/api.py +138 -0
  66. package/bench/refs/python-lib/pandas/core/array_algos/masked_accumulations.py +97 -0
  67. package/bench/refs/python-lib/pandas/core/array_algos/masked_reductions.py +252 -0
  68. package/bench/refs/python-lib/pandas/core/array_algos/putmask.py +150 -0
  69. package/bench/refs/python-lib/pandas/core/array_algos/quantile.py +232 -0
  70. package/bench/refs/python-lib/pandas/core/array_algos/replace.py +159 -0
  71. package/bench/refs/python-lib/pandas/core/array_algos/take.py +609 -0
  72. package/bench/refs/python-lib/pandas/core/arraylike.py +534 -0
  73. package/bench/refs/python-lib/pandas/core/arrays/_arrow_string_mixins.py +434 -0
  74. package/bench/refs/python-lib/pandas/core/arrays/_mixins.py +630 -0
  75. package/bench/refs/python-lib/pandas/core/arrays/_ranges.py +276 -0
  76. package/bench/refs/python-lib/pandas/core/arrays/_utils.py +77 -0
  77. package/bench/refs/python-lib/pandas/core/arrays/arrow/accessors.py +521 -0
  78. package/bench/refs/python-lib/pandas/core/arrays/arrow/extension_types.py +174 -0
  79. package/bench/refs/python-lib/pandas/core/arrays/boolean.py +454 -0
  80. package/bench/refs/python-lib/pandas/core/arrays/floating.py +192 -0
  81. package/bench/refs/python-lib/pandas/core/arrays/integer.py +296 -0
  82. package/bench/refs/python-lib/pandas/core/arrays/masked.py +2140 -0
  83. package/bench/refs/python-lib/pandas/core/arrays/numeric.py +305 -0
  84. package/bench/refs/python-lib/pandas/core/arrays/numpy_.py +701 -0
  85. package/bench/refs/python-lib/pandas/core/arrays/period.py +1586 -0
  86. package/bench/refs/python-lib/pandas/core/arrays/sparse/accessor.py +505 -0
  87. package/bench/refs/python-lib/pandas/core/arrays/sparse/scipy_sparse.py +208 -0
  88. package/bench/refs/rust-project/.refrev +1 -0
  89. package/bench/refs/rust-project/README.md +17 -0
  90. package/bench/refs/rust-project/tokio/src/doc/os.rs +68 -0
  91. package/bench/refs/rust-project/tokio/src/fs/dir_builder.rs +129 -0
  92. package/bench/refs/rust-project/tokio/src/fs/file.rs +1113 -0
  93. package/bench/refs/rust-project/tokio/src/fs/mocks.rs +176 -0
  94. package/bench/refs/rust-project/tokio/src/fs/mod.rs +324 -0
  95. package/bench/refs/rust-project/tokio/src/fs/open_options.rs +856 -0
  96. package/bench/refs/rust-project/tokio/src/fs/read.rs +80 -0
  97. package/bench/refs/rust-project/tokio/src/fs/read_dir.rs +357 -0
  98. package/bench/refs/rust-project/tokio/src/fs/write.rs +99 -0
  99. package/bench/refs/rust-project/tokio/src/future/maybe_done.rs +123 -0
  100. package/bench/refs/rust-project/tokio/src/future/try_join.rs +82 -0
  101. package/bench/refs/rust-project/tokio/src/io/async_buf_read.rs +117 -0
  102. package/bench/refs/rust-project/tokio/src/io/async_read.rs +133 -0
  103. package/bench/refs/rust-project/tokio/src/io/async_seek.rs +96 -0
  104. package/bench/refs/rust-project/tokio/src/io/async_write.rs +402 -0
  105. package/bench/refs/rust-project/tokio/src/io/blocking.rs +339 -0
  106. package/bench/refs/rust-project/tokio/src/io/interest.rs +345 -0
  107. package/bench/refs/rust-project/tokio/src/io/join.rs +130 -0
  108. package/bench/refs/rust-project/tokio/src/io/mod.rs +308 -0
  109. package/bench/refs/rust-project/tokio/src/io/poll_evented.rs +319 -0
  110. package/bench/refs/rust-project/tokio/src/io/read_buf.rs +344 -0
  111. package/bench/refs/rust-project/tokio/src/io/ready.rs +322 -0
  112. package/bench/refs/rust-project/tokio/src/io/split.rs +166 -0
  113. package/bench/refs/rust-project/tokio/src/io/stderr.rs +148 -0
  114. package/bench/refs/rust-project/tokio/src/io/stdin.rs +98 -0
  115. package/bench/refs/rust-project/tokio/src/io/stdio_common.rs +222 -0
  116. package/bench/refs/rust-project/tokio/src/io/stdout.rs +197 -0
  117. package/bench/refs/rust-project/tokio/src/io/util/buf_reader.rs +311 -0
  118. package/bench/refs/rust-project/tokio/src/io/util/buf_stream.rs +207 -0
  119. package/bench/refs/rust-project/tokio/src/io/util/buf_writer.rs +310 -0
  120. package/bench/refs/rust-project/tokio/src/io/util/chain.rs +144 -0
  121. package/commands/_spawn-patterns.json +32 -0
  122. package/commands/ashlr-allow.md +21 -0
  123. package/commands/ashlr-benchmark.md +53 -0
  124. package/commands/ashlr-brief.md +97 -0
  125. package/commands/ashlr-budget.md +76 -0
  126. package/commands/ashlr-compact.md +54 -0
  127. package/commands/ashlr-dashboard.md +37 -0
  128. package/commands/ashlr-doctor.md +56 -0
  129. package/commands/ashlr-eco-mode.md +92 -0
  130. package/commands/ashlr-genome-init.md +24 -0
  131. package/commands/ashlr-genome-keygen.md +36 -0
  132. package/commands/ashlr-genome-loop.md +118 -0
  133. package/commands/ashlr-genome-push.md +36 -0
  134. package/commands/ashlr-genome-rewrap.md +48 -0
  135. package/commands/ashlr-genome-team-init.md +67 -0
  136. package/commands/ashlr-handoff.md +23 -0
  137. package/commands/ashlr-help.md +86 -0
  138. package/commands/ashlr-hook-timings.md +30 -0
  139. package/commands/ashlr-leaderboard.md +50 -0
  140. package/commands/ashlr-ollama-setup.md +39 -0
  141. package/commands/ashlr-orchestrate-status.md +72 -0
  142. package/commands/ashlr-orchestrate.md +83 -0
  143. package/commands/ashlr-parallelize.md +63 -0
  144. package/commands/ashlr-report-crash.md +33 -0
  145. package/commands/ashlr-resume.md +72 -0
  146. package/commands/ashlr-savings.md +24 -0
  147. package/commands/ashlr-settings.md +50 -0
  148. package/commands/ashlr-spawn.md +61 -0
  149. package/commands/ashlr-start.md +60 -0
  150. package/commands/ashlr-status.md +64 -0
  151. package/commands/ashlr-team-invite.md +47 -0
  152. package/commands/ashlr-tier.md +122 -0
  153. package/commands/ashlr-tour.md +60 -0
  154. package/commands/ashlr-update.md +155 -0
  155. package/commands/ashlr-upgrade.md +96 -0
  156. package/commands/goal.md +58 -0
  157. package/commands/loop.md +40 -0
  158. package/docs/CNAME +1 -0
  159. package/docs/PRO_TIER.md +104 -0
  160. package/docs/README.md +21 -0
  161. package/docs/architecture.md +415 -0
  162. package/docs/ashlr-pipe.md +161 -0
  163. package/docs/assets/logo.svg +19 -0
  164. package/docs/assets/og.png +0 -0
  165. package/docs/assets/og.svg +41 -0
  166. package/docs/benchmarks-v2.json +355 -0
  167. package/docs/benchmarks.json +102 -0
  168. package/docs/benchmarks.md +211 -0
  169. package/docs/billing.md +185 -0
  170. package/docs/cloud-genome.md +155 -0
  171. package/docs/competitive-wozcode.md +92 -0
  172. package/docs/deploy.md +325 -0
  173. package/docs/email-templates.md +113 -0
  174. package/docs/embed-tuning.md +103 -0
  175. package/docs/genome.md +120 -0
  176. package/docs/github-oauth-onboarding.md +127 -0
  177. package/docs/hero-video-script.md +129 -0
  178. package/docs/index.html +2262 -0
  179. package/docs/install-prompt.md +78 -0
  180. package/docs/install-windows.md +132 -0
  181. package/docs/install.ps1 +171 -0
  182. package/docs/install.sh +146 -0
  183. package/docs/launch/README.md +114 -0
  184. package/docs/launch/hn.md +49 -0
  185. package/docs/launch/reddit.md +45 -0
  186. package/docs/launch/x.md +65 -0
  187. package/docs/launch-post.md +112 -0
  188. package/docs/legal.md +78 -0
  189. package/docs/llm-providers.md +99 -0
  190. package/docs/multi-host-mcp.md +217 -0
  191. package/docs/multi-turn-architecture.md +108 -0
  192. package/docs/operations/deployment.md +108 -0
  193. package/docs/operations/error-monitoring.md +70 -0
  194. package/docs/operations/weekly-digest.md +70 -0
  195. package/docs/operations.md +494 -0
  196. package/docs/platform-support.md +133 -0
  197. package/docs/policy-packs.md +188 -0
  198. package/docs/press-kit/fact-sheet.md +78 -0
  199. package/docs/press-kit/founder-bio.md +3 -0
  200. package/docs/press-kit/logo.svg +33 -0
  201. package/docs/press-kit/screenshots.md +146 -0
  202. package/docs/pricing.md +251 -0
  203. package/docs/pro-backend-architecture.md +523 -0
  204. package/docs/producthunt.md +52 -0
  205. package/docs/router-migration.md +110 -0
  206. package/docs/session-log-schema.md +68 -0
  207. package/docs/social.md +95 -0
  208. package/docs/team-genome.md +528 -0
  209. package/docs/telemetry.md +194 -0
  210. package/docs/test-isolation.md +100 -0
  211. package/docs/upgrade.md +159 -0
  212. package/hooks/_hook-errors.ts +87 -0
  213. package/hooks/_hook-perf-emit.ts +113 -0
  214. package/hooks/_hook-timing-ledger.ts +1133 -0
  215. package/hooks/_nudge-throttle.ts +127 -0
  216. package/hooks/_recent-blocks.ts +127 -0
  217. package/hooks/audit-upload.ts +86 -0
  218. package/hooks/codex-hooks.json +171 -0
  219. package/hooks/commit-attribution.ts +179 -0
  220. package/hooks/edit-batching-nudge.ts +154 -0
  221. package/hooks/genome-scribe-hook.ts +219 -0
  222. package/hooks/hooks.json +294 -0
  223. package/hooks/orient-nudge-hook.ts +242 -0
  224. package/hooks/policy-enforce.ts +214 -0
  225. package/hooks/post-tool-use-embedding.ts +93 -0
  226. package/hooks/post-tool-use-genome.sh +37 -0
  227. package/hooks/post-tool-use-genome.ts +69 -0
  228. package/hooks/posttooluse-correlate.ts +122 -0
  229. package/hooks/posttooluse-dedupe-output.ts +241 -0
  230. package/hooks/posttooluse-genome-refresh.ts +223 -0
  231. package/hooks/posttooluse-native-nudge.ts +205 -0
  232. package/hooks/posttooluse-stale-result.ts +277 -0
  233. package/hooks/pretooluse-bash.ts +63 -0
  234. package/hooks/pretooluse-budget-guard.ts +318 -0
  235. package/hooks/pretooluse-common.ts +985 -0
  236. package/hooks/pretooluse-eco-router.ts +196 -0
  237. package/hooks/pretooluse-edit.sh +93 -0
  238. package/hooks/pretooluse-edit.ts +197 -0
  239. package/hooks/pretooluse-glob.ts +70 -0
  240. package/hooks/pretooluse-grep.sh +85 -0
  241. package/hooks/pretooluse-grep.ts +96 -0
  242. package/hooks/pretooluse-notebookedit.ts +121 -0
  243. package/hooks/pretooluse-read.sh +118 -0
  244. package/hooks/pretooluse-read.ts +118 -0
  245. package/hooks/pretooluse-task.ts +130 -0
  246. package/hooks/pretooluse-webfetch.ts +66 -0
  247. package/hooks/pretooluse-websearch.ts +85 -0
  248. package/hooks/pretooluse-write.ts +128 -0
  249. package/hooks/pulse-emit.ts +197 -0
  250. package/hooks/session-end-consolidate.sh +35 -0
  251. package/hooks/session-end-consolidate.ts +188 -0
  252. package/hooks/session-end-stats-gc.ts +80 -0
  253. package/hooks/session-log-append.sh +94 -0
  254. package/hooks/session-log-append.ts +116 -0
  255. package/hooks/session-start.ts +993 -0
  256. package/hooks/sessionend-hook-health-nudge.ts +451 -0
  257. package/hooks/sessionend-savings-nudge.ts +318 -0
  258. package/hooks/sessionend-status-line-nudge.ts +296 -0
  259. package/hooks/sessionstart-brief.ts +140 -0
  260. package/hooks/sessionstart-cost-refactor.ts +95 -0
  261. package/hooks/sessionstart-efficient.ts +110 -0
  262. package/hooks/sessionstart-genome-author.ts +93 -0
  263. package/hooks/sessionstart-lean-tools.ts +98 -0
  264. package/hooks/sessionstart-search.ts +97 -0
  265. package/hooks/stop-accounting.ts +152 -0
  266. package/hooks/subagent-stop-rollup.ts +162 -0
  267. package/hooks/userpromptsubmit-brief-trigger.ts +156 -0
  268. package/package.json +56 -0
  269. package/ports/README.md +108 -0
  270. package/ports/cursor/mcp.json +11 -0
  271. package/ports/goose/recipe.yaml +26 -0
  272. package/scripts/ashlr-mcp.ts +40 -0
  273. package/scripts/auto-update.ts +177 -0
  274. package/scripts/baseline-scan.ts +831 -0
  275. package/scripts/bench-orchestrate.ts +377 -0
  276. package/scripts/benchmark-refs.ts +292 -0
  277. package/scripts/bootstrap.mjs +100 -0
  278. package/scripts/brief-eval.ts +234 -0
  279. package/scripts/bump-version.ts +82 -0
  280. package/scripts/bun-resolve.d.mts +11 -0
  281. package/scripts/bun-resolve.mjs +59 -0
  282. package/scripts/calibrate-grep.ts +467 -0
  283. package/scripts/capture-grep-workload.ts +260 -0
  284. package/scripts/check-tier.ts +61 -0
  285. package/scripts/check-version-sync.ts +97 -0
  286. package/scripts/cli-orchestrate-status.ts +386 -0
  287. package/scripts/cli-orchestrate.ts +303 -0
  288. package/scripts/cli.ts +478 -0
  289. package/scripts/cloud-smoke-test.ts +313 -0
  290. package/scripts/coach-report.ts +373 -0
  291. package/scripts/context-db-migrate.ts +137 -0
  292. package/scripts/context-status.ts +43 -0
  293. package/scripts/demo-run.ts +255 -0
  294. package/scripts/deploy-smoke.sh +140 -0
  295. package/scripts/doctor.ts +992 -0
  296. package/scripts/embed-file-worker.ts +104 -0
  297. package/scripts/embed-tune.ts +308 -0
  298. package/scripts/errors-report.ts +428 -0
  299. package/scripts/find-test-leak.ts +69 -0
  300. package/scripts/generate-badge.ts +357 -0
  301. package/scripts/genome-auto-consolidate.ts +533 -0
  302. package/scripts/genome-auto-propose.ts +578 -0
  303. package/scripts/genome-cloud-pull.ts +363 -0
  304. package/scripts/genome-cloud-push.ts +382 -0
  305. package/scripts/genome-cloud-sync.ts +587 -0
  306. package/scripts/genome-commit-watcher.ts +295 -0
  307. package/scripts/genome-init.ts +986 -0
  308. package/scripts/genome-key.ts +233 -0
  309. package/scripts/genome-keygen.ts +168 -0
  310. package/scripts/genome-link.ts +59 -0
  311. package/scripts/genome-refresh-worker.ts +364 -0
  312. package/scripts/genome-rewrap.ts +90 -0
  313. package/scripts/genome-synthesizer.ts +679 -0
  314. package/scripts/genome-team-init.ts +312 -0
  315. package/scripts/handoff-pack.ts +438 -0
  316. package/scripts/hook-bootstrap.mjs +75 -0
  317. package/scripts/hook-timing-reader.ts +371 -0
  318. package/scripts/hook-timings-report.ts +554 -0
  319. package/scripts/install-genome-hooks.ts +196 -0
  320. package/scripts/install-onnx-model.ts +154 -0
  321. package/scripts/install-permissions.ts +276 -0
  322. package/scripts/install-status-line.ts +150 -0
  323. package/scripts/mcp-entrypoint.sh +78 -0
  324. package/scripts/mcp-entrypoint.ts +130 -0
  325. package/scripts/mdx-angle-bracket-lint.ts +152 -0
  326. package/scripts/measure-cold-start.ts +126 -0
  327. package/scripts/migrate-stats-to-sqlite.ts +86 -0
  328. package/scripts/ollama-setup.ts +498 -0
  329. package/scripts/onboarding-wizard.ts +1691 -0
  330. package/scripts/orchestrate-emit-telemetry.ts +177 -0
  331. package/scripts/orchestrate-expand.ts +517 -0
  332. package/scripts/orchestrate-run.ts +744 -0
  333. package/scripts/print-legend.ts +50 -0
  334. package/scripts/product-metadata.ts +38 -0
  335. package/scripts/prune-old-memories.ts +208 -0
  336. package/scripts/publish.sh +88 -0
  337. package/scripts/read-calibration.ts +122 -0
  338. package/scripts/report-crash.ts +226 -0
  339. package/scripts/run-benchmark.ts +750 -0
  340. package/scripts/run-root-tests.ts +28 -0
  341. package/scripts/savings-dashboard.ts +1258 -0
  342. package/scripts/savings-report-extras.ts +447 -0
  343. package/scripts/savings-status-line.ts +873 -0
  344. package/scripts/session-event-emit.ts +266 -0
  345. package/scripts/session-greet.ts +686 -0
  346. package/scripts/session-log-report.ts +551 -0
  347. package/scripts/session-resume.ts +614 -0
  348. package/scripts/set-hook-mode.ts +83 -0
  349. package/scripts/smoke-cross-platform.ts +117 -0
  350. package/scripts/smoke-realtime.ts +257 -0
  351. package/scripts/smoke-tools.ts +21 -0
  352. package/scripts/stats-cloud-pull.ts +213 -0
  353. package/scripts/stats-cloud-sync.ts +261 -0
  354. package/scripts/telemetry-flush.ts +160 -0
  355. package/scripts/telemetry-status.ts +266 -0
  356. package/scripts/timing-budget.ts +35 -0
  357. package/scripts/ui-animation.ts +120 -0
  358. package/scripts/ui.ts +431 -0
  359. package/scripts/upgrade-flow.ts +775 -0
  360. package/scripts/weekly-digest.ts +394 -0
  361. package/servers/_accounting.ts +78 -0
  362. package/servers/_ask-router.ts +84 -0
  363. package/servers/_ast-chunker.ts +434 -0
  364. package/servers/_ast-helpers.ts +183 -0
  365. package/servers/_ast-languages.ts +153 -0
  366. package/servers/_ast-refactor/_shared.ts +221 -0
  367. package/servers/_ast-refactor/cross-file-rename.ts +560 -0
  368. package/servers/_ast-refactor/extract-function.ts +357 -0
  369. package/servers/_ast-refactor/file-local-rename.ts +172 -0
  370. package/servers/_ast-refactor.ts +41 -0
  371. package/servers/_ast-skeleton.ts +107 -0
  372. package/servers/_bash-summarizers-registry.ts +1096 -0
  373. package/servers/_crash-dump.ts +210 -0
  374. package/servers/_cwd-clamp.ts +342 -0
  375. package/servers/_edit-log.ts +28 -0
  376. package/servers/_edit-match.ts +236 -0
  377. package/servers/_edit-validate.ts +196 -0
  378. package/servers/_embed-calibration.ts +123 -0
  379. package/servers/_embedding-cache.ts +401 -0
  380. package/servers/_embedding-model.ts +329 -0
  381. package/servers/_events.ts +113 -0
  382. package/servers/_genome-cache.ts +154 -0
  383. package/servers/_genome-commits.ts +172 -0
  384. package/servers/_genome-crypto-v2.ts +242 -0
  385. package/servers/_genome-crypto.ts +259 -0
  386. package/servers/_genome-discoveries.ts +140 -0
  387. package/servers/_genome-embed-populator.ts +216 -0
  388. package/servers/_genome-freshness.ts +134 -0
  389. package/servers/_genome-issues.ts +171 -0
  390. package/servers/_genome-live.ts +263 -0
  391. package/servers/_genome-prs.ts +188 -0
  392. package/servers/_genome-search.ts +479 -0
  393. package/servers/_genome-sync.ts +297 -0
  394. package/servers/_history-tracker.ts +279 -0
  395. package/servers/_http-helpers.ts +151 -0
  396. package/servers/_identity-hash.ts +151 -0
  397. package/servers/_llm-providers/anthropic.ts +132 -0
  398. package/servers/_llm-providers/cloud.ts +195 -0
  399. package/servers/_llm-providers/index.ts +350 -0
  400. package/servers/_llm-providers/local.ts +127 -0
  401. package/servers/_llm-providers/onnx.ts +393 -0
  402. package/servers/_llm-providers/types.ts +27 -0
  403. package/servers/_manifest-v2.ts +447 -0
  404. package/servers/_mcp-host.ts +93 -0
  405. package/servers/_nudge-events.ts +451 -0
  406. package/servers/_orchestrate-executor.ts +316 -0
  407. package/servers/_prefetch.ts +435 -0
  408. package/servers/_pricing.ts +256 -0
  409. package/servers/_pro.ts +381 -0
  410. package/servers/_read-cache.ts +44 -0
  411. package/servers/_router-handlers.ts +46 -0
  412. package/servers/_router.ts +55 -0
  413. package/servers/_run-with-timeout.ts +173 -0
  414. package/servers/_savings-render.ts +214 -0
  415. package/servers/_stats-sqlite.ts +640 -0
  416. package/servers/_stats.ts +1183 -0
  417. package/servers/_status-line-cells.ts +469 -0
  418. package/servers/_streaks.ts +162 -0
  419. package/servers/_summarize.ts +208 -0
  420. package/servers/_task-graph-render.ts +217 -0
  421. package/servers/_task-graph.ts +545 -0
  422. package/servers/_telemetry.ts +719 -0
  423. package/servers/_test-parsers.ts +530 -0
  424. package/servers/_test-watch.ts +626 -0
  425. package/servers/_text-helpers.ts +37 -0
  426. package/servers/_token-measure.ts +160 -0
  427. package/servers/_tool-base.ts +248 -0
  428. package/servers/_weekly-digest.ts +391 -0
  429. package/servers/ask-server-handlers.ts +49 -0
  430. package/servers/ask-server.ts +174 -0
  431. package/servers/bash-server-handlers.ts +138 -0
  432. package/servers/bash-server.ts +1136 -0
  433. package/servers/bench.ts +186 -0
  434. package/servers/diff-semantic-server-handlers.ts +39 -0
  435. package/servers/diff-semantic-server.ts +566 -0
  436. package/servers/diff-server-handlers.ts +317 -0
  437. package/servers/diff-server.ts +20 -0
  438. package/servers/edit-server-handlers.ts +31 -0
  439. package/servers/edit-server.ts +209 -0
  440. package/servers/edit-structural-server-handlers.ts +322 -0
  441. package/servers/efficiency-server-handlers.ts +161 -0
  442. package/servers/efficiency-server.ts +1135 -0
  443. package/servers/flush-server-handlers.ts +21 -0
  444. package/servers/flush-server.ts +19 -0
  445. package/servers/genome-server-handlers.ts +118 -0
  446. package/servers/genome-server.ts +397 -0
  447. package/servers/github-server-handlers.ts +187 -0
  448. package/servers/github-server.ts +856 -0
  449. package/servers/glob-server-handlers.ts +233 -0
  450. package/servers/glob-server.ts +20 -0
  451. package/servers/grep-server-handlers.ts +61 -0
  452. package/servers/grep-server.ts +564 -0
  453. package/servers/http-server-handlers.ts +36 -0
  454. package/servers/http-server.ts +149 -0
  455. package/servers/logs-server-handlers.ts +42 -0
  456. package/servers/logs-server.ts +359 -0
  457. package/servers/ls-server-handlers.ts +166 -0
  458. package/servers/ls-server.ts +20 -0
  459. package/servers/multi-edit-server-handlers.ts +51 -0
  460. package/servers/multi-edit-server.ts +422 -0
  461. package/servers/notebook-edit-server-handlers.ts +34 -0
  462. package/servers/notebook-edit-server.ts +181 -0
  463. package/servers/orient-server-handlers.ts +52 -0
  464. package/servers/orient-server.ts +436 -0
  465. package/servers/pipe-server-handlers.ts +68 -0
  466. package/servers/pipe-server.ts +300 -0
  467. package/servers/read-server-handlers.ts +42 -0
  468. package/servers/read-server.ts +206 -0
  469. package/servers/rename-file-server-handlers.ts +67 -0
  470. package/servers/rename-file-server.ts +699 -0
  471. package/servers/savings-server-handlers.ts +27 -0
  472. package/servers/savings-server.ts +54 -0
  473. package/servers/search-replace-regex-server-handlers.ts +96 -0
  474. package/servers/search-replace-regex-server.ts +751 -0
  475. package/servers/sql-server-handlers.ts +58 -0
  476. package/servers/sql-server.ts +505 -0
  477. package/servers/task-server-handlers.ts +358 -0
  478. package/servers/task-server.ts +24 -0
  479. package/servers/test-server-handlers.ts +351 -0
  480. package/servers/test-server.ts +20 -0
  481. package/servers/tree-server-handlers.ts +503 -0
  482. package/servers/tree-server.ts +20 -0
  483. package/servers/webfetch-server-handlers.ts +166 -0
  484. package/servers/webfetch-server.ts +20 -0
  485. package/servers/websearch-server-handlers.ts +215 -0
  486. package/servers/websearch-server.ts +19 -0
  487. package/servers/write-server-handlers.ts +27 -0
  488. package/servers/write-server.ts +97 -0
  489. package/skills/ashlr-brief/SKILL.md +80 -0
  490. package/skills/ashlr-codex-doctor/SKILL.md +21 -0
  491. package/skills/ashlr-codex-efficient-tools/SKILL.md +17 -0
  492. package/skills/ashlr-codex-genome-refresh/SKILL.md +20 -0
  493. package/skills/ashlr-codex-parallel-explore/SKILL.md +20 -0
  494. package/skills/ashlr-codex-savings/SKILL.md +17 -0
  495. package/skills/ashlr-cost-refactor/SKILL.md +50 -0
  496. package/skills/ashlr-efficient/SKILL.md +64 -0
  497. package/skills/ashlr-genome-author/SKILL.md +43 -0
  498. package/skills/ashlr-lean-tools/SKILL.md +43 -0
  499. package/skills/ashlr-search/SKILL.md +46 -0
@@ -0,0 +1,1586 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import timedelta
4
+ import operator
5
+ from typing import (
6
+ TYPE_CHECKING,
7
+ Any,
8
+ Literal,
9
+ Self,
10
+ TypeVar,
11
+ cast,
12
+ )
13
+ import warnings
14
+
15
+ import numpy as np
16
+
17
+ from pandas._libs import (
18
+ algos as libalgos,
19
+ lib,
20
+ )
21
+ from pandas._libs.arrays import NDArrayBacked
22
+ from pandas._libs.tslibs import (
23
+ BaseOffset,
24
+ Day,
25
+ NaT,
26
+ NaTType,
27
+ Resolution,
28
+ Timedelta,
29
+ add_overflowsafe,
30
+ astype_overflowsafe,
31
+ dt64arr_to_periodarr as c_dt64arr_to_periodarr,
32
+ get_unit_from_dtype,
33
+ iNaT,
34
+ parsing,
35
+ period as libperiod,
36
+ to_offset,
37
+ )
38
+ from pandas._libs.tslibs.dtypes import (
39
+ FreqGroup,
40
+ PeriodDtypeBase,
41
+ )
42
+ from pandas._libs.tslibs.fields import isleapyear_arr
43
+ from pandas._libs.tslibs.offsets import (
44
+ Tick,
45
+ delta_to_tick,
46
+ )
47
+ from pandas._libs.tslibs.period import (
48
+ DIFFERENT_FREQ,
49
+ IncompatibleFrequency,
50
+ Period,
51
+ get_period_field_arr,
52
+ period_asfreq_arr,
53
+ )
54
+ from pandas.errors import Pandas4Warning
55
+ from pandas.util._decorators import (
56
+ cache_readonly,
57
+ set_module,
58
+ )
59
+ from pandas.util._exceptions import find_stack_level
60
+
61
+ from pandas.core.dtypes.common import (
62
+ ensure_object,
63
+ pandas_dtype,
64
+ )
65
+ from pandas.core.dtypes.dtypes import (
66
+ DatetimeTZDtype,
67
+ PeriodDtype,
68
+ )
69
+ from pandas.core.dtypes.generic import (
70
+ ABCIndex,
71
+ ABCPeriodIndex,
72
+ ABCSeries,
73
+ ABCTimedeltaArray,
74
+ )
75
+ from pandas.core.dtypes.missing import isna
76
+
77
+ from pandas.core.arrays import (
78
+ ExtensionArray,
79
+ datetimelike as dtl,
80
+ )
81
+ import pandas.core.common as com
82
+ from pandas.core.construction import extract_array
83
+
84
+ if TYPE_CHECKING:
85
+ from collections.abc import (
86
+ Callable,
87
+ Sequence,
88
+ )
89
+
90
+ from pandas._typing import (
91
+ AnyArrayLike,
92
+ Dtype,
93
+ DtypeObj,
94
+ FillnaOptions,
95
+ NpDtype,
96
+ NumpySorter,
97
+ NumpyValueArrayLike,
98
+ npt,
99
+ )
100
+
101
+ from pandas.core.dtypes.dtypes import ExtensionDtype
102
+
103
+ from pandas.core.arrays import (
104
+ DatetimeArray,
105
+ TimedeltaArray,
106
+ )
107
+
108
+
109
+ BaseOffsetT = TypeVar("BaseOffsetT", bound=BaseOffset)
110
+
111
+
112
+ def _field_accessor(name: str, docstring: str | None = None):
113
+ def f(self):
114
+ base = self.dtype._dtype_code
115
+ result = get_period_field_arr(name, self.asi8, base)
116
+ return result
117
+
118
+ f.__name__ = name
119
+ f.__doc__ = docstring
120
+ return property(f)
121
+
122
+
123
+ @set_module("pandas.arrays")
124
+ class PeriodArray(dtl.DatelikeOps, libperiod.PeriodMixin):
125
+ """
126
+ Pandas ExtensionArray for storing Period data.
127
+
128
+ Users should use :func:`~pandas.array` to create new instances.
129
+
130
+ Parameters
131
+ ----------
132
+ values : Union[PeriodArray, Series[period], ndarray[int], PeriodIndex]
133
+ The data to store. These should be arrays that can be directly
134
+ converted to ordinals without inference or copy (PeriodArray,
135
+ ndarray[int64]), or a box around such an array (Series[period],
136
+ PeriodIndex).
137
+ dtype : PeriodDtype, optional
138
+ A PeriodDtype instance from which to extract a `freq`. If both
139
+ `freq` and `dtype` are specified, then the frequencies must match.
140
+ copy : bool, default False
141
+ Whether to copy the ordinals before storing.
142
+
143
+ Attributes
144
+ ----------
145
+ None
146
+
147
+ Methods
148
+ -------
149
+ None
150
+
151
+ See Also
152
+ --------
153
+ Period: Represents a period of time.
154
+ PeriodIndex : Immutable Index for period data.
155
+ period_range: Create a fixed-frequency PeriodArray.
156
+ array: Construct a pandas array.
157
+
158
+ Notes
159
+ -----
160
+ There are two components to a PeriodArray
161
+
162
+ - ordinals : integer ndarray
163
+ - freq : pd.tseries.offsets.Offset
164
+
165
+ The values are physically stored as a 1-D ndarray of integers. These are
166
+ called "ordinals" and represent some kind of offset from a base.
167
+
168
+ The `freq` indicates the span covered by each element of the array.
169
+ All elements in the PeriodArray have the same `freq`.
170
+
171
+ Examples
172
+ --------
173
+ >>> pd.arrays.PeriodArray(pd.PeriodIndex(["2023-01-01", "2023-01-02"], freq="D"))
174
+ <PeriodArray>
175
+ ['2023-01-01', '2023-01-02']
176
+ Length: 2, dtype: period[D]
177
+ """
178
+
179
+ # array priority higher than numpy scalars
180
+ __array_priority__ = 1000
181
+ _typ = "periodarray" # ABCPeriodArray
182
+ _internal_fill_value = np.int64(iNaT)
183
+ _recognized_scalars = (Period,)
184
+ _is_recognized_dtype: Callable[[DtypeObj], bool] = lambda x: isinstance(
185
+ x, PeriodDtype
186
+ ) # check_compatible_with checks freq match
187
+
188
+ @property
189
+ def _scalar_type(self) -> type[Period]:
190
+ return Period
191
+
192
+ # Names others delegate to us
193
+ _other_ops: list[str] = []
194
+ _bool_ops: list[str] = ["is_leap_year"]
195
+ _object_ops: list[str] = ["start_time", "end_time", "freq"]
196
+ _field_ops: list[str] = [
197
+ "year",
198
+ "month",
199
+ "day",
200
+ "hour",
201
+ "minute",
202
+ "second",
203
+ "weekofyear",
204
+ "weekday",
205
+ "week",
206
+ "day_of_week",
207
+ "day_of_year",
208
+ "quarter",
209
+ "qyear",
210
+ "days_in_month",
211
+ ]
212
+ # GH#46768 - deprecated but still need to be accessible via .dt accessor
213
+ _deprecated_ops: list[str] = ["dayofweek", "dayofyear", "daysinmonth"]
214
+ _datetimelike_ops: list[str] = (
215
+ _field_ops + _object_ops + _bool_ops + _deprecated_ops
216
+ )
217
+ _datetimelike_methods: list[str] = ["strftime", "to_timestamp", "asfreq"]
218
+
219
+ _dtype: PeriodDtype
220
+
221
+ # --------------------------------------------------------------------
222
+ # Constructors
223
+
224
+ def __init__(self, values, dtype: Dtype | None = None, copy: bool = False) -> None:
225
+ if dtype is not None:
226
+ dtype = pandas_dtype(dtype)
227
+ if not isinstance(dtype, PeriodDtype):
228
+ raise ValueError(f"Invalid dtype {dtype} for PeriodArray")
229
+
230
+ if isinstance(values, ABCSeries):
231
+ values = values._values
232
+ if not isinstance(values, type(self)):
233
+ raise TypeError("Incorrect dtype")
234
+
235
+ elif isinstance(values, ABCPeriodIndex):
236
+ values = values._values
237
+
238
+ if isinstance(values, type(self)):
239
+ if dtype is not None and dtype != values.dtype:
240
+ raise raise_on_incompatible(values, dtype.freq)
241
+ values, dtype = values._ndarray, values.dtype
242
+
243
+ if not copy:
244
+ values = np.asarray(values, dtype="int64")
245
+ else:
246
+ values = np.array(values, dtype="int64", copy=copy)
247
+ if dtype is None:
248
+ raise ValueError("dtype is not specified and cannot be inferred")
249
+ dtype = cast("PeriodDtype", dtype)
250
+ NDArrayBacked.__init__(self, values, dtype)
251
+
252
+ # error: Signature of "_simple_new" incompatible with supertype "NDArrayBacked"
253
+ @classmethod
254
+ def _simple_new( # type: ignore[override]
255
+ cls,
256
+ values: npt.NDArray[np.int64],
257
+ dtype: PeriodDtype,
258
+ ) -> Self:
259
+ # alias for PeriodArray.__init__
260
+ assertion_msg = "Should be numpy array of type i8"
261
+ assert isinstance(values, np.ndarray) and values.dtype == "i8", assertion_msg
262
+ return cls(values, dtype=dtype)
263
+
264
+ @classmethod
265
+ def _from_sequence(
266
+ cls,
267
+ scalars,
268
+ *,
269
+ dtype: Dtype | None = None,
270
+ copy: bool = False,
271
+ ) -> Self:
272
+ if dtype is not None:
273
+ dtype = pandas_dtype(dtype)
274
+
275
+ # Note: we can't do extract_array until after from_datetime64 path
276
+ # bc of GH#64241
277
+ data_dtype = getattr(scalars, "dtype", None)
278
+ if lib.is_np_dtype(data_dtype, "M"):
279
+ freq = dtype._freq if dtype is not None else None # type: ignore[union-attr]
280
+ return cls._from_datetime64(scalars, freq)
281
+
282
+ scalars = extract_array(scalars, extract_numpy=True)
283
+ if isinstance(scalars, cls):
284
+ if dtype is not None:
285
+ return scalars.astype(dtype, copy=copy)
286
+ elif copy:
287
+ return scalars.copy()
288
+ return scalars
289
+
290
+ if not isinstance(
291
+ scalars, (np.ndarray, list, tuple, ABCSeries, ABCIndex, ExtensionArray)
292
+ ):
293
+ # test_constructor_empty_special has a case with an iter object
294
+ scalars = list(scalars)
295
+
296
+ arrdata = np.asarray(scalars)
297
+ if arrdata.dtype.kind == "f" and len(arrdata) > 0:
298
+ if not np.isnan(arrdata).all():
299
+ raise TypeError(
300
+ "PeriodArray does not allow floating point in construction"
301
+ )
302
+ ordinals = np.full(arrdata.shape, iNaT, dtype=np.int64)
303
+ return cls(ordinals, dtype=dtype)
304
+
305
+ elif arrdata.dtype.kind in "iu":
306
+ arr = arrdata.astype(np.int64, copy=False)
307
+ ordinals = libperiod.from_calendar_ordinals(arr, dtype) # type: ignore[arg-type]
308
+ return cls(ordinals, dtype=dtype)
309
+ else:
310
+ periods = ensure_object(arrdata)
311
+
312
+ if dtype is None:
313
+ dtype_base = libperiod.extract_period_unit(periods)
314
+ dtype = PeriodDtype(dtype_base)
315
+ ordinals = libperiod.extract_ordinals(periods, dtype) # type: ignore[arg-type]
316
+ return cls(ordinals, dtype=dtype)
317
+
318
+ @classmethod
319
+ def _from_sequence_of_strings(
320
+ cls, strings, *, dtype: ExtensionDtype, copy: bool = False
321
+ ) -> Self:
322
+ return cls._from_sequence(strings, dtype=dtype, copy=copy)
323
+
324
+ @classmethod
325
+ def _from_datetime64(cls, data, freq, tz=None) -> Self:
326
+ """
327
+ Construct a PeriodArray from a datetime64 array
328
+
329
+ Parameters
330
+ ----------
331
+ data : ndarray[datetime64[ns], datetime64[ns, tz]]
332
+ freq : str or Tick
333
+ tz : tzinfo, optional
334
+
335
+ Returns
336
+ -------
337
+ PeriodArray[freq]
338
+ """
339
+ if isinstance(freq, BaseOffset):
340
+ freq = PeriodDtype(freq)._freqstr
341
+ data, freq = dt64arr_to_periodarr(data, freq, tz)
342
+ dtype = PeriodDtype(freq)
343
+ return cls(data, dtype=dtype)
344
+
345
+ @classmethod
346
+ def _generate_range(cls, start, end, periods, freq):
347
+ periods = dtl.validate_periods(periods)
348
+
349
+ if freq is not None:
350
+ freq = Period._maybe_convert_freq(freq)
351
+
352
+ if start is not None or end is not None:
353
+ subarr, freq = _get_ordinal_range(start, end, periods, freq)
354
+ else:
355
+ raise ValueError("Not enough parameters to construct Period range")
356
+
357
+ return subarr, freq
358
+
359
+ @classmethod
360
+ def _from_fields(cls, *, fields: dict, freq) -> Self:
361
+ subarr, freq = _range_from_fields(freq=freq, **fields)
362
+ dtype = PeriodDtype(freq)
363
+ return cls._simple_new(subarr, dtype=dtype)
364
+
365
+ # -----------------------------------------------------------------
366
+ # DatetimeLike Interface
367
+
368
+ # error: Argument 1 of "_unbox_scalar" is incompatible with supertype
369
+ # "DatetimeLikeArrayMixin"; supertype defines the argument type as
370
+ # "Union[Union[Period, Any, Timedelta], NaTType]"
371
+ def _unbox_scalar( # type: ignore[override]
372
+ self,
373
+ value: Period | NaTType,
374
+ ) -> np.int64:
375
+ if value is NaT:
376
+ # error: Item "Period" of "Union[Period, NaTType]" has no attribute "value"
377
+ return np.int64(value._value) # type: ignore[union-attr]
378
+ elif isinstance(value, self._scalar_type):
379
+ self._check_compatible_with(value)
380
+ return np.int64(value.ordinal)
381
+ else:
382
+ raise ValueError(f"'value' should be a Period. Got '{value}' instead.")
383
+
384
+ def _scalar_from_string(self, value: str) -> Period:
385
+ return Period(value, freq=self.freq)
386
+
387
+ # error: Argument 1 of "_check_compatible_with" is incompatible with
388
+ # supertype "DatetimeLikeArrayMixin"; supertype defines the argument type
389
+ # as "Period | Timestamp | Timedelta | NaTType"
390
+ def _check_compatible_with(self, other: Period | NaTType | PeriodArray) -> None: # type: ignore[override]
391
+ if other is NaT:
392
+ return
393
+ elif isinstance(other, Period):
394
+ self._require_matching_unit(other._dtype._freqstr)
395
+ else:
396
+ # error: Item "NaTType" of "NaTType | PeriodArray" has no
397
+ # attribute "freq"
398
+ self._require_matching_unit(other.dtype._freqstr) # type: ignore[union-attr]
399
+
400
+ # --------------------------------------------------------------------
401
+ # Data / Attributes
402
+
403
+ @cache_readonly
404
+ def dtype(self) -> PeriodDtype:
405
+ return self._dtype
406
+
407
+ @property
408
+ def freq(self) -> BaseOffset:
409
+ """
410
+ Return the frequency object for this PeriodArray.
411
+ """
412
+ return self.dtype.freq
413
+
414
+ @property
415
+ def freqstr(self) -> str:
416
+ return PeriodDtype(self.freq)._freqstr
417
+
418
+ @property # NB: override with cache_readonly in immutable subclasses
419
+ def _resolution_obj(self) -> Resolution:
420
+ freqstr = self.freqstr
421
+ try:
422
+ return Resolution.get_reso_from_freqstr(freqstr)
423
+ except KeyError:
424
+ return None # type: ignore[return-value]
425
+
426
+ def __array__(
427
+ self, dtype: NpDtype | None = None, copy: bool | None = None
428
+ ) -> np.ndarray:
429
+ if dtype == "i8":
430
+ # For NumPy 1.x compatibility we cannot use copy=None. And
431
+ # `copy=False` has the meaning of `copy=None` here:
432
+ if not copy:
433
+ result = np.asarray(self.asi8, dtype=dtype)
434
+ if self._readonly:
435
+ result = result.view()
436
+ result.flags.writeable = False
437
+ return result
438
+ else:
439
+ return np.array(self.asi8, dtype=dtype)
440
+
441
+ if copy is False:
442
+ raise ValueError(
443
+ "Unable to avoid copy while creating an array as requested."
444
+ )
445
+
446
+ if dtype == bool:
447
+ return ~self._isnan
448
+
449
+ # This will raise TypeError for non-object dtypes
450
+ return np.array(list(self), dtype=object)
451
+
452
+ def __arrow_array__(self, type=None):
453
+ """
454
+ Convert myself into a pyarrow Array.
455
+ """
456
+ import pyarrow
457
+
458
+ from pandas.core.arrays.arrow.extension_types import ArrowPeriodType
459
+
460
+ if type is not None:
461
+ if pyarrow.types.is_integer(type):
462
+ return pyarrow.array(self._ndarray, mask=self.isna(), type=type)
463
+ elif isinstance(type, ArrowPeriodType):
464
+ # ensure we have the same freq
465
+ if self.freqstr != type.freq:
466
+ raise TypeError(
467
+ "Not supported to convert PeriodArray to array with different "
468
+ f"'freq' ({self.freqstr} vs {type.freq})"
469
+ )
470
+ else:
471
+ raise TypeError(
472
+ f"Not supported to convert PeriodArray to '{type}' type"
473
+ )
474
+
475
+ period_type = ArrowPeriodType(self.freqstr)
476
+ storage_array = pyarrow.array(self._ndarray, mask=self.isna(), type="int64")
477
+ return pyarrow.ExtensionArray.from_storage(period_type, storage_array)
478
+
479
+ # --------------------------------------------------------------------
480
+ # Vectorized analogues of Period properties
481
+
482
+ year = _field_accessor(
483
+ "year",
484
+ """
485
+ The year of the period.
486
+
487
+ Returns the year component for each period in the index.
488
+
489
+ See Also
490
+ --------
491
+ PeriodIndex.day_of_year : The ordinal day of the year.
492
+ PeriodIndex.dayofyear : The ordinal day of the year.
493
+ PeriodIndex.is_leap_year : Logical indicating if the date belongs to a
494
+ leap year.
495
+ PeriodIndex.weekofyear : The week ordinal of the year.
496
+ PeriodIndex.year : The year of the period.
497
+
498
+ Examples
499
+ --------
500
+ >>> idx = pd.PeriodIndex(["2023", "2024", "2025"], freq="Y")
501
+ >>> idx.year
502
+ Index([2023, 2024, 2025], dtype='int64')
503
+ """,
504
+ )
505
+ month = _field_accessor(
506
+ "month",
507
+ """
508
+ The month as January=1, December=12.
509
+
510
+ Returns the month component for each period in the index as an
511
+ integer, where January is 1 and December is 12.
512
+
513
+ See Also
514
+ --------
515
+ PeriodIndex.days_in_month : The number of days in the month.
516
+ PeriodIndex.daysinmonth : The number of days in the month.
517
+
518
+ Examples
519
+ --------
520
+ >>> idx = pd.PeriodIndex(["2023-01", "2023-02", "2023-03"], freq="M")
521
+ >>> idx.month
522
+ Index([1, 2, 3], dtype='int64')
523
+ """,
524
+ )
525
+ day = _field_accessor(
526
+ "day",
527
+ """
528
+ The days of the period.
529
+
530
+ Returns the day-of-month component for each period in the index.
531
+
532
+ See Also
533
+ --------
534
+ PeriodIndex.day_of_week : The day of the week with Monday=0, Sunday=6.
535
+ PeriodIndex.day_of_year : The ordinal day of the year.
536
+ PeriodIndex.dayofweek : The day of the week with Monday=0, Sunday=6.
537
+ PeriodIndex.dayofyear : The ordinal day of the year.
538
+ PeriodIndex.days_in_month : The number of days in the month.
539
+ PeriodIndex.daysinmonth : The number of days in the month.
540
+ PeriodIndex.weekday : The day of the week with Monday=0, Sunday=6.
541
+
542
+ Examples
543
+ --------
544
+ >>> idx = pd.PeriodIndex(['2020-01-31', '2020-02-28'], freq='D')
545
+ >>> idx.day
546
+ Index([31, 28], dtype='int64')
547
+ """,
548
+ )
549
+ hour = _field_accessor(
550
+ "hour",
551
+ """
552
+ The hour of the period.
553
+
554
+ Returns the hour component for each period in the index.
555
+
556
+ See Also
557
+ --------
558
+ PeriodIndex.minute : The minute of the period.
559
+ PeriodIndex.second : The second of the period.
560
+ PeriodIndex.to_timestamp : Cast to DatetimeArray/Index.
561
+
562
+ Examples
563
+ --------
564
+ >>> idx = pd.PeriodIndex(["2023-01-01 10:00", "2023-01-01 11:00"], freq='h')
565
+ >>> idx.hour
566
+ Index([10, 11], dtype='int64')
567
+ """,
568
+ )
569
+ minute = _field_accessor(
570
+ "minute",
571
+ """
572
+ The minute of the period.
573
+
574
+ Returns the minute component for each period in the index.
575
+
576
+ See Also
577
+ --------
578
+ PeriodIndex.hour : The hour of the period.
579
+ PeriodIndex.second : The second of the period.
580
+ PeriodIndex.to_timestamp : Cast to DatetimeArray/Index.
581
+
582
+ Examples
583
+ --------
584
+ >>> idx = pd.PeriodIndex(["2023-01-01 10:30:00",
585
+ ... "2023-01-01 11:50:00"], freq='min')
586
+ >>> idx.minute
587
+ Index([30, 50], dtype='int64')
588
+ """,
589
+ )
590
+ second = _field_accessor(
591
+ "second",
592
+ """
593
+ The second of the period.
594
+
595
+ Returns the second component for each period in the index.
596
+
597
+ See Also
598
+ --------
599
+ PeriodIndex.hour : The hour of the period.
600
+ PeriodIndex.minute : The minute of the period.
601
+ PeriodIndex.to_timestamp : Cast to DatetimeArray/Index.
602
+
603
+ Examples
604
+ --------
605
+ >>> idx = pd.PeriodIndex(["2023-01-01 10:00:30",
606
+ ... "2023-01-01 10:00:31"], freq='s')
607
+ >>> idx.second
608
+ Index([30, 31], dtype='int64')
609
+ """,
610
+ )
611
+ weekofyear = _field_accessor(
612
+ "week",
613
+ """
614
+ The week ordinal of the year.
615
+
616
+ Returns the week number (1 through 53) for each period in the index.
617
+
618
+ See Also
619
+ --------
620
+ PeriodIndex.day_of_week : The day of the week with Monday=0, Sunday=6.
621
+ PeriodIndex.dayofweek : The day of the week with Monday=0, Sunday=6.
622
+ PeriodIndex.week : The week ordinal of the year.
623
+ PeriodIndex.weekday : The day of the week with Monday=0, Sunday=6.
624
+ PeriodIndex.year : The year of the period.
625
+
626
+ Examples
627
+ --------
628
+ >>> idx = pd.PeriodIndex(["2023-01", "2023-02", "2023-03"], freq="M")
629
+ >>> idx.week # It can be written `weekofyear`
630
+ Index([5, 9, 13], dtype='int64')
631
+ """,
632
+ )
633
+ week = weekofyear
634
+ day_of_week = _field_accessor(
635
+ "day_of_week",
636
+ """
637
+ The day of the week with Monday=0, Sunday=6.
638
+
639
+ Returns the day-of-week component for each period, following the
640
+ Python convention where Monday is 0 and Sunday is 6.
641
+
642
+ See Also
643
+ --------
644
+ PeriodIndex.day : The days of the period.
645
+ PeriodIndex.day_of_week : The day of the week with Monday=0, Sunday=6.
646
+ PeriodIndex.day_of_year : The ordinal day of the year.
647
+ PeriodIndex.dayofweek : The day of the week with Monday=0, Sunday=6.
648
+ PeriodIndex.dayofyear : The ordinal day of the year.
649
+ PeriodIndex.week : The week ordinal of the year.
650
+ PeriodIndex.weekday : The day of the week with Monday=0, Sunday=6.
651
+ PeriodIndex.weekofyear : The week ordinal of the year.
652
+
653
+ Examples
654
+ --------
655
+ >>> idx = pd.PeriodIndex(["2023-01-01", "2023-01-02", "2023-01-03"], freq="D")
656
+ >>> idx.day_of_week
657
+ Index([6, 0, 1], dtype='int64')
658
+ """,
659
+ )
660
+
661
+ @property
662
+ def weekday(self):
663
+ """
664
+ The day of the week with Monday=0, Sunday=6.
665
+
666
+ .. deprecated:: 3.1.0
667
+ Use :attr:`PeriodIndex.day_of_week` instead.
668
+ """
669
+ # GH#12816
670
+ warnings.warn(
671
+ f"{type(self).__name__}.weekday is deprecated and will be removed "
672
+ "in a future version. Use PeriodIndex.day_of_week or "
673
+ "Series.dt.day_of_week instead.",
674
+ Pandas4Warning,
675
+ stacklevel=find_stack_level(),
676
+ )
677
+ return self.day_of_week
678
+
679
+ @property
680
+ def dayofweek(self):
681
+ """
682
+ The day of the week with Monday=0, Sunday=6.
683
+
684
+ .. deprecated:: 3.1.0
685
+ Use :attr:`PeriodIndex.day_of_week` instead.
686
+ """
687
+ from pandas.errors import Pandas4Warning
688
+ from pandas.util._exceptions import find_stack_level
689
+
690
+ warnings.warn(
691
+ "PeriodArray.dayofweek is deprecated and will be removed in a "
692
+ "future version. Use PeriodArray.day_of_week instead.",
693
+ Pandas4Warning,
694
+ stacklevel=find_stack_level(),
695
+ )
696
+ return self.day_of_week
697
+
698
+ day_of_year = _field_accessor(
699
+ "day_of_year",
700
+ """
701
+ The ordinal day of the year.
702
+
703
+ Returns the day-of-year component for each period, ranging from
704
+ 1 (January 1st) to 365 or 366 for leap years.
705
+
706
+ See Also
707
+ --------
708
+ PeriodIndex.day : The days of the period.
709
+ PeriodIndex.day_of_week : The day of the week with Monday=0, Sunday=6.
710
+ PeriodIndex.day_of_year : The ordinal day of the year.
711
+ PeriodIndex.dayofweek : The day of the week with Monday=0, Sunday=6.
712
+ PeriodIndex.dayofyear : The ordinal day of the year.
713
+ PeriodIndex.weekday : The day of the week with Monday=0, Sunday=6.
714
+ PeriodIndex.weekofyear : The week ordinal of the year.
715
+ PeriodIndex.year : The year of the period.
716
+
717
+ Examples
718
+ --------
719
+ >>> idx = pd.PeriodIndex(["2023-01-10", "2023-02-01", "2023-03-01"], freq="D")
720
+ >>> idx.day_of_year
721
+ Index([10, 32, 60], dtype='int64')
722
+
723
+ >>> idx = pd.PeriodIndex(["2023", "2024", "2025"], freq="Y")
724
+ >>> idx
725
+ PeriodIndex(['2023', '2024', '2025'], dtype='period[Y-DEC]')
726
+ >>> idx.day_of_year
727
+ Index([365, 366, 365], dtype='int64')
728
+ """,
729
+ )
730
+
731
+ @property
732
+ def dayofyear(self):
733
+ """
734
+ The ordinal day of the year.
735
+
736
+ .. deprecated:: 3.1.0
737
+ Use :attr:`PeriodIndex.day_of_year` instead.
738
+ """
739
+ from pandas.errors import Pandas4Warning
740
+ from pandas.util._exceptions import find_stack_level
741
+
742
+ warnings.warn(
743
+ "PeriodArray.dayofyear is deprecated and will be removed in a "
744
+ "future version. Use PeriodArray.day_of_year instead.",
745
+ Pandas4Warning,
746
+ stacklevel=find_stack_level(),
747
+ )
748
+ return self.day_of_year
749
+
750
+ quarter = _field_accessor(
751
+ "quarter",
752
+ """
753
+ The quarter of the date.
754
+
755
+ Returns the quarter (1 through 4) for each period in the index.
756
+
757
+ See Also
758
+ --------
759
+ PeriodIndex.qyear : Fiscal year the Period lies in according to its
760
+ starting-quarter.
761
+
762
+ Examples
763
+ --------
764
+ >>> idx = pd.PeriodIndex(["2023-01", "2023-02", "2023-03"], freq="M")
765
+ >>> idx.quarter
766
+ Index([1, 1, 1], dtype='int64')
767
+ """,
768
+ )
769
+ qyear = _field_accessor(
770
+ "qyear",
771
+ """
772
+ Fiscal year the Period lies in according to its starting-quarter.
773
+
774
+ The `year` and the `qyear` of the period will be the same if the fiscal
775
+ and calendar years are the same. When they are not, the fiscal year
776
+ can be different from the calendar year of the period.
777
+
778
+ Returns
779
+ -------
780
+ int
781
+ The fiscal year of the period.
782
+
783
+ See Also
784
+ --------
785
+ PeriodIndex.quarter : The quarter of the date.
786
+ PeriodIndex.year : The year of the period.
787
+
788
+ Examples
789
+ --------
790
+ If the natural and fiscal year are the same, `qyear` and `year` will
791
+ be the same.
792
+
793
+ >>> per = pd.Period('2018Q1', freq='Q')
794
+ >>> per.qyear
795
+ 2018
796
+ >>> per.year
797
+ 2018
798
+
799
+ If the fiscal year starts in April (`Q-MAR`), the first quarter of
800
+ 2018 will start in April 2017. `year` will then be 2017, but `qyear`
801
+ will be the fiscal year, 2018.
802
+
803
+ >>> per = pd.Period('2018Q1', freq='Q-MAR')
804
+ >>> per.start_time
805
+ Timestamp('2017-04-01 00:00:00')
806
+ >>> per.qyear
807
+ 2018
808
+ >>> per.year
809
+ 2017
810
+ """,
811
+ )
812
+
813
+ days_in_month = _field_accessor(
814
+ "days_in_month",
815
+ """
816
+ The number of days in the month.
817
+
818
+ Returns the total number of days in the month of each period,
819
+ accounting for leap years.
820
+
821
+ See Also
822
+ --------
823
+ PeriodIndex.day : The days of the period.
824
+ PeriodIndex.days_in_month : The number of days in the month.
825
+ PeriodIndex.daysinmonth : The number of days in the month.
826
+ PeriodIndex.month : The month as January=1, December=12.
827
+
828
+ Examples
829
+ --------
830
+ For Series:
831
+
832
+ >>> period = pd.period_range('2020-1-1 00:00', '2020-3-1 00:00', freq='M')
833
+ >>> s = pd.Series(period)
834
+ >>> s
835
+ 0 2020-01
836
+ 1 2020-02
837
+ 2 2020-03
838
+ dtype: period[M]
839
+ >>> s.dt.days_in_month
840
+ 0 31
841
+ 1 29
842
+ 2 31
843
+ dtype: int64
844
+
845
+ For PeriodIndex:
846
+
847
+ >>> idx = pd.PeriodIndex(["2023-01", "2023-02", "2023-03"], freq="M")
848
+ >>> idx.days_in_month # It can be also entered as `daysinmonth`
849
+ Index([31, 28, 31], dtype='int64')
850
+ """,
851
+ )
852
+
853
+ @property
854
+ def daysinmonth(self):
855
+ """
856
+ The number of days in the month.
857
+
858
+ .. deprecated:: 3.1.0
859
+ Use :attr:`PeriodIndex.days_in_month` instead.
860
+ """
861
+ from pandas.errors import Pandas4Warning
862
+ from pandas.util._exceptions import find_stack_level
863
+
864
+ warnings.warn(
865
+ "PeriodArray.daysinmonth is deprecated and will be removed in a "
866
+ "future version. Use PeriodArray.days_in_month instead.",
867
+ Pandas4Warning,
868
+ stacklevel=find_stack_level(),
869
+ )
870
+ return self.days_in_month
871
+
872
+ @property
873
+ def is_leap_year(self) -> npt.NDArray[np.bool_]:
874
+ """
875
+ Logical indicating if the date belongs to a leap year.
876
+
877
+ Returns a boolean array where ``True`` indicates the period's year
878
+ is a leap year.
879
+
880
+ See Also
881
+ --------
882
+ PeriodIndex.qyear : Fiscal year the Period lies in according to its
883
+ starting-quarter.
884
+ PeriodIndex.year : The year of the period.
885
+
886
+ Examples
887
+ --------
888
+ >>> idx = pd.PeriodIndex(["2023", "2024", "2025"], freq="Y")
889
+ >>> idx.is_leap_year
890
+ array([False, True, False])
891
+ """
892
+ return isleapyear_arr(np.asarray(self.year))
893
+
894
+ def to_timestamp(self, freq=None, how: str = "start") -> DatetimeArray:
895
+ """
896
+ Cast to DatetimeArray/Index.
897
+
898
+ If possible, gives microsecond-unit DatetimeArray/Index. Otherwise
899
+ gives nanosecond unit.
900
+
901
+ Parameters
902
+ ----------
903
+ freq : str or DateOffset, optional
904
+ Target frequency. The default is 'D' for week or longer,
905
+ 's' otherwise.
906
+ how : {'s', 'e', 'start', 'end'}
907
+ Whether to use the start or end of the time period being converted.
908
+
909
+ Returns
910
+ -------
911
+ DatetimeArray/Index
912
+ Timestamp representation of given Period-like object.
913
+
914
+ See Also
915
+ --------
916
+ PeriodIndex.day : The days of the period.
917
+ PeriodIndex.from_fields : Construct a PeriodIndex from fields
918
+ (year, month, day, etc.).
919
+ PeriodIndex.from_ordinals : Construct a PeriodIndex from ordinals.
920
+ PeriodIndex.hour : The hour of the period.
921
+ PeriodIndex.minute : The minute of the period.
922
+ PeriodIndex.month : The month as January=1, December=12.
923
+ PeriodIndex.second : The second of the period.
924
+ PeriodIndex.year : The year of the period.
925
+
926
+ Examples
927
+ --------
928
+ >>> idx = pd.PeriodIndex(["2023-01", "2023-02", "2023-03"], freq="M")
929
+ >>> idx.to_timestamp()
930
+ DatetimeIndex(['2023-01-01', '2023-02-01', '2023-03-01'],
931
+ dtype='datetime64[us]', freq='MS')
932
+
933
+ The frequency will not be inferred if the index contains less than
934
+ three elements, or if the values of index are not strictly monotonic:
935
+
936
+ >>> idx = pd.PeriodIndex(["2023-01", "2023-02"], freq="M")
937
+ >>> idx.to_timestamp()
938
+ DatetimeIndex(['2023-01-01', '2023-02-01'], dtype='datetime64[us]', freq=None)
939
+
940
+ >>> idx = pd.PeriodIndex(
941
+ ... ["2023-01", "2023-02", "2023-02", "2023-03"], freq="2M"
942
+ ... )
943
+ >>> idx.to_timestamp()
944
+ DatetimeIndex(['2023-01-01', '2023-02-01', '2023-02-01', '2023-03-01'],
945
+ dtype='datetime64[us]', freq=None)
946
+ """
947
+ from pandas.core.arrays import DatetimeArray
948
+
949
+ how = libperiod.validate_end_alias(how)
950
+
951
+ if self.freq.base == "ns" or freq == "ns":
952
+ unit = "ns"
953
+ else:
954
+ unit = "us"
955
+
956
+ end = how == "E"
957
+ if end:
958
+ if freq == "B" or self.freq == "B":
959
+ # roll forward to ensure we land on B date
960
+ adjust = Timedelta(1, unit="D") - Timedelta(1, unit=unit)
961
+ return self.to_timestamp(how="start") + adjust
962
+ else:
963
+ adjust = Timedelta(1, unit=unit)
964
+ return (self + self.freq).to_timestamp(how="start") - adjust
965
+
966
+ if freq is None:
967
+ freq_code = self._dtype._get_to_timestamp_base()
968
+ dtype = PeriodDtypeBase(freq_code, 1)
969
+ freq = dtype._freqstr
970
+ base = freq_code
971
+ else:
972
+ freq = Period._maybe_convert_freq(freq)
973
+ base = freq._period_dtype_code
974
+
975
+ new_parr = self.asfreq(freq, how=how)
976
+
977
+ new_data = libperiod.periodarr_to_dt64arr(new_parr.asi8, base)
978
+ dta = DatetimeArray._from_sequence(new_data, dtype=new_data.dtype)
979
+ assert dta.unit == unit
980
+
981
+ if self.freq.rule_code == "B":
982
+ # See if we can retain BDay instead of Day in cases where
983
+ # len(self) is too small for infer_freq to distinguish between them
984
+ diffs = libalgos.unique_deltas(self.asi8)
985
+ if len(diffs) == 1:
986
+ diff = diffs[0]
987
+ if diff == self.dtype._n:
988
+ dta._freq = self.freq
989
+ elif diff == 1:
990
+ dta._freq = self.freq.base
991
+ # TODO: other cases?
992
+ return dta
993
+ else:
994
+ dta._freq = to_offset(dta.inferred_freq)
995
+ if freq is not None:
996
+ freq = to_offset(freq)
997
+ if (
998
+ isinstance(dta.freq, Day)
999
+ and not isinstance(freq, Day)
1000
+ and Timedelta(freq) == Timedelta(days=dta.freq.n)
1001
+ ):
1002
+ dta._freq = freq
1003
+ return dta
1004
+
1005
+ # --------------------------------------------------------------------
1006
+
1007
+ def _box_func(self, x) -> Period | NaTType:
1008
+ return Period._from_ordinal(ordinal=x, dtype=self.dtype)
1009
+
1010
+ def asfreq(self, freq=None, how: str = "E") -> Self:
1011
+ """
1012
+ Convert the PeriodArray to the specified frequency `freq`.
1013
+
1014
+ Equivalent to applying :meth:`pandas.Period.asfreq` with the given arguments
1015
+ to each :class:`~pandas.Period` in this PeriodArray.
1016
+
1017
+ Parameters
1018
+ ----------
1019
+ freq : str
1020
+ A frequency.
1021
+ how : str {'E', 'S'}, default 'E'
1022
+ Whether the elements should be aligned to the end
1023
+ or start within pa period.
1024
+
1025
+ * 'E', 'END', or 'FINISH' for end,
1026
+ * 'S', 'START', or 'BEGIN' for start.
1027
+
1028
+ January 31st ('END') vs. January 1st ('START') for example.
1029
+
1030
+ Returns
1031
+ -------
1032
+ PeriodArray
1033
+ The transformed PeriodArray with the new frequency.
1034
+
1035
+ See Also
1036
+ --------
1037
+ PeriodIndex.asfreq: Convert each Period in a PeriodIndex to the given frequency.
1038
+ Period.asfreq : Convert a :class:`~pandas.Period` object to the given frequency.
1039
+
1040
+ Examples
1041
+ --------
1042
+ >>> pidx = pd.period_range("2010-01-01", "2015-01-01", freq="Y")
1043
+ >>> pidx
1044
+ PeriodIndex(['2010', '2011', '2012', '2013', '2014', '2015'],
1045
+ dtype='period[Y-DEC]')
1046
+
1047
+ >>> pidx.asfreq("M")
1048
+ PeriodIndex(['2010-12', '2011-12', '2012-12', '2013-12', '2014-12',
1049
+ '2015-12'], dtype='period[M]')
1050
+
1051
+ >>> pidx.asfreq("M", how="S")
1052
+ PeriodIndex(['2010-01', '2011-01', '2012-01', '2013-01', '2014-01',
1053
+ '2015-01'], dtype='period[M]')
1054
+ """
1055
+ how = libperiod.validate_end_alias(how)
1056
+ if isinstance(freq, BaseOffset) and hasattr(freq, "_period_dtype_code"):
1057
+ freq = PeriodDtype(freq)._freqstr
1058
+ freq = Period._maybe_convert_freq(freq)
1059
+
1060
+ base1 = self._dtype._dtype_code
1061
+ base2 = freq._period_dtype_code
1062
+
1063
+ asi8 = self.asi8
1064
+ # self.freq.n can't be negative or 0
1065
+ end = how == "E"
1066
+ if end:
1067
+ ordinal = asi8 + self.dtype._n - 1
1068
+ else:
1069
+ ordinal = asi8
1070
+
1071
+ new_data = period_asfreq_arr(ordinal, base1, base2, end)
1072
+
1073
+ if self._hasna:
1074
+ new_data[self._isnan] = iNaT
1075
+
1076
+ dtype = PeriodDtype(freq)
1077
+ return type(self)(new_data, dtype=dtype)
1078
+
1079
+ # ------------------------------------------------------------------
1080
+ # Rendering Methods
1081
+
1082
+ def _formatter(self, boxed: bool = False) -> Callable[[object], str]:
1083
+ if boxed:
1084
+ return str
1085
+ return "'{}'".format
1086
+
1087
+ def _format_native_types(
1088
+ self, *, na_rep: str | float = "NaT", date_format=None, **kwargs
1089
+ ) -> npt.NDArray[np.object_]:
1090
+ """
1091
+ actually format my specific types
1092
+ """
1093
+ return libperiod.period_array_strftime(
1094
+ self.asi8, self.dtype._dtype_code, na_rep, date_format
1095
+ )
1096
+
1097
+ # ------------------------------------------------------------------
1098
+
1099
+ def astype(self, dtype, copy: bool = True):
1100
+ # We handle Period[T] -> Period[U]
1101
+ # Our parent handles everything else.
1102
+ dtype = pandas_dtype(dtype)
1103
+ if dtype == self._dtype:
1104
+ if not copy:
1105
+ return self
1106
+ else:
1107
+ return self.copy()
1108
+ if isinstance(dtype, PeriodDtype):
1109
+ return self.asfreq(dtype.freq)
1110
+
1111
+ if lib.is_np_dtype(dtype, "M") or isinstance(dtype, DatetimeTZDtype):
1112
+ # GH#45038 match PeriodIndex behavior.
1113
+ tz = getattr(dtype, "tz", None)
1114
+ unit = dtl.dtype_to_unit(dtype)
1115
+ # error: Argument 1 to "as_unit" of "TimelikeOps" has incompatible
1116
+ # type "str"; expected "Literal['s', 'ms', 'us', 'ns']" [arg-type]
1117
+ return self.to_timestamp().tz_localize(tz).as_unit(unit) # type: ignore[arg-type]
1118
+
1119
+ return super().astype(dtype, copy=copy)
1120
+
1121
+ def searchsorted(
1122
+ self,
1123
+ value: NumpyValueArrayLike | ExtensionArray,
1124
+ side: Literal["left", "right"] = "left",
1125
+ sorter: NumpySorter | None = None,
1126
+ ) -> npt.NDArray[np.intp] | np.intp:
1127
+ npvalue = self._validate_setitem_value(value).view("M8[ns]")
1128
+
1129
+ # Cast to M8 to get datetime-like NaT placement,
1130
+ # similar to dtl._period_dispatch
1131
+ m8arr = self._ndarray.view("M8[ns]")
1132
+ return m8arr.searchsorted(npvalue, side=side, sorter=sorter)
1133
+
1134
+ def _pad_or_backfill(
1135
+ self,
1136
+ *,
1137
+ method: FillnaOptions,
1138
+ limit: int | None = None,
1139
+ limit_area: Literal["inside", "outside"] | None = None,
1140
+ copy: bool = True,
1141
+ ) -> Self:
1142
+ # view as dt64 so we get treated as timelike in core.missing,
1143
+ # similar to dtl._period_dispatch
1144
+ dta = self.view("M8[ns]")
1145
+ result = dta._pad_or_backfill(
1146
+ method=method, limit=limit, limit_area=limit_area, copy=copy
1147
+ )
1148
+ if copy:
1149
+ return cast("Self", result.view(self.dtype))
1150
+ else:
1151
+ return self
1152
+
1153
+ # ------------------------------------------------------------------
1154
+ # Arithmetic Methods
1155
+
1156
+ def _addsub_int_array_or_scalar(
1157
+ self, other: np.ndarray | int, op: Callable[[Any, Any], Any]
1158
+ ) -> Self:
1159
+ """
1160
+ Add or subtract array of integers.
1161
+
1162
+ Parameters
1163
+ ----------
1164
+ other : np.ndarray[int64] or int
1165
+ op : {operator.add, operator.sub}
1166
+
1167
+ Returns
1168
+ -------
1169
+ result : PeriodArray
1170
+ """
1171
+ assert op in [operator.add, operator.sub]
1172
+ if op is operator.sub:
1173
+ other = -other
1174
+ res_values = add_overflowsafe(self.asi8, np.asarray(other, dtype="i8"))
1175
+ return type(self)(res_values, dtype=self.dtype)
1176
+
1177
+ def _add_offset(self, other: BaseOffset):
1178
+ assert not isinstance(other, Tick)
1179
+
1180
+ if isinstance(other, Day):
1181
+ return self + np.timedelta64(other.n, "D")
1182
+
1183
+ self._require_matching_unit(other._period_unit, base=True)
1184
+ return self._addsub_int_array_or_scalar(other.n, operator.add)
1185
+
1186
+ # TODO: can we de-duplicate with Period._add_timedeltalike_scalar?
1187
+ def _add_timedeltalike_scalar(self, other):
1188
+ """
1189
+ Parameters
1190
+ ----------
1191
+ other : timedelta, Tick, np.timedelta64
1192
+
1193
+ Returns
1194
+ -------
1195
+ PeriodArray
1196
+ """
1197
+ if not isinstance(self.freq, (Tick, Day)):
1198
+ # We cannot add timedelta-like to non-tick PeriodArray
1199
+ raise raise_on_incompatible(self, other)
1200
+
1201
+ if isna(other):
1202
+ # i.e. np.timedelta64("NaT")
1203
+ return super()._add_timedeltalike_scalar(other)
1204
+
1205
+ if isinstance(other, Day):
1206
+ td = np.asarray(Timedelta(days=other.n).asm8)
1207
+ else:
1208
+ td = np.asarray(Timedelta(other).asm8)
1209
+ return self._add_timedelta_arraylike(td)
1210
+
1211
+ def _add_timedelta_arraylike(
1212
+ self, other: TimedeltaArray | npt.NDArray[np.timedelta64]
1213
+ ) -> Self:
1214
+ """
1215
+ Parameters
1216
+ ----------
1217
+ other : TimedeltaArray or ndarray[timedelta64]
1218
+
1219
+ Returns
1220
+ -------
1221
+ PeriodArray
1222
+ """
1223
+ if not self.dtype._is_tick_like():
1224
+ # We cannot add timedelta-like to non-tick PeriodArray
1225
+ raise TypeError(
1226
+ f"Cannot add or subtract timedelta64[ns] dtype from {self.dtype}"
1227
+ )
1228
+
1229
+ dtype = np.dtype(f"m8[{self.dtype._td64_unit}]")
1230
+
1231
+ # Similar to _check_timedeltalike_freq_compat, but we raise with a
1232
+ # more specific exception message if necessary.
1233
+ try:
1234
+ delta = astype_overflowsafe(
1235
+ np.asarray(other), dtype=dtype, copy=False, round_ok=False
1236
+ )
1237
+ except ValueError as err:
1238
+ # e.g. if we have minutes freq and try to add 30s
1239
+ # "Cannot losslessly convert units"
1240
+ raise IncompatibleFrequency(
1241
+ "Cannot add/subtract timedelta-like from PeriodArray that is "
1242
+ "not an integer multiple of the PeriodArray's freq."
1243
+ ) from err
1244
+
1245
+ res_values = add_overflowsafe(self.asi8, np.asarray(delta.view("i8")))
1246
+ return type(self)(res_values, dtype=self.dtype)
1247
+
1248
+ def _check_timedeltalike_freq_compat(self, other):
1249
+ """
1250
+ Arithmetic operations with timedelta-like scalars or array `other`
1251
+ are only valid if `other` is an integer multiple of `self.freq`.
1252
+ If the operation is valid, find that integer multiple. Otherwise,
1253
+ raise because the operation is invalid.
1254
+
1255
+ Parameters
1256
+ ----------
1257
+ other : timedelta, np.timedelta64, Tick,
1258
+ ndarray[timedelta64], TimedeltaArray, TimedeltaIndex
1259
+
1260
+ Returns
1261
+ -------
1262
+ multiple : int or ndarray[int64]
1263
+
1264
+ Raises
1265
+ ------
1266
+ IncompatibleFrequency
1267
+ """
1268
+ assert self.dtype._is_tick_like() # checked by calling function
1269
+
1270
+ dtype = np.dtype(f"m8[{self.dtype._td64_unit}]")
1271
+
1272
+ if isinstance(other, (timedelta, np.timedelta64, Tick)):
1273
+ td = np.asarray(Timedelta(other).asm8)
1274
+ else:
1275
+ td = np.asarray(other)
1276
+
1277
+ try:
1278
+ delta = astype_overflowsafe(td, dtype=dtype, copy=False, round_ok=False)
1279
+ except ValueError as err:
1280
+ raise raise_on_incompatible(self, other) from err
1281
+
1282
+ delta = delta.view("i8")
1283
+ return lib.item_from_zerodim(delta)
1284
+
1285
+ # ------------------------------------------------------------------
1286
+ # Reductions
1287
+
1288
+ def _reduce(
1289
+ self, name: str, *, skipna: bool = True, keepdims: bool = False, **kwargs
1290
+ ):
1291
+ result = super()._reduce(name, skipna=skipna, keepdims=keepdims, **kwargs)
1292
+ if keepdims and isinstance(result, np.ndarray):
1293
+ return self._from_sequence(result, dtype=self.dtype)
1294
+ return result
1295
+
1296
+
1297
+ def raise_on_incompatible(left, right) -> IncompatibleFrequency:
1298
+ """
1299
+ Helper function to render a consistent error message when raising
1300
+ IncompatibleFrequency.
1301
+
1302
+ Parameters
1303
+ ----------
1304
+ left : PeriodArray
1305
+ right : None, DateOffset, Period, ndarray, or timedelta-like
1306
+
1307
+ Returns
1308
+ -------
1309
+ IncompatibleFrequency
1310
+ Exception to be raised by the caller.
1311
+ """
1312
+ # GH#24283 error message format depends on whether right is scalar
1313
+ if isinstance(right, (np.ndarray, ABCTimedeltaArray)) or right is None:
1314
+ other_freq = None
1315
+ elif isinstance(right, BaseOffset):
1316
+ with warnings.catch_warnings():
1317
+ warnings.filterwarnings(
1318
+ "ignore", r"PeriodDtype\[B\] is deprecated", category=FutureWarning
1319
+ )
1320
+ other_freq = PeriodDtype(right)._freqstr
1321
+ elif isinstance(right, (ABCPeriodIndex, PeriodArray, Period)):
1322
+ other_freq = right.freqstr
1323
+ else:
1324
+ other_freq = delta_to_tick(Timedelta(right)).freqstr
1325
+
1326
+ own_freq = PeriodDtype(left.freq)._freqstr
1327
+ msg = DIFFERENT_FREQ.format(
1328
+ cls=type(left).__name__, own_freq=own_freq, other_freq=other_freq
1329
+ )
1330
+ return IncompatibleFrequency(msg)
1331
+
1332
+
1333
+ # -------------------------------------------------------------------
1334
+ # Constructor Helpers
1335
+
1336
+
1337
+ def period_array(
1338
+ data: Sequence[Period | str | None] | AnyArrayLike,
1339
+ dtype: PeriodDtype | None = None,
1340
+ ) -> PeriodArray:
1341
+ """
1342
+ Construct a new PeriodArray from a sequence of Period scalars.
1343
+
1344
+ Parameters
1345
+ ----------
1346
+ data : Sequence of Period objects
1347
+ A sequence of Period objects. These are required to all have
1348
+ the same ``freq.`` Missing values can be indicated by ``None``
1349
+ or ``pandas.NaT``.
1350
+ dtype : PeriodDtype or None, default None
1351
+ The dtype for the array. If not specified, is inferred from the data.
1352
+
1353
+ Returns
1354
+ -------
1355
+ PeriodArray
1356
+
1357
+ See Also
1358
+ --------
1359
+ PeriodArray
1360
+ pandas.PeriodIndex
1361
+
1362
+ Examples
1363
+ --------
1364
+ >>> period_array([pd.Period("2017", freq="Y"), pd.Period("2018", freq="Y")])
1365
+ <PeriodArray>
1366
+ ['2017', '2018']
1367
+ Length: 2, dtype: period[Y-DEC]
1368
+
1369
+ >>> period_array([pd.Period("2017", freq="Y"), pd.Period("2018", freq="Y"), pd.NaT])
1370
+ <PeriodArray>
1371
+ ['2017', '2018', 'NaT']
1372
+ Length: 3, dtype: period[Y-DEC]
1373
+
1374
+ Integers that look like years are handled
1375
+
1376
+ >>> period_array([2000, 2001, 2002], dtype=PeriodDtype("D"))
1377
+ <PeriodArray>
1378
+ ['2000-01-01', '2001-01-01', '2002-01-01']
1379
+ Length: 3, dtype: period[D]
1380
+
1381
+ Datetime-like strings may also be passed
1382
+
1383
+ >>> period_array(
1384
+ ... ["2000-Q1", "2000-Q2", "2000-Q3", "2000-Q4"], dtype=PeriodDtype("Q")
1385
+ ... )
1386
+ <PeriodArray>
1387
+ ['2000Q1', '2000Q2', '2000Q3', '2000Q4']
1388
+ Length: 4, dtype: period[Q-DEC]
1389
+ """
1390
+ return PeriodArray._from_sequence(data, dtype=dtype)
1391
+
1392
+
1393
+ def validate_dtype_freq(
1394
+ dtype: DtypeObj | None, dtype2: DtypeObj | None
1395
+ ) -> PeriodDtype | None:
1396
+ """
1397
+ If a dtype is specified both directly and indirectly via a `freq` (dtype2),
1398
+ ensure they match. If only the latter is available, return the indirect dtype.
1399
+
1400
+ Parameters
1401
+ ----------
1402
+ dtype : dtype
1403
+ dtype2 : PeriodDtype or None
1404
+ Dtype derived from a `freq` passed to the caller.
1405
+
1406
+ Returns
1407
+ -------
1408
+ PeriodDtype or None
1409
+
1410
+ Raises
1411
+ ------
1412
+ ValueError : non-period dtype
1413
+ IncompatibleFrequency : mismatch between dtype and freq
1414
+ """
1415
+ if dtype is not None:
1416
+ if not isinstance(dtype, PeriodDtype):
1417
+ raise ValueError("dtype must be PeriodDtype")
1418
+ if dtype2 is not None and dtype != dtype2:
1419
+ raise IncompatibleFrequency("specified freq and dtype are different")
1420
+
1421
+ elif dtype2 is not None:
1422
+ if not isinstance(dtype2, PeriodDtype):
1423
+ raise ValueError("dtype must be PeriodDtype")
1424
+ dtype = dtype2
1425
+
1426
+ return dtype
1427
+
1428
+
1429
+ def dt64arr_to_periodarr(
1430
+ data, freq, tz=None
1431
+ ) -> tuple[npt.NDArray[np.int64], BaseOffset]:
1432
+ """
1433
+ Convert a datetime-like array to values Period ordinals.
1434
+
1435
+ Parameters
1436
+ ----------
1437
+ data : Union[Series[datetime64[ns]], DatetimeIndex, ndarray[datetime64ns]]
1438
+ freq : Optional[Union[str, Tick]]
1439
+ Must match the `freq` on the `data` if `data` is a DatetimeIndex
1440
+ or Series.
1441
+ tz : Optional[tzinfo]
1442
+
1443
+ Returns
1444
+ -------
1445
+ ordinals : ndarray[int64]
1446
+ freq : Tick
1447
+ The frequency extracted from the Series or DatetimeIndex if that's
1448
+ used.
1449
+
1450
+ """
1451
+ if not isinstance(data.dtype, np.dtype) or data.dtype.kind != "M":
1452
+ raise ValueError(f"Wrong dtype: {data.dtype}")
1453
+
1454
+ if freq is None:
1455
+ if isinstance(data, ABCIndex):
1456
+ data, freq = data._values, data.freq
1457
+ elif isinstance(data, ABCSeries):
1458
+ data, freq = data._values, data.dt.freq
1459
+
1460
+ elif isinstance(data, (ABCIndex, ABCSeries)):
1461
+ data = data._values
1462
+
1463
+ reso = get_unit_from_dtype(data.dtype)
1464
+ freq = Period._maybe_convert_freq(freq)
1465
+ base = freq._period_dtype_code
1466
+ return c_dt64arr_to_periodarr(data.view("i8"), base, tz, reso=reso), freq
1467
+
1468
+
1469
+ def _get_ordinal_range(start, end, periods, freq, mult: int = 1):
1470
+ if com.count_not_none(start, end, periods) != 2:
1471
+ raise ValueError(
1472
+ "Of the three parameters: start, end, and periods, "
1473
+ "exactly two must be specified"
1474
+ )
1475
+
1476
+ if freq is not None:
1477
+ freq = to_offset(freq, is_period=True)
1478
+ mult = freq.n
1479
+
1480
+ if start is not None:
1481
+ start = Period(start, freq)
1482
+ if end is not None:
1483
+ end = Period(end, freq)
1484
+
1485
+ is_start_per = isinstance(start, Period)
1486
+ is_end_per = isinstance(end, Period)
1487
+
1488
+ if is_start_per and is_end_per and start.freq != end.freq:
1489
+ raise ValueError("start and end must have same freq")
1490
+ if start is NaT or end is NaT:
1491
+ raise ValueError("start and end must not be NaT")
1492
+
1493
+ if freq is None:
1494
+ if is_start_per:
1495
+ freq = start.freq
1496
+ elif is_end_per:
1497
+ freq = end.freq
1498
+ else: # pragma: no cover
1499
+ raise ValueError("Could not infer freq from start/end")
1500
+ mult = freq.n
1501
+
1502
+ if periods is not None:
1503
+ periods = periods * mult
1504
+ if start is None:
1505
+ data = np.arange(
1506
+ end.ordinal - periods + mult, end.ordinal + 1, mult, dtype=np.int64
1507
+ )
1508
+ else:
1509
+ data = np.arange(
1510
+ start.ordinal, start.ordinal + periods, mult, dtype=np.int64
1511
+ )
1512
+ else:
1513
+ data = np.arange(start.ordinal, end.ordinal + 1, mult, dtype=np.int64)
1514
+
1515
+ return data, freq
1516
+
1517
+
1518
+ def _range_from_fields(
1519
+ year=None,
1520
+ month=None,
1521
+ quarter=None,
1522
+ day=None,
1523
+ hour=None,
1524
+ minute=None,
1525
+ second=None,
1526
+ freq=None,
1527
+ ) -> tuple[np.ndarray, BaseOffset]:
1528
+ if hour is None:
1529
+ hour = 0
1530
+ if minute is None:
1531
+ minute = 0
1532
+ if second is None:
1533
+ second = 0
1534
+ if day is None:
1535
+ day = 1
1536
+
1537
+ ordinals = []
1538
+
1539
+ if quarter is not None:
1540
+ if freq is None:
1541
+ freq = to_offset("Q", is_period=True)
1542
+ base = cast("int", FreqGroup.FR_QTR.value)
1543
+ else:
1544
+ freq = to_offset(freq, is_period=True)
1545
+ base = libperiod.freq_to_dtype_code(freq)
1546
+ if base != cast("int", FreqGroup.FR_QTR.value):
1547
+ raise AssertionError("base must equal FR_QTR")
1548
+
1549
+ freqstr = freq.freqstr
1550
+ year, quarter = _make_field_arrays(year, quarter)
1551
+ for y, q in zip(year, quarter, strict=True):
1552
+ calendar_year, calendar_month = parsing.quarter_to_myear(y, q, freqstr)
1553
+ val = libperiod.period_ordinal(
1554
+ calendar_year, calendar_month, 1, 1, 1, 1, 0, 0, base
1555
+ )
1556
+ ordinals.append(val)
1557
+ else:
1558
+ freq = to_offset(freq, is_period=True)
1559
+ base = libperiod.freq_to_dtype_code(freq)
1560
+ arrays = _make_field_arrays(year, month, day, hour, minute, second)
1561
+ for y, mth, d, h, mn, s in zip(*arrays, strict=True):
1562
+ ordinals.append(libperiod.period_ordinal(y, mth, d, h, mn, s, 0, 0, base))
1563
+
1564
+ return np.array(ordinals, dtype=np.int64), freq
1565
+
1566
+
1567
+ def _make_field_arrays(*fields) -> list[np.ndarray]:
1568
+ length = None
1569
+ for x in fields:
1570
+ if isinstance(x, (list, np.ndarray, ABCSeries)):
1571
+ if length is not None and len(x) != length:
1572
+ raise ValueError("Mismatched Period array lengths")
1573
+ if length is None:
1574
+ length = len(x)
1575
+
1576
+ # error: Argument 2 to "repeat" has incompatible type "Optional[int]"; expected
1577
+ # "Union[Union[int, integer[Any]], Union[bool, bool_], ndarray, Sequence[Union[int,
1578
+ # integer[Any]]], Sequence[Union[bool, bool_]], Sequence[Sequence[Any]]]"
1579
+ return [
1580
+ (
1581
+ np.asarray(x)
1582
+ if isinstance(x, (np.ndarray, list, ABCSeries))
1583
+ else np.repeat(x, length) # type: ignore[arg-type]
1584
+ )
1585
+ for x in fields
1586
+ ]