diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 563864d2..00000000 --- a/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.git -__pycache__ -*.egg-info diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..ef0a64be --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: build + +on: + push: + pull_request: + schedule: + - cron: "0 4 * * *" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Poetry + run: pipx install poetry + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + cache: poetry + + - name: Install dependencies + run: poetry install + + # - name: Test + # run: poetry run pytest + + - name: Build + run: poetry run mkdocs build + + - if: ${{ github.ref == 'refs/heads/main' }} + name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./site + #cname: python.cz diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 328f09fe..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Main -on: - push: - pull_request: - schedule: - - cron: "0 4 * * *" -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.9 - uses: actions/setup-python@v2 - with: - python-version: 3.9 - - name: Install dependencies - run: | - python -m pip install --upgrade pipenv - pipenv install --dev - - name: Test - run: pipenv run test - - if: ${{ github.event_name == 'pull_request' }} - name: Build without fetching GitHub Issues - run: | - export DISABLE_GITHUB_ISSUES_FETCH=true - pipenv run build - - if: ${{ github.event_name != 'pull_request' }} - name: Build with fetching GitHub Issues - run: pipenv run build - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: ${{ github.ref == 'refs/heads/master' }} - name: Deploy - run: pipenv run deploy - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 01d66724..9fb3d8d4 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,10 @@ pip-log.txt .cache .pytest_cache/ -# Elsa -_build/ -/talks-archive/ +# MkDocs +/site/ + +# custom +.events_cache.json +overrides/events.ics +/talks_archive/ diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 6d9cd7a5..00000000 --- a/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -# This Dockerfile allows you to run python.cz website easily and without -# issues with dependencies - locally, on your server or in cloud like now.sh. -# That's handy for testing or for demonstration of new feature in a pull request. -# -# For running the website locally: -# -# docker build -t python.cz . -# docker run -p 8000:8000 python.cz -# -# ...and open in your browser: http://localhost:8000 -# -# Environment variables can be specified too> -# -# docker run -p 8000:8000 -e GITHUB_TOKEN=token123 python.cz - -FROM python:3.7-alpine - -RUN python3 -m venv /venv -RUN /venv/bin/pip install gunicorn pipenv -WORKDIR /app -COPY . ./ -RUN /venv/bin/pipenv install - -EXPOSE 8000 - -CMD [ \ - "/venv/bin/gunicorn", \ - "--bind", "0.0.0.0:8000", \ - "--workers", "4", \ - "pythoncz:app" \ -] diff --git a/LICENSE b/LICENSE index feca57bc..95958e53 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Honza Javorek +Copyright (c) 2013-2023 Honza Javorek and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 04accafe..00000000 --- a/Pipfile +++ /dev/null @@ -1,32 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[scripts] -test = "python -m pytest ./tests --cov=pythoncz --tb=native" -serve = "python runserver.py serve" -build = "python runserver.py freeze" -deploy = "python runserver.py deploy --no-freeze --push" - -[packages] -elsa = "*" -flask = "*" -frozen-flask = "*" -requests = "*" -czech-sort = "*" -pyyaml = "*" -python-slugify = "*" -ics = "*" -arrow = "*" -lxml = "*" -cssselect = "*" -cachelib = "*" - -[dev-packages] -pytest = "*" -pytest-cov = "*" -responses = "*" - -[requires] -python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 35430184..00000000 --- a/Pipfile.lock +++ /dev/null @@ -1,578 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "20648e54d177f143b9e290844e848fc215f941f5d55a19bdea39cceb3fa3c8a0" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.9" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "arrow": { - "hashes": [ - "sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1", - "sha256:5a49ab92e3b7b71d96cd6bfcc4df14efefc9dfa96ea19045815914a6ab6b1fe2" - ], - "index": "pypi", - "version": "==1.2.3" - }, - "attrs": { - "hashes": [ - "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6", - "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c" - ], - "markers": "python_version >= '3.5'", - "version": "==22.1.0" - }, - "cachelib": { - "hashes": [ - "sha256:38222cc7c1b79a23606de5c2607f4925779e37cdcea1c2ad21b8bae94b5425a5", - "sha256:811ceeb1209d2fe51cd2b62810bd1eccf70feba5c52641532498be5c675493b3" - ], - "index": "pypi", - "version": "==0.9.0" - }, - "certifi": { - "hashes": [ - "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", - "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" - ], - "markers": "python_version >= '3.6'", - "version": "==2022.12.7" - }, - "charset-normalizer": { - "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.1" - }, - "click": { - "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" - ], - "markers": "python_version >= '3.7'", - "version": "==8.1.3" - }, - "cssselect": { - "hashes": [ - "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc", - "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e" - ], - "index": "pypi", - "version": "==1.2.0" - }, - "czech-sort": { - "hashes": [ - "sha256:340bd050ef536ffcdd938fd162e39542964f65ceb4a08320fbf54d14c22121ec" - ], - "index": "pypi", - "version": "==1.0.1" - }, - "elsa": { - "hashes": [ - "sha256:caa4f03d1060c3ef960d25ad45d4548c6b937fe47aa3ff408f21fcd68dbe9db1", - "sha256:e0cb4c504e12e9f9e00486aa48ea549ebc2b46d93a175758a62f5644f2562355" - ], - "index": "pypi", - "version": "==0.1.6" - }, - "flask": { - "hashes": [ - "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b", - "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526" - ], - "index": "pypi", - "version": "==2.2.2" - }, - "frozen-flask": { - "hashes": [ - "sha256:4113638baebb348e16b10b12cbd88bddc7309f24d94332a18ae6a56c8ac02d3d", - "sha256:6d892fd929f6676c3270b7d91d86a1fc03c9850dc21e3b02b3946381c48ab307" - ], - "index": "pypi", - "version": "==0.18" - }, - "ghp-import": { - "hashes": [ - "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", - "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343" - ], - "version": "==2.1.0" - }, - "ics": { - "hashes": [ - "sha256:5fcf4d29ec6e7dfcb84120abd617bbba632eb77b097722b7df70e48dbcf26103", - "sha256:6743539bca10391635249b87d74fcd1094af20b82098bebf7c7521df91209f05", - "sha256:da352bdf8418619dc93611e6d251f3cefbb42664777f6e00b580a722098124b7" - ], - "index": "pypi", - "version": "==0.7.2" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "importlib-metadata": { - "hashes": [ - "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b", - "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313" - ], - "markers": "python_version < '3.10'", - "version": "==5.1.0" - }, - "itsdangerous": { - "hashes": [ - "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", - "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.2" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.2" - }, - "lxml": { - "hashes": [ - "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7", - "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726", - "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03", - "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140", - "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a", - "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05", - "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03", - "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419", - "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4", - "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e", - "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67", - "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50", - "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894", - "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf", - "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947", - "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1", - "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd", - "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92", - "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457", - "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74", - "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf", - "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1", - "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4", - "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975", - "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5", - "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe", - "sha256:6943826a0374fb135bb11843594eda9ae150fba9d1d027d2464c713da7c09afe", - "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7", - "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2", - "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409", - "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f", - "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f", - "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5", - "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24", - "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e", - "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4", - "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a", - "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c", - "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f", - "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7", - "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a", - "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c", - "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9", - "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e", - "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab", - "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941", - "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5", - "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45", - "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7", - "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892", - "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746", - "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c", - "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53", - "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184", - "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38", - "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9", - "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b", - "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2", - "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0", - "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b", - "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380", - "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8", - "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1", - "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889", - "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9", - "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f", - "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c" - ], - "index": "pypi", - "version": "==4.9.2" - }, - "markupsafe": { - "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.1" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" - }, - "python-slugify": { - "hashes": [ - "sha256:003aee64f9fd955d111549f96c4b58a3f40b9319383c70fad6277a4974bbf570", - "sha256:7a0f21a39fa6c1c4bf2e5984c9b9ae944483fd10b54804cb0e23a3ccd4954f0b" - ], - "index": "pypi", - "version": "==7.0.0" - }, - "pyyaml": { - "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "index": "pypi", - "version": "==6.0" - }, - "requests": { - "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" - ], - "index": "pypi", - "version": "==2.28.1" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" - }, - "tatsu": { - "hashes": [ - "sha256:0a836692e67247cad9f251e083b045b13345cc715e69a7fbc16522beaa0f2163", - "sha256:571ecbcdf33b7828c05e5cd95a8e8ad06af111c2c83a6a245be4d8f7c43de7bb" - ], - "markers": "python_version >= '3.8'", - "version": "==5.8.3" - }, - "text-unidecode": { - "hashes": [ - "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", - "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93" - ], - "version": "==1.3" - }, - "urllib3": { - "hashes": [ - "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc", - "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.13" - }, - "werkzeug": { - "hashes": [ - "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f", - "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5" - ], - "markers": "python_version >= '3.7'", - "version": "==2.2.2" - }, - "zipp": { - "hashes": [ - "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa", - "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766" - ], - "markers": "python_version >= '3.7'", - "version": "==3.11.0" - } - }, - "develop": { - "attrs": { - "hashes": [ - "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6", - "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c" - ], - "markers": "python_version >= '3.5'", - "version": "==22.1.0" - }, - "certifi": { - "hashes": [ - "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", - "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" - ], - "markers": "python_version >= '3.6'", - "version": "==2022.12.7" - }, - "charset-normalizer": { - "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.1" - }, - "coverage": { - "extras": [ - "toml" - ], - "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.7'", - "version": "==6.5.0" - }, - "exceptiongroup": { - "hashes": [ - "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828", - "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec" - ], - "markers": "python_version < '3.11'", - "version": "==1.0.4" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "iniconfig": { - "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" - ], - "version": "==1.1.1" - }, - "packaging": { - "hashes": [ - "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3", - "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3" - ], - "markers": "python_version >= '3.7'", - "version": "==22.0" - }, - "pluggy": { - "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==1.0.0" - }, - "pytest": { - "hashes": [ - "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71", - "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59" - ], - "index": "pypi", - "version": "==7.2.0" - }, - "pytest-cov": { - "hashes": [ - "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b", - "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470" - ], - "index": "pypi", - "version": "==4.0.0" - }, - "requests": { - "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" - ], - "index": "pypi", - "version": "==2.28.1" - }, - "responses": { - "hashes": [ - "sha256:396acb2a13d25297789a5866b4881cf4e46ffd49cc26c43ab1117f40b973102e", - "sha256:dcf294d204d14c436fddcc74caefdbc5764795a40ff4e6a7740ed8ddbf3294be" - ], - "index": "pypi", - "version": "==0.22.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:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "markers": "python_version < '3.11'", - "version": "==2.0.1" - }, - "types-toml": { - "hashes": [ - "sha256:171bdb3163d79a520560f24ba916a9fc9bff81659c5448a9fea89240923722be", - "sha256:b7b5c4977f96ab7b5ac06d8a6590d17c0bf252a96efc03b109c2711fb3e0eafd" - ], - "version": "==0.10.8.1" - }, - "urllib3": { - "hashes": [ - "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc", - "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.13" - } - } -} diff --git a/README.md b/README.md index 7673a081..a8165c43 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,13 @@ -

⚠️

-

Tento projekt nemá aktuálně nikoho, kdo by se o něj staral

-

Lákalo by tě python.cz udržovat, rozvíjet, nebo to celé předělat? Ozvi se na Slacku!

