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,2140 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import (
4
+ TYPE_CHECKING,
5
+ Any,
6
+ Literal,
7
+ Self,
8
+ cast,
9
+ overload,
10
+ )
11
+ import warnings
12
+
13
+ import numpy as np
14
+
15
+ from pandas._config import (
16
+ is_nan_na,
17
+ using_python_scalars,
18
+ )
19
+
20
+ from pandas._libs import (
21
+ algos as libalgos,
22
+ lib,
23
+ missing as libmissing,
24
+ )
25
+ from pandas._libs.tslibs import is_supported_dtype
26
+ from pandas.compat import (
27
+ IS64,
28
+ is_platform_windows,
29
+ )
30
+ from pandas.errors import (
31
+ AbstractMethodError,
32
+ Pandas4Warning,
33
+ )
34
+ from pandas.util._exceptions import find_stack_level
35
+
36
+ from pandas.core.dtypes.astype import astype_is_view
37
+ from pandas.core.dtypes.base import ExtensionDtype
38
+ from pandas.core.dtypes.cast import (
39
+ construct_1d_object_array_from_listlike,
40
+ maybe_downcast_to_dtype,
41
+ )
42
+ from pandas.core.dtypes.common import (
43
+ is_bool,
44
+ is_integer_dtype,
45
+ is_list_like,
46
+ is_scalar,
47
+ is_string_dtype,
48
+ pandas_dtype,
49
+ )
50
+ from pandas.core.dtypes.dtypes import (
51
+ ArrowDtype,
52
+ BaseMaskedDtype,
53
+ )
54
+ from pandas.core.dtypes.missing import (
55
+ array_equivalent,
56
+ is_valid_na_for_dtype,
57
+ isna,
58
+ notna,
59
+ )
60
+
61
+ from pandas.core import (
62
+ algorithms as algos,
63
+ arraylike,
64
+ missing,
65
+ nanops,
66
+ ops,
67
+ )
68
+ from pandas.core.algorithms import (
69
+ factorize_array,
70
+ isin,
71
+ mode,
72
+ take,
73
+ )
74
+ from pandas.core.array_algos import (
75
+ masked_accumulations,
76
+ masked_reductions,
77
+ )
78
+ from pandas.core.array_algos.quantile import quantile_with_mask
79
+ from pandas.core.array_algos.transforms import shift
80
+ from pandas.core.arraylike import OpsMixin
81
+ from pandas.core.arrays._utils import to_numpy_dtype_inference
82
+ from pandas.core.arrays.base import ExtensionArray
83
+ from pandas.core.construction import (
84
+ array as pd_array,
85
+ ensure_wrapped_if_datetimelike,
86
+ extract_array,
87
+ )
88
+ from pandas.core.indexers import (
89
+ check_array_indexer,
90
+ getitem_returns_view,
91
+ )
92
+ from pandas.core.ops import invalid_comparison
93
+ from pandas.core.util.hashing import hash_array
94
+
95
+ if TYPE_CHECKING:
96
+ from collections.abc import Callable
97
+ from collections.abc import (
98
+ Iterator,
99
+ Sequence,
100
+ )
101
+ from pandas import Series
102
+ from pandas.core.arrays import BooleanArray
103
+ from pandas._typing import (
104
+ Dtype,
105
+ NumpySorter,
106
+ NumpyValueArrayLike,
107
+ ArrayLike,
108
+ AstypeArg,
109
+ AxisInt,
110
+ DtypeObj,
111
+ FillnaOptions,
112
+ InterpolateOptions,
113
+ NpDtype,
114
+ PositionalIndexer,
115
+ Scalar,
116
+ ScalarIndexer,
117
+ SequenceIndexer,
118
+ Shape,
119
+ npt,
120
+ )
121
+ from pandas._libs.missing import NAType
122
+ from pandas.core.arrays import FloatingArray
123
+
124
+ from pandas.compat.numpy import function as nv
125
+
126
+
127
+ class BaseMaskedArray(OpsMixin, ExtensionArray):
128
+ """
129
+ Base class for masked arrays (which use _data and _mask to store the data).
130
+
131
+ numpy based
132
+ """
133
+
134
+ # our underlying data and mask are each ndarrays
135
+ _data: np.ndarray
136
+ _mask: npt.NDArray[np.bool_]
137
+
138
+ @classmethod
139
+ def _simple_new(cls, values: np.ndarray, mask: npt.NDArray[np.bool_]) -> Self:
140
+ result = BaseMaskedArray.__new__(cls)
141
+ result._data = values
142
+ result._mask = mask
143
+ return result
144
+
145
+ def __init__(
146
+ self, values: np.ndarray, mask: npt.NDArray[np.bool_], copy: bool = False
147
+ ) -> None:
148
+ # values is supposed to already be validated in the subclass
149
+ if not (isinstance(mask, np.ndarray) and mask.dtype == np.bool_):
150
+ raise TypeError(
151
+ "mask should be boolean numpy array. Use "
152
+ "the 'pd.array' function instead"
153
+ )
154
+ if values.shape != mask.shape:
155
+ raise ValueError("values.shape must match mask.shape")
156
+
157
+ if copy:
158
+ values = values.copy()
159
+ mask = mask.copy()
160
+
161
+ self._data = values
162
+ self._mask = mask
163
+
164
+ @classmethod
165
+ def _from_sequence(cls, scalars, *, dtype=None, copy: bool = False) -> Self:
166
+ values, mask = cls._coerce_to_array(scalars, dtype=dtype, copy=copy)
167
+ return cls(values, mask)
168
+
169
+ def _cast_pointwise_result(self, values) -> ArrayLike:
170
+ if isna(values).all():
171
+ return type(self)._from_sequence(values, dtype=self.dtype)
172
+ if not (isinstance(values, np.ndarray) and values.dtype == object):
173
+ values = construct_1d_object_array_from_listlike(values)
174
+ result = lib.maybe_convert_objects(values, convert_to_nullable_dtype=True)
175
+ lkind = self.dtype.kind
176
+ rkind = result.dtype.kind
177
+ if (lkind in "iu" and rkind in "iu") or (lkind == rkind == "f"):
178
+ result = cast("BaseMaskedArray", result)
179
+ new_data = maybe_downcast_to_dtype(
180
+ result._data, dtype=self.dtype.numpy_dtype
181
+ )
182
+ result = type(result)(new_data, result._mask)
183
+ return result
184
+
185
+ @classmethod
186
+ def _empty(cls, shape: Shape, dtype: ExtensionDtype) -> Self:
187
+ """
188
+ Create an ExtensionArray with the given shape and dtype.
189
+
190
+ See also
191
+ --------
192
+ ExtensionDtype.empty
193
+ ExtensionDtype.empty is the 'official' public version of this API.
194
+ """
195
+ dtype = cast("BaseMaskedDtype", dtype)
196
+ values: np.ndarray = np.empty(shape, dtype=dtype.type)
197
+ values.fill(dtype._internal_fill_value)
198
+ mask = np.ones(shape, dtype=bool)
199
+ result = cls(values, mask)
200
+ if not isinstance(result, cls) or dtype != result.dtype:
201
+ raise NotImplementedError(
202
+ f"Default 'empty' implementation is invalid for dtype='{dtype}'"
203
+ )
204
+ return result
205
+
206
+ def _formatter(self, boxed: bool = False) -> Callable[[Any], str | None]:
207
+ # NEP 51: https://github.com/numpy/numpy/pull/22449
208
+ return str
209
+
210
+ @property
211
+ def dtype(self) -> BaseMaskedDtype:
212
+ raise AbstractMethodError(self)
213
+
214
+ @overload
215
+ def __getitem__(self, item: ScalarIndexer) -> Any: ...
216
+
217
+ @overload
218
+ def __getitem__(self, item: SequenceIndexer) -> Self: ...
219
+
220
+ def __getitem__(self, item: PositionalIndexer) -> Self | Any:
221
+ item = check_array_indexer(self, item)
222
+
223
+ newmask = self._mask[item]
224
+ if is_bool(newmask):
225
+ # This is a scalar indexing
226
+ if newmask:
227
+ return self.dtype.na_value
228
+ return self._data[item]
229
+
230
+ result = self._simple_new(self._data[item], newmask)
231
+ if getitem_returns_view(self, item):
232
+ result._readonly = self._readonly
233
+ return result
234
+
235
+ def _pad_or_backfill(
236
+ self,
237
+ *,
238
+ method: FillnaOptions,
239
+ limit: int | None = None,
240
+ limit_area: Literal["inside", "outside"] | None = None,
241
+ copy: bool = True,
242
+ ) -> Self:
243
+ mask = self._mask
244
+
245
+ if mask.any():
246
+ func = missing.get_fill_func(method, ndim=self.ndim)
247
+
248
+ npvalues = self._data.T
249
+ new_mask = mask.T
250
+ if copy:
251
+ npvalues = npvalues.copy()
252
+ new_mask = new_mask.copy()
253
+ elif limit_area is not None:
254
+ mask = mask.copy()
255
+ func(npvalues, limit=limit, mask=new_mask)
256
+
257
+ if limit_area is not None and not mask.all():
258
+ mask = mask.T
259
+ neg_mask = ~mask
260
+ first = neg_mask.argmax()
261
+ last = len(neg_mask) - neg_mask[::-1].argmax() - 1
262
+ if limit_area == "inside":
263
+ new_mask[:first] |= mask[:first]
264
+ new_mask[last + 1 :] |= mask[last + 1 :]
265
+ elif limit_area == "outside":
266
+ new_mask[first + 1 : last] |= mask[first + 1 : last]
267
+
268
+ if copy:
269
+ return self._simple_new(npvalues.T, new_mask.T)
270
+ else:
271
+ return self
272
+ elif copy:
273
+ new_values = self.copy()
274
+ else:
275
+ new_values = self
276
+ return new_values
277
+
278
+ def fillna(self, value, limit: int | None = None, copy: bool = True) -> Self:
279
+ """
280
+ Fill NA/NaN values using the specified method.
281
+
282
+ Parameters
283
+ ----------
284
+ value : scalar, array-like
285
+ If a scalar value is passed it is used to fill all missing values.
286
+ Alternatively, an array-like "value" can be given. It's expected
287
+ that the array-like have the same length as 'self'.
288
+ limit : int, default None
289
+ The maximum number of entries where NA values will be filled.
290
+ copy : bool, default True
291
+ Whether to make a copy of the data before filling. If False, then
292
+ the original should be modified and no new memory should be allocated.
293
+ For ExtensionArray subclasses that cannot do this, it is at the
294
+ author's discretion whether to ignore "copy=False" or to raise.
295
+
296
+ Returns
297
+ -------
298
+ ExtensionArray
299
+ With NA/NaN filled.
300
+
301
+ See Also
302
+ --------
303
+ api.extensions.ExtensionArray.dropna : Return ExtensionArray without
304
+ NA values.
305
+ api.extensions.ExtensionArray.isna : A 1-D array indicating if
306
+ each value is missing.
307
+
308
+ Examples
309
+ --------
310
+ >>> arr = pd.array([np.nan, np.nan, 2, 3, np.nan, np.nan])
311
+ >>> arr.fillna(0)
312
+ <IntegerArray>
313
+ [0, 0, 2, 3, 0, 0]
314
+ Length: 6, dtype: Int64
315
+ """
316
+ mask = self._mask
317
+
318
+ # Fast path: single-pass Cython for scalar fill values. GH#42147
319
+ # Skip when fill value is itself NA — filling NAs with NA is a no-op,
320
+ # and the Cython path would incorrectly clear mask bits.
321
+ # When NaN and NA are distinguished (is_nan_na() is False), float NaN
322
+ # is a valid fill value, not NA.
323
+ value_is_na = is_valid_na_for_dtype(value, self.dtype) and not (
324
+ lib.is_float(value) and not is_nan_na()
325
+ )
326
+ if lib.is_scalar(value) and not value_is_na:
327
+ if not mask.any():
328
+ return self.copy() if copy else self[:]
329
+ try:
330
+ casted = self._validate_setitem_value(value)
331
+ except TypeError:
332
+ pass
333
+ else:
334
+ if copy:
335
+ new_data = self._data.copy()
336
+ new_mask = mask.copy()
337
+ else:
338
+ if self._readonly:
339
+ raise ValueError("Cannot modify read-only array")
340
+ new_data = self._data
341
+ new_mask = mask
342
+
343
+ if new_data.dtype.kind == "b":
344
+ # bool arrays need uint8 view for Cython memoryview
345
+ libalgos.scalar_fillna_inplace(
346
+ new_data.view("u1"),
347
+ np.uint8(casted),
348
+ mask=new_mask.view("u1"),
349
+ limit=limit,
350
+ )
351
+ else:
352
+ libalgos.scalar_fillna_inplace(
353
+ new_data,
354
+ casted,
355
+ mask=new_mask.view("u1"),
356
+ limit=limit,
357
+ )
358
+
359
+ return type(self)(new_data, new_mask, copy=False)
360
+
361
+ if limit is not None and limit < len(self):
362
+ modify = mask.cumsum() > limit
363
+ if modify.any():
364
+ # Only copy mask if necessary
365
+ mask = mask.copy()
366
+ mask[modify] = False
367
+
368
+ value = missing.check_value_size(value, mask, len(self))
369
+
370
+ if mask.any():
371
+ # fill with value
372
+ if copy:
373
+ new_values = self.copy()
374
+ else:
375
+ new_values = self[:]
376
+ new_values[mask] = value
377
+ elif copy:
378
+ new_values = self.copy()
379
+ else:
380
+ new_values = self[:]
381
+ return new_values
382
+
383
+ @classmethod
384
+ def _coerce_to_array(
385
+ cls, values, *, dtype: DtypeObj, copy: bool = False
386
+ ) -> tuple[np.ndarray, np.ndarray]:
387
+ raise AbstractMethodError(cls)
388
+
389
+ def _validate_setitem_value(self, value):
390
+ """
391
+ Check if we have a scalar that we can cast losslessly.
392
+
393
+ Raises
394
+ ------
395
+ TypeError
396
+ """
397
+ kind = self.dtype.kind
398
+ # TODO: get this all from np_can_hold_element?
399
+ if kind == "b":
400
+ if lib.is_bool(value):
401
+ return value
402
+
403
+ elif kind == "f":
404
+ if lib.is_integer(value) or lib.is_float(value):
405
+ return value
406
+
407
+ elif lib.is_integer(value) or (lib.is_float(value) and value.is_integer()):
408
+ return value
409
+ # TODO: unsigned checks
410
+
411
+ # Note: without the "str" here, the f-string rendering raises in
412
+ # py38 builds.
413
+ raise TypeError(f"Invalid value '{value!s}' for dtype '{self.dtype}'")
414
+
415
+ def insert(self, loc: int, item) -> Self:
416
+ if not is_valid_na_for_dtype(item, self.dtype):
417
+ self._validate_setitem_value(item)
418
+ return super().insert(loc, item)
419
+
420
+ def __setitem__(self, key, value) -> None:
421
+ if self._readonly:
422
+ raise ValueError("Cannot modify read-only array")
423
+
424
+ key = check_array_indexer(self, key)
425
+
426
+ if is_scalar(value):
427
+ if is_valid_na_for_dtype(value, self.dtype) and not (
428
+ lib.is_float(value) and not is_nan_na()
429
+ ):
430
+ self._mask[key] = True
431
+ else:
432
+ value = self._validate_setitem_value(value)
433
+ self._data[key] = value
434
+ self._mask[key] = False
435
+ return
436
+
437
+ value, mask = self._coerce_to_array(value, dtype=self.dtype)
438
+
439
+ self._data[key] = value
440
+ self._mask[key] = mask
441
+
442
+ def __contains__(self, key) -> bool:
443
+ if isna(key) and key is not self.dtype.na_value:
444
+ # GH#52840
445
+ if lib.is_float(key) and is_nan_na():
446
+ key = self.dtype.na_value
447
+ elif self._data.dtype.kind == "f" and lib.is_float(key):
448
+ return bool((np.isnan(self._data) & ~self._mask).any())
449
+
450
+ return bool(super().__contains__(key))
451
+
452
+ def __iter__(self) -> Iterator:
453
+ if self.ndim == 1:
454
+ if not self._hasna:
455
+ for val in self._data:
456
+ yield val
457
+ else:
458
+ na_value = self.dtype.na_value
459
+ for isna_, val in zip(self._mask, self._data, strict=True):
460
+ if isna_:
461
+ yield na_value
462
+ else:
463
+ yield val
464
+ else:
465
+ for i in range(len(self)):
466
+ yield self[i]
467
+
468
+ def __len__(self) -> int:
469
+ return len(self._data)
470
+
471
+ @property
472
+ def shape(self) -> Shape:
473
+ return self._data.shape
474
+
475
+ @property
476
+ def ndim(self) -> int:
477
+ return self._data.ndim
478
+
479
+ def swapaxes(self, axis1, axis2) -> Self:
480
+ data = self._data.swapaxes(axis1, axis2)
481
+ mask = self._mask.swapaxes(axis1, axis2)
482
+ return self._simple_new(data, mask)
483
+
484
+ def delete(self, loc, axis: AxisInt = 0) -> Self:
485
+ data = np.delete(self._data, loc, axis=axis)
486
+ mask = np.delete(self._mask, loc, axis=axis)
487
+ return self._simple_new(data, mask)
488
+
489
+ def reshape(self, *args, **kwargs) -> Self:
490
+ data = self._data.reshape(*args, **kwargs)
491
+ mask = self._mask.reshape(*args, **kwargs)
492
+ return self._simple_new(data, mask)
493
+
494
+ def ravel(self, *args, **kwargs) -> Self:
495
+ # TODO: need to make sure we have the same order for data/mask
496
+ data = self._data.ravel(*args, **kwargs)
497
+ mask = self._mask.ravel(*args, **kwargs)
498
+ return type(self)(data, mask)
499
+
500
+ def shift(self, periods: int = 1, fill_value=None) -> Self:
501
+ # NB: shift is always along axis=self.ndim-1
502
+ if fill_value is None:
503
+ new_data = shift(self._data, periods, 0)
504
+ new_mask = shift(self._mask, periods, True)
505
+ else:
506
+ new_data = shift(self._data, periods, fill_value)
507
+ new_mask = shift(self._mask, periods, False)
508
+ return type(self)(new_data, new_mask)
509
+
510
+ @property
511
+ def T(self) -> Self:
512
+ return self._simple_new(self._data.T, self._mask.T)
513
+
514
+ def round(self, decimals: int = 0, *args, **kwargs):
515
+ """
516
+ Round each value in the array a to the given number of decimals.
517
+
518
+ Parameters
519
+ ----------
520
+ decimals : int, default 0
521
+ Number of decimal places to round to. If decimals is negative,
522
+ it specifies the number of positions to the left of the decimal point.
523
+ *args, **kwargs
524
+ Additional arguments and keywords have no effect but might be
525
+ accepted for compatibility with NumPy.
526
+
527
+ Returns
528
+ -------
529
+ NumericArray
530
+ Rounded values of the NumericArray.
531
+
532
+ See Also
533
+ --------
534
+ numpy.around : Round values of an np.array.
535
+ DataFrame.round : Round values of a DataFrame.
536
+ Series.round : Round values of a Series.
537
+ """
538
+ if self.dtype.kind == "b":
539
+ return self
540
+ nv.validate_round(args, kwargs)
541
+ values = np.round(self._data, decimals=decimals, **kwargs)
542
+
543
+ # Usually we'll get same type as self, but ndarray[bool] casts to float
544
+ return self._maybe_mask_result(values, self._mask.copy())
545
+
546
+ # ------------------------------------------------------------------
547
+ # Unary Methods
548
+
549
+ def __invert__(self) -> Self:
550
+ return self._simple_new(~self._data, self._mask.copy())
551
+
552
+ def __neg__(self) -> Self:
553
+ return self._simple_new(-self._data, self._mask.copy())
554
+
555
+ def __pos__(self) -> Self:
556
+ return self.copy()
557
+
558
+ def __abs__(self) -> Self:
559
+ return self._simple_new(abs(self._data), self._mask.copy())
560
+
561
+ # ------------------------------------------------------------------
562
+
563
+ def _values_for_json(self) -> np.ndarray:
564
+ return np.asarray(self, dtype=object)
565
+
566
+ def to_numpy(
567
+ self,
568
+ dtype: npt.DTypeLike | None = None,
569
+ copy: bool = False,
570
+ na_value: object = lib.no_default,
571
+ ) -> np.ndarray:
572
+ """
573
+ Convert to a NumPy Array.
574
+
575
+ By default converts to an object-dtype NumPy array. Specify the `dtype` and
576
+ `na_value` keywords to customize the conversion.
577
+
578
+ Parameters
579
+ ----------
580
+ dtype : dtype, default object
581
+ The numpy dtype to convert to.
582
+ copy : bool, default False
583
+ Whether to ensure that the returned value is a not a view on
584
+ the array. Note that ``copy=False`` does not *ensure* that
585
+ ``to_numpy()`` is no-copy. Rather, ``copy=True`` ensure that
586
+ a copy is made, even if not strictly necessary. This is typically
587
+ only possible when no missing values are present and `dtype`
588
+ is the equivalent numpy dtype.
589
+ na_value : scalar, optional
590
+ Scalar missing value indicator to use in numpy array. Defaults
591
+ to the native missing value indicator of this array (pd.NA).
592
+
593
+ Returns
594
+ -------
595
+ numpy.ndarray
596
+
597
+ Examples
598
+ --------
599
+ An object-dtype is the default result
600
+
601
+ >>> a = pd.array([True, False, pd.NA], dtype="boolean")
602
+ >>> a.to_numpy()
603
+ array([True, False, <NA>], dtype=object)
604
+
605
+ When no missing values are present, an equivalent dtype can be used.
606
+
607
+ >>> pd.array([True, False], dtype="boolean").to_numpy(dtype="bool")
608
+ array([ True, False])
609
+ >>> pd.array([1, 2], dtype="Int64").to_numpy("int64")
610
+ array([1, 2])
611
+
612
+ However, requesting such dtype will raise a ValueError if
613
+ missing values are present and the default missing value :attr:`NA`
614
+ is used.
615
+
616
+ >>> a = pd.array([True, False, pd.NA], dtype="boolean")
617
+ >>> a
618
+ <BooleanArray>
619
+ [True, False, <NA>]
620
+ Length: 3, dtype: boolean
621
+
622
+ >>> a.to_numpy(dtype="bool")
623
+ Traceback (most recent call last):
624
+ ...
625
+ ValueError: cannot convert to bool numpy array in presence of missing values
626
+
627
+ Specify a valid `na_value` instead
628
+
629
+ >>> a.to_numpy(dtype="bool", na_value=False)
630
+ array([ True, False, False])
631
+ """
632
+ hasna = self._hasna
633
+ dtype, na_value = to_numpy_dtype_inference(self, dtype, na_value, hasna)
634
+ if dtype is None:
635
+ dtype = np.dtype(object)
636
+
637
+ if hasna:
638
+ if (
639
+ dtype != np.dtype(object)
640
+ and not is_string_dtype(dtype)
641
+ and na_value is libmissing.NA
642
+ ):
643
+ raise ValueError(
644
+ f"cannot convert to '{dtype}'-dtype NumPy array "
645
+ "with missing values. Specify an appropriate 'na_value' "
646
+ "for this dtype."
647
+ )
648
+ # don't pass copy to astype -> always need a copy since we are mutating
649
+ with warnings.catch_warnings():
650
+ warnings.filterwarnings("ignore", category=RuntimeWarning)
651
+ data = self._data.astype(dtype)
652
+ data[self._mask] = na_value
653
+ else:
654
+ with warnings.catch_warnings():
655
+ warnings.filterwarnings("ignore", category=RuntimeWarning)
656
+ data = self._data.astype(dtype, copy=copy)
657
+ if self._readonly and not copy and astype_is_view(self.dtype, dtype):
658
+ data = data.view()
659
+ data.flags.writeable = False
660
+ return data
661
+
662
+ def tolist(self) -> list:
663
+ """
664
+ Return a list of the values.
665
+
666
+ These are each a scalar type, which is a Python scalar
667
+ (for str, int, float) or a pandas scalar
668
+ (for Timestamp/Timedelta/Interval/Period)
669
+
670
+ Returns
671
+ -------
672
+ list
673
+ Python list of values in array.
674
+
675
+ See Also
676
+ --------
677
+ Index.to_list: Return a list of the values in the Index.
678
+ Series.to_list: Return a list of the values in the Series.
679
+
680
+ Examples
681
+ --------
682
+ >>> arr = pd.array([1, 2, 3])
683
+ >>> arr.tolist()
684
+ [1, 2, 3]
685
+ """
686
+ if self.ndim > 1:
687
+ return [x.tolist() for x in self]
688
+ dtype = None if self._hasna else self._data.dtype
689
+ return self.to_numpy(dtype=dtype, na_value=libmissing.NA).tolist()
690
+
691
+ @overload
692
+ def astype(self, dtype: npt.DTypeLike, copy: bool = ...) -> np.ndarray: ...
693
+
694
+ @overload
695
+ def astype(self, dtype: ExtensionDtype, copy: bool = ...) -> ExtensionArray: ...
696
+
697
+ @overload
698
+ def astype(self, dtype: AstypeArg, copy: bool = ...) -> ArrayLike: ...
699
+
700
+ def astype(self, dtype: AstypeArg, copy: bool = True) -> ArrayLike:
701
+ dtype = pandas_dtype(dtype)
702
+
703
+ if dtype == self.dtype:
704
+ if copy:
705
+ return self.copy()
706
+ return self
707
+
708
+ # if we are astyping to another nullable masked dtype, we can fastpath
709
+ if isinstance(dtype, BaseMaskedDtype):
710
+ # TODO deal with NaNs for FloatingArray case
711
+ with warnings.catch_warnings():
712
+ warnings.filterwarnings("ignore", category=RuntimeWarning)
713
+ # TODO: Is rounding what we want long term?
714
+ data = self._data.astype(dtype.numpy_dtype, copy=copy)
715
+ # mask is copied depending on whether the data was copied, and
716
+ # not directly depending on the `copy` keyword
717
+ mask = self._mask if data is self._data else self._mask.copy()
718
+ cls = dtype.construct_array_type()
719
+ return cls(data, mask, copy=False)
720
+
721
+ if isinstance(dtype, ExtensionDtype):
722
+ eacls = dtype.construct_array_type()
723
+ return eacls._from_sequence(self, dtype=dtype, copy=copy)
724
+
725
+ na_value: float | np.datetime64 | lib.NoDefault
726
+
727
+ # coerce
728
+ if dtype.kind == "f":
729
+ # In astype, we consider dtype=float to also mean na_value=np.nan
730
+ na_value = np.nan
731
+ elif dtype.kind == "M":
732
+ unit = np.datetime_data(dtype)[0]
733
+ na_value = np.datetime64("NaT", unit) # type: ignore[call-overload]
734
+ else:
735
+ na_value = lib.no_default
736
+
737
+ # to_numpy will also raise, but we get somewhat nicer exception messages here
738
+ if dtype.kind in "iu" and self._hasna:
739
+ raise ValueError("cannot convert NA to integer")
740
+ if dtype.kind == "b" and self._hasna:
741
+ # careful: astype_nansafe converts np.nan to True
742
+ raise ValueError("cannot convert float NaN to bool")
743
+
744
+ data = self.to_numpy(dtype=dtype, na_value=na_value, copy=copy)
745
+ return data
746
+
747
+ __array_priority__ = 1000 # higher than ndarray so ops dispatch to us
748
+
749
+ def __array__(
750
+ self, dtype: NpDtype | None = None, copy: bool | None = None
751
+ ) -> np.ndarray:
752
+ """
753
+ the array interface, return my values
754
+ We return an object array here to preserve our scalar values
755
+ """
756
+ if copy is False:
757
+ if not self._hasna:
758
+ # special case, here we can simply return the underlying data
759
+ result = np.array(self._data, dtype=dtype, copy=copy)
760
+ # If the ExtensionArray is readonly, make the numpy array readonly too
761
+ if self._readonly:
762
+ result = result.view()
763
+ result.flags.writeable = False
764
+ return result
765
+ raise ValueError(
766
+ "Unable to avoid copy while creating an array as requested."
767
+ )
768
+
769
+ if copy is None:
770
+ copy = False # The NumPy copy=False meaning is different here.
771
+ return self.to_numpy(dtype=dtype, copy=copy)
772
+
773
+ _HANDLED_TYPES: tuple[type, ...]
774
+
775
+ def __array_ufunc__(self, ufunc: np.ufunc, method: str, *inputs, **kwargs):
776
+ # For MaskedArray inputs, we apply the ufunc to ._data
777
+ # and mask the result.
778
+
779
+ out = kwargs.get("out", ())
780
+
781
+ for x in inputs + out:
782
+ if not isinstance(x, (*self._HANDLED_TYPES, BaseMaskedArray)):
783
+ return NotImplemented
784
+
785
+ # for binary ops, use our custom dunder methods
786
+ result = arraylike.maybe_dispatch_ufunc_to_dunder_op(
787
+ self, ufunc, method, *inputs, **kwargs
788
+ )
789
+ if result is not NotImplemented:
790
+ return result
791
+
792
+ if "out" in kwargs:
793
+ # e.g. test_ufunc_with_out
794
+ return arraylike.dispatch_ufunc_with_out(
795
+ self, ufunc, method, *inputs, **kwargs
796
+ )
797
+
798
+ if method == "reduce":
799
+ result = arraylike.dispatch_reduction_ufunc(
800
+ self, ufunc, method, *inputs, **kwargs
801
+ )
802
+ if result is not NotImplemented:
803
+ return result
804
+
805
+ mask = np.zeros(len(self), dtype=bool)
806
+ inputs2 = []
807
+ for x in inputs:
808
+ if isinstance(x, BaseMaskedArray):
809
+ mask |= x._mask
810
+ inputs2.append(x._data)
811
+ else:
812
+ inputs2.append(x)
813
+
814
+ def reconstruct(x: np.ndarray):
815
+ # we don't worry about scalar `x` here, since we
816
+ # raise for reduce up above.
817
+ from pandas.core.arrays import (
818
+ BooleanArray,
819
+ FloatingArray,
820
+ IntegerArray,
821
+ )
822
+
823
+ if x.dtype.kind == "b":
824
+ m = mask.copy()
825
+ return BooleanArray(x, m)
826
+ elif x.dtype.kind in "iu":
827
+ m = mask.copy()
828
+ return IntegerArray(x, m)
829
+ elif x.dtype.kind == "f":
830
+ m = mask.copy()
831
+ if x.dtype == np.float16:
832
+ # reached in e.g. np.sqrt on BooleanArray
833
+ # we don't support float16
834
+ x = x.astype(np.float32)
835
+ if is_nan_na():
836
+ m[np.isnan(x)] = True
837
+ return FloatingArray(x, m)
838
+ else:
839
+ x[mask] = np.nan
840
+ return x
841
+
842
+ result = getattr(ufunc, method)(*inputs2, **kwargs)
843
+ if ufunc.nout > 1:
844
+ # e.g. np.divmod
845
+ return tuple(reconstruct(x) for x in result)
846
+ elif method == "reduce":
847
+ # e.g. np.add.reduce; test_ufunc_reduce_raises
848
+ if self._mask.any():
849
+ return self._na_value
850
+ return result
851
+ else:
852
+ return reconstruct(result)
853
+
854
+ def __arrow_array__(self, type=None):
855
+ """
856
+ Convert myself into a pyarrow Array.
857
+ """
858
+ import pyarrow as pa
859
+
860
+ return pa.array(self._data, mask=self._mask, type=type)
861
+
862
+ @property
863
+ def _hasna(self) -> bool:
864
+ # Note: this is expensive right now! The hope is that we can
865
+ # make this faster by having an optional mask, but not have to change
866
+ # source code using it..
867
+
868
+ return bool(self._mask.any())
869
+
870
+ def _propagate_mask(
871
+ self, mask: npt.NDArray[np.bool_] | None, other
872
+ ) -> npt.NDArray[np.bool_]:
873
+ if mask is None:
874
+ mask = self._mask.copy() # TODO: need test for BooleanArray needing a copy
875
+ if other is libmissing.NA:
876
+ # GH#45421 don't alter inplace
877
+ mask = mask | True
878
+ elif is_list_like(other) and len(other) == len(mask):
879
+ mask = mask | isna(other)
880
+ else:
881
+ mask = self._mask | mask
882
+ return mask
883
+
884
+ def _arith_method(self, other, op):
885
+ op_name = op.__name__
886
+ omask = None
887
+
888
+ if (
889
+ is_list_like(other)
890
+ and not isinstance(other, (list, np.ndarray, ExtensionArray))
891
+ and not ops.has_castable_attr(other)
892
+ ):
893
+ warnings.warn(
894
+ f"Operation with {type(other).__name__} is deprecated. "
895
+ "In a future version these will be treated as scalar-like. "
896
+ "To retain the old behavior, explicitly wrap in a Series "
897
+ "instead.",
898
+ Pandas4Warning,
899
+ stacklevel=find_stack_level(),
900
+ )
901
+
902
+ if (
903
+ not hasattr(other, "dtype")
904
+ and is_list_like(other)
905
+ and len(other) == len(self)
906
+ ):
907
+ # Try inferring masked dtype instead of casting to object
908
+ other = pd_array(other)
909
+ other = extract_array(other, extract_numpy=True)
910
+
911
+ if isinstance(other, BaseMaskedArray):
912
+ other, omask = other._data, other._mask
913
+
914
+ elif is_list_like(other):
915
+ if not isinstance(other, ExtensionArray):
916
+ other = np.asarray(other)
917
+ if other.ndim > 1:
918
+ raise NotImplementedError("can only perform ops with 1-d structures")
919
+
920
+ # We wrap the non-masked arithmetic logic used for numpy dtypes
921
+ # in Series/Index arithmetic ops.
922
+ other = ops.maybe_prepare_scalar_for_op(other, (len(self),))
923
+ pd_op = ops.get_array_op(op)
924
+ other = ensure_wrapped_if_datetimelike(other)
925
+
926
+ if isinstance(other, ExtensionArray) and isinstance(other.dtype, ArrowDtype):
927
+ # GH#58602
928
+ return NotImplemented
929
+
930
+ if op_name in {"pow", "rpow"} and isinstance(other, np.bool_):
931
+ # Avoid DeprecationWarning: In future, it will be an error
932
+ # for 'np.bool_' scalars to be interpreted as an index
933
+ # e.g. test_array_scalar_like_equivalence
934
+ other = bool(other)
935
+
936
+ mask = self._propagate_mask(omask, other)
937
+
938
+ if other is libmissing.NA:
939
+ result = np.ones_like(self._data)
940
+ if self.dtype.kind == "b":
941
+ if op_name in {
942
+ "floordiv",
943
+ "rfloordiv",
944
+ "pow",
945
+ "rpow",
946
+ "truediv",
947
+ "rtruediv",
948
+ }:
949
+ # GH#41165 Try to match non-masked Series behavior
950
+ # This is still imperfect GH#46043
951
+ raise NotImplementedError(
952
+ f"operator '{op_name}' not implemented for bool dtypes"
953
+ )
954
+ if op_name in {"mod", "rmod"}:
955
+ dtype = "int8"
956
+ else:
957
+ dtype = "bool"
958
+ result = result.astype(dtype)
959
+ elif "truediv" in op_name and self.dtype.kind != "f":
960
+ # The actual data here doesn't matter since the mask
961
+ # will be all-True, but since this is division, we want
962
+ # to end up with floating dtype.
963
+ result = result.astype(np.float64)
964
+ elif op_name in {"divmod", "rdivmod"}:
965
+ # GH#62196
966
+ res = self._maybe_mask_result(result, mask)
967
+ return res, res.copy()
968
+ else:
969
+ # Make sure we do this before the "pow" mask checks
970
+ # to get an expected exception message on shape mismatch.
971
+ if self.dtype.kind in "iu" and op_name in ["floordiv", "mod"]:
972
+ # TODO(GH#30188) ATM we don't match the behavior of non-masked
973
+ # types with respect to floordiv-by-zero
974
+ pd_op = op
975
+
976
+ with np.errstate(all="ignore"):
977
+ result = pd_op(self._data, other)
978
+
979
+ if op_name == "pow":
980
+ # 1 ** x is 1.
981
+ mask = np.where((self._data == 1) & ~self._mask, False, mask)
982
+ # x ** 0 is 1.
983
+ if omask is not None:
984
+ mask = np.where((other == 0) & ~omask, False, mask)
985
+ elif other is not libmissing.NA:
986
+ mask = np.where(other == 0, False, mask)
987
+
988
+ elif op_name == "rpow":
989
+ # 1 ** x is 1.
990
+ if omask is not None:
991
+ mask = np.where((other == 1) & ~omask, False, mask)
992
+ elif other is not libmissing.NA:
993
+ mask = np.where(other == 1, False, mask)
994
+ # x ** 0 is 1.
995
+ mask = np.where((self._data == 0) & ~self._mask, False, mask)
996
+
997
+ return self._maybe_mask_result(result, mask)
998
+
999
+ _logical_method = _arith_method
1000
+
1001
+ def _cmp_method(self, other, op) -> BooleanArray:
1002
+ from pandas.core.arrays import BooleanArray
1003
+
1004
+ mask = None
1005
+
1006
+ if isinstance(other, ExtensionArray) and isinstance(other.dtype, ArrowDtype):
1007
+ # GH#58602
1008
+ return NotImplemented
1009
+
1010
+ elif isinstance(other, BaseMaskedArray):
1011
+ other, mask = other._data, other._mask
1012
+
1013
+ elif is_list_like(other):
1014
+ if not isinstance(
1015
+ other, (list, np.ndarray, ExtensionArray)
1016
+ ) and not ops.has_castable_attr(other):
1017
+ warnings.warn(
1018
+ f"Operation with {type(other).__name__} is deprecated. "
1019
+ "In a future version these will be treated as scalar-like. "
1020
+ "To retain the old behavior, explicitly wrap in a Series "
1021
+ "instead.",
1022
+ Pandas4Warning,
1023
+ stacklevel=find_stack_level(),
1024
+ )
1025
+ other = np.asarray(other)
1026
+ if other.ndim > 1:
1027
+ raise NotImplementedError("can only perform ops with 1-d structures")
1028
+ if len(self) != len(other):
1029
+ raise ValueError("Lengths must match to compare")
1030
+
1031
+ if other is libmissing.NA:
1032
+ # numpy does not handle pd.NA well as "other" scalar (it returns
1033
+ # a scalar False instead of an array)
1034
+ # This may be fixed by NA.__array_ufunc__. Revisit this check
1035
+ # once that's implemented.
1036
+ result = np.zeros(self._data.shape, dtype="bool")
1037
+ mask = np.ones(self._data.shape, dtype="bool")
1038
+ else:
1039
+ with warnings.catch_warnings():
1040
+ # numpy may show a FutureWarning or DeprecationWarning:
1041
+ # elementwise comparison failed; returning scalar instead,
1042
+ # but in the future will perform elementwise comparison
1043
+ # before returning NotImplemented. We fall back to the correct
1044
+ # behavior today, so that should be fine to ignore.
1045
+ warnings.filterwarnings("ignore", "elementwise", FutureWarning)
1046
+ warnings.filterwarnings("ignore", "elementwise", DeprecationWarning)
1047
+ method = getattr(self._data, f"__{op.__name__}__")
1048
+ result = method(other)
1049
+
1050
+ if result is NotImplemented:
1051
+ result = invalid_comparison(self._data, other, op)
1052
+
1053
+ mask = self._propagate_mask(mask, other)
1054
+ return BooleanArray(result, mask, copy=False)
1055
+
1056
+ def _maybe_mask_result(
1057
+ self, result: np.ndarray | tuple[np.ndarray, np.ndarray], mask: np.ndarray
1058
+ ):
1059
+ """
1060
+ Parameters
1061
+ ----------
1062
+ result : array-like or tuple[array-like]
1063
+ mask : array-like bool
1064
+ """
1065
+ if isinstance(result, tuple):
1066
+ # i.e. divmod
1067
+ div, mod = result
1068
+ return (
1069
+ self._maybe_mask_result(div, mask),
1070
+ self._maybe_mask_result(mod, mask),
1071
+ )
1072
+
1073
+ if result.dtype.kind == "f":
1074
+ from pandas.core.arrays import FloatingArray
1075
+
1076
+ if is_nan_na():
1077
+ mask[np.isnan(result)] = True
1078
+
1079
+ return FloatingArray(result, mask, copy=False)
1080
+
1081
+ elif result.dtype.kind == "b":
1082
+ from pandas.core.arrays import BooleanArray
1083
+
1084
+ return BooleanArray(result, mask, copy=False)
1085
+
1086
+ elif lib.is_np_dtype(result.dtype, "m") and is_supported_dtype(result.dtype):
1087
+ # e.g. test_numeric_arr_mul_tdscalar_numexpr_path
1088
+ from pandas.core.arrays import TimedeltaArray
1089
+
1090
+ unit = np.datetime_data(result.dtype)[0]
1091
+ result[mask] = np.timedelta64("NaT", unit) # type: ignore[call-overload]
1092
+
1093
+ if not isinstance(result, TimedeltaArray):
1094
+ return TimedeltaArray._simple_new(result, dtype=result.dtype)
1095
+
1096
+ return result
1097
+
1098
+ elif result.dtype.kind in "iu":
1099
+ from pandas.core.arrays import IntegerArray
1100
+
1101
+ return IntegerArray(result, mask, copy=False)
1102
+
1103
+ elif result.dtype == object:
1104
+ result[mask] = self.dtype.na_value
1105
+ return result
1106
+ else:
1107
+ result[mask] = np.nan
1108
+ return result
1109
+
1110
+ def isna(self) -> np.ndarray:
1111
+ return self._mask.copy()
1112
+
1113
+ @property
1114
+ def _na_value(self):
1115
+ return self.dtype.na_value
1116
+
1117
+ @property
1118
+ def nbytes(self) -> int:
1119
+ return self._data.nbytes + self._mask.nbytes
1120
+
1121
+ @classmethod
1122
+ def _concat_same_type(
1123
+ cls,
1124
+ to_concat: Sequence[Self],
1125
+ axis: AxisInt = 0,
1126
+ ) -> Self:
1127
+ data = np.concatenate([x._data for x in to_concat], axis=axis)
1128
+ mask = np.concatenate([x._mask for x in to_concat], axis=axis)
1129
+ return cls(data, mask)
1130
+
1131
+ def _hash_pandas_object(
1132
+ self, *, encoding: str, hash_key: str, categorize: bool
1133
+ ) -> npt.NDArray[np.uint64]:
1134
+ hashed_array = hash_array(
1135
+ self._data, encoding=encoding, hash_key=hash_key, categorize=categorize
1136
+ )
1137
+ hashed_array[self.isna()] = hash(self.dtype.na_value)
1138
+ return hashed_array
1139
+
1140
+ def take(
1141
+ self,
1142
+ indexer,
1143
+ *,
1144
+ allow_fill: bool = False,
1145
+ fill_value: Scalar | None = None,
1146
+ axis: AxisInt = 0,
1147
+ ) -> Self:
1148
+ # we always fill with 1 internally
1149
+ # to avoid upcasting
1150
+ data_fill_value = (
1151
+ self.dtype._internal_fill_value if isna(fill_value) else fill_value
1152
+ )
1153
+ result = take(
1154
+ self._data,
1155
+ indexer,
1156
+ fill_value=data_fill_value,
1157
+ allow_fill=allow_fill,
1158
+ axis=axis,
1159
+ )
1160
+
1161
+ mask = take(
1162
+ self._mask, indexer, fill_value=True, allow_fill=allow_fill, axis=axis
1163
+ )
1164
+
1165
+ # if we are filling
1166
+ # we only fill where the indexer is null
1167
+ # not existing missing values
1168
+ # TODO(jreback) what if we have a non-na float as a fill value?
1169
+ if allow_fill and notna(fill_value):
1170
+ fill_mask = np.asarray(indexer) == -1
1171
+ result[fill_mask] = fill_value
1172
+ mask = mask ^ fill_mask
1173
+
1174
+ return self._simple_new(result, mask)
1175
+
1176
+ # error: Return type "BooleanArray" of "isin" incompatible with return type
1177
+ # "ndarray" in supertype "ExtensionArray"
1178
+ def isin(self, values: ArrayLike) -> BooleanArray: # type: ignore[override]
1179
+ from pandas.core.arrays import BooleanArray
1180
+
1181
+ # algorithms.isin will eventually convert values to an ndarray, so no extra
1182
+ # cost to doing it here first
1183
+ values_arr = np.asarray(values)
1184
+ result = isin(self._data, values_arr)
1185
+
1186
+ if self._hasna:
1187
+ values_have_NA = values_arr.dtype == object and any(
1188
+ val is self.dtype.na_value for val in values_arr
1189
+ )
1190
+
1191
+ # For now, NA does not propagate so set result according to presence of NA,
1192
+ # see https://github.com/pandas-dev/pandas/pull/38379 for some discussion
1193
+ result[self._mask] = values_have_NA
1194
+
1195
+ mask = np.zeros(self._data.shape, dtype=bool)
1196
+ return BooleanArray(result, mask, copy=False)
1197
+
1198
+ def copy(self) -> Self:
1199
+ data = self._data.copy()
1200
+ mask = self._mask.copy()
1201
+ return self._simple_new(data, mask)
1202
+
1203
+ @overload
1204
+ def view(self, dtype: None = ...) -> Self: ...
1205
+
1206
+ @overload
1207
+ def view(self, dtype: Dtype | None = ...) -> ArrayLike: ...
1208
+
1209
+ def view(self, dtype: Dtype | None = None) -> ArrayLike:
1210
+ if dtype is not None:
1211
+ return super().view(dtype)
1212
+ result = self._simple_new(self._data[:], self._mask[:])
1213
+ result._readonly = self._readonly
1214
+ return result
1215
+
1216
+ @property
1217
+ def _is_monotonic_increasing(self) -> bool:
1218
+ if self._hasna:
1219
+ return False
1220
+ data = self._data
1221
+ if data.dtype.kind == "b":
1222
+ data = data.view("uint8")
1223
+ return libalgos.is_monotonic(data, timelike=False)[0]
1224
+
1225
+ @property
1226
+ def _is_monotonic_decreasing(self) -> bool:
1227
+ if self._hasna:
1228
+ return False
1229
+ data = self._data
1230
+ if data.dtype.kind == "b":
1231
+ data = data.view("uint8")
1232
+ return libalgos.is_monotonic(data, timelike=False)[1]
1233
+
1234
+ def _rank(
1235
+ self,
1236
+ *,
1237
+ axis: AxisInt = 0,
1238
+ method: str = "average",
1239
+ na_option: str = "keep",
1240
+ ascending: bool = True,
1241
+ pct: bool = False,
1242
+ ):
1243
+ # GH#62043 Avoid going through copy-making ensure_data in algorithms.rank
1244
+ if axis != 0 or self.ndim != 1:
1245
+ raise NotImplementedError
1246
+
1247
+ from pandas.core.arrays import FloatingArray
1248
+
1249
+ data = self._data
1250
+ if data.dtype.kind == "b":
1251
+ data = data.view("uint8")
1252
+
1253
+ result = libalgos.rank_1d(
1254
+ data,
1255
+ is_datetimelike=False,
1256
+ ties_method=method,
1257
+ ascending=ascending,
1258
+ na_option=na_option,
1259
+ pct=pct,
1260
+ mask=self.isna(),
1261
+ )
1262
+ if na_option in ["top", "bottom"]:
1263
+ mask = np.zeros(self.shape, dtype=bool)
1264
+ else:
1265
+ mask = self._mask.copy()
1266
+
1267
+ if method != "average" and not pct:
1268
+ if na_option not in ["top", "bottom"]:
1269
+ result[self._mask] = 0 # avoid warning on casting
1270
+ result = result.astype("uint64", copy=False)
1271
+ from pandas.core.arrays import IntegerArray
1272
+
1273
+ return IntegerArray(result, mask=mask)
1274
+
1275
+ return FloatingArray(result, mask=mask)
1276
+
1277
+ def duplicated(
1278
+ self, keep: Literal["first", "last", False] = "first"
1279
+ ) -> npt.NDArray[np.bool_]:
1280
+ """
1281
+ Return boolean ndarray denoting duplicate values.
1282
+
1283
+ Parameters
1284
+ ----------
1285
+ keep : {'first', 'last', False}, default 'first'
1286
+ - ``first`` : Mark duplicates as ``True`` except for the first occurrence.
1287
+ - ``last`` : Mark duplicates as ``True`` except for the last occurrence.
1288
+ - False : Mark all duplicates as ``True``.
1289
+
1290
+ Returns
1291
+ -------
1292
+ ndarray[bool]
1293
+ With true in indices where elements are duplicated and false otherwise.
1294
+
1295
+ See Also
1296
+ --------
1297
+ DataFrame.duplicated : Return boolean Series denoting
1298
+ duplicate rows.
1299
+ Series.duplicated : Indicate duplicate Series values.
1300
+ api.extensions.ExtensionArray.unique : Compute the ExtensionArray
1301
+ of unique values.
1302
+
1303
+ Examples
1304
+ --------
1305
+ >>> pd.array([1, 1, 2, 3, 3], dtype="Int64").duplicated()
1306
+ array([False, True, False, False, True])
1307
+ """
1308
+ values = self._data
1309
+ mask = self._mask
1310
+ return algos.duplicated(values, keep=keep, mask=mask)
1311
+
1312
+ def unique(self) -> Self:
1313
+ """
1314
+ Compute the BaseMaskedArray of unique values.
1315
+
1316
+ Returns
1317
+ -------
1318
+ uniques : BaseMaskedArray
1319
+ """
1320
+ uniques, mask = algos.unique_with_mask(self._data, self._mask)
1321
+ return self._simple_new(uniques, mask)
1322
+
1323
+ def searchsorted(
1324
+ self,
1325
+ value: NumpyValueArrayLike | ExtensionArray,
1326
+ side: Literal["left", "right"] = "left",
1327
+ sorter: NumpySorter | None = None,
1328
+ ) -> npt.NDArray[np.intp] | np.intp:
1329
+ """
1330
+ Find indices where elements should be inserted to maintain order.
1331
+
1332
+ Find the indices into a sorted array `self` (a) such that, if the
1333
+ corresponding elements in `value` were inserted before the indices,
1334
+ the order of `self` would be preserved.
1335
+
1336
+ Assuming that `self` is sorted:
1337
+
1338
+ ====== ================================
1339
+ `side` returned index `i` satisfies
1340
+ ====== ================================
1341
+ left ``self[i-1] < value <= self[i]``
1342
+ right ``self[i-1] <= value < self[i]``
1343
+ ====== ================================
1344
+
1345
+ Parameters
1346
+ ----------
1347
+ value : array-like, list or scalar
1348
+ Value(s) to insert into `self`.
1349
+ side : {'left', 'right'}, optional
1350
+ If 'left', the index of the first suitable location found is given.
1351
+ If 'right', return the last such index. If there is no suitable
1352
+ index, return either 0 or N (where N is the length of `self`).
1353
+ sorter : 1-D array-like, optional
1354
+ Optional array of integer indices that sort array a into ascending
1355
+ order. They are typically the result of argsort.
1356
+
1357
+ Returns
1358
+ -------
1359
+ array of ints or int
1360
+ If value is array-like, array of insertion points.
1361
+ If value is scalar, a single integer.
1362
+
1363
+ See Also
1364
+ --------
1365
+ numpy.searchsorted : Similar method from NumPy.
1366
+
1367
+ Examples
1368
+ --------
1369
+ >>> arr = pd.array([1, 2, 3, 5])
1370
+ >>> arr.searchsorted([4])
1371
+ array([3])
1372
+ """
1373
+ if self._hasna:
1374
+ raise ValueError(
1375
+ "searchsorted requires array to be sorted, which is impossible "
1376
+ "with NAs present."
1377
+ )
1378
+ if isinstance(value, ExtensionArray):
1379
+ value = value.astype(object)
1380
+ # Base class searchsorted would cast to object, which is *much* slower.
1381
+ return self._data.searchsorted(value, side=side, sorter=sorter)
1382
+
1383
+ def factorize(
1384
+ self,
1385
+ use_na_sentinel: bool = True,
1386
+ ) -> tuple[np.ndarray, ExtensionArray]:
1387
+ """
1388
+ Encode the extension array as an enumerated type.
1389
+
1390
+ Parameters
1391
+ ----------
1392
+ use_na_sentinel : bool, default True
1393
+ If True, the sentinel -1 will be used for NaN values. If False,
1394
+ NaN values will be encoded as non-negative integers and will not drop the
1395
+ NaN from the uniques of the values.
1396
+
1397
+ Returns
1398
+ -------
1399
+ codes : ndarray
1400
+ An integer NumPy array that's an indexer into the original
1401
+ ExtensionArray.
1402
+ uniques : ExtensionArray
1403
+ An ExtensionArray containing the unique values of `self`.
1404
+
1405
+ .. note::
1406
+
1407
+ uniques will *not* contain an entry for the NA value of
1408
+ the ExtensionArray if there are any missing values present
1409
+ in `self`.
1410
+
1411
+ See Also
1412
+ --------
1413
+ factorize : Top-level factorize method that dispatches here.
1414
+
1415
+ Notes
1416
+ -----
1417
+ :meth:`pandas.factorize` offers a `sort` keyword as well.
1418
+
1419
+ Examples
1420
+ --------
1421
+ >>> idx1 = pd.PeriodIndex(
1422
+ ... ["2014-01", "2014-01", "2014-02", "2014-02", "2014-03", "2014-03"],
1423
+ ... freq="M",
1424
+ ... )
1425
+ >>> arr, idx = idx1.factorize()
1426
+ >>> arr
1427
+ array([0, 0, 1, 1, 2, 2])
1428
+ >>> idx
1429
+ PeriodIndex(['2014-01', '2014-02', '2014-03'], dtype='period[M]')
1430
+ """
1431
+ arr = self._data
1432
+ mask = self._mask
1433
+
1434
+ # Use a sentinel for na; recode and add NA to uniques if necessary below
1435
+ codes, uniques = factorize_array(arr, use_na_sentinel=True, mask=mask)
1436
+
1437
+ # check that factorize_array correctly preserves dtype.
1438
+ assert uniques.dtype == self.dtype.numpy_dtype, (uniques.dtype, self.dtype)
1439
+
1440
+ has_na = mask.any()
1441
+ if use_na_sentinel or not has_na:
1442
+ size = len(uniques)
1443
+ else:
1444
+ # Make room for an NA value
1445
+ size = len(uniques) + 1
1446
+ uniques_mask = np.zeros(size, dtype=bool)
1447
+ if not use_na_sentinel and has_na:
1448
+ na_index = mask.argmax()
1449
+ # Insert na with the proper code
1450
+ if na_index == 0:
1451
+ na_code = np.intp(0)
1452
+ else:
1453
+ na_code = codes[:na_index].max() + 1
1454
+ codes[codes >= na_code] += 1
1455
+ codes[codes == -1] = na_code
1456
+ # dummy value for uniques; not used since uniques_mask will be True
1457
+ uniques = np.insert(uniques, na_code, 0)
1458
+ uniques_mask[na_code] = True
1459
+ uniques_ea = self._simple_new(uniques, uniques_mask)
1460
+
1461
+ return codes, uniques_ea
1462
+
1463
+ def _values_for_argsort(self) -> np.ndarray:
1464
+ """
1465
+ Return values for sorting.
1466
+
1467
+ Returns
1468
+ -------
1469
+ ndarray
1470
+ The transformed values should maintain the ordering between values
1471
+ within the array.
1472
+
1473
+ See Also
1474
+ --------
1475
+ ExtensionArray.argsort : Return the indices that would sort this array.
1476
+
1477
+ Notes
1478
+ -----
1479
+ The caller is responsible for *not* modifying these values in-place, so
1480
+ it is safe for implementers to give views on ``self``.
1481
+
1482
+ Functions that use this (e.g. ``ExtensionArray.argsort``) should ignore
1483
+ entries with missing values in the original array (according to
1484
+ ``self.isna()``). This means that the corresponding entries in the returned
1485
+ array don't need to be modified to sort correctly.
1486
+
1487
+ Examples
1488
+ --------
1489
+ In most cases, this is the underlying Numpy array of the ``ExtensionArray``:
1490
+
1491
+ >>> arr = pd.array([1, 2, 3])
1492
+ >>> arr._values_for_argsort()
1493
+ array([1, 2, 3])
1494
+ """
1495
+ return self._data
1496
+
1497
+ def value_counts(self, dropna: bool = True) -> Series:
1498
+ """
1499
+ Returns a Series containing counts of each unique value.
1500
+
1501
+ Parameters
1502
+ ----------
1503
+ dropna : bool, default True
1504
+ Don't include counts of missing values.
1505
+
1506
+ Returns
1507
+ -------
1508
+ counts : Series
1509
+
1510
+ See Also
1511
+ --------
1512
+ Series.value_counts
1513
+ """
1514
+ from pandas import (
1515
+ Index,
1516
+ Series,
1517
+ )
1518
+ from pandas.arrays import IntegerArray
1519
+
1520
+ keys, value_counts, na_counter = algos.value_counts_arraylike(
1521
+ self._data, dropna=dropna, mask=self._mask
1522
+ )
1523
+ mask_index = np.zeros((len(value_counts),), dtype=np.bool_)
1524
+ mask = mask_index.copy()
1525
+
1526
+ if na_counter > 0:
1527
+ mask_index[-1] = True
1528
+
1529
+ arr = IntegerArray(value_counts, mask)
1530
+ index = Index(
1531
+ self.dtype.construct_array_type()(
1532
+ keys, # type: ignore[arg-type]
1533
+ mask_index,
1534
+ ),
1535
+ copy=False,
1536
+ )
1537
+ return Series(arr, index=index, name="count", copy=False)
1538
+
1539
+ def _mode(self, dropna: bool = True) -> Self:
1540
+ result, res_mask = mode(self._data, dropna=dropna, mask=self._mask)
1541
+ result = type(self)(result, res_mask)
1542
+ return result[result.argsort()]
1543
+
1544
+ def equals(self, other) -> bool:
1545
+ """
1546
+ Return if another array is equivalent to this array.
1547
+
1548
+ Equivalent means that both arrays have the same shape and dtype, and
1549
+ all values compare equal. Missing values in the same location are
1550
+ considered equal (in contrast with normal equality).
1551
+
1552
+ Parameters
1553
+ ----------
1554
+ other : ExtensionArray
1555
+ Array to compare to this Array.
1556
+
1557
+ Returns
1558
+ -------
1559
+ boolean
1560
+ Whether the arrays are equivalent.
1561
+
1562
+ See Also
1563
+ --------
1564
+ numpy.array_equal : Equivalent method for numpy array.
1565
+ Series.equals : Equivalent method for Series.
1566
+ DataFrame.equals : Equivalent method for DataFrame.
1567
+
1568
+ Examples
1569
+ --------
1570
+ >>> arr1 = pd.array([1, 2, np.nan])
1571
+ >>> arr2 = pd.array([1, 2, np.nan])
1572
+ >>> arr1.equals(arr2)
1573
+ True
1574
+
1575
+ >>> arr1 = pd.array([1, 3, np.nan])
1576
+ >>> arr2 = pd.array([1, 2, np.nan])
1577
+ >>> arr1.equals(arr2)
1578
+ False
1579
+ """
1580
+ if type(self) != type(other):
1581
+ return False
1582
+ if other.dtype != self.dtype:
1583
+ return False
1584
+
1585
+ # GH#44382 if e.g. self[1] is np.nan and other[1] is pd.NA, we are NOT
1586
+ # equal.
1587
+ if not np.array_equal(self._mask, other._mask):
1588
+ return False
1589
+
1590
+ left = self._data[~self._mask]
1591
+ right = other._data[~other._mask]
1592
+ return array_equivalent(left, right, strict_nan=True, dtype_equal=True)
1593
+
1594
+ def _quantile(
1595
+ self, qs: npt.NDArray[np.float64], interpolation: str
1596
+ ) -> BaseMaskedArray:
1597
+ """
1598
+ Dispatch to quantile_with_mask, needed because we do not have
1599
+ _from_factorized.
1600
+
1601
+ Notes
1602
+ -----
1603
+ We assume that all impacted cases are 1D-only.
1604
+ """
1605
+ res = quantile_with_mask(
1606
+ self._data,
1607
+ mask=self._mask,
1608
+ # TODO(GH#40932): na_value_for_dtype(self.dtype.numpy_dtype)
1609
+ # instead of np.nan
1610
+ fill_value=np.nan,
1611
+ qs=qs,
1612
+ interpolation=interpolation,
1613
+ )
1614
+
1615
+ if self._hasna:
1616
+ # Our result mask is all-False unless we are all-NA, in which
1617
+ # case it is all-True.
1618
+ if self.ndim == 2:
1619
+ # I think this should be out_mask=self.isna().all(axis=1)
1620
+ # but am holding off until we have tests
1621
+ raise NotImplementedError
1622
+ if self.isna().all():
1623
+ out_mask = np.ones(res.shape, dtype=bool)
1624
+
1625
+ if is_integer_dtype(self.dtype):
1626
+ # We try to maintain int dtype if possible for not all-na case
1627
+ # as well
1628
+ res = np.zeros(res.shape, dtype=self.dtype.numpy_dtype)
1629
+ else:
1630
+ out_mask = np.zeros(res.shape, dtype=bool)
1631
+ else:
1632
+ out_mask = np.zeros(res.shape, dtype=bool)
1633
+ return self._maybe_mask_result(res, mask=out_mask)
1634
+
1635
+ # ------------------------------------------------------------------
1636
+ # Reductions
1637
+
1638
+ def _reduce(
1639
+ self, name: str, *, skipna: bool = True, keepdims: bool = False, **kwargs
1640
+ ):
1641
+ if name in {"any", "all", "min", "max", "sum", "prod", "mean", "var", "std"}:
1642
+ result = getattr(self, name)(skipna=skipna, **kwargs)
1643
+ else:
1644
+ # median, skew, kurt, sem
1645
+ data = self._data
1646
+ mask = self._mask
1647
+ op = getattr(nanops, f"nan{name}")
1648
+ axis = kwargs.pop("axis", None)
1649
+ result = op(data, axis=axis, skipna=skipna, mask=mask, **kwargs)
1650
+
1651
+ if keepdims:
1652
+ if isna(result):
1653
+ return self._wrap_na_result(name=name, axis=0, mask_size=(1,))
1654
+ else:
1655
+ if using_python_scalars():
1656
+ result = np.array([result])
1657
+ else:
1658
+ result = result.reshape(1)
1659
+ mask = np.zeros(1, dtype=bool)
1660
+ return self._maybe_mask_result(result, mask)
1661
+
1662
+ if isna(result):
1663
+ return libmissing.NA
1664
+ else:
1665
+ return result
1666
+
1667
+ def _wrap_reduction_result(self, name: str, result, *, skipna, axis):
1668
+ if isinstance(result, np.ndarray):
1669
+ if skipna:
1670
+ # we only retain mask for all-NA rows/columns
1671
+ mask = self._mask.all(axis=axis)
1672
+ else:
1673
+ mask = self._mask.any(axis=axis)
1674
+
1675
+ return self._maybe_mask_result(result, mask)
1676
+ return result
1677
+
1678
+ def _wrap_na_result(self, *, name, axis, mask_size):
1679
+ mask = np.ones(mask_size, dtype=bool)
1680
+
1681
+ float_dtyp = "float32" if self.dtype == "Float32" else "float64"
1682
+ if name in ["mean", "median", "var", "std", "skew", "kurt", "sem"]:
1683
+ np_dtype = float_dtyp
1684
+ elif name in ["min", "max"] or self.dtype.itemsize == 8:
1685
+ np_dtype = self.dtype.numpy_dtype.name
1686
+ else:
1687
+ is_windows_or_32bit = is_platform_windows() or not IS64
1688
+ int_dtyp = "int32" if is_windows_or_32bit else "int64"
1689
+ uint_dtyp = "uint32" if is_windows_or_32bit else "uint64"
1690
+ np_dtype = {"b": int_dtyp, "i": int_dtyp, "u": uint_dtyp, "f": float_dtyp}[
1691
+ self.dtype.kind
1692
+ ]
1693
+
1694
+ value = np.array([1], dtype=np_dtype)
1695
+ return self._maybe_mask_result(value, mask=mask)
1696
+
1697
+ def _wrap_min_count_reduction_result(
1698
+ self, name: str, result, *, skipna, min_count, axis
1699
+ ):
1700
+ if min_count == 0 and skipna and isinstance(result, np.ndarray):
1701
+ return self._maybe_mask_result(result, np.zeros(result.shape, dtype=bool))
1702
+ return self._wrap_reduction_result(name, result, skipna=skipna, axis=axis)
1703
+
1704
+ def sum(
1705
+ self,
1706
+ *,
1707
+ skipna: bool = True,
1708
+ min_count: int = 0,
1709
+ axis: AxisInt | None = 0,
1710
+ **kwargs,
1711
+ ):
1712
+ nv.validate_sum((), kwargs)
1713
+
1714
+ result = masked_reductions.sum(
1715
+ self._data,
1716
+ self._mask,
1717
+ skipna=skipna,
1718
+ min_count=min_count,
1719
+ axis=axis,
1720
+ )
1721
+ return self._wrap_min_count_reduction_result(
1722
+ "sum", result, skipna=skipna, min_count=min_count, axis=axis
1723
+ )
1724
+
1725
+ def prod(
1726
+ self,
1727
+ *,
1728
+ skipna: bool = True,
1729
+ min_count: int = 0,
1730
+ axis: AxisInt | None = 0,
1731
+ **kwargs,
1732
+ ):
1733
+ nv.validate_prod((), kwargs)
1734
+
1735
+ result = masked_reductions.prod(
1736
+ self._data,
1737
+ self._mask,
1738
+ skipna=skipna,
1739
+ min_count=min_count,
1740
+ axis=axis,
1741
+ )
1742
+ return self._wrap_min_count_reduction_result(
1743
+ "prod", result, skipna=skipna, min_count=min_count, axis=axis
1744
+ )
1745
+
1746
+ def mean(self, *, skipna: bool = True, axis: AxisInt | None = 0, **kwargs):
1747
+ nv.validate_mean((), kwargs)
1748
+ result = masked_reductions.mean(
1749
+ self._data,
1750
+ self._mask,
1751
+ skipna=skipna,
1752
+ axis=axis,
1753
+ )
1754
+ return self._wrap_reduction_result("mean", result, skipna=skipna, axis=axis)
1755
+
1756
+ def var(
1757
+ self, *, skipna: bool = True, axis: AxisInt | None = 0, ddof: int = 1, **kwargs
1758
+ ):
1759
+ nv.validate_stat_ddof_func((), kwargs, fname="var")
1760
+ result = masked_reductions.var(
1761
+ self._data,
1762
+ self._mask,
1763
+ skipna=skipna,
1764
+ axis=axis,
1765
+ ddof=ddof,
1766
+ )
1767
+ return self._wrap_reduction_result("var", result, skipna=skipna, axis=axis)
1768
+
1769
+ def std(
1770
+ self, *, skipna: bool = True, axis: AxisInt | None = 0, ddof: int = 1, **kwargs
1771
+ ):
1772
+ nv.validate_stat_ddof_func((), kwargs, fname="std")
1773
+ result = masked_reductions.std(
1774
+ self._data,
1775
+ self._mask,
1776
+ skipna=skipna,
1777
+ axis=axis,
1778
+ ddof=ddof,
1779
+ )
1780
+ return self._wrap_reduction_result("std", result, skipna=skipna, axis=axis)
1781
+
1782
+ def min(self, *, skipna: bool = True, axis: AxisInt | None = 0, **kwargs):
1783
+ nv.validate_min((), kwargs)
1784
+ result = masked_reductions.min(
1785
+ self._data,
1786
+ self._mask,
1787
+ skipna=skipna,
1788
+ axis=axis,
1789
+ )
1790
+ return self._wrap_reduction_result("min", result, skipna=skipna, axis=axis)
1791
+
1792
+ def max(self, *, skipna: bool = True, axis: AxisInt | None = 0, **kwargs):
1793
+ nv.validate_max((), kwargs)
1794
+ result = masked_reductions.max(
1795
+ self._data,
1796
+ self._mask,
1797
+ skipna=skipna,
1798
+ axis=axis,
1799
+ )
1800
+ return self._wrap_reduction_result("max", result, skipna=skipna, axis=axis)
1801
+
1802
+ def count(self) -> np.int64:
1803
+ return (~self._mask).sum()
1804
+
1805
+ @overload
1806
+ def any(
1807
+ self, *, skipna: Literal[True] = ..., axis: AxisInt | None = ..., **kwargs
1808
+ ) -> np.bool_: ...
1809
+
1810
+ @overload
1811
+ def any(
1812
+ self, *, skipna: bool, axis: AxisInt | None = ..., **kwargs
1813
+ ) -> np.bool_ | NAType: ...
1814
+
1815
+ def any(
1816
+ self, *, skipna: bool = True, axis: AxisInt | None = 0, **kwargs
1817
+ ) -> np.bool_ | NAType:
1818
+ """
1819
+ Return whether any element is truthy.
1820
+
1821
+ Returns False unless there is at least one element that is truthy.
1822
+ By default, NAs are skipped. If ``skipna=False`` is specified and
1823
+ missing values are present, similar :ref:`Kleene logic <boolean.kleene>`
1824
+ is used as for logical operations.
1825
+
1826
+ Parameters
1827
+ ----------
1828
+ skipna : bool, default True
1829
+ Exclude NA values. If the entire array is NA and `skipna` is
1830
+ True, then the result will be False, as for an empty array.
1831
+ If `skipna` is False, the result will still be True if there is
1832
+ at least one element that is truthy, otherwise NA will be returned
1833
+ if there are NA's present.
1834
+ axis : int, optional, default 0
1835
+ **kwargs : any, default None
1836
+ Additional keywords have no effect but might be accepted for
1837
+ compatibility with NumPy.
1838
+
1839
+ Returns
1840
+ -------
1841
+ bool or :attr:`pandas.NA`
1842
+
1843
+ See Also
1844
+ --------
1845
+ numpy.any : Numpy version of this method.
1846
+ BaseMaskedArray.all : Return whether all elements are truthy.
1847
+
1848
+ Examples
1849
+ --------
1850
+ The result indicates whether any element is truthy (and by default
1851
+ skips NAs):
1852
+
1853
+ >>> pd.array([True, False, True]).any()
1854
+ np.True_
1855
+ >>> pd.array([True, False, pd.NA]).any()
1856
+ np.True_
1857
+ >>> pd.array([False, False, pd.NA]).any()
1858
+ np.False_
1859
+ >>> pd.array([], dtype="boolean").any()
1860
+ np.False_
1861
+ >>> pd.array([pd.NA], dtype="boolean").any()
1862
+ np.False_
1863
+ >>> pd.array([pd.NA], dtype="Float64").any()
1864
+ np.False_
1865
+
1866
+ With ``skipna=False``, the result can be NA if this is logically
1867
+ required (whether ``pd.NA`` is True or False influences the result):
1868
+
1869
+ >>> pd.array([True, False, pd.NA]).any(skipna=False)
1870
+ np.True_
1871
+ >>> pd.array([1, 0, pd.NA]).any(skipna=False)
1872
+ np.True_
1873
+ >>> pd.array([False, False, pd.NA]).any(skipna=False)
1874
+ <NA>
1875
+ >>> pd.array([0, 0, pd.NA]).any(skipna=False)
1876
+ <NA>
1877
+ """
1878
+ nv.validate_any((), kwargs)
1879
+
1880
+ values = self._data.copy()
1881
+ np.putmask(values, self._mask, self.dtype._falsey_value)
1882
+ result = values.any(axis=axis)
1883
+
1884
+ if isinstance(result, np.ndarray):
1885
+ if skipna:
1886
+ mask = np.zeros(result.shape, dtype=bool)
1887
+ else:
1888
+ # Kleene logic: False | NA = NA, True | NA = True
1889
+ mask = ~result & self._mask.any(axis=axis)
1890
+ return self._maybe_mask_result(result, mask)
1891
+
1892
+ if skipna:
1893
+ return result
1894
+ elif result or len(self) == 0 or not self._mask.any():
1895
+ return result
1896
+ else:
1897
+ return self.dtype.na_value
1898
+
1899
+ @overload
1900
+ def all(
1901
+ self, *, skipna: Literal[True] = ..., axis: AxisInt | None = ..., **kwargs
1902
+ ) -> np.bool_: ...
1903
+
1904
+ @overload
1905
+ def all(
1906
+ self, *, skipna: bool, axis: AxisInt | None = ..., **kwargs
1907
+ ) -> np.bool_ | NAType: ...
1908
+
1909
+ def all(
1910
+ self, *, skipna: bool = True, axis: AxisInt | None = 0, **kwargs
1911
+ ) -> np.bool_ | NAType:
1912
+ """
1913
+ Return whether all elements are truthy.
1914
+
1915
+ Returns True unless there is at least one element that is falsey.
1916
+ By default, NAs are skipped. If ``skipna=False`` is specified and
1917
+ missing values are present, similar :ref:`Kleene logic <boolean.kleene>`
1918
+ is used as for logical operations.
1919
+
1920
+ Parameters
1921
+ ----------
1922
+ skipna : bool, default True
1923
+ Exclude NA values. If the entire array is NA and `skipna` is
1924
+ True, then the result will be True, as for an empty array.
1925
+ If `skipna` is False, the result will still be False if there is
1926
+ at least one element that is falsey, otherwise NA will be returned
1927
+ if there are NA's present.
1928
+ axis : int, optional, default 0
1929
+ **kwargs : any, default None
1930
+ Additional keywords have no effect but might be accepted for
1931
+ compatibility with NumPy.
1932
+
1933
+ Returns
1934
+ -------
1935
+ bool or :attr:`pandas.NA`
1936
+
1937
+ See Also
1938
+ --------
1939
+ numpy.all : Numpy version of this method.
1940
+ BooleanArray.any : Return whether any element is truthy.
1941
+
1942
+ Examples
1943
+ --------
1944
+ The result indicates whether all elements are truthy (and by default
1945
+ skips NAs):
1946
+
1947
+ >>> pd.array([True, True, pd.NA]).all()
1948
+ np.True_
1949
+ >>> pd.array([1, 1, pd.NA]).all()
1950
+ np.True_
1951
+ >>> pd.array([True, False, pd.NA]).all()
1952
+ np.False_
1953
+ >>> pd.array([], dtype="boolean").all()
1954
+ np.True_
1955
+ >>> pd.array([pd.NA], dtype="boolean").all()
1956
+ np.True_
1957
+ >>> pd.array([pd.NA], dtype="Float64").all()
1958
+ np.True_
1959
+
1960
+ With ``skipna=False``, the result can be NA if this is logically
1961
+ required (whether ``pd.NA`` is True or False influences the result):
1962
+
1963
+ >>> pd.array([True, True, pd.NA]).all(skipna=False)
1964
+ <NA>
1965
+ >>> pd.array([1, 1, pd.NA]).all(skipna=False)
1966
+ <NA>
1967
+ >>> pd.array([True, False, pd.NA]).all(skipna=False)
1968
+ np.False_
1969
+ >>> pd.array([1, 0, pd.NA]).all(skipna=False)
1970
+ np.False_
1971
+ """
1972
+ nv.validate_all((), kwargs)
1973
+
1974
+ values = self._data.copy()
1975
+ np.putmask(values, self._mask, self.dtype._truthy_value)
1976
+ result = values.all(axis=axis)
1977
+
1978
+ if isinstance(result, np.ndarray):
1979
+ if skipna:
1980
+ mask = np.zeros(result.shape, dtype=bool)
1981
+ else:
1982
+ # Kleene logic: True & NA = NA, False & NA = False
1983
+ mask = result & self._mask.any(axis=axis)
1984
+ return self._maybe_mask_result(result, mask)
1985
+
1986
+ if skipna:
1987
+ return result
1988
+ elif not result or len(self) == 0 or not self._mask.any():
1989
+ return result
1990
+ else:
1991
+ return self.dtype.na_value
1992
+
1993
+ def interpolate(
1994
+ self,
1995
+ *,
1996
+ method: InterpolateOptions,
1997
+ axis: int,
1998
+ index,
1999
+ limit,
2000
+ limit_direction,
2001
+ limit_area,
2002
+ copy: bool,
2003
+ **kwargs,
2004
+ ) -> FloatingArray:
2005
+ """
2006
+ See NDFrame.interpolate.__doc__.
2007
+ """
2008
+ # NB: we return type(self) even if copy=False
2009
+ if self.dtype.kind == "f":
2010
+ if copy:
2011
+ data = self._data.copy()
2012
+ mask = self._mask.copy()
2013
+ else:
2014
+ data = self._data
2015
+ mask = self._mask
2016
+ elif self.dtype.kind in "iu":
2017
+ copy = True
2018
+ data = self._data.astype("f8")
2019
+ mask = self._mask.copy()
2020
+ else:
2021
+ raise NotImplementedError(
2022
+ f"interpolate is not implemented for dtype={self.dtype}"
2023
+ )
2024
+
2025
+ missing.interpolate_2d_inplace(
2026
+ data,
2027
+ method=method,
2028
+ axis=0,
2029
+ index=index,
2030
+ limit=limit,
2031
+ limit_direction=limit_direction,
2032
+ limit_area=limit_area,
2033
+ mask=mask,
2034
+ **kwargs,
2035
+ )
2036
+ if not copy:
2037
+ return self # type: ignore[return-value]
2038
+ if self.dtype.kind == "f":
2039
+ return type(self)._simple_new(data, mask) # type: ignore[return-value]
2040
+ else:
2041
+ from pandas.core.arrays import FloatingArray
2042
+
2043
+ return FloatingArray._simple_new(data, mask)
2044
+
2045
+ def _accumulate(
2046
+ self, name: str, *, skipna: bool = True, **kwargs
2047
+ ) -> BaseMaskedArray:
2048
+ data = self._data
2049
+ mask = self._mask
2050
+
2051
+ op = getattr(masked_accumulations, name)
2052
+ data, mask = op(data, mask, skipna=skipna, **kwargs)
2053
+
2054
+ return self._simple_new(data, mask)
2055
+
2056
+ # ------------------------------------------------------------------
2057
+ # GroupBy Methods
2058
+
2059
+ def _groupby_op(
2060
+ self,
2061
+ *,
2062
+ how: str,
2063
+ has_dropped_na: bool,
2064
+ min_count: int,
2065
+ ngroups: int,
2066
+ ids: npt.NDArray[np.intp],
2067
+ **kwargs,
2068
+ ):
2069
+ from pandas.core.groupby.ops import WrappedCythonOp
2070
+
2071
+ kind = WrappedCythonOp.get_kind_from_how(how)
2072
+ op = WrappedCythonOp(how=how, kind=kind, has_dropped_na=has_dropped_na)
2073
+
2074
+ # libgroupby functions are responsible for NOT altering mask
2075
+ mask = self._mask
2076
+ if op.kind != "aggregate":
2077
+ result_mask = mask.copy()
2078
+ else:
2079
+ result_mask = np.zeros(ngroups, dtype=bool)
2080
+
2081
+ if how == "rank" and kwargs.get("na_option") in ["top", "bottom"]:
2082
+ result_mask[:] = False
2083
+
2084
+ res_values = op._cython_op_ndim_compat(
2085
+ self._data,
2086
+ min_count=min_count,
2087
+ ngroups=ngroups,
2088
+ comp_ids=ids,
2089
+ mask=mask,
2090
+ result_mask=result_mask,
2091
+ **kwargs,
2092
+ )
2093
+
2094
+ if op.how == "ohlc":
2095
+ arity = op._cython_arity.get(op.how, 1)
2096
+ result_mask = np.tile(result_mask, (arity, 1)).T
2097
+
2098
+ if op.how in ["idxmin", "idxmax"]:
2099
+ # Result values are indexes to take, keep as ndarray
2100
+ return res_values
2101
+ else:
2102
+ # res_values should already have the correct dtype, we just need to
2103
+ # wrap in a MaskedArray
2104
+ return self._maybe_mask_result(res_values, result_mask)
2105
+
2106
+
2107
+ def transpose_homogeneous_masked_arrays(
2108
+ masked_arrays: Sequence[BaseMaskedArray],
2109
+ ) -> list[BaseMaskedArray]:
2110
+ """Transpose masked arrays in a list, but faster.
2111
+
2112
+ Input should be a list of 1-dim masked arrays of equal length and all have the
2113
+ same dtype. The caller is responsible for ensuring validity of input data.
2114
+ """
2115
+ masked_arrays = list(masked_arrays)
2116
+ dtype = masked_arrays[0].dtype
2117
+
2118
+ values = [arr._data.reshape(1, -1) for arr in masked_arrays]
2119
+ transposed_values = np.concatenate(
2120
+ values,
2121
+ axis=0,
2122
+ out=np.empty(
2123
+ (len(masked_arrays), len(masked_arrays[0])),
2124
+ order="F",
2125
+ dtype=dtype.numpy_dtype,
2126
+ ),
2127
+ )
2128
+
2129
+ masks = [arr._mask.reshape(1, -1) for arr in masked_arrays]
2130
+ transposed_masks = np.concatenate(
2131
+ masks, axis=0, out=np.empty_like(transposed_values, dtype=bool)
2132
+ )
2133
+
2134
+ arr_type = dtype.construct_array_type()
2135
+ transposed_arrays: list[BaseMaskedArray] = []
2136
+ for i in range(transposed_values.shape[1]):
2137
+ transposed_arr = arr_type(transposed_values[:, i], mask=transposed_masks[:, i])
2138
+ transposed_arrays.append(transposed_arr)
2139
+
2140
+ return transposed_arrays