ohmydata 0.3.2__tar.gz → 0.3.3__tar.gz
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.
- {ohmydata-0.3.2 → ohmydata-0.3.3}/CHANGELOG.md +7 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/PKG-INFO +38 -1
- {ohmydata-0.3.2 → ohmydata-0.3.3}/README.md +37 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/pyproject.toml +1 -1
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/__init__.py +1 -1
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/__init__.py +3 -0
- ohmydata-0.3.3/src/ohmydata/providers/sec/submissions.py +143 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/uv.lock +1 -1
- {ohmydata-0.3.2 → ohmydata-0.3.3}/.gitignore +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/adapters/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/adapters/polars.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/cli.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/_vintage_lock.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/availability.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/errors.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/facts.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/instruments.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/policy.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/provenance.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/rate_limit.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/snapshot.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/specs.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/core/vintage.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_accounting_models.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_dated_invalidation_models.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_document_bundle_codec.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_document_financial_contract.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_document_source_links.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_discovery_models.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_execution_io.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_execution_models.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_execution_receipts.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_ledger_io.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_recompute_codec.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_work_codec.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_work_models.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_event_work_transitions.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_live_unit_corroboration.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_metric_arithmetic.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_metric_common.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_metric_evaluation.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_metric_graph_models.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_metric_inputs.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_financial_bundle_codec.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_financial_bundle_graph.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_financial_output.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_financial_receipts.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_xbrl_units.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_pit_bundle_findings.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_pit_projection.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_pit_query.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_statement_parser.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_structural_admission.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/artifacts.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/batch.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/cli.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/core_dataset.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/dated_invalidation.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/document_accounting.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/document_financial_bundle.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/document_financial_replay.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/document_financials.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/document_source.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/edgar.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/edgartools_adapter.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/embedded_document_source.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/endpoints.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/errors.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/event_dependencies.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/event_discovery.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/event_execution.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/event_ledger.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/event_recompute.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/event_work.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/financials.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/financials_dataset.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/http.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/known_by_ttm.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/metric_graph.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/nport.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/observed_accounting.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/observed_financial_bundle.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/observed_financial_replay.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/observed_xbrl_financials.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/observed_xbrl_package.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/pit.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/pit_bundle.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/qualification.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/qualification_dataset.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/quality_findings.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/quarter_binding.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/quarter_ttm.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/sgml_financials.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/structural_quality.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/unit_evidence.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/xbrl_package.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/xbrl_package_financials.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/client.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/endpoints.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/errors.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/observations/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/observations/capture.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/observations/serialization.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/etf_adjusted_bars.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/etf_index_mapping.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/etf_pcf_history.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/index_weight_vintage.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/lookthrough_bundle.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/shared.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/weighted_dividend_yield.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/vintage_artifacts.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/vintage_canonical.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/vintage_gates.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/vintage_plane.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/vintage_producer.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/_fundamentals_parsers.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/_fundamentals_periods.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/client.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/endpoints.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/errors.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/fundamentals.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/yfinance/quality.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/tools/__init__.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/tools/cli.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/tools/drift_audit.py +0 -0
- {ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/tools/universes.py +0 -0
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.3.3 — 2026-09-23
|
|
6
|
+
|
|
7
|
+
- Add `fetch_sec_submissions_closure` to fetch and retain a complete SEC
|
|
8
|
+
Submissions root and its advertised history pages using the injected SEC HTTP
|
|
9
|
+
client. It returns snapshot-backed discovery sources and fails explicitly on
|
|
10
|
+
missing pages, malformed schemas, conflicting accession metadata or bounds.
|
|
11
|
+
|
|
5
12
|
## 0.3.2 — 2026-09-13
|
|
6
13
|
|
|
7
14
|
- Narrow OMD SEC v2 live XBRL compatibility fix:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ohmydata
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Financial and alternative market data ingestion SDK.
|
|
5
5
|
Author: OMD contributors
|
|
6
6
|
Requires-Python: <3.13,>=3.11
|
|
@@ -728,6 +728,43 @@ It preserves acceptance metadata, emits filing events and exact 8-K item 2.02
|
|
|
728
728
|
events, and fails on missing pages or conflicting facts. Acceptance is not proof
|
|
729
729
|
of the website's first publication time.
|
|
730
730
|
|
|
731
|
+
`fetch_sec_submissions_closure` obtains that complete root and every advertised
|
|
732
|
+
history page with an injected `SecHttpClient` and `SnapshotStore`. The client
|
|
733
|
+
requires a caller supplied SEC User-Agent and applies its request spacing and
|
|
734
|
+
retry policy for transient connection and HTTP status failures. A response body
|
|
735
|
+
read failure is classified as transient; the caller retries the full closure.
|
|
736
|
+
The fetcher validates bounded JSON, response length, CIK, page names,
|
|
737
|
+
columns and duplicate accession metadata, then retains exact response bytes as
|
|
738
|
+
append-only observations. A failed later page leaves earlier observations
|
|
739
|
+
available for inspection but returns no complete closure. A new call fetches a
|
|
740
|
+
fresh root and all pages it advertises; callers choose their own schedule and
|
|
741
|
+
reconciliation windows. Up to 16 history pages, 8 MiB per page, 64 MiB total and
|
|
742
|
+
100,000 filing rows are supported; exceeding a bound fails explicitly.
|
|
743
|
+
|
|
744
|
+
```python
|
|
745
|
+
from ohmydata.providers.sec import (
|
|
746
|
+
SecHttpClient,
|
|
747
|
+
fetch_sec_submissions_closure,
|
|
748
|
+
discover_sec_filing_events,
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
closure = fetch_sec_submissions_closure(snapshot_store, SecHttpClient(sec_user_agent), "0000000001")
|
|
752
|
+
batch = discover_sec_filing_events(
|
|
753
|
+
snapshot_store,
|
|
754
|
+
closure.root_source,
|
|
755
|
+
closure.historical_sources,
|
|
756
|
+
policy=discovery_policy,
|
|
757
|
+
prior_cursor=prior_cursor,
|
|
758
|
+
)
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
The closure is retained source evidence. Event discovery does not infer whether
|
|
762
|
+
an amendment changes financial values. Existing retained document and SGML
|
|
763
|
+
financial production paths take an explicit accession, while the live
|
|
764
|
+
`SecFinancialsClient` still selects filings by form and date. This fetcher does
|
|
765
|
+
not acquire the filing artifacts needed for exact-accession financial production.
|
|
766
|
+
Event ledger/work processing remains a separate step.
|
|
767
|
+
|
|
731
768
|
`SecEventDiscoveryLedger` atomically stores discovered events and their cursor in
|
|
732
769
|
immutable generations. On POSIX filesystems, appenders cooperate through a writer
|
|
733
770
|
lock; `load()` replays the retained source observations and reconstructs the
|
|
@@ -702,6 +702,43 @@ It preserves acceptance metadata, emits filing events and exact 8-K item 2.02
|
|
|
702
702
|
events, and fails on missing pages or conflicting facts. Acceptance is not proof
|
|
703
703
|
of the website's first publication time.
|
|
704
704
|
|
|
705
|
+
`fetch_sec_submissions_closure` obtains that complete root and every advertised
|
|
706
|
+
history page with an injected `SecHttpClient` and `SnapshotStore`. The client
|
|
707
|
+
requires a caller supplied SEC User-Agent and applies its request spacing and
|
|
708
|
+
retry policy for transient connection and HTTP status failures. A response body
|
|
709
|
+
read failure is classified as transient; the caller retries the full closure.
|
|
710
|
+
The fetcher validates bounded JSON, response length, CIK, page names,
|
|
711
|
+
columns and duplicate accession metadata, then retains exact response bytes as
|
|
712
|
+
append-only observations. A failed later page leaves earlier observations
|
|
713
|
+
available for inspection but returns no complete closure. A new call fetches a
|
|
714
|
+
fresh root and all pages it advertises; callers choose their own schedule and
|
|
715
|
+
reconciliation windows. Up to 16 history pages, 8 MiB per page, 64 MiB total and
|
|
716
|
+
100,000 filing rows are supported; exceeding a bound fails explicitly.
|
|
717
|
+
|
|
718
|
+
```python
|
|
719
|
+
from ohmydata.providers.sec import (
|
|
720
|
+
SecHttpClient,
|
|
721
|
+
fetch_sec_submissions_closure,
|
|
722
|
+
discover_sec_filing_events,
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
closure = fetch_sec_submissions_closure(snapshot_store, SecHttpClient(sec_user_agent), "0000000001")
|
|
726
|
+
batch = discover_sec_filing_events(
|
|
727
|
+
snapshot_store,
|
|
728
|
+
closure.root_source,
|
|
729
|
+
closure.historical_sources,
|
|
730
|
+
policy=discovery_policy,
|
|
731
|
+
prior_cursor=prior_cursor,
|
|
732
|
+
)
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
The closure is retained source evidence. Event discovery does not infer whether
|
|
736
|
+
an amendment changes financial values. Existing retained document and SGML
|
|
737
|
+
financial production paths take an explicit accession, while the live
|
|
738
|
+
`SecFinancialsClient` still selects filings by form and date. This fetcher does
|
|
739
|
+
not acquire the filing artifacts needed for exact-accession financial production.
|
|
740
|
+
Event ledger/work processing remains a separate step.
|
|
741
|
+
|
|
705
742
|
`SecEventDiscoveryLedger` atomically stores discovered events and their cursor in
|
|
706
743
|
immutable generations. On POSIX filesystems, appenders cooperate through a writer
|
|
707
744
|
lock; `load()` replays the retained source observations and reconstructs the
|
|
@@ -266,6 +266,7 @@ from .sgml_financials import (
|
|
|
266
266
|
produce_sec_financials_from_sgml,
|
|
267
267
|
)
|
|
268
268
|
from .structural_quality import SecStructuralQualityReport, evaluate_sec_structural_quality
|
|
269
|
+
from .submissions import SecSubmissionsClosure, fetch_sec_submissions_closure
|
|
269
270
|
from .unit_evidence import SecFinancialUnitEvidence
|
|
270
271
|
from .xbrl_package import (
|
|
271
272
|
SecXbrlPackage,
|
|
@@ -419,6 +420,7 @@ __all__ = [
|
|
|
419
420
|
"SecStatementParseError",
|
|
420
421
|
"SecStatementRow",
|
|
421
422
|
"SecStructuralQualityReport",
|
|
423
|
+
"SecSubmissionsClosure",
|
|
422
424
|
"SecTargetMetricInputs",
|
|
423
425
|
"SecTransportEvidence",
|
|
424
426
|
"SecUnavailableResult",
|
|
@@ -449,6 +451,7 @@ __all__ = [
|
|
|
449
451
|
"evaluate_sec_structural_quality",
|
|
450
452
|
"execute_sec_metric_recompute",
|
|
451
453
|
"extract_from_artifact",
|
|
454
|
+
"fetch_sec_submissions_closure",
|
|
452
455
|
"historical_basenames",
|
|
453
456
|
"historical_submission_url",
|
|
454
457
|
"latest_completed_quarter",
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Retain a complete SEC Submissions root and its advertised history pages."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from datetime import UTC, datetime
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from ...core import RequestSpec, SnapshotMode, SnapshotStore
|
|
12
|
+
from ._event_discovery_models import SecDiscoverySource
|
|
13
|
+
from .edgar import historical_basenames, historical_submission_url
|
|
14
|
+
from .errors import (
|
|
15
|
+
PermanentProviderError,
|
|
16
|
+
ResourceLimitError,
|
|
17
|
+
SchemaMismatchError,
|
|
18
|
+
TransientProviderError,
|
|
19
|
+
)
|
|
20
|
+
from .event_discovery import _strict_json, _submission_rows
|
|
21
|
+
from .http import SecHttpClient, validate_sec_url
|
|
22
|
+
|
|
23
|
+
_SOURCE_LIMIT = 8 * 1024**2
|
|
24
|
+
_TOTAL_LIMIT = 64 * 1024**2
|
|
25
|
+
_ROW_LIMIT = 100_000
|
|
26
|
+
_SERIALIZATION = "sec-submissions-json-v1"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass(frozen=True)
|
|
30
|
+
class SecSubmissionsClosure:
|
|
31
|
+
"""A retained root and every history page named by that exact root."""
|
|
32
|
+
|
|
33
|
+
cik: str
|
|
34
|
+
root_source: SecDiscoverySource
|
|
35
|
+
historical_sources: tuple[SecDiscoverySource, ...]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _exact_url(expected: str, actual: str) -> str:
|
|
39
|
+
if validate_sec_url(actual) != validate_sec_url(expected):
|
|
40
|
+
raise PermanentProviderError("SEC submissions redirect changed source URL")
|
|
41
|
+
return actual
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _fetch(client: SecHttpClient, url: str, remaining: int) -> bytes:
|
|
45
|
+
if remaining <= 0:
|
|
46
|
+
raise ResourceLimitError("aggregate submissions bytes exceeded")
|
|
47
|
+
response = client.open(
|
|
48
|
+
url,
|
|
49
|
+
accept="application/json",
|
|
50
|
+
max_bytes=min(_SOURCE_LIMIT, remaining),
|
|
51
|
+
redirect_validator=lambda actual: _exact_url(url, actual),
|
|
52
|
+
)
|
|
53
|
+
try:
|
|
54
|
+
_exact_url(url, response.url)
|
|
55
|
+
try:
|
|
56
|
+
body: bytes = response.body.read()
|
|
57
|
+
except (TimeoutError, ConnectionError, OSError) as exc:
|
|
58
|
+
raise TransientProviderError("SEC submissions response read failed") from exc
|
|
59
|
+
if type(body) is not bytes or len(body) > min(_SOURCE_LIMIT, remaining):
|
|
60
|
+
raise ResourceLimitError("submissions response bytes exceeded")
|
|
61
|
+
declared_length = response.headers.get("Content-Length")
|
|
62
|
+
if declared_length is not None and len(body) != int(declared_length):
|
|
63
|
+
raise TransientProviderError("SEC submissions response length mismatch")
|
|
64
|
+
return body
|
|
65
|
+
finally:
|
|
66
|
+
response.body.close()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def fetch_sec_submissions_closure(
|
|
70
|
+
store: SnapshotStore,
|
|
71
|
+
client: SecHttpClient,
|
|
72
|
+
cik: str,
|
|
73
|
+
*,
|
|
74
|
+
utc_now: Callable[[], datetime] = lambda: datetime.now(UTC),
|
|
75
|
+
) -> SecSubmissionsClosure:
|
|
76
|
+
"""Fetch and append immutable observations for one complete advertised closure.
|
|
77
|
+
|
|
78
|
+
Each HTTP GET uses the injected SEC client's limiter and classified retries.
|
|
79
|
+
Failed later pages leave earlier observations retained, but no closure is returned.
|
|
80
|
+
A subsequent invocation fetches a fresh root and all pages it advertises.
|
|
81
|
+
"""
|
|
82
|
+
if type(cik) is not str or re.fullmatch(r"[0-9]{10}", cik) is None:
|
|
83
|
+
raise ValueError("CIK must be ten digits")
|
|
84
|
+
if not isinstance(store, SnapshotStore) or not isinstance(client, SecHttpClient):
|
|
85
|
+
raise TypeError("invalid submissions fetch dependencies")
|
|
86
|
+
|
|
87
|
+
root_url = f"https://data.sec.gov/submissions/CIK{cik}.json"
|
|
88
|
+
root_bytes = _fetch(client, root_url, _TOTAL_LIMIT)
|
|
89
|
+
root = _strict_json(root_bytes)
|
|
90
|
+
filings = root.get("filings")
|
|
91
|
+
if not isinstance(filings, dict) or not isinstance(filings.get("files"), list):
|
|
92
|
+
raise SchemaMismatchError("historical submissions references missing")
|
|
93
|
+
names = historical_basenames(root, cik)
|
|
94
|
+
observed = len(root_bytes)
|
|
95
|
+
rows: dict[str, dict[str, object]] = {}
|
|
96
|
+
row_count = 0
|
|
97
|
+
|
|
98
|
+
def validate_rows(payload: dict[str, Any], *, child: bool) -> None:
|
|
99
|
+
nonlocal row_count
|
|
100
|
+
for row in _submission_rows(payload, cik, child=child):
|
|
101
|
+
row_count += 1
|
|
102
|
+
if row_count > _ROW_LIMIT:
|
|
103
|
+
raise ResourceLimitError("aggregate filing row limit exceeded")
|
|
104
|
+
accession = row["accessionNumber"]
|
|
105
|
+
if (
|
|
106
|
+
not isinstance(accession, str)
|
|
107
|
+
or re.fullmatch(r"[0-9]{10}-[0-9]{2}-[0-9]{6}", accession) is None
|
|
108
|
+
):
|
|
109
|
+
raise SchemaMismatchError("invalid accession")
|
|
110
|
+
old = rows.setdefault(accession, row)
|
|
111
|
+
if old != row:
|
|
112
|
+
raise SchemaMismatchError("conflicting submission metadata")
|
|
113
|
+
|
|
114
|
+
validate_rows(root, child=False)
|
|
115
|
+
|
|
116
|
+
def retain(
|
|
117
|
+
endpoint: str, parameters: dict[str, str], url: str, body: bytes
|
|
118
|
+
) -> SecDiscoverySource:
|
|
119
|
+
fetched_at = utc_now()
|
|
120
|
+
observation = store.observe(
|
|
121
|
+
RequestSpec("sec", endpoint, parameters),
|
|
122
|
+
body,
|
|
123
|
+
fetched_at,
|
|
124
|
+
_SERIALIZATION,
|
|
125
|
+
SnapshotMode.APPEND,
|
|
126
|
+
)
|
|
127
|
+
return SecDiscoverySource(url, observation)
|
|
128
|
+
|
|
129
|
+
root_source = retain("edgar_submissions", {"cik": cik}, root_url, root_bytes)
|
|
130
|
+
children: list[SecDiscoverySource] = []
|
|
131
|
+
for name in names:
|
|
132
|
+
url = historical_submission_url(cik, name)
|
|
133
|
+
body = _fetch(client, url, _TOTAL_LIMIT - observed)
|
|
134
|
+
observed += len(body)
|
|
135
|
+
child = _strict_json(body)
|
|
136
|
+
validate_rows(child, child=True)
|
|
137
|
+
children.append(
|
|
138
|
+
retain("edgar_submissions_history", {"cik": cik, "basename": name}, url, body)
|
|
139
|
+
)
|
|
140
|
+
return SecSubmissionsClosure(cik, root_source, tuple(children))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
__all__ = ["SecSubmissionsClosure", "fetch_sec_submissions_closure"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_document_financial_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_financial_bundle_codec.py
RENAMED
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_financial_bundle_graph.py
RENAMED
|
File without changes
|
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/sec/_observed_financial_receipts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/observations/serialization.py
RENAMED
|
File without changes
|
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/etf_adjusted_bars.py
RENAMED
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/etf_index_mapping.py
RENAMED
|
File without changes
|
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/index_weight_vintage.py
RENAMED
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/lookthrough_bundle.py
RENAMED
|
File without changes
|
|
File without changes
|
{ohmydata-0.3.2 → ohmydata-0.3.3}/src/ohmydata/providers/tushare/recipes/weighted_dividend_yield.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|