From 3a0052fe198945b6e0d3f601f600abeee8ecf0a0 Mon Sep 17 00:00:00 2001 From: Pavel Vavilin Date: Mon, 21 Sep 2026 10:58:14 +0500 Subject: [PATCH] Essential SQLAlchemy: Chapter 7 (P.II) --- Essential-SQLAlchemy-2nd.org | 295 ++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + uv.lock | 133 ++++++++++++++++ 3 files changed, 428 insertions(+), 1 deletion(-) diff --git a/Essential-SQLAlchemy-2nd.org b/Essential-SQLAlchemy-2nd.org index 0cdd4ca..d9506b2 100644 --- a/Essential-SQLAlchemy-2nd.org +++ b/Essential-SQLAlchemy-2nd.org @@ -3853,7 +3853,7 @@ Table( * Chapter 7: Working with Data via SQLAlchemy ORM ** SQLAlchemy v1 :PROPERTIES: -:header-args:python: :session *ch7-v1* :tangle ch7-v1.py :cache no +:header-args:python: :session *ch7-v1* :tangle ch7-v1.py :cache yes :END: #+BEGIN_SRC python :shebang "#!/usr/bin/env python3" :results none @@ -3991,5 +3991,298 @@ Table( ) ] #+end_example +**** Controlling the Columns in the Query +#+BEGIN_SRC python :results table + session.query(Cookie.cookie_name, Cookie.quantity).first() +#+END_SRC + +#+RESULTS: +| chocolate chip | 12 | +**** Ordering +#+BEGIN_SRC python :results table + results = [('quantity', 'cookie_name')] + + for cookie in session.query(Cookie).order_by(Cookie.quantity): + results.append((cookie.quantity, cookie.cookie_name)) + results +#+END_SRC + +#+RESULTS[f815708c1194af5a00412df8cece6ec9db3af9ad]: +| quantity | cookie_name | +| 1 | dark chocolate chip | +| 1 | molasses | +| 12 | chocolate chip | +| 24 | peanut butter | +| 100 | oatmeal raisin | + +#+BEGIN_SRC python :results value table + import pandas as pd + from sqlalchemy import desc + results = {'quantity': [], 'cookie_name': []} + + for cookie in session.query(Cookie).order_by(desc(Cookie.quantity)): + results['quantity'].append(cookie.quantity) + results['cookie_name'].append(cookie.cookie_name) + df = pd.DataFrame(results) + # Преобразуем DataFrame в список списков для Org Babel + # 1. Заголовки: берем названия колонок и добавляем пустую ячейку для индекса + headers = [''] + df.columns.tolist() + + # 2. Данные: объединяем индекс и значения строк + rows = [[idx] + row.tolist() for idx, row in df.iterrows()] + + # 3. Собираем всё вместе: заголовки + разделитель (None) + строки + summary = [headers] + [None] + rows + summary +#+END_SRC + +#+RESULTS[be902b1b955e9eadcdc6ba6670ac21a903f3f662]: +| | quantity | cookie_name | +|---+----------+---------------------| +| 0 | 100 | oatmeal raisin | +| 1 | 24 | peanut butter | +| 2 | 12 | chocolate chip | +| 3 | 1 | dark chocolate chip | +| 4 | 1 | molasses | + +**** Limiting +#+BEGIN_SRC python :results table + query = session.query(Cookie).order_by(Cookie.quantity)[:2] + # query = session.query(Cookie).order_by(Cookie.quantity).limit(2) + [(result.cookie_name,) for result in query] +#+END_SRC + +#+RESULTS[8c45f7d97da1645225462855a200559d1feaec44]: +| dark chocolate chip | +| molasses | + +**** Functions and Labels +#+BEGIN_SRC python :results value + from sqlalchemy import func + + inv_count = session.query(func.sum(Cookie.quantity)).scalar() + inv_count +#+END_SRC + +#+RESULTS[f1b621d0ce17b8f55883a46a7777bbeb162e412c]: +: 138 + +#+BEGIN_SRC python :results raw + rec_count = session.query(func.count(Cookie.cookie_name)).first() + rec_count +#+END_SRC + +#+RESULTS[10949d37140b7bcb96a26788a765d195b86950c7]: +(5,) + +#+BEGIN_SRC python :results table + rec_count = session.query( + func.count(Cookie.cookie_name).label("inventory_count") + ).first() + (list(rec_count._mapping.keys()), (rec_count.inventory_count, )) +#+END_SRC + +#+RESULTS[bc76d2b5448873014373602ade270610b301b86a]: +| inventory_count | +| 5 | + +**** Filtering +#+BEGIN_SRC python :results value + record = session.query(Cookie).filter(Cookie.cookie_name == "chocolate chip").first() + record +#+END_SRC + +#+RESULTS[00fbaff9a1d4dcb32caf86614258e147478b1a39]: +: Cookie( +: cookie_id="1", +: cookie_name="chocolate chip", +: cookie_recipe_url="http://some.aweso.me/cookie/recipe.html", +: cookie_sku="CC01", +: quantity="12", +: unit_cost="0.50", +: ) +#+BEGIN_SRC python :results value + record = session.query(Cookie).filter_by(cookie_name="chocolate chip").first() + record +#+END_SRC + +#+RESULTS[c00b3f6260c658d7a3e6fe76c8cb1fa00d9dd58a]: +: Cookie( +: cookie_id="1", +: cookie_name="chocolate chip", +: cookie_recipe_url="http://some.aweso.me/cookie/recipe.html", +: cookie_sku="CC01", +: quantity="12", +: unit_cost="0.50", +: ) + +#+BEGIN_SRC python :results table + query = session.query(Cookie).filter(Cookie.cookie_name.like("chocolate chip")) + [record.cookie_name for record in query] +#+END_SRC + +#+RESULTS[498d5d0b02d3bea28799083caf1de588eccebac1]: +| chocolate chip | + +**** Operators +#+BEGIN_SRC python :results table + results = session.query(Cookie.cookie_name, "SKU-" + Cookie.cookie_sku).all() + [row for row in results] +#+END_SRC + +#+RESULTS[18ddc67a0b92126197fac22eea073f2e86cf5388]: +| chocolate chip | SKU-CC01 | +| dark chocolate chip | SKU-CC02 | +| molasses | SKU-MOL01 | +| peanut butter | SKU-PB01 | +| oatmeal raisin | SKU-EWW01 | + +#+BEGIN_SRC python :results table + from sqlalchemy import cast + + query = session.query( + Cookie.cookie_name, + cast((Cookie.quantity * Cookie.unit_cost), Numeric(12, 2)).label("inv_cost"), + ) + [(result.cookie_name, repr(result.inv_cost)) for result in query] +#+END_SRC + +#+RESULTS[2ce8116fbd2ec77937a191730c2536005f9ac130]: +| chocolate chip | Decimal('6.00') | +| dark chocolate chip | Decimal('0.75') | +| molasses | Decimal('0.80') | +| peanut butter | Decimal('6.00') | +| oatmeal raisin | Decimal('100.00') | + +**** Conjunctions +#+BEGIN_SRC python :table + query = session.query(Cookie).filter(Cookie.quantity > 23, Cookie.unit_cost < 0.40) + [(result.cookie_name,) for result in query] +#+END_SRC + +#+RESULTS[419334c901cd5a42e1b7bf59d3ba8a8b421cca81]: +| peanut butter | + +#+BEGIN_SRC python :table + from sqlalchemy import and_, or_, not_ + + query = session.query(Cookie).filter( + or_(Cookie.quantity.between(10, 50), Cookie.cookie_name.contains("chip")) + ) + + [(result.cookie_name,) for result in query] +#+END_SRC + +#+RESULTS[f1cb32abbfcf01a6b29078b44c8cddf396180df9]: +| chocolate chip | +| dark chocolate chip | +| peanut butter | + +*** Updating Data +#+BEGIN_SRC python :results value + query = session.query(Cookie) + cc_cookie = query.filter(Cookie.cookie_name == "chocolate chip").first() + cc_cookie.quantity = cc_cookie.quantity + 120 + session.commit() + cc_cookie.quantity +#+END_SRC + +#+RESULTS[457d95f641df08c05b2a22152eb07da84eb2d44e]: +: 132 + +#+BEGIN_SRC python :results value + query = session.query(Cookie) + query = query.filter(Cookie.cookie_name == "chocolate chip") + query.update({Cookie.quantity: Cookie.quantity - 20}) + cc_cookie = query.first() + cc_cookie.quantity +#+END_SRC + +#+RESULTS[746058c87e4012a5ce9ced0b2378ce48f9991d8c]: +: 112 + +*** Deleting Data +#+BEGIN_SRC python :results value + query = session.query(Cookie) + query = query.filter(Cookie.cookie_name == "dark chocolate chip") + # Гарантируем, что такая запись только одна, + # и только она одна будет удалена + dcc_cookie = query.one() + session.delete(dcc_cookie) + session.commit() + dcc_cookie = query.first() + # Здесь должен быть None + assert dcc_cookie is None +#+END_SRC + +#+RESULTS[61c6636ec27b672253b640a4609f3a229eec09c6]: +: None + +#+BEGIN_SRC python :results value + query = session.query(Cookie) + query = query.filter(Cookie.cookie_name == "molasses") + query.delete() + # Убедимся, что больше такой записи нет + mol_cookie = query.first() + # Вернёт None + assert mol_cookie is None +#+END_SRC + +#+RESULTS[c28ab2893e1da785db9221a9f016ecaea39a7e91]: +: None + +*** Relations +#+BEGIN_SRC python :results none + cookiemon = User( + username="cookiemon", + email_address="mon@cookie.com", + phone="111-111-1111", + password="password", + ) + cakeeater = User( + username="cakeeater", + email_address="cakeeater@cake.com", + phone="222-222-2222", + password="password", + ) + pieperson = User( + username="pieperson", + email_address="person@pie.com", + phone="333-333-3333", + password="password", + ) + session.add(cookiemon) + session.add(cakeeater) + session.add(pieperson) + session.commit() +#+END_SRC + +#+BEGIN_SRC python :results none + o1 = Order() + o1.user = cookiemon + session.add(o1) + cc = session.query(Cookie).filter(Cookie.cookie_name == "chocolate chip").one() + line1 = LineItem(cookie=cc, quantity=2, extended_cost=1.00) + pb = session.query(Cookie).filter(Cookie.cookie_name == "peanut butter").one() + line2 = LineItem(quantity=12, extended_cost=3.00) + line2.cookie = pb + line2.order = o1 + o1.line_items.append(line1) + o1.line_items.append(line2) + session.commit() +#+END_SRC + +#+BEGIN_SRC python :results none + o2 = Order() + o2.user = cakeeater + cc = session.query(Cookie).filter(Cookie.cookie_name == "chocolate chip").one() + line1 = LineItem(cookie=cc, quantity=24, extended_cost=12.00) + oat = session.query(Cookie).filter(Cookie.cookie_name == "oatmeal raisin").one() + line2 = LineItem(cookie=oat, quantity=6, extended_cost=6.00) + o2.line_items.append(line1) + o2.line_items.append(line2) + session.add(o2) + session.commit() +#+END_SRC diff --git a/pyproject.toml b/pyproject.toml index 3a0143d..19dfbef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ readme = "README.md" requires-python = ">=3.14" dependencies = [ "alembic>=1.20.0", + "pandas>=3.0.6", "pytest>=9.1.1", "pytest-randomly>=5.0.0", "ruff-format>=0.5.4", diff --git a/uv.lock b/uv.lock index 56259e9..55befbc 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,11 @@ version = 1 revision = 3 requires-python = ">=3.14" +resolution-markers = [ + "sys_platform == 'win32'", + "sys_platform == 'emscripten'", + "sys_platform != 'emscripten' and sys_platform != 'win32'", +] [[package]] name = "alembic" @@ -115,6 +120,57 @@ wheels = [ { url = "https://mirror.yandex.ru/pypi/web/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa" }, ] +[[package]] +name = "numpy" +version = "2.5.3" +source = { registry = "https://mirror.yandex.ru/pypi/web/simple/" } +sdist = { url = "https://mirror.yandex.ru/pypi/web/packages/13/01/11703282db468b85f6f7b8c7f22d058de5970d5c7e60a3a8aaa313c3de36/numpy-2.5.3.tar.gz", hash = "sha256:df2d5874ff183595a4ba404edd04f6bd9b5505c1d7708573f6a6c17489a67563" } +wheels = [ + { url = "https://mirror.yandex.ru/pypi/web/packages/70/78/cf416f15dc29375a229d9dfebf8db6e313f291580b39fa1a568b6052bb07/numpy-2.5.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:350ba9783ce969cf9f7ce6e6a9a58e1a6e2a19ca025b7ee448c4db727706212a" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/9e/59/abcc2d8def4fd60eec7d87f92d27c13448ffd9ab14339bcc63a0d7a2fdea/numpy-2.5.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:012e66aca395d795496446e52aeeb5866312a5d4d3f27da270e5a0b43f70dc5c" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/94/75/4640d2d6e4b64a049e48425a82728a41ef4adb61332d2cba68055774878b/numpy-2.5.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:adc1ada2662f8a5f960b8a10d9986897e7499ef07e06d4cfe7197f8cce923c07" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/96/cd/625b57ae33d4ca560f32cc0b47b4a5922146d9beb998ddf773900d440a73/numpy-2.5.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:54a115e5a73b8fc44f0cebef486365a1894b5c9760685d4558b72b7c3eb846e0" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/9c/72/12918652e7912ef9751e8694c88820fcd1908e0618cb23f5f3caa6004b7b/numpy-2.5.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be5a8381859b6da607c84f4f7d6847725f1cf1853ef8a2c9e115b7d58bef47dc" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/45/8f/9beacf79ca7c650688ad0baa80931adb988fe6e6e5d5903c23cc3dbd70eb/numpy-2.5.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b0521d0f4aebb6e06189451025fa17a913287b13c03d5fe05c017333b654ea5b" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/09/8d/41d0a56e1ac4c87495c897a211b1368691b7237aadabec8b3b8f3a74d48f/numpy-2.5.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9deb49575e5b0b94ed72c8a64ec4d033381adc27e9060ae842971f697ba96104" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/08/1e/0dfbc5cc251d54e2af790f254d24ec38637fa97ec7d5d11de7ffed787098/numpy-2.5.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b00eefbcf0f292945c4b4dec2ae845389ef5bcdcd596e6e4328051db5b5ba694" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/b5/2c/dfa40f6991f8185c8c30ffd023dfcbb11888e823cfab9557b920f3bb7bed/numpy-2.5.3-cp314-cp314-win32.whl", hash = "sha256:c2381f82999704f818e2c987a865050e285ec3621262c66d40f5a96c8f899f8e" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/a4/73/d2c08231e4fde7e415501fd02c715d96e98599b2d8384445933944152984/numpy-2.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:2c25dfa72943e4336ddb6b0ee4277b47a0c85bede0807530ec68103bf58e2c10" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/5c/e9/dcdcc9b95cf5f49815055573aee1b11cfbf5299f38a180e437ded050810f/numpy-2.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:15aa985ac73a8db02db7663381aa109510449d3819d37206caed27b33a65a8a6" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/49/c4/af8bc08a7ef4e1529a7c0cf24969accce316b783999802089a581ec99272/numpy-2.5.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ac7bb1c52d445bd4f8f7f97fefe6abc3a084dc4d63df50d79b17fa2b78e89297" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/c5/ae/0f15eb56d4ec5e13c1f7ff04ff407f997d1acbadb45d3e1f2e2645a8f43c/numpy-2.5.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e6ab667ba76450084eb64013762c438ea76d9d29cc676dcd6c2e9892ba37f841" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/23/fb/c72a8f25d4b6e96c354e7ab45ace3b27dc11e5d6a13b6c7d0cd6b08bf112/numpy-2.5.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f7fabeb6cea87d65f3b926de33d03fb016cfdc29314c90974383b5582ae72891" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/07/a9/968c90ed2ab15060c338e8137f1215b5a60756ae07328e0a60d1c6734df4/numpy-2.5.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1fb6f8fb9ff0b3a69f52c66ce397b0246583e9f28616231b0e32ca49259a5fa6" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/59/08/9df04103947b95e3b6b1f2ed1a70521f325647a31b82da6a2aae3a485508/numpy-2.5.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93e1f5447e2b1e479d7bd74701e84746b86450cff1fc368b132d195e2b8f8211" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/41/a0/14c8d5fe5b53a334aabb653deb391c0fef49558f491880ea300ed6785224/numpy-2.5.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c00abe94c1a69d75d827dcf1c025b25c8a45d230b3bcd77a9020883a1b047653" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/c4/a6/d7e96e42f01522e154c32489640f16dfc4f6181d165d05fc3bec8c2c4999/numpy-2.5.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:536f963710a4e63934d80ac0dc4f478804a83e9a84b6828018f25d09953ada33" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/25/39/3453afb7119d0449ef11c886874120ff180e2c337760e0e2d88f70f1a945/numpy-2.5.3-cp314-cp314t-win32.whl", hash = "sha256:4c8a6d2ebce6305fd82fbefca827775437147052a976ee7c94b36a0c1b52ac6c" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/99/01/22815d2b19a1a746b1d45205cffebb3fe511a18acb75fba6c88491fc9894/numpy-2.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:9a37475425b431b4d060f23b4f52cd2f3aef6bc7c654bd760adf0040eec9d435" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/fa/ee/a7cbba67eeaff038dc29ca8b98a88396c8b0cc9c89d4924f4a27a5c9150b/numpy-2.5.3-cp314-cp314t-win_arm64.whl", hash = "sha256:2d8240cb4c16fd831074aa2b2cf9fc54664d826341d61c372245b96a74a49a9a" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/45/56/78194492883ff5eec90423fe56a3a44b154da047d88a6307f629713c584f/numpy-2.5.3-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:a6391fafaba97500887132cd582abc6e19452b1ac775a47caa7b24490e152058" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/11/39/dd55c0af90bbab564b09ae3b0aa60ec5c02b900fa4f1ba23440525c8b32d/numpy-2.5.3-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:09d5a423c71ad5feb5625844ad58050e35df43871004b52ac9c0ad44a56775be" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/b6/51/04f67d32e4862b281b1cb84ceeaed3421189a84fb6fb51a391cd6d5009f7/numpy-2.5.3-cp315-cp315-macosx_14_0_arm64.whl", hash = "sha256:f9579f383d1bf9df80081e72760e84960a7fd4f88cf0c9e535a8597c9bb646f5" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/a3/c9/25b4dc0dd1344ec26c7319e84fd4e9809d2b5628f4e12decd618036e5178/numpy-2.5.3-cp315-cp315-macosx_14_0_x86_64.whl", hash = "sha256:86bff898a431c0fb71f7610b75726e75a54d47b37edc9d537f48de63bb3c0b90" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/fc/c7/29285be1e5232a6e7ee3268a33c85843f5a8ee93350c6465cddd66ebbf76/numpy-2.5.3-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f3ed25271581281f2fccb1adcedfcde4c07362eec69189b50baf6f90e3ae159" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/55/49/bbad5335fb4996a16881f853ff3e0ba582f01720e55c89b1c06b8fc42a90/numpy-2.5.3-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ffdc76bfcae6b255dff75202c5e7feaf95b40246bc0a17944facc1fecf9f79ab" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/ef/e9/1df35483760b04a65ea44669f89dc64f30e5aca098b48ceb8b1310b0e0fe/numpy-2.5.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:116f96cadd935c6122e9228d676fe7ede19e741f5c8bb1c3cddbe0c51ccebea2" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/b8/99/66e54da8265cc8be8a7382bf96edce17aaa2837d6f484432025932a3caa5/numpy-2.5.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:09ffa5d903faeaa5c4dd05009cf81c8bab9f2cb37c548b8d39b65b4cfa7c97f7" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/01/bc/b5e90a91c115168d793dfd2ad9c69c438c2fe7a13a437e770bc5b078e732/numpy-2.5.3-cp315-cp315-win32.whl", hash = "sha256:e01c918ac3d48e18a927cf7b14a26a3e29ff2bdf2eacb976da0aecd6a43ed034" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/37/ea/780748fd3985109075514ef8fc64cd25f943e40dde13a6d59141eb268fc8/numpy-2.5.3-cp315-cp315-win_amd64.whl", hash = "sha256:e931e4f499e0dc7ef29d269a8e5b35dd722e5d14be07df6240166ea7c6532fae" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/b3/16/407be69a2a87c8cab64d95975a8977a426a29e138f07e276ec258f0fe4e5/numpy-2.5.3-cp315-cp315-win_arm64.whl", hash = "sha256:26e15e4aecd8617dfbaecb37d223e365d7b39411fba20454be2670a96aa74cb5" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/44/bf/a97ffb01e41d50a32a9177aef942a4d0e389a3daf451d04e5f38ef6afb87/numpy-2.5.3-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:6cef4bb1706dfec49243c05d921eefb4e190d41e2528b30d8035ea1f36b4c24a" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/d1/24/136c02f2c2af9a067a84d0c3aa10c99012c0476fa5066732fa4a4202557d/numpy-2.5.3-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:d1c89973648c85069c5046ad460f7b8a00218b29a2e42359ac8cc63e9ab94832" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/fe/6c/b47582d6597789bf946d5efbeb6b9e56fd8bcbd5efc6fbf51dbe1ea31eb3/numpy-2.5.3-cp315-cp315t-macosx_14_0_arm64.whl", hash = "sha256:214045a5bf00113a146ab9ee9730c44501af6723cdf1f6830932f7b5ef2e7af0" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/be/b4/ef3cc6da73774202d4deae16bb321fd8298a4e0561e3539f8c4be237d916/numpy-2.5.3-cp315-cp315t-macosx_14_0_x86_64.whl", hash = "sha256:8617bbfae4486cf99c9f899966699428d19da931d06ca94ad3da986c76e15997" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/9e/24/e3813329498596cb842703dcacac1741612ed9fb9c4e6a3e0c7e2ebbc597/numpy-2.5.3-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:595d020938c84e320bcf40ad71089e108eac0d377cd018e14a8c094f39e98d85" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/4a/9e/4e7a07fd0776dc2210cdacf2010be8665194d094defc10c419d7dea794cc/numpy-2.5.3-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f24021b9f22bc6301c37b196974a92c1c18dccedb6fef3dd252e95f2d6adbe4" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/91/db/01674c0e20335057813a00c2ebd546ed25bff9ed7914f9bced00f8c55d94/numpy-2.5.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:71b39d9f935b6ec0f8753e3e2afb51e3efba6f2e05b68b32a40754d24bcd4a3c" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/45/7a/584c5e71f8d378e57cac0b033891ed65c683ef90573ba4854e8c28203db0/numpy-2.5.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:6b05c171afb3aa07adbd20abc00aea86fe375beb0fdb9ef780ec5b7f63bab1c0" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/a1/d2/4e1014173aa3c55e6a756e0e567290743a6ab33a288460374d7ef6bcd239/numpy-2.5.3-cp315-cp315t-win32.whl", hash = "sha256:f54660b0eb6b0b9f36e7fe1cdfdff472028dd0d14acd9b9b65098efbad059469" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/6c/b0/ff5658a58199b7bcaad87bf260eef6713d9d42cca4e028f935b4fc5fbac6/numpy-2.5.3-cp315-cp315t-win_amd64.whl", hash = "sha256:1aad64d99730d013cfc6debafed22783b4fc5a7f4b8bc744d2d8cf7dcc880551" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/fb/0b/b12a2df5d1b774bd9007a6fdff9381145b6223d37f11afc9c37ab0efd9a1/numpy-2.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:befa1ae5bd6030b3f512b43ff3fa5290bbed6b84411a44244b14adf835f5b89d" }, +] + [[package]] name = "packaging" version = "26.3" @@ -124,6 +180,51 @@ wheels = [ { url = "https://mirror.yandex.ru/pypi/web/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c" }, ] +[[package]] +name = "pandas" +version = "3.0.6" +source = { registry = "https://mirror.yandex.ru/pypi/web/simple/" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://mirror.yandex.ru/pypi/web/packages/e2/17/d7b106e05bfa642e8694451e7d3d759c6a241c5386a5d962e4f66c047e06/pandas-3.0.6.tar.gz", hash = "sha256:66b07ef7315a31bfe1089cd3d71a7de781c9dca986762d0b4fe7c0ef17465d10" } +wheels = [ + { url = "https://mirror.yandex.ru/pypi/web/packages/75/55/1a8875395b05ccd572cbca0b9255dcd2db6e6508e632a558c1a6884b39ad/pandas-3.0.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ee913a91669056c1de1a6b733fbfeab711de9e54e3bee2dfa5fe79d9457247d1" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/35/61/47ae13476995cc8a40cd609e93e7cf11f273d8692925c2903cb6d38aa0d1/pandas-3.0.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ff51a4459ed036e93d1eb1bb5e6e7b28685d3cb6b7c12b91c05b31024e234729" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/bc/f2/cc5f2adb8d6e86a85d9fb5128f8cf205a61189336f70d1f7faf0d1b53ec9/pandas-3.0.6-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654aae059295dbba6ecd2328ca12712a2cf1676214c8699f1c29213f7ccf9c34" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/ca/ba/ffdcb19be4ff6bfe7d969e7cef2c567c633df5a3a1cc1053394ad053bca8/pandas-3.0.6-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f51d7f651c8054c5e82a69265c98082e795d1442df7ca6edc3a545d61214b1" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/77/5b/e150075b2c6eb69fae896f2d9239bc6ed07db97735971d53d66de6553460/pandas-3.0.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:22172a92e7ee678ec0140c7af4fc9366b55413834a1cd86af78b3caa0b0574de" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/d6/8a/b441c587dc7355bf6e1f68a91b4f76a6c29740f0c23be3acc5d4ebbeea6d/pandas-3.0.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583be68728a31d0d750d5b8d9e00f02b153df0d4655f858bde93cb84cfc4227c" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/b7/e9/f43410fada510b43fec09993c08f552086c3d247d3ee801a678f3cb10ea5/pandas-3.0.6-cp314-cp314-win_amd64.whl", hash = "sha256:77ccbe5057aece6fc172b9b77f19c04335af6882bc2e10c8f3ee4e6bfb3da553" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/8b/9e/db14c059c21f9baa1907d436f8bf30e0c76c6288225c5e8b79a08ba8b2c5/pandas-3.0.6-cp314-cp314-win_arm64.whl", hash = "sha256:fb625f426b375bcc96e3a04c5d5d266cd7be6ae5d6866e0e703382ab5164068c" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/67/ba/bad0f8dac020ab38a8637fddab01a57a82da7a496a6e6f19590aad53ab62/pandas-3.0.6-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:9e492cd4bdba6778de4fe0df7f4590c012161ebcf9902dce01b01dc683105514" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/c4/a9/b500982e9aac6d52a58da4ad3f11e14168a315b06906b3f397c427878065/pandas-3.0.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d7dcd21238cbb4828ff148481ba01cac8946dc5121457b5aeba28636f8f99a60" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/4b/fa/e6ecd0073c98be8f840ac3125b955272835d7d9fd69f5944383b164deb5e/pandas-3.0.6-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ff482fa91fa2bafd92e8fe66ce3645c851824310f295c1f0a2f96e928fc4541" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/04/f5/001e230a7a7803590d9275a1a3f7e1bb605e3a495cfe5e8d3a532090621b/pandas-3.0.6-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:db7ec631f26223beee8e5c9e0b8f23c24d8197bbd1d982421d4e3188bea51965" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/ca/ab/bab587148a3852c96aae26c4b5f9e04ce2221801ad94e166b4fbf969ede0/pandas-3.0.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd75ed0c840f709fc2ae26ddd9534ac77ca1a48ac0cce521a74acaa85f3340a7" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/f3/32/74b48d87df2b80892d713c149abfe36d5db4de41b4eccb042a2bc07dafc1/pandas-3.0.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ef738d71d1059245b6bb03e312be06d8b3821326a83486c1ad03b9aba3710e44" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/f6/c6/d64b72d64d7eb0fad9fe424d34138e45dee70ddbea1360dcd0adf30e28f6/pandas-3.0.6-cp314-cp314t-win_amd64.whl", hash = "sha256:429d9df32731ab01383ed98f2baa7a60368090d1a94fc06019a12062510e8630" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/7a/30/5e5b2ccabeca73ae2b03fc82bca3eabb7466cf43737f05ac08d591665d47/pandas-3.0.6-cp314-cp314t-win_arm64.whl", hash = "sha256:a4dbd4dc65cbe645b92b8785d0f96dd7311010dc6606cf620e51b07b8788a12a" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/b6/77/47c5fb0be8bdd00116814c2c40d9ec42dbeb943865ef95130fe58a898226/pandas-3.0.6-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:50c44cbf5820b6b91a5f74aae04972472aefadd3cd9fbd1010409d85528bd570" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/09/08/a310cb2fefe6d2b4623ab2150da818d93d4e73e33b58e4d163bb74243c5a/pandas-3.0.6-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:eb6900de08ac85f93ac4948aa6b80842eba555875337b8359035ac9c43e92d34" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/54/36/6af478ec3a26d7754555cd62c3101c589c0931b1d85398e4fa5403910a1c/pandas-3.0.6-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e25e2e1adee99ddfada6f7206a79ae8e9c8a8861b0e3eaaba165006d3eef18e" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/43/20/5ece0e9cb79a6473216620db6a90546f578001c2bd857b77c444b27acad1/pandas-3.0.6-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ff44b2cb51cbd691c91f92c4ea6c71e34003f239ebd67c2e857dc898466b49c" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/2f/b6/cd3038f31ade5e8d2b4e1c9549d4b31e4d598469562f47142b2ad9171c0a/pandas-3.0.6-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:5edd0a7abb0986ecce1ac81f56d99b6763f86aa6946dceb6c661224f90af5a19" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/0a/87/05bb3003737f80375d7311774916a24d161e2e591abe8c672aed7813defc/pandas-3.0.6-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:1bcb3e9ed29e74a7439cedff9e2aefd3ea65de84d7de9ccb6c194192541bd60e" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/c0/30/1c0d46acf236d19ef975e9cdd5d1e0dd54924b03f0ed8287096ad4a18152/pandas-3.0.6-cp315-cp315-win_amd64.whl", hash = "sha256:253e12cb9081b0afbac607920f6142975966bc315135e09de275fdbaa415d2de" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/87/03/df3304a9c2833c4810e7f1c887b04105b24731f9deef8b5d5d04522a375b/pandas-3.0.6-cp315-cp315-win_arm64.whl", hash = "sha256:97274c9adf6255bb48c620cd6959805efa7f09ea2167f0e0ae006a448cd2fca7" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/47/25/d5f6cce5efa17c38e4f752a875b4a26d66cfadd529cb8c81672f0376d6a6/pandas-3.0.6-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:265f562fdd1079f69f3de96dd425c3405224038c0af4f920c54bd240ee2c4640" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/ea/8b/e1876bfdc1df06bafc022d33202b5663bd86c81df2a6140aacafd0344669/pandas-3.0.6-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:c6e4aae3e9bea26c6c9a20d88d96c86ec4a99b4db5fd516bcb4e829ab2c0ee36" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/e9/27/e0a27a5a5c27f7db66657b44def9e93121fd0ad4f0808355b9898fcbf204/pandas-3.0.6-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a77a1a44e4d88f1c6a2a64d3eb12efec8420875722e14279800b173a7c7c2804" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/d5/4f/4eadb7d86a921c1e8bc70916cfe601ed667c4169118d17d69958611c21f8/pandas-3.0.6-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86fa853a12e0b70927e2b1ee00d56d2224ec9cbb4b9d58348b5ad52d2f21150e" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/c7/d1/eba72e9d905e84e79aefeefdcc6bc1abe15d9077973566643f4211636966/pandas-3.0.6-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:c826e9babb7790142c399f58599d8de679bea059d7b39c5b6efa2096fac37266" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/9d/8a/1c5bd2642b450e374b6191189f47c49538fe41f82348a66de6f647e6ab59/pandas-3.0.6-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:8fe77b408d82e2615674dfed62533b95e18a03610573877422aada4f625d4947" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/73/3d/1b142bd0d0f1326a5d98c91c955b923cd1e06b5eecb428cd9d8817fa01c0/pandas-3.0.6-cp315-cp315t-win_amd64.whl", hash = "sha256:83e91d15738d7783c050197cef2f2cf82fc6353dae9865aa87ed1fa16aa4d55a" }, + { url = "https://mirror.yandex.ru/pypi/web/packages/0b/a3/6419c14da2adc1f09a6a183b8f91d7494d325b287f4ca984ac04f663638a/pandas-3.0.6-cp315-cp315t-win_arm64.whl", hash = "sha256:963ca21199097a84c7827c4678b04e30833084fbf8ef44fde3fa7180a29f8fa0" }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -170,6 +271,18 @@ wheels = [ { url = "https://mirror.yandex.ru/pypi/web/packages/10/b4/47e939285caad9a623d021512912ac08dc92a467ad075d179f43729d2934/pytest_randomly-5.0.0-py3-none-any.whl", hash = "sha256:8a0d4703115c0c25b38b6e129fc16b1947b9643ff26a41bc1d185d7e5a7689c1" }, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://mirror.yandex.ru/pypi/web/simple/" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://mirror.yandex.ru/pypi/web/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3" } +wheels = [ + { url = "https://mirror.yandex.ru/pypi/web/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" }, +] + [[package]] name = "ruff-format" version = "0.5.4" @@ -208,6 +321,15 @@ wheels = [ { url = "https://mirror.yandex.ru/pypi/web/packages/d6/92/477780b98169e0dc3d37fac015f3f9ef3ced1dfcd2ec3a44686c8e07f8d8/ruff_format-0.5.4-cp38-abi3-win_arm64.whl", hash = "sha256:b0dfb4ef7c7f0da7b17c018dc48103907375f06c7b9e3dac3bc396722a725a65" }, ] +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://mirror.yandex.ru/pypi/web/simple/" } +sdist = { url = "https://mirror.yandex.ru/pypi/web/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81" } +wheels = [ + { url = "https://mirror.yandex.ru/pypi/web/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274" }, +] + [[package]] name = "sqlalchemy" version = "2.0.54" @@ -241,6 +363,7 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "alembic" }, + { name = "pandas" }, { name = "pytest" }, { name = "pytest-randomly" }, { name = "ruff-format" }, @@ -251,6 +374,7 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "alembic", specifier = ">=1.20.0" }, + { name = "pandas", specifier = ">=3.0.6" }, { name = "pytest", specifier = ">=9.1.1" }, { name = "pytest-randomly", specifier = ">=5.0.0" }, { name = "ruff-format", specifier = ">=0.5.4" }, @@ -275,3 +399,12 @@ sdist = { url = "https://mirror.yandex.ru/pypi/web/packages/f6/cc/6253133b5bb138 wheels = [ { url = "https://mirror.yandex.ru/pypi/web/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8" }, ] + +[[package]] +name = "tzdata" +version = "2026.4" +source = { registry = "https://mirror.yandex.ru/pypi/web/simple/" } +sdist = { url = "https://mirror.yandex.ru/pypi/web/packages/e4/31/3d74fa778a63b98b7374323befcc0be5ab3bd94afd4096a0124e7379152c/tzdata-2026.4.tar.gz", hash = "sha256:f1b8bd365d8d210c55353f4d7f8d6d8561c0ba50d704b700d195a9424bba0d79" } +wheels = [ + { url = "https://mirror.yandex.ru/pypi/web/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl", hash = "sha256:c2169a8b0a7a5e9674da5a135ccdfb2b3e671b333ed9fed17b41f73c34476e81" }, +]