-
- # python.cz -Czech Python community homepage. - -## Installation - -The code is **Python 3.7**. - -1. [Install Pipenv](https://pipenv.readthedocs.io/en/latest/install/#installing-pipenv) -1. Clone the project: - - ```sh - $ git clone git@github.com:pyvec/python.cz.git --depth=10 - ``` - - It is recommended to start with a [shallow clone](https://git-scm.com/docs/git-clone#git-clone---depthltdepthgt) as historically, this repo has contained a lot of rather large photos. -1. Go inside the project directory and run Pipenv to install dependencies: - - ``` - $ cd ./python.cz - $ pipenv install --dev - ``` - -### Development - -The site uses GitHub API. For certain pages to work correctly, you need to set the `GITHUB_TOKEN` environment variable to a [GitHub Personal Access Token](https://github.com/settings/tokens) (no scopes needed). - -```sh -$ export GITHUB_TOKEN=... -$ pipenv run serve -``` - -### Deployment - -The site gets automatically deployed after any push to the `master` branch. It is frozen by [Elsa](https://github.com/pyvec/elsa). A GitHub action redeploys it daily, so any content of dynamic nature isn't outdated. - -- **Domain:** bestowed by [KRAXNET](http://www.kraxnet.cz/)
- Access: e-mail request to [KRAXNET](http://www.kraxnet.cz/) -- **Public Analytics:** [Simple Analytics](https://simpleanalytics.com/python.cz)
- Access: [@honzajavorek](http://github.com/honzajavorek) +Czech Python community homepage powered by [MkDocs](https://www.mkdocs.org/). -## Authors & Contributions +# How to run (for development) -**This site is community effort and contributions are very welcome!** See the [Hall of fame](https://github.com/pyvec/python.cz/graphs/contributors) for the most active contributors. +1. Clone repository +1. `poetry install` +1. `poetry run mkdocs serve` -The site is backed by [Pyvec](http://pyvec.org/), nonprofit organization dedicated to support of Python in the Czech Republic. [Honza Javorek](http://github.com/honzajavorek) is the original author, the [@pyvec/python-cz](https://github.com/orgs/pyvec/teams/python-cz) are python.cz maintainers. ## License diff --git a/app.py b/app.py deleted file mode 100644 index 25c6a0ae..00000000 --- a/app.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python - - -from pythoncz import app as application # NOQA - - -application.config['SERVER_NAME'] = 'python.cz' diff --git a/docs/akce.md b/docs/akce.md new file mode 100644 index 00000000..adf32ac2 --- /dev/null +++ b/docs/akce.md @@ -0,0 +1,58 @@ +# Akce + +
+Srazy, konference, workshopy. Vše, co se v ČR děje kolem jazyka Python, na jednom místě. +
+ +
+![Ilustrace hada hrajícího na ukulele](images/ukulele.svg) +
+ + + +## Všechny akce {: #akce } + +- **Pravidelné akce** lze přidat přes tzv. + [iCal](https://cs.wikipedia.org/wiki/ICalendar) export. Ten může + generovat přímo vaše webová stránka (jako v případě + [pyvo.cz](https://pyvo.cz)), nebo jej lze vytáhnout z nějaké služby + (Google Calendar, meetup.com). URL exportu pak na náš web [přidejte pomocí Pull Requestu](https://github.com/pyvec/python.cz/edit/master/pythoncz/static/data/events_feeds.yml). +- **Jednorázové akce** lze přidat přes kalendář [Czech Python Events](https://calendar.google.com/calendar/embed?src=kfdeelic1a13jsp7jvai861vfs%40group.calendar.google.com&ctz=Europe%2FPrague). + Do kalendáře má přístup mnoho z organizátorů existujících Python + akcí, takže je poproste, ať vaši akci přidají, nebo napište na + . První URL z popisu události se zde zobrazí jako + odkaz. + +## Kalendář + + + + diff --git a/docs/css/extra.css b/docs/css/extra.css new file mode 100644 index 00000000..6be81532 --- /dev/null +++ b/docs/css/extra.css @@ -0,0 +1,84 @@ +:root { + --md-primary-fg-color: #4b8bbe; + --md-accent-fg-color: #306998; + --md-primary-fg-color--dark: #306998; +} + +.md-typeset h1 { + color: var(--md-default-fg-color); + font-weight: 700; + font-size: 2.5em; + margin-bottom: 1em; +} + +.md-grid { + max-width: 50rem; +} + +.md-content { + padding-bottom: 2em; +} + +.md-typeset figure { + text-align: center; +} + +.md-typeset figure img { + width: 100%; + margin: 1em auto; +} + +.md-typeset figure.md img { + max-height: 440px; + max-width: 704px; +} + +.md-typeset figure.sm img { + max-height: 250px; + max-width: 400px; +} + +.md-typeset button.center { + display: block; + width: 100%; + text-align: center; +} + +.md-typeset button a { + display: inline-block; + margin: 1em auto; + padding: 0.5em 1em; + background-color: var(--md-primary-fg-color); + color: #fff; +} + +.md-typeset button a:hover, +.md-typeset button a:focus, +.md-typeset button a:active { + background-color: var(--md-accent-fg-color); + color: #fff; +} + +.md-typeset h1 .headerlink { + display: none; +} + +.logo { + text-align: center; +} + +.logo img { + margin: 0; + width: 100%; + max-width: 700px; +} + +.lead { + font-size: 1.2em; + font-weight: 400; + line-height: 1.6em; +} + +.tentative { + opacity: 0.3; +} diff --git a/docs/en.md b/docs/en.md new file mode 100644 index 00000000..a7d50176 --- /dev/null +++ b/docs/en.md @@ -0,0 +1,85 @@ +

+ ![Czech Python User Group](images/python-logo.svg) +

+ +
+Python is a modern programming language. See [python.org](https://python.org) for details. +The Czech Python community is **active and friendly**. +Come and **join us** at meetups and workshops in several cities! +
+ +
+![Czech Python User Group](images/czech-python-user-group.svg) +
+ +## Where you can find us? + +- [Pyonýři on Facebook](https://www.facebook.com/groups/pyonieri/) +- [Discord](https://discord.gg/yUbgArVAyF) +- [Email group](https://groups.google.com/group/django-cs/) +- [Email group at py.cz](http://www.py.cz/mailman/listinfo/python) +- [Pyvo meetups](https://twitter.com/naPyvo) +- [PyCon CZ](https://twitter.com/PyConCZ) +- [PyLadies CZ](https://twitter.com/PyLadiesCZ) +- [PyData Prague](https://twitter.com/PyDataPrague) +- [IRC #python-cs](irc://irc.freenode.net/python-cs) +- [IRC #django-cs](irc://irc.freenode.net/django-cs) +- [Slack for organizers](http://pyvec.slack.com/) + +## Events + +The events page are in Czech, but we believe the calendar is quite obvious even to someone who doesn't understand Czech. +English speakers are welcome to most of our events. + + + +## Links + +- [PyLadies CZ](https://pyladies.cz/) - There are events for ladies in multiple Czech cities. +- [Blog](http://blog.python.cz/) - TODO +- [PyCon CZ](http://cz.pycon.org/) - Czech Python conference! Help us with preparations, spread the word, register a talk or workshop, consider sponsorship, or just come and enjoy the event! +- [Knihovna](https://books.pyvo.cz/) - We have a library of Python-related books. If you want to borrow one, let us know, and come to the nearest [Pyvo meetup](#meetups) to pick the book up. By the way, you already know [Python Books](http://pythonbooks.revolunet.com/), right? + +## Jobs + +How can you address Czech software engineers working in Python with your +**job offer**? Why is it **worth the effort**? + +### How to find Czech Python software engineers? {: #offer } + +- Attend a [meetup](/en/#meetups) and ask around. Speak to real + people, get them hooked for your ideas, learn about their options + and requirements. +- Ask your company to sponsor the next [PyCon + CZ](http://cz.pycon.org/) or [PyCon SK](http://pycon.sk/) + conferences. Both are unique opportunities to speak with 400+ + developers from the central-european region. +- Write down a job offer. **Honest story instead of boring bullet + points** will bring you larger audience. **Don\'t forget to mention + how much is it possible to work remotely.** +- Send the offer to django-cs and py.cz discussions (see + [homepage](/en/#communication)) and to the [Facebook + group](https://www.facebook.com/groups/pyonieri/). Many Czech + Pythonistas are subscribed to them. +- Please do not overuse any of the discussions. Job offers are + welcome, they\'re free and without limitations, but if it starts to + be annoying, it doesn\'t have to be without regulation forever. +- Post the offer to [global job + board](https://www.python.org/community/jobs/howto/) -- the board is + free, only registration is needed. The offer then appears also on + [@pyjobo](https://twitter.com/pyjobo) Twitter account. Advertise + also at Czech job boards: + [Jobs.cz](http://www.jobs.cz/prace/?q%5B%5D=python){target="_blank"}, + [StartupJobs.cz](https://www.startupjobs.cz/nabidky/15/python-programmer){target="_blank"}, + ... + +### I wish more Czech Pythonistas would exist! {: #more } + +We too and it's also the main goal of [Pyvec](http://pyvec.org/), our +nonprofit. Pyvec is dedicated to support all sorts of activities focused +on introducing more people to Python in the Czech Republic. Pyvec also +supports local chapters of [PyLadies](http://pyladies.cz) and +[DjangoGirls](http://djangogirls.org). If you wish to sponsor our +activities, please drop an e-mail to . diff --git a/pythoncz/static/images/czech-python-user-group.svg b/docs/images/czech-python-user-group.svg similarity index 100% rename from pythoncz/static/images/czech-python-user-group.svg rename to docs/images/czech-python-user-group.svg diff --git a/pythoncz/static/favicon.ico b/docs/images/favicon.ico similarity index 100% rename from pythoncz/static/favicon.ico rename to docs/images/favicon.ico diff --git a/pythoncz/static/images/jobs.svg b/docs/images/jobs.svg similarity index 100% rename from pythoncz/static/images/jobs.svg rename to docs/images/jobs.svg diff --git a/pythoncz/static/images/learning-python-general.svg b/docs/images/learning-python-general.svg similarity index 100% rename from pythoncz/static/images/learning-python-general.svg rename to docs/images/learning-python-general.svg diff --git a/pythoncz/static/images/learning-python-job.svg b/docs/images/learning-python-web.svg similarity index 100% rename from pythoncz/static/images/learning-python-job.svg rename to docs/images/learning-python-web.svg diff --git a/pythoncz/static/images/learning-python.svg b/docs/images/learning-python.svg similarity index 100% rename from pythoncz/static/images/learning-python.svg rename to docs/images/learning-python.svg diff --git a/pythoncz/static/images/logo.svg b/docs/images/python-logo.svg similarity index 100% rename from pythoncz/static/images/logo.svg rename to docs/images/python-logo.svg diff --git a/docs/images/site-logo.svg b/docs/images/site-logo.svg new file mode 100644 index 00000000..7ed1dbf1 --- /dev/null +++ b/docs/images/site-logo.svg @@ -0,0 +1,247 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pythoncz/static/images/ukulele.svg b/docs/images/ukulele.svg similarity index 99% rename from pythoncz/static/images/ukulele.svg rename to docs/images/ukulele.svg index b92041e5..45fb70a1 100644 --- a/pythoncz/static/images/ukulele.svg +++ b/docs/images/ukulele.svg @@ -8,7 +8,7 @@ Created by potrace 1.13, written by Peter Selinger 2001-2015 +fill="#333333" stroke="none"> + ![Python v ČR](images/python-logo.svg) + + +
+Python je **moderní programovací jazyk**. Je **univerzální** – pohání weby i rakety. +Dobře se čte a dá se velice **rychle naučit**. Je skvělý pro **výuku** programování. +**Česká komunita** je aktivní. Najdeš v ní **pomoc, kamarády i práci**. +
+ +
+![česká Python komunita](images/czech-python-user-group.svg) +
+ +## Kde nás najdeš + +- [Skupina Pyonýři](https://www.facebook.com/groups/pyonieri/) +- [Discord](https://discord.gg/yUbgArVAyF) +- [E-mailová skupina](https://groups.google.com/group/django-cs/) +- [E-mailová skupina na py.cz](http://www.py.cz/mailman/listinfo/python) +- [Srazy Pyvo](https://twitter.com/naPyvo) +- [PyCon CZ](https://twitter.com/PyConCZ) +- [PyLadies CZ](https://twitter.com/PyLadiesCZ) +- [PyData Praha](https://twitter.com/PyDataPrague) +- [IRC #python-cs](irc://irc.freenode.net/python-cs) +- [IRC #django-cs](irc://irc.freenode.net/django-cs) +- [Slack pro organizátory](http://pyvec.slack.com/) + +## Akce + + + +## Odkazy + +- [PyLadies CZ](https://pyladies.cz/) - TODO +- [Blog](http://blog.python.cz/) - Díky blogu se **dovíš o všem, co se v české Python komunitě zrovna děje**. A co je nejlepší – můžeš klidně přidat svůj vlastní článek! +- [PyCon CZ](http://cz.pycon.org/) - Česká Python konference! Pomoz nám s přípravami, propagací, zkus si přihlásit přednášku nebo workshop, sponzoruj nás, nebo prostě jen přijď a akci si užij! +- [Knihovna](https://books.pyvo.cz/) - Máme knihovničku s literaturou o Pythonu a podobných technologiích. Knihy si lze **zdarma půjčit** – ozvi se a přijď si knížku vyzvednout na nejbližším [srazu](akce.md). Mimochodem, [Python Books](http://pythonbooks.revolunet.com/) znáš, že? diff --git a/docs/prace.md b/docs/prace.md new file mode 100644 index 00000000..defd66c0 --- /dev/null +++ b/docs/prace.md @@ -0,0 +1,92 @@ +# Python a práce + +
+Používá vůbec někdo Python? **Ano!** Jde o jazyk vhodný k výuce nebo +skriptování, ale to neznamená, že jej nepoužívají firmy z celého světa a +nepíšou se v něm rozsáhlé projekty. +
+ +
+![Ilustrace hada v kanceláři](images/jobs.svg) +
+ +## Python ve světě + +Python používají např. **Blender 3D, YouTube, +Dropbox, Disqus, IBM, Instagram, Lucasfilm, Mozilla, NASA, Spotify, Walt +Disney, [a mnoho dalších](https://www.python.org/about/success/)** – +mimo jiné také spousta vědeckých organizací **včetně švýcarského +CERNu**. + +## Python u nás + +TODO - zrušit seznam, dát sem sponzory PyConu a nějaký text, možná odkazy na job boardy s filtrováním na python + +## Jak najít práci? {: #poptavka } + +- Přijď na [sraz](akce.md) a poptej se tam. +- Sleduj všechny [diskusní kanály](index.md), kde se nabídky + objevují. +- Na zmíněné kanály aktivně napiš, že hledáš práci nebo stáž. +- Zkus přímo oslovit firmy výše. +- Sleduj Twitter účet [@pyjobo](https://twitter.com/pyjobo) a + pročítej [globální nástěnku nabídek](https://www.python.org/jobs/) + – inzeráty lze hledat [podle + lokace](https://www.python.org/jobs/locations/) nebo třeba i podle + toho, [zda lze pracovat na + dálku](https://www.python.org/jobs/location/telecommute/). Sleduj + Python na pracovních serverech: + [Jobs.cz](http://www.jobs.cz/prace/?q%5B%5D=python), + [StartupJobs.cz](https://www.startupjobs.cz/nabidky/15/python-programmer), + ... (Víš o dalších? [Přidej + odkaz!](https://github.com/pyvec/python.cz/edit/master/pythoncz/static/data/jobs.yml)) +- Odzkoušej si své znalosti v testech: + [StartupJobs.cz](https://www.startupjobs.cz/test/python), + [Toptal.com](http://www.toptal.com/python/interview-questions), + ... (Víš o dalších? [Přidej + odkaz!](https://github.com/pyvec/python.cz/edit/master/pythoncz/static/data/jobs.yml)) + +## Jak najít Python programátory? {: #nabidka } + +- Přijď na [sraz](akce.md) a poptej se tam. Promluv si s reálnými + lidmi, nadchni je, zlákej je, zjisti jaké mají možnosti a požadavky. +- Popros svou společnost, aby sponzorovala příští [PyCon + CZ](http://cz.pycon.org/) nebo [PyCon SK](http://pycon.sk/). Obě + konference jsou jedinečnou příležitostí promluvit si s 400+ vývojáři + z celé střední Evropy. +- Sepiš si inzerát a konkretizuj jej, aspoň do tvaru něčeho jako + *„hledám nadšence/nájemného profíka na krátkodobý projekt ve stylu + CMS s galerií, nejspíš v Djangu, platím penězi“*. Čím víc bude + **lidsky od srdíčka** a čím méně to budou odrážky ve stylu + poptáváme/nabízíme, tím více lidí to zaujme. **Nezapomeň napsat do + jaké míry je možná práce na dálku.** +- Napiš inzerát na diskuse django-cs a py.cz ([viz hlavní + stránka](index.md)) a na [Facebookovou + skupinu](https://www.facebook.com/groups/pyonieri/). Čte je mnoho + českých a slovenských Pythonistů. +- Nepřehlcuj žádnou z diskusí. Inzeráty jsou vítány, jsou zadarmo a + bez omezení, ale pokud se to zvrhne, nemusí to tak zůstat. +- Pošli inzerát na [globální nástěnku + nabídek](https://www.python.org/community/jobs/howto/) – ta + uveřejňuje nabídky zdarma, jen je potřeba se registrovat. Nabídka se + pak objeví i na Twitter účtu [@pyjobo](https://twitter.com/pyjobo). + Inzeruj nabídku na pracovních serverech: + [Jobs.cz](http://www.jobs.cz/prace/?q%5B%5D=python), + [StartupJobs.cz](https://www.startupjobs.cz/nabidky/15/python-programmer), + ... + +## Chci, aby bylo víc Pythonistů! {: #vic } + +**My taky!** Máme na to dokonce [neziskovku Pyvec](http://pyvec.org/). +Můžeš se [zapojit](zapojse.md) a s naší misí nám pomoci. + +Pokud zastupuješ nějakou firmu, můžeš nás **sponzorovat ([číslo +účtu](https://www.fio.cz/scgi-bin/hermes/dz-transparent.cgi?ID_ucet=2600260438))**. +Přes Pyvec se peníze rozdělí na dílčí projekty. Podporujeme např. srazy +a workshopy pro dámy – [PyLadies](http://pyladies.cz), +[DjangoGirls](http://djangogirls.org). + +Budeme také rádi, pokud nám **napíšete *success story* o tom, jak jste +Python použili u vás** a jak vám to usnadnilo práci a co vše jste s ním +dokázali. Takovou zkušenost zde rádi uveřejníme, klidně i na samostatné +stránce, s logem apod. diff --git a/docs/zacatecnici.md b/docs/zacatecnici.md new file mode 100644 index 00000000..2a67dfda --- /dev/null +++ b/docs/zacatecnici.md @@ -0,0 +1,130 @@ +# Učíme se Python + +
+Česká **komunita je přátelská a živá**. Vždy bude po ruce **někdo, kdo ti pomůže**. +**Nebudeš mít problém [sehnat práci](prace.md).** Pythonistů je nedostatek! +I kdyby weby vyšly z módy, Python nachází **uplatnění v desítkách dalších oborů**. +
+ +
+![Ilustrace hada s knížkou](images/learning-python.svg) +
+ +## Online materiály – neumím vůbec programovat {: #onlineneumim } + +Následující materiály vznikly v rámci aktivit, které se snaží přiblížit +**IT ženám a ženy k IT**. Jsou skvěle zpracované a může se z nich naučit +programovat od úplných základů kdokoliv. + +- [Materiály od PyLadies](http://naucse.python.cz/course/pyladies/) +- [Návod od Django Girls](http://tutorial.djangogirls.org/) + +## Online materiály – programovat trochu umím {: #onlineumim } + +### Přecházím z jiného jazyka + +- [Naučte se Python za X minut](http://learnxinyminutes.com/docs/cs-cz/python3/) +- [Jak přejít z PHP](http://www.zdrojak.cz/clanky/jak-napisu-webovou-aplikaci-v-pythonu/) + ([2. díl](http://www.zdrojak.cz/clanky/jak-napisu-webovou-aplikaci-v-pythonu-2/)) +- [Úvod do Pythonu pro programátory](https://speakerdeck.com/u/pydanny/p/intro-to-python) +- [Tahák na podobné konstrukce v PHP, Perlu, Pythonu a Ruby](http://hyperpolyglot.org/scripting) +- [Pragmatické tipy na to jak začít a co použít](http://blog.jmoz.co.uk/learning-python-the-pragmatic-way/) +- [Průvodce Python ekosystémem](http://docs.python-guide.org/) +- [Oficiální návod k Pythonu](https://docs.python.org/3/tutorial/) +- [Rychlokurz Pythonu pro programátory](http://stephensugden.com/crash_into_python/) + +### Návody pro začátečníky + +- [Kniha Ponořme se do Pythonu 3](http://diveintopython3.py.cz/index.html) + ([PDF](http://knihy.nic.cz/files/nic/edice/mark_pilgrim_dip3_ver3.pdf)) +- [Učíme se programovat v jazyce Python 3](http://howto.py.cz/) +- [Základy Pythonu 3, interaktivní materiály](https://github.com/tomasbedrich/skoleni-python) +- [Seznam nejlepších materiálů](http://net.tutsplus.com/tutorials/the-best-way-to-learn-python/) +- [Sada krátkých videí jako úvod do Pythonu](https://www.cbtnuggets.com/it-training/python-programming) +- [Sada screencastů k vylepšení dovedností s Pythonem](http://www.neckbeardrepublic.com/screencasts/) +- [Screencasty pro webový framework Django](https://godjango.com/) +- [Dokumentace k webovému frameworku Django](https://docs.djangoproject.com/) +- [Základní algoritmy - v Pythonu a interaktivně](http://interactivepython.org/runestone/static/pythonds/index.html) +- [Vysvětlení nejčastějších chyb začátečníků](https://inventwithpython.com/blog/2012/07/09/16-common-python-runtime-errors-beginners-find/) +- [Různé úvodní lekce od Microsoft Virtual Academy](https://mva.microsoft.com/search/SearchResults.aspx?q=python&index=2&lang=1029$1033) +- [Odkazy na vysvětlení zajímavých či pokročilých detailů jazyka](https://web.archive.org/web/20170912115918/http://jessenoller.com/good-to-great-python-reads/) +- [Syntaxi už umím, co dál?](http://newcoder.io/) +- [Learn Python The Hard Way](http://learnpythonthehardway.org/) + +### Chci si to hned zkusit + +- [Python na Umíme programovat](https://www.umimeprogramovat.cz/programovani-v-pythonu) +- [Python konzole v prohlížeči](http://repl.it/) +- [Programovací hra](http://www.checkio.org) +- [Python na Codecademy, interaktivní online kurz](https://www.codecademy.com/pro/intensive/programming-with-python) +- [Python na Code School, interaktivní online kurz](https://www.codeschool.com/learn/python) +- [Programming for Everybody, interaktivní online kurz](https://www.coursera.org/course/pythonlearn) +- [Interaktivní vysvětlení toho, co se děje v kódu](http://www.pythontutor.com/) +- [Codewars](https://www.codewars.com/?language=python) + +### Knihy + +Díky [naší knihovničce](https://books.pyvo.cz/) si můžeš zadarmo půjčit +knihy o Pythonu. Na stránkách [Python Books](http://pythonbooks.revolunet.com/) navíc najdeš seznam knih, +které si můžeš zdarma číst online nebo si je rovnou stáhnout. Určitě to +omrkni! + +### Přednášky + +Nahráváme přednášky ze [srazů](akce.md) a [dáváme je na YouTube](https://www.youtube.com/user/pyvec/playlists). Na stránkách +[pyvideo.org](http://pyvideo.org/) najdeš přednášky z celého světa. + +### Konvence pro psaní kódu + +- [Style Guide for Python Code](https://pep8.org/) +- [Python Docstring Conventions](http://www.python.org/dev/peps/pep-0257/) +- [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html) + +### Kam nahrát web napsaný v Pythonu? + +- [Roští.cz](https://rosti.cz/python-hosting/) +- [Heroku](https://www.heroku.com/) +- [Google App Engine](https://developers.google.com/appengine/) +- [PythonAnywhere](https://www.pythonanywhere.com/) +- [AlwaysData](https://www.alwaysdata.com/) + +## Kurzy + +### Pro dámy + +- [Pravidelné srazy PyLadies](http://pyladies.cz) +- [Jednorázové workshopy Django Girls](http://djangogirls.org) +- [Workshopy Czechitas (v Pythonu jen některé)](http://www.czechitas.cz) +- [Workshopy Geek Girls Carrots v Ostravě (v Pythonu jen některé)](http://geekgirlscarrots.org) + +### Pro studenty + +- [Kurz ČVUT FEL A4B99RPH](https://cw.fel.cvut.cz/wiki/courses/a4b99rph/prednasky/start) +- [Kurzy MU Brno](http://is.muni.cz/vyhledavani/?search=jazyk+python+agenda%3Apr) +- [Kurz ZČU v Plzni KKY/ITE](https://portal.zcu.cz/StagPortletsJSR168/CleanUrl?urlid=prohlizeni-predmet-sylabus&predmetZkrPrac=KKY&predmetZkrPred=ITE) +- [Kurz ZČU v Plzni KKY/APK](https://portal.zcu.cz/StagPortletsJSR168/CleanUrl?urlid=prohlizeni-predmet-sylabus&predmetZkrPrac=KKY&predmetZkrPred=APK) +- [Kurz FIT ČVUT v Praze (BI-PYT)](http://bk.fit.cvut.cz/cz/predmety/00/00/00/00/00/00/01/29/14/p1291406.html) + +### Pro mládež + +- [Kroužek na Praze 10](http://kapsa.cz/cs/krouzky-pro-deti#python) +- [Kroužek v Lázně Toušeň](https://www.programovanihrou.cz/) +- [Czechitas - kroužky a tábory pro různé věkové kategorie](http://www.czechitas.cz) +- [Kroužky, workshopy a tábory makeITtoday](https://makeittoday.cz/courses_cz.html) +- [Kurzy v Praze pro děti 8-12 let](https://www.digikids.cz) +- [Kurzy v Praze a online od 11-19 let](https://vzdelanibudoucnosti.cz) + +### Ostatní + +- [Nepravidelné intenzivní Python kurzy kiwi.com](https://pythonweekend.cz/) +- [Celodenní workshopy a setkání pro Python začátečníky](https://pyworking.cz/) +- [Sedlákovi - různé kurzy související s Pythonem](https://www.sedlakovi.org/kurzy/) +- [Engeto - Python akademie v Praze a Brně](https://engeto.cz/python-akademie/) + +[Přidat kurz](https://github.com/pyvec/python.cz/edit/master/pythoncz/static/data/beginners.yml) + +## Koučování {: #koucovani } + +Aneb osobní konzultace, mentoring, doučování... + +- Učíme Python: [Facebook skupina](https://www.facebook.com/groups/800923800012580/), [Google Groups](https://groups.google.com/forum/#!forum/ucime-python) diff --git a/docs/zapojse.md b/docs/zapojse.md new file mode 100644 index 00000000..a12a2bb6 --- /dev/null +++ b/docs/zapojse.md @@ -0,0 +1,94 @@ +# Zapoj se! + +
+Líbí se ti Python? **Pomoz nám ho rozšířit i mezi ostatní.** Můžeš nám poslat peníze, učit, přednášet, psát, organizovat, programovat, ale třeba i jen vymýšlet, co a jak by se dalo zlepšit. Máme práci pro každého! +
+ +
+![česká Python komunita](images/czech-python-user-group.svg) +
+ +## Proč? + +Python komunita je fajn jen díky tomu, že jsou v ní **lidi, kteří se nebojí přiložit ruku k dílu**. Všichni to děláme po večerech ve volném čase, z čirého nadšení. **Děláme to proto, že chceme, aby to bylo lepší i pro tebe.** Ať jsi profík nebo začátečník, z Prahy nebo z Karviné, můžeš nám pomoci. Odměnou ti budou kontakty, reference, zkušenosti. + +## Přispěj + +Budeme rádi, když přispěješ na provoz neziskovky [Pyvec](http://pyvec.org/), jejíž misí je podporovat a propagovat Python komunitu v ČR. + +Srazy nebo workshopy dělají konkrétní lidé a Pyvec jim do toho nemluví - nabízí ale pomocnou ruku co se týče financí a zázemí. + +## Vyučuj + +- Přidej se na skupiny **Učíme Python**: + [Facebook](https://www.facebook.com/groups/800923800012580/), + [Google + Groups](https://groups.google.com/forum/#!forum/ucime-python). +- Koučuj pro [PyLadies](http://pyladies.cz/). +- [Rozjeď kurz pro začátečníky podle našeho + návodu](https://docs.pyvec.org/guides/beginners-course.html). Použij + a vylepšuj naše Open Source [materiály](zacatecnici.md). +- Přečti si [tipy na koučování od Django + Girls](https://coach.djangogirls.org/). + +## Přednášej + +- Přihlaš se s přednáškou na nejbližší [sraz](https://pyvo.cz). +- Pokud se necítíš na 15-20 minut, připrav si tzv. lightning talk. Je + to pětiminutovka o čemkoliv a můžeš s ní přijít na + [srazy](https://pyvo.cz) přijít i bez ohlášení. +- Koukni se, jestli zrovna nehledají řečníky + [PyCon CZ](https://cz.pycon.org/) nebo + [PyCon SK](https://www.pycon.sk/). Na mnohé konference se může + přihlásit s přednáškou kdokoliv, stačí vyplnit formulář – tzv. CfP + (Call for Proposals). + +## Piš + +- Poděl se o zážitky z akcí nebo o svůj životní příběh na [komunitní + blog](http://blog.python.cz). +- Technické články piš např. na [Zdroják.cz](http://zdrojak.cz/). + Redakce bude nadšená a ty budeš mít větší publikum. +- Python učíme podle Open Source + [materiálů](zacatecnici.md). Můžeš nám pomoci je + vylepšovat. +- Když se nám povede něco zorganizovat, snažíme se sepsat naše + know-how do [komunitní dokumentace](https://docs.pyvec.org/). Chybí + tam ještě spousta věcí! + +## Organizuj + +- Pokud ve tvém městě není [Python sraz](https://pyvo.cz) nebo třeba + [PyLadies](http://pyladies.cz/) skupina, tak gratulujeme: Můžeš je + založit! Jestliže už se kolem tebe něco koná, nejlepší bude, když se + spojíš s organizátory a zeptáš se, jak jim můžeš pomoci. +- Každoročně sháníme dobrovolníky na konferenci [PyCon + CZ](https://pycon.cz). Potřebné činnosti mají většinou pramálo + společného s Pythonem a programováním. +- Když se nám povede něco zorganizovat, snažíme se sepsat naše + know-how do [komunitní dokumentace](https://docs.pyvec.org/). +- Všechny důležité věci řešíme na [Slacku](http://pyvec.slack.com/). + Napiš nám na , my tě přidáme, pak můžeš pokukovat co + se v jaké místnosti řeší a brzy uvidíš, kde je tvoje pomoc nejvíc + potřeba. +- Máme neziskovku [Pyvec](http://pyvec.org/). Její misí je podporovat + a propagovat Python komunitu v ČR. Srazy nebo workshopy dělají lidé + jako ty a Pyvec jim do toho nemluví - nabízí ale pomocnou ruku co se + týče financí a zázemí. + +## Další nápady + +Pro organizaci jednorázových úkolů používáme +[GitHub](https://github.com/pyvec/zapojse/) (viz Issues, můžeš tady [přidat svůj nápad](https://github.com/pyvec/zapojse/issues/new)) + +Když nic, tak aspoň +[hlasuj](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) +nebo [přidej vlastní +nápad](https://github.com/pyvec/zapojse/issues/new). Díky hlasům budeme +mít přinejmenším přehled o tom, co si přeje nejvíc lidí. + +Značka _Kouč pomůže!_ znamená, že někdo navrhl, +že ti s úkolem pomůže, pokud se do něj pustíš. Jestli se ty chceš někde +navrhnout jako kouč, napiš to do komentáře pod daný úkol a [přiřaď mu +štítek](https://help.github.com/articles/applying-labels-to-issues-and-pull-requests/) + diff --git a/events_feeds.yml b/events_feeds.yml new file mode 100644 index 00000000..7873d75c --- /dev/null +++ b/events_feeds.yml @@ -0,0 +1,24 @@ +- name: Pyvo + site_url: https://pyvo.cz/ + url: https://pyvo.cz/api/pyvo.ics + format: icalendar + +- name: PyWorking + site_url: https://pyworking.cz/ + url: https://pyworking.cz/workshops.ics + format: icalendar + +- name: PyWorking Sessions + site_url: https://pyworking.cz/ + url: https://www.meetup.com/pyworking/events/ + format: json-dl + +- name: PyData Prague + site_url: https://www.meetup.com/PyData-Prague/ + url: https://www.meetup.com/PyData-Prague/events/ + format: json-dl + +- name: Czech Python Events + site_url: https://calendar.google.com/calendar/embed?src=kfdeelic1a13jsp7jvai861vfs%40group.calendar.google.com&ctz=Europe%2FPrague + url: https://calendar.google.com/calendar/ical/kfdeelic1a13jsp7jvai861vfs%40group.calendar.google.com/public/basic.ics + format: icalendar diff --git a/pythoncz/models/__init__.py b/hooks/__init__.py similarity index 100% rename from pythoncz/models/__init__.py rename to hooks/__init__.py diff --git a/hooks/events.py b/hooks/events.py new file mode 100644 index 00000000..0aca20ab --- /dev/null +++ b/hooks/events.py @@ -0,0 +1,161 @@ +import json +import re +from datetime import date, datetime, timedelta +from functools import cache +from operator import itemgetter +from pathlib import Path +from zoneinfo import ZoneInfo + +import ics +import requests +import teemup +from strictyaml import Map, Seq, Str, Url, load as load_yaml + + +YAML_SCHEMA = Seq( + Map( + { + "name": Str(), + "site_url": Url(), + "url": Url(), + "format": Str(), + } + ) +) + +USER_AGENT = "python.cz (+https://python.cz)" + + +@cache +def fetch_events(days_limit: int | None = None, past: bool = False) -> list[dict]: + cache_path = Path(".events_cache.json") + try: + print(f"INFO - Loading events feeds from {cache_path}") + data = json.loads(cache_path.read_text()) + except FileNotFoundError: + print("INFO - No cache") + yaml = Path("events_feeds.yml").read_text() + data = [] + for feed in load_yaml(yaml, YAML_SCHEMA).data: + print(f"Fetching {feed['url']}") + response = requests.get(feed["url"], headers={"User-Agent": USER_AGENT}) + response.raise_for_status() + feed["url"] = response.url # overwrite with the final URL + feed["data"] = response.text + data.append(feed) + cache_path.write_text(json.dumps(data, indent=2, ensure_ascii=False)) + + print("INFO - Parsing events") + events = [] + for feed in data: + if feed["format"] == "icalendar": + events.extend( + [ + dict(feed=feed, **event_data) + for event_data in parse_icalendar(feed["data"]) + ] + ) + elif feed["format"] == "json-dl": + events.extend( + [ + dict(feed=feed, **event_data) + for event_data in parse_json_dl(feed["data"], feed["url"]) + ] + ) + else: + raise ValueError(f"Unknown feed format {feed['format']!r}") + + print("INFO - Sorting events") + return sorted(events, key=itemgetter("starts_at")) + + +def filter_events( + events: list[dict], + days_limit: int | None = None, + only_upcoming: bool = True, + today: date | None = None, +) -> list[dict]: + today = today or date.today() + if only_upcoming: + events = [ + event + for event in events + if event["starts_at"].date() >= today + or (event["ends_at"] and event["ends_at"].date() >= today) + ] + if days_limit is not None: + events = [ + event + for event in events + if event["starts_at"].date() <= today + timedelta(days=days_limit) + ] + return events + + +def generate_icalendar(events: list[dict]) -> str: + calendar = ics.Calendar() + for event in events: + calendar.events.append( + ics.Event( + summary=event["name"], + begin=event["starts_at"], + end=event["ends_at"], + location=event["location"], + url=event["url"], + categories=["tentative-date"] if event["is_tentative"] else [], + ) + ) + return calendar.serialize() + + +def parse_icalendar(text: str) -> list[dict]: + return [ + dict( + name=event.summary, + starts_at=to_prague_tz(event.begin), + ends_at=to_prague_tz(event.end) if event.end else None, + location=event.location, + url=event.url if event.url else find_first_url(event.description), + is_tentative="tentative-date" in event.categories, + ) + for event in ics.Calendar(text).events + ] + + +def parse_json_dl(html: str, base_url: str) -> list[dict]: + response = requests.get(base_url) + events = teemup.parse(response.text) + return [ + dict( + name=event["title"], + starts_at=event["starts_at"], + ends_at=event["ends_at"], + location=event["venue"], + url=event["url"], + is_tentative=False, + ) + for event in events + ] + + +def parse_json_dl_location(location: dict[str, str]) -> str: + return f"{location['name']}, {location['address']['streetAddress']}, {location['address']['addressLocality']}, {location['address']['addressCountry']}" + + +def to_prague_tz(dt: datetime) -> datetime: + prague_tz = ZoneInfo("Europe/Prague") + if dt.tzinfo is None: + return dt.replace(tzinfo=prague_tz) + return dt.astimezone(prague_tz) + + +def find_first_url(text: str) -> str | None: + if match := re.search(r'https?://[^\s"<]+', text or ""): + return match.group(0) + return None + + +if __name__ == "__main__": + from pprint import pprint + + pprint(fetch_events(), depth=2) diff --git a/hooks/on_page_markdown.py b/hooks/on_page_markdown.py new file mode 100644 index 00000000..6be48d30 --- /dev/null +++ b/hooks/on_page_markdown.py @@ -0,0 +1,29 @@ +from urllib.parse import quote_plus + +from events import fetch_events, filter_events +from jinja2 import Environment +from mkdocs.config import Config +from mkdocs.structure.files import Files +from mkdocs.structure.pages import Page + + +def on_page_markdown( + markdown: str, + page: Page, + config: Config, + files: Files, +) -> str: + # Unfortunately this is aparently the only way to hide the navigation + # on every page using the material theme. Solution described in + # https://github.com/squidfunk/mkdocs-material/issues/3686 breaks + # hamburger menu on small viewports. + page.meta["hide"] = ["toc", "navigation"] + + print(f"INFO - Rendering jinja on {page.file.src_path}") + env = Environment() + env.filters["urlencode"] = quote_plus + template = env.from_string(markdown) + + return template.render( + events=filter_events(fetch_events(), days_limit=60, only_upcoming=True) + ) diff --git a/hooks/on_post_build.py b/hooks/on_post_build.py new file mode 100644 index 00000000..1d723a0e --- /dev/null +++ b/hooks/on_post_build.py @@ -0,0 +1,79 @@ +from pathlib import Path + +from mkdocs.config import Config + + +def on_post_build(config: Config): + site_dir = Path(config["site_dir"]) + + print("INFO - Generating redirects") + # https://developers.google.com/search/docs/advanced/crawling/301-redirects + redirects = { + "en/jobs/index.html": "https://python.cz/en/", + "en/events/index.html": "https://python.cz/akce/", + "pyladies/s001-install/index.html": "https://pyladies.cz/v1/s001-install/", + "pyladies/s002-hello-world/index.html": "https://pyladies.cz/v1/s002-hello-world/", + "pyladies/s003-looping/index.html": "https://pyladies.cz/v1/s003-looping/", + "pyladies/s004-strings/index.html": "https://pyladies.cz/v1/s004-strings/", + "pyladies/s005-modules/index.html": "https://pyladies.cz/v1/s005-modules/", + "pyladies/s006-lists/index.html": "https://pyladies.cz/v1/s006-lists/", + "pyladies/s007-cards/index.html": "https://pyladies.cz/v1/s007-cards/", + "pyladies/s008-cards2/index.html": "https://pyladies.cz/v1/s008-cards2/", + "pyladies/s009-git/index.html": "https://pyladies.cz/v1/s009-git/", + "pyladies/s010-data/index.html": "https://pyladies.cz/v1/s010-data/", + "pyladies/s011-dicts/index.html": "https://pyladies.cz/v1/s011-dicts/", + "pyladies/s012-pyglet/index.html": "https://pyladies.cz/v1/s012-pyglet/", + "pyladies/s014-class/index.html": "https://pyladies.cz/v1/s014-class/", + "pyladies/s015-asteroids/index.html": "https://pyladies.cz/v1/s015-asteroids/", + "pyladies/s016-micropython/index.html": "https://pyladies.cz/v1/s016-micropython/", + } + for src, dst in redirects.items(): + path = Path(f"{site_dir}/{src}") + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text( + f""" + + + + + Přesměrování + + + + + +

Přesměrování

+

To, co tady bylo, je teď jinde: {dst}

+ + + """.strip() + ) + + print("INFO - Generating talks archive redirects") + path = Path(f"{site_dir}/404.html") + path.write_text( + """ + + + + + 404 + + + +

404

+ + + """.strip() + ) diff --git a/hooks/on_pre_build.py b/hooks/on_pre_build.py new file mode 100644 index 00000000..bb434a9f --- /dev/null +++ b/hooks/on_pre_build.py @@ -0,0 +1,11 @@ +from pathlib import Path + +from events import fetch_events, generate_icalendar +from mkdocs.config import Config + + +def on_pre_build(config: Config): + print("INFO - Generating events.ics") + Path(f"{config['theme'].dirs[0]}/events.ics").write_text( + generate_icalendar(fetch_events()) + ) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..b953ac23 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,61 @@ +site_name: Python v ČR +site_url: https://python.cz/ + +repo_url: https://github.com/pyvec/python.cz +repo_name: Upravit tyto stránky + +nav: + - Ahoj!: index.md + - Akce: akce.md + - Pro začátečníky: zacatecnici.md + - Práce: prace.md + - Zapoj se!: zapojse.md + - English: en.md + +theme: + name: material + logo: images/site-logo.svg + favicon: images/favicon.ico + language: cs + palette: + primary: custom + accent: custom + font: false + features: + - navigation.instant + - navigation.tracking + - navigation.tabs + - navigation.tabs.sticky + - content.action.edit + custom_dir: overrides + static_templates: + - events.ics + icon: + repo: fontawesome/brands/github + edit_uri: edit/main/docs/ + +markdown_extensions: + - toc: + toc_depth: 2-2 + permalink: '#' + permalink_title: Odkaz na tuto sekci + - pymdownx.emoji: + emoji_index: !!python/name:pymdownx.emoji.twemoji + emoji_generator: !!python/name:pymdownx.emoji.to_svg + - attr_list + - md_in_html + +hooks: + - hooks/on_pre_build.py + - hooks/on_page_markdown.py + - hooks/on_post_build.py + +extra_css: + - css/extra.css + +plugins: [] + + +watch: + - docs + - hooks diff --git a/overrides/main.html b/overrides/main.html new file mode 100644 index 00000000..d41ba3ed --- /dev/null +++ b/overrides/main.html @@ -0,0 +1,7 @@ +{% extends "base.html" %} + +{% block scripts %} + {{ super() }} + + +{% endblock %} diff --git a/overrides/partials/copyright.html b/overrides/partials/copyright.html new file mode 100644 index 00000000..ee10b8cc --- /dev/null +++ b/overrides/partials/copyright.html @@ -0,0 +1,8 @@ + diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..f726c66c --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1173 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "attrs" +version = "24.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + +[[package]] +name = "babel" +version = "2.16.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, +] + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "certifi" +version = "2024.8.30" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cssselect" +version = "1.2.0" +description = "cssselect parses CSS3 Selectors and translates them to XPath 1.0" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cssselect-1.2.0-py2.py3-none-any.whl", hash = "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e"}, + {file = "cssselect-1.2.0.tar.gz", hash = "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc"}, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "ics" +version = "0.8.0.dev0" +description = "Pythonic iCalendar (RFC 5545) Parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ics-0.8.0.dev0-py3-none-any.whl", hash = "sha256:7b78a02d3aa7e7143f27ff9072390cbda5795839f59fd09bd2f404932b49eaf6"}, + {file = "ics-0.8.0.dev0.tar.gz", hash = "sha256:51169026b9368e88abf167e7a86cb39c576299d7c36a871f1a39e36beabcfcae"}, +] + +[package.dependencies] +attrs = ">=20.3" +ics-vtimezones = ">=2020.1" +python-dateutil = ">=2.8" + +[package.extras] +checks = ["flake8 (>=3.8.1)", "mypy (==0.960)"] +dev = ["bump2version (>=1.0.0)", "tox (>=3.25)"] +docs = ["sphinx (>=5)", "sphinx-autodoc-typehints"] +test = ["freezegun (>=1.2.1)", "hypothesis (>=6)", "importlib-resources (>=1.4)", "lipsum (>=0.1.2)", "pytest (>=7)", "pytest-cov (>=3)", "tatsu (>4.2)"] + +[[package]] +name = "ics-vtimezones" +version = "2020.2" +description = "iCalendar vTimezone Data" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "ics_vtimezones-2020.2-py3-none-any.whl", hash = "sha256:e26de1a7e732b53f23bce88431ce6b2db59d03aad72f47d5785bfa3f56cdf118"}, + {file = "ics_vtimezones-2020.2.tar.gz", hash = "sha256:ee02fb3bb7df7e2e60ea11ad07ca30d3fee4d40929ae496651f76b76dc1cac73"}, +] + +[package.dependencies] +importlib_resources = ">=1.4" + +[package.extras] +update = ["ics (==0.8.*)"] + +[[package]] +name = "idna" +version = "3.8" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, + {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, +] + +[[package]] +name = "importlib-resources" +version = "6.4.4" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.4.4-py3-none-any.whl", hash = "sha256:dda242603d1c9cd836c3368b1174ed74cb4049ecd209e7a1a0104620c18c5c11"}, + {file = "importlib_resources-6.4.4.tar.gz", hash = "sha256:20600c8b7361938dc0bb2d5ec0297802e575df486f5a544fa414da65e13721f7"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "lxml" +version = "5.3.0" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +optional = false +python-versions = ">=3.6" +files = [ + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, + {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, + {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, + {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, + {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, + {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, + {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, + {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, + {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, + {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, + {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, + {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, + {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, + {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, + {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, + {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, + {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, + {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, + {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, + {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, + {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, + {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, +] + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml-html-clean"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] +source = ["Cython (>=3.0.11)"] + +[[package]] +name = "markdown" +version = "3.7" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, + {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, +] + +[package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markdown2" +version = "2.5.0" +description = "A fast and complete Python implementation of Markdown" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "markdown2-2.5.0-py2.py3-none-any.whl", hash = "sha256:300d4429b620ebc974ef512339a9e08bc080473f95135a91f33906e24e8280c1"}, + {file = "markdown2-2.5.0.tar.gz", hash = "sha256:9bff02911f8b617b61eb269c4c1a5f9b2087d7ff051604f66a61b63cab30adc2"}, +] + +[package.extras] +all = ["latex2mathml", "pygments (>=2.7.3)", "wavedrom"] +code-syntax-highlighting = ["pygments (>=2.7.3)"] +latex = ["latex2mathml"] +wavedrom = ["wavedrom"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +optional = false +python-versions = ">=3.6" +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, + {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +jinja2 = ">=2.11.1" +markdown = ">=3.3.6" +markupsafe = ">=2.0.1" +mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" +packaging = ">=20.5" +pathspec = ">=0.11.1" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[package.dependencies] +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + +[[package]] +name = "mkdocs-material" +version = "9.2.3" +description = "Documentation that simply works" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mkdocs_material-9.2.3-py3-none-any.whl", hash = "sha256:1cbac871826bbe0b5a42d7a86cfe729e03cef60cbd4d7425c640115bf1936360"}, + {file = "mkdocs_material-9.2.3.tar.gz", hash = "sha256:7a8c5638e28cb1c0a0c7596dd85835c461a73637ce8640ea9302dbc674c2aa29"}, +] + +[package.dependencies] +babel = ">=2.10.3" +colorama = ">=0.4" +jinja2 = ">=3.0" +lxml = ">=4.6" +markdown = ">=3.2" +mkdocs = ">=1.5.2" +mkdocs-material-extensions = ">=1.1" +paginate = ">=0.5.6" +pygments = ">=2.14" +pymdown-extensions = ">=9.9.1" +readtime = ">=2.0" +regex = ">=2022.4.24" +requests = ">=2.26" + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +description = "Extension pack for Python Markdown and MkDocs Material." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, +] + +[[package]] +name = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "paginate" +version = "0.5.7" +description = "Divides large result sets into pages for easier browsing" +optional = false +python-versions = "*" +files = [ + {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, + {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, +] + +[package.extras] +dev = ["pytest", "tox"] +lint = ["black"] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pymdown-extensions" +version = "10.9" +description = "Extension pack for Python Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pymdown_extensions-10.9-py3-none-any.whl", hash = "sha256:d323f7e90d83c86113ee78f3fe62fc9dee5f56b54d912660703ea1816fed5626"}, + {file = "pymdown_extensions-10.9.tar.gz", hash = "sha256:6ff740bcd99ec4172a938970d42b96128bdc9d4b9bcad72494f29921dc69b753"}, +] + +[package.dependencies] +markdown = ">=3.6" +pyyaml = "*" + +[package.extras] +extra = ["pygments (>=2.12)"] + +[[package]] +name = "pyquery" +version = "2.0.1" +description = "A jquery-like library for python" +optional = false +python-versions = "*" +files = [ + {file = "pyquery-2.0.1-py3-none-any.whl", hash = "sha256:aedfa0bd0eb9afc94b3ddbec8f375a6362b32bc9662f46e3e0d866483f4771b0"}, + {file = "pyquery-2.0.1.tar.gz", hash = "sha256:0194bb2706b12d037db12c51928fe9ebb36b72d9e719565daba5a6c595322faf"}, +] + +[package.dependencies] +cssselect = ">=1.2.0" +lxml = ">=2.1" + +[package.extras] +test = ["pytest", "pytest-cov", "requests", "webob", "webtest"] + +[[package]] +name = "pytest" +version = "7.4.0" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, + {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-ruff" +version = "0.4.1" +description = "pytest plugin to check ruff requirements." +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "pytest_ruff-0.4.1-py3-none-any.whl", hash = "sha256:69acd5b2ba68d65998c730b5b4d656788193190e45f61a53aa66ef8b390634a4"}, + {file = "pytest_ruff-0.4.1.tar.gz", hash = "sha256:2c9a30f15f384c229c881b52ec86cfaf1e79d39530dd7dd5f2d6aebe278f7eb7"}, +] + +[package.dependencies] +pytest = ">=5" +ruff = ">=0.0.242" + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "readtime" +version = "3.0.0" +description = "Calculates the time some text takes the average human to read, based on Medium's read time forumula" +optional = false +python-versions = "*" +files = [ + {file = "readtime-3.0.0.tar.gz", hash = "sha256:76c5a0d773ad49858c53b42ba3a942f62fbe20cc8c6f07875797ac7dc30963a9"}, +] + +[package.dependencies] +beautifulsoup4 = ">=4.0.1" +markdown2 = ">=2.4.3" +pyquery = ">=1.2" + +[[package]] +name = "regex" +version = "2024.7.24" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.8" +files = [ + {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"}, + {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"}, + {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"}, + {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"}, + {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"}, + {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"}, + {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, + {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, + {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, + {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, + {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, + {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, + {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, + {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, + {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, + {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, + {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, + {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"}, + {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"}, + {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"}, + {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"}, + {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"}, + {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"}, + {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"}, + {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"}, + {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"}, + {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"}, + {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"}, + {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"}, + {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"}, + {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"}, + {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "ruff" +version = "0.6.3" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.6.3-py3-none-linux_armv6l.whl", hash = "sha256:97f58fda4e309382ad30ede7f30e2791d70dd29ea17f41970119f55bdb7a45c3"}, + {file = "ruff-0.6.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3b061e49b5cf3a297b4d1c27ac5587954ccb4ff601160d3d6b2f70b1622194dc"}, + {file = "ruff-0.6.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:34e2824a13bb8c668c71c1760a6ac7d795ccbd8d38ff4a0d8471fdb15de910b1"}, + {file = "ruff-0.6.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bddfbb8d63c460f4b4128b6a506e7052bad4d6f3ff607ebbb41b0aa19c2770d1"}, + {file = "ruff-0.6.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ced3eeb44df75353e08ab3b6a9e113b5f3f996bea48d4f7c027bc528ba87b672"}, + {file = "ruff-0.6.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47021dff5445d549be954eb275156dfd7c37222acc1e8014311badcb9b4ec8c1"}, + {file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7d7bd20dc07cebd68cc8bc7b3f5ada6d637f42d947c85264f94b0d1cd9d87384"}, + {file = "ruff-0.6.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:500f166d03fc6d0e61c8e40a3ff853fa8a43d938f5d14c183c612df1b0d6c58a"}, + {file = "ruff-0.6.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42844ff678f9b976366b262fa2d1d1a3fe76f6e145bd92c84e27d172e3c34500"}, + {file = "ruff-0.6.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70452a10eb2d66549de8e75f89ae82462159855e983ddff91bc0bce6511d0470"}, + {file = "ruff-0.6.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:65a533235ed55f767d1fc62193a21cbf9e3329cf26d427b800fdeacfb77d296f"}, + {file = "ruff-0.6.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2e2c23cef30dc3cbe9cc5d04f2899e7f5e478c40d2e0a633513ad081f7361b5"}, + {file = "ruff-0.6.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8a136aa7d228975a6aee3dd8bea9b28e2b43e9444aa678fb62aeb1956ff2351"}, + {file = "ruff-0.6.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f92fe93bc72e262b7b3f2bba9879897e2d58a989b4714ba6a5a7273e842ad2f8"}, + {file = "ruff-0.6.3-py3-none-win32.whl", hash = "sha256:7a62d3b5b0d7f9143d94893f8ba43aa5a5c51a0ffc4a401aa97a81ed76930521"}, + {file = "ruff-0.6.3-py3-none-win_amd64.whl", hash = "sha256:746af39356fee2b89aada06c7376e1aa274a23493d7016059c3a72e3b296befb"}, + {file = "ruff-0.6.3-py3-none-win_arm64.whl", hash = "sha256:14a9528a8b70ccc7a847637c29e56fd1f9183a9db743bbc5b8e0c4ad60592a82"}, + {file = "ruff-0.6.3.tar.gz", hash = "sha256:183b99e9edd1ef63be34a3b51fee0a9f4ab95add123dbf89a71f7b1f0c991983"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "soupsieve" +version = "2.6" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, +] + +[[package]] +name = "strictyaml" +version = "1.7.3" +description = "Strict, typed YAML parser" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "strictyaml-1.7.3-py3-none-any.whl", hash = "sha256:fb5c8a4edb43bebb765959e420f9b3978d7f1af88c80606c03fb420888f5d1c7"}, + {file = "strictyaml-1.7.3.tar.gz", hash = "sha256:22f854a5fcab42b5ddba8030a0e4be51ca89af0267961c8d6cfa86395586c407"}, +] + +[package.dependencies] +python-dateutil = ">=2.6.0" + +[[package]] +name = "teemup" +version = "1.0.3" +description = "If Meetup didn't become a walled garden, the world wouldn't need Teemup" +optional = false +python-versions = "==3.11.*" +files = [ + {file = "teemup-1.0.3-py3-none-any.whl", hash = "sha256:f4e18eccc6a56bc9c8b628dc35dd65ec82a97e7b2140be802cd839cc49b188d6"}, + {file = "teemup-1.0.3.tar.gz", hash = "sha256:577945c42e143d1239913b962587efae4722b90e3eb6c1af1974324045dcaf23"}, +] + +[package.dependencies] +cssselect = "1.2.0" +lxml = "5.3.0" + +[[package]] +name = "urllib3" +version = "2.2.2" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "watchdog" +version = "5.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.9" +files = [ + {file = "watchdog-5.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bf3216ec994eabb2212df9861f19056ca0d4cd3516d56cb95801933876519bfe"}, + {file = "watchdog-5.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb59ad83a1700304fc1ac7bc53ae9e5cbe9d60a52ed9bba8e2e2d782a201bb2b"}, + {file = "watchdog-5.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1228cb097e855d1798b550be8f0e9f0cfbac4384f9a3e91f66d250d03e11294e"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3c177085c3d210d1c73cb4569442bdaef706ebebc423bd7aed9e90fc12b2e553"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:01ab36cddc836a0f202c66267daaef92ba5c17c7d6436deff0587bb61234c5c9"}, + {file = "watchdog-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0834c21efa3e767849b09e667274604c7cdfe30b49eb95d794565c53f4db3c1e"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1e26f570dd7f5178656affb24d6f0e22ce66c8daf88d4061a27bfb9ac866b40d"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d146331e6b206baa9f6dd40f72b5783ad2302c240df68e7fce196d30588ccf7b"}, + {file = "watchdog-5.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c96b1706430839872a3e33b9370ee3f7a0079f6b828129d88498ad1f96a0f45"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:663b096368ed7831ac42259919fdb9e0a1f0a8994d972675dfbcca0225e74de1"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:685931412978d00a91a193d9018fc9e394e565e8e7a0c275512a80e59c6e85f8"}, + {file = "watchdog-5.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:109daafc5b0f2a98d1fa9475ff9737eb3559d57b18129a36495e20c71de0b44f"}, + {file = "watchdog-5.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c2b4d90962639ae7cee371ea3a8da506831945d4418eee090c53bc38e6648dc6"}, + {file = "watchdog-5.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e58eafe9cc5ceebe1562cdb89bacdcd0ef470896e8b0139fe677a5abec243da"}, + {file = "watchdog-5.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8d747bf6d8fe5ce89cb1a36c3724d1599bd4cde3f90fcba518e6260c7058a52"}, + {file = "watchdog-5.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bc16d448a74a929b896ed9578c25756b2125400b19b3258be8d9a681c7ae8e71"}, + {file = "watchdog-5.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7e6b0e9b8a9dc3865d65888b5f5222da4ba9c4e09eab13cff5e305e7b7e7248f"}, + {file = "watchdog-5.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4fe6780915000743074236b21b6c37419aea71112af62237881bc265589fe463"}, + {file = "watchdog-5.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0710e9502727f688a7e06d48078545c54485b3d6eb53b171810879d8223c362a"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d76efab5248aafbf8a2c2a63cd7b9545e6b346ad1397af8b862a3bb3140787d8"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:ff4e957c45c446de34c513eadce01d0b65da7eee47c01dce472dd136124552c9"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:16c1aa3377bb1f82c5e24277fcbf4e2cac3c4ce46aaaf7212d53caa9076eb7b7"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:22fcad6168fc43cf0e709bd854be5b8edbb0b260f0a6f28f1ea9baa53c6907f7"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0120b2fa65732797ffa65fa8ee5540c288aa861d91447df298626d6385a24658"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2aa59fab7ff75281778c649557275ca3085eccbdf825a0e2a5ca3810e977afe5"}, + {file = "watchdog-5.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:78db0fe0336958fc0e1269545c980b6f33d04d184ba191b2800a8b71d3e971a9"}, + {file = "watchdog-5.0.0-py3-none-win32.whl", hash = "sha256:d1acef802916083f2ad7988efc7decf07e46e266916c0a09d8fb9d387288ea12"}, + {file = "watchdog-5.0.0-py3-none-win_amd64.whl", hash = "sha256:3c2d50fdb86aa6df3973313272f5a17eb26eab29ff5a0bf54b6d34597b4dc4e4"}, + {file = "watchdog-5.0.0-py3-none-win_ia64.whl", hash = "sha256:1d17ec7e022c34fa7ddc72aa41bf28c9d1207ffb193df18ba4f6fde453725b3c"}, + {file = "watchdog-5.0.0.tar.gz", hash = "sha256:990aedb9e2f336b45a70aed9c014450e7c4a70fd99c5f5b1834d57e1453a177e"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[metadata] +lock-version = "2.0" +python-versions = "3.11.*" +content-hash = "8d2f9fd1d95ee3b6db7a79a6bd3fd2160953ae6ca1dc34273f5cea1d5b4ba7a8" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..e7073caf --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,41 @@ +[tool.poetry] +description = "Czech Python user group homepage" +authors = ["Honza Javorek "] +readme = "README.md" +homepage = "https://python.cz/" +repository = "https://github.com/honzajavorek/mkdocs-python.cz/" +classifiers = ["Private :: Do Not Upload"] +package-mode = false + +[tool.poetry.dependencies] +python = "3.11.*" +mkdocs-material = "9.2.3" +strictyaml = "1.7.3" +ics = {version = "0.8.0.dev0", allow-prereleases = true} +requests = "2.31.0" +teemup = "1.0.3" +mkdocs = "1.6.1" + +[tool.poetry.group.dev.dependencies] +pytest = "7.4.0" +pytest-ruff = "0.4.1" + +[tool.pytest.ini_options] +python_files = "test_*.py" +testpaths = "tests" +norecursedirs = "node_modules" +addopts = "--ff --ruff --ruff-format" + +[tool.ruff] +target-version = "py312" + +[tool.ruff.lint] +extend-select = ["I"] + +[tool.ruff.lint.isort] +combine-as-imports = true +lines-after-imports = 2 + +[build-system] +requires = ["poetry-core>=1.5.0"] +build-backend = "poetry.core.masonry.api" diff --git a/pythoncz/__init__.py b/pythoncz/__init__.py deleted file mode 100644 index 89c65a3f..00000000 --- a/pythoncz/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -import os - -import yaml -from flask import Flask -from flask_frozen import Freezer - - -ROOT_DIR = os.path.join(os.path.dirname(__file__), '..') - -GITHUB_URL = 'https://github.com/pyvec/python.cz' -GITHUB_EDIT_URL = GITHUB_URL + '/edit/master/pythoncz' - -TEMPLATES_DIR_URL = GITHUB_EDIT_URL + '/templates/' -BUSINESS_LIST_URL = GITHUB_EDIT_URL + '/static/data/business.geojson' -BEGINNERS_DATA_URL = GITHUB_EDIT_URL + '/static/data/beginners.yml' -EVENTS_DATA_URL = GITHUB_EDIT_URL + '/static/data/events_feeds.yml' -JOBS_DATA_URL = GITHUB_EDIT_URL + '/static/data/jobs.yml' - -PYVEC_ACCOUNT_URL = ( - 'https://www.fio.cz/scgi-bin/hermes/' - 'dz-transparent.cgi?ID_ucet=2600260438' -) -GET_INVOLVED_URL = ( - 'https://github.com/pulls?utf8=%E2%9C%93&q=is%3Aopen+org%3Apyvec' -) - -GITHUB_ORGANIZATIONS = ('pyvec', 'pyladiescz') -GITHUB_TOKEN = os.getenv('GITHUB_TOKEN') or os.getenv('GH_TOKEN') -CACHE_DIR = os.getenv('CACHE_DIR') or os.path.join(ROOT_DIR, 'cache') - - -app = Flask('pythoncz') - - -with open(os.path.join(app.static_folder, 'data', 'events_feeds.yml')) as f: - app.config['CZECH_PYTHON_EVENTS_CALENDAR_URL'] = next(filter( - lambda feed: feed['name'] == 'Czech Python Events', - yaml.safe_load(f.read())['feeds'] - ))['url'] - - -freezer = Freezer(app) - -app.config.from_object(__name__) - - -from . import views # NOQA diff --git a/pythoncz/models/beginners.py b/pythoncz/models/beginners.py deleted file mode 100644 index f3efef6a..00000000 --- a/pythoncz/models/beginners.py +++ /dev/null @@ -1,14 +0,0 @@ -import os - -import yaml - -from .. import app - - -__all__ = ('data',) - - -# Data loaded on import time so file system is not read and YAML parsed -# on every request. -with open(os.path.join(app.static_folder, 'data', 'beginners.yml')) as f: - data = yaml.safe_load(f.read()) diff --git a/pythoncz/models/events.py b/pythoncz/models/events.py deleted file mode 100644 index a1238999..00000000 --- a/pythoncz/models/events.py +++ /dev/null @@ -1,92 +0,0 @@ -import re -from pathlib import Path -from typing import List - -import yaml -import requests -import ics -import arrow - -from pythoncz import app - - -feeds_datafile = Path(app.root_path) / "static/data/events_feeds.yml" -data = [] - - -def preprocess_ical(text: str) -> str: - """Removes VALARM ACTION:NONE from the iCal file (included in some events from Google Calendar) - """ - lines = text.splitlines() - new_lines = [] - - i = 0 - - try: - while i < len(lines): - if lines[i] != "BEGIN:VALARM" or lines[i + 1].replace("ACTION:", "") in {"DISPLAY", "AUDIO"}: - new_lines.append(lines[i]) - i += 1 - continue - - while lines[i] != "END:VALARM": - i += 1 - - i += 1 - except IndexError: - raise ValueError("Can't preprocess iCal file to remove ACTION:NONE") - - return '\r\n'.join(new_lines) - - -def load_events(ical_url): - try: - response = requests.get(ical_url) - - response.raise_for_status() - except Exception as e: - raise ValueError(f"Could not load iCal feed from {ical_url}") from e - - text = preprocess_ical(response.text) - - calendar = ics.Calendar(text) - - return calendar.events - - -def find_first_url(text): - match = re.search(r'https?://\S+', text or '') - if match: - return match.group(0) - return None - - -def set_url_from_description(event): - if not event.url: - url = find_first_url(event.description) - if url: - event.url = url - return event - - -@app.before_first_request -def load_data(): - feeds = yaml.safe_load(feeds_datafile.read_text())["feeds"] - - now = arrow.now("Europe/Prague") - for feed in feeds: - data.extend( - {"feed": feed, "event": set_url_from_description(event)} - for event in load_events(feed["ical"]) - if event.begin > now - ) - - data.sort(key=lambda e: e["event"].begin) - - -def get_calendar(): - calendar = ics.Calendar() - for e in data: - calendar.events.add(e["event"]) - - return calendar diff --git a/pythoncz/models/github.py b/pythoncz/models/github.py deleted file mode 100644 index b4417981..00000000 --- a/pythoncz/models/github.py +++ /dev/null @@ -1,169 +0,0 @@ -import os -import itertools -import warnings -from datetime import datetime - -import requests -from cachelib import FileSystemCache - -from pythoncz import app - - -__all__ = ('get_issues',) - - -get_issues_graphql_filename = ( - os.path.join(os.path.dirname(__file__), 'github_get_issues.graphql') -) -with open(get_issues_graphql_filename) as f: - GET_ISSUES_GRAPHQL = f.read() - -SIX_HOURS_AS_SECONDS = 21600 - - -cache = FileSystemCache(app.config['CACHE_DIR'], - default_timeout=SIX_HOURS_AS_SECONDS) - - -def get_issues(org_names): - issues = cache.get('github-issues') - if issues is None: - session = _create_api_session() - issues = itertools.chain(*( - _get_issues_for_org(session, org_name) for org_name in org_names) - ) - issues = _sort_issues(issues) - cache.set('github-issues', issues) - return issues - - -def _create_api_session(): - user_agent = ('pythoncz/{now.year}-{now.month} ' - '(+https://python.cz)').format(now=datetime.now()) - - session = requests.Session() - token = app.config['GITHUB_TOKEN'] - if not token: - raise Exception('GITHUB_TOKEN not configured') - session.headers.update({ - 'User-Agent': user_agent, - 'Authorization': 'token {}'.format(token), - }) - return session - - -def _get_issues_for_org(session, org_name): - json = _request_api(session, GET_ISSUES_GRAPHQL, {'org_name': org_name}) - try: - organization = json['data']['organization'] - repositories = _get_nodes(organization, 'repositories') - - for repository in repositories: - if repository['isPrivate']: - continue - - for issue in _get_nodes(repository, 'issues'): - yield _format_issue(org_name, repository, issue) - - for pull_request in _get_nodes(repository, 'pullRequests'): - yield _format_issue(org_name, repository, pull_request, - is_pull_request=True) - except KeyError as e: - raise ValueError( - 'Unexpected structure of the GitHub API response: {}'.format(e) - ) - - -def _request_api(session, query, variables): - res = session.post('https://api.github.com/graphql', json={ - 'query': query, - 'variables': variables, - }) - try: - json = res.json() - except ValueError as e: - res.raise_for_status() - raise ValueError( - 'Unexpected structure of the GitHub API response: {}'.format(e) - ) - if json.get('errors'): - message = '; '.join(error['message'] for error in json['errors']) - raise requests.HTTPError(message, response=res) - res.raise_for_status() - return json - - -def _format_issue(org_name, repository, issue, is_pull_request=False): - author = issue['author'] or { - 'login': None, - 'url': 'https://github.com/ghost', - } - labels = [label['name'] for label in _get_nodes(issue, 'labels')] - - return { - 'title': issue['title'], - 'html_url': issue['url'], - 'updated_at': issue['updatedAt'], - 'user': { - 'login': author['login'], - 'html_url': author['url'], - }, - 'is_pull_request': is_pull_request, - 'repository_name': repository['name'], - 'repository_url_html': repository['url'], - 'organization_name': org_name, - 'comments': issue['comments']['totalCount'], - 'participants': issue['participants']['totalCount'], - 'votes': _calculate_votes(issue), - 'labels': labels, - 'coach': 'coach' in labels, - 'sprint-idea': 'sprint-idea' in labels, - } - - -def _calculate_votes(issue): - """Get votes per issue from counts of Reactions - - A THUMBS_DOWN and CONFUSED counts as "-1", the rest as "+1". - """ - # First, count *all* reactions as "+1" - score = issue['reactions']['totalCount'] - - # Then change the negative ones from "+1" to "-1" - # (subtract 2 for each negative reaction) - score -= issue['thumbs_down']['totalCount'] * 2 - score -= issue['confuseds']['totalCount'] * 2 - - return score - - -def _get_nodes(node, connection_name): - connection_nodes = node[connection_name]['nodes'] - - if 'totalCount' in node[connection_name]: - connection_nodes_count = len(connection_nodes) - connection_nodes_total_count = node[connection_name]['totalCount'] - - if connection_nodes_count < connection_nodes_total_count: - warnings.warn(( - "The '{}' contain {} nodes in total, but only {} was fetched" - ).format( - connection_name, - connection_nodes_total_count, - connection_nodes_count, - ), UserWarning) - - return connection_nodes - - -def _sort_issues(issues): - return sorted(issues, key=_get_issue_sort_key, reverse=True) - - -def _get_issue_sort_key(issue): - return ( - issue['coach'], - issue['votes'], - issue['comments'] + issue['participants'], - issue['updated_at'], - ) diff --git a/pythoncz/models/github_get_issues.graphql b/pythoncz/models/github_get_issues.graphql deleted file mode 100644 index ba4f1bef..00000000 --- a/pythoncz/models/github_get_issues.graphql +++ /dev/null @@ -1,77 +0,0 @@ -query($org_name:String!) { - organization(login:$org_name) { - repositories(first:10, isLocked:false, privacy:PUBLIC, orderBy:{direction:DESC, field:PUSHED_AT}) { - totalCount - nodes { - name - nameWithOwner - isPrivate - url - issues(first:20, states:OPEN, orderBy:{direction:DESC, field:UPDATED_AT}) { - totalCount - nodes { - title - url - updatedAt - author { - login - url - } - labels(first:5) { - nodes { - name - } - } - reactions { - totalCount - } - thumbs_down:reactions(content:THUMBS_DOWN) { - totalCount - } - confuseds:reactions(content:CONFUSED) { - totalCount - } - comments { - totalCount - } - participants { - totalCount - } - } - } - pullRequests(first:20, states:OPEN, orderBy:{direction:DESC, field:UPDATED_AT}) { - totalCount - nodes { - title - url - updatedAt - author { - login - url - } - labels(first:5) { - nodes { - name - } - } - reactions { - totalCount - } - thumbs_down:reactions(content:THUMBS_DOWN) { - totalCount - } - confuseds:reactions(content:CONFUSED) { - totalCount - } - comments { - totalCount - } - participants { - totalCount - } - } - } - } - } - } -} diff --git a/pythoncz/models/jobs.py b/pythoncz/models/jobs.py deleted file mode 100644 index 0873e4ca..00000000 --- a/pythoncz/models/jobs.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import json - -import yaml -import czech_sort - -from pythoncz import app - - -__all__ = ('data',) - - -def _group_business_data(data): - groups = {} - for point in data: - if point.get('company'): - name = 'companies' - else: - name = 'individuals' - - groups.setdefault(name, []) - groups[name].append(point) - - for name, group in groups.items(): - groups[name] = _sort_cs(group) - - return groups - - -def _load_business_data(data_file): - with open(data_file) as f: - data = json.load(f) - - for feature in data['features']: - point = feature['properties'] - - geometry = feature.get('geometry') - if geometry: - point['coordinates'] = geometry['coordinates'] - - yield point - - -def _sort_cs(iterable, key='name'): - def item_key(item): - return czech_sort.key(item[key]) - return sorted(iterable, key=item_key) - - -# Data loaded on import time so file system is not read and YAML parsed -# on every request. - - -# jobs.yml -_path = os.path.join(app.static_folder, 'data', 'jobs.yml') -with open(os.path.join(_path)) as f: - data = yaml.safe_load(f.read()) - -data['job_boards'] = _sort_cs(data['job_boards']) -data['knowledge_tests'] = _sort_cs(data['knowledge_tests']) - - -# business.geojson -_path = os.path.join(app.static_folder, 'data', 'business.geojson') -data['business_groups'] = _group_business_data(_load_business_data(_path)) diff --git a/pythoncz/models/meetups.py b/pythoncz/models/meetups.py deleted file mode 100644 index ce28f6b2..00000000 --- a/pythoncz/models/meetups.py +++ /dev/null @@ -1,90 +0,0 @@ -from functools import lru_cache -from lxml import html -import requests -from slugify import slugify - - -__all__ = ('get_meetups',) - - -# Source: https://cs.wikipedia.org/wiki/Seznam_m%C4%9Bst_v_%C4%8Cesku_podle_po%C4%8Dtu_obyvatel -SORTED_CITY_SLUGS = [ - 'praha-pyvo', - 'brno-pyvo', - 'ostrava-pyvo', - 'plzen-pyvo', - 'liberec-pyvo', - 'olomouc-pyvo', - 'ceske-budejovice-pyvo', - 'usti-nad-labem-pyvo', - 'hradec-pyvo', - 'pardubice-pyvo', - 'zlin-pyvo', - 'havirov-pyvo', - 'kladno-pyvo', - 'most-pyvo', - 'opava-pyvo', - 'frydek-mistek-pyvo', - 'karvina-pyvo', - 'jihlava-pyvo', - 'teplice-pyvo', - 'decin-pyvo', - 'karlovy-vary-pyvo', -] - - -@lru_cache() -def get_meetups(lang='cs'): - return sort_by_city_size(scrape_meetups(lang)) - - -def scrape_meetups(lang='cs'): - """ - Ideally, pyvo.cz would have an API where we get all this info. Let's assume - HTML API is good enough API for us now. - """ - url = 'https://pyvo.cz/en/' if lang == 'en' else 'https://pyvo.cz/' - res = requests.get(url, headers={'Accept-Charset': 'utf-8'}) - res.raise_for_status() - - root = html.fromstring(res.content.decode('utf-8')) - root.make_links_absolute(res.url) - - for event in root.cssselect('#events .event'): - try: - yield { - 'name': event.cssselect('h3')[0].text_content().strip(), - 'url': event.cssselect('h3 a')[0].get('href'), - } - except IndexError: - continue - - -@lru_cache() -def scrape_cities(): - res = requests.get(WIKI_URL) - res.raise_for_status() - root = html.fromstring(res.text) - rows = root.cssselect('.wikitable tbody tr') - return [row.cssselect('td')[1].text_content().strip() for row in rows[1:]] - - -def sort_by_city_size(meetups): - """ - Sorts given iterable of meetups by the size of the city. While pyvo.cz - lists the meetups according to when the closest event happens or happened, - this doesn't make sense for python.cz where the meetups are listed just - as a general overview. Also alphabetical sorting is pretty much just - confusing for the visitor. It only makes sense to sort the meetups by the - size of the city. The most populated cities have a larger probability - that the visitor of the page is close to them, thus they deserve to be - higher in the list. - """ - # convert list [city1, city2, ...] into dict {city1: 0, city2: 1, ...} - city_slugs = {city: n for n, city in enumerate(SORTED_CITY_SLUGS)} - - def key_func(meetup): - slug = meetup['url'].rstrip('/').split('/')[-1] - return city_slugs[slug] - - return sorted(meetups, key=key_func) diff --git a/pythoncz/static/data/beginners.yml b/pythoncz/static/data/beginners.yml deleted file mode 100644 index b0e74777..00000000 --- a/pythoncz/static/data/beginners.yml +++ /dev/null @@ -1,54 +0,0 @@ -courses: - - name: Pro dámy - icon: female - links: - - text: Pravidelné srazy PyLadies - url: http://pyladies.cz - - text: Jednorázové workshopy Django Girls - url: http://djangogirls.org - - text: Workshopy Czechitas (v Pythonu jen některé) - url: http://www.czechitas.cz - - text: Workshopy Geek Girls Carrots v Ostravě (v Pythonu jen některé) - url: http://geekgirlscarrots.org - - - name: Pro studenty - icon: graduation-cap - links: - - text: Kurz ČVUT FEL A4B99RPH - url: https://cw.fel.cvut.cz/wiki/courses/a4b99rph/prednasky/start - - text: Kurzy MU Brno - url: http://is.muni.cz/vyhledavani/?search=jazyk+python+agenda%3Apr - - text: Kurz ZČU v Plzni KKY/ITE - url: https://portal.zcu.cz/StagPortletsJSR168/CleanUrl?urlid=prohlizeni-predmet-sylabus&predmetZkrPrac=KKY&predmetZkrPred=ITE - - text: Kurz ZČU v Plzni KKY/APK - url: https://portal.zcu.cz/StagPortletsJSR168/CleanUrl?urlid=prohlizeni-predmet-sylabus&predmetZkrPrac=KKY&predmetZkrPred=APK - - text: Kurz FIT ČVUT v Praze (BI-PYT) - url: http://bk.fit.cvut.cz/cz/predmety/00/00/00/00/00/00/01/29/14/p1291406.html - - - name: Pro mládež - icon: child - links: - - text: Kroužek na Praze 10 - url: 'http://kapsa.cz/cs/krouzky-pro-deti#python' - - text: Kroužek v Lázně Toušeň - url: 'https://www.programovanihrou.cz/' - - text: Czechitas - kroužky a tábory pro různé věkové kategorie - url: http://www.czechitas.cz - - text: Kroužky, workshopy a tábory makeITtoday - url: https://makeittoday.cz/courses_cz.html - - text: Kurzy v Praze pro děti 8-12 let - url: https://www.digikids.cz - - text: Kurzy v Praze a online od 11-19 let - url: https://vzdelanibudoucnosti.cz - - - name: Ostatní - icon: code - links: - - text: Nepravidelné intenzivní Python kurzy kiwi.com - url: 'https://pythonweekend.cz/' - - text: Celodenní workshopy a setkání pro Python začátečníky - url: 'https://pyworking.cz/' - - text: Sedlákovi - různé kurzy související s Pythonem - url: 'https://www.sedlakovi.org/kurzy/' - - text: Engeto - Python akademie v Praze a Brně - url: 'https://engeto.cz/python-akademie/' diff --git a/pythoncz/static/data/business.geojson b/pythoncz/static/data/business.geojson deleted file mode 100644 index 6238b411..00000000 --- a/pythoncz/static/data/business.geojson +++ /dev/null @@ -1,1437 +0,0 @@ -{ - "type":"FeatureCollection", - "features":[ - { - "type":"Feature", - "properties":{ - "name":"Neuron soundware", - "url":"https://www.neuronsw.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4301578, - 50.0599442 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"H2O.ai", - "url":"https://www.h2o.ai", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.452568, - 50.092226 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Akamai", - "url":"https://www.akamai.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4006753, - 50.0703272 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"CreativeDock", - "url":"https://creativedock.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.403246, - 50.076407 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"CYAN Research & Development s.r.o.", - "url":"https://www.cyanrd.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.594788, - 49.224163 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Twisto", - "url":"https://www.twisto.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.448897, - 50.093668 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Exponea", - "url":"https://exponea.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 17.125383000000056, - 48.145637 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Red Hat", - "url":"http://www.redhat.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.5816069, - 49.2261222 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Vaultier", - "url":"http://www.vaultier.org", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4319322, - 50.0713247 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Nanooq IT", - "url":"http://www.nanooq.eu/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4412558, - 50.1005167 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Inuits", - "url":"https://www.inuits.eu/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.402740, - 50.066360 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Y Soft", - "url":"https://www.ysoft.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.5805856, - 49.2222800 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Economia", - "url":"http://economia.ihned.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4538628, - 50.0912414 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Business Factory", - "url":"http://business-factory.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.6127981, - 49.2007753 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"ROI Hunter", - "url":"http://www.roihunter.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.6127981, - 49.2007753 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"ARMATURY Group a.s.", - "url":"http://www.armaturygroup.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 18.117507, - 49.922203 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"AOW", - "url":"http://aow.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.5758983, - 49.2182178 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"WebSupport", - "url":"https://www.websupport.sk/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 17.0734000, - 48.1551500 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"WebExpo", - "url":"http://webexpo.net/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.402740, - 50.066360 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Videoflot", - "url":"http://www.videoflot.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.5989164, - 49.2099833 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Grand IT", - "url":"http://grandit.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4812706, - 50.0713181 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"User Technologies", - "url":"http://usertechnologies.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4077361, - 50.0970125 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Tabfoundry", - "url":"https://www.tabfoundry.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4070231, - 50.0516553 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Kiwi.com", - "url":"http://kiwi.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.6007883, - 49.1840633 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Seznam.cz", - "url":"https://kariera.seznam.cz/", - "company":true - }, - "geometry":{ - "type":"MultiPoint", - "coordinates":[ - [ - 14.4009400, - 50.0710808 - ], - [ - 18.2722244, - 49.8162225 - ], - [ - 16.5990161, - 49.1718178 - ] - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Scuk.cz", - "url":"http://www.scuk.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4211, - 50.0872 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Scarfbot", - "url":"https://scarfbot.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.3937183, - 50.0746403 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"PC HELP", - "url":"http://www.pchelp.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 15.8952006, - 49.2172933 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Národní knihovna České republiky", - "url":"http://www.nkp.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4155778, - 50.0864564 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Česká národní banka", - "url":"https://www.cnb.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4285386, - 50.0870197 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Český Rozhlas", - "url":"http://www.rozhlas.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4345006, - 50.0785892 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Mergado", - "url":"https://www.mergado.cz/prace", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.5858589, - 49.2103950 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"IT4Innovations", - "url":"http://www.it4i.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 18.1560956, - 49.8376314 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"CodeScale", - "url":"http://www.codescale.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4009383, - 50.0694664 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"COEX", - "url":"https://www.coex.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4534092, - 50.1017800 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"WalkSource", - "url":"https://www.walksource.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.2538889, - 50.4236111 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Common Tongue", - "url":"http://www.commontongue.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4643847, - 50.0766186 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"CZ.NIC", - "url":"http://www.nic.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4513181, - 50.0791300 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"DIFFSolutions", - "url":"http://www.yottly.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4584328, - 50.0492022 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Dynameyes", - "url":"https://dynameyes.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.5476861, - 50.0728192 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Energomonitor", - "url":"https://www.energomonitor.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 17.9881464, - 49.4765639 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Fragaria", - "url":"http://www.fragaria.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4226003, - 50.0754761 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"ICFLIX", - "url":"http://www.icflix.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.0736344, - 49.9654289 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Imper", - "url":"https://imper.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4092097, - 50.0615613 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Investiční aukce", - "url":"http://www.investaukce.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.5727125, - 49.2332925 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"IT Academy", - "url":"http://www.it-academy.sk/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 17.1261600, - 48.1686100 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Vladimír Macek", - "url":"http://macek.sandbox.cz/" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 15.0957467, - 50.7451942 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Tomáš Ehrlich", - "url":"http://www.tomasehrlich.cz/" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.616667, - 49.2 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Creatiweb s.r.o.", - "url":"https://creatiweb.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4477, - 50.0772 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"CzechGlobe", - "url":"http://www.czechglobe.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.5930000, - 49.1870000 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Věroš Kaplan", - "url":"http://veroskaplan.cz" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.62073, - 49.19031 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Nubium Development SE", - "url":"http://www.nubium.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4292935, - 50.0809328 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"tcp cloud a.s.", - "url":"http://tcpcloud.eu", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4527403, - 50.0919999 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"OpenGeoLabs s.r.o.", - "url":"http://opengeolabs.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.5160186, - 50.0324947 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Direct-services s.r.o.", - "url":"http://www.direct-services.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 18.010309, - 49.594368 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Leadhub s.r.o.", - "url":"http://www.leadhub.co/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4036089, - 50.0751008 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Leadspicker s.r.o.", - "url":"https://leadspicker.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4262344, - 50.0907506 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Roští.cz, s.r.o.", - "url":"http://rosti.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 15.814811, - 50.206445 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Miloň Krejča", - "url":"http://www.milonline.eu" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 15.2232711, - 49.4309486 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Stories", - "url":"http://www.stories.bi/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4070231, - 50.0516553 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Vojtěch Bartoš", - "url":"http://vojtech.me" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.2134464, - 50.1236622 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"SparkTECH s.r.o.", - "url":"http://www.sparktech.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.341330, - 50.088202 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Jan Šváger", - "url":"https://www.svager.cz" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.631337, - 50.918289 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Petr Blahoš", - "url":"http://petr.blahos.com/" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.6380850, - 49.6401267 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"EPAM", - "url":"https://www.epam.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4343922, - 50.0506023 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Proboston Creative", - "url":"https://www.proboston.net", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4368203, - 50.0770531 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"OLC Systems s.r.o.", - "url":"https://www.olc.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 17.282280, - 49.576409 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"DANTEM s.r.o.", - "url":"http://www.dantem.cz/", - "company":true - }, - "geometry":{ - "type":"MultiPoint", - "coordinates":[ - [ - 14.3755908, - 50.0806400 - ], - [ - 18.2618453, - 49.8317611 - ] - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Jack.cz", - "url":"http://www.jack.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4334178, - 50.0896022 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"MSD IT Global Innovation Center s.r.o.", - "url":"http://www.msdit.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4099194, - 50.0670106 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"NTK - Národní technická knihovna", - "url":"https://www.techlib.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.3905997, - 50.1039000 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"SlushPool", - "url":"https://slushpool.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.47374, - 50.10514 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"STOCKED s.r.o.", - "url":"https://www.stocked.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4722669, - 50.0781181 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Atollon CS", - "url":"http://www.atollon.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.424799, - 50.088100 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"LMC s.r.o.", - "url":"https://www.lmc.eu/cs/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4568872, - 50.1028653 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"OKIN BPS", - "url":"https://okinbps.com/us/home/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 18.2923319, - 49.8392964 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"AutoCont CZ a. s.", - "url":"http://www.autocont.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 18.2715000, - 49.8410000 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"REMAK a.s.", - "url":"http://www.remak.eu/cs/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 18.1154847, - 49.4607186 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Heureka", - "url":"https://www.heurekadevs.cz/", - "company":true - }, - "geometry":{ - "type":"MultiPoint", - "coordinates":[ - [ - 15.058695, - 50.766428 - ], - [ - 14.443173, - 50.094377 - ], - [ - 13.3818922, - 49.7372414 - ] - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"SpaceKnow", - "url":"https://spaceknow.com/", - "company":true - }, - "geometry":{ - "type":"MultiPoint", - "coordinates":[ - [ - 14.4525094, - 50.0924147 - ] - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"BoxtrapSecurity", - "url":"https://www.boxtrapsecurity.com/", - "company":true - }, - "geometry":{ - "type":"MultiPoint", - "coordinates":[ - [ - 14.4220517, - 50.0823494 - ] - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Monitora media", - "url":"https://monitora.cz/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4092097, - 50.0615613 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Josef Rousek", - "url":"https://rousek.name/" - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4537655, - 50.0714368 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Oracle", - "url":"https://www.oracle.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.3753233, - 50.0559844 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Colpirio.com s.r.o.", - "url":"https://www.colpirio.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.602532, - 49.200819 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"ICT & MEDIA s.r.o.", - "url":"https://www.ictmedia.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.594788, - 49.224163 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"REDAMP.cz", - "url":"https://www.redamp.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 16.594788, - 49.224163 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Truly Scaled", - "url":"https://trulyscaled.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4538687, - 50.0696205 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Orgis IT", - "url":"https://www.orgis.cz", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 13.3701336, - 49.7315498 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"SentinelOne", - "url":"https://www.sentinelone.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.45066, - 50.0981919 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Medallia", - "url":"https://www.medallia.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.4216931, - 50.0833064 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Rossum", - "url":"https://www.rossum.ai", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.46422, - 50.09559 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Ataccama", - "url":"https://www.ataccama.com", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.45096, - 50.09214 - ] - } - }, - { - "type":"Feature", - "properties":{ - "name":"Pure Storage", - "url":"https://www.purestorage.com/", - "company":true - }, - "geometry":{ - "type":"Point", - "coordinates":[ - 14.44641, - 50.09437 - ] - } - } - ] -} diff --git a/pythoncz/static/data/events_feeds.yml b/pythoncz/static/data/events_feeds.yml deleted file mode 100644 index 09a3f2ee..00000000 --- a/pythoncz/static/data/events_feeds.yml +++ /dev/null @@ -1,19 +0,0 @@ -feeds: - - name: Pyvo - url: https://pyvo.cz/ - ical: https://pyvo.cz/api/pyvo.ics - - name: PyWorking - url: https://pyworking.cz/ - ical: https://pyworking.cz/workshops.ics - -## Meetup.com iCal is not available, see https://github.com/pyvec/python.cz/issues/557 -# - name: PyWorking Sessions -# url: https://pyworking.cz/ -# ical: https://www.meetup.com/pyworking/events/ical/ -# - name: PyData Prague -# url: https://www.meetup.com/PyData-Prague/ -# ical: https://www.meetup.com/PyData-Prague/events/ical/ - - - name: Czech Python Events - url: https://calendar.google.com/calendar/embed?src=kfdeelic1a13jsp7jvai861vfs%40group.calendar.google.com&ctz=Europe%2FPrague - ical: https://calendar.google.com/calendar/ical/kfdeelic1a13jsp7jvai861vfs%40group.calendar.google.com/public/basic.ics diff --git a/pythoncz/static/data/jobs.yml b/pythoncz/static/data/jobs.yml deleted file mode 100644 index 38801866..00000000 --- a/pythoncz/static/data/jobs.yml +++ /dev/null @@ -1,20 +0,0 @@ -job_boards: - # Pravidla: - # - # * Pouze odkazy, které přímo filtrují Python. - # * Pouze odkazy na české (maximálně slovenské) weby. - # * Odkazy, které v době přidávání povedou na prázdné výsledky vyhledávání - # (tzn. žádná nabídka práce v Pythonu) mají minimální šanci, že budou - # schváleny. - # - - name: StartupJobs.cz - url: 'https://www.startupjobs.cz/nabidky/15/python-programmer' - - - name: Jobs.cz - url: 'http://www.jobs.cz/prace/?q[]=python' - -knowledge_tests: - - name: StartupJobs.cz - url: 'https://www.startupjobs.cz/test/python' - - name: Toptal.com - url: 'http://www.toptal.com/python/interview-questions' diff --git a/pythoncz/static/images/404.png b/pythoncz/static/images/404.png deleted file mode 100644 index b457440b..00000000 Binary files a/pythoncz/static/images/404.png and /dev/null differ diff --git a/pythoncz/static/images/icon.png b/pythoncz/static/images/icon.png deleted file mode 100644 index 56eb15ac..00000000 Binary files a/pythoncz/static/images/icon.png and /dev/null differ diff --git a/pythoncz/static/images/learning-python-web.svg b/pythoncz/static/images/learning-python-web.svg deleted file mode 100644 index 2655e7ce..00000000 --- a/pythoncz/static/images/learning-python-web.svg +++ /dev/null @@ -1,863 +0,0 @@ - - - - -Created by potrace 1.13, written by Peter Selinger 2001-2015 - - - - - - - - - - - - - - - - - - - - diff --git a/pythoncz/static/images/logo-fb.png b/pythoncz/static/images/logo-fb.png deleted file mode 100644 index 978a5a84..00000000 Binary files a/pythoncz/static/images/logo-fb.png and /dev/null differ diff --git a/pythoncz/static/images/logo-plain.png b/pythoncz/static/images/logo-plain.png deleted file mode 100644 index dd4b3741..00000000 Binary files a/pythoncz/static/images/logo-plain.png and /dev/null differ diff --git a/pythoncz/static/images/pyvo.png b/pythoncz/static/images/pyvo.png deleted file mode 100644 index f85c03f4..00000000 Binary files a/pythoncz/static/images/pyvo.png and /dev/null differ diff --git a/pythoncz/static/images/uk-flag.svg b/pythoncz/static/images/uk-flag.svg deleted file mode 100644 index 63b1cb3d..00000000 --- a/pythoncz/static/images/uk-flag.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/pythoncz/static/main.css b/pythoncz/static/main.css deleted file mode 100644 index ac96a212..00000000 --- a/pythoncz/static/main.css +++ /dev/null @@ -1,725 +0,0 @@ - -body { - padding-top: 20px; - padding-bottom: 20px; - text-align: center; - height: auto; -} - -.container { - margin: 0 auto; - text-align: left; -} - -.header, -.marketing, -.footer { - padding-right: 15px; - padding-left: 15px; -} - -hr { - margin: 4em 0; -} - -h1, -h2, -h3, -h4, -.title, -.tasks .panel-body, -.online-courses .panel-body { - font-family: 'Arbutus Slab', serif; -} - -.content > h1, -h2, -h3 { - margin: 1.3em 0 1em 0; -} - -.content > h1 { - text-align: center; - font-size: 400%; - margin-bottom: 1.5em; -} - -.get-involved h2, -.beginners h2, -.jobs h2 { - text-align: center; -} - -.boxes h2 { - text-align: left; -} - -.boxes #organizuj h2 { - text-align: center; -} - -.columns h3 { - margin-top: 2em; -} - -.permalink-container { - position: relative; -} - -a.permalink { - position: absolute; - left: 0; - bottom: 0; - visibility: hidden; - font-family: sans-serif; - margin-left: 0.1em; - padding: 0 0.3em; - text-decoration: none; - color: #d5d5d5; -} - -h1[id]:hover .permalink, -h2[id]:hover .permalink, -h3[id]:hover .permalink, -h4[id]:hover .permalink, -h5[id]:hover .permalink, -h6[id]:hover .permalink { - visibility: visible; -} - -ul { - padding-left: 1.5em; -} - -ul li { - list-style-type: none; - position: relative; - margin-bottom: 0.3em; -} - -ul li:before { - content: '•'; - position: absolute; - left: -1em; -} - -.header { - padding-bottom: 1.5em; -} - -.header .title { - margin-top: 0; - margin-bottom: 0; - line-height: 2em; - font-size: 1.5em; -} - -.header .title a { - text-decoration: none; - color: #646464; -} - -.header .title img { - vertical-align: text-top; - margin-right: 0.1em; -} - -.logo { - text-align: center; - margin-bottom: 2em; -} - -.logo img { - width: 100%; -} - -ul.lead { - text-align: center; - padding: 0; -} - -ul.lead li:before, -ul.nav li:before, -ul.list-group li:before, -ul.events-list li:before { - display: none; -} - -.box-body { - min-height: 18em; - padding: 1em 0; -} - -.box-content { - min-height: 10em; -} - -.box h2 { - margin: 0 0 0.5em 0; -} - -.boxes { - margin: 2em 0; -} - -.index .call-to-action, .beginners .call-to-action { - text-align: right; -} - -.beginners .index .btn, .beginners .call-to-action .btn { - margin: 1em 0.5em 0 auto; -} - -.jobs .call-to-action, .get-involved .call-to-action, .events .call-to-action { - text-align: center; -} - -.jobs .call-to-action { - margin-top: -1em; -} - -.jobs .call-to-action .btn { - margin: 0 auto; -} - -.get-involved .call-to-action .btn { - margin: 1em auto; -} - -.discussions { - margin: 0; -} - -.discussions .list-group-item { - border: none; -} - -i.fa { - margin-right: 0.3em; -} - -h2 i.fa { - margin-right: 0.1em; -} - -.footer { - margin-top: 2em; - padding: 2em 1em; - border-top: 1px solid #e5e5e5; -} - -.footer p { - line-height: 2em; -} - -.footer .edit { - text-align: right; -} - -.footer .edit a { - text-align: left; -} - -.columns { - margin: 4em 2em; - - -webkit-columns: 2; - -moz-columns: 2; - columns: 2; - - -webkit-column-rule: 1px dotted #aaa; - -moz-column-rule: 1px dotted #aaa; - column-rule: 1px dotted #aaa; - - -webkit-column-gap: 3em; - -moz-column-gap: 3em; - column-gap: 3em; -} - -.columns-many { - -webkit-columns: 4; - -moz-columns: 4; - columns: 4; -} - -.columns h2:first-of-type, -.columns h3:first-of-type { - margin-top: 0; -} - -.columns img { - width: 100%; -} - -.help { - cursor: help; -} - -i.fa.help { - margin-left: 0.3em; -} - -img.img-small { - width: 50%; - margin-left: 25%; - margin-right: 25%; -} - -.tasks h3 { - text-align: center; - margin: 2em 0 2em 0; -} - -.tasks .panel-body { - height: 120px; - overflow: hidden; - position: relative; -} - -.tasks .panel-body .shadow { - position: absolute; - height: 20px; - bottom: 0; - left: 0; - right: 0; - box-shadow: inset 0px -15px 20px 0px rgba(255,255,255,1); -} - -.tasks .panel-body, -.online-courses .panel-body { - text-align: center; - font-size: 110%; -} - -.tasks .panel-body a { - color: #333; - height: 70px; - width: 100%; - display: table; -} - -.tasks .panel-body a span, -.tasks .panel-body a strong { - display: table-cell; - vertical-align: middle; -} - -.tasks .panel-footer { - text-align: right; -} - -.tasks .votes { - margin-right: 1em; -} - -.online-courses { - margin: 3em 0 1em 0; -} - -.online-courses .panel { - text-align: center; -} - -.jobs .thumbnail { - margin-top: 2em; -} - -.jobs #map, .events #map { - height: 350px; -} - -.cartoon { - display: block; - width: 100%; -} - -.cartoon-container { - margin: 0 auto; - padding: 2em 0; - max-width: 768px; -} - -.cartoon-hr { - padding-bottom: 4em; -} - -.panel-body .cartoon { - margin: 0 auto 1.5em auto; - max-height: 10em; - width: auto; -} - -.get-involved .cartoon { - margin-bottom: 2em; -} - -img[src*="jobs.svg"] { - max-height: 400px; -} - -.communication { - text-align: center; - display: flex; - justify-content: center; - flex-wrap: wrap; - margin: 2em 0 0 0; -} - -.communication-item { - display: block; - width: 10em; - height: 8em; - padding: 0; - margin: 0; - list-style-type: none; -} - -li.communication-item::before { - display: none; -} - -.communication-item a { - text-decoration: none; -} - -.communication-item-icon { - font-size: 2.5em; - display: block; -} - -.communication-item-icon i { - margin: 0; -} - -.communication-item-caption { - display: block; -} - -.label { - margin-right: 0.5em; -} - -.issues, .issues-error { - margin: 2em 0; -} - -.issues-error { - text-align: center; -} - -.issues-error .fa { - font-size: 200%; - margin-bottom: 0.3em; -} - -.issue { - padding: 0.5em 0.5em 0.5em 2em; - margin: 0.5em 0; - border-bottom: #F5F5F5 1px solid; - position: relative; -} - -.issue h3 { - font-size: inherit; - font-family: inherit; - margin: 0.3em 0 0.5em 0; - padding: 0; - white-space: nowrap; - overflow: hidden; -} - -.issue-title a { - color: #333; -} - -.issue-title::before { - content: "\00a0"; - width: 2em; - background: linear-gradient( - to right, - rgba(255,255,255,0) 0%, - rgba(255,255,255,1) 100% - ); - position: absolute; - right: 0.5em; -} - -.issue-icon { - color: #6CC644; - font-size: 1.5em; - position: absolute; - left: 0; - top: 0.7em; -} - -.issue-repo { - line-height: 0.7em; - font-size: 0.7em; - display: table; /* trick to have a 'block' as wide as content */ -} - -.issue-repo-specific .issue-title { - line-height: 1.3em; -} - -.issue-general .issue-title { - line-height: 2em; -} - -a.issue-repo, -a.issue-repo:hover, -a.issue-repo:focus, -.issue-details .label-default, -.issue-details a.label-default:hover, -.issue-details a.label-default:focus { - color: #777; -} - -.issue-details .label-default { - background-color: #F5F5F5; -} - -.issue-details a.label-default:hover, -.issue-details a.label-default:focus { - background-color: #E5E5E5; -} - -.label-pyladies { - background-color: #FF8181; -} -.label-sprint-idea { - background-color: #FBCA04; - color: black; -} - -i.icon-english { - display: inline-block; - width: 1.3em; - border-radius: 0.4em; - background: url("./images/uk-flag.svg"); - background-repeat: no-repeat; - background-size: contain; - background-position: center center; -} - -i.icon-english::before { - content: "\00a0"; -} - -.notice { - background: #337ab7; - color: #fff; - padding: 0.5em; - text-align: center; - margin-top: -20px; - margin-bottom: 0.5em; -} - -.notice a { - color: #fff; - text-decoration: underline; - font-weight: bold; -} - -.pagenotfound { - text-align: center; - margin-bottom: 2em; -} - -.pagenotfound img { - width: 50%; -} - -.events .lead, -.events-index h2 { - text-align: center; -} - -.events-index h3 { - text-align: left; -} - -.events .cartoon { - height: 10em; -} - -.events .content h2, -.events .content p, -.events-month { - text-align: center; -} - -.events-list, -.events-list li { - padding: 0; - margin: 0; -} - -.events-month { - padding-bottom: 0.3em; - border-bottom: 1px #eee solid; -} - -.events-list .event { - margin-bottom: 2em; -} - -.event-datetime { - color: #337ab7; - display: block; - text-align: center; - border: 1px #337ab7 solid; - border-radius: 0.3em; - min-width: 8em; /* sized for "WEDNESDAY" */ - padding: 0.3em 1em 1em 1em; -} - -.event-day, -.event-time { - display: block; -} - -.event-day { - font-size: 230%; -} - -.event-weekday { - text-transform: uppercase; - text-align: center; - display: inline-block; - min-width: 4.5em; -} - -.event h4 { - font-size: inherit; - font-family: inherit; - margin: 0.3em 0 0.5em 0; - padding: 0; - white-space: nowrap; - overflow: hidden; -} - -.event-title, a.event-title { - line-height: 2em; -} - -.event-title::before { - content: "\00a0"; - width: 2em; - background: linear-gradient( - to right, - rgba(255,255,255,0) 0%, - rgba(255,255,255,1) 100% - ); - position: absolute; - right: 0; -} - -.event-feed { - line-height: 0.7em; - font-size: 0.7em; - display: table; /* trick to have a 'block' as wide as content */ -} - -.event-feed, -.event-feed a, -.event-feed a:hover, -.event-feed a:focus { - color: #777; -} - -.events .content p.event-location, -.events .content p.event-map-links { - text-align: left; - font-size: 90%; - margin: 0; - margin-bottom: 0.1em; -} - -.event-map-links a { - margin-right: 0.5em; -} - -.event-tentative, -.event-tentative a, -.event-tentative a:hover, -.event-tentative a:focus, -.event-tentative .event-feed, -.event-tentative .event-datetime { - color: #AAA; - border-color: #AAA; -} - -.event-tentative .event-datetime { - padding-bottom: 0.5em; -} - -.event-tentative .event-day { - font-size: 180%; -} - -.event-tentative .event-weekday, -.event-tentative .event-time { - display: inline; -} - -.meetups { - margin: 2em 0; -} - -.meetups-city { - text-align: center; - font-size: 120%; -} - -.meetups-city a { - display: inline-block; - line-height: 2.5em; - padding-left: 3em; - margin: 0.5em 0; - background: url("./images/pyvo.png"); - background-size: 2em; - background-repeat: no-repeat; -} - - -@media only screen and (max-width: 992px) { - .boxes { - margin: 0; - padding: 0; - } - - .columns { - margin: 0; - - -webkit-columns: 1; - -moz-columns: 1; - columns: 1; - } - - .columns-many { - margin: 4em 2em; - - -webkit-columns: 3; - -moz-columns: 3; - columns: 3; - } -} - - -@media only screen and (max-width: 768px) { - .columns-many { - -webkit-columns: 2; - -moz-columns: 2; - columns: 2; - } - - .discussions { - width: 50%; - margin: 0 auto; - } - - .pagenotfound img { - width: 80%; - } -} diff --git a/pythoncz/static/maps.js b/pythoncz/static/maps.js deleted file mode 100644 index 889daaa4..00000000 --- a/pythoncz/static/maps.js +++ /dev/null @@ -1,42 +0,0 @@ - -var layer = L.tileLayer('https://a.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', { - maxZoom: 18, - attribution: '© OpenStreetMap contributors' -}); - - -$(function() { - var element = $('#map'); - - var iconSize = parseInt(element.attr('data-icon-size'), 10) || 16; - var icon = L.icon({ - iconUrl: element.attr('data-icon-src'), - iconSize: [iconSize, iconSize], - shadowSize: [0, 0], - iconAnchor: [iconSize / 2, iconSize / 2], - popupAnchor: [0, 0] - }); - - var zoom = element.attr('data-zoom') || 7; - var lat = element.attr('data-lat') || 49.8; - var lng = element.attr('data-lng') || 15.55; - - var map = L.map('map', {'scrollWheelZoom': false}) - .setView([lat, lng], zoom) - .addLayer(layer); - - var dataUrl = element.attr('data-src'); - $.getJSON(dataUrl, function(data) { - L.geoJson(data, { - pointToLayer: function (feature, coordinates) { - return L.marker(coordinates, {icon: icon}); - }, - onEachFeature: function (feature, marker) { - if (feature.properties) { - text = '

' + feature.properties.name + '

' - marker.bindPopup(text); - } - } - }).addTo(map); - }); -}); diff --git a/pythoncz/static/permalinks.js b/pythoncz/static/permalinks.js deleted file mode 100644 index d5484bbc..00000000 --- a/pythoncz/static/permalinks.js +++ /dev/null @@ -1,27 +0,0 @@ - -$(function() { - var lang = $('html').attr('lang'); - var title = (lang == 'cs') ? 'Trvalý odkaz' : 'Permanent link'; - - var selectors = []; - for (var i = 1; i <= 6; i++) { - selectors.push('h' + i + '[id]'); - } - - $(selectors.join(', ')).each(function () { - var $heading = $(this); - - var $link = $('', { - 'href': '#' + $heading.attr('id'), - 'class': 'permalink', - 'title': title, - 'text': '¶', - }); - var $container = $('', { - 'class': 'permalink-container', - }); - - $heading.append($container); - $container.append($link); - }); -}); diff --git a/pythoncz/templates/404.html b/pythoncz/templates/404.html deleted file mode 100644 index 0616c8e9..00000000 --- a/pythoncz/templates/404.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python - 404 -{% endblock %} -{% block content %} - -
-

Stránka nenalezena.

-

Page not found.

- 404 -
- -{% endblock %} diff --git a/pythoncz/templates/_base.html b/pythoncz/templates/_base.html deleted file mode 100644 index 2b143256..00000000 --- a/pythoncz/templates/_base.html +++ /dev/null @@ -1,141 +0,0 @@ -{% set is_homepage = request.path in ['/', '/{}'.format(lang), '/{}/'.format(lang)] %} - - - - - - - - - - - - - - - - - - - - - - - - {% block head %} - Python, programovací jazyk - - - - - {% endblock %} - - - - -
- - - {% if not is_homepage %} - - {% endif %} - -
- {% block content %}{% endblock %} -
- - - - - - {% if not debug %} - - - {% endif %} - {% block scripts %}{% endblock %} -
- - diff --git a/pythoncz/templates/_communication.html b/pythoncz/templates/_communication.html deleted file mode 100644 index 3df9f06f..00000000 --- a/pythoncz/templates/_communication.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - diff --git a/pythoncz/templates/_events.html b/pythoncz/templates/_events.html deleted file mode 100644 index 1eb794d9..00000000 --- a/pythoncz/templates/_events.html +++ /dev/null @@ -1,61 +0,0 @@ -{% for (year, month), events in data %} -

{{ month|format_month(lang) }}

-
    - {% for event in events %} -
  • -
    -
    - -
    -
    -

    - - {% if event.feed.url %} - - {{ event.feed.name }} - - {% else %} - {{ event.feed.name }} - {% endif %} - — iCal - - - {% if event.event.url %} - {{ event.event.name }} - {% else %} - {{ event.event.name }} - {% endif %} -

    - {% if event.event.location %} -

    - {{ event.event.location }} -

    - - {% endif %} -
    -
    -
  • - {% endfor %} -
-{% endfor %} diff --git a/pythoncz/templates/_meetups.html b/pythoncz/templates/_meetups.html deleted file mode 100644 index fd8a40b3..00000000 --- a/pythoncz/templates/_meetups.html +++ /dev/null @@ -1,7 +0,0 @@ -
-{% for meetup in meetups %} - -{% endfor %} -
diff --git a/pythoncz/templates/beginners_cs.html b/pythoncz/templates/beginners_cs.html deleted file mode 100644 index 1363ebce..00000000 --- a/pythoncz/templates/beginners_cs.html +++ /dev/null @@ -1,234 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python v ČR: Pro začátečníky - - - - -{% endblock %} - -{% block body_class %}beginners{% endblock %} - -{% block breadcrumb %} - Pro začátečníky -{% endblock %} - -{% set en = ''|safe %} - -{% block content %} -

Učíme se Python

-
    -
  • - Česká komunita je přátelská a živá. Vždy bude po ruce někdo, kdo ti pomůže. -
  • -
  • - Nebudeš mít problém sehnat práci. Pythonistů je nedostatek! -
  • -
  • - I kdyby weby vyšly z módy, Python nachází uplatnění v desítkách dalších oborů. -
  • -
- -
- -
- -

Online materiály – neumím vůbec programovat

-
-
-

- Následující materiály vznikly v rámci aktivit, které se snaží přiblížit IT ženám a ženy k IT. Jsou skvěle zpracované a může se z nich naučit programovat od úplných základů kdokoliv. -

- -
-
-
-
- - Chci umět obecně programovat -
- -
-
-
-
-
- - Chci vytvořit webovou stránku -
- -
-
-
-
-
- -
- -

Online materiály – programovat trochu umím

-
-

- - Přecházím z jiného jazyka -

- - -

- - Návody pro začátečníky -

- - -

- - Chci si to hned zkusit -

- - -

- - Knihy -

-

- Díky naší knihovničce si můžeš zadarmo půjčit knihy o Pythonu. Na stránkách Python Books navíc najdeš seznam knih, které si můžeš zdarma číst online nebo si je rovnou stáhnout. Určitě to omrkni! -

- -

- - Přednášky -

-

- Nahráváme přednášky ze srazů a dáváme je na YouTube. Na stránkách pyvideo.org najdeš přednášky z celého světa. -

- -

- - Konvence pro psaní kódu -

- - -

- - Kam nahrát web napsaný v Pythonu? -

- -
- -
- -

Kurzy

-
- {% for column in data.courses %} -
-
-
- - {{ column.name }} -
- -
-
- {% endfor %} -
- - -

Koučování

- -
-
-

Aneb osobní konzultace, mentoring, doučování…

- -
-
-{% endblock %} diff --git a/pythoncz/templates/events_cs.html b/pythoncz/templates/events_cs.html deleted file mode 100644 index eb4893eb..00000000 --- a/pythoncz/templates/events_cs.html +++ /dev/null @@ -1,81 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python v ČR: Akce - - - - -{% endblock %} - -{% block body_class %}events{% endblock %} - -{% block breadcrumb %} - Akce -{% endblock %} - -{% block content %} -

Akce

-
-

- Srazy, konference, workshopy. Vše, co se v ČR děje kolem jazyka Python, na jednom místě. -

-
-
- -
-
- -

Srazy

-

- Srazy Python programátorů zvané - Pyvo se pořádají po celé republice. Přijď si - poslechnout přednášky od chytrých lidí a - popovídat si nejen o Pythonu! -

- - {% include '_meetups.html' with context %} - -

- - Chci uspořádat sraz v mém městě - -

- -
- -
- -
- -

Všechny akce

-
    -
  • - Pravidelné akce lze přidat přes tzv. - iCal export. - Ten může generovat přímo vaše webová stránka (jako v případě - pyvo.cz), nebo jej lze vytáhnout - z nějaké služby (Google Calendar, meetup.com). URL exportu pak - na náš web přidejte pomocí - Pull Requestu. -
  • -
  • - Jednorázové akce lze přidat přes kalendář - Czech - Python Events. Do kalendáře má přístup mnoho z organizátorů - existujících Python akcí, takže je poproste, ať vaši akci přidají, - nebo napište na info@pyvec.org. První URL z popisu události se zde zobrazí jako - odkaz. -
  • -
- - {% include '_events.html' with context %} - -

- - iCal na všechny akce - -

- -
-{% endblock %} diff --git a/pythoncz/templates/events_en.html b/pythoncz/templates/events_en.html deleted file mode 100644 index b1ce4c4f..00000000 --- a/pythoncz/templates/events_en.html +++ /dev/null @@ -1,73 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python in the Czech Republic: Events - - - - -{% endblock %} - -{% block body_class %}events{% endblock %} - -{% block breadcrumb %} - Events -{% endblock %} - -{% block content %} -

Events

-
-

- Meetups, conferences, workshops. All Czech Python events, at one place. -

-
-
- -
-
- -

Meetups

-

- Python meetups called “Pyvo” are happening - across the country. You're welcome to come, or present at one! -

- - {% include '_meetups.html' with context %} - -
- -
- -
- -

All Events

-
    -
  • - Regular events can be added using an - iCal feed. - The feed can be generated directly by your website (as in the case of - pyvo.cz), or you can obtain it from - your platform, such as Google Calendar, meetup.com, etc. - Then send a Pull Request - to add your iCal feed URL to our website. -
  • -
  • - One-time events can be added using the - Czech - Python Events calendar. A lot of local event organizers have - access to edit the calendar, so you can ask them to add your event, - or let us know at info@pyvec.org. The first URL in the event description will - display here as a link. -
  • -
- - {% include '_events.html' with context %} - -

- - iCal of all events - -

- -
-{% endblock %} diff --git a/pythoncz/templates/get_involved_cs.html b/pythoncz/templates/get_involved_cs.html deleted file mode 100644 index c83940f4..00000000 --- a/pythoncz/templates/get_involved_cs.html +++ /dev/null @@ -1,259 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python v ČR: Zapoj se! - - - - -{% endblock %} - -{% block body_class %}get-involved{% endblock %} - -{% block breadcrumb %} - Zapoj se! -{% endblock %} - -{% block content %} -

Zapoj se!

-
-
-

- Líbí se ti Python? Pomoz nám ho rozšířit i mezi ostatní. Můžeš nám poslat peníze, učit, přednášet, psát, organizovat, programovat, ale třeba i jen vymýšlet, co a jak by se dalo zlepšit. Máme práci pro každého! -

-

- Python komunita je fajn jen díky tomu, že jsou v ní lidi, kteří se nebojí přiložit ruku k dílu. Všichni to děláme po večerech ve volném čase, z čirého nadšení. Děláme to proto, že chceme, aby to bylo lepší i pro tebe. Ať jsi profík nebo začátečník, z Prahy nebo z Karviné, můžeš nám pomoci. Odměnou ti budou kontakty, reference, zkušenosti. -

-
-
- -
- Česká Python komunita -
- -
-
-
-
-

- - Přispěj -

-

- Budeme rádi, když přispěješ na provoz neziskovky Pyvec, jejíž misí je podporovat a propagovat Python komunitu v ČR. -

-

- Srazy nebo workshopy dělají konkrétní lidé a Pyvec jim do toho nemluví - nabízí ale pomocnou ruku co se týče financí a zázemí. -

-
-
-
-
-
-
-

- - Vyučuj -

- -
-
-
- -
- -
-
-
-

- - Přednášej -

-
    -
  • - Přihlaš se s přednáškou na nejbližší sraz. -
  • -
  • - Pokud se necítíš na 15-20 minut, připrav si tzv. lightning talk. Je to pětiminutovka o čemkoliv a můžeš s ní přijít na srazy přijít i bez ohlášení. -
  • -
  • - Koukni se, jestli zrovna nehledají řečníky PyCon CZ nebo PyCon SK. Na mnohé konference se může přihlásit s přednáškou kdokoliv, stačí vyplnit formulář – tzv. CfP (Call for Proposals). -
  • -
-
-
-
- -
-
-
-

- - Piš -

-
    -
  • - Poděl se o zážitky z akcí nebo o svůj životní příběh na komunitní blog. -
  • -
  • - Technické články piš např. na Zdroják.cz. Redakce bude nadšená a ty budeš mít větší publikum. -
  • -
  • - Python učíme podle Open Source materiálů. Můžeš nám pomoci je vylepšovat. -
  • -
  • - Když se nám povede něco zorganizovat, snažíme se sepsat naše know-how do komunitní dokumentace. Chybí tam ještě spousta věcí! -
  • -
-
-
-
-
- -

Organizuj

-
-
-
    -
  • - Pokud ve tvém městě není Python sraz nebo třeba PyLadies skupina, tak gratulujeme: Můžeš je založit! Jestliže už se kolem tebe něco koná, nejlepší bude, když se spojíš s organizátory a zeptáš se, jak jim můžeš pomoci. -
  • -
  • - Každoročně sháníme dobrovolníky na konferenci PyCon CZ. Potřebné činnosti mají většinou pramálo společného s Pythonem a programováním. -
  • -
  • - Když se nám povede něco zorganizovat, snažíme se sepsat naše know-how do komunitní dokumentace. -
  • -
-
-
-
    -
  • - Všechny důležité věci řešíme na Slacku. Napiš nám na info@pyvec.org, my tě přidáme, pak můžeš pokukovat co se v jaké místnosti řeší a brzy uvidíš, kde je tvoje pomoc nejvíc potřeba. -
  • -
  • - Máme neziskovku Pyvec. Její misí je podporovat a propagovat Python komunitu v ČR. Srazy nebo workshopy dělají lidé jako ty a Pyvec jim do toho nemluví - nabízí ale pomocnou ruku co se týče financí a zázemí. -
  • -
-
-
- -

Další nápady

-
-
-

- Pro organizaci jednorázových úkolů používáme GitHub. Když nic, tak aspoň hlasuj nebo přidej vlastní nápad. Díky hlasům budeme mít přinejmenším přehled o tom, co si přeje nejvíc lidí. -

-

- Značka Kouč pomůže! znamená, že někdo navrhl, že ti s úkolem pomůže, pokud se do něj pustíš. Jestli se ty chceš někde navrhnout jako kouč, napiš to do komentáře pod daný úkol a přiřaď mu štítek „coach“. -

-

- - Přidat nápad - -

-
-
- - {% if error %} -
-
-

-
- Nápady se nepovedlo načíst. Většinu z nich lze alternativně najít na pyvec/zapojse. Pokud tento stav přetrvává, dejte nám o tom prosím vědět sem. -

-
-
- {% else %} -
- {% for issue in issues %} -
-

- {% if issue.is_pull_request %} - - {% else %} - - {% endif %} - - {% if issue.repository_name != 'zapojse' %} - - {{ issue.repository_name|lower }} - - {% endif %} - - - {{ issue.title }} - - -

-

- {% if issue.user.login %} - - {{ issue.user.login }} - - {% else %} - - ? - - {% endif %} - {% if issue.participants %} - - {{ issue.participants }} - - {% endif %} - {% if issue.votes %} - - {{ issue.votes }} - - {% endif %} - {% if issue.comments %} - - {{ issue.comments }} - - {% endif %} - - {% if issue.organization_name|lower == 'pyladiescz' %} - - PyLadies - - {% endif %} - {% if issue.coach %} - - Kouč pomůže! - - {% endif %} - {% if issue['sprint-idea'] %} - - Sprint - - {% endif %} -

-
- {% endfor %} -
- {% endif %} - - -{% endblock %} diff --git a/pythoncz/templates/index_cs.html b/pythoncz/templates/index_cs.html deleted file mode 100644 index 81a08795..00000000 --- a/pythoncz/templates/index_cs.html +++ /dev/null @@ -1,180 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python, programovací jazyk - - - - -{% endblock %} -{% block content %} - -
    -
  • - Python je moderní programovací jazyk. - Je univerzální – pohání weby i rakety. -
  • -
  • - Dobře se čte a dá se velice rychle naučit. - Je skvělý pro výuku programování. -
  • -
  • - Česká komunita je aktivní. - Najdeš v ní pomoc, kamarády i práci. -
  • -
- -
- Česká Python komunita -
-
- {% include '_communication.html' %} -
- -
- -
-

- - Nejbližší akce -

- {% include '_events.html' with context %} -

- - - Všechny akce - -

-
- -
- -
-
-
-
-

- - Blog -

-

- Díky blogu se dovíš o všem, co se v české Python komunitě zrovna děje. A co je nejlepší – můžeš klidně přidat svůj vlastní článek! -

-
-

- - - Chci být v obraze! - -

-
-
-
-
-
-

- - Pro začátečníky -

-

- Základy Pythonu se dají naučit i z prohlížeče. Máme pro tebe odkazy na výukové hry, online kurzy, videa, články, knihy a další. -

-
-

- - - Prahnu po vědění - -

-
-
- -
- -
-
-
-

- - Práce -

-

- Jakou práci seženeš, když se naučíš Python? Kdo jej používá? Jak a kam napsat nabídku práce pro Pythonisty? -

-
-

- - - Nabízím, poptávám - -

-
-
- -
- -
-
-
-

- - Zapoj se! -

-

- Pomoz nám rozšířit Python mezi ostatní. Pro lenochy s penězi máme číslo účtu, ale spíš oceníme, když se chopíš nějakého úkolu a dotlačíš jej do konce. Věčná sláva zaručena! Pokud chceš zorganizovat sraz či workshop ve svém městě, koukni na příručky pro pořadatele. -

-
-

- - - Toužím po věčné slávě - -

-
-
- -
- -
-
-
-

- - PyCon CZ -

-

- Česká Python konference! Pomoz nám s přípravami, propagací, zkus si přihlásit přednášku nebo workshop, sponzoruj nás, nebo prostě jen přijď a akci si užij! -

-
-

- - - Hurá, konference! - -

-
-
-
-
-
-

- - Knihovna -

-

- Máme knihovničku s literaturou o Pythonu a podobných technologiích. Knihy si lze zdarma půjčit – ozvi se a přijď si knížku vyzvednout na nejbližším srazu. Mimochodem, Python Books znáš, že? -

-
-

- - - Co si můžu půjčit? - -

-
-
-
-{% endblock %} diff --git a/pythoncz/templates/index_en.html b/pythoncz/templates/index_en.html deleted file mode 100644 index 74ffa688..00000000 --- a/pythoncz/templates/index_en.html +++ /dev/null @@ -1,150 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python in the Czech Republic - - - - -{% endblock %} -{% block content %} - -
    -
  • - Python is a modern programming language. See python.org for details. -
  • -
  • - The Czech Python community is active and friendly. -
  • -
  • - Come and join us at meetups and workshops in several cities! -
  • -
- -
- Czech Python User Group -
-
- {% include '_communication.html' %} -
- -
- -
-

- - Closest Events -

- {% include '_events.html' with context %} -

- - - All events - -

-
- -
- -
- -
-
-
-
-

- - Jobs -

-

- How can you address Czech software engineers working in Python with your job offer? Why is it worth the effort? -

-
-

- - - Let me hunt some heads! - -

-
-
- -
- -
-
-
-

- - For Ladies -

-

- There are events for ladies in multiple Czech cities. -

- -
-

- - - I want to get involved - -

-
-
- -
- -
-
-
-

- - PyCon CZ -

-

- Czech Python conference! Help us with preparations, spread the word, register a talk or workshop, consider sponsorship, or just come and enjoy the event! -

-
-

- - - Let me be your speaker! - -

-
-
- -
- -
-
-
-

- - Library -

-

- We have a library of Python-related books. If you want to borrow one, let us know, and come to the nearest Pyvo meetup to pick the book up. By the way, you already know Python Books, right? -

-
-

- - - What can I borrow? - -

-
-
-
-{% endblock %} diff --git a/pythoncz/templates/jobs_cs.html b/pythoncz/templates/jobs_cs.html deleted file mode 100644 index 6b08ec1e..00000000 --- a/pythoncz/templates/jobs_cs.html +++ /dev/null @@ -1,154 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python v ČR: Práce - - - - - - -{% endblock %} - -{% block body_class %}jobs{% endblock %} - -{% block breadcrumb %} - Práce -{% endblock %} - -{% block content %} -

Python a práce

-
-
-

- Používá vůbec někdo Python? Ano! Jde o jazyk vhodný k výuce nebo skriptování, ale to neznamená, že jej nepoužívají firmy z celého světa a nepíšou se v něm rozsáhlé projekty. -

-

- Ve světě Python používají např. Blender 3D, Google (YouTube!), Dropbox, Disqus, IBM, Instagram, Lucasfilm, Mozilla, NASA, Spotify, Walt Disney, a mnoho dalších – mimo jiné také spousta vědeckých organizací včetně švýcarského CERNu. -

-
-
- -
- -
- -

Python u nás

-
-
-
-
-
- -
-

- - Firmy, instituce -

- - -

- - Jednotlivci -

- -
-

- - - Chci být na seznamu - -

- -
- -

Jak najít práci?

-
-
- -
-
- -

Jak najít Python programátory?

-
-
-
    -
  • - Přijď na sraz a poptej se tam. Promluv si s reálnými lidmi, nadchni je, zlákej je, zjisti jaké mají možnosti a požadavky. -
  • -
  • - Popros svou společnost, aby sponzorovala příští PyCon CZ nebo PyCon SK. Obě konference jsou jedinečnou příležitostí promluvit si s 400+ vývojáři z celé střední Evropy. -
  • -
  • - Sepiš si inzerát a konkretizuj jej, aspoň do tvaru něčeho jako "hledám nadšence/nájemného profíka na krátkodobý projekt ve stylu CMS s galerií, nejspíš v Djangu, platím penězi". Čím víc bude lidsky od srdíčka a čím méně to budou odrážky ve stylu poptáváme/nabízíme, tím více lidí to zaujme. Nezapomeň napsat do jaké míry je možná práce na dálku. -
  • -
  • - Napiš inzerát na diskuse django-cs a py.cz (viz hlavní stránka) a na Facebookovou skupinu. Čte je mnoho českých a slovenských Pythonistů. -
  • -
  • - Nepřehlcuj žádnou z diskusí. Inzeráty jsou vítány, jsou zadarmo a bez omezení, ale pokud se to zvrhne, nemusí to tak zůstat. -
  • -
  • - Pošli inzerát na globální nástěnku nabídek – ta uveřejňuje nabídky zdarma, jen je potřeba se registrovat. Nabídka se pak objeví i na Twitter účtu @pyjobo. Inzeruj nabídku na pracovních serverech: {% for link in data.job_boards %}{{ link.name }}, {% endfor %}… -
  • -
-
-
- -

Chci, aby bylo víc Pythonistů!

-
-
-

- My taky! Máme na to dokonce neziskovku Pyvec. Můžeš se zapojit a s naší misí nám pomoci. -

-

- Pokud zastupuješ nějakou firmu, můžeš nás sponzorovat (číslo účtu). Přes Pyvec se peníze rozdělí na dílčí projekty. Podporujeme např. srazy a workshopy pro dámy – PyLadies, DjangoGirls. -

-

- Budeme také rádi, pokud nám napíšete success story o tom, jak jste Python použili u vás a jak vám to usnadnilo práci a co vše jste s ním dokázali. Takovou zkušenost zde rádi uveřejníme, klidně i na samostatné stránce, s logem apod. -

-
-
-{% endblock %} - - -{% block scripts %} - - -{% endblock %} diff --git a/pythoncz/templates/jobs_en.html b/pythoncz/templates/jobs_en.html deleted file mode 100644 index 9d5eb668..00000000 --- a/pythoncz/templates/jobs_en.html +++ /dev/null @@ -1,113 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - Python in the Czech Republic: Jobs - - - - - - -{% endblock %} - -{% block body_class %}jobs{% endblock %} - -{% block breadcrumb %} - Jobs -{% endblock %} - -{% block content %} -

Python Jobs

- -

Who uses Python in the Czech Republic?

-
-
-
-
-
- -
-

- - Companies, institutions -

- - -

- - Individuals -

- -
-

- - - I want to be on the list - -

- -
- -

How to find Czech Python software engineers?

-
-
-
    -
  • - Attend a meetup and ask around. Speak to real people, get them hooked for your ideas, learn about their options and requirements. -
  • -
  • - Ask your company to sponsor the next PyCon CZ or PyCon SK conferences. Both are unique opportunities to speak with 400+ developers from the central-european region. -
  • -
  • - Write down a job offer. Honest story instead of boring bullet points will bring you larger audience. Don't forget to mention how much is it possible to work remotely. -
  • -
  • - Send the offer to django-cs and py.cz discussions (see homepage) and to the Facebook group. Many Czech Pythonistas are subscribed to them. -
  • -
  • - Please do not overuse any of the discussions. Job offers are welcome, they're free and without limitations, but if it starts to be annoying, it doesn't have to be without regulation forever. -
  • -
  • - Post the offer to global job board – the board is free, only registration is needed. The offer then appears also on @pyjobo Twitter account. Advertise also at Czech job boards: {% for link in data.job_boards %}{{ link.name }}, {% endfor %}… -
  • -
-
-
- -

I wish more Czech Pythonistas would exist!

-
-
-

- We too and it's also the main goal of Pyvec, our nonprofit. Pyvec is dedicated to support all sorts of activities focused on introducing more people to Python in the Czech Republic. Pyvec also supports local chapters of PyLadies and DjangoGirls. If you wish to sponsor our activities, please drop an e-mail to info@pyvec.org. -

-
-
- -
- -
-{% endblock %} - - -{% block scripts %} - - -{% endblock %} diff --git a/pythoncz/templates/meta_redirect.html b/pythoncz/templates/meta_redirect.html deleted file mode 100644 index 7c460b55..00000000 --- a/pythoncz/templates/meta_redirect.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends '_base.html' %} -{% block head %} - - - - -{% endblock %} - -{% block content %} -

Přesměrování

-
-
-

- Obsah této stránky byl přesunut na novou adresu: - {{ url }}. -

-
-
-{% endblock %} diff --git a/pythoncz/views.py b/pythoncz/views.py deleted file mode 100644 index 7dfa5cfc..00000000 --- a/pythoncz/views.py +++ /dev/null @@ -1,242 +0,0 @@ -import logging -import os -import subprocess -import itertools -from fnmatch import fnmatch -from urllib.parse import quote_plus as url_quote_plus - -from arrow import Arrow -from flask import (render_template as _render_template, url_for, - request, make_response, send_from_directory, Response) - -from pythoncz import app, freezer -from pythoncz.models import jobs, beginners, github, events, meetups - - -INDEX_EVENTS_LIMIT = 3 - -logger = logging.getLogger(__name__) - - -# Templating - -def render_template(filename, **kwargs): - kwargs['template_url'] = app.config['TEMPLATES_DIR_URL'] + filename - return _render_template(filename, **kwargs) - - -@app.errorhandler(404) -def page_not_found(e): - return render_template('404.html'), 404 - - -@app.template_filter('urlencode') -def urlencode_filter(s): - return url_quote_plus(str(s).encode('utf8')) - - -@app.template_filter('format_dt') -def format_dt_filter(dt: Arrow, fmt): - return dt.to('Europe/Prague').strftime(fmt) - - -@app.template_filter('format_dt_iso') -def format_dt_iso_filter(dt: Arrow): - return dt.to('Europe/Prague').isoformat() - - -@app.template_filter('format_month') -def format_month_filter(month, lang='cs'): - months = {'en': [None, 'January', 'February', 'March', 'April', 'May', - 'June', 'July', 'August', 'September', 'October', - 'November', 'December'], - 'cs': [None, 'Leden', 'Únor', 'Březen', 'Duben', 'Květen', - 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', - 'Listopad', 'Prosinec']} - return months[lang][month] - - -@app.template_filter('format_weekday') -def format_weekday_filter(weekday, lang='cs'): - weekdays = {'en': ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', - 'Friday', 'Saturday'], - 'cs': ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', - 'pátek', 'sobota']} - return weekdays[lang][weekday] - - -@app.template_filter('format_weekday_short') -def format_weekday_short_filter(weekday, lang='cs'): - weekdays = {'en': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - 'cs': ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so']} - return weekdays[lang][weekday] - - -@app.context_processor -def inject_context(): - return { - 'debug': app.debug, - 'config': app.config, - 'url': request.url, - 'lang': 'cs', - } - - -def by_month(event): - return (event['event'].begin.year, event['event'].begin.month) - - -# Regular views - -@app.route('/') -def index_cs(): - data = itertools.groupby(events.data[:INDEX_EVENTS_LIMIT], key=by_month) - return render_template('index_cs.html', data=data) - - -@app.route('/en/') -def index_en(): - data = itertools.groupby(events.data[:INDEX_EVENTS_LIMIT], key=by_month) - return render_template('index_en.html', lang='en', data=data) - - -@app.route('/zacatecnici/') -def beginners_cs(): - return render_template('beginners_cs.html', data=beginners.data) - - -@app.route('/prace/') -def jobs_cs(): - return render_template('jobs_cs.html', data=jobs.data) - - -@app.route('/en/jobs/') -def jobs_en(): - return render_template('jobs_en.html', data=jobs.data, lang='en') - - -@app.route('/akce/') -def events_cs(): - return render_template('events_cs.html', - data=itertools.groupby(events.data, key=by_month), - meetups=meetups.get_meetups()) - - -@app.route('/en/events/') -def events_en(): - return render_template('events_en.html', lang='en', - data=itertools.groupby(events.data, key=by_month), - meetups=meetups.get_meetups(lang='en')) - - -@app.route('/events.ics') -def events_ical(): - return Response(events.get_calendar().serialize(), mimetype='text/calendar') - - -@app.route('/zapojse/') -def get_involved_cs(): - disabled = os.getenv('DISABLE_GITHUB_ISSUES_FETCH', False) - issues = [] - error = None - if not disabled: - try: - issues = github.get_issues(app.config['GITHUB_ORGANIZATIONS']) - except Exception as e: - logger.exception('Failed to fetch GitHub issues') - error = e - template = render_template('get_involved_cs.html', issues=issues, error=error) - return make_response(template) - - -# Redirects of legacy stuff - -def redirect(url, code=None): - """Return a response with a Meta redirect, code is unused""" - - # With static pages, we can't use HTTP redirects. - # Return a page wit instead. - # - # When Frozen-Flask gets support for redirects - # (https://github.com/Frozen-Flask/Frozen-Flask/issues/81), - # this should be revisited. - - return render_template('meta_redirect.html', url=url) - - -@app.route('/english.html') -def index_en_legacy(): - return redirect(url_for('index_en'), code=301) - - -@app.route('/pyladies/') -def pyladies(target): - return redirect('http://pyladies.cz/v1/' + target, code=301) - - -@freezer.register_generator -def pyladies(): - # This is hardcoded because it doesn't change & it's easier to hardcode it - targets = ( - 's001-install/', - 's002-hello-world/', - 's003-looping/', - 's004-strings/', - 's005-modules/', - 's006-lists/', - 's007-cards/', - 's008-cards2/', - 's009-git/', - 's010-data/', - 's011-dicts/', - 's012-pyglet/', - 's014-class/', - 's015-asteroids/', - 's016-micropython/', - ) - yield from ({'target': t} for t in targets) - - -@app.route('/pyladies/') -def pyladies_index(): - return redirect('http://pyladies.cz/', code=301) - - -# Talks, this used to redirect, but that's not possible with *.pdf HTML files -talks_dir = 'talks-archive' - - -@app.before_first_request -def clone_talks(): - try: - os.chdir(talks_dir) - except FileNotFoundError: - subprocess.run(('git', 'clone', - 'https://github.com/pyvec/talks-archive', - '--depth', '1')) - os.chdir(talks_dir) - else: - subprocess.run(('git', 'fetch', 'origin'), check=True) - subprocess.run(('git', 'reset', '--hard', 'origin/master'), check=True) - finally: - os.chdir('..') - - -@app.route('/talks/') -def talks(target): - # sends from pythoncz directory, hence ../ - return send_from_directory(f'../{talks_dir}', target) - - -@freezer.register_generator -def talks(): - ignore = ['.travis.yml', '.gitignore'] - for name, dirs, files in os.walk(talks_dir): - if '.git' in dirs: - dirs.remove('.git') - for file in files: - if file == '.git': - continue - if not any(fnmatch(file, ig) for ig in ignore): - path = os.path.relpath(os.path.join(name, file), talks_dir) - yield {'target': path} diff --git a/runserver.py b/runserver.py deleted file mode 100755 index 36a6ac31..00000000 --- a/runserver.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -from pythoncz import app, freezer - - -if __name__ == '__main__': - from elsa import cli - cli(app, freezer=freezer, base_url='https://python.cz') diff --git a/tests/models/events_test.py b/tests/models/events_test.py index 6a1b7564..17abe67a 100644 --- a/tests/models/events_test.py +++ b/tests/models/events_test.py @@ -2,13 +2,15 @@ import pytest from ics import Calendar, Event - -from pythoncz.models.events import (preprocess_ical, find_first_url, - set_url_from_description) +from pythoncz.models.events import ( + find_first_url, + preprocess_ical, + set_url_from_description, +) def test_preprocess_ical(): - path = Path(__file__).parent / 'invalid_ical.ics' + path = Path(__file__).parent / "invalid_ical.ics" text = preprocess_ical(path.read_text()) calendar = Calendar(text) @@ -24,31 +26,43 @@ def test_preprocess_ical(): assert events[0].alarms[0].action == "AUDIO" -@pytest.mark.parametrize('text,expected', [ - (None, None), - ('', None), - ('lorem ipsum dolor sit amet', None), - ('https://python.cz', 'https://python.cz'), - ('http://python.cz', 'http://python.cz'), - ('lorem ipsum https://python.cz dolor sit amet', 'https://python.cz'), - ('lorem https://python.cz ipsum https://pyvo.cz', 'https://python.cz'), -]) +@pytest.mark.parametrize( + "text,expected", + [ + (None, None), + ("", None), + ("lorem ipsum dolor sit amet", None), + ("https://python.cz", "https://python.cz"), + ("http://python.cz", "http://python.cz"), + ("lorem ipsum https://python.cz dolor sit amet", "https://python.cz"), + ("lorem https://python.cz ipsum https://pyvo.cz", "https://python.cz"), + ], +) def test_find_first_url(text, expected): assert find_first_url(text) == expected -@pytest.mark.parametrize('event,expected_url', [ - (Event(), None), - (Event(url='https://python.cz'), 'https://python.cz'), - (Event(description='https://pyvo.cz', url='https://python.cz'), - 'https://python.cz'), - (Event(description='https://pyvo.cz'), 'https://pyvo.cz'), - (Event(description=''' +@pytest.mark.parametrize( + "event,expected_url", + [ + (Event(), None), + (Event(url="https://python.cz"), "https://python.cz"), + ( + Event(description="https://pyvo.cz", url="https://python.cz"), + "https://python.cz", + ), + (Event(description="https://pyvo.cz"), "https://pyvo.cz"), + ( + Event( + description=""" See: https://www.meetup.com/PyData-Prague/events/257775220 Looking forward to see you! - '''), - 'https://www.meetup.com/PyData-Prague/events/257775220'), -]) + """ + ), + "https://www.meetup.com/PyData-Prague/events/257775220", + ), + ], +) def test_set_url_from_description(event, expected_url): assert set_url_from_description(event).url == expected_url diff --git a/tests/models/github_test.py b/tests/models/github_test.py deleted file mode 100644 index 7cde2447..00000000 --- a/tests/models/github_test.py +++ /dev/null @@ -1,400 +0,0 @@ -import re -import warnings - -import pytest -import requests -import responses -from cachelib import NullCache - -from pythoncz import app -from pythoncz.models import github as github_module -import github_test_fixtures as fixtures - - -class RequestsMock(responses.RequestsMock): - def add_github_graphql(self, *args, **kwargs): - """ - Convenience method to simplify adding fake responses for calls - to GitHub's v4 GraphQL API - """ - return self.add(responses.POST, 'https://api.github.com/graphql', - *args, **kwargs) - - -@pytest.fixture() -def patched_token(): - """ - Code expects the token to be configured. - Also this makes sure that we do not accidentally access the non-mock API. - """ - orig_value = app.config['GITHUB_TOKEN'] - app.config['GITHUB_TOKEN'] = 'test' - yield - app.config['GITHUB_TOKEN'] = orig_value - - -@pytest.fixture() -def requests_mock(patched_token): - """Provides mechanism for faking HTTP responses""" - with RequestsMock() as mock: - yield mock - - -@pytest.fixture() -def github(): - """Provides the 'github' module with caching disabled""" - original_cache = github_module.cache - github_module.cache = NullCache() - yield github_module - github_module.cache = original_cache - - -def test_get_issues_merges_orgs(github, requests_mock): - """ - Tests whether 'get_issues' makes two HTTP requests for each given GitHub - organization name and whether both data gets combined in the results - """ - issue_org1 = fixtures.issue() - requests_mock.add_github_graphql( - json=fixtures.api_response_body(repos=[ - fixtures.repository(issues=[issue_org1], pull_requests=[], - private=False), - ]), - ) - issue_org2 = fixtures.issue() - requests_mock.add_github_graphql( - json=fixtures.api_response_body(repos=[ - fixtures.repository(issues=[issue_org2], pull_requests=[], - private=False), - ]), - ) - - issues = github.get_issues(['org1', 'org2']) - titles = set(i['title'] for i in issues) - - assert titles == {issue_org1['title'], issue_org2['title']} - - -def test_get_issues_api_error(github, requests_mock): - """ - In case of API error, the 'get_issues' function should raise HTTPError - with combined error messages - """ - requests_mock.add_github_graphql( - status=500, - json={'errors': [{'message': 'Error 1'}, {'message': 'Error 2'}]}, - ) - error_message = 'Error 1; Error 2' - with pytest.raises(requests.HTTPError, match=error_message) as excinfo: - github.get_issues(['org']) - - assert excinfo.value.response.status_code == 500 - - -def test_create_api_session(patched_token, github): - """ - The '_create_api_session' helper should add User-Agent and Authorization - HTTP headers to the HTTP session - """ - session = github._create_api_session() - headers = session.headers - - assert 'https://python.cz' in headers.get('User-Agent') - assert re.match(r'token \w+', headers.get('Authorization')) - - -def test_get_issues_for_org_key_error(github, requests_mock): - """ - If the API response doesn't have the expected structure, the - '_get_issues_for_org' helper should raise ValueError - """ - requests_mock.add_github_graphql(json={'data': {}}) - error_message = 'Unexpected structure of the GitHub API response' - with pytest.raises(ValueError, match=error_message): - list(github._get_issues_for_org(requests.Session(), 'org')) - - -def test_get_issues_for_org_merges_issues_pull_requests(github, requests_mock): - """ - The '_get_issues_for_org' helper should merge both issues with - pull requests and treat them both as issues - """ - repo1 = fixtures.repository( - issues=[fixtures.issue(), fixtures.issue(), fixtures.issue()], - pull_requests=[fixtures.issue(pr=True)], - private=False - ) - repo2 = fixtures.repository( - issues=[fixtures.issue(), fixtures.issue()], - pull_requests=[fixtures.issue(pr=True), fixtures.issue(pr=True)], - private=False - ) - - expected_titles_are_pr = {} - for repo in [repo1, repo2]: - for issue in repo['issues']['nodes']: - expected_titles_are_pr[issue['title']] = False - for pull_request in repo['pullRequests']['nodes']: - expected_titles_are_pr[pull_request['title']] = True - - api_response_body = fixtures.api_response_body(repos=[repo1, repo2]) - requests_mock.add_github_graphql(json=api_response_body) - issues = github._get_issues_for_org(requests.Session(), 'org') - - titles_are_pr = {i['title']: i['is_pull_request'] for i in issues} - - assert titles_are_pr == expected_titles_are_pr - - -def test_get_issues_for_org_skips_private(github, requests_mock): - """ - The '_get_issues_for_org' helper should skip private repositories - """ - public_repo = fixtures.repository(private=False) - - expected_titles = set() - for issue in public_repo['issues']['nodes']: - expected_titles.add(issue['title']) - for pull_request in public_repo['pullRequests']['nodes']: - expected_titles.add(pull_request['title']) - - api_response_body = fixtures.api_response_body(repos=[ - fixtures.repository(private=True), - public_repo, - fixtures.repository(private=True), - fixtures.repository(private=True), - fixtures.repository(private=True), - ]) - requests_mock.add_github_graphql(json=api_response_body) - issues = github._get_issues_for_org(requests.Session(), 'org') - - titles = set(i['title'] for i in issues) - assert titles == expected_titles - - -def test_request_api_200_invalid_json(github, requests_mock): - """ - The '_request_api' helper should raise 'ValueError' if the JSON in the - response cannot be decoded - """ - requests_mock.add_github_graphql(body='... invalid JSON ...') - error_message = 'Unexpected structure of the GitHub API response' - with pytest.raises(ValueError, match=error_message): - github._request_api(requests.Session(), '... query ...', {}) - - -def test_request_api_500_invalid_json(github, requests_mock): - """ - The '_request_api' helper should raise HTTP error even if the JSON in the - response cannot be decoded - """ - requests_mock.add_github_graphql(status=500, body='... invalid JSON ...') - with pytest.raises(requests.HTTPError) as excinfo: - github._request_api(requests.Session(), '... query ...', {}) - - assert excinfo.value.response.status_code == 500 - - -@pytest.mark.parametrize('status_code', (200, 500)) -def test_request_api_X00_errors(github, requests_mock, status_code): - """ - The '_request_api' helper should raise HTTP error with error messages - sent in the response body if they're present, regardless of the HTTP status - code - """ - requests_mock.add_github_graphql( - status=status_code, - json={'errors': [{'message': 'Error 1'}, {'message': 'Error 2'}]}, - ) - error_message = 'Error 1; Error 2' - with pytest.raises(requests.HTTPError, match=error_message) as excinfo: - github._request_api(requests.Session(), '... query ...', {}) - - assert excinfo.value.response.status_code == status_code - - -def test_request_api_200(github, requests_mock): - """ - The '_request_api' helper should parse valid JSON response and return it - """ - requests_mock.add_github_graphql(json={'data': '...'}) - json = github._request_api(requests.Session(), '... query ...', {}) - - assert json == {'data': '...'} - - -def test_request_api_500(github, requests_mock): - """ - The '_request_api' helper should raise HTTP error if the HTTP status code - indicates HTTP error, even if there are no errors in the JSON response - """ - requests_mock.add_github_graphql(status=500, json={'data': '...'}) - with pytest.raises(requests.HTTPError) as excinfo: - github._request_api(requests.Session(), '... query ...', {}) - - assert excinfo.value.response.status_code == 500 - - -def test_format_issue_missing_author(github): - """ - The '_format_issue' helper should be able to deal with the situation - when the author is deleted/disabled user - """ - issue = fixtures.issue() - issue['author'] = None - formatted_issue = github._format_issue('org', fixtures.repository(), issue) - - assert formatted_issue['user'] == { - 'login': None, - 'html_url': 'https://github.com/ghost', - } - - -def test_format_issue_labels(github): - """The '_format_issue' helper should be able to process labels""" - issue = fixtures.issue(labels=[{'name': 'bug'}, {'name': 'feature'}]) - formatted_issue = github._format_issue('org', fixtures.repository(), issue) - - assert formatted_issue['labels'] == ['bug', 'feature'] - assert formatted_issue['coach'] is False - - -@pytest.mark.parametrize('label_name', ('coach', 'sprint-idea')) -def test_format_issue_special_labels(github, label_name): - """ - The '_format_issue' helper should be able to process the 'coach' label - and to mark the resulting formatted issue with the 'coach' flag accordingly - """ - issue = fixtures.issue(labels=[{'name': 'bug'}, {'name': label_name}]) - formatted_issue = github._format_issue('org', fixtures.repository(), issue) - - assert formatted_issue['labels'] == ['bug', label_name] - assert formatted_issue[label_name] is True - - -def test_format_issue_reactions(github): - """ - The '_format_issue' helper should be able to calculate 'votes' - from reactions - """ - issue = fixtures.issue(reactions_counts={ - 'LAUGH': 42, - 'HEART': 3, - }) - formatted_issue = github._format_issue('org', fixtures.repository(), issue) - - assert formatted_issue['votes'] == 42 + 3 - - -def test_calculate_votes(github): - """ - The '_calculate_votes' helper should correctly deal with negative votes - """ - votes = github._calculate_votes(fixtures.issue(reactions_counts={ - 'THUMBS_UP': 1, - 'THUMBS_DOWN': 1, - 'LAUGH': 1, - 'HOORAY': 1, - 'CONFUSED': 1, - 'HEART': 1, - })) - - assert votes == 2 - - -def test_get_nodes_without_total_count(github): - subnodes = [1, 2, 3, 4] - result = github._get_nodes({'something': {'nodes': subnodes}}, 'something') - - assert result == subnodes - - -def test_get_nodes_with_total_count(github): - subnodes = [1, 2, 3, 4] - result = github._get_nodes({'something': { - 'totalCount': len(subnodes), - 'nodes': subnodes, - }}, 'something') - - assert result == subnodes - - -def test_get_nodes_with_different_total_count(github): - """ - If the total count of sub-nodes is different then the number of sub-nodes - available in the API response, at least warn about the fact that there's - some data missing and limits should be raised or results paginated - """ - subnodes = [1, 2, 3, 4] - node = {'something': { - 'totalCount': len(subnodes) + 42, - 'nodes': subnodes, - }} - with warnings.catch_warnings(record=True) as recorded_warnings: - result = github._get_nodes(node, 'something') - - assert result == subnodes - assert len(recorded_warnings) == 1 - assert issubclass(recorded_warnings[0].category, UserWarning) - assert 'nodes in total, but only' in str(recorded_warnings[0].message) - - -def test_sort_issues_coach(github): - """ - Issues with coaching offer should always go first no matter what - """ - repository = fixtures.repository() - issues = [github._format_issue('org', repository, issue) for issue in [ - fixtures.issue(labels=[]), - fixtures.issue(labels=[{'name': 'foo'}]), - fixtures.issue(labels=[{'name': 'bar'}, {'name': 'coach'}]), - fixtures.issue(labels=[]), - ]] - sorted_issues = github._sort_issues(issues) - - assert sorted_issues[0]['coach'] is True - - -def test_sort_issues_votes(github): - """ - Issues with most votes should go first if there's no 'coach' issue - """ - repository = fixtures.repository() - issues = [github._format_issue('org', repository, issue) for issue in [ - fixtures.issue(labels=[], reactions_counts={'THUMBS_UP': 1}), - fixtures.issue(labels=[], reactions_counts={'THUMBS_DOWN': 1}), - fixtures.issue(labels=[], reactions_counts={'THUMBS_UP': 4}), - fixtures.issue(labels=[], reactions_counts={'THUMBS_UP': 3}), - ]] - sorted_issues = github._sort_issues(issues) - - assert sorted_issues[0]['votes'] == 4 - - -def test_sort_issues_activity(github): - """ - Issues with most user activity should go first if there's no 'coach' - issue and no reactions. - User activity is comments count + participants count - """ - issue1 = fixtures.issue(labels=[], reactions_counts={}) - issue1['comments']['totalCount'] = 3 - issue1['participants']['totalCount'] = 2 - - issue2 = fixtures.issue(labels=[], reactions_counts={}) - issue2['comments']['totalCount'] = 1 - issue2['participants']['totalCount'] = 9 - - issue3 = fixtures.issue(labels=[], reactions_counts={}) - issue3['comments']['totalCount'] = 0 - issue3['participants']['totalCount'] = 4 - - repository = fixtures.repository() - sorted_issues = github._sort_issues([ - github._format_issue('org', repository, issue) - for issue in [issue1, issue2, issue3] - ]) - - assert sorted_issues[0]['comments'] == 1 # + 9 = 10 - assert sorted_issues[1]['comments'] == 3 # + 2 = 7 - assert sorted_issues[2]['comments'] == 0 # + 4 = 4 diff --git a/tests/models/github_test_fixtures.py b/tests/models/github_test_fixtures.py deleted file mode 100644 index 06c3e0ca..00000000 --- a/tests/models/github_test_fixtures.py +++ /dev/null @@ -1,101 +0,0 @@ -import uuid -import random - - -def api_response_body(repos=None, repos_count=None): - if repos is None: - if repos_count is None: - repos_count = random.randint(2, 4) - repos = [repository() for i in range(repos_count)] - else: - repos_count = len(repos) - - return {'data': {'organization': {'repositories': { - 'totalCount': repos_count, - 'nodes': repos, - }}}} - - -def repository(issues=None, issues_count=None, - pull_requests=None, pull_requests_count=None, - private=None): - if issues is None: - if issues_count is None: - issues_count = random.randint(0, 4) - issues = [issue() for i in range(issues_count)] - else: - issues_count = len(issues) - - if pull_requests is None: - if pull_requests_count is None: - pull_requests_count = random.randint(0, 4) - pull_requests = [ - issue(pr=True) for i in range(pull_requests_count) - ] - else: - pull_requests_count = len(pull_requests) - - if private is None: - private = random.choice([True, False]) - - return { - 'name': 'repo-{}'.format(uuid.uuid4()), - 'nameWithOwner': 'org/repo', - 'isPrivate': private, - 'url': 'https://github.com/org/repo', - 'issues': { - 'totalCount': issues_count, - 'nodes': issues, - }, - 'pullRequests': { - 'totalCount': pull_requests_count, - 'nodes': pull_requests, - }, - } - - -def issue(pr=False, labels=None, reactions_counts=None): - issue_number = random.randint(1, 4242) - author = random.choice(['zuzejk', 'zzuzzy', 'encukou', 'honzajavorek']) - - if pr: - issue_type = 'pull' - title = "Fix '{}'".format(uuid.uuid4()) - else: - issue_type = 'issue' - title = "Looks like '{}' is broken".format(uuid.uuid4()) - - url = 'https://github.com/org/repo/{}/{}'.format(issue_type, issue_number) - - if labels is None: - labels_fake_values = ['bug', 'improvement', 'coach', 'duplicate'] - labels_count = random.randint(0, len(labels_fake_values)) - labels = [ - {'name': label_name} for label_name in - random.sample(labels_fake_values, labels_count) - ] - - if reactions_counts is None: - reaction_count = random.randint(0, 4242) - thumbsdown_count = random.randint(0, reaction_count) - confused_count = random.randint(0, reaction_count - thumbsdown_count) - else: - reaction_count = sum(reactions_counts.values()) - thumbsdown_count = reactions_counts.get('THUMBS_DOWN', 0) - confused_count = reactions_counts.get('CONFUSED', 0) - - return { - 'title': title, - 'url': url, - 'updatedAt': '2017-02-07T16:52:01Z', - 'author': { - 'login': author, - 'url': 'https://github.com/{}'.format(author), - }, - 'labels': {'nodes': labels}, - 'reactions': {'totalCount': reaction_count}, - 'thumbs_down': {'totalCount': thumbsdown_count}, - 'confuseds': {'totalCount': confused_count}, - 'comments': {'totalCount': random.randint(1, 4242)}, - 'participants': {'totalCount': random.randint(1, 42)}, - } diff --git a/tests/static/data/geojson_europe_test.py b/tests/static/data/geojson_europe_test.py index 243123f8..9bf7f461 100644 --- a/tests/static/data/geojson_europe_test.py +++ b/tests/static/data/geojson_europe_test.py @@ -10,16 +10,16 @@ ) -path = Path(__file__).parent / '../../../pythoncz/static/data/business.geojson' +path = Path(__file__).parent / "../../../pythoncz/static/data/business.geojson" with path.open() as f: - features = json.load(f)['features'] + features = json.load(f)["features"] assert len(features) > 0 -@pytest.mark.parametrize('feature', [ - pytest.param(feature, id=feature['properties']['name']) - for feature in features -]) +@pytest.mark.parametrize( + "feature", + [pytest.param(feature, id=feature["properties"]["name"]) for feature in features], +) def test_geojson_coords_are_in_europe(feature): """Tests whether entries in GeoJSON are in Europe. If this test failed for you, it's very likely because you have @@ -33,9 +33,9 @@ def test_geojson_coords_are_in_europe(feature): (which is Prague) in your GeoJSON entry. """ # For Point, convert list of coords to nested list - geometry_type = feature['geometry']['type'] - coords = feature['geometry']['coordinates'] - places = [coords] if geometry_type == 'Point' else coords + geometry_type = feature["geometry"]["type"] + coords = feature["geometry"]["coordinates"] + places = [coords] if geometry_type == "Point" else coords for place_coords in places: for i, coord in enumerate(place_coords): diff --git a/tests/static/data/valid_json_test.py b/tests/static/data/valid_json_test.py index 10b0a390..a139c156 100644 --- a/tests/static/data/valid_json_test.py +++ b/tests/static/data/valid_json_test.py @@ -4,15 +4,15 @@ import pytest -project_dir = Path(__file__).parent / '../../..' -paths = list(project_dir.rglob('*.*json')) +project_dir = Path(__file__).parent / "../../.." +paths = list(project_dir.rglob("*.*json")) assert len(paths) > 0 -@pytest.mark.parametrize('path', [ - pytest.param(path, id=str(path.relative_to(project_dir))) - for path in paths -]) +@pytest.mark.parametrize( + "path", + [pytest.param(path, id=str(path.relative_to(project_dir))) for path in paths], +) def test_json_file_is_valid(path): """Tests whether JSON data file is a valid JSON document.""" with path.open() as f: diff --git a/tests/static/data/valid_yaml_test.py b/tests/static/data/valid_yaml_test.py index bce25e02..890e8f3e 100644 --- a/tests/static/data/valid_yaml_test.py +++ b/tests/static/data/valid_yaml_test.py @@ -1,18 +1,18 @@ -import yaml from pathlib import Path import pytest +import yaml -project_dir = Path(__file__).parent / '../../..' -paths = list(project_dir.rglob('*.y*ml')) +project_dir = Path(__file__).parent / "../../.." +paths = list(project_dir.rglob("*.y*ml")) assert len(paths) > 0 -@pytest.mark.parametrize('path', [ - pytest.param(path, id=str(path.relative_to(project_dir))) - for path in paths -]) +@pytest.mark.parametrize( + "path", + [pytest.param(path, id=str(path.relative_to(project_dir))) for path in paths], +) def test_json_file_is_valid(path): """Tests whether YAML data file is a valid YAML document.""" with path.open() as f: diff --git a/tests/views_test.py b/tests/views_test.py index 941e421d..ba9749ad 100644 --- a/tests/views_test.py +++ b/tests/views_test.py @@ -2,9 +2,8 @@ import ics import pytest -from flask import url_for from cachelib import NullCache - +from flask import url_for from pythoncz import app from pythoncz.models import github as github_module @@ -17,23 +16,23 @@ def generate_issue_mock(**kwargs): of testing. """ issue = { - 'title': 'Test Issue', - 'html_url': 'http://github.com/pyvec/zapojse/issues/42', - 'updated_at': '2017-02-07T16:52:01Z', - 'user': { - 'login': 'encukou', - 'html_url': 'https://github.com/encukou', + "title": "Test Issue", + "html_url": "http://github.com/pyvec/zapojse/issues/42", + "updated_at": "2017-02-07T16:52:01Z", + "user": { + "login": "encukou", + "html_url": "https://github.com/encukou", }, - 'is_pull_request': False, - 'repository_name': 'zapojse', - 'repository_url_html': 'http://github.com/pyvec/zapojse/', - 'organization_name': 'pyvec', - 'comments': 5, - 'participants': 6, - 'votes': 3, - 'labels': ['bug'], - 'coach': False, - 'sprint-idea': False, + "is_pull_request": False, + "repository_name": "zapojse", + "repository_url_html": "http://github.com/pyvec/zapojse/", + "organization_name": "pyvec", + "comments": 5, + "participants": 6, + "votes": 3, + "labels": ["bug"], + "coach": False, + "sprint-idea": False, } for key, value in kwargs.items(): issue[key] = value @@ -77,97 +76,122 @@ def github(): def test_get_involved_cs_renders_ordinary_issue(github, test_client): def get_issues(self, *args, **kwargs): return [generate_issue_mock()] + github.get_issues = get_issues - response = test_client.get('/zapojse/') + response = test_client.get("/zapojse/") html = extract_issues_html(response.get_data(as_text=True)) assertions = [ - ('Test Issue', 'Issue title'), - ('http://github.com/pyvec/zapojse/issues/42', 'Issue URL'), - ('https://github.com/encukou', 'Issue author URL'), - ('od encukou', 'Issue author'), - ('komentářů: 5', 'Comments count'), - ('účastníků diskuze: 6', 'Participants count'), - ('hlasů: 3', 'Votes count'), + ("Test Issue", "Issue title"), + ("http://github.com/pyvec/zapojse/issues/42", "Issue URL"), + ("https://github.com/encukou", "Issue author URL"), + ("od encukou", "Issue author"), + ("komentářů: 5", "Comments count"), + ("účastníků diskuze: 6", "Participants count"), + ("hlasů: 3", "Votes count"), ] assert response.status_code == 200 for expectation, description in assertions: assert expectation in html, description + " isn't present in the HTML" -@pytest.mark.parametrize('label_name,label_text', [ - ('coach', 'Kouč pomůže!'), - ('sprint-idea', 'Sprint'), -]) -def test_get_involved_cs_renders_special_labels(github, test_client, - label_name, label_text): +@pytest.mark.parametrize( + "label_name,label_text", + [ + ("coach", "Kouč pomůže!"), + ("sprint-idea", "Sprint"), + ], +) +def test_get_involved_cs_renders_special_labels( + github, test_client, label_name, label_text +): """ Some GitHub issue labels have a special meaning and the 'get_involved_cs' page promotes them """ + def get_issues(self, *args, **kwargs): - return [generate_issue_mock(**{ - 'labels': [label_name], - label_name: True, - })] + return [ + generate_issue_mock( + **{ + "labels": [label_name], + label_name: True, + } + ) + ] + github.get_issues = get_issues - response = test_client.get('/zapojse/') + response = test_client.get("/zapojse/") html = extract_issues_html(response.get_data(as_text=True)) assert response.status_code == 200 assert label_text in html, "Special label isn't present in the HTML" -@pytest.mark.parametrize('repo_name,is_rendered,label_cls', [ - ('pyvec/zapojse', False, None), - ('pyvec/repo', True, None), - ('pyladiescz/repo', True, 'label-pyladies'), -]) -def test_get_involved_cs_renders_repo_name(github, test_client, - repo_name, is_rendered, label_cls): +@pytest.mark.parametrize( + "repo_name,is_rendered,label_cls", + [ + ("pyvec/zapojse", False, None), + ("pyvec/repo", True, None), + ("pyladiescz/repo", True, "label-pyladies"), + ], +) +def test_get_involved_cs_renders_repo_name( + github, test_client, repo_name, is_rendered, label_cls +): """ If the issue (or pull request) is not from the pyvec/zapojse repository, it is preceeded by a link to its repository. If the issue is from the PyLadiesCZ GitHub organization, it is labeled with a 'PyLadies' label """ + def get_issues(self, *args, **kwargs): - return [generate_issue_mock( - html_url='http://github.com/{}/issues/42'.format(repo_name), - repository_name=repo_name.split('/')[1], - repository_url_html='http://github.com/{}/'.format(repo_name), - organization_name=repo_name.split('/')[0], - )] + return [ + generate_issue_mock( + html_url="http://github.com/{}/issues/42".format(repo_name), + repository_name=repo_name.split("/")[1], + repository_url_html="http://github.com/{}/".format(repo_name), + organization_name=repo_name.split("/")[0], + ) + ] + github.get_issues = get_issues - response = test_client.get('/zapojse/') + response = test_client.get("/zapojse/") html = extract_issues_html(response.get_data(as_text=True)) if is_rendered: - assert 'fa-code-branch' in html, "Repo icon isn't present in the HTML" - url = 'http://github.com/{}/'.format(repo_name) + assert "fa-code-branch" in html, "Repo icon isn't present in the HTML" + url = "http://github.com/{}/".format(repo_name) assert url in html, "Repo URL isn't present in the HTML" else: - assert 'fa-code-branch' not in html, "Repo icon is present in the HTML" + assert "fa-code-branch" not in html, "Repo icon is present in the HTML" if label_cls: assert label_cls in html, "Label isn't present in the HTML" -@pytest.mark.parametrize('is_pull_request,icon_name', [ - (True, 'fa-pencil-square'), - (False, 'fa-exclamation-circle'), -]) -def test_get_involved_cs_pull_request_icon(github, test_client, - is_pull_request, icon_name): +@pytest.mark.parametrize( + "is_pull_request,icon_name", + [ + (True, "fa-pencil-square"), + (False, "fa-exclamation-circle"), + ], +) +def test_get_involved_cs_pull_request_icon( + github, test_client, is_pull_request, icon_name +): """ Pull Requests have a different icon than Issues """ + def get_issues(self, *args, **kwargs): return [generate_issue_mock(is_pull_request=is_pull_request)] + github.get_issues = get_issues - response = test_client.get('/zapojse/') + response = test_client.get("/zapojse/") html = extract_issues_html(response.get_data(as_text=True)) assert icon_name in html @@ -179,56 +203,56 @@ def test_get_involved_cs_handles_error(github, test_client): should handle it and still display most of the content. The issues section should contain an error message with some useful links """ + def get_issues(self, *args, **kwargs): - raise RuntimeError('Ouch!') + raise RuntimeError("Ouch!") + github.get_issues = get_issues - response = test_client.get('/zapojse/') + response = test_client.get("/zapojse/") html = extract_issues_html(response.get_data(as_text=True)) assert response.status_code == 200 # otherwise Elsa build fails message = "DIV with the 'issues-error' class isn't present in the HTML" - assert 'issues-error' in html, message + assert "issues-error" in html, message message = "Link to alternative issues listing isn't present in the HTML" - assert 'https://github.com/pyvec/zapojse/issues' in html, message - url = '{base_url}?title={title}&body={body}'.format( - base_url='https://github.com/pyvec/python.cz/issues/new', - title=url_quote_plus('Nefunguje Zapoj se'), - body=url_quote_plus('RuntimeError: Ouch!'), + assert "https://github.com/pyvec/zapojse/issues" in html, message + url = "{base_url}?title={title}&body={body}".format( + base_url="https://github.com/pyvec/python.cz/issues/new", + title=url_quote_plus("Nefunguje Zapoj se"), + body=url_quote_plus("RuntimeError: Ouch!"), ) assert url in html, "URL for filing a bug report isn't present in the HTML" def test_index_en_legacy_redirect(test_client): - response = test_client.get('/english.html') - url = url_for('index_en') + response = test_client.get("/english.html") + url = url_for("index_en") html = response.get_data(as_text=True) - head = html[:html.find('')] + head = html[: html.find("")] assert ''.format(url) in head -@pytest.mark.parametrize('suffix', ('', 's001-install/')) +@pytest.mark.parametrize("suffix", ("", "s001-install/")) def test_pyladies_redirect(test_client, suffix): - response = test_client.get('/pyladies/' + suffix) - url = 'http://pyladies.cz/' + response = test_client.get("/pyladies/" + suffix) + url = "http://pyladies.cz/" if suffix: - url += 'v1/' + suffix + url += "v1/" + suffix html = response.get_data(as_text=True) - head = html[:html.find('')] + head = html[: html.find("")] assert ''.format(url) in head def test_talks_pdf_download(test_client): - response = test_client.get( - '/talks/brno-2013-11-28-veros-kaplan-postgis.pdf' - ) - assert response.headers['content-type'] == 'application/pdf' + response = test_client.get("/talks/brno-2013-11-28-veros-kaplan-postgis.pdf") + assert response.headers["content-type"] == "application/pdf" def test_ical_generation(test_client): - response = test_client.get('events.ics') + response = test_client.get("events.ics") assert response.status_code == 200 - assert 'text/calendar' in response.headers['content-type'] + assert "text/calendar" in response.headers["content-type"] assert ics.Calendar(response.get_data(as_text=True))