hkex-filing-scraper 2.1.0__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.
- hkex_filing_scraper-2.1.0/.editorconfig +16 -0
- hkex_filing_scraper-2.1.0/.env.example +140 -0
- hkex_filing_scraper-2.1.0/.gitattributes +18 -0
- hkex_filing_scraper-2.1.0/.github/CODEOWNERS +8 -0
- hkex_filing_scraper-2.1.0/.github/FUNDING.yml +5 -0
- hkex_filing_scraper-2.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +78 -0
- hkex_filing_scraper-2.1.0/.github/ISSUE_TEMPLATE/config.yml +11 -0
- hkex_filing_scraper-2.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +46 -0
- hkex_filing_scraper-2.1.0/.github/PULL_REQUEST_TEMPLATE.md +35 -0
- hkex_filing_scraper-2.1.0/.github/dependabot.yml +30 -0
- hkex_filing_scraper-2.1.0/.github/workflows/canary.yml +70 -0
- hkex_filing_scraper-2.1.0/.github/workflows/ci.yml +374 -0
- hkex_filing_scraper-2.1.0/.github/workflows/codeql.yml +26 -0
- hkex_filing_scraper-2.1.0/.github/workflows/pages.yml +50 -0
- hkex_filing_scraper-2.1.0/.github/workflows/pypi.yml +59 -0
- hkex_filing_scraper-2.1.0/.github/workflows/release.yml +140 -0
- hkex_filing_scraper-2.1.0/.github/workflows/scorecard.yml +48 -0
- hkex_filing_scraper-2.1.0/.github/workflows/wiki.yml +76 -0
- hkex_filing_scraper-2.1.0/.gitignore +53 -0
- hkex_filing_scraper-2.1.0/.markdownlint-cli2.jsonc +32 -0
- hkex_filing_scraper-2.1.0/.pre-commit-config.yaml +27 -0
- hkex_filing_scraper-2.1.0/AGENTS.md +124 -0
- hkex_filing_scraper-2.1.0/CHANGELOG.md +192 -0
- hkex_filing_scraper-2.1.0/CITATION.cff +27 -0
- hkex_filing_scraper-2.1.0/CODE_OF_CONDUCT.md +127 -0
- hkex_filing_scraper-2.1.0/CONTRIBUTING.md +95 -0
- hkex_filing_scraper-2.1.0/GOVERNANCE.md +65 -0
- hkex_filing_scraper-2.1.0/LICENSE +9 -0
- hkex_filing_scraper-2.1.0/PKG-INFO +464 -0
- hkex_filing_scraper-2.1.0/README.md +401 -0
- hkex_filing_scraper-2.1.0/SECURITY.md +92 -0
- hkex_filing_scraper-2.1.0/SUPPORT.md +47 -0
- hkex_filing_scraper-2.1.0/constitution.md +147 -0
- hkex_filing_scraper-2.1.0/docs/STYLE.md +64 -0
- hkex_filing_scraper-2.1.0/docs/adr/0001-versioning-and-release-automation.md +45 -0
- hkex_filing_scraper-2.1.0/docs/adr/0002-multi-sink-architecture.md +62 -0
- hkex_filing_scraper-2.1.0/docs/adr/0003-sink-support-policy.md +59 -0
- hkex_filing_scraper-2.1.0/docs/architecture.md +120 -0
- hkex_filing_scraper-2.1.0/docs/assets/banner.svg +70 -0
- hkex_filing_scraper-2.1.0/docs/assets/favicon.svg +8 -0
- hkex_filing_scraper-2.1.0/docs/assets/javascripts/a11y.js +62 -0
- hkex_filing_scraper-2.1.0/docs/assets/stylesheets/terminal.css +307 -0
- hkex_filing_scraper-2.1.0/docs/cli.md +62 -0
- hkex_filing_scraper-2.1.0/docs/configuration.md +137 -0
- hkex_filing_scraper-2.1.0/docs/de-risking.md +51 -0
- hkex_filing_scraper-2.1.0/docs/getting-started.md +133 -0
- hkex_filing_scraper-2.1.0/docs/index.md +54 -0
- hkex_filing_scraper-2.1.0/docs/legal.md +58 -0
- hkex_filing_scraper-2.1.0/docs/release-automation.md +185 -0
- hkex_filing_scraper-2.1.0/docs/releasing.md +129 -0
- hkex_filing_scraper-2.1.0/docs/sinks/README.md +84 -0
- hkex_filing_scraper-2.1.0/docs/sinks/clickhouse.md +78 -0
- hkex_filing_scraper-2.1.0/docs/sinks/duckdb.md +68 -0
- hkex_filing_scraper-2.1.0/docs/sinks/mongodb.md +82 -0
- hkex_filing_scraper-2.1.0/docs/sinks/mysql.md +69 -0
- hkex_filing_scraper-2.1.0/docs/sinks/neo4j.md +84 -0
- hkex_filing_scraper-2.1.0/docs/sinks/postgresql.md +130 -0
- hkex_filing_scraper-2.1.0/docs/sinks/sqlite.md +72 -0
- hkex_filing_scraper-2.1.0/docs/sinks/surrealdb.md +106 -0
- hkex_filing_scraper-2.1.0/docs/social_preview.png +0 -0
- hkex_filing_scraper-2.1.0/docs/testing.md +150 -0
- hkex_filing_scraper-2.1.0/docs/troubleshooting.md +117 -0
- hkex_filing_scraper-2.1.0/docs/upgrading.md +74 -0
- hkex_filing_scraper-2.1.0/examples/README.md +60 -0
- hkex_filing_scraper-2.1.0/examples/docker-compose.yml +74 -0
- hkex_filing_scraper-2.1.0/examples/quickstart.sh +45 -0
- hkex_filing_scraper-2.1.0/mkdocs.yml +71 -0
- hkex_filing_scraper-2.1.0/pyproject.toml +137 -0
- hkex_filing_scraper-2.1.0/scripts/canary.py +127 -0
- hkex_filing_scraper-2.1.0/scripts/check_licenses.py +77 -0
- hkex_filing_scraper-2.1.0/scripts/mirror_wiki.py +260 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/__init__.py +10 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/_version.py +24 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/api.py +302 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/config.py +240 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/db.py +267 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/db_postgres.py +713 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/extractor.py +732 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/graph.py +175 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/http.py +149 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/main.py +425 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/pipeline.py +702 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/py.typed +0 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/__init__.py +96 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/base.py +158 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/clickhouse.py +474 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/dialects.py +540 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/duckdb.py +122 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/mongodb.py +428 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/mysql.py +158 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/neo4j.py +413 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/postgres.py +90 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/registry.py +192 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/relational.py +340 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/sqlite.py +111 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/sinks/surrealdb.py +606 -0
- hkex_filing_scraper-2.1.0/src/hkex_scraper/utils.py +211 -0
- hkex_filing_scraper-2.1.0/tests/__init__.py +0 -0
- hkex_filing_scraper-2.1.0/tests/conftest.py +50 -0
- hkex_filing_scraper-2.1.0/tests/test_api_contract.py +226 -0
- hkex_filing_scraper-2.1.0/tests/test_canary.py +137 -0
- hkex_filing_scraper-2.1.0/tests/test_cli.py +164 -0
- hkex_filing_scraper-2.1.0/tests/test_config.py +96 -0
- hkex_filing_scraper-2.1.0/tests/test_coverage.py +101 -0
- hkex_filing_scraper-2.1.0/tests/test_dialects.py +154 -0
- hkex_filing_scraper-2.1.0/tests/test_docs_consistency.py +213 -0
- hkex_filing_scraper-2.1.0/tests/test_duckdb_integration.py +163 -0
- hkex_filing_scraper-2.1.0/tests/test_extra_sinks.py +215 -0
- hkex_filing_scraper-2.1.0/tests/test_extra_sinks_integration.py +153 -0
- hkex_filing_scraper-2.1.0/tests/test_fault_injection.py +183 -0
- hkex_filing_scraper-2.1.0/tests/test_fidelity.py +129 -0
- hkex_filing_scraper-2.1.0/tests/test_http.py +233 -0
- hkex_filing_scraper-2.1.0/tests/test_hypothesis.py +163 -0
- hkex_filing_scraper-2.1.0/tests/test_multi_sink_integration.py +92 -0
- hkex_filing_scraper-2.1.0/tests/test_mysql_integration.py +104 -0
- hkex_filing_scraper-2.1.0/tests/test_postgres_integration.py +148 -0
- hkex_filing_scraper-2.1.0/tests/test_postgres_sink.py +292 -0
- hkex_filing_scraper-2.1.0/tests/test_registry.py +94 -0
- hkex_filing_scraper-2.1.0/tests/test_relational_sink.py +62 -0
- hkex_filing_scraper-2.1.0/tests/test_sink_dispatch.py +234 -0
- hkex_filing_scraper-2.1.0/tests/test_sqlite_integration.py +203 -0
- hkex_filing_scraper-2.1.0/tests/test_supply_chain.py +167 -0
- hkex_filing_scraper-2.1.0/tests/test_surrealdb_integration.py +131 -0
- hkex_filing_scraper-2.1.0/tests/test_theme.py +147 -0
- hkex_filing_scraper-2.1.0/tests/test_utils.py +149 -0
- hkex_filing_scraper-2.1.0/tests/test_verify.py +263 -0
- hkex_filing_scraper-2.1.0/uv.lock +2471 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
indent_size = 4
|
|
10
|
+
max_line_length = 100
|
|
11
|
+
|
|
12
|
+
[*.{yml,yaml,json,toml}]
|
|
13
|
+
indent_size = 2
|
|
14
|
+
|
|
15
|
+
[*.md]
|
|
16
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# HKEx Filing Scraper — Environment Configuration
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Copy this file to .env and fill in your values:
|
|
5
|
+
# cp .env.example .env
|
|
6
|
+
#
|
|
7
|
+
# .env is loaded from the CURRENT WORKING DIRECTORY, not the repo root.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
# Database sink selection (REQUIRED)
|
|
12
|
+
# ---------------------------------------------------------------------------
|
|
13
|
+
# An ordered, comma-separated list of sink ids. Every configured sink is
|
|
14
|
+
# written to; reads come from the first sink that supports them.
|
|
15
|
+
# Valid ids (documented popularity order):
|
|
16
|
+
# postgres PostgreSQL 13+ (extra: postgres)
|
|
17
|
+
# mysql MySQL 8 (extra: mysql)
|
|
18
|
+
# sqlite SQLite file (no extra)
|
|
19
|
+
# mongodb MongoDB 6+ (extra: mongodb)
|
|
20
|
+
# mariadb MariaDB 10.5+ (extra: mysql)
|
|
21
|
+
# neo4j Neo4j 5 (extra: neo4j)
|
|
22
|
+
# clickhouse ClickHouse 24+ (extra: clickhouse)
|
|
23
|
+
# duckdb DuckDB file (extra: duckdb)
|
|
24
|
+
# surrealdb SurrealDB (no extra)
|
|
25
|
+
#
|
|
26
|
+
# Examples:
|
|
27
|
+
# DATABASE_TARGET=postgres,sqlite
|
|
28
|
+
# DATABASE_TARGET=mysql,clickhouse
|
|
29
|
+
# DATABASE_TARGET=sqlite
|
|
30
|
+
DATABASE_TARGET=postgres,sqlite
|
|
31
|
+
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
# PostgreSQL (required when DATABASE_TARGET includes postgres)
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
# Install the driver first: pip install "hkex-filing-scraper[postgres]"
|
|
36
|
+
#
|
|
37
|
+
# Either provide a full connection string...
|
|
38
|
+
POSTGRES_DSN=
|
|
39
|
+
# ...or the discrete settings below (used when POSTGRES_DSN is empty).
|
|
40
|
+
POSTGRES_HOST=localhost
|
|
41
|
+
POSTGRES_PORT=5432
|
|
42
|
+
POSTGRES_DATABASE=
|
|
43
|
+
POSTGRES_USER=
|
|
44
|
+
POSTGRES_PASSWORD=
|
|
45
|
+
POSTGRES_SCHEMA=public
|
|
46
|
+
# Connection pool sizing (OPTIONAL)
|
|
47
|
+
# POSTGRES_MIN_POOL=1
|
|
48
|
+
# POSTGRES_MAX_POOL=15
|
|
49
|
+
|
|
50
|
+
# ---------------------------------------------------------------------------
|
|
51
|
+
# MySQL / MariaDB (required when DATABASE_TARGET includes mysql or mariadb)
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# Install the driver first: pip install "hkex-filing-scraper[mysql]"
|
|
54
|
+
#
|
|
55
|
+
# MYSQL_DSN=mysql://user:password@localhost:3306/hkex
|
|
56
|
+
MYSQL_HOST=localhost
|
|
57
|
+
MYSQL_PORT=3306
|
|
58
|
+
MYSQL_DATABASE=
|
|
59
|
+
MYSQL_USER=
|
|
60
|
+
MYSQL_PASSWORD=
|
|
61
|
+
# The mariadb sink reads MARIADB_* and falls back to MYSQL_* when its own are unset.
|
|
62
|
+
# MARIADB_DSN=
|
|
63
|
+
# MARIADB_HOST=localhost
|
|
64
|
+
# MARIADB_PORT=3306
|
|
65
|
+
# MARIADB_DATABASE=
|
|
66
|
+
# MARIADB_USER=
|
|
67
|
+
# MARIADB_PASSWORD=
|
|
68
|
+
|
|
69
|
+
# ---------------------------------------------------------------------------
|
|
70
|
+
# SQLite / DuckDB (required when DATABASE_TARGET includes sqlite or duckdb)
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# SQLite needs no extra dependency.
|
|
73
|
+
# DuckDB: pip install "hkex-filing-scraper[duckdb]"
|
|
74
|
+
#
|
|
75
|
+
# SQLITE_PATH=hkex.db # a file path, or :memory:
|
|
76
|
+
# DUCKDB_PATH=hkex.duckdb # a file path, or :memory:
|
|
77
|
+
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
# MongoDB (required when DATABASE_TARGET includes mongodb)
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
# Install the driver first: pip install "hkex-filing-scraper[mongodb]"
|
|
82
|
+
#
|
|
83
|
+
# MONGODB_URI=mongodb://localhost:27017
|
|
84
|
+
# MONGODB_DATABASE=hkex
|
|
85
|
+
|
|
86
|
+
# ---------------------------------------------------------------------------
|
|
87
|
+
# ClickHouse (required when DATABASE_TARGET includes clickhouse)
|
|
88
|
+
# ---------------------------------------------------------------------------
|
|
89
|
+
# Install the driver first: pip install "hkex-filing-scraper[clickhouse]"
|
|
90
|
+
#
|
|
91
|
+
# CLICKHOUSE_HOST=localhost
|
|
92
|
+
# CLICKHOUSE_PORT=8123
|
|
93
|
+
# CLICKHOUSE_DATABASE=hkex
|
|
94
|
+
# CLICKHOUSE_USER=default
|
|
95
|
+
# CLICKHOUSE_PASSWORD=
|
|
96
|
+
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
# Neo4j (required when DATABASE_TARGET includes neo4j)
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
# Install the driver first: pip install "hkex-filing-scraper[neo4j]"
|
|
101
|
+
#
|
|
102
|
+
# NEO4J_URI=bolt://localhost:7687
|
|
103
|
+
# NEO4J_USER=neo4j
|
|
104
|
+
# NEO4J_PASSWORD=
|
|
105
|
+
# NEO4J_DATABASE=
|
|
106
|
+
|
|
107
|
+
# ---------------------------------------------------------------------------
|
|
108
|
+
# SurrealDB (required when DATABASE_TARGET includes surrealdb)
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# No extra dependency.
|
|
111
|
+
#
|
|
112
|
+
# SURREAL_ENDPOINT=http://localhost:8000
|
|
113
|
+
# SURREAL_NAMESPACE=default
|
|
114
|
+
# SURREAL_DATABASE=default
|
|
115
|
+
# SURREAL_USERNAME=root
|
|
116
|
+
# SURREAL_PASSWORD=
|
|
117
|
+
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
# Graph linking (OPTIONAL)
|
|
120
|
+
# ---------------------------------------------------------------------------
|
|
121
|
+
# Set COMPANY_TABLE to the name of your existing company table to enable
|
|
122
|
+
# graph edges (has_filing, references_filing) between companies and filings.
|
|
123
|
+
# Leave empty to disable graph linking entirely.
|
|
124
|
+
#
|
|
125
|
+
# COMPANY_TABLE=my_company
|
|
126
|
+
#
|
|
127
|
+
# Pattern for converting a ticker like "0451.HK" into a company key.
|
|
128
|
+
# Placeholders: {code} = leading-zero-stripped stock code, {exchange} = exchange suffix.
|
|
129
|
+
# Default: "{code}_{exchange}" produces "451_HK"
|
|
130
|
+
#
|
|
131
|
+
# COMPANY_ID_PATTERN={code}_{exchange}
|
|
132
|
+
|
|
133
|
+
# ---------------------------------------------------------------------------
|
|
134
|
+
# Performance tuning (OPTIONAL)
|
|
135
|
+
# ---------------------------------------------------------------------------
|
|
136
|
+
# MAX_DOWNLOAD_WORKERS=15
|
|
137
|
+
#
|
|
138
|
+
# Minimum seconds between request starts, process-wide. 0 disables pacing (default).
|
|
139
|
+
# Set a small value (e.g. 0.25) to be deliberately polite to the endpoint.
|
|
140
|
+
# REQUEST_DELAY_SECONDS=0
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Auto-detect text files and normalise line endings.
|
|
2
|
+
* text=auto eol=lf
|
|
3
|
+
|
|
4
|
+
# Windows scripts keep CRLF.
|
|
5
|
+
*.bat text eol=crlf
|
|
6
|
+
*.cmd text eol=crlf
|
|
7
|
+
|
|
8
|
+
# Binary assets.
|
|
9
|
+
*.png binary
|
|
10
|
+
*.jpg binary
|
|
11
|
+
*.gif binary
|
|
12
|
+
*.pdf binary
|
|
13
|
+
*.whl binary
|
|
14
|
+
*.gz binary
|
|
15
|
+
|
|
16
|
+
# Keep generated/vendored files out of language stats.
|
|
17
|
+
src/hkex_scraper/_version.py linguist-generated=true
|
|
18
|
+
docs/*.png linguist-documentation
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Funding options for this project.
|
|
2
|
+
# The Sponsor button appears only for platforms that are actually enrolled,
|
|
3
|
+
# so leaving a handle here is safe; remove a line if you are not enrolled.
|
|
4
|
+
github: [simonplmak-cloud]
|
|
5
|
+
# custom: ["https://simonplmak-cloud.github.io/hkex-filing-scraper/"]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a reproducible problem with the scraper
|
|
3
|
+
title: "[Bug] "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for the report. Please do not include credentials or `.env` contents.
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: what-happened
|
|
12
|
+
attributes:
|
|
13
|
+
label: What happened?
|
|
14
|
+
description: A clear description of the bug and what you expected instead.
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: reproduce
|
|
19
|
+
attributes:
|
|
20
|
+
label: Steps to reproduce
|
|
21
|
+
description: Exact commands and configuration (redact secrets).
|
|
22
|
+
placeholder: |
|
|
23
|
+
1. DATABASE_TARGET=...
|
|
24
|
+
2. hkex-scraper ...
|
|
25
|
+
3. ...
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
- type: dropdown
|
|
29
|
+
id: sink
|
|
30
|
+
attributes:
|
|
31
|
+
label: Database target
|
|
32
|
+
options:
|
|
33
|
+
- postgres
|
|
34
|
+
- mysql
|
|
35
|
+
- mariadb
|
|
36
|
+
- sqlite
|
|
37
|
+
- duckdb
|
|
38
|
+
- mongodb
|
|
39
|
+
- clickhouse
|
|
40
|
+
- neo4j
|
|
41
|
+
- surrealdb
|
|
42
|
+
- multiple / other
|
|
43
|
+
validations:
|
|
44
|
+
required: true
|
|
45
|
+
- type: input
|
|
46
|
+
id: version
|
|
47
|
+
attributes:
|
|
48
|
+
label: Version
|
|
49
|
+
description: Output of `hkex-scraper --version` or the release tag.
|
|
50
|
+
placeholder: "1.1.0"
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
- type: input
|
|
54
|
+
id: python
|
|
55
|
+
attributes:
|
|
56
|
+
label: Python version
|
|
57
|
+
placeholder: "3.11.9"
|
|
58
|
+
validations:
|
|
59
|
+
required: true
|
|
60
|
+
- type: dropdown
|
|
61
|
+
id: os
|
|
62
|
+
attributes:
|
|
63
|
+
label: Operating system
|
|
64
|
+
options:
|
|
65
|
+
- Linux
|
|
66
|
+
- macOS
|
|
67
|
+
- Windows
|
|
68
|
+
- Other
|
|
69
|
+
validations:
|
|
70
|
+
required: true
|
|
71
|
+
- type: textarea
|
|
72
|
+
id: logs
|
|
73
|
+
attributes:
|
|
74
|
+
label: Relevant log output
|
|
75
|
+
description: Paste the relevant lines from `logs/hkex_filings_*.log` (redact secrets).
|
|
76
|
+
render: shell
|
|
77
|
+
validations:
|
|
78
|
+
required: false
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Question or usage help
|
|
4
|
+
url: https://github.com/simonplmak-cloud/hkex-filing-scraper/discussions
|
|
5
|
+
about: Ask a question, share a setup, or discuss an idea in Discussions. Please do not open an issue for usage questions.
|
|
6
|
+
- name: Documentation
|
|
7
|
+
url: https://simonplmak-cloud.github.io/hkex-filing-scraper/
|
|
8
|
+
about: Getting started, configuration, CLI, sink guides, and troubleshooting.
|
|
9
|
+
- name: Security vulnerability
|
|
10
|
+
url: https://github.com/simonplmak-cloud/hkex-filing-scraper/security/policy
|
|
11
|
+
about: Report a vulnerability privately per the security policy. Never open a public issue for security.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea or improvement
|
|
3
|
+
title: "[Feature] "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: problem
|
|
8
|
+
attributes:
|
|
9
|
+
label: Problem / motivation
|
|
10
|
+
description: What problem does this solve? Who benefits?
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: proposal
|
|
15
|
+
attributes:
|
|
16
|
+
label: Proposed solution
|
|
17
|
+
description: Describe the change you would like. Include CLI/config sketches if relevant.
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
- type: textarea
|
|
21
|
+
id: alternatives
|
|
22
|
+
attributes:
|
|
23
|
+
label: Alternatives considered
|
|
24
|
+
description: Other approaches or workarounds you have tried.
|
|
25
|
+
validations:
|
|
26
|
+
required: false
|
|
27
|
+
- type: dropdown
|
|
28
|
+
id: area
|
|
29
|
+
attributes:
|
|
30
|
+
label: Area
|
|
31
|
+
options:
|
|
32
|
+
- Scraping / API
|
|
33
|
+
- Document extraction
|
|
34
|
+
- PostgreSQL sink
|
|
35
|
+
- MySQL / MariaDB sink
|
|
36
|
+
- SQLite / DuckDB sink
|
|
37
|
+
- MongoDB sink
|
|
38
|
+
- ClickHouse sink
|
|
39
|
+
- Neo4j sink
|
|
40
|
+
- SurrealDB sink
|
|
41
|
+
- Graph linking
|
|
42
|
+
- CLI / configuration
|
|
43
|
+
- Documentation
|
|
44
|
+
- Other
|
|
45
|
+
validations:
|
|
46
|
+
required: true
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Thanks for contributing. Keep the description focused on the why and the impact.
|
|
3
|
+
-->
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
<!-- One or two sentences: what changes, and why. -->
|
|
8
|
+
|
|
9
|
+
## Type of change
|
|
10
|
+
|
|
11
|
+
- [ ] `feat` — new feature
|
|
12
|
+
- [ ] `fix` — bug fix
|
|
13
|
+
- [ ] `docs` — documentation only
|
|
14
|
+
- [ ] `refactor` — no behavior change
|
|
15
|
+
- [ ] `chore` — tooling, dependencies, maintenance
|
|
16
|
+
- [ ] `test` — tests only
|
|
17
|
+
|
|
18
|
+
## Related issues
|
|
19
|
+
|
|
20
|
+
<!-- e.g. Closes #123 -->
|
|
21
|
+
|
|
22
|
+
## How this was tested
|
|
23
|
+
|
|
24
|
+
- [ ] `ruff check && ruff format --check` passes
|
|
25
|
+
- [ ] `pytest -q` passes
|
|
26
|
+
- [ ] Added or updated tests for the change
|
|
27
|
+
- [ ] Verified against a live sink (which one? — PostgreSQL / MySQL / SQLite / DuckDB / MongoDB / ClickHouse / Neo4j / SurrealDB)
|
|
28
|
+
|
|
29
|
+
## Checklist
|
|
30
|
+
|
|
31
|
+
- [ ] New or changed sink fields are mirrored across every schema (SurrealDB, PostgreSQL, dialect DDL, MongoDB/Neo4j/ClickHouse)
|
|
32
|
+
- [ ] SQL is parameterised; no values interpolated; credentials are never logged
|
|
33
|
+
- [ ] Docs, templates, and `.env.example` updated (the docs consistency test covers this)
|
|
34
|
+
- [ ] `CHANGELOG.md` updated under `Unreleased`
|
|
35
|
+
- [ ] No secrets, tokens, or real credentials committed
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: pip
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: weekly
|
|
7
|
+
open-pull-requests-limit: 5
|
|
8
|
+
groups:
|
|
9
|
+
python-minor:
|
|
10
|
+
patterns: ["*"]
|
|
11
|
+
update-types: ["minor", "patch"]
|
|
12
|
+
labels: ["dependencies"]
|
|
13
|
+
|
|
14
|
+
- package-ecosystem: uv
|
|
15
|
+
directory: "/"
|
|
16
|
+
schedule:
|
|
17
|
+
interval: weekly
|
|
18
|
+
open-pull-requests-limit: 5
|
|
19
|
+
labels: ["dependencies"]
|
|
20
|
+
|
|
21
|
+
- package-ecosystem: github-actions
|
|
22
|
+
directory: "/"
|
|
23
|
+
schedule:
|
|
24
|
+
interval: weekly
|
|
25
|
+
labels: ["dependencies", "ci"]
|
|
26
|
+
|
|
27
|
+
# Container images are pinned by digest in .github/workflows/ci.yml and
|
|
28
|
+
# examples/docker-compose.yml. Dependabot's `docker` ecosystem only understands Dockerfiles
|
|
29
|
+
# and Kubernetes YAML (not compose files), so those digests are bumped manually when an
|
|
30
|
+
# engine release is worth adopting.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: Canary
|
|
2
|
+
|
|
3
|
+
# Early-warning control for risk R1: the undocumented HKEx API changing shape.
|
|
4
|
+
# Runs the real fetch path against a small recent window once a day, and opens an issue
|
|
5
|
+
# (or comments on the existing one) when the response no longer matches what the scraper
|
|
6
|
+
# depends on. Target: detect an API break within 24 hours.
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
schedule:
|
|
10
|
+
- cron: "17 1 * * *"
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
canary:
|
|
18
|
+
name: HKEx API canary
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
issues: write # create/comment on the tracking issue
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
|
|
30
|
+
- name: Install the package
|
|
31
|
+
run: pip install --quiet .
|
|
32
|
+
|
|
33
|
+
- name: Run the canary
|
|
34
|
+
id: canary
|
|
35
|
+
run: |
|
|
36
|
+
set +e
|
|
37
|
+
set -o pipefail
|
|
38
|
+
python scripts/canary.py --days 7 --max 5 --json | tee canary.json
|
|
39
|
+
code=$?
|
|
40
|
+
echo "exit_code=$code" >> "$GITHUB_OUTPUT"
|
|
41
|
+
|
|
42
|
+
- name: Report a failure on the tracking issue
|
|
43
|
+
if: steps.canary.outputs.exit_code != '0'
|
|
44
|
+
env:
|
|
45
|
+
GH_TOKEN: ${{ github.token }}
|
|
46
|
+
run: |
|
|
47
|
+
set -euo pipefail
|
|
48
|
+
TITLE="Canary: HKEx API response shape changed"
|
|
49
|
+
BODY="$(printf 'The scheduled canary failed on %s.\n\n```json\n%s\n```\n\nSee the workflow run: %s/%s/actions/runs/%s' \
|
|
50
|
+
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(cat canary.json)" \
|
|
51
|
+
"$GITHUB_SERVER_URL" "$GITHUB_REPOSITORY" "$GITHUB_RUN_ID")"
|
|
52
|
+
EXISTING="$(gh issue list --state open --search "in:title \"$TITLE\"" --json number --jq '.[0].number // empty')"
|
|
53
|
+
if [ -n "$EXISTING" ]; then
|
|
54
|
+
gh issue comment "$EXISTING" --body "$BODY"
|
|
55
|
+
else
|
|
56
|
+
gh issue create --title "$TITLE" --body "$BODY" --label bug
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
- name: Keep the report
|
|
60
|
+
if: always()
|
|
61
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
62
|
+
with:
|
|
63
|
+
name: canary-report
|
|
64
|
+
path: canary.json
|
|
65
|
+
if-no-files-found: ignore
|
|
66
|
+
retention-days: 14
|
|
67
|
+
|
|
68
|
+
- name: Fail the run when the canary failed
|
|
69
|
+
if: steps.canary.outputs.exit_code != '0'
|
|
70
|
+
run: exit 1
|