diff --git a/.github/workflows/github-publish-celery-flaskomics.yml b/.github/workflows/github-publish-celery-flaskomics.yml new file mode 100644 index 00000000..10a78df1 --- /dev/null +++ b/.github/workflows/github-publish-celery-flaskomics.yml @@ -0,0 +1,67 @@ +name: Publish Flaskomics Docker image to github + +on: + push: + branches: + - 'master' + - 'dev' + tags: + - '*.*.*' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: celery-flaskomics + +jobs: + build-and-push-image: + if: github.repository == 'askomics/flaskomics' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - + name: Checkout repository + uses: actions/checkout@v3 + + - + name: Login to registry + uses: docker/login-action@v1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - + name: Docker meta + id: meta + uses: docker/metadata-action@v3 + with: + # list of Docker images to use as base name for tags + images: ${{ env.REGISTRY }}/askomics/${{ env.IMAGE_NAME }} + # generate Docker tags based on the following events/attributes + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./docker/DockerfileCelery + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/github-publish-flaskomics.yml b/.github/workflows/github-publish-flaskomics.yml new file mode 100644 index 00000000..51d25330 --- /dev/null +++ b/.github/workflows/github-publish-flaskomics.yml @@ -0,0 +1,67 @@ +name: Publish Flaskomics Docker image to github + +on: + push: + branches: + - 'master' + - 'dev' + tags: + - '*.*.*' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: flaskomics + +jobs: + build-and-push-image: + if: github.repository == 'askomics/flaskomics' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - + name: Checkout repository + uses: actions/checkout@v3 + + - + name: Login to registry + uses: docker/login-action@v1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - + name: Docker meta + id: meta + uses: docker/metadata-action@v3 + with: + # list of Docker images to use as base name for tags + images: ${{ env.REGISTRY }}/askomics/${{ env.IMAGE_NAME }} + # generate Docker tags based on the following events/attributes + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - + name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + file: ./docker/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/lint_test.yml b/.github/workflows/lint_test.yml index 84ca6d05..4cf0e4e3 100644 --- a/.github/workflows/lint_test.yml +++ b/.github/workflows/lint_test.yml @@ -57,7 +57,7 @@ jobs: docker run -d --name corese -p 8082:8080 -t xgaia/corese:latest /bin/sh -c "netstat -nr | grep '^0\.0\.0\.0' | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])' | grep -v '^0\.0\.0\.0' | sed 's/$/ askomics-host/' >> /etc/hosts && /corese/start.sh" docker run -d --name isql-api -p 5051:5050 -e VIRTUOSO_HOST=askomics-host -e VIRTUOSO_ISQL_PORT=1112 -t xgaia/isql-api:2.1.1 /bin/sh -c "netstat -nr | grep '^0\.0\.0\.0' | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])' | grep -v '^0\.0\.0\.0' | sed 's/$/ askomics-host/' >> /etc/hosts && sh /isqlapi/docker-run.sh" docker run -d --name ldap -p 8389:389 -e ORGANISATION_NAME=AskOmics -e SUFFIX='dc=askomics,dc=org' -e ROOT_USER=admin -e ROOT_PW_CLEAR=admin -e FIRST_USER=true -e USER_UID=jwick -e USER_GIVEN_NAME=John -e USER_SURNAME=Wick -e USER_EMAIL=john.wick@askomics.org -e USER_PW_CLEAR=jwick -t xgaia/simple-ldap:latest - galaxy-wait -g http://localhost:8081 --timeout 300 + galaxy-wait -g http://localhost:8081 --timeout 900 echo "Galaxy is online, waiting a bit more for admin user creation" sleep 1m - name: Run tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 0766ab02..0bf87afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,65 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 This changelog was started for release 4.2.0. +## [4.5.0] - 2023-10-20 + +### **Deprecation warning** + +- Due to a change in the way *strands* are integrated for FALDO entities, you will need to re-integrate them. +- 'Results' from older version of Askomics using 'Minus' or 'Union' blocks will use 'legacy' mode. (Meaning, they will not have recursive block support). To enable recursive block support, please recreate the query from scratch, or manually delete the blocks and re-create them. + + +### Added + +- Added 'anonymous_query' and 'anonymous_query_cleanup' variables + - These enable 'anonymous query' mode, allowing anonymous users to send 'full queries'. See documentation +- Added 'overview' button in the query page. This button will show all 'selected' attributes, and allow users to quickly select the related entity. +- Added 'Abstraction' tab on the navbar. This will print the whole abstraction as a 2d/3d graph. +- Added 'distance' notion, using attribute link. This allows user to filter a value based on another value, with an optional modifier. +- Added 'custom distance' option for faldo relation (instead of just 'included_in' and 'overlap_with') +- Store 'version' value when storing results. Not used for now, but might be used in deprecation warnings later +- Removed some lines from coverage computation +- Added 'indirect relations': Two entities will be linked on the graph, without a direct relation between them (same as faldo relations). This is intended to be used with 'linked attributes' (ex: get all entities B where B.color is the same as A.color, without a direct relation between A and B) +- Basic support for 'skos:broader' and 'skos:narrower' for ontologies. + +### Fixed + +- Fixed new linting +- Fixed logs for production setup +- Fixed profile update & password reset tab in user profile page +- Fixed Gff Faldo integration (was only integrating the last selected entity) +- Fixed an issue when using filters and an 'UNION' node +- Fixed an issue when launching a query with a 'linked' attribute toggled but unselected +- Fixed missing includeIn and includeInReference in bed files +- Fixed 'overlap_with' faldo query + +### Changed + +- Added contact_message config option, displayed in a new 'Contact' page +- Added front_message config option, displayed on the front page +- Now print reset link into logs if there are no mailer configured +- Fixed markupsafe to 2.0.1 +- Increased Galaxy timeout for tests +- Fix documentation build +- Force all 'user queries'(ask/sparql interfaces) to go to the unauthenticated endpoint, to increase security (no write permissions) +- Force all queries to use 'POST' instead of 'GET' to avoid max length issues +- Changed the way 'strands' are integrated, to quicken FALDO queries. (Require re-integrating the data) +- 'Same strand' queries will now match 'BothStrand' with a forward or reverse strand +- Use '+', '-' and '.' for strand values in CSV instead of raw value (for homogenization) +- Now allows 'infinite' recursive blocks (ie, a Minus block inside a Union block, or the opposite) +- Overhaul faldo relation: add 'direct shortcut' triples between entities and values, to avoid using slow property paths when using faldo queries + +### Security + +- Bump markdown-captions from 2 to 2.1.2 +- Bump http-cache-semantics from 4.1.0 to 4.1.1 +- Bump minimatch from 3.0.4 to 3.1.2 +- Bump json5 from 1.0.1 to 1.0.2 +- Bump qs from 6.10.1 to 6.10.3 +- Bump decode-uri-component from 0.2.0 to 0.2.2 +- Bump loader-utils from 1.4.0 to 1.4.2 + + ## [4.4.0] - 2022-07-01 ### Fixed diff --git a/Makefile b/Makefile index 12f74d0c..e948fa8b 100644 --- a/Makefile +++ b/Makefile @@ -114,11 +114,18 @@ serve-celery: check-venv build-config create-user @echo 'Serving Celery...' . $(ACTIVATE) ifeq ($(MODE), dev) - FLASK_ENV=development FLASK_APP=app watchmedo auto-restart -d $(BASEDIR)/askomics --recursive -p '*.py' --ignore-patterns='*.pyc' -- celery -A askomics.tasks.celery worker -Q default -c $(NTASKS) -n default -l info + FLASK_ENV=development FLASK_APP=app watchmedo auto-restart -d $(BASEDIR)/askomics --recursive -p '*.py' --ignore-patterns='*.pyc' -- celery -A askomics.tasks.celery worker -Q default -c $(NTASKS) -n default -l info -B else FLASK_ENV=production FLASK_APP=app celery -A askomics.tasks.celery worker -Q default -c $(NTASKS) -n default -l info endif +serve-celery-beat: check-venv build-config create-user + @echo 'Starting Celerybeat' + . $(ACTIVATE) +ifeq ($(MODE), prod) + FLASK_ENV=production FLASK_APP=app celery -A askomics.tasks.celery beat -l info +endif + check-venv: test -s $(ACTIVATE) || { echo "$(ACTIVATE) not found. Run make install first"; exit 1; } diff --git a/Pipfile b/Pipfile index 6509b8eb..07dc5e69 100644 --- a/Pipfile +++ b/Pipfile @@ -29,6 +29,7 @@ tld = "*" argh = "*" python-ldap = "*" python-dateutil = "*" +markupsafe = "==2.0.1" [dev-packages] pytest = "*" diff --git a/Pipfile.lock b/Pipfile.lock index ef4d555b..5c6cb30f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5d768dd0f5c397f0380f7a594b66aed5e23d923674edfa3c62b4e47f5ce3e81e" + "sha256": "c3e2bf3cd152f0ca24a42d065d9e7d95f660a97f0cf91f61cef82eb45d016e83" }, "pipfile-spec": 6, "requires": {}, @@ -14,28 +14,154 @@ ] }, "default": { + "aiohttp": { + "hashes": [ + "sha256:002f23e6ea8d3dd8d149e569fd580c999232b5fbc601c48d55398fbc2e582e8c", + "sha256:01770d8c04bd8db568abb636c1fdd4f7140b284b8b3e0b4584f070180c1e5c62", + "sha256:0912ed87fee967940aacc5306d3aa8ba3a459fcd12add0b407081fbefc931e53", + "sha256:0cccd1de239afa866e4ce5c789b3032442f19c261c7d8a01183fd956b1935349", + "sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47", + "sha256:13da35c9ceb847732bf5c6c5781dcf4780e14392e5d3b3c689f6d22f8e15ae31", + "sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9", + "sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887", + "sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358", + "sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566", + "sha256:1f13f60d78224f0dace220d8ab4ef1dbc37115eeeab8c06804fec11bec2bbd07", + "sha256:229852e147f44da0241954fc6cb910ba074e597f06789c867cb7fb0621e0ba7a", + "sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e", + "sha256:255ba9d6d5ff1a382bb9a578cd563605aa69bec845680e21c44afc2670607a95", + "sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93", + "sha256:2b8d4e166e600dcfbff51919c7a3789ff6ca8b3ecce16e1d9c96d95dd569eb4c", + "sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad", + "sha256:3161ce82ab85acd267c8f4b14aa226047a6bee1e4e6adb74b798bd42c6ae1f80", + "sha256:33164093be11fcef3ce2571a0dccd9041c9a93fa3bde86569d7b03120d276c6f", + "sha256:39a312d0e991690ccc1a61f1e9e42daa519dcc34ad03eb6f826d94c1190190dd", + "sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0", + "sha256:3c68330a59506254b556b99a91857428cab98b2f84061260a67865f7f52899f5", + "sha256:3f0e27e5b733803333bb2371249f41cf42bae8884863e8e8965ec69bebe53132", + "sha256:3f5c7ce535a1d2429a634310e308fb7d718905487257060e5d4598e29dc17f0b", + "sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096", + "sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321", + "sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1", + "sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f", + "sha256:45ad816b2c8e3b60b510f30dbd37fe74fd4a772248a52bb021f6fd65dff809b6", + "sha256:4ac39027011414dbd3d87f7edb31680e1f430834c8cef029f11c66dad0670aa5", + "sha256:4d4cbe4ffa9d05f46a28252efc5941e0462792930caa370a6efaf491f412bc66", + "sha256:4fcf3eabd3fd1a5e6092d1242295fa37d0354b2eb2077e6eb670accad78e40e1", + "sha256:5d791245a894be071d5ab04bbb4850534261a7d4fd363b094a7b9963e8cdbd31", + "sha256:6c43ecfef7deaf0617cee936836518e7424ee12cb709883f2c9a1adda63cc460", + "sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22", + "sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34", + "sha256:713103a8bdde61d13490adf47171a1039fd880113981e55401a0f7b42c37d071", + "sha256:71783b0b6455ac8f34b5ec99d83e686892c50498d5d00b8e56d47f41b38fbe04", + "sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8", + "sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d", + "sha256:7ee912f7e78287516df155f69da575a0ba33b02dd7c1d6614dbc9463f43066e3", + "sha256:86f20cee0f0a317c76573b627b954c412ea766d6ada1a9fcf1b805763ae7feeb", + "sha256:89341b2c19fb5eac30c341133ae2cc3544d40d9b1892749cdd25892bbc6ac951", + "sha256:8a9b5a0606faca4f6cc0d338359d6fa137104c337f489cd135bb7fbdbccb1e39", + "sha256:8d399dade330c53b4106160f75f55407e9ae7505263ea86f2ccca6bfcbdb4921", + "sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5", + "sha256:90c72ebb7cb3a08a7f40061079817133f502a160561d0675b0a6adf231382c92", + "sha256:918810ef188f84152af6b938254911055a72e0f935b5fbc4c1a4ed0b0584aed1", + "sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865", + "sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d", + "sha256:99c5ac4ad492b4a19fc132306cd57075c28446ec2ed970973bbf036bcda1bcc6", + "sha256:9c19b26acdd08dd239e0d3669a3dddafd600902e37881f13fbd8a53943079dbc", + "sha256:9de50a199b7710fa2904be5a4a9b51af587ab24c8e540a7243ab737b45844543", + "sha256:9e2ee0ac5a1f5c7dd3197de309adfb99ac4617ff02b0603fd1e65b07dc772e4b", + "sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684", + "sha256:a3628b6c7b880b181a3ae0a0683698513874df63783fd89de99b7b7539e3e8a8", + "sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed", + "sha256:b04691bc6601ef47c88f0255043df6f570ada1a9ebef99c34bd0b72866c217ae", + "sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c", + "sha256:b2fe42e523be344124c6c8ef32a011444e869dc5f883c591ed87f84339de5976", + "sha256:b30e963f9e0d52c28f284d554a9469af073030030cef8693106d918b2ca92f54", + "sha256:bb54c54510e47a8c7c8e63454a6acc817519337b2b78606c4e840871a3e15349", + "sha256:bd111d7fc5591ddf377a408ed9067045259ff2770f37e2d94e6478d0f3fc0c17", + "sha256:bdf70bfe5a1414ba9afb9d49f0c912dc524cf60141102f3a11143ba3d291870f", + "sha256:ca80e1b90a05a4f476547f904992ae81eda5c2c85c66ee4195bb8f9c5fb47f28", + "sha256:caf486ac1e689dda3502567eb89ffe02876546599bbf915ec94b1fa424eeffd4", + "sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2", + "sha256:d25036d161c4fe2225d1abff2bd52c34ed0b1099f02c208cd34d8c05729882f0", + "sha256:d52d5dc7c6682b720280f9d9db41d36ebe4791622c842e258c9206232251ab2b", + "sha256:d67f8baed00870aa390ea2590798766256f31dc5ed3ecc737debb6e97e2ede78", + "sha256:d76e8b13161a202d14c9584590c4df4d068c9567c99506497bdd67eaedf36403", + "sha256:d95fc1bf33a9a81469aa760617b5971331cdd74370d1214f0b3109272c0e1e3c", + "sha256:de6a1c9f6803b90e20869e6b99c2c18cef5cc691363954c93cb9adeb26d9f3ae", + "sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965", + "sha256:e2a988a0c673c2e12084f5e6ba3392d76c75ddb8ebc6c7e9ead68248101cd446", + "sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a", + "sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca", + "sha256:e827d48cf802de06d9c935088c2924e3c7e7533377d66b6f31ed175c1620e05e", + "sha256:ebf3fd9f141700b510d4b190094db0ce37ac6361a6806c153c161dc6c041ccda", + "sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2", + "sha256:ec4fd86658c6a8964d75426517dc01cbf840bbf32d055ce64a9e63a40fd7b771", + "sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb", + "sha256:f0f03211fd14a6a0aed2997d4b1c013d49fb7b50eeb9ffdf5e51f23cfe2c77fa", + "sha256:f628dbf3c91e12f4d6c8b3f092069567d8eb17814aebba3d7d60c149391aee3a", + "sha256:f8ef51e459eb2ad8e7a66c1d6440c808485840ad55ecc3cafefadea47d1b1ba2", + "sha256:fc37e9aef10a696a5a4474802930079ccfc14d9f9c10b4662169671ff034b7df", + "sha256:fdee8405931b0615220e5ddf8cd7edd8592c606a8e4ca2a00704883c396e4479" + ], + "markers": "python_version >= '3.6'", + "version": "==3.8.6" + }, + "aiosignal": { + "hashes": [ + "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", + "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.1" + }, "amqp": { "hashes": [ - "sha256:03e16e94f2b34c31f8bf1206d8ddd3ccaa4c315f7f6a1879b7b1210d229568c2", - "sha256:493a2ac6788ce270a2f6a765b017299f60c1998f5a8617908ee9be082f7300fb" + "sha256:2c1b13fecc0893e946c65cbd5f36427861cffa4ea2201d8f6fca22e2a373b5e2", + "sha256:6f0956d2c23d8fa6e7691934d8c3930eadb44972cbbd1a7ae3a520f735d43359" ], "markers": "python_version >= '3.6'", - "version": "==5.0.6" + "version": "==5.1.1" }, "argh": { "hashes": [ - "sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3", - "sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65" + "sha256:00c9027f6f461bcf24afe599a281bbda5cbd5dee4b6705befbea293a4ca7d221", + "sha256:58ce3aeba09e45e7f7522b07c441eab19a005009d802d930ae7be785a2d1a76e" ], "index": "pypi", - "version": "==0.26.2" + "version": "==0.27.2" + }, + "async-timeout": { + "hashes": [ + "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", + "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" + ], + "markers": "python_full_version <= '3.11.2'", + "version": "==4.0.3" + }, + "asynctest": { + "hashes": [ + "sha256:5da6118a7e6d6b54d83a8f7197769d046922a44d2a99c21382f0a6e4fadae676", + "sha256:c27862842d15d83e6a34eb0b2866c323880eb3a75e4485b079ea11748fd77fac" + ], + "markers": "python_version < '3.8'", + "version": "==0.13.0" + }, + "attrs": { + "hashes": [ + "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04", + "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015" + ], + "markers": "python_version >= '3.7'", + "version": "==23.1.0" }, "bcbio-gff": { "hashes": [ - "sha256:34dfa970e14f4533dc63c0a5512b7b5221e4a06449e6aaa344162ed5fdd7a1de" + "sha256:9f1bc9629ef1be13e713971c208223e1812ba1a6119979e9ce80b25212120d65", + "sha256:f7b3922ee274106f8716703f41f05a1795aa9d73e903f4e481995ed8f5f65d2d" ], "index": "pypi", - "version": "==0.6.9" + "version": "==0.7.0" }, "billiard": { "hashes": [ @@ -46,55 +172,50 @@ }, "bioblend": { "hashes": [ - "sha256:057450d39054cf91fff31e9025f269eb08e1ef1b437d71dfc73957e7cb0d8195", - "sha256:814312e3583a4cbb4ffaa1fb103107d9a24c069604abf51c670251fdc8bf094a" + "sha256:14d2d932ddabba47b88a0e030a0972a1287a1a051a9e555c1966964ef0a15cd5", + "sha256:90be67c5e0dbdb1235fd9a8cb463b5ded1c6a2d6a8303913649068973d037903" ], "index": "pypi", - "version": "==0.16.0" + "markers": "python_version >= '3.7'", + "version": "==1.2.0" }, "biopython": { "hashes": [ - "sha256:03ee5c72b3cc3f0675a8c22ce1c45fe99a32a60db18df059df479ae6cf619708", - "sha256:155c5b95857bca7ebd607210cb9d8ea459bb0b86b3ca37ea44ec47c26ede7e9a", - "sha256:2dbb4388c75b5dfca8ce729e791f465c9c878dbd7ba2ab9a1f9854609d2b5426", - "sha256:365569543ea58dd07ef205ec351c23b6c1a3200d5d321eb28ceaecd55eb5955e", - "sha256:4b3d4eec2e348c3d97a7fde80ee0f2b8ebeed849d2bd64a616833a9be03b93c8", - "sha256:4be31815226052d86d4c2f6a103c40504e34bba3e25cc1b1d687a3203c42fb6e", - "sha256:51eb467a60c38820ad1e6c3a7d4cb10535606f559646e824cc65c96091d91ff7", - "sha256:5ae69c5e09769390643aa0f8064517665df6fb99c37433821d6664584d0ecb8c", - "sha256:72a1477cf1701964c7224e506a54fd65d1cc5228da200b634a17992230aa1cbd", - "sha256:76988ed3d7383d566db1d7fc69c9cf136c6275813fb749fc6753c340f81f1a8f", - "sha256:83bfea8a19f9352c47b13965c4b73853e7aeef3c5aed8489895b0679e32c621b", - "sha256:884a2b99ac7820cb84f70089769a512e3238ee60438b8c934ed519613dc570ce", - "sha256:8f33dafd3c7254fff5e1684b965e45a7c08d9b8e1bf51562b0a521ff9a6f5ea0", - "sha256:947b793e804c59ea45ae46945a57612ad1789ca87af4af0d6a62dcecf3a6246a", - "sha256:9580978803b582e0612b71673cab289e6bf261a865009cfb9501d65bc726a76e", - "sha256:98deacc30b8654cfcdcf707d93fa4e3c8717bbda07c3f9f828cf84753d4a1e4d", - "sha256:aa23a83a220486af6193760d079b36543fe00afcfbd18280ca2fd0b2c1c8dd6d", - "sha256:ab93d5749b375be3682866b3a606aa2ebd3e6d868079793925bf4fbb0987cf1f", - "sha256:b3ab26f26a1956ef26303386510d84e917e31fcbbc94918c336da0163ef628df", - "sha256:bf634a56f449a4123e48e538d661948e5ac29fb452acd2962b8cb834b472a9d7", - "sha256:ceab668be9cbdcddef55ad459f87acd0316ae4a00d32251fea4cf665f5062fda", - "sha256:d9f6ce961e0c380e2a5435f64c96421dbcebeab6a1b41506bd81251feb733c08", - "sha256:e921571b51514a6d35944242d6fef6427c3998acf58940fe1f209ac8a92a6e87", - "sha256:edb07eac99d3b8abd7ba56ff4bedec9263f76dfc3c3f450e7d2e2bcdecf8559b", - "sha256:f0a7e1d94a318f74974345fd0987ec389b16988ec484e67218e900b116b932a8" + "sha256:11d673698b3d0d6589292ea951fb62cb24ea27d273eca0d08dbbd956690f97f5", + "sha256:2cf38112b6d8415ad39d6a611988cd11fb5f33eb09346666a87263beba9614e0", + "sha256:2f9cfaf16d55ab80d514e7aebe5710dabe4e4ff47ede851031202e33b3249da3", + "sha256:35506e39822c52d11cf09a3951e82375ca1bb9303960b4286acf02c9a6f6c4cc", + "sha256:3b36ba1bf6395c09a365c53530c9d71f3617763fa2c1d452b3d8948368c0f1de", + "sha256:655df416936662c0c8a06a549cb25e1560e1fea5067d850f34fb714b8a3fae6c", + "sha256:65b93b513ce9dd7b2ce058720eadf42cd03f312db3409356efeb93123d1320aa", + "sha256:6ebfbce0d91796c7aef422ee9dffe8827e07e5abaa94545e006f1f20e965c80b", + "sha256:762c6c43a8486b5fcd07f136a3217b87d24755618b9ea9da1f17124ff44c2ad6", + "sha256:793c42a376cd63f62f8a088ce39b7dc6b5c55e4e9031d887c434de1595bfa4b8", + "sha256:7a168709694e10b338718c18d967edd5b56c237dc88642c22275796007a70000", + "sha256:7c5c07123ff5f44c9e6b5369df854a38afd3c0c50ef58498a0ae8f7eb799f3e8", + "sha256:811796f8d222aa3869a50e31e54ce62b69106b47cd8bb06934867c0d843297b5", + "sha256:8bb0c690c7368f255ed45236bf0f5464b476b8c083c8f634533921af78278261", + "sha256:919a2c583cabf9c96d2ae4e1245a6b0376932fb342aca302a0fc198b71ab3275", + "sha256:97cbdbed01b2512471f36c74b91658d1dfbdcbf39bc038f6ce5a41c3e60a8fc6", + "sha256:9ba33244f0eff830beaa7240065bdb5095d96fded6599b76bbb9ddab45cd2bbd", + "sha256:a51d9c1d1b4b634447535da74a644fae59bc234fbbf9001e2dc6b6fbabb98019", + "sha256:b09efcb4733c8770f25eab5fe555a96a08f5ab9e1bc36939e08ebf2ffbf3e0f1", + "sha256:b37c0d24191e5c96ca02415a5188551980c83a0d518bbc4ffe3c9a5d1fe0ee81", + "sha256:ccd729249fd5f586dd4c2a3507c2ea2456825d7e615e97c07c409c850eaf4594", + "sha256:e41b55edcfd448630e77bf4de66a7235324a8a149621499891da6bd1d5085b9a", + "sha256:ee51bb1cd7decffd24da6b76d5e01b7e2fd818ab85cf0c180226cbb5793a3abd", + "sha256:ef7c79b65b0b3f3c7dc59e20a7f8ae5758d8e852cb8b9cace590dc5617e348ba" ], "index": "pypi", - "version": "==1.79" + "markers": "python_version >= '3.7'", + "version": "==1.81" }, "blinker": { "hashes": [ - "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" + "sha256:152090d27c1c5c722ee7e48504b02d76502811ce02e1523553b4cf8c8b3d3a8d", + "sha256:296320d6c28b006eb5e32d4712202dbcdcbf5dc482da298c2f44881c43884aaa" ], - "version": "==1.4" - }, - "boto": { - "hashes": [ - "sha256:147758d41ae7240dc989f0039f27da8ca0d53734be0eb869ef16e3adcfa462e8", - "sha256:ea0d3b40a2d852767be77ca343b58a9e3a4b00d9db440efb8da74b4e58025e5a" - ], - "version": "==2.49.0" + "version": "==1.6.3" }, "cached-property": { "hashes": [ @@ -110,22 +231,112 @@ "sha256:f4efebe6f8629b0da2b8e529424de376494f5b7a743c321c8a2ddc2b1414921c" ], "index": "pypi", + "markers": "python_version >= '3.6'", "version": "==5.0.5" }, "certifi": { "hashes": [ - "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], - "version": "==2021.10.8" + "markers": "python_version >= '3.6'", + "version": "==2023.7.22" }, "charset-normalizer": { "hashes": [ - "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721", - "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c" - ], - "markers": "python_version >= '3'", - "version": "==2.0.9" + "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843", + "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786", + "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e", + "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8", + "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4", + "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa", + "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d", + "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82", + "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7", + "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895", + "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d", + "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a", + "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382", + "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678", + "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b", + "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e", + "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741", + "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4", + "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596", + "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9", + "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69", + "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c", + "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77", + "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13", + "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459", + "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e", + "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7", + "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908", + "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a", + "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f", + "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8", + "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482", + "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d", + "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d", + "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545", + "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34", + "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86", + "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6", + "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe", + "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e", + "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc", + "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7", + "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd", + "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c", + "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557", + "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a", + "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89", + "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078", + "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e", + "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4", + "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403", + "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0", + "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89", + "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115", + "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9", + "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05", + "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a", + "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec", + "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56", + "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38", + "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479", + "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c", + "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e", + "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd", + "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186", + "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455", + "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c", + "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65", + "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78", + "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287", + "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df", + "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43", + "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1", + "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7", + "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989", + "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a", + "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63", + "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884", + "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649", + "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810", + "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828", + "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4", + "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2", + "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd", + "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5", + "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe", + "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293", + "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e", + "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e", + "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.0" }, "click": { "hashes": [ @@ -152,34 +363,29 @@ }, "click-repl": { "hashes": [ - "sha256:94b3fbbc9406a236f176e0506524b2937e4b23b6f4c0c0b2a0a83f8a64e9194b", - "sha256:cd12f68d745bf6151210790540b4cb064c7b13e571bc64b6957d98d120dacfd8" + "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9", + "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812" ], - "version": "==0.2.0" + "markers": "python_version >= '3.6'", + "version": "==0.3.0" }, "configparser": { "hashes": [ - "sha256:1b35798fdf1713f1c3139016cfcbc461f09edbf099d1fb658d4b7479fcaa3daa", - "sha256:e8b39238fb6f0153a069aa253d349467c3c4737934f253ef6abac5fe0eca1e5d" + "sha256:8be267824b541c09b08db124917f48ab525a6c3e837011f3130781a224c57090", + "sha256:b065779fd93c6bf4cee42202fa4351b4bb842e96a3fb469440e484517a49b9fa" ], "index": "pypi", - "version": "==5.2.0" + "markers": "python_version >= '3.7'", + "version": "==5.3.0" }, "deepdiff": { "hashes": [ - "sha256:e3f1c3a375c7ea5ca69dba6f7920f9368658318ff1d8a496293c79481f48e649", - "sha256:ef3410ca31e059a9d10edfdff552245829835b3ecd03212dc5b533d45a6c3f57" + "sha256:75c75b1511f0e48edef2b70d785a9c32b2631666b465fa8c32270a77a7b950b5", + "sha256:891b3cb12837e5d376ac0b58f4c8a2764e3a8bbceabb7108ff82235f1f2c4460" ], "index": "pypi", - "version": "==5.6.0" - }, - "deprecated": { - "hashes": [ - "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d", - "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.2.13" + "markers": "python_version >= '3.7'", + "version": "==6.6.1" }, "flask": { "hashes": [ @@ -187,6 +393,7 @@ "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22" ], "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.1.4" }, "flask-reverse-proxy-fix": { @@ -197,52 +404,141 @@ "index": "pypi", "version": "==0.2.1" }, + "frozenlist": { + "hashes": [ + "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c", + "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f", + "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a", + "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784", + "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27", + "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d", + "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3", + "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678", + "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a", + "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483", + "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8", + "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf", + "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99", + "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c", + "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48", + "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5", + "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56", + "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e", + "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1", + "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401", + "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4", + "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e", + "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649", + "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a", + "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d", + "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0", + "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6", + "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d", + "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b", + "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6", + "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf", + "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef", + "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7", + "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842", + "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba", + "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420", + "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b", + "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d", + "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332", + "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936", + "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816", + "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91", + "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420", + "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448", + "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411", + "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4", + "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32", + "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b", + "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0", + "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530", + "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669", + "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7", + "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1", + "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5", + "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce", + "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4", + "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e", + "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2", + "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d", + "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9", + "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642", + "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0", + "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703", + "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb", + "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1", + "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13", + "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab", + "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38", + "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb", + "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb", + "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81", + "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8", + "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd", + "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4" + ], + "markers": "python_version >= '3.7'", + "version": "==1.3.3" + }, + "future": { + "hashes": [ + "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307" + ], + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2'", + "version": "==0.18.3" + }, "gitdb": { "hashes": [ - "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd", - "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa" + "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4", + "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b" ], - "markers": "python_version >= '3.6'", - "version": "==4.0.9" + "markers": "python_version >= '3.7'", + "version": "==4.0.11" }, "gitpython": { "hashes": [ - "sha256:dc0a7f2f697657acc8d7f89033e8b1ea94dd90356b2983bca89dc8d2ab3cc647", - "sha256:df83fdf5e684fef7c6ee2c02fc68a5ceb7e7e759d08b694088d0cacb4eba59e5" + "sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4", + "sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a" ], "index": "pypi", - "version": "==3.1.24" + "markers": "python_version >= '3.7'", + "version": "==3.1.40" }, "gunicorn": { "hashes": [ - "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", - "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" + "sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0", + "sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033" ], "index": "pypi", - "version": "==20.1.0" + "markers": "python_version >= '3.5'", + "version": "==21.2.0" }, "idna": { "hashes": [ - "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", - "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" ], - "markers": "python_version >= '3'", - "version": "==3.3" + "markers": "python_version >= '3.5'", + "version": "==3.4" }, "importlib-metadata": { "hashes": [ - "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100", - "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb" + "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116", + "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d" ], - "markers": "python_version < '3.8'", - "version": "==4.8.2" + "markers": "python_version >= '3.7' and python_version < '3.8'", + "version": "==4.13.0" }, "isodate": { "hashes": [ - "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8", - "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81" + "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96", + "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9" ], - "version": "==0.6.0" + "version": "==0.6.1" }, "itsdangerous": { "hashes": [ @@ -262,11 +558,11 @@ }, "kombu": { "hashes": [ - "sha256:0f5d0763fb916808f617b886697b2be28e6bc35026f08e679697fc814b48a608", - "sha256:d36f0cde6a18d9eb7b6b3aa62a59bfdff7f5724689850e447eca5be8efc9d501" + "sha256:37cee3ee725f94ea8bb173eaab7c1760203ea53bbebae226328600f9d2799610", + "sha256:8b213b24293d3417bcf0d2f5537b7f756079e3ea232a8386dcc89a59fd2361a4" ], "markers": "python_version >= '3.7'", - "version": "==5.2.2" + "version": "==5.2.4" }, "markupsafe": { "hashes": [ @@ -340,132 +636,215 @@ "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" ], + "index": "pypi", "markers": "python_version >= '3.6'", "version": "==2.0.1" }, + "multidict": { + "hashes": [ + "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9", + "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8", + "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03", + "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710", + "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161", + "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664", + "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569", + "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067", + "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313", + "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706", + "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2", + "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636", + "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49", + "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93", + "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603", + "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0", + "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60", + "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4", + "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e", + "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1", + "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60", + "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951", + "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc", + "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe", + "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95", + "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d", + "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8", + "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed", + "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2", + "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775", + "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87", + "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c", + "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2", + "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98", + "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3", + "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe", + "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78", + "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660", + "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176", + "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e", + "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988", + "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c", + "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c", + "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0", + "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449", + "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f", + "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde", + "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5", + "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d", + "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac", + "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a", + "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9", + "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca", + "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11", + "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35", + "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063", + "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b", + "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982", + "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258", + "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1", + "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52", + "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480", + "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7", + "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461", + "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d", + "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc", + "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779", + "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a", + "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547", + "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0", + "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171", + "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf", + "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d", + "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba" + ], + "markers": "python_version >= '3.7'", + "version": "==6.0.4" + }, "numpy": { "hashes": [ - "sha256:0b78ecfa070460104934e2caf51694ccd00f37d5e5dbe76f021b1b0b0d221823", - "sha256:1247ef28387b7bb7f21caf2dbe4767f4f4175df44d30604d42ad9bd701ebb31f", - "sha256:1403b4e2181fc72664737d848b60e65150f272fe5a1c1cbc16145ed43884065a", - "sha256:170b2a0805c6891ca78c1d96ee72e4c3ed1ae0a992c75444b6ab20ff038ba2cd", - "sha256:2e4ed57f45f0aa38beca2a03b6532e70e548faf2debbeb3291cfc9b315d9be8f", - "sha256:32fe5b12061f6446adcbb32cf4060a14741f9c21e15aaee59a207b6ce6423469", - "sha256:34f3456f530ae8b44231c63082c8899fe9c983fd9b108c997c4b1c8c2d435333", - "sha256:4c9c23158b87ed0e70d9a50c67e5c0b3f75bcf2581a8e34668d4e9d7474d76c6", - "sha256:5d95668e727c75b3f5088ec7700e260f90ec83f488e4c0aaccb941148b2cd377", - "sha256:615d4e328af7204c13ae3d4df7615a13ff60a49cb0d9106fde07f541207883ca", - "sha256:69077388c5a4b997442b843dbdc3a85b420fb693ec8e33020bb24d647c164fa5", - "sha256:74b85a17528ca60cf98381a5e779fc0264b4a88b46025e6bcbe9621f46bb3e63", - "sha256:81225e58ef5fce7f1d80399575576fc5febec79a8a2742e8ef86d7b03beef49f", - "sha256:8890b3360f345e8360133bc078d2dacc2843b6ee6059b568781b15b97acbe39f", - "sha256:92aafa03da8658609f59f18722b88f0a73a249101169e28415b4fa148caf7e41", - "sha256:9864424631775b0c052f3bd98bc2712d131b3e2cd95d1c0c68b91709170890b0", - "sha256:9e6f5f50d1eff2f2f752b3089a118aee1ea0da63d56c44f3865681009b0af162", - "sha256:a3deb31bc84f2b42584b8c4001c85d1934dbfb4030827110bc36bfd11509b7bf", - "sha256:ad010846cdffe7ec27e3f933397f8a8d6c801a48634f419e3d075db27acf5880", - "sha256:b1e2312f5b8843a3e4e8224b2b48fe16119617b8fc0a54df8f50098721b5bed2", - "sha256:bc988afcea53e6156546e5b2885b7efab089570783d9d82caf1cfd323b0bb3dd", - "sha256:c449eb870616a7b62e097982c622d2577b3dbc800aaf8689254ec6e0197cbf1e", - "sha256:c74c699b122918a6c4611285cc2cad4a3aafdb135c22a16ec483340ef97d573c", - "sha256:c885bfc07f77e8fee3dc879152ba993732601f1f11de248d4f357f0ffea6a6d4", - "sha256:e3c3e990274444031482a31280bf48674441e0a5b55ddb168f3a6db3e0c38ec8", - "sha256:e4799be6a2d7d3c33699a6f77201836ac975b2e1b98c2a07f66a38f499cb50ce", - "sha256:e6c76a87633aa3fa16614b61ccedfae45b91df2767cf097aa9c933932a7ed1e0", - "sha256:e89717274b41ebd568cd7943fc9418eeb49b1785b66031bc8a7f6300463c5898", - "sha256:f5162ec777ba7138906c9c274353ece5603646c6965570d82905546579573f73", - "sha256:fde96af889262e85aa033f8ee1d3241e32bf36228318a61f1ace579df4e8170d" + "sha256:1dbe1c91269f880e364526649a52eff93ac30035507ae980d2fed33aaee633ac", + "sha256:357768c2e4451ac241465157a3e929b265dfac85d9214074985b1786244f2ef3", + "sha256:3820724272f9913b597ccd13a467cc492a0da6b05df26ea09e78b171a0bb9da6", + "sha256:4391bd07606be175aafd267ef9bea87cf1b8210c787666ce82073b05f202add1", + "sha256:4aa48afdce4660b0076a00d80afa54e8a97cd49f457d68a4342d188a09451c1a", + "sha256:58459d3bad03343ac4b1b42ed14d571b8743dc80ccbf27444f266729df1d6f5b", + "sha256:5c3c8def4230e1b959671eb959083661b4a0d2e9af93ee339c7dada6759a9470", + "sha256:5f30427731561ce75d7048ac254dbe47a2ba576229250fb60f0fb74db96501a1", + "sha256:643843bcc1c50526b3a71cd2ee561cf0d8773f062c8cbaf9ffac9fdf573f83ab", + "sha256:67c261d6c0a9981820c3a149d255a76918278a6b03b6a036800359aba1256d46", + "sha256:67f21981ba2f9d7ba9ade60c9e8cbaa8cf8e9ae51673934480e45cf55e953673", + "sha256:6aaf96c7f8cebc220cdfc03f1d5a31952f027dda050e5a703a0d1c396075e3e7", + "sha256:7c4068a8c44014b2d55f3c3f574c376b2494ca9cc73d2f1bd692382b6dffe3db", + "sha256:7c7e5fa88d9ff656e067876e4736379cc962d185d5cd808014a8a928d529ef4e", + "sha256:7f5ae4f304257569ef3b948810816bc87c9146e8c446053539947eedeaa32786", + "sha256:82691fda7c3f77c90e62da69ae60b5ac08e87e775b09813559f8901a88266552", + "sha256:8737609c3bbdd48e380d463134a35ffad3b22dc56295eff6f79fd85bd0eeeb25", + "sha256:9f411b2c3f3d76bba0865b35a425157c5dcf54937f82bbeb3d3c180789dd66a6", + "sha256:a6be4cb0ef3b8c9250c19cc122267263093eee7edd4e3fa75395dfda8c17a8e2", + "sha256:bcb238c9c96c00d3085b264e5c1a1207672577b93fa666c3b14a45240b14123a", + "sha256:bf2ec4b75d0e9356edea834d1de42b31fe11f726a81dfb2c2112bc1eaa508fcf", + "sha256:d136337ae3cc69aa5e447e78d8e1514be8c3ec9b54264e680cf0b4bd9011574f", + "sha256:d4bf4d43077db55589ffc9009c0ba0a94fa4908b9586d6ccce2e0b164c86303c", + "sha256:d6a96eef20f639e6a97d23e57dd0c1b1069a7b4fd7027482a4c5c451cd7732f4", + "sha256:d9caa9d5e682102453d96a0ee10c7241b72859b01a941a397fd965f23b3e016b", + "sha256:dd1c8f6bd65d07d3810b90d02eba7997e32abbdf1277a481d698969e921a3be0", + "sha256:e31f0bb5928b793169b87e3d1e070f2342b22d5245c755e2b81caa29756246c3", + "sha256:ecb55251139706669fdec2ff073c98ef8e9a84473e51e716211b41aa0f18e656", + "sha256:ee5ec40fdd06d62fe5d4084bef4fd50fd4bb6bfd2bf519365f569dc470163ab0", + "sha256:f17e562de9edf691a42ddb1eb4a5541c20dd3f9e65b09ded2beb0799c0cf29bb", + "sha256:fdffbfb6832cd0b300995a2b08b8f6fa9f6e856d562800fea9182316d99c4e8e" ], "markers": "python_version < '3.11' and python_version >= '3.7'", - "version": "==1.21.4" + "version": "==1.21.6" }, "ordered-set": { "hashes": [ - "sha256:ba93b2df055bca202116ec44b9bead3df33ea63a7d5827ff8e16738b97f33a95" + "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562", + "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8" ], - "markers": "python_version >= '3.5'", - "version": "==4.0.2" + "markers": "python_version >= '3.7'", + "version": "==4.1.0" + }, + "packaging": { + "hashes": [ + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" + ], + "markers": "python_version >= '3.7'", + "version": "==23.2" }, "prompt-toolkit": { "hashes": [ - "sha256:5f29d62cb7a0ecacfa3d8ceea05a63cd22500543472d64298fc06ddda906b25d", - "sha256:7053aba00895473cb357819358ef33f11aa97e4ac83d38efb123e5649ceeecaf" + "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac", + "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88" ], - "markers": "python_full_version >= '3.6.2'", - "version": "==3.0.23" + "markers": "python_full_version >= '3.7.0'", + "version": "==3.0.39" }, "pyasn1": { "hashes": [ - "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", - "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", - "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", - "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", - "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", - "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", - "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", - "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", - "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", - "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", - "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", - "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", - "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" - ], - "version": "==0.4.8" + "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57", + "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==0.5.0" }, "pyasn1-modules": { "hashes": [ - "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", - "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199", - "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811", - "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed", - "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", - "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", - "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", - "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", - "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", - "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", - "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", - "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d", - "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405" + "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c", + "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d" ], - "version": "==0.2.8" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==0.3.0" }, "pybedtools": { "hashes": [ - "sha256:a184a36099458627e7ef52ea88218f7c00dc9c505b4256ece9ede58b1efa8771" + "sha256:586a626895b1b7215aef877e985c03fd8a908fd6c636e5b9ff8a1a1d09a1d514" ], "index": "pypi", - "version": "==0.8.2" + "version": "==0.9.1" }, "pyparsing": { "hashes": [ - "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", - "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" + "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb", + "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.6" + "markers": "python_full_version >= '3.6.8'", + "version": "==3.1.1" }, "pysam": { "hashes": [ - "sha256:0cfa16f76ed3c3119c7b3c8dfdcba9e010fbcdcf87eaa165351bb369da5a6bf1", - "sha256:1d6d49a0b3c626fae410a93d4c80583a8b5ddaacc9b46a080b250dbcebd30a59", - "sha256:2717509556fecddf7c73966fa62066c6a59a7d39b755d8972afa8d143a1d5aa5", - "sha256:493988420db16e6ee03393518e4d272df05f0a35780248c08c61da7411e520e7", - "sha256:7a8a25fceaaa96e5b4c8b0a7fd6bb0b20b6c262dc4cc867c6d1467ac990f1d77", - "sha256:7ea2e019294e4bf25e4892b5de69c43f54fb6ac42b681265268aa322e1f36f5b", - "sha256:7f6a4ec58ad7995b791a71bf35f673ea794e734c587ea7329fca5cce9c53a7af", - "sha256:9422c2d0b581c3d24f247c15bb8981569e636003c4d6cad39ccd1bf205a79f2c", - "sha256:a88f875114bd3d8efb7fade80e0640094383ec5043861aa575175fa9a56edf90", - "sha256:c90341434e7a99439174aa64ca5406f63528be4217d4401fb30ec4ea4629c559", - "sha256:ca0c9289dfdc5e1a81bccdb8305192cd14cf9730bd21320ceca949fde071a572", - "sha256:cfb162358c5284b31b2b88b10947e0f1013da2d85ba0fd0b5723dd142c15329e", - "sha256:cfffad99cf3968cf85aadb70a8a02303f9172ea21abe02d587c44f808c504f52", - "sha256:e13e496da3a432db24f424439834b0ab5f40700a3db6e610d06f8bd639d9fd2d", - "sha256:ef5d8ad01cac8974cd09832c226cbb63a3f7c5bd63727d8e59447021ee16a186", - "sha256:f5a23a5dcf32f01c66d44e89113fa8f7522997ea43fbc0f98e5250a907911a5f" + "sha256:021fbf6874ad998aba19be33828ad9d23d52273643793488ac4b12917d714c68", + "sha256:116278a7caa122b2b8acc56d13b3599be9b1236f27a12488bffc306858ff0d57", + "sha256:1b84f99aa04e30bd1cc35c01bd41c2b7680131f56c71a740805aff8086f24b56", + "sha256:26199e403855b9da45341d25682e0df27013687d9cb1b4fd328136fbd506292b", + "sha256:32042e0bf3c5dd8554769442c2e1f7b6ada902c33ee44c616d0403e7acd12ee3", + "sha256:34f5653a82138d28a8e86205785a0398eb6c89f776b4145ff42783168757323c", + "sha256:4779a99d1ece17a98724d87a5c10c455cf212b3baa3a8399d3d072e4d0ae5ba0", + "sha256:481e4efbfbc07b6b92194a005cb9a98006c8378024f41c7b66c58b14f6e77f9c", + "sha256:4f6657a09c81333adb5545cf9a20d4c2ca1686acf8609ad58f13b3ec1b52a9cf", + "sha256:6d6aa2346b11ad35e88c65eb0067321318c25c7f35f75c98061173eabefcf8b0", + "sha256:6ffe5c98725fea54b1b2aa8f14a60ee9ceaed32c04460d1b861a62603dcd7153", + "sha256:83776ba587eb9575a209efed1cedb49d69c5fa6cc520dd722a0a09d0bb4e9b87", + "sha256:87dbf72f3e61fd6d3f92b1b683d9a9e797b6cc213ffcd971899f24a16f9f6e8f", + "sha256:93eb12be3822fb387e5438811f62a0f5e56c1edd5c830aaa316fb50d3d0bc181", + "sha256:942dd4a2263996bc2daa21200886e9fde027f32ce8820e7832b20bbdb97eb393", + "sha256:9af1cd3d07fd4c84e9b3d8a46c65b25f95278185bc6d44c4a48951679d5189ac", + "sha256:9b8e18520e7a79bad91b44cf9199c7fa42cec5c3020024d7ef9a7161d0099bf8", + "sha256:9ba53f9b0b2c5cb57908855cdb35a31b34c5211d215aa01bdb3e9b3d05c659cc", + "sha256:9bfebf89b1dc2ff6f88d64b5f05d8630deb89562b22764f8ee7f6fa9e677bb91", + "sha256:9d3ebb1515c2fd9b11823469e5b211ca3cc89e976c00c284a2190804c9f11726", + "sha256:a98d1ddca64943f3ead507721e52466aea2f7303e549d4960a2eb1d9fff8e3d7", + "sha256:ab7a46973cf0ab8c6ac327f4c3fb67698d7ccbeef8631a716898c6ba01ef3e45", + "sha256:bb61bf30c15f6767403b423b04c293e96fd7635457b506c849aafcf48fc13242", + "sha256:cfd2b858c7405cf38c730cba779ddf9f8cff28b4842c6440e64781650dcb9a52", + "sha256:da2f1af461e44d5c2c7210d458ee216f8ab98486adf1eea6c88eea5c1058a62f", + "sha256:f23b2f47528b94e8abe3b700103fb1214c623ae1c1b8125ecf22d4d33d76720f", + "sha256:f73d7923c89618fb7024875ed8eddc5fb0c911f430e3495de482fcee48143e45" ], "index": "pypi", - "version": "==0.18.0" + "markers": "python_version >= '3.6'", + "version": "==0.22.0" }, "python-dateutil": { "hashes": [ @@ -473,182 +852,142 @@ "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.8.2" }, "python-ldap": { "hashes": [ - "sha256:60464c8fc25e71e0fd40449a24eae482dcd0fb7fcf823e7de627a6525b3e0d12" + "sha256:ab26c519a0ef2a443a2a10391fa3c5cb52d7871323399db949ebfaa9f25ee2a0" ], "index": "pypi", - "version": "==3.4.0" + "markers": "python_version >= '3.6'", + "version": "==3.4.3" }, "python-magic": { "hashes": [ - "sha256:4fec8ee805fea30c07afccd1592c0f17977089895bdfaae5fec870a84e997626", - "sha256:de800df9fb50f8ec5974761054a708af6e4246b03b4bdaee993f948947b0ebcf" + "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b", + "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3" ], "index": "pypi", - "version": "==0.4.24" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==0.4.27" }, "pytz": { "hashes": [ - "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c", - "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326" - ], - "version": "==2021.3" - }, - "pyyaml": { - "hashes": [ - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", + "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7" ], - "markers": "python_version >= '3.6'", - "version": "==6.0" + "version": "==2023.3.post1" }, "rdflib": { "hashes": [ - "sha256:6136ae056001474ee2aff5fc5b956e62a11c3a9c66bb0f3d9c0aaa5fbb56854e", - "sha256:b7642daac8cdad1ba157fecb236f5d1b2aa1de64e714dcee80d65e2b794d88a6" + "sha256:36b4e74a32aa1e4fa7b8719876fb192f19ecd45ff932ea5ebbd2e417a0247e63", + "sha256:72af591ff704f4caacea7ecc0c5a9056b8553e0489dd4f35a9bc52dbd41522e0" ], "index": "pypi", - "version": "==6.0.2" + "markers": "python_version >= '3.7' and python_version < '4.0'", + "version": "==6.3.2" }, "redis": { "hashes": [ - "sha256:c8481cf414474e3497ec7971a1ba9b998c8efad0f0d289a009a5bbef040894f9", - "sha256:ccf692811f2c1fc7a92b466aa2599e4a6d2d73d5f736a2c70be600657c0da34a" + "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f", + "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f" ], "index": "pypi", - "version": "==4.0.2" + "markers": "python_version >= '3.7'", + "version": "==5.0.1" }, "requests": { "hashes": [ - "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", - "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], "index": "pypi", - "version": "==2.26.0" + "markers": "python_version >= '3.7'", + "version": "==2.31.0" }, "requests-toolbelt": { "hashes": [ - "sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f", - "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0" + "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", + "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" ], - "version": "==0.9.1" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.0.0" }, "sentry-sdk": { "extras": [ "flask" ], "hashes": [ - "sha256:0db297ab32e095705c20f742c3a5dac62fe15c4318681884053d0898e5abb2f6", - "sha256:789a11a87ca02491896e121efdd64e8fd93327b69e8f2f7d42f03e2569648e88" - ], - "index": "pypi", - "version": "==1.5.0" - }, - "setuptools": { - "hashes": [ - "sha256:6d10741ff20b89cd8c6a536ee9dc90d3002dec0226c78fb98605bfb9ef8a7adf", - "sha256:d144f85102f999444d06f9c0e8c737fd0194f10f2f7e5fdb77573f6e2fa4fad0" - ], - "markers": "python_version >= '3.6'", - "version": "==59.5.0" - }, - "setuptools": { - "hashes": [ - "sha256:b4c634615a0cf5b02cf83c7bedffc8da0ca439f00e79452699454da6fbd4153d", - "sha256:feb5ff19b354cde9efd2344ef6d5e79880ce4be643037641b49508bbb850d060" + "sha256:935e8fbd7787a3702457393b74b13d89a5afb67185bc0af85c00cb27cbd42e7c", + "sha256:eeb0b3550536f3bbc05bb1c7e0feb3a78d74acb43b607159a606ed2ec0a33a4d" ], - "markers": "python_version >= '3.6'", - "version": "==59.4.0" + "version": "==1.32.0" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "smmap": { "hashes": [ - "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94", - "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936" + "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62", + "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da" ], - "markers": "python_version >= '3.6'", - "version": "==5.0.0" + "markers": "python_version >= '3.7'", + "version": "==5.0.1" }, "sparqlwrapper": { "hashes": [ - "sha256:17ec44b08b8ae2888c801066249f74fe328eec25d90203ce7eadaf82e64484c7", - "sha256:357ee8a27bc910ea13d77836dbddd0b914991495b8cc1bf70676578155e962a8", - "sha256:8cf6c21126ed76edc85c5c232fd6f77b9f61f8ad1db90a7147cdde2104aff145", - "sha256:c7f9c9d8ebb13428771bc3b6dee54197422507dcc3dea34e30d5dcfc53478dec", - "sha256:d6a66b5b8cda141660e07aeb00472db077a98d22cb588c973209c7336850fb3c" + "sha256:3fed3ebcc77617a4a74d2644b86fd88e0f32e7f7003ac7b2b334c026201731f1", + "sha256:c99a7204fff676ee28e6acef327dc1ff8451c6f7217dcd8d49e8872f324a8a20" ], "index": "pypi", - "version": "==1.8.5" + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, + "tinydb": { + "hashes": [ + "sha256:30c06d12383d7c332e404ca6a6103fb2b32cbf25712689648c39d9a6bd34bd3d", + "sha256:6dd686a9c5a75dfa9280088fd79a419aefe19cd7f4bd85eba203540ef856d564" + ], + "markers": "python_version >= '3.7' and python_version < '4.0'", + "version": "==4.8.0" }, "tld": { "hashes": [ - "sha256:266106ad9035f54cd5cce5f823911a51f697e7c58cb45bfbd6c53b4c2976ece2", - "sha256:69fed19d26bb3f715366fb4af66fdeace896c55c052b00e8aaba3a7b63f3e7f0", - "sha256:826bbe61dccc8d63144b51caef83e1373fbaac6f9ada46fca7846021f5d36fef", - "sha256:843844e4256c943983d86366b5af3ac9cd1c9a0b6465f04d9f70e3b4c1a7989f", - "sha256:a92ac6b84917e7d9e934434b8d37e9be534598f138fbb86b3c0d5426f2621890", - "sha256:b6650f2d5392a49760064bc55d73ce3397a378ef24ded96efb516c6b8ec68c26", - "sha256:ef5b162d6fa295822dacd4fe4df1b62d8df2550795a97399a8905821b58d3702" + "sha256:93dde5e1c04bdf1844976eae440706379d21f4ab235b73c05d7483e074fb5629", + "sha256:f75b2be080f767ed17c2338a339eaa4fab5792586319ca819119da252f9f3749" ], "index": "pypi", - "version": "==0.12.6" + "markers": "python_version >= '3.7' and python_version < '4'", + "version": "==0.13" + }, + "tuspy": { + "hashes": [ + "sha256:09a4ef6e20b05c6f83c53c5839892ead141947afb2f6b7dea5cca45f8d120793", + "sha256:4c136bb97593367376e77f1d9580c1990bd535698f86765c80db9b9d3864f35f" + ], + "version": "==1.0.1" }, "typing-extensions": { "hashes": [ - "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", - "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" + "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", + "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2" ], - "markers": "python_version < '3.10'", - "version": "==4.0.1" + "markers": "python_version >= '3.7'", + "version": "==4.7.1" }, "urllib3": { "hashes": [ - "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", - "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" + "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", + "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'", - "version": "==1.26.7" + "markers": "python_version >= '3.6'", + "version": "==2.0.7" }, "validate-email": { "hashes": [ @@ -667,39 +1006,44 @@ }, "watchdog": { "hashes": [ - "sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685", - "sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04", - "sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb", - "sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542", - "sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6", - "sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b", - "sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660", - "sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3", - "sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923", - "sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7", - "sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b", - "sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669", - "sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2", - "sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3", - "sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604", - "sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8", - "sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5", - "sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0", - "sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6", - "sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65", - "sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d", - "sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15", - "sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9" + "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a", + "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100", + "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8", + "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc", + "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae", + "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41", + "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0", + "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f", + "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c", + "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9", + "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3", + "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709", + "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83", + "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759", + "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9", + "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3", + "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7", + "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f", + "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346", + "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674", + "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397", + "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96", + "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d", + "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a", + "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64", + "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44", + "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33" ], "index": "pypi", - "version": "==2.1.6" + "markers": "python_version >= '3.7'", + "version": "==3.0.0" }, "wcwidth": { "hashes": [ - "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784", - "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83" + "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704", + "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4" ], - "version": "==0.2.5" + "version": "==0.2.8" }, "werkzeug": { "hashes": [ @@ -707,97 +1051,202 @@ "sha256:b353856d37dec59d6511359f97f6a4b2468442e454bd1c98298ddce53cac1f04" ], "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.16.1" }, - "wrapt": { - "hashes": [ - "sha256:086218a72ec7d986a3eddb7707c8c4526d677c7b35e355875a0fe2918b059179", - "sha256:0877fe981fd76b183711d767500e6b3111378ed2043c145e21816ee589d91096", - "sha256:0a017a667d1f7411816e4bf214646d0ad5b1da2c1ea13dec6c162736ff25a374", - "sha256:0cb23d36ed03bf46b894cfec777eec754146d68429c30431c99ef28482b5c1df", - "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185", - "sha256:220a869982ea9023e163ba915077816ca439489de6d2c09089b219f4e11b6785", - "sha256:25b1b1d5df495d82be1c9d2fad408f7ce5ca8a38085e2da41bb63c914baadff7", - "sha256:2dded5496e8f1592ec27079b28b6ad2a1ef0b9296d270f77b8e4a3a796cf6909", - "sha256:2ebdde19cd3c8cdf8df3fc165bc7827334bc4e353465048b36f7deeae8ee0918", - "sha256:43e69ffe47e3609a6aec0fe723001c60c65305784d964f5007d5b4fb1bc6bf33", - "sha256:46f7f3af321a573fc0c3586612db4decb7eb37172af1bc6173d81f5b66c2e068", - "sha256:47f0a183743e7f71f29e4e21574ad3fa95676136f45b91afcf83f6a050914829", - "sha256:498e6217523111d07cd67e87a791f5e9ee769f9241fcf8a379696e25806965af", - "sha256:4b9c458732450ec42578b5642ac53e312092acf8c0bfce140ada5ca1ac556f79", - "sha256:51799ca950cfee9396a87f4a1240622ac38973b6df5ef7a41e7f0b98797099ce", - "sha256:5601f44a0f38fed36cc07db004f0eedeaadbdcec90e4e90509480e7e6060a5bc", - "sha256:5f223101f21cfd41deec8ce3889dc59f88a59b409db028c469c9b20cfeefbe36", - "sha256:610f5f83dd1e0ad40254c306f4764fcdc846641f120c3cf424ff57a19d5f7ade", - "sha256:6a03d9917aee887690aa3f1747ce634e610f6db6f6b332b35c2dd89412912bca", - "sha256:705e2af1f7be4707e49ced9153f8d72131090e52be9278b5dbb1498c749a1e32", - "sha256:766b32c762e07e26f50d8a3468e3b4228b3736c805018e4b0ec8cc01ecd88125", - "sha256:77416e6b17926d953b5c666a3cb718d5945df63ecf922af0ee576206d7033b5e", - "sha256:778fd096ee96890c10ce96187c76b3e99b2da44e08c9e24d5652f356873f6709", - "sha256:78dea98c81915bbf510eb6a3c9c24915e4660302937b9ae05a0947164248020f", - "sha256:7dd215e4e8514004c8d810a73e342c536547038fb130205ec4bba9f5de35d45b", - "sha256:7dde79d007cd6dfa65afe404766057c2409316135cb892be4b1c768e3f3a11cb", - "sha256:81bd7c90d28a4b2e1df135bfbd7c23aee3050078ca6441bead44c42483f9ebfb", - "sha256:85148f4225287b6a0665eef08a178c15097366d46b210574a658c1ff5b377489", - "sha256:865c0b50003616f05858b22174c40ffc27a38e67359fa1495605f96125f76640", - "sha256:87883690cae293541e08ba2da22cacaae0a092e0ed56bbba8d018cc486fbafbb", - "sha256:8aab36778fa9bba1a8f06a4919556f9f8c7b33102bd71b3ab307bb3fecb21851", - "sha256:8c73c1a2ec7c98d7eaded149f6d225a692caa1bd7b2401a14125446e9e90410d", - "sha256:936503cb0a6ed28dbfa87e8fcd0a56458822144e9d11a49ccee6d9a8adb2ac44", - "sha256:944b180f61f5e36c0634d3202ba8509b986b5fbaf57db3e94df11abee244ba13", - "sha256:96b81ae75591a795d8c90edc0bfaab44d3d41ffc1aae4d994c5aa21d9b8e19a2", - "sha256:981da26722bebb9247a0601e2922cedf8bb7a600e89c852d063313102de6f2cb", - "sha256:ae9de71eb60940e58207f8e71fe113c639da42adb02fb2bcbcaccc1ccecd092b", - "sha256:b73d4b78807bd299b38e4598b8e7bd34ed55d480160d2e7fdaabd9931afa65f9", - "sha256:d4a5f6146cfa5c7ba0134249665acd322a70d1ea61732723c7d3e8cc0fa80755", - "sha256:dd91006848eb55af2159375134d724032a2d1d13bcc6f81cd8d3ed9f2b8e846c", - "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a", - "sha256:e6906d6f48437dfd80464f7d7af1740eadc572b9f7a4301e7dd3d65db285cacf", - "sha256:e92d0d4fa68ea0c02d39f1e2f9cb5bc4b4a71e8c442207433d8db47ee79d7aa3", - "sha256:e94b7d9deaa4cc7bac9198a58a7240aaf87fe56c6277ee25fa5b3aa1edebd229", - "sha256:ea3e746e29d4000cd98d572f3ee2a6050a4f784bb536f4ac1f035987fc1ed83e", - "sha256:ec7e20258ecc5174029a0f391e1b948bf2906cd64c198a9b8b281b811cbc04de", - "sha256:ec9465dd69d5657b5d2fa6133b3e1e989ae27d29471a672416fd729b429eb554", - "sha256:f122ccd12fdc69628786d0c947bdd9cb2733be8f800d88b5a37c57f1f1d73c10", - "sha256:f99c0489258086308aad4ae57da9e8ecf9e1f3f30fa35d5e170b4d4896554d80", - "sha256:f9c51d9af9abb899bd34ace878fbec8bf357b3194a10c4e8e0a25512826ef056", - "sha256:fd76c47f20984b43d93de9a82011bb6e5f8325df6c9ed4d8310029a55fa361ea" + "yarl": { + "hashes": [ + "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571", + "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3", + "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3", + "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c", + "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7", + "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04", + "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191", + "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea", + "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4", + "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4", + "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095", + "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e", + "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74", + "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef", + "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33", + "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde", + "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45", + "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf", + "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b", + "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac", + "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0", + "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528", + "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716", + "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb", + "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18", + "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72", + "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6", + "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582", + "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5", + "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368", + "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc", + "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9", + "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be", + "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a", + "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80", + "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8", + "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6", + "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417", + "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574", + "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59", + "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608", + "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82", + "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1", + "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3", + "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d", + "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8", + "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc", + "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac", + "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8", + "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955", + "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0", + "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367", + "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb", + "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a", + "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623", + "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2", + "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6", + "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7", + "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4", + "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051", + "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938", + "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8", + "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9", + "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3", + "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5", + "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9", + "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333", + "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185", + "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3", + "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560", + "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b", + "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7", + "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78", + "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.13.3" + "markers": "python_version >= '3.7'", + "version": "==1.9.2" }, "zipp": { "hashes": [ - "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", - "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc" + "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b", + "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556" ], - "markers": "python_version >= '3.6'", - "version": "==3.6.0" + "markers": "python_version >= '3.7'", + "version": "==3.15.0" } }, "develop": { - "attrs": { - "hashes": [ - "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", - "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.2.0" - }, "certifi": { "hashes": [ - "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], - "version": "==2021.10.8" + "markers": "python_version >= '3.6'", + "version": "==2023.7.22" }, "charset-normalizer": { "hashes": [ - "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721", - "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c" - ], - "markers": "python_version >= '3'", - "version": "==2.0.9" + "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843", + "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786", + "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e", + "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8", + "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4", + "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa", + "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d", + "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82", + "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7", + "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895", + "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d", + "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a", + "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382", + "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678", + "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b", + "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e", + "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741", + "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4", + "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596", + "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9", + "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69", + "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c", + "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77", + "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13", + "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459", + "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e", + "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7", + "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908", + "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a", + "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f", + "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8", + "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482", + "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d", + "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d", + "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545", + "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34", + "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86", + "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6", + "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe", + "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e", + "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc", + "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7", + "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd", + "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c", + "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557", + "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a", + "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89", + "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078", + "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e", + "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4", + "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403", + "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0", + "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89", + "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115", + "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9", + "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05", + "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a", + "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec", + "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56", + "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38", + "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479", + "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c", + "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e", + "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd", + "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186", + "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455", + "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c", + "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65", + "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78", + "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287", + "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df", + "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43", + "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1", + "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7", + "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989", + "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a", + "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63", + "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884", + "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649", + "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810", + "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828", + "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4", + "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2", + "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd", + "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5", + "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe", + "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293", + "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e", + "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e", + "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.0" }, "click": { "hashes": [ @@ -808,60 +1257,60 @@ "version": "==7.1.2" }, "coverage": { - "extras": [ - - ], - "hashes": [ - "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0", - "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd", - "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884", - "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48", - "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76", - "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0", - "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64", - "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685", - "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47", - "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d", - "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840", - "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f", - "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971", - "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c", - "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a", - "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de", - "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17", - "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4", - "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521", - "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57", - "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b", - "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282", - "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644", - "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475", - "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d", - "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da", - "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953", - "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2", - "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e", - "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c", - "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc", - "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64", - "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74", - "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617", - "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3", - "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d", - "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa", - "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739", - "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8", - "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8", - "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781", - "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58", - "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9", - "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c", - "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd", - "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e", - "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49" + "hashes": [ + "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79", + "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a", + "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f", + "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a", + "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa", + "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398", + "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba", + "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d", + "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf", + "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b", + "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518", + "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d", + "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795", + "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2", + "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e", + "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32", + "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745", + "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b", + "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e", + "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d", + "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f", + "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660", + "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62", + "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6", + "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04", + "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c", + "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5", + "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef", + "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc", + "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae", + "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578", + "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466", + "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4", + "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91", + "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0", + "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4", + "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b", + "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe", + "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b", + "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75", + "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b", + "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c", + "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72", + "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b", + "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f", + "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e", + "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53", + "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3", + "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84", + "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987" ], - "markers": "python_version >= '3.6'", - "version": "==6.2" + "markers": "python_version >= '3.7'", + "version": "==6.5.0" }, "coveralls": { "hashes": [ @@ -869,6 +1318,7 @@ "sha256:f42015f31d386b351d4226389b387ae173207058832fbf5c8ec4b40e27b16026" ], "index": "pypi", + "markers": "python_version >= '3.5'", "version": "==3.3.1" }, "docopt": { @@ -877,43 +1327,53 @@ ], "version": "==0.6.2" }, + "exceptiongroup": { + "hashes": [ + "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9", + "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3" + ], + "markers": "python_version < '3.11'", + "version": "==1.1.3" + }, "flake8": { "hashes": [ - "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d", - "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d" + "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db", + "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248" ], "index": "pypi", - "version": "==4.0.1" + "markers": "python_full_version >= '3.6.1'", + "version": "==5.0.4" }, "ghp-import": { "hashes": [ - "sha256:5f8962b30b20652cdffa9c5a9812f7de6bcb56ec475acac579807719bf242c46", - "sha256:947b3771f11be850c852c64b561c600fdddf794bab363060854c1ee7ad05e071" + "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", + "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343" ], - "version": "==2.0.2" + "version": "==2.1.0" }, "idna": { "hashes": [ - "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", - "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", + "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" ], - "markers": "python_version >= '3'", - "version": "==3.3" + "markers": "python_version >= '3.5'", + "version": "==3.4" }, "importlib-metadata": { "hashes": [ - "sha256:53ccfd5c134223e497627b9815d5030edf77d2ed573922f7a0b8f8bb81a1c100", - "sha256:75bdec14c397f528724c1bfd9709d660b33a4d2e77387a3358f20b848bb5e5fb" + "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116", + "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d" ], - "markers": "python_version < '3.8'", - "version": "==4.8.2" + "markers": "python_version >= '3.7' and python_version < '3.8'", + "version": "==4.13.0" }, "iniconfig": { "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" ], - "version": "==1.1.1" + "markers": "python_version >= '3.7'", + "version": "==2.0.0" }, "jinja2": { "hashes": [ @@ -925,11 +1385,11 @@ }, "markdown": { "hashes": [ - "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006", - "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3" + "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49", + "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c" ], "markers": "python_version >= '3.6'", - "version": "==3.3.6" + "version": "==3.3.4" }, "markupsafe": { "hashes": [ @@ -1003,15 +1463,17 @@ "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" ], + "index": "pypi", "markers": "python_version >= '3.6'", "version": "==2.0.1" }, "mccabe": { "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" ], - "version": "==0.6.1" + "markers": "python_version >= '3.6'", + "version": "==0.7.0" }, "mergedeep": { "hashes": [ @@ -1023,75 +1485,62 @@ }, "mkdocs": { "hashes": [ - "sha256:89f5a094764381cda656af4298727c9f53dc3e602983087e1fe96ea1df24f4c1", - "sha256:a1fa8c2d0c1305d7fc2b9d9f607c71778572a8b110fb26642aa00296c9e6d072" + "sha256:8e7970a26183487fe2a1041940c6fd03aa0dbe5549e50c3e7194f565cb3c678a", + "sha256:f108e7ab5a7ed3e30826dbf82f37638f0d90d11161644616cc4f01a1e2ab3940" ], "index": "pypi", - "version": "==1.2.3" + "markers": "python_version >= '3.6'", + "version": "==1.2.4" }, "packaging": { "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" ], - "markers": "python_version >= '3.6'", - "version": "==21.3" + "markers": "python_version >= '3.7'", + "version": "==23.2" }, "pluggy": { "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" - ], - "markers": "python_version >= '3.6'", - "version": "==1.0.0" - }, - "py": { - "hashes": [ - "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", - "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" + "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849", + "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.11.0" + "markers": "python_version >= '3.7'", + "version": "==1.2.0" }, "pycodestyle": { "hashes": [ - "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20", - "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f" + "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785", + "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==2.8.0" + "markers": "python_version >= '3.6'", + "version": "==2.9.1" }, "pyflakes": { "hashes": [ - "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c", - "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.0" - }, - "pyparsing": { - "hashes": [ - "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4", - "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81" + "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2", + "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3" ], "markers": "python_version >= '3.6'", - "version": "==3.0.6" + "version": "==2.5.0" }, "pytest": { "hashes": [ - "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89", - "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134" + "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002", + "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069" ], "index": "pypi", - "version": "==6.2.5" + "markers": "python_version >= '3.7'", + "version": "==7.4.2" }, "pytest-cov": { "hashes": [ - "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6", - "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470" + "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6", + "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a" ], "index": "pypi", - "version": "==3.0.0" + "markers": "python_version >= '3.7'", + "version": "==4.1.0" }, "python-dateutil": { "hashes": [ @@ -1099,46 +1548,64 @@ "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.8.2" }, "pyyaml": { "hashes": [ - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" ], "markers": "python_version >= '3.6'", - "version": "==6.0" + "version": "==6.0.1" }, "pyyaml-env-tag": { "hashes": [ @@ -1150,87 +1617,86 @@ }, "requests": { "hashes": [ - "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", - "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], "index": "pypi", - "version": "==2.26.0" + "markers": "python_version >= '3.7'", + "version": "==2.31.0" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, "tomli": { "hashes": [ - "sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee", - "sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade" + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" ], - "version": "==1.2.2" + "markers": "python_version < '3.11'", + "version": "==2.0.1" }, "typing-extensions": { "hashes": [ - "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e", - "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b" + "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", + "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2" ], - "markers": "python_version < '3.10'", - "version": "==4.0.1" + "markers": "python_version >= '3.7'", + "version": "==4.7.1" }, "urllib3": { "hashes": [ - "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", - "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" + "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84", + "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'", - "version": "==1.26.7" + "markers": "python_version >= '3.6'", + "version": "==2.0.7" }, "watchdog": { "hashes": [ - "sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685", - "sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04", - "sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb", - "sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542", - "sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6", - "sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b", - "sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660", - "sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3", - "sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923", - "sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7", - "sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b", - "sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669", - "sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2", - "sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3", - "sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604", - "sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8", - "sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5", - "sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0", - "sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6", - "sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65", - "sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d", - "sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15", - "sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9" + "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a", + "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100", + "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8", + "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc", + "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae", + "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41", + "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0", + "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f", + "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c", + "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9", + "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3", + "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709", + "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83", + "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759", + "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9", + "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3", + "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7", + "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f", + "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346", + "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674", + "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397", + "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96", + "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d", + "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a", + "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64", + "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44", + "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33" ], "index": "pypi", - "version": "==2.1.6" + "markers": "python_version >= '3.7'", + "version": "==3.0.0" }, "zipp": { "hashes": [ - "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832", - "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc" + "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b", + "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556" ], - "markers": "python_version >= '3.6'", - "version": "==3.6.0" + "markers": "python_version >= '3.7'", + "version": "==3.15.0" } } } diff --git a/askomics/api/admin.py b/askomics/api/admin.py index 5200ebb5..1610c2a7 100644 --- a/askomics/api/admin.py +++ b/askomics/api/admin.py @@ -116,7 +116,7 @@ def get_files(): @admin_required def get_queries(): """Get all public queries - + (And anonymous queries) Returns ------- json @@ -126,7 +126,7 @@ def get_queries(): """ try: results_handler = ResultsHandler(current_app, session) - public_queries = results_handler.get_admin_public_queries() + queries = results_handler.get_admin_queries() except Exception as e: traceback.print_exc(file=sys.stdout) @@ -137,7 +137,7 @@ def get_queries(): }), 500 return jsonify({ - "queries": public_queries, + "queries": queries, 'error': False, 'errorMessage': '' }) @@ -287,7 +287,7 @@ def toogle_public_dataset(): @admin_bp.route('/api/admin/publicize_query', methods=['POST']) @api_auth @admin_required -def togle_public_query(): +def toggle_public_query(): """Publish a query template from a result Returns @@ -304,7 +304,7 @@ def togle_public_query(): result.publish_query(json["newStatus"], admin=True) results_handler = ResultsHandler(current_app, session) - public_queries = results_handler.get_admin_public_queries() + public_queries = results_handler.get_admin_queries() except Exception as e: traceback.print_exc(file=sys.stdout) @@ -321,6 +321,57 @@ def togle_public_query(): }) +@admin_bp.route('/api/admin/update_description', methods=['POST']) +@api_auth +@admin_required +def update_query_description(): + """Update a query description + + Returns + ------- + json + error: True if error, else False + errorMessage: the error message of error, else an empty string + """ + try: + data = request.get_json() + if not (data and data.get("queryId") and data.get("newDesc")): + return jsonify({ + 'files': [], + 'error': True, + 'errorMessage': "Missing parameters" + }), 400 + + result_info = {"id": data["queryId"]} + new_desc = data["newDesc"] + + result = Result(current_app, session, result_info, admin=True) + if not result: + return jsonify({ + 'files': [], + 'error': True, + 'errorMessage': "You do not have access to this result" + }), 500 + result.update_description(new_desc, admin=True) + + results_handler = ResultsHandler(current_app, session) + queries = results_handler.get_admin_queries() + + except Exception as e: + traceback.print_exc(file=sys.stdout) + return jsonify({ + 'queries': [], + 'error': True, + 'errorMessage': 'Failed to update description: \n{}'.format(str(e)) + }), 500 + + return jsonify({ + 'queries': queries, + 'error': False, + 'errorMessage': '' + }) + + @admin_bp.route("/api/admin/adduser", methods=["POST"]) @api_auth @admin_required @@ -520,6 +571,47 @@ def delete_datasets(): }) +@admin_bp.route("/api/admin/delete_queries", methods=["POST"]) +@api_auth +@admin_required +def delete_queries(): + """Delete queries + + Returns + ------- + json + queries: list of all queries (either public or anonymous) + error: True if error, else False + errorMessage: the error message of error, else an empty string + """ + data = request.get_json() + if not data.get("queriesIdToDelete"): + return jsonify({ + 'queries': [], + 'error': True, + 'errorMessage': "Missing queriesIdToDelete key" + }), 400 + + try: + queries_id = data["queriesIdToDelete"] + results_handler = ResultsHandler(current_app, session) + remaining_queries = results_handler.delete_results(queries_id, admin=True) + + except Exception as e: + traceback.print_exc(file=sys.stdout) + return jsonify({ + 'queries': [], + 'error': True, + 'errorMessage': str(e) + }), 500 + + return jsonify({ + 'queries': remaining_queries, + 'error': False, + 'errorMessage': '' + }) + + @admin_bp.route("/api/admin/getprefixes", methods=["GET"]) @api_auth @admin_required diff --git a/askomics/api/auth.py b/askomics/api/auth.py index 607735b2..ff15df50 100644 --- a/askomics/api/auth.py +++ b/askomics/api/auth.py @@ -13,14 +13,38 @@ def login_required(f): + """Login required function""" + @wraps(f) + def decorated_function(*args, **kwargs): + """Login required decorator""" + if 'user' in session and not session['user'].get('fake', False): + if not session['user']['blocked']: + return f(*args, **kwargs) + return jsonify({"error": True, "errorMessage": "Blocked account"}), 401 + return jsonify({"error": True, "errorMessage": "Login required"}), 401 + + return decorated_function + + +def login_required_query(f): """Login required function""" @wraps(f) def decorated_function(*args, **kwargs): """Login required decorator""" if 'user' in session: + # If conf has changed, clear session + if session['user'].get('fake', False) and not current_app.iniconfig.getboolean('askomics', 'anonymous_query', fallback=False): + session.pop('user') + return jsonify({"error": True, "errorMessage": "Login required"}), 401 + if not session['user']['blocked']: return f(*args, **kwargs) + return jsonify({"error": True, "errorMessage": "Blocked account"}), 401 + elif current_app.iniconfig.getboolean('askomics', 'anonymous_query', fallback=False): + local_auth = LocalAuth(current_app, session) + session['user'] = local_auth.get_anonymous_user() + return f(*args, **kwargs) return jsonify({"error": True, "errorMessage": "Login required"}), 401 return decorated_function diff --git a/askomics/api/file.py b/askomics/api/file.py index 5d224030..69cd82e4 100644 --- a/askomics/api/file.py +++ b/askomics/api/file.py @@ -397,7 +397,7 @@ def serve_file(path, user_id, username): username ) - return(send_from_directory(dir_path, path)) + return send_from_directory(dir_path, path) @file_bp.route('/api/files/columns', methods=['GET']) @@ -410,7 +410,7 @@ def get_column_types(): types: list of available column types """ - data = ["numeric", "text", "category", "boolean", "date", "reference", "strand", "start", "end", "general_relation", "symetric_relation", "label"] + data = ["numeric", "text", "category", "boolean", "date", "reference", "strand", "start", "end", "general_relation", "symetric_relation", "indirect_relation", "label"] return jsonify({ "types": data diff --git a/askomics/api/query.py b/askomics/api/query.py index 45dd8c6d..f58ea6e8 100644 --- a/askomics/api/query.py +++ b/askomics/api/query.py @@ -1,7 +1,7 @@ import sys import traceback -from askomics.api.auth import api_auth, login_required +from askomics.api.auth import api_auth, login_required_query from askomics.libaskomics.FilesUtils import FilesUtils from askomics.libaskomics.ResultsHandler import ResultsHandler from askomics.libaskomics.Result import Result @@ -155,7 +155,7 @@ def get_preview(): @query_bp.route('/api/query/save_result', methods=['POST']) @api_auth -@login_required +@login_required_query def save_result(): """Save a query in filesystem and db, using a celery task @@ -168,14 +168,14 @@ def save_result(): """ try: files_utils = FilesUtils(current_app, session) - disk_space = files_utils.get_size_occupied_by_user() if "user" in session else None - - if session["user"]["quota"] > 0 and disk_space >= session["user"]["quota"]: - return jsonify({ - 'error': True, - 'errorMessage': "Exceeded quota", - 'result_id': None - }), 400 + if "user" in session: + disk_space = files_utils.get_size_occupied_by_user() + if session["user"]["quota"] > 0 and disk_space >= session["user"]["quota"]: + return jsonify({ + 'error': True, + 'errorMessage': "Exceeded quota", + 'result_id': None + }), 400 # Get query and endpoints and graphs of the query data = request.get_json() diff --git a/askomics/api/results.py b/askomics/api/results.py index d87f9e9e..6348ae9b 100644 --- a/askomics/api/results.py +++ b/askomics/api/results.py @@ -1,7 +1,7 @@ import traceback import sys -from askomics.api.auth import api_auth, login_required, admin_required +from askomics.api.auth import api_auth, login_required, login_required_query, admin_required from askomics.libaskomics.FilesUtils import FilesUtils from askomics.libaskomics.ResultsHandler import ResultsHandler from askomics.libaskomics.Result import Result @@ -22,7 +22,7 @@ def can_access(user): @results_bp.route('/api/results', methods=['GET']) @api_auth -@login_required +@login_required_query def get_results(): """Get ... @@ -60,7 +60,7 @@ def get_results(): @results_bp.route('/api/results/preview', methods=['POST']) @api_auth -@login_required +@login_required_query def get_preview(): """Summary @@ -85,7 +85,7 @@ def get_preview(): file_id = data["fileId"] result_info = {"id": file_id} - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'preview': [], @@ -250,7 +250,7 @@ def get_graph_state(): @results_bp.route('/api/results/download', methods=['POST']) @api_auth -@login_required +@login_required_query def download_result(): """Download result file""" try: @@ -263,7 +263,7 @@ def download_result(): file_id = data["fileId"] result_info = {"id": file_id} - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'error': True, @@ -279,7 +279,7 @@ def download_result(): 'errorMessage': str(e) }), 500 - return(send_from_directory(dir_path, file_name)) + return send_from_directory(dir_path, file_name) @results_bp.route('/api/results/delete', methods=['POST']) @@ -324,7 +324,7 @@ def delete_result(): @results_bp.route('/api/results/sparqlquery', methods=['POST']) @api_auth -@login_required +@login_required_query def get_sparql_query(): """Get sparql query of result for the query editor @@ -405,7 +405,7 @@ def get_sparql_query(): @results_bp.route('/api/results/description', methods=['POST']) @api_auth -@login_required +@login_required_query def set_description(): """Update a result description @@ -428,7 +428,7 @@ def set_description(): result_info = {"id": data["id"]} new_desc = data["newDesc"] - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'files': [], @@ -478,7 +478,7 @@ def publish_query(): result_info = {"id": data["id"]} - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'files': [], @@ -528,7 +528,7 @@ def template_query(): result_info = {"id": data["id"]} - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'files': [], @@ -578,7 +578,7 @@ def form_query(): result_info = {"id": data["id"]} - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'files': [], @@ -626,7 +626,7 @@ def send2galaxy(): }), 400 result_info = {"id": data["fileId"]} - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'error': True, @@ -669,7 +669,7 @@ def save_form(): result_info = {"id": data["formId"]} - result = Result(current_app, session, result_info) + result = Result(current_app, session, result_info, owner=True) if not result: return jsonify({ 'error': True, diff --git a/askomics/api/sparql.py b/askomics/api/sparql.py index 043897c8..f755516c 100644 --- a/askomics/api/sparql.py +++ b/askomics/api/sparql.py @@ -1,6 +1,6 @@ import traceback import sys -from askomics.api.auth import api_auth, login_required +from askomics.api.auth import api_auth, login_required_query from askomics.libaskomics.FilesUtils import FilesUtils from askomics.libaskomics.Result import Result from askomics.libaskomics.SparqlQuery import SparqlQuery @@ -18,7 +18,7 @@ def can_access(user): @sparql_bp.route("/api/sparql/init", methods=["GET"]) @api_auth -@login_required +@login_required_query def init(): """Get the default sparql query @@ -65,7 +65,7 @@ def init(): @sparql_bp.route('/api/sparql/previewquery', methods=['POST']) @api_auth -@login_required +@login_required_query def query(): """Perform a sparql query @@ -149,7 +149,7 @@ def query(): @sparql_bp.route('/api/sparql/savequery', methods=["POST"]) @api_auth -@login_required +@login_required_query def save_query(): """Perform a sparql query diff --git a/askomics/api/start.py b/askomics/api/start.py index 910af044..a1425535 100644 --- a/askomics/api/start.py +++ b/askomics/api/start.py @@ -45,6 +45,12 @@ def start(): except Exception: pass + contact_message = None + try: + contact_message = current_app.iniconfig.get('askomics', 'contact_message') + except Exception: + pass + # get proxy path proxy_path = "/" try: @@ -71,6 +77,7 @@ def start(): config = { "footerMessage": current_app.iniconfig.get('askomics', 'footer_message'), "frontMessage": front_message, + "contactMessage": contact_message, "version": get_distribution('askomics').version, "commit": sha, "gitUrl": current_app.iniconfig.get('askomics', 'github'), @@ -86,7 +93,8 @@ def start(): "logged": False, "ontologies": ontologies, "singleTenant": current_app.iniconfig.getboolean('askomics', 'single_tenant', fallback=False), - "autocompleteMaxResults": current_app.iniconfig.getint("askomics", "autocomplete_max_results", fallback=10) + "autocompleteMaxResults": current_app.iniconfig.getint("askomics", "autocomplete_max_results", fallback=10), + "anonymousQuery": current_app.iniconfig.getboolean('askomics', 'anonymous_query', fallback=False) } json = { @@ -95,7 +103,7 @@ def start(): "config": config } - if 'user' in session: + if 'user' in session and not session['user'].get('fake', False): local_auth = LocalAuth(current_app, session) user = local_auth.get_user(session['user']['username']) local_auth.update_last_action(session["user"]["username"]) diff --git a/askomics/app.py b/askomics/app.py index e26b858c..a2d9050b 100644 --- a/askomics/app.py +++ b/askomics/app.py @@ -34,6 +34,8 @@ from sentry_sdk.integrations.flask import FlaskIntegration from sentry_sdk.integrations.celery import CeleryIntegration +import logging + __all__ = ('create_app', 'create_celery') BLUEPRINTS = ( @@ -107,6 +109,12 @@ def create_app(config='config/askomics.ini', app_name='askomics', blueprints=Non for blueprint in blueprints: app.register_blueprint(blueprint) + if app.config['ENV'] == "production": + log_level = 10 if app.config['DEBUG'] else 20 + gunicorn_logger = logging.getLogger('gunicorn.error') + app.logger.handlers = gunicorn_logger.handlers + app.logger.setLevel(log_level) + if proxy_path: ReverseProxyPrefixFix(app) diff --git a/askomics/libaskomics/BedFile.py b/askomics/libaskomics/BedFile.py index 98802ada..0c4a9ee5 100644 --- a/askomics/libaskomics/BedFile.py +++ b/askomics/libaskomics/BedFile.py @@ -110,12 +110,12 @@ def set_rdf_abstraction_domain_knowledge(self): # Domain Knowledge if "values" in attribute.keys(): for value in attribute["values"]: - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri(value)], rdflib.RDF.type, self.namespace_data[self.format_uri("{}CategoryValue".format(attribute["label"]))])) - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri(value)], rdflib.RDFS.label, rdflib.Literal(value))) - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri("{}Category".format(attribute["label"]))], self.namespace_internal[self.format_uri("category")], self.namespace_data[self.format_uri(value)])) - + o = self.namespace_data[self.format_uri(value)] if attribute["label"] == rdflib.Literal("strand"): - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri(value)], rdflib.RDF.type, self.get_faldo_strand(value))) + o = self.get_faldo_strand(value) + self.graph_abstraction_dk.add((o, rdflib.RDF.type, self.namespace_data[self.format_uri("{}CategoryValue".format(attribute["label"]))])) + self.graph_abstraction_dk.add((o, rdflib.RDFS.label, rdflib.Literal(value))) + self.graph_abstraction_dk.add((self.namespace_data[self.format_uri("{}Category".format(attribute["label"]))], self.namespace_internal[self.format_uri("category")], o)) # Faldo: if self.faldo_entity: @@ -172,7 +172,7 @@ def generate_rdf_content(self): attribute = self.namespace_data[self.format_uri(feature.chrom)] faldo_reference = attribute self.faldo_abstraction["reference"] = relation - self.graph_chunk.add((entity, relation, attribute)) + # self.graph_chunk.add((entity, relation, attribute)) if "reference" not in attribute_list: attribute_list.append("reference") @@ -195,7 +195,7 @@ def generate_rdf_content(self): attribute = rdflib.Literal(self.convert_type(feature.start + 1)) # +1 because bed is 0 based faldo_start = attribute self.faldo_abstraction["start"] = relation - self.graph_chunk.add((entity, relation, attribute)) + # self.graph_chunk.add((entity, relation, attribute)) if "start" not in attribute_list: attribute_list.append("start") @@ -212,7 +212,7 @@ def generate_rdf_content(self): attribute = rdflib.Literal(self.convert_type(feature.end)) faldo_end = attribute self.faldo_abstraction["end"] = relation - self.graph_chunk.add((entity, relation, attribute)) + # self.graph_chunk.add((entity, relation, attribute)) if "end" not in attribute_list: attribute_list.append("end") @@ -233,7 +233,7 @@ def generate_rdf_content(self): attribute = self.namespace_data[self.format_uri("+")] faldo_strand = self.get_faldo_strand("+") self.faldo_abstraction["strand"] = relation - self.graph_chunk.add((entity, relation, attribute)) + # self.graph_chunk.add((entity, relation, attribute)) strand = True strand_type = "+" elif feature.strand == "-": @@ -242,7 +242,7 @@ def generate_rdf_content(self): attribute = self.namespace_data[self.format_uri("-")] faldo_strand = self.get_faldo_strand("-") self.faldo_abstraction["strand"] = relation - self.graph_chunk.add((entity, relation, attribute)) + # self.graph_chunk.add((entity, relation, attribute)) strand = True strand_type = "-" else: @@ -251,7 +251,7 @@ def generate_rdf_content(self): attribute = self.namespace_data[self.format_uri(".")] faldo_strand = self.get_faldo_strand(".") self.faldo_abstraction["strand"] = relation - self.graph_chunk.add((entity, relation, attribute)) + # self.graph_chunk.add((entity, relation, attribute)) strand = True strand_type = "." @@ -271,7 +271,7 @@ def generate_rdf_content(self): if feature.score != '.': relation = self.namespace_data[self.format_uri("score")] attribute = rdflib.Literal(self.convert_type(feature.score)) - self.graph_chunk.add((entity, relation, attribute)) + # self.graph_chunk.add((entity, relation, attribute)) if "score" not in attribute_list: attribute_list.append("score") @@ -283,6 +283,8 @@ def generate_rdf_content(self): "range": rdflib.XSD.decimal }) + # Triples respecting faldo ontology + location = BNode() begin = BNode() end = BNode() @@ -306,4 +308,32 @@ def generate_rdf_content(self): self.graph_chunk.add((begin, rdflib.RDF.type, faldo_strand)) self.graph_chunk.add((end, rdflib.RDF.type, faldo_strand)) + # Shortcut triple for faldo queries + self.graph_chunk.add((entity, self.namespace_internal["faldoBegin"], faldo_start)) + self.graph_chunk.add((entity, self.namespace_internal["faldoEnd"], faldo_end)) + self.graph_chunk.add((entity, self.namespace_internal["faldoReference"], faldo_reference)) + + if faldo_strand: + self.graph_chunk.add((entity, self.namespace_internal["faldoStrand"], faldo_strand)) + strand_ref = self.get_reference_strand_uri(feature.chrom, faldo_strand, None) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["referenceStrand"], sref)) + + # blocks + block_base = self.settings.getint("triplestore", "block_size") + block_start = int(self.convert_type(feature.start + 1)) // block_base + block_end = int(self.convert_type(feature.end)) // block_base + + for slice_block in range(block_start, block_end + 1): + self.graph_chunk.add((entity, self.namespace_internal['includeIn'], rdflib.Literal(int(slice_block)))) + block_reference = self.rdfize(self.format_uri("{}_{}".format(feature.chrom, slice_block))) + self.graph_chunk.add((entity, self.namespace_internal["includeInReference"], block_reference)) + if faldo_strand: + strand_ref = self.get_reference_strand_uri(feature.chrom, faldo_strand, slice_block) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["includeInReferenceStrand"], sref)) + strand_ref = self.get_reference_strand_uri(None, faldo_strand, slice_block) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["includeInStrand"], sref)) + yield diff --git a/askomics/libaskomics/CsvFile.py b/askomics/libaskomics/CsvFile.py index 821f00dd..064c814a 100644 --- a/askomics/libaskomics/CsvFile.py +++ b/askomics/libaskomics/CsvFile.py @@ -367,11 +367,11 @@ def set_rdf_domain_knowledge(self): p = self.namespace_internal["category"] for value in self.category_values[self.header[index]]: o = self.rdfize(value) + if self.columns_type[index] == "strand": + o = self.get_faldo_strand(value) self.graph_abstraction_dk.add((s, p, o)) self.graph_abstraction_dk.add((o, rdflib.RDF.type, self.namespace_data["{}CategoryValue".format(self.format_uri(self.header[index]))])) self.graph_abstraction_dk.add((o, rdflib.RDFS.label, rdflib.Literal(value))) - if self.columns_type[index] == "strand": - self.graph_abstraction_dk.add((o, rdflib.RDF.type, self.get_faldo_strand(value))) def set_rdf_abstraction(self): """Set the abstraction""" @@ -416,8 +416,9 @@ def set_rdf_abstraction(self): blank = BNode() # Relation - if self.columns_type[index] in ('general_relation', 'symetric_relation'): + if self.columns_type[index] in ('general_relation', 'symetric_relation', 'indirect_relation'): symetric_relation = True if self.columns_type[index] == 'symetric_relation' else False + indirect_relation = True if self.columns_type[index] == 'indirect_relation' else False splitted = attribute_name.split('@') attribute = self.rdfize(splitted[0]) @@ -439,6 +440,8 @@ def set_rdf_abstraction(self): if symetric_relation: self.graph_abstraction_dk.add((blank, rdflib.RDFS.domain, rdf_range)) self.graph_abstraction_dk.add((blank, rdflib.RDFS.range, entity)) + if indirect_relation: + self.graph_abstraction_dk.add((blank, self.namespace_internal["isIndirectRelation"], rdflib.Literal("true", datatype=rdflib.XSD.boolean))) continue @@ -597,6 +600,10 @@ def generate_rdf_content(self): if current_type == "label" and column_number == 1: continue + # We ignore all data for indirect relations + if current_type == "indirect_relation": + continue + # Skip entity and blank cells if column_number == 0 or (not cell and not current_type == "strand"): continue @@ -617,8 +624,9 @@ def generate_rdf_content(self): # Category elif current_type in ('category', 'reference', 'strand'): potential_relation = self.rdfize(current_header) - if not cell: - cell = "unknown/both" + if current_type == "strand": + # Override csv value, use "proper" values + cell = self.get_faldo_strand_label(cell) if current_header not in self.category_values.keys(): # Add the category in dict, and the first value in a set self.category_values[current_header] = {cell, } @@ -674,6 +682,9 @@ def generate_rdf_content(self): self.graph_chunk.add((attribute, relation, entity)) if self.faldo_entity and faldo_start and faldo_end: + + # Triples respecting faldo ontology + location = BNode() begin_node = BNode() end_node = BNode() @@ -698,6 +709,19 @@ def generate_rdf_content(self): self.graph_chunk.add((begin_node, rdflib.RDF.type, faldo_strand)) self.graph_chunk.add((end_node, rdflib.RDF.type, faldo_strand)) + # Shortcut triple for faldo queries + self.graph_chunk.add((entity, self.namespace_internal["faldoBegin"], faldo_start)) + self.graph_chunk.add((entity, self.namespace_internal["faldoEnd"], faldo_end)) + if faldo_reference: + self.graph_chunk.add((entity, self.namespace_internal["faldoReference"], faldo_reference)) + if faldo_strand: + strand_ref = self.get_reference_strand_uri(reference, faldo_strand, None) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["referenceStrand"], sref)) + + if faldo_strand: + self.graph_chunk.add((entity, self.namespace_internal["faldoStrand"], faldo_strand)) + # blocks block_base = self.settings.getint("triplestore", "block_size") block_start = int(start) // block_base @@ -708,5 +732,13 @@ def generate_rdf_content(self): if reference: block_reference = self.rdfize(self.format_uri("{}_{}".format(reference, slice_block))) self.graph_chunk.add((entity, self.namespace_internal["includeInReference"], block_reference)) + if faldo_strand: + strand_ref = self.get_reference_strand_uri(reference, faldo_strand, slice_block) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["includeInReferenceStrand"], sref)) + if faldo_strand: + strand_ref = self.get_reference_strand_uri(None, faldo_strand, slice_block) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["includeInStrand"], sref)) yield diff --git a/askomics/libaskomics/Database.py b/askomics/libaskomics/Database.py index 9fc02acb..6b18a746 100644 --- a/askomics/libaskomics/Database.py +++ b/askomics/libaskomics/Database.py @@ -270,6 +270,7 @@ def create_results_table(self): template boolean, has_form_attr boolean, form boolean, + version text, FOREIGN KEY(user_id) REFERENCES users(user_id) ) ''' @@ -355,6 +356,17 @@ def update_results_table(self): except Exception: pass + query = ''' + ALTER TABLE results + ADD version text NULL + DEFAULT(NULL) + ''' + + try: + self.execute_sql_query(query) + except Exception: + pass + def create_endpoints_table(self): """Create the endpoints table""" query = ''' diff --git a/askomics/libaskomics/File.py b/askomics/libaskomics/File.py index 030f30e3..83276fb0 100644 --- a/askomics/libaskomics/File.py +++ b/askomics/libaskomics/File.py @@ -436,6 +436,50 @@ def get_faldo_strand(self, raw_strand): return self.faldo.BothStrandPosition + def get_faldo_strand_label(self, raw_strand): + """Get faldo strand label + + Parameters + ---------- + raw_strand : string + raw value of strand + + Returns + ------- + label + "+", "-", or "." + """ + + if raw_strand in ("+", "plus", "1", "positive", "forward"): + return "+" + + if raw_strand in ("-", "minus", "moins", "-1", "reverse", "negative"): + return "-" + + return "." + + def get_reference_strand_uri(self, reference, strand, block=None): + faldo_dict = { + self.faldo.ForwardStrandPosition: "ForwardStrand", + self.faldo.ReverseStrandPosition: "ReverseStrand", + self.faldo.BothStrandPosition: "BothStrand" + } + if reference is None: + if strand == self.faldo.BothStrandPosition: + return [self.rdfize(self.format_uri("s{}_{}".format(dstrand, block))) for dstrand in faldo_dict.values()] + + return [self.rdfize(self.format_uri("s{}_{}".format(faldo_dict[strand], block)))] + + if block is None: + if strand == self.faldo.BothStrandPosition: + return [self.rdfize(self.format_uri("{}_s{}s".format(reference, dstrand))) for dstrand in faldo_dict.values()] + return [self.rdfize(self.format_uri("{}_s{}".format(reference, faldo_dict[strand])))] + + if strand == self.faldo.BothStrandPosition: + return [self.rdfize(self.format_uri("{}_s{}_{}".format(reference, dstrand, block))) for dstrand in faldo_dict.values()] + + return [self.rdfize(self.format_uri("{}_s{}_{}".format(reference, faldo_dict[strand], block)))] + def get_rdf_type(self, value): """get xsd type of a value diff --git a/askomics/libaskomics/FilesHandler.py b/askomics/libaskomics/FilesHandler.py index 04254028..4bacfd17 100644 --- a/askomics/libaskomics/FilesHandler.py +++ b/askomics/libaskomics/FilesHandler.py @@ -356,7 +356,7 @@ def persist_chunk(self, chunk_info): self.delete_file_from_fs(file_path) except Exception: pass - raise(e) + raise e def download_url(self, url, task_id): """Download a file from an URL and insert info in database diff --git a/askomics/libaskomics/GffFile.py b/askomics/libaskomics/GffFile.py index 7c413de7..d87d7d9c 100644 --- a/askomics/libaskomics/GffFile.py +++ b/askomics/libaskomics/GffFile.py @@ -45,6 +45,13 @@ def __init__(self, app, session, file_info, host_url=None, external_endpoint=Non self.faldo_entity = True + self.faldo_abstraction = { + "start": [], + "end": [], + "strand": [], + "reference": [] + } + def set_preview(self): """Summary""" try: @@ -133,24 +140,24 @@ def set_rdf_abstraction_domain_knowledge(self): self.graph_abstraction_dk.add((blank, rdflib.RDFS.domain, attribute["domain"])) self.graph_abstraction_dk.add((blank, rdflib.RDFS.range, attribute["range"])) - attribute_blanks[attribute["uri"]] = blank + attribute_blanks[(attribute['domain'], attribute["uri"])] = blank # Domain Knowledge if "values" in attribute.keys(): for value in attribute["values"]: - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri(value)], rdflib.RDF.type, self.namespace_data[self.format_uri("{}CategoryValue".format(attribute["label"]))])) - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri(value)], rdflib.RDFS.label, rdflib.Literal(value))) - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri("{}Category".format(attribute["label"]))], self.namespace_internal[self.format_uri("category")], self.namespace_data[self.format_uri(value)])) - + o = self.namespace_data[self.format_uri(value)] if attribute["label"] == rdflib.Literal("strand"): - self.graph_abstraction_dk.add((self.namespace_data[self.format_uri(value)], rdflib.RDF.type, self.get_faldo_strand(value))) - + o = self.get_faldo_strand(value) + self.graph_abstraction_dk.add((o, rdflib.RDF.type, self.namespace_data[self.format_uri("{}CategoryValue".format(attribute["label"]))])) + self.graph_abstraction_dk.add((o, rdflib.RDFS.label, rdflib.Literal(value))) + self.graph_abstraction_dk.add((self.namespace_data[self.format_uri("{}Category".format(attribute["label"]))], self.namespace_internal[self.format_uri("category")], o)) # Faldo: if self.faldo_entity: - for key, value in self.faldo_abstraction.items(): - if value: - blank = attribute_blanks[value] - self.graph_abstraction_dk.add((blank, rdflib.RDF.type, self.faldo_abstraction_eq[key])) - self.graph_abstraction_dk.add((blank, self.namespace_internal["uri"], value)) + for key, values in self.faldo_abstraction.items(): + if values: + for val in values: + blank = attribute_blanks[val] + self.graph_abstraction_dk.add((blank, rdflib.RDF.type, self.faldo_abstraction_eq[key])) + self.graph_abstraction_dk.add((blank, self.namespace_internal["uri"], val[1])) def format_gff_entity(self, entity): """Format a gff entity name by removing type (type:entity --> entity) @@ -233,7 +240,7 @@ def generate_rdf_content(self): relation = self.namespace_data[self.format_uri("reference")] attribute = self.namespace_data[self.format_uri(rec.id)] faldo_reference = attribute - self.faldo_abstraction["reference"] = relation + self.faldo_abstraction["reference"].append((entity_type, relation)) # self.graph_chunk.add((entity, relation, attribute)) if (feature.type, "reference") not in attribute_list: @@ -256,7 +263,7 @@ def generate_rdf_content(self): relation = self.namespace_data[self.format_uri("start")] attribute = rdflib.Literal(self.convert_type(feature.location.start)) faldo_start = attribute - self.faldo_abstraction["start"] = relation + self.faldo_abstraction["start"].append((entity_type, relation)) # self.graph_chunk.add((entity, relation, attribute)) if (feature.type, "start") not in attribute_list: @@ -273,7 +280,7 @@ def generate_rdf_content(self): relation = self.namespace_data[self.format_uri("end")] attribute = rdflib.Literal(self.convert_type(feature.location.end)) faldo_end = attribute - self.faldo_abstraction["end"] = relation + self.faldo_abstraction["end"].append((entity_type, relation)) # self.graph_chunk.add((entity, relation, attribute)) if (feature.type, "end") not in attribute_list: @@ -292,7 +299,7 @@ def generate_rdf_content(self): relation = self.namespace_data[self.format_uri("strand")] attribute = self.namespace_data[self.format_uri("+")] faldo_strand = self.get_faldo_strand("+") - self.faldo_abstraction["strand"] = relation + self.faldo_abstraction["strand"].append((entity_type, relation)) strand_type = "+" # self.graph_chunk.add((entity, relation, attribute)) elif feature.location.strand == -1: @@ -300,7 +307,7 @@ def generate_rdf_content(self): relation = self.namespace_data[self.format_uri("strand")] attribute = self.namespace_data[self.format_uri("-")] faldo_strand = self.get_faldo_strand("-") - self.faldo_abstraction["strand"] = relation + self.faldo_abstraction["strand"].append((entity_type, relation)) strand_type = "-" # self.graph_chunk.add((entity, relation, attribute)) else: @@ -308,7 +315,7 @@ def generate_rdf_content(self): relation = self.namespace_data[self.format_uri("strand")] attribute = self.namespace_data[self.format_uri(".")] faldo_strand = self.get_faldo_strand(".") - self.faldo_abstraction["strand"] = relation + self.faldo_abstraction["strand"].append((entity_type, relation)) strand_type = "." if (feature.type, "strand", strand_type) not in attribute_list: @@ -381,6 +388,8 @@ def generate_rdf_content(self): self.graph_chunk.add((entity, relation, attribute)) + # Triples respecting faldo ontology + location = BNode() begin = BNode() end = BNode() @@ -404,15 +413,33 @@ def generate_rdf_content(self): self.graph_chunk.add((begin, rdflib.RDF.type, faldo_strand)) self.graph_chunk.add((end, rdflib.RDF.type, faldo_strand)) - # blocks - block_base = self.settings.getint("triplestore", "block_size") - block_start = int(self.convert_type(feature.location.start)) // block_base - block_end = int(self.convert_type(feature.location.end)) // block_base + # Shortcut triple for faldo queries + self.graph_chunk.add((entity, self.namespace_internal["faldoBegin"], faldo_start)) + self.graph_chunk.add((entity, self.namespace_internal["faldoEnd"], faldo_end)) + self.graph_chunk.add((entity, self.namespace_internal["faldoReference"], faldo_reference)) - for slice_block in range(block_start, block_end + 1): - self.graph_chunk.add((entity, self.namespace_internal['includeIn'], rdflib.Literal(int(slice_block)))) - block_reference = self.rdfize(self.format_uri("{}_{}".format(rec.id, slice_block))) - self.graph_chunk.add((entity, self.namespace_internal["includeInReference"], block_reference)) + if faldo_strand: + self.graph_chunk.add((entity, self.namespace_internal["faldoStrand"], faldo_strand)) + strand_ref = self.get_reference_strand_uri(rec.id, faldo_strand, None) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["referenceStrand"], sref)) + + # blocks + block_base = self.settings.getint("triplestore", "block_size") + block_start = int(self.convert_type(feature.location.start)) // block_base + block_end = int(self.convert_type(feature.location.end)) // block_base + + for slice_block in range(block_start, block_end + 1): + self.graph_chunk.add((entity, self.namespace_internal['includeIn'], rdflib.Literal(int(slice_block)))) + block_reference = self.rdfize(self.format_uri("{}_{}".format(rec.id, slice_block))) + self.graph_chunk.add((entity, self.namespace_internal["includeInReference"], block_reference)) + if faldo_strand: + strand_ref = self.get_reference_strand_uri(rec.id, faldo_strand, slice_block) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["includeInReferenceStrand"], sref)) + strand_ref = self.get_reference_strand_uri(None, faldo_strand, slice_block) + for sref in strand_ref: + self.graph_chunk.add((entity, self.namespace_internal["includeInStrand"], sref)) yield diff --git a/askomics/libaskomics/LocalAuth.py b/askomics/libaskomics/LocalAuth.py index a1bf0c4f..1748f29c 100644 --- a/askomics/libaskomics/LocalAuth.py +++ b/askomics/libaskomics/LocalAuth.py @@ -1070,6 +1070,9 @@ def send_mail_to_new_user(self, user): pass mailer.send_mail(user["email"], "[AskOmics{}] New account".format(asko_subtitle), body) + else: + self.log.info("Account created for user {}".format(user["username"])) + self.log.info("Link: {url}/password_reset?token={token}".format(url=self.settings.get('askomics', 'instance_url'), token=token)) def send_reset_link(self, login): """Send a reset link to a user @@ -1129,6 +1132,9 @@ def send_reset_link(self, login): pass mailer.send_mail(email, "[AskOmics{}] Password reset".format(asko_subtitle), body) + else: + self.log.info("Password reset for user {}".format(username)) + self.log.info("Link: {url}/password_reset?token={token}".format(url=self.settings.get('askomics', 'instance_url'), token=token)) def check_token(self, token): """Get username corresponding to the token @@ -1325,3 +1331,21 @@ def clear_abstraction_cache(self): tse = TriplestoreExplorer(self.app, self.session) tse.uncache_abstraction(public=True, force=True) + + def get_anonymous_user(self): + """ Return an anonymous user for queries """ + user = { + 'id': 0, + 'ldap': "", + 'fname': "", + 'lname': "", + 'username': "anonymous", + 'email': "", + 'admin': False, + 'blocked': False, + 'quota': Utils.humansize_to_bytes(self.settings.get("askomics", "quota")), + 'apikey': "", + 'galaxy': None, + 'fake': True + } + return user diff --git a/askomics/libaskomics/RdfFile.py b/askomics/libaskomics/RdfFile.py index 008bbd3b..db067986 100644 --- a/askomics/libaskomics/RdfFile.py +++ b/askomics/libaskomics/RdfFile.py @@ -79,10 +79,13 @@ def get_preview(self): head += ttl_file.readline() location = None + remote_graph = None try: location, remote_graph = self.get_location_and_remote_graph() except Exception as e: self.error_message = str(e) + # Todo: Better error management + raise e return { 'type': self.type, diff --git a/askomics/libaskomics/Result.py b/askomics/libaskomics/Result.py index d48f7725..262ad70a 100644 --- a/askomics/libaskomics/Result.py +++ b/askomics/libaskomics/Result.py @@ -9,6 +9,8 @@ from askomics.libaskomics.Params import Params from askomics.libaskomics.Utils import Utils +from pkg_resources import get_distribution + class Result(Params): """Result represent a query result file @@ -29,7 +31,7 @@ class Result(Params): results directory path """ - def __init__(self, app, session, result_info, force_no_db=False): + def __init__(self, app, session, result_info, force_no_db=False, owner=False, admin=False): """init object Parameters @@ -52,7 +54,7 @@ def __init__(self, app, session, result_info, force_no_db=False): if "id" in result_info and not force_no_db: self.id = result_info["id"] - if not self.set_info_from_db_with_id(): + if not self.set_info_from_db_with_id(owner=owner, admin=admin): return None else: self.id = result_info["id"] if "id" in result_info else None @@ -243,27 +245,36 @@ def set_celery_id(self, celery_id): """ self.celery_id = celery_id - def set_info_from_db_with_id(self): + def set_info_from_db_with_id(self, owner=False, admin=False): """Set result info from the db""" database = Database(self.app, self.session) - if "user" in self.session: + if 'user' not in self.session: + if owner: + return False query = ''' SELECT celery_id, path, graph_state, start, end, nrows, sparql_query, graphs_and_endpoints, has_form_attr, template, form FROM results - WHERE (user_id = ? OR public = ?) AND id = ? + WHERE public = ? AND id = ? ''' - - rows = database.execute_sql_query(query, (self.session["user"]["id"], True, self.id)) - + rows = database.execute_sql_query(query, (True, self.id)) else: + if admin: + select_subquery = "WHERE id = ?" + params = (self.id,) + elif owner: + select_subquery = "WHERE user_id = ? AND id = ?" + params = (self.session["user"]["id"], self.id,) + else: + select_subquery = "WHERE (user_id = ? OR public = ?) AND id = ?" + params = (self.session["user"]["id"], True, self.id,) query = ''' SELECT celery_id, path, graph_state, start, end, nrows, sparql_query, graphs_and_endpoints, has_form_attr, template, form FROM results - WHERE public = ? AND id = ? - ''' + {} + '''.format(select_subquery) - rows = database.execute_sql_query(query, (True, self.id)) + rows = database.execute_sql_query(query, params) if not rows: return False @@ -343,11 +354,14 @@ def save_result_in_file(self, headers, results): return os.path.getsize(self.file_path) - def save_in_db(self): + def save_in_db(self, start=None): """Save results file info into the database""" database = Database(self.app, self.session) - self.start = int(time.time()) + if not start: + self.start = int(time.time()) + else: + self.start = start query = ''' INSERT INTO results VALUES( @@ -369,6 +383,7 @@ def save_in_db(self): ?, ?, ?, + ?, ? ) ''' @@ -384,7 +399,8 @@ def save_in_db(self): json.dumps({"graphs": self.graphs, "endpoints": self.endpoints}), False, self.session["user"]["admin"] and any([attrib.get("form") for attrib in self.graph_state["attr"]]) if (self.graph_state and self.graph_state.get("attr")) else False, - False + False, + get_distribution('askomics').version ), get_id=True) return self.id @@ -500,21 +516,28 @@ def rollback(self): """Delete file""" self.delete_file_from_filesystem() - def delete_result(self): + def delete_result(self, admin=False): """Remove results from db and filesystem""" - self.delete_db_entry() + self.delete_db_entry(admin=admin) self.delete_file_from_filesystem() - def delete_db_entry(self): + def delete_db_entry(self, admin=False): """Delete results from db""" database = Database(self.app, self.session) + if admin: + query = ''' + DELETE FROM results + WHERE id = ? + ''' + args = (self.id,) + else: + query = ''' + DELETE FROM results + WHERE id = ? AND user_id = ? + ''' + args = (self.id, self.session["user"]["id"],) - query = ''' - DELETE FROM results - WHERE id = ? AND user_id = ? - ''' - - database.execute_sql_query(query, (self.id, self.session["user"]["id"])) + database.execute_sql_query(query, args) def delete_file_from_filesystem(self): """Remove result file from filesystem""" @@ -603,21 +626,32 @@ def form_query(self, form): database.execute_sql_query(query, sql_var) - def update_description(self, description): + def update_description(self, description, admin=False): """Change the result description""" database = Database(self.app, self.session) + if admin: + query = ''' + UPDATE results SET + description=? + WHERE id=? + ''' - query = ''' - UPDATE results SET - description=? - WHERE user_id=? AND id=? - ''' + database.execute_sql_query(query, ( + description, + self.id + )) + else: + query = ''' + UPDATE results SET + description=? + WHERE user_id=? AND id=? + ''' - database.execute_sql_query(query, ( - description, - self.session["user"]["id"], - self.id - )) + database.execute_sql_query(query, ( + description, + self.session["user"]["id"], + self.id + )) def update_graph(self, newGraph): """Change the result description""" diff --git a/askomics/libaskomics/ResultsHandler.py b/askomics/libaskomics/ResultsHandler.py index 8b9fe5ec..862a676c 100644 --- a/askomics/libaskomics/ResultsHandler.py +++ b/askomics/libaskomics/ResultsHandler.py @@ -18,7 +18,7 @@ def __init__(self, app, session): """ Params.__init__(self, app, session) - def delete_results(self, files_id): + def delete_results(self, files_id, admin=False): """Delete files Parameters @@ -32,9 +32,13 @@ def delete_results(self, files_id): list of remaining files """ for file_id in files_id: - result = Result(self.app, self.session, {"id": file_id}) - self.app.celery.control.revoke(result.celery_id, terminate=True) - result.delete_result() + result = Result(self.app, self.session, {"id": file_id}, owner=True, admin=admin) + if result.celery_id: + self.app.celery.control.revoke(result.celery_id, terminate=True) + if result.id: + result.delete_result(admin=admin) + if admin: + return self.get_admin_queries() return self.get_files_info() @@ -156,26 +160,24 @@ def get_public_form_queries(self): return queries - def get_admin_public_queries(self): - """Get id description, and owner of published queries + def get_admin_queries(self): + """Get id description, and owner of all queries Returns ------- List - List of published queries (id and description) + List of all queries (id and description) """ - sql_var = (True, ) database = Database(self.app, self.session) query = ''' SELECT results.id, results.status, results.start, results.end, results.nrows, results.public, results.description, results.size, users.username FROM results - INNER JOIN users ON results.user_id=users.user_id - WHERE results.public = ? + LEFT JOIN users ON results.user_id=users.user_id ''' - rows = database.execute_sql_query(query, sql_var) + rows = database.execute_sql_query(query) queries = [] @@ -195,6 +197,31 @@ def get_admin_public_queries(self): 'public': row[5], 'description': row[6], 'size': row[7], - 'user': row[8] + 'user': row[8] if row[8] else "anonymous" }) return queries + + def delete_older_results(self, delta, deltatype, user_id, status=None): + """Delete results older than a specific delta for a specific user_id + + Returns + ------- + List + None + """ + + database = Database(self.app, self.session) + date_str = '"%s", "now", "-{} {}"'.format(delta, deltatype) + status_substr = "" + arg_tuple = (user_id) + + if status: + status_substr = "AND status = ?" + arg_tuple = (user_id, status) + + query = ''' + DELETE FROM results + WHERE user_id = ? AND start <= strftime({}) {} + '''.format(date_str, status_substr) + + database.execute_sql_query(query, arg_tuple) diff --git a/askomics/libaskomics/SparqlQuery.py b/askomics/libaskomics/SparqlQuery.py index 57d2c29a..33c36e93 100644 --- a/askomics/libaskomics/SparqlQuery.py +++ b/askomics/libaskomics/SparqlQuery.py @@ -273,7 +273,7 @@ def toggle_public(self, graph, public): '''.format(graph=graph, public=public) query_launcher = SparqlQueryLauncher(self.app, self.session) - query_launcher.execute_query(self.prefix_query(query)) + query_launcher.execute_query(self.prefix_query(query), is_update=True) def get_default_query_with_prefix(self): """Get default query with the prefixes @@ -533,9 +533,7 @@ def get_uri_parameters(self, uri, endpoints): }} OPTIONAL {{ - ?object faldo:begin/rdf:type ?Gene1_strandCategory . - ?Gene1_strand_faldoStrand a ?Gene1_strandCategory . - ?Gene1_strand_faldoStrand rdfs:label ?faldo_value . + ?object faldo:begin/rdf:type/rdfs:label ?faldo_value . ?faldo_uri rdf:type askomics:faldoStrand . }} @@ -673,9 +671,9 @@ def get_block_ids(self, node_id): """ for node in self.json["nodes"]: if node["id"] == node_id: - return node["specialNodeId"], node["specialNodeGroupId"], node["specialPreviousIds"] + return node["specialNodeId"], node["specialNodeGroupId"], node["specialPreviousIds"], node.get("depth") - return None, None, (None, None) + return None, None, (None, None), None def triple_block_to_string(self, triple_block): """Convert a triple block to a SPARQL string @@ -713,7 +711,7 @@ def triple_block_to_string(self, triple_block): return block_string - def triple_dict_to_string(self, triple_dict): + def triple_dict_to_string(self, triple_dict): # pragma: no cover """Convert a triple dict into a triple string Parameters @@ -781,7 +779,7 @@ def get_uri_filter_value(self, value): raise ValueError("{} is not a valid URI or CURIE".format(value)) - def get_block_type(self, blockid): + def get_block_type(self, blockid): # pragma: no cover """Summary Parameters @@ -799,13 +797,17 @@ def get_block_type(self, blockid): "minusNode": "MINUS" } + # Union sub-block + if '_' in str(blockid): + return "DEFAULT" + for node in self.json["nodes"]: if node["type"] in ("unionNode", "minusNode"): if node["specialNodeId"] == blockid: return types_dict[node["type"]] return None - def store_triple(self, triple, blockid, sblockid, pblock_ids): + def store_triple(self, triple, blockid, sblockid, pblock_ids, depth): """Store a triple inthe right list Parameters @@ -818,11 +820,14 @@ def store_triple(self, triple, blockid, sblockid, pblock_ids): block info if triple is part of a block """ if blockid: - self.store_block(triple, blockid, sblockid, pblock_ids) + if depth: + self.update_block_dict(depth, "triples", triple) + else: + self.store_block(triple, blockid, sblockid, pblock_ids) else: self.triples.append(triple) - def store_filter(self, filtr, blockid, sblockid, pblock_ids): + def store_filter(self, filtr, blockid, sblockid, pblock_ids, depth): """Store a FILTER in the right list Parameters @@ -835,11 +840,14 @@ def store_filter(self, filtr, blockid, sblockid, pblock_ids): block info if triple is part of a block """ if blockid: - self.store_filter_block(filtr, blockid, sblockid) + if depth: + self.update_block_dict(depth, "filters", filtr) + else: + self.store_filter_block(filtr, blockid, sblockid) else: self.filters.append(filtr) - def store_value(self, value, blockid, sblockid, pblock_ids): + def store_value(self, value, blockid, sblockid, pblock_ids, depth): """Store a VALUES inthe right list Parameters @@ -852,11 +860,14 @@ def store_value(self, value, blockid, sblockid, pblock_ids): block info if triple is part of a block """ if blockid: - self.store_values_block(value, blockid, sblockid) + if depth: + self.update_block_dict(depth, "values", value) + else: + self.store_values_block(value, blockid, sblockid) else: self.values.append(value) - def store_values_block(self, value, blockid, sblockid): + def store_values_block(self, value, blockid, sblockid): # pragma: no cover """Add a VALUES in a block. If block exist, add the triples, else, create a new block. Same for the sub block @@ -894,7 +905,7 @@ def store_values_block(self, value, blockid, sblockid): }, ] }) - def store_filter_block(self, filtr, blockid, sblockid): + def store_filter_block(self, filtr, blockid, sblockid): # pragma: no cover """Add a FILTER in a block. If block exist, add the triples, else, create a new block. Same for the sub block @@ -932,7 +943,7 @@ def store_filter_block(self, filtr, blockid, sblockid): }, ] }) - def store_block(self, triple, blockid, sblockid, pblock_ids): + def store_block(self, triple, blockid, sblockid, pblock_ids): # pragma: no cover """Add a triple in a block. If block exist, add the triples, else, create a new block. Same for the sub block @@ -970,6 +981,25 @@ def store_block(self, triple, blockid, sblockid, pblock_ids): }, ] }) + def update_sub_block(self, block_dict, depths, type, value, current_depth): # pragma: no cover + depth = depths[current_depth] + if depth not in block_dict: + block_dict[depth] = { + "type": self.get_block_type(depth), + "triples": [], + "filters": [], + "values": [], + "sub_blocks": {} + } + # End of branch + if current_depth == len(depths) - 1: + block_dict[depth][type].append(value) + else: + self.update_sub_block(block_dict[depth]["sub_blocks"], depths, type, value, current_depth + 1) + + def update_block_dict(self, depths, type, value): # pragma: no cover + self.update_sub_block(self.triples_blocks_dict, depths, type, value, 0) + def replace_variables_in_triples(self, var_to_replace): """Replace variables in triples @@ -994,7 +1024,69 @@ def replace_variables_in_triples(self, var_to_replace): self.triples = Utils.unique(self.triples) self.selects = Utils.unique(self.selects) - def replace_variables_in_blocks(self, var_to_replace): + def replace_variables_in_sub_block(self, var_to_replace, content): # pragma: no cover + for var_source, var_target in var_to_replace: + for ntriple, triple_dict in enumerate(content["triples"]): + for key, value in triple_dict.items(): + if key not in ["optional", "nested", "nested_start", "nested_end", "form"]: + content["triples"][ntriple][key] = value.replace(var_source, var_target) + + for i, filtr in enumerate(content["filters"]): + content["filters"][i] = filtr.replace(var_source, var_target) + + for i, value in enumerate(content["values"]): + content["values"][i] = value.replace(var_source, var_target) + content["triples"] = Utils.unique(content["triples"]) + + if content['sub_blocks']: + for sub_block in content['sub_blocks'].values(): + self.replace_variables_in_sub_block(var_to_replace, sub_block) + + def replace_variables_in_blocks_dict(self, var_to_replace): # pragma: no cover + """Replace variables in blocks + + Parameters + ---------- + var_to_replace : list of tuples + var to replace in block + """ + for block in self.triples_blocks_dict.values(): + self.replace_variables_in_sub_block(var_to_replace, block) + + def triple_sub_block_to_string(self, block, indent=" "): # pragma: no cover + new_indent = indent + " " + sub_content = "" + if block['sub_blocks']: + if block["type"] == "UNION": + sub_content = "\n{}UNION ".format(new_indent).join([self.triple_sub_block_to_string(sub_block, new_indent) for sub_block in block['sub_blocks'].values()]) + elif block["type"] == "MINUS": + sub_content = "MINUS " + "\n{}MINUS ".format(indent).join([self.triple_sub_block_to_string(sub_block, new_indent) for sub_block in block['sub_blocks'].values()]) + else: + sub_content = "\n{}".format(indent).join([self.triple_sub_block_to_string(sub_block, new_indent) for sub_block in block['sub_blocks'].values()]) + + content = "{{\n{}".format(new_indent) + triples_string = '\n{}'.format(new_indent).join([self.triple_dict_to_string(triple_dict) for triple_dict in block["triples"]]) + triples_string += '\n{}'.format(new_indent) if block["filters"] else "" + triples_string += '\n{}'.format(new_indent).join([filtr for filtr in block["filters"]]) + triples_string += '\n{}'.format(new_indent) if block["values"] else "" + triples_string += '\n{}'.format(new_indent).join([value for value in block["values"]]) + content += triples_string + content += '\n{}'.format(new_indent) if sub_content and triples_string else "" + content += sub_content + + content += "\n{}}}".format(indent) + + return content + + def triple_blocks_dict_to_string(self): # pragma: no cover + return '\n '.join([self.triple_sub_block_to_string(triple_block) for triple_block in self.triples_blocks_dict.values()]) + + def blocks_to_string(self): # pragma: no cover + if self.legacy_block: + return '\n '.join([self.triple_block_to_string(triple_block) for triple_block in self.triples_blocks]) + return self.triple_blocks_dict_to_string() + + def replace_variables_in_blocks(self, var_to_replace): # pragma: no cover """Replace variables in blocks Parameters @@ -1021,7 +1113,7 @@ def replace_variables_in_blocks(self, var_to_replace): self.triples_blocks[nblock]["sblocks"][nsblock]["triples"] = Utils.unique(self.triples_blocks[nblock]["sblocks"][nsblock]["triples"]) - def get_source_of_special_node(self, special_node_id): + def get_source_of_special_node(self, special_node_id): # pragma: no cover """Get if of original node of a special one Parameters @@ -1036,8 +1128,9 @@ def get_source_of_special_node(self, special_node_id): """ for link in self.json["links"]: if link["type"] == "specialLink": - if link["source"]["id"] == special_node_id: - return link["target"]["id"] + # Source is also a special node. Get source of source + if link["source"]['type'] in ['unionNode', 'minusNode']: + return self.get_source_of_special_node(link["source"]['id']) if link["target"]["id"] == special_node_id: return link["source"]["id"] return None @@ -1062,6 +1155,7 @@ def build_query_from_json(self, preview=False, for_editor=False): self.triples = [] self.triples_blocks = [] + self.triples_blocks_dict = {} self.values = [] self.filters = [] @@ -1080,6 +1174,9 @@ def build_query_from_json(self, preview=False, for_editor=False): if attr["type"] == "uri" and attr.get("ontology", False) is True and not attr["entityUris"][0] in ontologies: ontologies[attr["entityUris"][0]] = om.get_ontology(uri=attr["entityUris"][0]) + # Check if legacy block mode (ie, stored queries) + self.legacy_block = any([entity.get('legacyBlock') for entity in self.json['nodes']]) + entities = list(set(entities)) # uniq list # Set graphs in function of entities needed @@ -1093,12 +1190,17 @@ def build_query_from_json(self, preview=False, for_editor=False): # if link is special, replace the special node variable with its real node if link["type"] == "specialLink": - special_node = link["source"] if link["source"]["type"] in ("unionNode", "minusNode") else link["target"] - real_node = link["target"] if link["source"]["type"] in ("unionNode", "minusNode") else link["source"] + special_node = link["target"] + real_node = link["source"] + real_node_id = real_node['id'] + + # Both end are special nodes. + if real_node['type'] in ['minusNode', 'unionNode']: + real_node_id = self.get_source_of_special_node(real_node_id) var_to_replace.append(( self.format_sparql_variable("{}{}_uri".format(special_node["label"], special_node["id"])), - self.format_sparql_variable("{}{}_uri".format(real_node["label"], real_node["id"])) + self.format_sparql_variable("{}{}_uri".format(real_node["label"], real_node_id)) )) continue @@ -1110,13 +1212,18 @@ def build_query_from_json(self, preview=False, for_editor=False): block_id = None sblock_id = None pblock_ids = (None, None) + depth = None if link["source"]["specialNodeId"] or link["target"]["specialNodeId"]: block_id = link["source"]["specialNodeId"] sblock_id = link["source"]["specialNodeGroupId"] if link["source"]["specialNodeGroupId"] else link["target"]["specialNodeGroupId"] pblock_ids = link["source"]["specialPreviousIds"] + # Correct depth is the longest one + depth = link["target"].get("depth", []) + if len(link["source"].get("depth", [])) > len(depth): + depth = link["source"].get("depth", []) # Position - if link["uri"] in ('included_in', 'overlap_with'): + if link["uri"] in ('included_in', 'overlap_with', 'distance_from'): # If source of target is a special node, replace the id with the id of the concerned node source_id = link["source"]["id"] @@ -1138,9 +1245,6 @@ def build_query_from_json(self, preview=False, for_editor=False): if attr["faldo"].endswith("faldoEnd"): start_end.append(attr["id"]) end_1 = self.format_sparql_variable("{}{}_{}".format(attr["entityLabel"], attr["nodeId"], attr["label"])) - if attr["faldo"].endswith("faldoStrand"): - strand_1 = self.format_sparql_variable("{}{}_{}_faldoStrand".format(attr["entityLabel"], attr["nodeId"], attr["label"])) - strands.append(attr["id"]) if attr["nodeId"] == target_id: if attr["faldo"].endswith("faldoStart"): start_end.append(attr["id"]) @@ -1148,30 +1252,31 @@ def build_query_from_json(self, preview=False, for_editor=False): if attr["faldo"].endswith("faldoEnd"): start_end.append(attr["id"]) end_2 = self.format_sparql_variable("{}{}_{}".format(attr["entityLabel"], attr["nodeId"], attr["label"])) - if attr["faldo"].endswith("faldoStrand"): - strand_2 = self.format_sparql_variable("{}{}_{}_faldoStrand".format(attr["entityLabel"], attr["nodeId"], attr["label"])) - strands.append(attr["id"]) - self.store_triple({ - "subject": source, - "predicate": "askomics:{}".format("includeInReference" if link["sameRef"] else "includeIn"), - "object": common_block, - "optional": False + block_uri = "includeIn" + if link["sameRef"]: + block_uri = "includeInReference" + if link["sameStrand"]: + block_uri = "includeInReferenceStrand" + elif link["sameStrand"]: + block_uri = "includeInStrand" - }, block_id, sblock_id, pblock_ids) + if link["uri"] in ('included_in', 'overlap_with'): + self.store_triple({ + "subject": source, + "predicate": "askomics:{}".format(block_uri), + "object": common_block, + "optional": False - self.store_triple({ - "subject": target, - "predicate": "askomics:{}".format("includeInReference" if link["sameRef"] else "includeIn"), - "object": common_block, - "optional": False + }, block_id, sblock_id, pblock_ids, depth) - }, block_id, sblock_id, pblock_ids) + self.store_triple({ + "subject": target, + "predicate": "askomics:{}".format(block_uri), + "object": common_block, + "optional": False - if link["sameStrand"]: - var_to_replace.append((strand_1, strand_2)) - else: - strands = [] + }, block_id, sblock_id, pblock_ids, depth) equal_sign = "" if link["strict"] else "=" @@ -1182,16 +1287,77 @@ def build_query_from_json(self, preview=False, for_editor=False): end1=end_1, end2=end_2, equalsign=equal_sign - ), block_id, sblock_id, pblock_ids) + ), block_id, sblock_id, pblock_ids, depth) elif link["uri"] == "overlap_with": - self.store_filter("FILTER (({start2} >{equalsign} {start1} && {start2} <{equalsign} {end1}) || ({end2} >{equalsign} {start1} && {end2} <{equalsign} {end1}))".format( + self.store_filter("FILTER (({start2} >{equalsign} {start1} && {start2} <{equalsign} {end1}) || ({end2} >{equalsign} {start1} && {end2} <{equalsign} {end1}) || ({start1} >{equalsign} {start2} && {end1} <{equalsign} {end2}))".format( start1=start_1, start2=start_2, end1=end_1, end2=end_2, equalsign=equal_sign - ), block_id, sblock_id, pblock_ids) + ), block_id, sblock_id, pblock_ids, depth) + else: + if link["sameRef"]: + if link['sameStrand']: + self.store_triple({ + "subject": source, + "predicate": "askomics:referenceStrand", + "object": common_block, + "optional": False + + }, block_id, sblock_id, pblock_ids, depth) + + self.store_triple({ + "subject": target, + "predicate": "askomics:referenceStrand", + "object": common_block, + "optional": False + + }, block_id, sblock_id, pblock_ids, depth) + else: + self.store_triple({ + "subject": source, + "predicate": "askomics:faldoReference", + "object": common_block, + "optional": False + + }, block_id, sblock_id, pblock_ids, depth) + + self.store_triple({ + "subject": target, + "predicate": "askomics:faldoReference", + "object": common_block, + "optional": False + + }, block_id, sblock_id, pblock_ids, depth) + + elif link["sameStrand"]: + self.store_triple({ + "subject": source, + "predicate": "askomics:faldoStrand", + "object": common_block, + "optional": False + + }, block_id, sblock_id, pblock_ids, depth) + + self.store_triple({ + "subject": target, + "predicate": "askomics:faldoStrand", + "object": common_block, + "optional": False + + }, block_id, sblock_id, pblock_ids, depth) + + for filter in link.get('faldoFilters', []): + modifier_string = "" + if filter['filterValue']: + modifier_string = " {} {}".format(filter['filterModifier'], filter['filterValue']) + + start = start_1 if filter['filterStart'] == "start" else end_1 + end = start_2 if filter['filterEnd'] == "start" else end_2 + filter_string = "FILTER ( {} {} {} {} ) .".format(start, filter['filterSign'], end, modifier_string) + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) # Classic relation else: @@ -1216,7 +1382,8 @@ def build_query_from_json(self, preview=False, for_editor=False): "optional": False } - self.store_triple(triple, block_id, sblock_id, pblock_ids) + if not link.get('indirect', False): + self.store_triple(triple, block_id, sblock_id, pblock_ids, depth) # Store linked attributes for attribute in self.json["attr"]: @@ -1225,13 +1392,13 @@ def build_query_from_json(self, preview=False, for_editor=False): "entity_label": attribute["entityLabel"], "entity_id": attribute["nodeId"] } - if attribute["linked"]: + if attribute["linked"] and attribute["linkedWith"]: linked_attributes.extend((attribute["id"], attribute["linkedWith"])) # Browse attributes for attribute in self.json["attr"]: # Get blockid and sblockid of the attribute node - block_id, sblock_id, pblock_ids = self.get_block_ids(attribute["nodeId"]) + block_id, sblock_id, pblock_ids, depth = self.get_block_ids(attribute["nodeId"]) # URI --- if attribute["type"] == "uri": @@ -1244,14 +1411,14 @@ def build_query_from_json(self, preview=False, for_editor=False): "predicate": predicate, "object": obj, "optional": False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute.get("ontology", False) is True: self.store_triple({ "subject": subject, "predicate": predicate, "object": "owl:Class", "optional": False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.selects.append(subject) @@ -1262,14 +1429,14 @@ def build_query_from_json(self, preview=False, for_editor=False): negative_sign = "" if attribute["negative"]: negative_sign = "!" - self.store_filter("FILTER ({}regex({}, {}, 'i'))".format(negative_sign, subject, filter_value), block_id, sblock_id, pblock_ids) + self.store_filter("FILTER ({}regex({}, {}, 'i'))".format(negative_sign, subject, filter_value), block_id, sblock_id, pblock_ids, depth) elif attribute["filterType"] == "exact": if attribute["negative"]: - self.store_filter("FILTER (str({}) != {}) .".format(subject, filter_value), block_id, sblock_id, pblock_ids) + self.store_filter("FILTER (str({}) != {}) .".format(subject, filter_value), block_id, sblock_id, pblock_ids, depth) else: - self.store_value("VALUES {} {{ {} }} .".format(subject, filter_value), block_id, sblock_id, pblock_ids) + self.store_value("VALUES {} {{ {} }} .".format(subject, filter_value), block_id, sblock_id, pblock_ids, depth) - if attribute["linked"]: + if attribute["linked"] and attribute["linkedWith"]: var_2 = self.format_sparql_variable("{}{}_uri".format( attributes[attribute["linkedWith"]]["entity_label"], attributes[attribute["linkedWith"]]["entity_id"] @@ -1287,7 +1454,7 @@ def build_query_from_json(self, preview=False, for_editor=False): "predicate": predicate, "object": obj, "optional": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.selects.append(obj) @@ -1304,14 +1471,18 @@ def build_query_from_json(self, preview=False, for_editor=False): uri_val_list.append(bool_value) if uri_val_list: - self.store_value("VALUES {} {{ {} }}".format(value_var, ' '.join(uri_val_list)), block_id, sblock_id, pblock_ids) - if attribute["linked"]: + self.store_value("VALUES {} {{ {} }}".format(value_var, ' '.join(uri_val_list)), block_id, sblock_id, pblock_ids, depth) + if attribute["linked"] and attribute["linkedWith"]: var_2 = self.format_sparql_variable("{}{}_{}".format( attributes[attribute["linkedWith"]]["entity_label"], attributes[attribute["linkedWith"]]["entity_id"], attributes[attribute["linkedWith"]]["label"] )) - var_to_replace.append((obj, var_2)) + if not attribute.get('linkedNegative', False): + var_to_replace.append((obj, var_2)) + else: + filter_string = "FILTER ( {} {} {} ) .".format(obj, "!=", var_2) + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) # Text if attribute["type"] == "text": @@ -1331,7 +1502,7 @@ def build_query_from_json(self, preview=False, for_editor=False): "predicate": predicate, "object": obj, "optional": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.selects.append(obj) # filters/values @@ -1340,19 +1511,27 @@ def build_query_from_json(self, preview=False, for_editor=False): negative_sign = "" if attribute["negative"]: negative_sign = "!" - self.store_filter("FILTER ({}regex({}, '{}', 'i'))".format(negative_sign, obj, attribute["filterValue"]), block_id, sblock_id, pblock_ids) + self.store_filter("FILTER ({}regex({}, '{}', 'i'))".format(negative_sign, obj, attribute["filterValue"]), block_id, sblock_id, pblock_ids, depth) elif attribute["filterType"] == "exact": if attribute["negative"]: - self.store_filter("FILTER (str({}) != '{}') .".format(obj, attribute["filterValue"]), block_id, sblock_id, pblock_ids) + self.store_filter("FILTER (str({}) != '{}') .".format(obj, attribute["filterValue"]), block_id, sblock_id, pblock_ids, depth) else: - self.store_value("VALUES {} {{ '{}' }} .".format(obj, attribute["filterValue"]), block_id, sblock_id, pblock_ids) - if attribute["linked"]: + self.store_value("VALUES {} {{ '{}' }} .".format(obj, attribute["filterValue"]), block_id, sblock_id, pblock_ids, depth) + if attribute["linked"] and attribute["linkedWith"]: var_2 = self.format_sparql_variable("{}{}_{}".format( attributes[attribute["linkedWith"]]["entity_label"], attributes[attribute["linkedWith"]]["entity_id"], attributes[attribute["linkedWith"]]["label"] )) - var_to_replace.append((obj, var_2)) + if not (attribute.get('linkedNegative', False) or attribute.get('linkedFilterValue')): + var_to_replace.append((obj, var_2)) + else: + filter = "!" if attribute.get('linkedNegative', False) else "" + regex_clause = "{} = {}".format(obj, var_2) + if attribute.get('linkedFilterValue'): + regex_clause = r"REGEX({}, REPLACE('{}', '\\$1', {}), 'i')".format(obj, attribute.get('linkedFilterValue', "$1"), var_2) + filter_string = "FILTER ( {} {} ) .".format(filter, regex_clause) + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) # Numeric if attribute["type"] == "decimal": @@ -1360,6 +1539,9 @@ def build_query_from_json(self, preview=False, for_editor=False): subject = self.format_sparql_variable("{}{}_uri".format(attribute["entityLabel"], attribute["nodeId"])) if attribute["faldo"]: predicate = "faldo:location/faldo:{}/faldo:position".format("begin" if attribute["faldo"].endswith("faldoStart") else "end") + # Use faldo shortcut for faldo queries + if attribute["id"] in start_end or attribute["id"] in linked_attributes: + predicate = "askomics:{}".format("faldoBegin" if attribute["faldo"].endswith("faldoStart") else "faldoEnd") else: predicate = "<{}>".format(attribute["uri"]) obj = self.format_sparql_variable("{}{}_{}".format(attribute["entityLabel"], attribute["nodeId"], attribute["label"])) @@ -1368,24 +1550,32 @@ def build_query_from_json(self, preview=False, for_editor=False): "predicate": predicate, "object": obj, "optional": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.selects.append(obj) # filters for filtr in attribute["filters"]: if filtr["filterValue"] != "" and not attribute["optional"] and not attribute["linked"]: if filtr['filterSign'] == "=": - self.store_value("VALUES {} {{ {} }} .".format(obj, filtr["filterValue"]), block_id, sblock_id, pblock_ids) + self.store_value("VALUES {} {{ {} }} .".format(obj, filtr["filterValue"]), block_id, sblock_id, pblock_ids, depth) else: filter_string = "FILTER ( {} {} {} ) .".format(obj, filtr["filterSign"], filtr["filterValue"]) - self.store_filter(filter_string, block_id, sblock_id, pblock_ids) - if attribute["linked"]: + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) + if attribute["linked"] and attribute["linkedWith"]: var_2 = self.format_sparql_variable("{}{}_{}".format( attributes[attribute["linkedWith"]]["entity_label"], attributes[attribute["linkedWith"]]["entity_id"], attributes[attribute["linkedWith"]]["label"] )) - var_to_replace.append((obj, var_2)) + if any([filter['filterSign'] == "=" and not filter['filterValue'] for filter in attribute.get('linkedFilters', [])]): + var_to_replace.append((obj, var_2)) + else: + for filter in attribute.get('linkedFilters', []): + modifier_string = "" + if filter['filterValue']: + modifier_string = " {} {}".format(filter['filterModifier'], filter['filterValue']) + filter_string = "FILTER ( {} {} {} {} ) .".format(obj, filter['filterSign'], var_2, modifier_string) + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) if attribute["type"] == "date": if attribute["visible"] or Utils.check_key_in_list_of_dict(attribute["filters"], "filterValue") or attribute["id"] in linked_attributes: @@ -1397,7 +1587,7 @@ def build_query_from_json(self, preview=False, for_editor=False): "predicate": predicate, "object": obj, "optional": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.selects.append(obj) # filters @@ -1406,25 +1596,35 @@ def build_query_from_json(self, preview=False, for_editor=False): # COnvert datetime to date val = filtr["filterValue"].split("T")[0] if filtr['filterSign'] == "=": - self.store_value("VALUES {} {{ '{}'^^xsd:date }} .".format(obj, val), block_id, sblock_id, pblock_ids) + self.store_value("VALUES {} {{ '{}'^^xsd:date }} .".format(obj, val), block_id, sblock_id, pblock_ids, depth) else: filter_string = "FILTER ( {} {} '{}'^^xsd:date ) .".format(obj, filtr["filterSign"], val) - self.store_filter(filter_string, block_id, sblock_id, pblock_ids) - if attribute["linked"]: + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) + if attribute["linked"] and attribute["linkedWith"]: var_2 = self.format_sparql_variable("{}{}_{}".format( attributes[attribute["linkedWith"]]["entity_label"], attributes[attribute["linkedWith"]]["entity_id"], attributes[attribute["linkedWith"]]["label"] )) - var_to_replace.append((obj, var_2)) - + if any([filter['filterSign'] == "=" and not filter['filterValue'] for filter in attribute.get('linkedFilters', [])]): + var_to_replace.append((obj, var_2)) + else: + for filter in attribute.get('linkedFilters', []): + modifier_string = "" + if filter['filterValue']: + # Issue with virtuoso: engine-specific syntax for now (convert days to seconds) + if self.settings.get('triplestore', 'triplestore') == "virtuoso": + modifier_string = " {} {}".format(filter['filterModifier'], 24 * 3600 * int(filter['filterValue'])) + else: + modifier_string = ' {} "P{}D"xsd:duration'.format(filter['filterModifier'], filter['filterValue']) + filter_string = "FILTER ( {} {} {} {} ) .".format(obj, filter['filterSign'], var_2, modifier_string) + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) # Category if attribute["type"] == "category": if attribute["visible"] or attribute["filterSelectedValues"] != [] or attribute["id"] in strands or attribute["id"] in linked_attributes: node_uri = self.format_sparql_variable("{}{}_uri".format(attribute["entityLabel"], attribute["nodeId"])) category_value_uri = self.format_sparql_variable("{}{}_{}Category".format(attribute["entityLabel"], attribute["nodeId"], attribute["label"])) category_label = self.format_sparql_variable("{}{}_{}".format(attribute["entityLabel"], attribute["humanNodeId"], attribute["label"])) - faldo_strand = self.format_sparql_variable("{}{}_{}_faldoStrand".format(attribute["entityLabel"], attribute["nodeId"], attribute["label"])) if attribute["faldo"] and attribute["faldo"].endswith("faldoReference"): category_name = 'faldo:location/faldo:begin/faldo:reference' self.store_triple({ @@ -1433,7 +1633,7 @@ def build_query_from_json(self, preview=False, for_editor=False): "object": category_value_uri, "optional": True if attribute["optional"] else False, "nested_start": True if (attribute["optional"] and attribute["visible"]) else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.store_triple({ "subject": category_value_uri, @@ -1441,29 +1641,24 @@ def build_query_from_json(self, preview=False, for_editor=False): "object": category_label, "optional": True if attribute["optional"] else False, "nested_end": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) elif attribute["faldo"] and attribute["faldo"].endswith("faldoStrand"): category_name = 'faldo:location/faldo:begin/rdf:type' self.store_triple({ "subject": node_uri, "predicate": category_name, "object": category_value_uri, - "optional": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) - self.store_triple({ - "subject": faldo_strand, - "predicate": "a", - "object": category_value_uri, - "optional": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) + "optional": True if attribute["optional"] else False, + "nested_start": True if (attribute["optional"] and attribute["visible"]) else False + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.store_triple({ - "subject": faldo_strand, + "subject": category_value_uri, "predicate": "rdfs:label", "object": category_label, - "optional": False - }, block_id, sblock_id, pblock_ids) - self.store_value("VALUES {} {{ faldo:ReverseStrandPosition faldo:ForwardStrandPosition faldo:BothStrandPosition}} .".format(category_value_uri), block_id, sblock_id, pblock_ids) + "optional": True if attribute["optional"] else False, + "nested_end": True if attribute["optional"] else False + }, block_id, sblock_id, pblock_ids, depth) else: category_name = "<{}>".format(attribute["uri"]) self.store_triple({ @@ -1472,7 +1667,7 @@ def build_query_from_json(self, preview=False, for_editor=False): "object": category_value_uri, "optional": True if attribute["optional"] else False, "nested_start": True if (attribute["optional"] and attribute["visible"]) else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.store_triple({ "subject": category_value_uri, @@ -1480,32 +1675,34 @@ def build_query_from_json(self, preview=False, for_editor=False): "object": category_label, "optional": True if attribute["optional"] else False, "nested_end": True if attribute["optional"] else False - }, block_id, sblock_id, pblock_ids) + }, block_id, sblock_id, pblock_ids, depth) if attribute["visible"]: self.selects.append(category_label) # values if attribute["filterSelectedValues"] != [] and not attribute["optional"] and not attribute["linked"]: uri_val_list = [] - if attribute["faldo"] and attribute["faldo"].endswith("faldoStrand"): - value_var = faldo_strand - else: - value_var = category_value_uri + value_var = category_value_uri uri_val_list = ["<{}>".format(value) for value in attribute["filterSelectedValues"]] if uri_val_list: if attribute["exclude"]: filter_string = "FILTER ( {} NOT IN ( {} ) ) .".format(value_var, " ,".join(uri_val_list)) - self.store_filter(filter_string, block_id, sblock_id, pblock_ids) + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) else: - self.store_value("VALUES {} {{ {} }}".format(value_var, ' '.join(uri_val_list)), block_id, sblock_id, pblock_ids) + self.store_value("VALUES {} {{ {} }}".format(value_var, ' '.join(uri_val_list)), block_id, sblock_id, pblock_ids, depth) - if attribute["linked"]: + if attribute["linked"] and attribute["linkedWith"]: var_2 = self.format_sparql_variable("{}{}_{}Category".format( attributes[attribute["linkedWith"]]["entity_label"], attributes[attribute["linkedWith"]]["entity_id"], attributes[attribute["linkedWith"]]["label"] )) - var_to_replace.append((category_value_uri, var_2)) + + if not attribute.get('linkedNegative', False): + var_to_replace.append((category_value_uri, var_2)) + else: + filter_string = "FILTER ( {} {} {} ) .".format(category_value_uri, "!=", var_2) + self.store_filter(filter_string, block_id, sblock_id, pblock_ids, depth) from_string = "" if self.settings.getboolean("askomics", "single_tenant", fallback=False) else self.get_froms_from_graphs(self.graphs) federated_from_string = self.get_federated_froms_from_graphs(self.graphs) @@ -1515,9 +1712,9 @@ def build_query_from_json(self, preview=False, for_editor=False): # Linked attributes: replace SPARQL variable target by source self.replace_variables_in_blocks(var_to_replace) self.replace_variables_in_triples(var_to_replace) + self.replace_variables_in_blocks_dict(var_to_replace) # Write the query - # query is for editor (no froms, no federated) if for_editor: query = """ @@ -1531,7 +1728,7 @@ def build_query_from_json(self, preview=False, for_editor=False): """.format( selects=' '.join(self.selects), triples='\n '.join([self.triple_dict_to_string(triple_dict) for triple_dict in self.triples]), - blocks='\n '.join([self.triple_block_to_string(triple_block) for triple_block in self.triples_blocks]), + blocks=self.blocks_to_string(), filters='\n '.join(self.filters), values='\n '.join(self.values)) @@ -1555,7 +1752,7 @@ def build_query_from_json(self, preview=False, for_editor=False): remote_graphs=federated_graphs_string, selects=' '.join(self.selects), triples='\n '.join([self.triple_dict_to_string(triple_dict) for triple_dict in self.triples]), - blocks='\n '.join([self.triple_block_to_string(triple_block) for triple_block in self.triples_blocks]), + blocks=self.blocks_to_string(), filters='\n '.join(self.filters), values='\n '.join(self.values) ) @@ -1575,7 +1772,7 @@ def build_query_from_json(self, preview=False, for_editor=False): selects=' '.join(self.selects), froms=from_string, triples='\n '.join([self.triple_dict_to_string(triple_dict) for triple_dict in self.triples]), - blocks='\n '.join([self.triple_block_to_string(triple_block) for triple_block in self.triples_blocks]), + blocks=self.blocks_to_string(), filters='\n '.join(self.filters), values='\n '.join(self.values)) @@ -1592,7 +1789,7 @@ def build_query_from_json(self, preview=False, for_editor=False): """.format( selects=' '.join(self.selects), triples='\n '.join([self.triple_dict_to_string(triple_dict) for triple_dict in self.triples]), - blocks='\n '.join([self.triple_block_to_string(triple_block) for triple_block in self.triples_blocks]), + blocks=self.blocks_to_string(), filters='\n '.join(self.filters), values='\n '.join(self.values)) diff --git a/askomics/libaskomics/SparqlQueryLauncher.py b/askomics/libaskomics/SparqlQueryLauncher.py index 64fe2802..848ba897 100644 --- a/askomics/libaskomics/SparqlQueryLauncher.py +++ b/askomics/libaskomics/SparqlQueryLauncher.py @@ -163,7 +163,7 @@ def load_data_virtuoso(self, file_name, graph, host_url): ) query = "LOAD <{}> INTO GRAPH <{}>".format(file_url, graph) - return self.execute_query(query) + return self.execute_query(query, is_update=True) def get_triples_from_graph(self, graph): """Get triples from a rdflib graph @@ -206,7 +206,7 @@ def insert_ttl_string(self, ttl_string, graph): }} '''.format(graph, ttl_string) - return self.execute_query(query) + return self.execute_query(query, is_update=True) def insert_data(self, ttl, graph, metadata=False): """Insert data into the triplesotre using INSERT @@ -235,7 +235,7 @@ def insert_data(self, ttl, graph, metadata=False): }} '''.format(graph, triples) - return self.execute_query(query) + return self.execute_query(query, is_update=True) def drop_dataset(self, graph): """Drop the datasets of the triplestore and its metadata @@ -248,9 +248,9 @@ def drop_dataset(self, graph): query = ''' DROP SILENT GRAPH <{}> '''.format(graph) - self.execute_query(query, disable_log=True, isql_api=True) + self.execute_query(query, disable_log=True, isql_api=True, is_update=True) - def process_query(self, query, isql_api=False): + def process_query(self, query, isql_api=False, is_update=False): """Execute a query and return parsed results Parameters @@ -263,9 +263,9 @@ def process_query(self, query, isql_api=False): list Parsed results """ - return self.parse_results(self.execute_query(query, isql_api=isql_api)) + return self.parse_results(self.execute_query(query, isql_api=isql_api, is_update=is_update)) - def execute_query(self, query, disable_log=False, isql_api=False): + def execute_query(self, query, disable_log=False, isql_api=False, is_update=False): """Execute a sparql query Parameters @@ -299,7 +299,7 @@ def execute_query(self, query, disable_log=False, isql_api=False): if use_isql: formatted_query = "SPARQL {}".format(query) - json = {"command": formatted_query, "disable_log": disable_log, "sparql_select": not self.endpoint.isSparqlUpdateRequest()} + json = {"command": formatted_query, "disable_log": disable_log, "sparql_select": not is_update} response = requests.post(url=isql_api_url, json=json) results = response.json() if results["status"] == 500: @@ -307,16 +307,17 @@ def execute_query(self, query, disable_log=False, isql_api=False): else: # Update - if self.endpoint.isSparqlUpdateRequest(): - self.endpoint.setMethod('POST') - # Virtuoso hack - # if self.triplestore == 'virtuoso': - # self.endpoint.queryType = "SELECT" - + self.endpoint.setMethod('POST') + if is_update: + # Force sending to secure endpoint + self.endpoint.queryType = "INSERT" results = self.endpoint.query() + # Select else: self.endpoint.setReturnFormat(JSON) + # Force sending to public endpoint + self.endpoint.queryType = "SELECT" results = self.endpoint.query().convert() self.query_time = time.time() - start_time diff --git a/askomics/libaskomics/Start.py b/askomics/libaskomics/Start.py index 2905de3c..40697226 100644 --- a/askomics/libaskomics/Start.py +++ b/askomics/libaskomics/Start.py @@ -38,6 +38,7 @@ def start(self): """ self.create_data_directory() self.create_database() + self.create_anonymous() def create_data_directory(self): """Create the data directory if it not exists @@ -50,3 +51,15 @@ def create_database(self): """ database = Database(self.app, self.session) database.init_database() + + def create_anonymous(self): + """Create anonymous data folder if required + """ + if self.settings.get('askomics', 'anonymous_query', fallback=False): + data_path = "{}/{}_{}/results".format( + self.data_directory, + "0", + "anonymous" + ) + if not os.path.isdir(data_path): + os.makedirs(data_path) diff --git a/askomics/libaskomics/TriplestoreExplorer.py b/askomics/libaskomics/TriplestoreExplorer.py index ced8a54e..b62b5131 100644 --- a/askomics/libaskomics/TriplestoreExplorer.py +++ b/askomics/libaskomics/TriplestoreExplorer.py @@ -519,7 +519,7 @@ def get_abstraction_relations(self, single_tenant=False): query_builder = SparqlQuery(self.app, self.session) query = ''' - SELECT DISTINCT ?graph ?entity_uri ?entity_faldo ?entity_label ?attribute_uri ?attribute_faldo ?attribute_label ?attribute_range ?property_uri ?property_faldo ?property_label ?range_uri ?category_value_uri ?category_value_label + SELECT DISTINCT ?graph ?entity_uri ?entity_faldo ?entity_label ?attribute_uri ?attribute_faldo ?attribute_label ?attribute_range ?property_uri ?property_faldo ?property_label ?range_uri ?category_value_uri ?category_value_label ?indirect_relation WHERE {{ # Graphs ?graph askomics:public ?public . @@ -530,6 +530,7 @@ def get_abstraction_relations(self, single_tenant=False): ?node a askomics:AskomicsRelation . ?node rdfs:label ?property_label . ?node rdfs:range ?range_uri . + OPTIONAL {{ ?node askomics:isIndirectRelation ?indirect_relation . }} # Retrocompatibility OPTIONAL {{?node askomics:uri ?new_property_uri}} BIND( IF(isBlank(?node), ?new_property_uri, ?node) as ?property_uri) @@ -563,7 +564,8 @@ def get_abstraction_relations(self, single_tenant=False): "label": result["property_label"], "graphs": [result["graph"], ], "source": result["entity_uri"], - "target": result["range_uri"] + "target": result["range_uri"], + "indirect": result.get("indirect_relation", False) } relations.append(relation) else: diff --git a/askomics/libaskomics/Utils.py b/askomics/libaskomics/Utils.py index 57eb14ee..bf0f6014 100644 --- a/askomics/libaskomics/Utils.py +++ b/askomics/libaskomics/Utils.py @@ -33,7 +33,7 @@ def redo_if_failure(logger, max_redo, sleep_time, call, *args): break except Exception as e: if i == max_redo: - raise(e) + raise e traceback.print_exc(file=sys.stdout) logger.debug("Fail to execute {}. Retrying in {} sec...".format(call.__name__, sleep_time)) time.sleep(sleep_time) diff --git a/askomics/react/src/contact.jsx b/askomics/react/src/contact.jsx new file mode 100644 index 00000000..2b214808 --- /dev/null +++ b/askomics/react/src/contact.jsx @@ -0,0 +1,28 @@ +import React, { Component } from 'react' +import { Link } from 'react-router-dom' +import { Collapse, Navbar, NavbarBrand, Nav, NavItem } from 'reactstrap' +import PropTypes from 'prop-types' +import Template from './components/template' + +export default class Contact extends Component { + constructor (props) { + super(props) + console.log("test") + } + + render () { + return ( +
+

Contact

+
+
+