├── .gitignore ├── MANIFEST.in ├── Makefile ├── Pipfile ├── Pipfile.lock ├── README.md ├── pyproject.toml ├── setup.cfg ├── setup.py └── src └── kaku ├── __init__.py ├── cli.py └── tools.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | *.cfg 4 | *.log 5 | *.py[cod] 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Packages 11 | *.egg 12 | *.egg-info 13 | dist 14 | build 15 | eggs 16 | parts 17 | bin 18 | var 19 | sdist 20 | develop-eggs 21 | .installed.cfg 22 | lib 23 | lib64 24 | __pycache__ 25 | .cache 26 | 27 | # Installer logs 28 | pip-log.txt 29 | 30 | # Unit test / coverage reports 31 | .coverage 32 | .codecov-token 33 | .tox 34 | nosetests.xml 35 | htmlcov 36 | coverage.xml 37 | 38 | # Translations 39 | *.mo 40 | 41 | # Mr Developer 42 | .mr.developer.cfg 43 | .project 44 | .pydevproject 45 | 46 | violations.flake8.txt 47 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.md 2 | include *.txt 3 | include Makefile 4 | include Pipfile 5 | exclude Pipfile.lock 6 | exclude violations.flake8.txt 7 | prune .DS_Store 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | help: 2 | @echo " env install all dependencies" 3 | @echo " dev install all development dependencies" 4 | @echo " clean remove unwanted stuff" 5 | @echo " lint lint with flake8" 6 | @echo " test run tests" 7 | @echo " coverage run codecov" 8 | 9 | info: 10 | pipenv --version 11 | pipenv run python --version 12 | 13 | env: 14 | pipenv install --python 3.9 15 | 16 | dev: 17 | pipenv install --dev 18 | 19 | clean: 20 | rm -rf build 21 | rm -rf dist 22 | rm -f violations.flake8.txt 23 | find . -name '*.pyc' -exec rm -f {} \; 24 | find . -name '*.pyo' -exec rm -f {} \; 25 | find . -name '*~' -exec rm -f {} \; 26 | 27 | lint: clean 28 | pipenv run black src tests 29 | pipenv run flake8 src tests --tee --output-file=violations.flake8.txt 30 | 31 | test: lint 32 | pipenv install --dev "-e ." 33 | pipenv run pytest 34 | 35 | coverage: test 36 | pipenv run coverage run -m pytest 37 | pipenv run coverage report 38 | pipenv run coverage html 39 | pipenv run codecov 40 | 41 | check: lint 42 | pipenv run check-manifest -v 43 | 44 | dist: check 45 | pipenv run python -m build 46 | 47 | upload: dist 48 | pipenv run python -m twine upload --repository testpypi dist/* 49 | 50 | upload-prod: dist 51 | pipenv run python -m twine upload dist/* 52 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | pytest = "*" 8 | pytest-runner = "*" 9 | mccabe = "*" 10 | flake8 = "*" 11 | black = "*" 12 | coverage = "*" 13 | coveralls = "*" 14 | codecov = "*" 15 | check-manifest = "*" 16 | wheel = "*" 17 | build = "*" 18 | twine = "*" 19 | bleach = "*" 20 | kaku = {editable = true, path = "."} 21 | 22 | [packages] 23 | click = "*" 24 | python-dotenv = "*" 25 | toml = "*" 26 | pytz = "*" 27 | 28 | [requires] 29 | python_version = "3.9" 30 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "29abd04a7ac30701c55825dd0d1f9693ae27fd5751567390305f29ad5aac519d" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.9" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "click": { 20 | "hashes": [ 21 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", 22 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" 23 | ], 24 | "index": "pypi", 25 | "version": "==8.1.3" 26 | }, 27 | "python-dotenv": { 28 | "hashes": [ 29 | "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f", 30 | "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938" 31 | ], 32 | "index": "pypi", 33 | "version": "==0.20.0" 34 | }, 35 | "pytz": { 36 | "hashes": [ 37 | "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", 38 | "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c" 39 | ], 40 | "index": "pypi", 41 | "version": "==2022.1" 42 | }, 43 | "toml": { 44 | "hashes": [ 45 | "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", 46 | "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" 47 | ], 48 | "index": "pypi", 49 | "version": "==0.10.2" 50 | } 51 | }, 52 | "develop": { 53 | "attrs": { 54 | "hashes": [ 55 | "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", 56 | "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" 57 | ], 58 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 59 | "version": "==21.4.0" 60 | }, 61 | "black": { 62 | "hashes": [ 63 | "sha256:074458dc2f6e0d3dab7928d4417bb6957bb834434516f21514138437accdbe90", 64 | "sha256:187d96c5e713f441a5829e77120c269b6514418f4513a390b0499b0987f2ff1c", 65 | "sha256:2ea29072e954a4d55a2ff58971b83365eba5d3d357352a07a7a4df0d95f51c78", 66 | "sha256:4af5bc0e1f96be5ae9bd7aaec219c901a94d6caa2484c21983d043371c733fc4", 67 | "sha256:560558527e52ce8afba936fcce93a7411ab40c7d5fe8c2463e279e843c0328ee", 68 | "sha256:568ac3c465b1c8b34b61cd7a4e349e93f91abf0f9371eda1cf87194663ab684e", 69 | "sha256:6797f58943fceb1c461fb572edbe828d811e719c24e03375fd25170ada53825e", 70 | "sha256:6c1734ab264b8f7929cef8ae5f900b85d579e6cbfde09d7387da8f04771b51c6", 71 | "sha256:6c6d39e28aed379aec40da1c65434c77d75e65bb59a1e1c283de545fb4e7c6c9", 72 | "sha256:7ba9be198ecca5031cd78745780d65a3f75a34b2ff9be5837045dce55db83d1c", 73 | "sha256:94783f636bca89f11eb5d50437e8e17fbc6a929a628d82304c80fa9cd945f256", 74 | "sha256:a218d7e5856f91d20f04e931b6f16d15356db1c846ee55f01bac297a705ca24f", 75 | "sha256:a3db5b6409b96d9bd543323b23ef32a1a2b06416d525d27e0f67e74f1446c8f2", 76 | "sha256:ac609cf8ef5e7115ddd07d85d988d074ed00e10fbc3445aee393e70164a2219c", 77 | "sha256:b154e6bbde1e79ea3260c4b40c0b7b3109ffcdf7bc4ebf8859169a6af72cd70b", 78 | "sha256:b270a168d69edb8b7ed32c193ef10fd27844e5c60852039599f9184460ce0807", 79 | "sha256:b9fd45787ba8aa3f5e0a0a98920c1012c884622c6c920dbe98dbd05bc7c70fbf", 80 | "sha256:c85928b9d5f83b23cee7d0efcb310172412fbf7cb9d9ce963bd67fd141781def", 81 | "sha256:c9a3ac16efe9ec7d7381ddebcc022119794872abce99475345c5a61aa18c45ad", 82 | "sha256:cfaf3895a9634e882bf9d2363fed5af8888802d670f58b279b0bece00e9a872d", 83 | "sha256:e439798f819d49ba1c0bd9664427a05aab79bfba777a6db94fd4e56fae0cb849", 84 | "sha256:f586c26118bc6e714ec58c09df0157fe2d9ee195c764f630eb0d8e7ccce72e69", 85 | "sha256:f6fe02afde060bbeef044af7996f335fbe90b039ccf3f5eb8f16df8b20f77666" 86 | ], 87 | "index": "pypi", 88 | "version": "==22.6.0" 89 | }, 90 | "bleach": { 91 | "hashes": [ 92 | "sha256:085f7f33c15bd408dd9b17a4ad77c577db66d76203e5984b1bd59baeee948b2a", 93 | "sha256:0d03255c47eb9bd2f26aa9bb7f2107732e7e8fe195ca2f64709fcf3b0a4a085c" 94 | ], 95 | "index": "pypi", 96 | "version": "==5.0.1" 97 | }, 98 | "build": { 99 | "hashes": [ 100 | "sha256:19b0ed489f92ace6947698c3ca8436cb0556a66e2aa2d34cd70e2a5d27cd0437", 101 | "sha256:887a6d471c901b1a6e6574ebaeeebb45e5269a79d095fe9a8f88d6614ed2e5f0" 102 | ], 103 | "index": "pypi", 104 | "version": "==0.8.0" 105 | }, 106 | "certifi": { 107 | "hashes": [ 108 | "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", 109 | "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" 110 | ], 111 | "markers": "python_full_version >= '3.6.0'", 112 | "version": "==2022.6.15" 113 | }, 114 | "charset-normalizer": { 115 | "hashes": [ 116 | "sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5", 117 | "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413" 118 | ], 119 | "markers": "python_full_version >= '3.6.0'", 120 | "version": "==2.1.0" 121 | }, 122 | "check-manifest": { 123 | "hashes": [ 124 | "sha256:3b575f1dade7beb3078ef4bf33a94519834457c7281dbc726b15c5466b55c657", 125 | "sha256:b1923685f98c1c2468601a1a7bed655db549a25d43c583caded3860ad8308f8c" 126 | ], 127 | "index": "pypi", 128 | "version": "==0.48" 129 | }, 130 | "click": { 131 | "hashes": [ 132 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", 133 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" 134 | ], 135 | "index": "pypi", 136 | "version": "==8.1.3" 137 | }, 138 | "codecov": { 139 | "hashes": [ 140 | "sha256:585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47", 141 | "sha256:782a8e5352f22593cbc5427a35320b99490eb24d9dcfa2155fd99d2b75cfb635", 142 | "sha256:a0da46bb5025426da895af90938def8ee12d37fcbcbbbc15b6dc64cf7ebc51c1" 143 | ], 144 | "index": "pypi", 145 | "version": "==2.1.12" 146 | }, 147 | "commonmark": { 148 | "hashes": [ 149 | "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60", 150 | "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9" 151 | ], 152 | "version": "==0.9.1" 153 | }, 154 | "coverage": { 155 | "hashes": [ 156 | "sha256:01c5615d13f3dd3aa8543afc069e5319cfa0c7d712f6e04b920431e5c564a749", 157 | "sha256:106c16dfe494de3193ec55cac9640dd039b66e196e4641fa8ac396181578b982", 158 | "sha256:129cd05ba6f0d08a766d942a9ed4b29283aff7b2cccf5b7ce279d50796860bb3", 159 | "sha256:145f296d00441ca703a659e8f3eb48ae39fb083baba2d7ce4482fb2723e050d9", 160 | "sha256:1480ff858b4113db2718848d7b2d1b75bc79895a9c22e76a221b9d8d62496428", 161 | "sha256:269eaa2c20a13a5bf17558d4dc91a8d078c4fa1872f25303dddcbba3a813085e", 162 | "sha256:26dff09fb0d82693ba9e6231248641d60ba606150d02ed45110f9ec26404ed1c", 163 | "sha256:2bd9a6fc18aab8d2e18f89b7ff91c0f34ff4d5e0ba0b33e989b3cd4194c81fd9", 164 | "sha256:309ce4a522ed5fca432af4ebe0f32b21d6d7ccbb0f5fcc99290e71feba67c264", 165 | "sha256:3384f2a3652cef289e38100f2d037956194a837221edd520a7ee5b42d00cc605", 166 | "sha256:342d4aefd1c3e7f620a13f4fe563154d808b69cccef415415aece4c786665397", 167 | "sha256:39ee53946bf009788108b4dd2894bf1349b4e0ca18c2016ffa7d26ce46b8f10d", 168 | "sha256:4321f075095a096e70aff1d002030ee612b65a205a0a0f5b815280d5dc58100c", 169 | "sha256:4803e7ccf93230accb928f3a68f00ffa80a88213af98ed338a57ad021ef06815", 170 | "sha256:4ce1b258493cbf8aec43e9b50d89982346b98e9ffdfaae8ae5793bc112fb0068", 171 | "sha256:664a47ce62fe4bef9e2d2c430306e1428ecea207ffd68649e3b942fa8ea83b0b", 172 | "sha256:75ab269400706fab15981fd4bd5080c56bd5cc07c3bccb86aab5e1d5a88dc8f4", 173 | "sha256:83c4e737f60c6936460c5be330d296dd5b48b3963f48634c53b3f7deb0f34ec4", 174 | "sha256:84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3", 175 | "sha256:84e65ef149028516c6d64461b95a8dbcfce95cfd5b9eb634320596173332ea84", 176 | "sha256:865d69ae811a392f4d06bde506d531f6a28a00af36f5c8649684a9e5e4a85c83", 177 | "sha256:87f4f3df85aa39da00fd3ec4b5abeb7407e82b68c7c5ad181308b0e2526da5d4", 178 | "sha256:8c08da0bd238f2970230c2a0d28ff0e99961598cb2e810245d7fc5afcf1254e8", 179 | "sha256:961e2fb0680b4f5ad63234e0bf55dfb90d302740ae9c7ed0120677a94a1590cb", 180 | "sha256:9b3e07152b4563722be523e8cd0b209e0d1a373022cfbde395ebb6575bf6790d", 181 | "sha256:a7f3049243783df2e6cc6deafc49ea123522b59f464831476d3d1448e30d72df", 182 | "sha256:bf5601c33213d3cb19d17a796f8a14a9eaa5e87629a53979a5981e3e3ae166f6", 183 | "sha256:cec3a0f75c8f1031825e19cd86ee787e87cf03e4fd2865c79c057092e69e3a3b", 184 | "sha256:d42c549a8f41dc103a8004b9f0c433e2086add8a719da00e246e17cbe4056f72", 185 | "sha256:d67d44996140af8b84284e5e7d398e589574b376fb4de8ccd28d82ad8e3bea13", 186 | "sha256:d9c80df769f5ec05ad21ea34be7458d1dc51ff1fb4b2219e77fe24edf462d6df", 187 | "sha256:e57816f8ffe46b1df8f12e1b348f06d164fd5219beba7d9433ba79608ef011cc", 188 | "sha256:ee2ddcac99b2d2aec413e36d7a429ae9ebcadf912946b13ffa88e7d4c9b712d6", 189 | "sha256:f02cbbf8119db68455b9d763f2f8737bb7db7e43720afa07d8eb1604e5c5ae28", 190 | "sha256:f1d5aa2703e1dab4ae6cf416eb0095304f49d004c39e9db1d86f57924f43006b", 191 | "sha256:f5b66caa62922531059bc5ac04f836860412f7f88d38a476eda0a6f11d4724f4", 192 | "sha256:f69718750eaae75efe506406c490d6fc5a6161d047206cc63ce25527e8a3adad", 193 | "sha256:fb73e0011b8793c053bfa85e53129ba5f0250fdc0392c1591fd35d915ec75c46", 194 | "sha256:fd180ed867e289964404051a958f7cccabdeed423f91a899829264bb7974d3d3", 195 | "sha256:fdb6f7bd51c2d1714cea40718f6149ad9be6a2ee7d93b19e9f00934c0f2a74d9", 196 | "sha256:ffa9297c3a453fba4717d06df579af42ab9a28022444cae7fa605af4df612d54" 197 | ], 198 | "index": "pypi", 199 | "version": "==6.4.1" 200 | }, 201 | "coveralls": { 202 | "hashes": [ 203 | "sha256:b32a8bb5d2df585207c119d6c01567b81fba690c9c10a753bfe27a335bfc43ea", 204 | "sha256:f42015f31d386b351d4226389b387ae173207058832fbf5c8ec4b40e27b16026" 205 | ], 206 | "index": "pypi", 207 | "version": "==3.3.1" 208 | }, 209 | "docopt": { 210 | "hashes": [ 211 | "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491" 212 | ], 213 | "version": "==0.6.2" 214 | }, 215 | "docutils": { 216 | "hashes": [ 217 | "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c", 218 | "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06" 219 | ], 220 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 221 | "version": "==0.18.1" 222 | }, 223 | "flake8": { 224 | "hashes": [ 225 | "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d", 226 | "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d" 227 | ], 228 | "index": "pypi", 229 | "version": "==4.0.1" 230 | }, 231 | "hakkan": { 232 | "editable": true, 233 | "path": "." 234 | }, 235 | "idna": { 236 | "hashes": [ 237 | "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", 238 | "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" 239 | ], 240 | "markers": "python_version >= '3.5'", 241 | "version": "==3.3" 242 | }, 243 | "importlib-metadata": { 244 | "hashes": [ 245 | "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670", 246 | "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23" 247 | ], 248 | "markers": "python_version >= '3.7'", 249 | "version": "==4.12.0" 250 | }, 251 | "iniconfig": { 252 | "hashes": [ 253 | "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", 254 | "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" 255 | ], 256 | "version": "==1.1.1" 257 | }, 258 | "kaku": { 259 | "editable": true, 260 | "path": "." 261 | }, 262 | "keyring": { 263 | "hashes": [ 264 | "sha256:372ff2fc43ab779e3f87911c26e6c7acc8bb440cbd82683e383ca37594cb0617", 265 | "sha256:3ac00c26e4c93739e19103091a9986a9f79665a78cf15a4df1dba7ea9ac8da2f" 266 | ], 267 | "markers": "python_version >= '3.7'", 268 | "version": "==23.6.0" 269 | }, 270 | "mccabe": { 271 | "hashes": [ 272 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", 273 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" 274 | ], 275 | "index": "pypi", 276 | "version": "==0.6.1" 277 | }, 278 | "mypy-extensions": { 279 | "hashes": [ 280 | "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", 281 | "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" 282 | ], 283 | "version": "==0.4.3" 284 | }, 285 | "packaging": { 286 | "hashes": [ 287 | "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", 288 | "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" 289 | ], 290 | "markers": "python_full_version >= '3.6.0'", 291 | "version": "==21.3" 292 | }, 293 | "pathspec": { 294 | "hashes": [ 295 | "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", 296 | "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" 297 | ], 298 | "version": "==0.9.0" 299 | }, 300 | "pep517": { 301 | "hashes": [ 302 | "sha256:931378d93d11b298cf511dd634cf5ea4cb249a28ef84160b3247ee9afb4e8ab0", 303 | "sha256:dd884c326898e2c6e11f9e0b64940606a93eb10ea022a2e067959f3a110cf161" 304 | ], 305 | "version": "==0.12.0" 306 | }, 307 | "pkginfo": { 308 | "hashes": [ 309 | "sha256:848865108ec99d4901b2f7e84058b6e7660aae8ae10164e015a6dcf5b242a594", 310 | "sha256:a84da4318dd86f870a9447a8c98340aa06216bfc6f2b7bdc4b8766984ae1867c" 311 | ], 312 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", 313 | "version": "==1.8.3" 314 | }, 315 | "platformdirs": { 316 | "hashes": [ 317 | "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", 318 | "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" 319 | ], 320 | "markers": "python_version >= '3.7'", 321 | "version": "==2.5.2" 322 | }, 323 | "pluggy": { 324 | "hashes": [ 325 | "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", 326 | "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" 327 | ], 328 | "markers": "python_full_version >= '3.6.0'", 329 | "version": "==1.0.0" 330 | }, 331 | "py": { 332 | "hashes": [ 333 | "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", 334 | "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" 335 | ], 336 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 337 | "version": "==1.11.0" 338 | }, 339 | "pycodestyle": { 340 | "hashes": [ 341 | "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", 342 | "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" 343 | ], 344 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", 345 | "version": "==2.8.0" 346 | }, 347 | "pyflakes": { 348 | "hashes": [ 349 | "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c", 350 | "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e" 351 | ], 352 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 353 | "version": "==2.4.0" 354 | }, 355 | "pygments": { 356 | "hashes": [ 357 | "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", 358 | "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" 359 | ], 360 | "markers": "python_full_version >= '3.6.0'", 361 | "version": "==2.12.0" 362 | }, 363 | "pyparsing": { 364 | "hashes": [ 365 | "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", 366 | "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" 367 | ], 368 | "markers": "python_full_version >= '3.6.8'", 369 | "version": "==3.0.9" 370 | }, 371 | "pytest": { 372 | "hashes": [ 373 | "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c", 374 | "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45" 375 | ], 376 | "index": "pypi", 377 | "version": "==7.1.2" 378 | }, 379 | "pytest-runner": { 380 | "hashes": [ 381 | "sha256:4c059cf11cf4306e369c0f8f703d1eaf8f32fad370f41deb5f007044656aca6b", 382 | "sha256:b4d85362ed29b4c348678de797df438f0f0509497ddb8c647096c02a6d87b685" 383 | ], 384 | "index": "pypi", 385 | "version": "==6.0.0" 386 | }, 387 | "readme-renderer": { 388 | "hashes": [ 389 | "sha256:73b84905d091c31f36e50b4ae05ae2acead661f6a09a9abb4df7d2ddcdb6a698", 390 | "sha256:a727999acfc222fc21d82a12ed48c957c4989785e5865807c65a487d21677497" 391 | ], 392 | "markers": "python_version >= '3.7'", 393 | "version": "==35.0" 394 | }, 395 | "requests": { 396 | "hashes": [ 397 | "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", 398 | "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" 399 | ], 400 | "markers": "python_version >= '3.7' and python_version < '4'", 401 | "version": "==2.28.1" 402 | }, 403 | "requests-toolbelt": { 404 | "hashes": [ 405 | "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f", 406 | "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0" 407 | ], 408 | "version": "==0.9.1" 409 | }, 410 | "rfc3986": { 411 | "hashes": [ 412 | "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", 413 | "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c" 414 | ], 415 | "markers": "python_version >= '3.7'", 416 | "version": "==2.0.0" 417 | }, 418 | "rich": { 419 | "hashes": [ 420 | "sha256:4c586de507202505346f3e32d1363eb9ed6932f0c2f63184dea88983ff4971e2", 421 | "sha256:d2bbd99c320a2532ac71ff6a3164867884357da3e3301f0240090c5d2fdac7ec" 422 | ], 423 | "markers": "python_version < '4' and python_full_version >= '3.6.3'", 424 | "version": "==12.4.4" 425 | }, 426 | "setuptools": { 427 | "hashes": [ 428 | "sha256:990a4f7861b31532871ab72331e755b5f14efbe52d336ea7f6118144dd478741", 429 | "sha256:c1848f654aea2e3526d17fc3ce6aeaa5e7e24e66e645b5be2171f3f6b4e5a178" 430 | ], 431 | "markers": "python_version >= '3.7'", 432 | "version": "==62.6.0" 433 | }, 434 | "six": { 435 | "hashes": [ 436 | "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", 437 | "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" 438 | ], 439 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", 440 | "version": "==1.16.0" 441 | }, 442 | "tomli": { 443 | "hashes": [ 444 | "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", 445 | "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" 446 | ], 447 | "markers": "python_version >= '3.7'", 448 | "version": "==2.0.1" 449 | }, 450 | "twine": { 451 | "hashes": [ 452 | "sha256:42026c18e394eac3e06693ee52010baa5313e4811d5a11050e7d48436cf41b9e", 453 | "sha256:96b1cf12f7ae611a4a40b6ae8e9570215daff0611828f5fe1f37a16255ab24a0" 454 | ], 455 | "index": "pypi", 456 | "version": "==4.0.1" 457 | }, 458 | "typing-extensions": { 459 | "hashes": [ 460 | "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", 461 | "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" 462 | ], 463 | "markers": "python_version < '3.10'", 464 | "version": "==4.3.0" 465 | }, 466 | "urllib3": { 467 | "hashes": [ 468 | "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", 469 | "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" 470 | ], 471 | "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", 472 | "version": "==1.26.9" 473 | }, 474 | "webencodings": { 475 | "hashes": [ 476 | "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", 477 | "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" 478 | ], 479 | "version": "==0.5.1" 480 | }, 481 | "wheel": { 482 | "hashes": [ 483 | "sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a", 484 | "sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4" 485 | ], 486 | "index": "pypi", 487 | "version": "==0.37.1" 488 | }, 489 | "zipp": { 490 | "hashes": [ 491 | "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad", 492 | "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099" 493 | ], 494 | "markers": "python_version >= '3.7'", 495 | "version": "==3.8.0" 496 | } 497 | } 498 | } 499 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 書く kaku 2 | to write 3 | 4 | Kaku by choice does NOT push, distribute or other post-process the generated files. This is to keep the core code specific to discovery and generation, publishing will most likely be handled by Hakkan. 5 | 6 | ## Discovery 7 | Discovery of the items to generate is declarative and very purposeful, if a directory or file is not specified then it is ignored, this will both simplify the code for discovery and also allow for secondary metadata files to be added in future enhancements without requiring tweaks to kaku for special handling. 8 | 9 | To enable this, and also to hopefully make the discovery code simple, the discovery part of kaku will be driven by a list of action objects that define a file pattern and commands to run. I want to explore using existing tools for this along the lines of Makefiles - can I put the kaku.toml config in a directory and specify target patterns using the `glob` Python module with commands to execute across each item in the returned list. 10 | 11 | Kaku can then make use of a collection of small conversion scripts that all take the same inputs: file to act on and config block. The config block would contain the necessary items to drive the targeted conversion tool. 12 | 13 | Directory example 14 | ``` 15 | kaku.toml 16 | /templates/ 17 | root.jinja 18 | about.jinja 19 | index.jinja 20 | post.jinja 21 | /pages/ 22 | site-index/ 23 | index.asciidoc 24 | posts/ 25 | *.asciidoc 26 | static/ 27 | *.asciidoc 28 | /assets/ 29 | bear.png 30 | github.png 31 | ``` 32 | 33 | `kaku.toml` 34 | ``` 35 | site-url = `https://bear.im` 36 | author = `bear` 37 | 38 | [paths] 39 | rootdir="/bearim/" 40 | outputdir="output/" 41 | templates="/templates" 42 | images="/assets" 43 | 44 | [rules] 45 | [rules.site] 46 | glob = 'pages/site-index/*.asciidoc' 47 | target = '{stem}.html' 48 | 49 | [rules.static] 50 | glob = 'pages/static/**/*.asciidoc' 51 | target = '{parent}/{stem}.html' 52 | 53 | [rules.posts] 54 | glob = 'pages/posts/**/*.asciidoc' 55 | target="{parent}/{stem}.html' 56 | ``` 57 | 58 | ## Generation 59 | When a file is being processed, the source and target file is generated with a core set of variables available for expansion. Only files that have their source date/time attribute newer than the target date/time will be processed. 60 | 61 | When files are being generated, any path that is not an absolute reference, i.e. those that do not start with `/`, will be processed using the `rootdir` value for reading and the path will be expanded with the the values from Python's `pathlib` being available for expansion and `{parent}` set as appropriate for the glob'd result, for example given the following configuration 62 | 63 | ``` 64 | [paths] 65 | rootdir = '/sitedata/' 66 | outputdir = 'output/' 67 | [rules.relative] 68 | glob = '**/*.txt' 69 | target = '{parent}/{stem}.html' 70 | [rules.absolute] 71 | glob = '/foo/**/*.txt' 72 | target = '{parent}/{stem}.html' 73 | ``` 74 | 75 | An input file of `/foo/bob/bar.txt` would result in 76 | - `{outputdir}`: "/foo/" 77 | - `{parent}`: "bob/" 78 | - `{name}`: "bar.txt" 79 | - `{stem}`: "bar" 80 | - `{suffix}`: ".txt" 81 | - target file: `/foo/bob/bar.html` 82 | 83 | An input file of `/sitedata/bob/bar.txt` would result in 84 | - `{outputdir}`: "output/" 85 | - `{parent}`: "bob/" 86 | - `{name}`: "bar.txt" 87 | - `{stem}`: "bar" 88 | - `{suffix}`: ".txt" 89 | - target file: `/foo/bob/bar.html` 90 | 91 | Other assumptions are in place for variable expansion 92 | - any input path that does not have a leading `/` will be prepended with `{rootdir}/` 93 | - any output path that does not have a leading `/` will be prepended with `{outputdir}/` 94 | - `{images-path}` will be expanded to the value of the `images` paths value relative to the output path, this allows for html and css relative paths to resolve properly 95 | - `{today}` will be today's date in YYYY-MM-DD format 96 | - `{today-year}` will be the current year 97 | - `{author}` will be the defined `author` configuration value 98 | - `{site-url}` will be the expanded to the network and url of the generated site 99 | - `{root}` will be the full filename incl 100 | - `{parent}` will be the path that the `**` glob expanded as without the root 101 | - `{stem}` will be the base filename without the extension 102 | - `{name}` will be the filename without the path 103 | - `{suffix}` will be the filename without the stem 104 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=42", 4 | "wheel" 5 | ] 6 | build-backend = "setuptools.build_meta" 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = kaku 3 | version = 0.1 4 | author = Mike Taylor 5 | author_email = bear@bear.im 6 | description = "to write" 7 | long_description = file: README.md 8 | long_description_content_type = text/markdown 9 | url = https://github.com/bear/kaku 10 | license = CC0 1.0 Universal 11 | classifiers = 12 | Programming Language :: Python :: 3 13 | License :: OSI Approved :: MIT License 14 | Operating System :: OS Independent 15 | Topic :: Software Development :: Libraries :: Python Modules 16 | 17 | [options] 18 | package_dir = 19 | = src 20 | packages = find: 21 | python_requires = >=3.9 22 | install_requires = 23 | click 24 | 25 | [options.packages.find] 26 | where = src 27 | 28 | [options.entry_points] 29 | console_scripts = 30 | kaku = kaku.cli:cli 31 | 32 | [check-manifest] 33 | ignore = 34 | violations.flake8.txt 35 | 36 | [isort] 37 | multi_line_output=3 38 | include_trailing_comma=True 39 | force_grid_wrap=0 40 | use_parentheses=True 41 | line_length=88 42 | 43 | [flake8] 44 | filename = *.py src/ tests/ 45 | exclude = .cache,.tox,.git,.eggs,.venv,__pycache__,build,dist 46 | ignore = E203, E221, E241, E266, E501, W503 47 | max-complexity = 18 48 | select = B,C,E,F,W,T4 49 | 50 | [tool:pytest] 51 | testpaths=tests 52 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup() 4 | -------------------------------------------------------------------------------- /src/kaku/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bear/kaku-deprecated/a2bb478ab9dca1541c11bbf1f2ae7ffbed630aa1/src/kaku/__init__.py -------------------------------------------------------------------------------- /src/kaku/cli.py: -------------------------------------------------------------------------------- 1 | import click 2 | from dotenv import load_dotenv 3 | from .tools import loadConfig 4 | 5 | 6 | load_dotenv() 7 | 8 | 9 | @click.command() 10 | @click.option( 11 | "-c", 12 | "--config", 13 | envvar="HAKKAN_CONFIG", 14 | default="./hakkan.toml", 15 | help="Hakkan configuration file", 16 | ) 17 | @click.option( 18 | "-v", 19 | "--verbose", 20 | default=False, 21 | envvar="HAKKAN_VERBOSE", 22 | ) 23 | def cli(config, verbose): 24 | """Publish a project 25 | 26 | Load and process the given project's .toml configuration file then exit. 27 | 28 | The default project filename is `hakkan.toml` and can be given by setting the HAKKAN_CONFIG environment variable. 29 | \f 30 | 31 | :param config 32 | """ 33 | click.echo(f"config: {config}, verbose: {verbose}") 34 | loadConfig(config) 35 | 36 | 37 | if __name__ == "__main__": 38 | cli() 39 | -------------------------------------------------------------------------------- /src/kaku/tools.py: -------------------------------------------------------------------------------- 1 | def loadConfig(configFile=None): 2 | print(f"loading {configFile}") 3 | --------------------------------------------------------------------------------