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