dividendcase 0.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.
- dividendcase-0.1.0/.github/workflows/build.yml +87 -0
- dividendcase-0.1.0/.github/workflows/release.yml +151 -0
- dividendcase-0.1.0/.github/workflows/tests.yml +39 -0
- dividendcase-0.1.0/.gitignore +39 -0
- dividendcase-0.1.0/.python-version +1 -0
- dividendcase-0.1.0/CHANGELOG.md +19 -0
- dividendcase-0.1.0/LICENSE +662 -0
- dividendcase-0.1.0/PKG-INFO +172 -0
- dividendcase-0.1.0/README.md +124 -0
- dividendcase-0.1.0/pyproject.toml +93 -0
- dividendcase-0.1.0/scripts/build_web.py +44 -0
- dividendcase-0.1.0/scripts/check_dist.py +54 -0
- dividendcase-0.1.0/scripts/smoke_test.py +91 -0
- dividendcase-0.1.0/src/dividendcase/__init__.py +7 -0
- dividendcase-0.1.0/src/dividendcase/__main__.py +4 -0
- dividendcase-0.1.0/src/dividendcase/api/__init__.py +0 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/__init__.py +0 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/data.py +34 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/deps.py +10 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/dividends.py +238 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/excel_io.py +1093 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/fx.py +29 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/health.py +38 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/investment.py +261 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/portfolio.py +706 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/portfolios.py +147 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/router.py +17 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/search.py +181 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/stocks.py +292 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/user.py +108 -0
- dividendcase-0.1.0/src/dividendcase/api/v1/watchlist.py +289 -0
- dividendcase-0.1.0/src/dividendcase/cli.py +72 -0
- dividendcase-0.1.0/src/dividendcase/config.py +45 -0
- dividendcase-0.1.0/src/dividendcase/crud/__init__.py +7 -0
- dividendcase-0.1.0/src/dividendcase/crud/dividend.py +57 -0
- dividendcase-0.1.0/src/dividendcase/crud/stock.py +78 -0
- dividendcase-0.1.0/src/dividendcase/database.py +38 -0
- dividendcase-0.1.0/src/dividendcase/main.py +115 -0
- dividendcase-0.1.0/src/dividendcase/migrate.py +161 -0
- dividendcase-0.1.0/src/dividendcase/migrations/env.py +35 -0
- dividendcase-0.1.0/src/dividendcase/migrations/script.py.mako +24 -0
- dividendcase-0.1.0/src/dividendcase/migrations/versions/0001_baseline.py +180 -0
- dividendcase-0.1.0/src/dividendcase/migrations/versions/0002_check_for_updates.py +26 -0
- dividendcase-0.1.0/src/dividendcase/migrations/versions/0003_fx_rates_and_setup.py +41 -0
- dividendcase-0.1.0/src/dividendcase/models/__init__.py +21 -0
- dividendcase-0.1.0/src/dividendcase/models/dividend.py +18 -0
- dividendcase-0.1.0/src/dividendcase/models/fx_rate.py +14 -0
- dividendcase-0.1.0/src/dividendcase/models/scheduler_run.py +14 -0
- dividendcase-0.1.0/src/dividendcase/models/stock.py +29 -0
- dividendcase-0.1.0/src/dividendcase/models/user_investment.py +24 -0
- dividendcase-0.1.0/src/dividendcase/models/user_portfolio.py +12 -0
- dividendcase-0.1.0/src/dividendcase/models/user_preferences.py +22 -0
- dividendcase-0.1.0/src/dividendcase/models/user_watchlist.py +17 -0
- dividendcase-0.1.0/src/dividendcase/models/user_watchlist_group.py +12 -0
- dividendcase-0.1.0/src/dividendcase/scheduler/__init__.py +0 -0
- dividendcase-0.1.0/src/dividendcase/scheduler/tasks.py +7 -0
- dividendcase-0.1.0/src/dividendcase/schemas/__init__.py +9 -0
- dividendcase-0.1.0/src/dividendcase/schemas/dividend.py +55 -0
- dividendcase-0.1.0/src/dividendcase/schemas/investment.py +21 -0
- dividendcase-0.1.0/src/dividendcase/schemas/stock.py +47 -0
- dividendcase-0.1.0/src/dividendcase/schemas/user_investment.py +126 -0
- dividendcase-0.1.0/src/dividendcase/schemas/user_preferences.py +34 -0
- dividendcase-0.1.0/src/dividendcase/schemas/watchlist.py +42 -0
- dividendcase-0.1.0/src/dividendcase/services/__init__.py +0 -0
- dividendcase-0.1.0/src/dividendcase/services/derived.py +33 -0
- dividendcase-0.1.0/src/dividendcase/services/fx.py +204 -0
- dividendcase-0.1.0/src/dividendcase/services/refresh.py +318 -0
- dividendcase-0.1.0/src/dividendcase/services/universe.py +193 -0
- dividendcase-0.1.0/src/dividendcase/services/updates.py +115 -0
- dividendcase-0.1.0/src/dividendcase/services/yahoo_fetcher.py +856 -0
- dividendcase-0.1.0/src/dividendcase/web/.gitkeep +0 -0
- dividendcase-0.1.0/src/dividendcase/web/404/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/404.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/__next.__PAGE__.txt +23 -0
- dividendcase-0.1.0/src/dividendcase/web/__next._full.txt +21 -0
- dividendcase-0.1.0/src/dividendcase/web/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/DhRV7h_G5oje4BFbueGOW/_buildManifest.js +11 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/DhRV7h_G5oje4BFbueGOW/_clientMiddlewareManifest.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/DhRV7h_G5oje4BFbueGOW/_ssgManifest.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0c87cux8r1ss5.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0cev4x3kzarbu.js +2 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0cz1d0mv5g_q7.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0g-bslilw6tiu.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0izc_4m5nyqrd.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0lfebwmsk92ym.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0nmuijbkm3ipd.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/0ozczpntpufql.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/1-ift1mtsuqvh.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/10oy-ed_zrrd9.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/13-u82nfffhrp.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/138wmfea-yk08.js +22 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/14jt62gawmtd9.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/15m8s8ua7v57_.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/193r1px8kfm06.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/1l-w55cdq629z.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/1q2bxv0xj7vse.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/1s5tue3q2i-8b.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/1xrz4-jij46i_.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/24f36pdyspt8c.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/2aqpz6z087bo4.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/2ft48jvqut7tm.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/2i51e627rllld.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/2o72ftwupypgx.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/2vq-8ocdpjh4a.css +4 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/33-cg7-y-5zm5.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/3cju952ndgmmn.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/3il2yixgws-43.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/3mc6dra1m0098.js +31 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/431n5e16l34_0.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/453cd1tlxz5wi.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/chunks/turbopack-1che7mqzsn0nh.js +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/7ebf22b5a21034f8-s.p.3j3877k49yy0l.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/fc0a7394b875fa43-s.2ytmazkdrg7t9.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
- dividendcase-0.1.0/src/dividendcase/web/_next/static/media/icon.0kxjuvpgwz_c6.svg +85 -0
- dividendcase-0.1.0/src/dividendcase/web/_not-found/__next._full.txt +16 -0
- dividendcase-0.1.0/src/dividendcase/web/_not-found/__next._not-found.__PAGE__.txt +22 -0
- dividendcase-0.1.0/src/dividendcase/web/_not-found/__next._tree.txt +2 -0
- dividendcase-0.1.0/src/dividendcase/web/_not-found/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/_not-found/index.txt +16 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/__next._full.txt +24 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/__next.dashboard.__PAGE__.txt +27 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/about/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/about/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/about/__next.dashboard.about.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/about/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/about/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/calendar/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/calendar/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/calendar/__next.dashboard.calendar.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/calendar/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/calendar/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/compare/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/compare/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/compare/__next.dashboard.compare.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/compare/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/compare/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/data/__next._full.txt +23 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/data/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/data/__next.dashboard.data.__PAGE__.txt +27 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/data/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/data/index.txt +23 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/drip/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/drip/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/drip/__next.dashboard.drip.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/drip/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/drip/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/index.txt +24 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/__next.dashboard.investments.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/portfolio/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/portfolio/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/portfolio/__next.dashboard.investments.portfolio.__PAGE__.txt +31 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/portfolio/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/investments/portfolio/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/screener/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/screener/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/screener/__next.dashboard.screener.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/screener/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/screener/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/settings/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/settings/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/settings/__next.dashboard.settings.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/settings/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/settings/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/stock/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/stock/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/stock/__next.dashboard.stock.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/stock/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/stock/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/watchlist/__next._full.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/watchlist/__next._tree.txt +5 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/watchlist/__next.dashboard.watchlist.__PAGE__.txt +30 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/watchlist/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/dashboard/watchlist/index.txt +26 -0
- dividendcase-0.1.0/src/dividendcase/web/icon.svg +85 -0
- dividendcase-0.1.0/src/dividendcase/web/index.html +1 -0
- dividendcase-0.1.0/src/dividendcase/web/index.txt +21 -0
- dividendcase-0.1.0/src/dividendcase/web/logo-full.svg +105 -0
- dividendcase-0.1.0/src/dividendcase/web/logo-icon.svg +85 -0
- dividendcase-0.1.0/src/dividendcase/web/tickers.json +1 -0
- dividendcase-0.1.0/tests/conftest.py +198 -0
- dividendcase-0.1.0/tests/test_api.py +229 -0
- dividendcase-0.1.0/tests/test_derived_and_updates.py +39 -0
- dividendcase-0.1.0/tests/test_fx_and_setup.py +189 -0
- dividendcase-0.1.0/tests/test_migrations.py +83 -0
- dividendcase-0.1.0/uv.lock +1954 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: build-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
interface:
|
|
18
|
+
name: Interface and website
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 15
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v5
|
|
23
|
+
- uses: actions/setup-node@v5
|
|
24
|
+
with:
|
|
25
|
+
node-version: 22
|
|
26
|
+
cache: npm
|
|
27
|
+
- name: Install
|
|
28
|
+
run: npm ci --no-audit --no-fund
|
|
29
|
+
- name: Type-check
|
|
30
|
+
run: |
|
|
31
|
+
npx tsc --noEmit -p frontend
|
|
32
|
+
npx tsc --noEmit -p site
|
|
33
|
+
- name: Build the website
|
|
34
|
+
run: npm run build -w site
|
|
35
|
+
|
|
36
|
+
package:
|
|
37
|
+
name: Package
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
timeout-minutes: 15
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v5
|
|
42
|
+
- uses: actions/setup-node@v5
|
|
43
|
+
with:
|
|
44
|
+
node-version: 22
|
|
45
|
+
cache: npm
|
|
46
|
+
- uses: astral-sh/setup-uv@v6
|
|
47
|
+
with:
|
|
48
|
+
enable-cache: true
|
|
49
|
+
- name: Build the interface into the package
|
|
50
|
+
run: uv run python scripts/build_web.py
|
|
51
|
+
- name: Serve the built pages
|
|
52
|
+
run: uv run pytest tests/test_api.py -k interface
|
|
53
|
+
- name: Build the wheel and sdist
|
|
54
|
+
run: uv build
|
|
55
|
+
- name: Check them
|
|
56
|
+
run: uv run python scripts/check_dist.py
|
|
57
|
+
- uses: actions/upload-artifact@v4
|
|
58
|
+
with:
|
|
59
|
+
name: dist
|
|
60
|
+
path: dist/
|
|
61
|
+
retention-days: 7
|
|
62
|
+
|
|
63
|
+
install:
|
|
64
|
+
name: Install and run (${{ matrix.os }})
|
|
65
|
+
needs: package
|
|
66
|
+
strategy:
|
|
67
|
+
fail-fast: false
|
|
68
|
+
matrix:
|
|
69
|
+
os: ${{ github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "macos-latest", "windows-latest"]') }}
|
|
70
|
+
runs-on: ${{ matrix.os }}
|
|
71
|
+
timeout-minutes: 15
|
|
72
|
+
defaults:
|
|
73
|
+
run:
|
|
74
|
+
shell: bash
|
|
75
|
+
steps:
|
|
76
|
+
- uses: actions/checkout@v5
|
|
77
|
+
- uses: actions/download-artifact@v5
|
|
78
|
+
with:
|
|
79
|
+
name: dist
|
|
80
|
+
path: dist/
|
|
81
|
+
- uses: astral-sh/setup-uv@v6
|
|
82
|
+
- name: uv tool install, as the README says
|
|
83
|
+
run: |
|
|
84
|
+
uv tool install "$(ls dist/*.whl)"
|
|
85
|
+
echo "$(uv tool dir --bin)" >> "$GITHUB_PATH"
|
|
86
|
+
- name: Start it and check it works
|
|
87
|
+
run: uv run --no-project python scripts/smoke_test.py
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# A release is a tag: bump `version` in pyproject.toml, add a CHANGELOG.md section with the
|
|
4
|
+
# same number, merge, then push the tag `v<version>`. PyPI trusts this workflow directly
|
|
5
|
+
# (trusted publishing), so there are no tokens or passwords in the repository.
|
|
6
|
+
#
|
|
7
|
+
# Run it by hand ("Run workflow") for a dry run on TestPyPI instead.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
tags: ["v*"]
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
inputs:
|
|
14
|
+
testpypi:
|
|
15
|
+
description: Publish to TestPyPI (a dry run; real releases come from a v* tag)
|
|
16
|
+
type: boolean
|
|
17
|
+
default: true
|
|
18
|
+
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
22
|
+
concurrency:
|
|
23
|
+
group: release-${{ github.ref }}
|
|
24
|
+
cancel-in-progress: false
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
build:
|
|
28
|
+
name: Build and test
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
timeout-minutes: 20
|
|
31
|
+
outputs:
|
|
32
|
+
version: ${{ steps.version.outputs.version }}
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v5
|
|
35
|
+
- uses: actions/setup-node@v5
|
|
36
|
+
with:
|
|
37
|
+
node-version: 22
|
|
38
|
+
cache: npm
|
|
39
|
+
- uses: astral-sh/setup-uv@v6
|
|
40
|
+
with:
|
|
41
|
+
enable-cache: true
|
|
42
|
+
- name: Version matches the tag
|
|
43
|
+
id: version
|
|
44
|
+
run: |
|
|
45
|
+
version=$(uv run --no-project python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
46
|
+
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
47
|
+
if [ "$GITHUB_REF_TYPE" = "tag" ] && [ "$GITHUB_REF_NAME" != "v$version" ]; then
|
|
48
|
+
echo "::error::The tag $GITHUB_REF_NAME doesn't match the version in pyproject.toml ($version)"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
if ! grep -q "^## $version\$" CHANGELOG.md; then
|
|
52
|
+
echo "::error::CHANGELOG.md has no '## $version' section"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
- name: Tests
|
|
56
|
+
run: |
|
|
57
|
+
uv sync --locked
|
|
58
|
+
uv run pytest
|
|
59
|
+
uv run python -m dividendcase.migrate check
|
|
60
|
+
- name: Build the interface into the package
|
|
61
|
+
run: uv run python scripts/build_web.py
|
|
62
|
+
- name: Build the wheel and sdist
|
|
63
|
+
run: uv build
|
|
64
|
+
- name: Check them
|
|
65
|
+
run: uv run python scripts/check_dist.py "${{ steps.version.outputs.version }}"
|
|
66
|
+
- uses: actions/upload-artifact@v4
|
|
67
|
+
with:
|
|
68
|
+
name: dist
|
|
69
|
+
path: dist/
|
|
70
|
+
retention-days: 30
|
|
71
|
+
|
|
72
|
+
install:
|
|
73
|
+
name: Install and run (${{ matrix.os }})
|
|
74
|
+
needs: build
|
|
75
|
+
strategy:
|
|
76
|
+
fail-fast: false
|
|
77
|
+
matrix:
|
|
78
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
79
|
+
runs-on: ${{ matrix.os }}
|
|
80
|
+
timeout-minutes: 15
|
|
81
|
+
defaults:
|
|
82
|
+
run:
|
|
83
|
+
shell: bash
|
|
84
|
+
steps:
|
|
85
|
+
- uses: actions/checkout@v5
|
|
86
|
+
- uses: actions/download-artifact@v5
|
|
87
|
+
with:
|
|
88
|
+
name: dist
|
|
89
|
+
path: dist/
|
|
90
|
+
- uses: astral-sh/setup-uv@v6
|
|
91
|
+
- name: uv tool install, as the README says
|
|
92
|
+
run: |
|
|
93
|
+
uv tool install "$(ls dist/*.whl)"
|
|
94
|
+
echo "$(uv tool dir --bin)" >> "$GITHUB_PATH"
|
|
95
|
+
- name: Start it and check it works
|
|
96
|
+
run: uv run --no-project python scripts/smoke_test.py
|
|
97
|
+
|
|
98
|
+
testpypi:
|
|
99
|
+
name: Publish to TestPyPI
|
|
100
|
+
if: github.event_name == 'workflow_dispatch' && inputs.testpypi
|
|
101
|
+
needs: [build, install]
|
|
102
|
+
runs-on: ubuntu-latest
|
|
103
|
+
permissions:
|
|
104
|
+
id-token: write # trusted publishing
|
|
105
|
+
steps:
|
|
106
|
+
- uses: actions/download-artifact@v5
|
|
107
|
+
with:
|
|
108
|
+
name: dist
|
|
109
|
+
path: dist/
|
|
110
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
111
|
+
with:
|
|
112
|
+
repository-url: https://test.pypi.org/legacy/
|
|
113
|
+
skip-existing: true
|
|
114
|
+
|
|
115
|
+
pypi:
|
|
116
|
+
name: Publish to PyPI
|
|
117
|
+
if: github.ref_type == 'tag'
|
|
118
|
+
needs: [build, install]
|
|
119
|
+
runs-on: ubuntu-latest
|
|
120
|
+
permissions:
|
|
121
|
+
id-token: write # trusted publishing
|
|
122
|
+
steps:
|
|
123
|
+
- uses: actions/download-artifact@v5
|
|
124
|
+
with:
|
|
125
|
+
name: dist
|
|
126
|
+
path: dist/
|
|
127
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
128
|
+
|
|
129
|
+
github-release:
|
|
130
|
+
name: GitHub release
|
|
131
|
+
if: github.ref_type == 'tag'
|
|
132
|
+
needs: [build, pypi]
|
|
133
|
+
runs-on: ubuntu-latest
|
|
134
|
+
permissions:
|
|
135
|
+
contents: write
|
|
136
|
+
steps:
|
|
137
|
+
- uses: actions/checkout@v5
|
|
138
|
+
- uses: actions/download-artifact@v5
|
|
139
|
+
with:
|
|
140
|
+
name: dist
|
|
141
|
+
path: dist/
|
|
142
|
+
- name: Create the release with the changelog's notes
|
|
143
|
+
env:
|
|
144
|
+
GH_TOKEN: ${{ github.token }}
|
|
145
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
146
|
+
run: |
|
|
147
|
+
awk -v heading="## $VERSION" '$0 == heading {found = 1; next} /^## / {found = 0} found' CHANGELOG.md > notes.md
|
|
148
|
+
printf '\n**Install:** `uv tool install dividendcase` · **Update:** `uv tool upgrade dividendcase`\n' >> notes.md
|
|
149
|
+
prerelease=""
|
|
150
|
+
if echo "$VERSION" | grep -q '[a-z]'; then prerelease="--prerelease"; fi
|
|
151
|
+
gh release create "$GITHUB_REF_NAME" dist/* --title "DividendCase $VERSION" --notes-file notes.md $prerelease
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: tests-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
tests:
|
|
18
|
+
name: Python ${{ matrix.python }} (${{ matrix.os }})
|
|
19
|
+
# Pull requests: Linux only. main: every supported Python on Linux, plus macOS and Windows,
|
|
20
|
+
# where people install the app
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
include: ${{ fromJSON(github.event_name == 'pull_request' && '[{"os":"ubuntu-latest","python":"3.12"}]' || '[{"os":"ubuntu-latest","python":"3.11"},{"os":"ubuntu-latest","python":"3.12"},{"os":"ubuntu-latest","python":"3.13"},{"os":"macos-latest","python":"3.12"},{"os":"windows-latest","python":"3.12"}]') }}
|
|
25
|
+
runs-on: ${{ matrix.os }}
|
|
26
|
+
timeout-minutes: 15
|
|
27
|
+
env:
|
|
28
|
+
UV_PYTHON: ${{ matrix.python }}
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v5
|
|
31
|
+
- uses: astral-sh/setup-uv@v6
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
- name: Install
|
|
35
|
+
run: uv sync --locked
|
|
36
|
+
- name: Tests (real SQLite, no network)
|
|
37
|
+
run: uv run pytest
|
|
38
|
+
- name: Models and migrations agree
|
|
39
|
+
run: uv run python -m dividendcase.migrate check
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.venv/
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
|
|
9
|
+
# Interface, website and shared packages (npm workspaces)
|
|
10
|
+
node_modules/
|
|
11
|
+
.next/
|
|
12
|
+
out/
|
|
13
|
+
*.tsbuildinfo
|
|
14
|
+
next-env.d.ts
|
|
15
|
+
|
|
16
|
+
# The built interface is copied into the package at release time
|
|
17
|
+
src/dividendcase/web/*
|
|
18
|
+
!src/dividendcase/web/.gitkeep
|
|
19
|
+
|
|
20
|
+
# Local data and secrets: never commit these
|
|
21
|
+
*.db
|
|
22
|
+
*.db-shm
|
|
23
|
+
*.db-wal
|
|
24
|
+
.env
|
|
25
|
+
.env.*
|
|
26
|
+
!.env.example
|
|
27
|
+
# Only points `npm run dev` at the local API; no secrets
|
|
28
|
+
!frontend/.env.development
|
|
29
|
+
|
|
30
|
+
# OS / editors
|
|
31
|
+
.DS_Store
|
|
32
|
+
.idea/
|
|
33
|
+
.vscode/
|
|
34
|
+
|
|
35
|
+
# Personal Claude Code settings
|
|
36
|
+
.claude/
|
|
37
|
+
|
|
38
|
+
# Throwaway data folder for testing (DIVIDENDCASE_DATA_DIR)
|
|
39
|
+
.test-data/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to DividendCase. Versions follow [semantic versioning](https://semver.org/);
|
|
4
|
+
while the version starts with 0, a minor release (0.2, 0.3…) may change things.
|
|
5
|
+
|
|
6
|
+
## 0.1.0
|
|
7
|
+
|
|
8
|
+
The first release of DividendCase as an app that runs on your own computer.
|
|
9
|
+
|
|
10
|
+
- **Income home:** what your holdings should pay over the next 12 months, month by month, with upcoming payments, where the income comes from and a few plain-English notes.
|
|
11
|
+
- **One currency:** totals across USD, GBP, EUR, INR, CAD, AUD and more are converted into your home currency with the European Central Bank's daily reference rates. Past amounts use the rate on their date, future income the latest rate.
|
|
12
|
+
- **First-run setup:** tax residence, home currency and which markets the screener downloads.
|
|
13
|
+
- **Stock pages:** 10 years of dividend history, TTM and forward yield, a safety score, dividend growth and growth streaks.
|
|
14
|
+
- **Screener:** index members of the S&P 500, NIFTY 50, TSX 60, FTSE 100, ISEQ 20 and ASX 200, plus high-yield groups, filtered by market, yield and how often they pay.
|
|
15
|
+
- **Portfolios:** up to four, with individual purchase lots in any currency, performance against a benchmark and diversification charts.
|
|
16
|
+
- **Income calendar, watchlists, side-by-side comparison and a DRIP calculator.**
|
|
17
|
+
- **Excel import and export** of portfolios, holdings and watchlists, and an Excel report.
|
|
18
|
+
- **⌘K search** for any stock, page or action.
|
|
19
|
+
- **Your data stays on your computer:** one SQLite file, market data fetched by your computer from Yahoo Finance for your own use, a copy saved before every upgrade, and a daily check for new versions that you can turn off.
|