Update documentation
This commit is contained in:
@@ -11,3 +11,6 @@ httpretty = "*"
|
||||
pycodestyle = "*"
|
||||
pydocstyle = "*"
|
||||
pylint = "*"
|
||||
sphinx = "*"
|
||||
sphinx-autobuild = "*"
|
||||
sphinx-rtd-theme = "*"
|
||||
|
||||
Generated
+201
-4
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "9205540483d67319c3bbf524d7200eb07daa0ec49322c12c71e5cd82a82bdea1"
|
||||
"sha256": "18a4e58148426115c0ddb7e285007ea1de384fae5cc4cf0c2e1c6257dc58a182"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@@ -128,6 +128,20 @@
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"alabaster": {
|
||||
"hashes": [
|
||||
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
|
||||
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
|
||||
],
|
||||
"version": "==0.7.12"
|
||||
},
|
||||
"argh": {
|
||||
"hashes": [
|
||||
"sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3",
|
||||
"sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65"
|
||||
],
|
||||
"version": "==0.26.2"
|
||||
},
|
||||
"asn1crypto": {
|
||||
"hashes": [
|
||||
"sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87",
|
||||
@@ -156,12 +170,19 @@
|
||||
],
|
||||
"version": "==18.2.0"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669",
|
||||
"sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23"
|
||||
],
|
||||
"version": "==2.6.0"
|
||||
},
|
||||
"backports.functools-lru-cache": {
|
||||
"hashes": [
|
||||
"sha256:9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a",
|
||||
"sha256:f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd"
|
||||
],
|
||||
"markers": "python_version < '3.4'",
|
||||
"markers": "python_version == '2.7'",
|
||||
"version": "==1.5"
|
||||
},
|
||||
"certifi": {
|
||||
@@ -299,6 +320,14 @@
|
||||
],
|
||||
"version": "==0.6.2"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
|
||||
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
|
||||
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
|
||||
],
|
||||
"version": "==0.14"
|
||||
},
|
||||
"enum34": {
|
||||
"hashes": [
|
||||
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
|
||||
@@ -306,7 +335,7 @@
|
||||
"sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
|
||||
"sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
|
||||
],
|
||||
"markers": "python_version < '3'",
|
||||
"markers": "python_version < '3.4'",
|
||||
"version": "==1.1.6"
|
||||
},
|
||||
"funcsigs": {
|
||||
@@ -338,12 +367,19 @@
|
||||
],
|
||||
"version": "==2.8"
|
||||
},
|
||||
"imagesize": {
|
||||
"hashes": [
|
||||
"sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8",
|
||||
"sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"ipaddress": {
|
||||
"hashes": [
|
||||
"sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794",
|
||||
"sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c"
|
||||
],
|
||||
"markers": "python_version < '3'",
|
||||
"markers": "extra == 'secure'",
|
||||
"version": "==1.0.22"
|
||||
},
|
||||
"isort": {
|
||||
@@ -354,6 +390,13 @@
|
||||
],
|
||||
"version": "==4.3.4"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
|
||||
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
|
||||
],
|
||||
"version": "==2.10"
|
||||
},
|
||||
"lazy-object-proxy": {
|
||||
"hashes": [
|
||||
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33",
|
||||
@@ -388,6 +431,46 @@
|
||||
],
|
||||
"version": "==1.3.1"
|
||||
},
|
||||
"livereload": {
|
||||
"hashes": [
|
||||
"sha256:29cadfabcedd12eed792e0131991235b9d4764d4474bed75cf525f57109ec0a2",
|
||||
"sha256:e632a6cd1d349155c1d7f13a65be873b38f43ef02961804a1bba8d817fa649a7"
|
||||
],
|
||||
"version": "==2.6.0"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432",
|
||||
"sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b",
|
||||
"sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9",
|
||||
"sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af",
|
||||
"sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834",
|
||||
"sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd",
|
||||
"sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d",
|
||||
"sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7",
|
||||
"sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b",
|
||||
"sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3",
|
||||
"sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c",
|
||||
"sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2",
|
||||
"sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7",
|
||||
"sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36",
|
||||
"sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1",
|
||||
"sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e",
|
||||
"sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1",
|
||||
"sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c",
|
||||
"sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856",
|
||||
"sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550",
|
||||
"sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492",
|
||||
"sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672",
|
||||
"sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401",
|
||||
"sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6",
|
||||
"sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6",
|
||||
"sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c",
|
||||
"sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd",
|
||||
"sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||
@@ -403,6 +486,13 @@
|
||||
],
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af",
|
||||
"sha256:9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"
|
||||
],
|
||||
"version": "==19.0"
|
||||
},
|
||||
"pathlib2": {
|
||||
"hashes": [
|
||||
"sha256:25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742",
|
||||
@@ -411,6 +501,12 @@
|
||||
"markers": "python_version < '3.6'",
|
||||
"version": "==2.3.3"
|
||||
},
|
||||
"pathtools": {
|
||||
"hashes": [
|
||||
"sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0"
|
||||
],
|
||||
"version": "==0.1.2"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:8ddc32f03971bfdf900a81961a48ccf2fb677cf7715108f85295c67405798616",
|
||||
@@ -418,6 +514,12 @@
|
||||
],
|
||||
"version": "==0.8.1"
|
||||
},
|
||||
"port-for": {
|
||||
"hashes": [
|
||||
"sha256:b16a84bb29c2954db44c29be38b17c659c9c27e33918dec16b90d375cc596f1c"
|
||||
],
|
||||
"version": "==0.3.1"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
"sha256:bf92637198836372b520efcba9e020c330123be8ce527e535d185ed4b6f45694",
|
||||
@@ -448,6 +550,13 @@
|
||||
"index": "pypi",
|
||||
"version": "==3.0.0"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a",
|
||||
"sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"
|
||||
],
|
||||
"version": "==2.3.1"
|
||||
},
|
||||
"pylint": {
|
||||
"hashes": [
|
||||
"sha256:02c2b6d268695a8b64ad61847f92e611e6afcff33fd26c3a2125370c4662905d",
|
||||
@@ -464,6 +573,13 @@
|
||||
"markers": "extra == 'secure'",
|
||||
"version": "==19.0.0"
|
||||
},
|
||||
"pyparsing": {
|
||||
"hashes": [
|
||||
"sha256:66c9268862641abcac4a96ba74506e594c884e3f57690a696d21ad8210ed667a",
|
||||
"sha256:f6c5ef0d7480ad048c054c37632c67fca55299990fff127850181659eea33fc3"
|
||||
],
|
||||
"version": "==2.3.1"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:41568ea7ecb4a68d7f63837cf65b92ce8d0105e43196ff2b26622995bb3dc4b2",
|
||||
@@ -480,6 +596,29 @@
|
||||
"index": "pypi",
|
||||
"version": "==2.6.1"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:32b0891edff07e28efe91284ed9c31e123d84bea3fd98e1f72be2508f43ef8d9",
|
||||
"sha256:d5f05e487007e29e03409f9398d074e158d920d36eb82eaf66fb1136b0c5374c"
|
||||
],
|
||||
"version": "==2018.9"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b",
|
||||
"sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf",
|
||||
"sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a",
|
||||
"sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3",
|
||||
"sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1",
|
||||
"sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1",
|
||||
"sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613",
|
||||
"sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04",
|
||||
"sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f",
|
||||
"sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537",
|
||||
"sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531"
|
||||
],
|
||||
"version": "==3.13"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e",
|
||||
@@ -527,6 +666,58 @@
|
||||
],
|
||||
"version": "==1.2.1"
|
||||
},
|
||||
"sphinx": {
|
||||
"hashes": [
|
||||
"sha256:429e3172466df289f0f742471d7e30ba3ee11f3b5aecd9a840480d03f14bcfe5",
|
||||
"sha256:c4cb17ba44acffae3d3209646b6baec1e215cad3065e852c68cc569d4df1b9f8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.8.3"
|
||||
},
|
||||
"sphinx-autobuild": {
|
||||
"hashes": [
|
||||
"sha256:66388f81884666e3821edbe05dd53a0cfb68093873d17320d0610de8db28c74e",
|
||||
"sha256:e60aea0789cab02fa32ee63c7acae5ef41c06f1434d9fd0a74250a61f5994692"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"sphinx-rtd-theme": {
|
||||
"hashes": [
|
||||
"sha256:02f02a676d6baabb758a20c7a479d58648e0f64f13e07d1b388e9bb2afe86a09",
|
||||
"sha256:d0f6bc70f98961145c5b0e26a992829363a197321ba571b31b24ea91879e0c96"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.4.2"
|
||||
},
|
||||
"sphinxcontrib-websupport": {
|
||||
"hashes": [
|
||||
"sha256:68ca7ff70785cbe1e7bccc71a48b5b6d965d79ca50629606c7861a21b206d9dd",
|
||||
"sha256:9de47f375baf1ea07cdb3436ff39d7a9c76042c10a769c52353ec46e4e8fc3b9"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"tornado": {
|
||||
"hashes": [
|
||||
"sha256:0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d",
|
||||
"sha256:4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409",
|
||||
"sha256:732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f",
|
||||
"sha256:8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f",
|
||||
"sha256:8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5",
|
||||
"sha256:d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb",
|
||||
"sha256:e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444"
|
||||
],
|
||||
"version": "==5.1.1"
|
||||
},
|
||||
"typing": {
|
||||
"hashes": [
|
||||
"sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d",
|
||||
"sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4",
|
||||
"sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a"
|
||||
],
|
||||
"markers": "python_version < '3.5'",
|
||||
"version": "==3.6.6"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||
@@ -534,6 +725,12 @@
|
||||
],
|
||||
"version": "==1.24.1"
|
||||
},
|
||||
"watchdog": {
|
||||
"hashes": [
|
||||
"sha256:965f658d0732de3188211932aeb0bb457587f04f63ab4c1e33eab878e9de961d"
|
||||
],
|
||||
"version": "==0.9.0"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
"sha256:4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533"
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
# OpenMensa STW Potsdam
|
||||
# OpenMensa Parser STW Potsdam
|
||||
|
||||
[](https://travis-ci.org/f4lco/om-parser-stw-potsdam-v2)
|
||||
[](https://coveralls.io/github/f4lco/om-parser-stw-potsdam-v2?branch=master)
|
||||
[](https://om-parser-stw-potsdam-v2.readthedocs.io/en/latest/)
|
||||
|
||||
## Development Quickstart
|
||||
[OpenMensa][om] parser components query canteen websites for menus and transform them into OpenMensa's data format.
|
||||
This project came to life after the website of the canteens of the Studentenwerk Potsdam changed, and is therefore the successor to [kaifabian/om-parser-potsdam][prev-parser] (hence the "-v2").
|
||||
|
||||
$ pipenv install --two --dev # Create venv
|
||||
$ make test # Check setup by running tests
|
||||
$ make debug # Start app instance with debugger
|
||||
Among others, OpenMensa powers the popular [Mensa Uni Potsdam][steppschuh] Android app.
|
||||
|
||||
The current application is built with [Python][py], [PyOpenMensa][pom], and [Flask][flask]. Learn more about the technical details at [Read the Docs][rtd].
|
||||
|
||||
**Contributions** are always welcome, in particular if the response format of the canteens change. Feel free to file a PR with improvements.
|
||||
|
||||
**Deployment** If in need of a deployment, file a PR to this fork: [kaifabian/om-parser-potsdam-v2](kai). Kai is currently in charge of running an instance of the parser and the registration on the OpenMensa platform.
|
||||
|
||||
**Where to go next** maybe use this parser or the OpenMensa API to source a new dataset for training a predictor for your favorite lunch?
|
||||
|
||||
**License** Just assume this project is licensed in terms of [WTFPL](http://www.wtfpl.net/) ;)
|
||||
|
||||
[om]: https://openmensa.org
|
||||
[prev-parser]: https://github.com/kaifabian/om-parser-potsdam
|
||||
[rtd]: https://om-parser-stw-potsdam-v2.readthedocs.io/en/latest/
|
||||
[steppschuh]: https://steppschuh.net/blog/?p=951
|
||||
[py]: http://python.org
|
||||
[pom]: https://github.com/mswart/pyopenmensa
|
||||
[flask]: https://palletsprojects.com/p/flask/
|
||||
[kai]: https://github.com/kaifabian/om-parser-stw-potsdam-v2
|
||||
@@ -0,0 +1 @@
|
||||
/_build
|
||||
@@ -0,0 +1,23 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
# https://pypi.org/project/sphinx-autobuild/
|
||||
livehtml:
|
||||
sphinx-autobuild --open-browser $(SPHINXOPTS) . $(BUILDDIR)/html
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
/* Make the headlines for class and function documentation span the entire width */
|
||||
.rst-content dl.class dt, .rst-content dl.function dt {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
.. _cache_hash:
|
||||
|
||||
Cache Hash
|
||||
----------
|
||||
|
||||
The JSON endpoint requires a query parameter named ``cHash`` (short for cache hash).
|
||||
It origins from TYPO and asserts that the other query parameters still have their predefined value.
|
||||
The problem solved is the following: imagine a view that is subject to caching and takes a single parameter, say a blog entry ID, which sets the output of the entire view fixed.
|
||||
A malicious client could start enumerating that ID, and for every possible outcome (found blog entry, 404 pages, other behaviours), one cache entry is created.
|
||||
In order to prevent excessive memory consumption, TYPO ships a hash of the parameters in order to turn down "guessed" parameters up front.
|
||||
|
||||
The value of ``cHash`` is computed as follows: ::
|
||||
|
||||
md5(serialize(sort(array(super => secret, key1 => value1, key2 => value2, ...))))
|
||||
|
||||
Keys and values are drawn from the query string of the URL and restricted to a known set of "relevant" URL parameters.
|
||||
The first array entry contains the server's secret - think of it as salt, of course only known to the server.
|
||||
|
||||
Because the hash involves a salt / secret that clients' are unable to compute, we need to obtain or hardcode these.
|
||||
With greater effort, it is of course possible to extract ``cHash`` from the DOM.
|
||||
However, fetching ``cHash`` does not make the parser more resilient to change. As noted, ``cHash`` is the hash of the query parameters plus some salt, effectively ``md5(secret + canteen ID)`` for our purposes. If the canteen ID changed, there is more to fix than just to account for the changed hash.
|
||||
|
||||
It's placing the bet on which changes first: the canteen ID or the canteen page structure. Given that extracting content from the DOM is inherently unreliable, one would have to implement the following extraction pipeline to assemble all pieces of information required to access the JSON endpoint:
|
||||
|
||||
1. Access the canteen selection page, this works without ``cHash``. Find canteen and extract the ``cHash`` for the canteen specific site.
|
||||
2. Access canteen specific site and find the JSON endpoint URL in the DOM, containing the ``cHash`` specific to that endpoint.
|
||||
3. Access the JSON endpoint to get the menu.
|
||||
|
||||
Given that this alternative consists of two more indirections, hard-coding ``cHash`` appears justifiable.
|
||||
For this reason the automated retrieval of ``cHash`` and others is postponed until they are subject to frequent change.
|
||||
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = u'OpenMensa Potsdam'
|
||||
copyright = u'2018, f4lco'
|
||||
author = u'f4lco'
|
||||
|
||||
# The short X.Y version
|
||||
version = u''
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = u'0.1'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
def setup(app):
|
||||
app.add_stylesheet('css/custom.css')
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.githubpages',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# The default sidebars (for documents that don't match any pattern) are
|
||||
# defined by theme itself. Builtin themes are using these templates by
|
||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||
# 'searchbox.html']``.
|
||||
#
|
||||
# html_sidebars = {}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'OpenMensaPotsdamdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'OpenMensaPotsdam.tex', u'OpenMensa Potsdam Documentation',
|
||||
u'f4lco', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'openmensapotsdam', u'OpenMensa Potsdam Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'OpenMensaPotsdam', u'OpenMensa Potsdam Documentation',
|
||||
author, 'OpenMensaPotsdam', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Epub output -------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#
|
||||
# epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
@@ -0,0 +1,61 @@
|
||||
Development
|
||||
-----------
|
||||
|
||||
Because the parser may break on changes to the canteen website, it should be easy to fix. Refer to the following sections to jumpstart development.
|
||||
|
||||
Quickstart
|
||||
~~~~~~~~~~
|
||||
|
||||
Use `Pipenv <https://pipenv.readthedocs.io/en/latest/>`_ to setup the environment and start coding: ::
|
||||
|
||||
$ pipenv install --two --dev # Create venv
|
||||
$ make test # Check setup by running tests
|
||||
$ make debug # Start app instance with debugger and pretty printing of JSON
|
||||
$ make run # Start app without debugger
|
||||
$ make lint # Enforce style guide / check for logic bugs
|
||||
$ cd docs && make livehtml # View live-updating docs in the browser
|
||||
|
||||
The list of available canteens is available at the ``/canteens`` endpoint. The ``/canteens/<name>`` endpoint provides the XML feed for individual canteens, e.g., ``/canteens/griebnitzsee``.
|
||||
|
||||
Given the default configuration, http://127.0.0.1:5000/canteens/griebnitzsee will display the `OpenMensa` meta-feed for the Griebnitzsee canteen, and http://127.0.0.1:5000/canteens/griebnitzsee/menu will render the menu feed.
|
||||
|
||||
Main Module Entry Points
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the following the main workflow of this parser is explained.
|
||||
Generating a new `OpenMensa` feed starts by reading the configured canteens. Some canteen data, such as ID, name, and location, are currently not scraped. Doing so would be very brittle and involve a multistep process. Refer to the :ref:`cache_hash` for deeper insight into the obstacles.
|
||||
|
||||
.. autofunction:: stw_potsdam.config.read_canteen_config
|
||||
|
||||
.. autoclass:: stw_potsdam.config.Canteen
|
||||
|
||||
Use the canteen data to assemble the menu parameters in order to download the menu JSON. The menu parameters are also used as cache key: it should uniquely identify the retrieved menu.
|
||||
|
||||
.. autoclass:: stw_potsdam.canteen_api.MenuParams
|
||||
|
||||
.. autofunction:: stw_potsdam.canteen_api.download_menu
|
||||
|
||||
The render module contains methods for converting the JSON response into valid `OpenMensa` menu and meta feeds, respectively:
|
||||
|
||||
.. autofunction:: stw_potsdam.feed.render_menu
|
||||
.. autofunction:: stw_potsdam.feed.render_meta
|
||||
|
||||
Tests
|
||||
~~~~~
|
||||
|
||||
Unit tests are not a really good fit to the problem at hand. The parser is basically a converter, transforming loosely defined JSON input to well-specified XML output. The conversion is not very sophisticated, and the parser's correctness mainly depends on the stability of the JSON output of the canteen website. Two main questions are remaining.
|
||||
|
||||
First, if the parser logic has changed, has the change been intentionally, and is it meaningful? The `consistency` integration test covers that, it compares the results of one examplary API response to a canned XML feed.
|
||||
|
||||
Second, if the canteen API changed, or there is some variance in the response which has not been apparent at development time, which canteens are affected? The `retrieval` acceptance test iterates over all configured canteens, and tries to download and interpret the current API responses. No exception indicates a successful run.
|
||||
|
||||
Test execution works as follows: ::
|
||||
|
||||
make test # (1)
|
||||
ENABLE_API_QUERY=1 make test # (2)
|
||||
|
||||
The first invocation runs tests whose outcome can solely be determined by the test suite, which makes them suitable for frequent execution and CI systems.
|
||||
Setting the environment variable ``ENABLE_API_QUERY`` enables tests which require querying the canteen API. Because third-party services are queried, those are more suited to manual execution. Developers can quickly check if their change is applicable to today's menu.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Welcome to OpenMensa Parser Potsdam's documentation!
|
||||
====================================================
|
||||
|
||||
An OpenMensa parser retrieves canteen menus and renders them in a commonly understood format.
|
||||
Learn more about OpenMensa_.
|
||||
|
||||
|
||||
.. _OpenMensa: https://openmensa.org/
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
dev
|
||||
api
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
@@ -68,6 +68,7 @@ def render_meta(canteen, menu_feed_url):
|
||||
"""Render a OpenMensa XML meta feed for a given canteen.
|
||||
|
||||
:param Canteen canteen: the canteen
|
||||
:param menu_feed_url: the canteen menu URL
|
||||
:return: the XML meta feed as string
|
||||
"""
|
||||
builder = LazyBuilder()
|
||||
|
||||
Reference in New Issue
Block a user