Compare commits

..

No commits in common. "master" and "20f64216df33bb76b5bd447fa524af938b169cf8" have entirely different histories.

2 changed files with 1381 additions and 1580 deletions

File diff suppressed because it is too large Load Diff

View File

@ -3,324 +3,246 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {},
"outputs": [],
"source": [ "source": [
"from spielbergerscripts.connector import IBMConnector\n", "from spielbergerscripts.spielbergerscripts.storageunit import Product, Bundle, NVE\r\n",
"from spielbergerscripts.primitives.batch import Batch\n", "from spielbergerscripts.spielbergerscripts.connector import IBMConnector"
"from spielbergerscripts.primitives.nve import NVE\n", ],
"from spielbergerscripts.primitives.product import Product, Bundle\n", "outputs": [],
"from spielbergerscripts.helpers.functions import spiel_prefix\n", "metadata": {}
"\n",
"from dataclasses import dataclass"
]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {},
"outputs": [],
"source": [ "source": [
"ibmconnect = IBMConnector(True)\n", "ibmconnect = IBMConnector(True)\r\n",
"nveDict = ibmconnect.getNVETable()\n", "nveDict = ibmconnect.getNVETable()\r\n",
"prodDict = ibmconnect.getProductsTable()\n", "prodDict = ibmconnect.getProductsTable()"
"batchDict = ibmconnect.getBatchData()" ],
] "outputs": [],
"metadata": {}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {},
"outputs": [],
"source": [ "source": [
"@dataclass\n", "extResource = dict()\r\n",
"class ProductArea:\n", "\r\n",
" prod_nr: str\n", "for nve in nveDict.values():\r\n",
" area: str\n", " prod = prodDict.get(nve.article)\r\n",
" amount: int\n", "\r\n",
" batches: list()\n", " if not prod is None:\r\n",
"\n", " if nve.area != '01' and nve.area != '02' and nve.area != prod.pickArea:\r\n",
" def from_batch(batch):\n", " extResource[(nve.article, nve.area, nve.vq)] = (prod.name, prod.bundle, extResource.get((nve.article, nve.area, nve.vq), ('', '', 0))[2] + nve.amount)"
" return ProductArea(\n", ],
" batch.art_nr, batch.area, 0, list()\n", "outputs": [],
" )\n", "metadata": {}
"\n",
" def add_batch(self, batch):\n",
" assert(batch.area == batch.area)\n",
"\n",
" self.amount += batch.amount\n",
" self.batches.append(batch)\n",
"\n",
"\n",
"@dataclass\n",
"class ProductAreas:\n",
" prod_nr: str\n",
" areas: dict()\n",
"\n",
" def addBatch(self, batch):\n",
" parea = self.areas.get(batch.area, ProductArea.from_batch(batch))\n",
" parea.add_batch(batch)\n",
"\n",
" self.areas[batch.area] = parea\n",
"\n",
"prod_areas = dict()\n",
"for prod_nr, batches in batchDict.items():\n",
" prod = prodDict.get(prod_nr, None)\n",
" if prod is None:\n",
" # print(f\"Error on batch {batch}\")\n",
" continue\n",
"\n",
" pa = ProductAreas(prod_nr, dict())\n",
" for batch in batches:\n",
" if batch.amount > 0 and (int(batch.vq) < 30 or int(batch.vq) == 39):\n",
" pa.addBatch(batch)\n",
"\n",
" prod_areas[pa.prod_nr] = pa"
]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {}, "source": [
"ART_WU = set()\r\n",
"\r\n",
"for (pNr, area, vq), (pName, bundle, amount) in extResource.items():\r\n",
" if area != '36' or bundle.strip() == \"25 KG\" or bundle.strip() == \"BIG-BAG\" or bundle.strip() == \"1000 ST\":\r\n",
" continue\r\n",
" print(f\"Lager {area}\\t{amount}x {pName.strip()} (#{pNr} / VQ{vq}) {bundle} auf Vorrat\")\r\n",
" ART_WU.add(pNr)\r\n",
"\r\n",
"# zusätzlich\r\n",
"ART_WU.union({\"062346\", \"062356\", \"062306\", \"062416\", \"104406\", \"104409\"})\r\n",
"\r\n",
"ART_WU = list(ART_WU)\r\n",
"ART_WU.sort()"
],
"outputs": [], "outputs": [],
"source": [ "metadata": {}
"ART_EXT = dict()\n",
"\n",
"\n",
"for prodarea in prod_areas.values():\n",
" prod = prodDict[prodarea.prod_nr]\n",
" if prod.bundle.strip() == \"25 KG\" or prod.bundle.strip() == \"20 KG\" or prod.bundle.strip() == \"BIG-BAG\" or prod.bundle.strip() == \"1000 ST\" or prod.bundle.strip() == \"LOSE\":\n",
" continue\n",
"\n",
" ext_res = []\n",
" for aid, area in prodarea.areas.items():\n",
" if aid == prod.pickArea or (aid != \"00\" and aid != \"33\" and aid != \"36\"):\n",
" continue\n",
" if area.amount > 0:\n",
" ext_res.append((aid, area))\n",
" print(f\"Lager {aid}\\t{area.amount}x {prod.name.strip()} (#{prodarea.prod_nr}) {prod.bundle} auf Vorrat\")\n",
"\n",
" if ext_res:\n",
" ART_EXT[prodarea.prod_nr] = ext_res\n",
"\n",
"L_ART_EXT = list(ART_EXT.keys())\n",
"L_ART_EXT.sort()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# IBM 11/09 - Negative Verfügbarkeit ausführen!"
]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {},
"outputs": [],
"source": [ "source": [
"\n", "\r\n",
"from openpyxl import load_workbook\n", "from openpyxl import load_workbook\r\n",
"from openpyxl.styles import Color, PatternFill\n", "from openpyxl.styles import Color, PatternFill\r\n",
"\n", "\r\n",
"from dataclasses import dataclass\n", "from dataclasses import dataclass\r\n",
"from datetime import date, datetime, timedelta\n", "from datetime import date, datetime, timedelta\r\n",
"\n", "\r\n",
"from spielbergerscripts.helpers.functions import spiel_prefix\n", "@dataclass\r\n",
"\n", "class Request:\r\n",
"@dataclass\n", " ordernr: str\r\n",
"class Request:\n", " cust_name: str\r\n",
" ordernr: str\n", " delivdate: date\r\n",
" cust_name: str\n", " artnr: str\r\n",
" delivdate: date\n", " artname: str\r\n",
" artnr: str\n", " bundle: str\r\n",
" artname: str\n", " stock: int\r\n",
" bundle: str\n", " ordered: int\r\n",
" stock: int\n", " ord_rem: int\r\n",
" ordered: int\n", " available: int\r\n",
" ord_rem: int\n", " avail_wo_36:int\r\n",
" available: int\n", " upcoming: int\r\n",
" avail_wo_36:int\n", " upc_date: str\r\n",
" upcoming: int\n", " upc_area: str\r\n",
" upc_date: str\n", " stock00: int\r\n",
" upc_area: str\n", " stock01: int\r\n",
" comm_area: str\n", " stock33: int\r\n",
" stock00: int\n", " stock36: int\r\n",
" stock01: int\n", "\r\n",
" stock33: int\n", " def from_tuple(t):\r\n",
" stock36: int\n", " d = str(t[2])\r\n",
"\n", " szd = f\"20{d[-2:]}-{d[-4:-2]}-{int(d[:-4]):02d}\"\r\n",
" def from_tuple(t):\n", " return Request(\r\n",
" d = str(t[2])\n", " ordernr=str(t[0]),\r\n",
" szd = f\"20{d[-2:]}-{d[-4:-2]}-{int(d[:-4]):02d}\"\n", " cust_name=str(t[1]).strip(),\r\n",
" return Request(\n", " delivdate=date.fromisoformat(szd),\r\n",
" ordernr=str(t[0]),\n", " artnr=str(t[3]),\r\n",
" cust_name=str(t[1]).strip(),\n", " artname=str(t[4]),\r\n",
" delivdate=date.fromisoformat(szd),\n", " bundle=str(t[5]),\r\n",
" artnr=spiel_prefix(str(t[3]), True),\n", " stock=int(t[6]),\r\n",
" artname=str(t[4]),\n", " ordered=int(t[7]),\r\n",
" bundle=str(t[5]),\n", " ord_rem=int(t[23]),\r\n",
" stock=int(t[6]),\n", " available=int(t[9]),\r\n",
" ordered=int(t[7]),\n", " avail_wo_36=int(t[28]),\r\n",
" ord_rem=int(t[23]),\n", " upcoming=int(t[10]),\r\n",
" available=int(t[9]),\n", " upc_date=date.fromisoformat(f\"20{str(t[11])[-2:]}-{str(t[11])[-4:-2]}-{int(str(t[11])[:-4]):02d}\") if int(t[10]) > 0 else None,\r\n",
" avail_wo_36=int(t[28]),\n", " upc_area=str(t[12]),\r\n",
" upcoming=int(t[10]),\n", " stock00=int(t[24]),\r\n",
" upc_date=date.fromisoformat(f\"20{str(t[11])[-2:]}-{str(t[11])[-4:-2]}-{int(str(t[11])[:-4]):02d}\") if int(t[10]) > 0 else None,\n", " stock01=int(t[25]),\r\n",
" upc_area=str(t[12]),\n", " stock33=int(t[26]),\r\n",
" comm_area=t[18],\n", " stock36=int(t[27]),\r\n",
" stock00=int(t[24]),\n", " )\r\n",
" stock01=int(t[25]),\n", "\r\n",
" stock33=int(t[26]),\n", "\r\n",
" stock36=int(t[27]),\n", "RED = Color(rgb='E6B8B7')\r\n",
" )\n", "\r\n",
"\n", "FROM = datetime.now().date()\r\n",
"\n", "TO = FROM + timedelta(days=14)\r\n",
"RED = Color(rgb='E6B8B7')\n", "\r\n",
"\n", "if FROM.month == TO.month and FROM.year == TO.year:\r\n",
"FROM = datetime.now().date()\n", " aufbes = list(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(FROM.day, TO.day, FROM.month, FROM.year)))\r\n",
"TO = FROM + timedelta(days=14)\n", "else:\r\n",
"\n", " temp_to = FROM + timedelta(days = 31 if FROM.day >= 15 else 20)\r\n",
"if FROM.month == TO.month and FROM.year == TO.year:\n", " temp_to = temp_to.replace(day = 1)\r\n",
" aufbes = list(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(FROM.day, TO.day, FROM.month, FROM.year)))\n", " print(f\"Temp to = {temp_to}\")\r\n",
"else:\n", " temp_to = temp_to - timedelta(days=1)\r\n",
" temp_to = FROM + timedelta(days = 31 if FROM.day >= 15 else 20)\n", " print(f\"Temp to = {temp_to}\")\r\n",
" temp_to = temp_to.replace(day = 1)\n", " aufbes = list(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(FROM.day, temp_to.day, FROM.month, FROM.year)))\r\n",
" print(f\"Temp to = {temp_to}\")\n", " temp_from = temp_to + timedelta(days=1)\r\n",
" temp_to = temp_to - timedelta(days=1)\n", " print(f\"Temp from = {temp_from}\")\r\n",
" print(f\"Temp to = {temp_to}\")\n", " while temp_from.month < TO.month:\r\n",
" aufbes = list(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(FROM.day, temp_to.day, FROM.month, FROM.year)))\n", " temp_to = FROM + timedelta(days = 31 if FROM.day >= 15 else 20)\r\n",
" temp_from = temp_to + timedelta(days=1)\n", " temp_to = temp_to.replace(day=1)\r\n",
" print(f\"Temp from = {temp_from}\")\n", " temp_to = temp_to - timedelta(days=1)\r\n",
" while temp_from.month < TO.month:\n", " aufbes.extend(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(temp_from.day, temp_to.day, temp_from.month, temp_from.year)))\r\n",
" temp_to = FROM + timedelta(days = 31 if FROM.day >= 15 else 20)\n", " temp_from = temp_to + timedelta(days=1)\r\n",
" temp_to = temp_to.replace(day=1)\n", " \r\n",
" temp_to = temp_to - timedelta(days=1)\n", " # last month. temp_from is the current TO month\r\n",
" aufbes.extend(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(temp_from.day, temp_to.day, temp_from.month, temp_from.year)))\n", " aufbes.extend(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(temp_from.day, TO.day, temp_from.month, temp_from.year)))\r\n",
" temp_from = temp_to + timedelta(days=1)\n", " \r\n",
" \n", "\r\n",
" # last month. temp_from is the current TO month\n", "\r\n",
" aufbes.extend(map(lambda t: Request.from_tuple(t), ibmconnect.getNegAvail(temp_from.day, TO.day, temp_from.month, temp_from.year)))\n", "aufbes.sort(key = lambda a: a.delivdate)\r\n",
" \n", "\r\n",
"\n", "vorlage = load_workbook(\"Umfuhrplanung_Vorlage.xlsx\")\r\n",
"\n", "\r\n",
"aufbes.sort(key = lambda a: a.delivdate)\n", "for prodNr in ART_WU:\r\n",
"\n", " aufbes_filt = [t for t in aufbes if t.artnr == prodNr]\r\n",
"vorlage = load_workbook(\"Umfuhrplanung_Vorlage.xlsx\")\n", "\r\n",
"\n", " if len(aufbes_filt) > 0:\r\n",
"for prodNr in L_ART_EXT:\n", " prod = prodDict.get(prodNr)\r\n",
" aufbes_filt = [t for t in aufbes if t.artnr == prodNr]\n", " sheet = vorlage.copy_worksheet(vorlage[\"Vorlage\"])\r\n",
"\n", " sheet.title = prodNr\r\n",
" if len(aufbes_filt) > 0:\n", " sheet['A1'] = f\"{prod.name.strip()} (#{prodNr})\"\r\n",
" prod = prodDict.get(prodNr)\n", " sheet['N1'] = f\"vom {FROM} bis inklussive {TO}\\n\\n\"\r\n",
" pareas = prod_areas.get(prodNr, None)\n", "\r\n",
" if pareas is None:\n", " first = aufbes_filt[0]\r\n",
" print(f\"Produktareas nicht gefunden: {prodNr}\")\n", " bestand_00 = first.stock00\r\n",
"\n", " bestand_01 = first.stock01\r\n",
" sheet = vorlage.copy_worksheet(vorlage[\"Vorlage\"])\n", " bestand_33 = first.stock33\r\n",
" sheet.title = prodNr\n", " bestand_36 = first.stock36\r\n",
" sheet['A1'] = f\"{prod.name.strip()} (#{prodNr})\"\n", " \r\n",
" sheet['F1'] = f\"Kommiort {prod.pickArea}\"\n", "\r\n",
" sheet['N1'] = f\"vom {FROM} bis inklussive {TO}\\n\\n\"\n", " we = first.upcoming\r\n",
"\n", " we_dat = first.upc_date\r\n",
" first = aufbes_filt[0]\n", " we_area = first.upc_area\r\n",
" verbleibend = {\n", " we_done = False\r\n",
" \"00\": pareas.areas.get(\"00\").amount if \"00\" in pareas.areas else 0,\n", "\r\n",
" \"01\": pareas.areas.get(\"01\").amount if \"01\" in pareas.areas else 0,\n", " sheet['C2'] = bestand_00\r\n",
" \"05\": pareas.areas.get(\"05\").amount if \"05\" in pareas.areas else 0,\n", " sheet['E2'] = bestand_33\r\n",
" \"33\": pareas.areas.get(\"33\").amount if \"33\" in pareas.areas else 0,\n", " sheet['G2'] = bestand_36\r\n",
" \"36\": pareas.areas.get(\"36\").amount if \"36\" in pareas.areas else 0,\n", " sheet['B3'] = we\r\n",
" }\n", " sheet['D3'] = we_dat\r\n",
" \n", "\r\n",
"\n", " verbleibend = bestand_00\r\n",
" we = first.upcoming\n", " bedarf_am = \"\"\r\n",
" we_dat = first.upc_date\n", " bedarf_durch = \"\"\r\n",
" we_area = first.upc_area\n", " bedarf_auftrag = \"\"\r\n",
" we_done = False\n", " umfuhrmenge = 0\r\n",
"\n", " umfuhr_an = \"\"\r\n",
" sheet['C2'] = verbleibend[\"00\"]\n", " auftrag = 0\r\n",
" sheet['E2'] = verbleibend[\"33\"]\n", " auftr_dennree = 0\r\n",
" sheet['G2'] = verbleibend[\"36\"]\n", " for t in aufbes_filt:\r\n",
" sheet['B3'] = we\n", " if we > 0 and t.delivdate > we_dat:\r\n",
" sheet['D3'] = we_dat\n", " if we_area == \"00\":\r\n",
"\n", " verbleibend += we\r\n",
" verbleibendL = verbleibend\n", " \r\n",
" bedarf_am = \"\"\n", " sheet.append([\"\", \"Produktion\", we_dat, t.delivdate, t.artnr, t.artname, t.bundle, \"\", f\"+{we}\", verbleibend, t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\r\n",
" bedarf_durch = \"\"\n", " we = 0\r\n",
" bedarf_auftrag = \"\"\n", " if t.cust_name.strip() == \"dennree GmbH\":\r\n",
" umfuhrmenge = 0\n", " sheet.append([t.ordernr, t.cust_name, t.delivdate, t.artnr, t.artname, t.bundle, t.ordered, t.ord_rem, verbleibend, t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\r\n",
" umfuhr_an = \"\"\n", " for row in sheet.iter_cols(min_col=1, max_col=16, min_row=sheet.max_row, max_row=sheet.max_row):\r\n",
" auftrag = 0\n", " for cell in row:\r\n",
" auftr_dennree = 0\n", " cell.fill = PatternFill(fgColor=RED, fill_type = 'solid')\r\n",
" for t in aufbes_filt:\n", " elif t.cust_name.strip() == \"Interne Umlagerung\":\r\n",
" if we > 0 and t.delivdate > we_dat:\n", " verbleibend += t.ordered\r\n",
" if not we_area in {\"00\", \"05\", \"33\", \"36\"}:\n", " sheet.append([t.ordernr, t.cust_name, t.delivdate, t.artnr, t.artname, t.bundle, t.ordered, f\"+{t.ordered}\", verbleibend, t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\r\n",
" print(f\"Unable to handle we of {prod_nr} in area {we_area}\")\n", " else:\r\n",
" if we_area != \"05\":\n", " verbleibend -= t.ord_rem\r\n",
" verbleibendL[we_area] += we\n", " sheet.append([t.ordernr, t.cust_name, t.delivdate, t.artnr, t.artname, t.bundle, t.ordered, t.ord_rem, verbleibend, t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\r\n",
" else:\n", " \r\n",
" verbleibendL[prod.pickArea] += we\n", " if we > 0:\r\n",
" \n", " if we_area == \"00\":\r\n",
" sheet.append([\"\", \"Produktion\", we_dat, t.artnr, t.artname, t.bundle, \"\", f\"+{we}\", verbleibendL[\"00\"], verbleibendL[\"01\"], verbleibendL[\"33\"], verbleibendL[\"36\"], t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\n", " verbleibend += we\r\n",
" we = 0\n", " \r\n",
" if t.cust_name.strip() == \"dennree GmbH\":\n", " sheet.append([\"\", \"Produktion\", we_dat, t.delivdate, t.artnr, t.artname, t.bundle, \"\", f\"+{we}\", verbleibend, t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\r\n",
" sheet.append([t.ordernr, t.cust_name, t.delivdate, t.artnr, t.artname, t.bundle, t.ordered, t.ord_rem, verbleibendL[\"00\"], verbleibendL[\"01\"], verbleibendL[\"33\"], verbleibendL[\"36\"], t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\n", "\r\n",
" for row in sheet.iter_cols(min_col=1, max_col=16, min_row=sheet.max_row, max_row=sheet.max_row):\n",
" for cell in row:\n",
" cell.fill = PatternFill(fgColor=RED, fill_type = 'solid')\n",
" elif t.cust_name.strip() == \"Interne Umlagerung\":\n",
" #verbleibend += t.ordered\n",
" verbleibendL[\"00\"] += t.ordered\n",
" sheet.append([t.ordernr, t.cust_name, t.delivdate, t.artnr, t.artname, t.bundle, t.ordered, f\"+{t.ordered}\", verbleibendL[\"00\"], verbleibendL[\"01\"], verbleibendL[\"33\"], verbleibendL[\"36\"], t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\n",
" else:\n",
" #verbleibend -= t.ord_rem\n",
" verbleibendL[t.comm_area] -= t.ord_rem\n",
" sheet.append([t.ordernr, t.cust_name, t.delivdate, t.artnr, t.artname, t.bundle, t.ordered, t.ord_rem, verbleibendL[\"00\"], verbleibendL[\"01\"], verbleibendL[\"33\"], verbleibendL[\"36\"], t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\n",
" \n",
" if we > 0:\n",
" if not we_area in {\"00\", \"05\", \"33\", \"36\"}:\n",
" print(f\"Unable to handle we of {prod_nr} in area {we_area}\")\n",
" if we_area != \"05\":\n",
" verbleibendL[we_area] += we\n",
" else:\n",
" verbleibendL[prod.pickArea] += we\n",
" \n",
" sheet.append([\"\", \"Produktion\", we_dat, t.artnr, t.artname, t.bundle, \"\", f\"+{we}\", *verbleibendL.values(), t.upcoming, t.upc_date, t.upc_area, t.stock00, t.stock01, t.stock33, t.stock36])\n",
"\n",
"vorlage.save(f\"Umfuhrplanung_{FROM}.xlsx\")" "vorlage.save(f\"Umfuhrplanung_{FROM}.xlsx\")"
] ],
"outputs": [],
"metadata": {}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"metadata": {}, "source": [],
"outputs": [], "outputs": [],
"source": [] "metadata": {}
} }
], ],
"metadata": { "metadata": {
"interpreter": { "orig_nbformat": 4,
"hash": "2be5faf79681da6f2a61fdfdd5405d65d042280f7fba6178067603e3a2925119"
},
"kernelspec": {
"display_name": "Python 3.10.0 64-bit",
"name": "python3"
},
"language_info": { "language_info": {
"name": "python",
"version": "3.9.7",
"mimetype": "text/x-python",
"codemirror_mode": { "codemirror_mode": {
"name": "ipython", "name": "ipython",
"version": 3 "version": 3
}, },
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.1" "nbconvert_exporter": "python",
"file_extension": ".py"
}, },
"orig_nbformat": 4 "kernelspec": {
"name": "python3",
"display_name": "Python 3.9.7 64-bit"
},
"interpreter": {
"hash": "032eb40c1682b1e6109824d577ff4427b0bbc2f8ebe1487b7b1be524c4843266"
}
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 2 "nbformat_minor": 2
} }