fix: pyinstaller
parent
4dc23b47ba
commit
fa59daa416
|
|
@ -1,7 +1,7 @@
|
|||
__pycache__/
|
||||
build/
|
||||
dist/
|
||||
other/
|
||||
*.egg-info/
|
||||
*.pdf
|
||||
*.spec
|
||||
__pycache__/
|
||||
build/
|
||||
dist/
|
||||
other/
|
||||
*.egg-info/
|
||||
*.pdf
|
||||
*.spec
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.12
|
||||
3.12
|
||||
|
|
|
|||
330
README.md
330
README.md
|
|
@ -1,165 +1,167 @@
|
|||
# EVA 值班排班工具
|
||||
|
||||
## 环境配置
|
||||
|
||||
本项目使用 `uv` 进行包管理。
|
||||
|
||||
安装项目中所需要的所有包的最新版本。其中 `pyside6` 是一个前端库,`pyinstaller` 用于打包项目,`ortools` 是一个高效的组合优化求解器,`pandas` 用于处理表格数据:
|
||||
```bash
|
||||
uv sync
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
```
|
||||
EVA_duty_arrange_tool/
|
||||
├─ main.py // 主函数,定义了前端界面和组件的回调函数
|
||||
├─ solve.py // 定义了值班排班问题的求解函数
|
||||
├─ utils.py // 定义了读取、写入 excel 的函数
|
||||
├─ pics // 储存了说明文档中用到的图片
|
||||
│ ├─ *.jpg/*.png
|
||||
├─ *.md // 说明文档
|
||||
├─ *.xlsx // 测试用例
|
||||
```
|
||||
|
||||
## 项目运行 & 打包
|
||||
项目运行方式:
|
||||
```bash
|
||||
uv run main.py
|
||||
```
|
||||
|
||||
本项目使用 `pyinstaller` 工具进行打包。如果要打包,请确保能够正常运行项目。打包命令如下:
|
||||
```bash
|
||||
uv run pyinstaller --onefile --windowed --name=EVA_duty_arrange_tool main.py
|
||||
```
|
||||
|
||||
## 数学原理
|
||||
本项目将值班排班问题建模为了一个[组合优化](https://zh.wikipedia.org/wiki/%E7%BB%84%E5%90%88%E4%BC%98%E5%8C%96)问题,使用 Google 的 OR-Tools 求解器中的 SCIP 求解器进行求解。
|
||||
|
||||
### 问题描述
|
||||
|
||||
在本问题中,优化目标是一个涉及多个方面的量化指标:
|
||||
- **目标1**:每一班同学数量的平均程度
|
||||
- **目标2**:每一班技术部老人数量接近期望值
|
||||
- **目标3**:每一班技术部小朋友数量接近期望值
|
||||
- **目标4**:每一班人资部小朋友数量接近期望值
|
||||
- **目标5**:每一班各部门人数的平均程度
|
||||
|
||||
在本问题中,主要约束是:
|
||||
1. 让每位同学每周的班次数符合意愿(特别地,选择3次的同学可以安排2-3次)
|
||||
2. 让每位同学只在自己有空的时间段值班
|
||||
3. 每班次的总人数在指定范围内
|
||||
4. 每班次技术部老人数量在指定范围内
|
||||
5. 每班次老人总数在指定范围内
|
||||
6. 每班次小朋友总数在指定范围内
|
||||
|
||||
### 数学建模
|
||||
|
||||
设一共有 $n$ 位同学,$m$ 个值班的班次,协会共有 $t=5$ 个部门(电脑部、电器部、人资部、财外部、文宣部),定义以下符号:
|
||||
|
||||
**决策变量:**
|
||||
- $x_{ij} \in \{0,1\}, \quad i=1,2,\dots,n,\quad j=1,2,\dots,m$ 表示第 $i$ 位同学是否值第 $j$ 班
|
||||
|
||||
**已知参数:**
|
||||
- $N_i \in \mathbb{N}, \quad i=1,2,\dots,n$ 表示第 $i$ 个同学每周愿意值班次数
|
||||
- $v_{ij} \in \{0,1\}, \quad i=1,2,\dots,n,\quad j=1,2,\dots,m$ 表示第 $i$ 位同学是否有空值第 $j$ 班
|
||||
- $\text{old}_i \in \{0,1\}, \quad i=1,2,\dots,n$ 表示第 $i$ 位同学是否是老人(非小朋友)
|
||||
- $d_{ik}\in\{0,1\}, \quad i=1,2,\dots,n,\quad k=1,2,\dots,t$ 表示第 $i$ 位同学是否属于第 $k$ 个部门
|
||||
- $\text{tech}_i = d_{i1} + d_{i2} \in \{0,1\}$ 表示第 $i$ 位同学是否属于技术部(电脑部或电器部)
|
||||
- $\text{hr}_i = d_{i3} \in \{0,1\}$ 表示第 $i$ 位同学是否属于人资部
|
||||
|
||||
**派生量:**
|
||||
- $M_j = \sum_{i=1}^{n} x_{ij}, \quad j=1,2,\dots,m$ 表示第 $j$ 班次实际安排的值班人数
|
||||
- $\bar{M} = \frac{\sum_{i=1}^{n}N_i}{m}$ 表示平均每班的人数
|
||||
|
||||
### 优化目标
|
||||
|
||||
为了处理多目标优化问题,我们采用**线性加权法**将多个目标组合成单一目标函数。引入归一化系数 $m_1=2.5, m_2=3, m_3=4, m_4=1, m_5=8$ 和权重 $w_1, w_2, w_3, w_4, w_5$,总目标函数为:
|
||||
|
||||
$$\min \quad Z = w_1 \cdot \frac{X_1}{m_1 \cdot M} + w_2 \cdot \frac{X_2}{m_2 \cdot M} + w_3 \cdot \frac{X_3}{m_3 \cdot M} + w_4 \cdot \frac{X_4}{m_4 \cdot M} + w_5 \cdot \frac{X_5}{m_5 \cdot M}$$
|
||||
|
||||
各目标定义如下:
|
||||
|
||||
**目标1:均衡班次人数**
|
||||
|
||||
$$X_1 = \sum_{j=1}^{m} a_j^{(1)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(1)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(1)} \ge M_j - \bar{M}, \quad a_j^{(1)} \ge \bar{M} - M_j, \quad \forall j$$
|
||||
|
||||
> 注:在组合优化问题中只能定义线性约束,不能直接使用绝对值。因此引入辅助变量 $a_j^{(1)}$ 并添加两个不等式约束,使得在优化过程中 $a_j^{(1)}$ 自动收敛到 $|M_j - \bar{M}|$。
|
||||
|
||||
**目标2:每班技术部老人数量接近期望值**
|
||||
|
||||
期望每班有 $m_2 = 3$ 位技术部老人,定义缺口:
|
||||
|
||||
$$X_2 = \sum_{j=1}^{m} a_j^{(2)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(2)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(2)} \ge \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \cdot \text{tech}_i - m_2$$
|
||||
$$a_j^{(2)} \ge m_2 - \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \cdot \text{tech}_i, \quad \forall j$$
|
||||
|
||||
**目标3:每班技术部小朋友数量接近期望值**
|
||||
|
||||
期望每班有 $m_3 = 4$ 位技术部小朋友,定义缺口:
|
||||
|
||||
$$X_3 = \sum_{j=1}^{m} a_j^{(3)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(3)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(3)} \ge \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{tech}_i - m_3$$
|
||||
$$a_j^{(3)} \ge m_3 - \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{tech}_i, \quad \forall j$$
|
||||
|
||||
**目标4:每班人资部小朋友数量接近期望值**
|
||||
|
||||
期望每班有 $m_4 = 1$ 位人资部小朋友,定义缺口:
|
||||
|
||||
$$X_4 = \sum_{j=1}^{m} a_j^{(4)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(4)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(4)} \ge \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{hr}_i - m_4$$
|
||||
$$a_j^{(4)} \ge m_4 - \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{hr}_i, \quad \forall j$$
|
||||
|
||||
**目标5:均衡各部门人数分布**
|
||||
|
||||
对每个班次 $j$ 和每个部门 $k$,定义该班次该部门的人数偏差:
|
||||
|
||||
$$X_5 = \sum_{j=1}^{m} \sum_{k=1}^{t} a_{jk}^{(5)}$$
|
||||
|
||||
其中 $\bar{M}_j = \frac{M_j}{t}$ 表示第 $j$ 班次各部门的平均人数,$C_{jk} = \sum_{i=1}^{n} x_{ij} \cdot d_{ik}$ 表示第 $j$ 班次第 $k$ 部门的实际人数,辅助变量 $a_{jk}^{(5)} \in [0,+\infty)$ 满足:
|
||||
|
||||
$$a_{jk}^{(5)} \ge C_{jk} - \bar{M}_j, \quad a_{jk}^{(5)} \ge \bar{M}_j - C_{jk}, \quad \forall j,k$$
|
||||
|
||||
### 约束条件
|
||||
|
||||
**基本约束:**
|
||||
|
||||
1. **意愿班次约束**:每位同学的值班次数必须符合其意愿
|
||||
$$\sum_{j=1}^{m}x_{ij} = N_i, \quad \forall i \text{ where } N_i \neq 3$$
|
||||
$$2 \le \sum_{j=1}^{m}x_{ij} \le 3, \quad \forall i \text{ where } N_i = 3$$
|
||||
|
||||
2. **时间可行性约束**:只在有空的时间段排班
|
||||
$$x_{ij} \le v_{ij}, \quad \forall i,j$$
|
||||
|
||||
**班次人数约束:**
|
||||
|
||||
3. **总人数约束**:每班次人数在 $[n_{\min}, n_{\max}]$ 范围内
|
||||
$$n_{\min} \le \sum_{i=1}^{n} x_{ij} \le n_{\max}, \quad \forall j$$
|
||||
|
||||
4. **技术部老人约束**:每班次技术部老人数在范围内
|
||||
$$n_{\text{tech\_old\_min}} \le \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \cdot \text{tech}_i \le n_{\text{tech\_old\_max}}, \quad \forall j$$
|
||||
|
||||
5. **老人总数约束**:每班次老人总数在范围内
|
||||
$$n_{\text{old\_min}} \le \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \le n_{\text{old\_max}}, \quad \forall j$$
|
||||
|
||||
6. **小朋友总数约束**:每班次小朋友总数在范围内
|
||||
$$n_{\text{new\_min}} \le \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \le n_{\text{new\_max}}, \quad \forall j$$
|
||||
|
||||
### 求解器
|
||||
|
||||
以上完成了整个排班问题的建模。本项目使用 Google OR-Tools 中的 **SCIP 求解器**(Solving Constraint Integer Programs)进行求解。SCIP 是一个强大的混合整数规划(MIP)求解器,特别适合处理这类组合优化问题。
|
||||
|
||||
OR-Tools 支持 `C++`、`Python`、`C#`、`Java` 等多种语言,并提供跨平台支持。在本项目中,我们使用其 Python 接口 `ortools.linear_solver.pywraplp` 进行建模和求解。当找到最优解时,求解器会输出详细的目标值和各个优化指标的统计信息。
|
||||
|
||||
## 维护指南
|
||||
- 如果你想更改 Excel 的读取、写入相关的功能,应该修改 `utils.py` 中的相关函数。
|
||||
- 如果你想更改软件的前端界面,应该修改 `main.py` 中 `MyWidget` 这个类相关的代码。
|
||||
# EVA 值班排班工具
|
||||
|
||||
## 环境配置
|
||||
|
||||
本项目使用 `uv` 进行包管理。
|
||||
|
||||
安装项目中所需要的所有包的最新版本。其中 `pyside6` 是一个前端库,`pyinstaller` 用于打包项目,`ortools` 是一个高效的组合优化求解器,`pandas` 用于处理表格数据:
|
||||
```bash
|
||||
uv sync
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
```
|
||||
EVA_duty_arrange_tool/
|
||||
├─ main.py // 主函数,定义了前端界面和组件的回调函数
|
||||
├─ solve.py // 定义了值班排班问题的求解函数
|
||||
├─ utils.py // 定义了读取、写入 excel 的函数
|
||||
├─ pics // 储存了说明文档中用到的图片
|
||||
│ ├─ *.jpg/*.png
|
||||
├─ *.md // 说明文档
|
||||
├─ *.xlsx // 测试用例
|
||||
```
|
||||
|
||||
## 项目运行 & 打包
|
||||
项目运行方式:
|
||||
```bash
|
||||
uv run main.py
|
||||
```
|
||||
|
||||
本项目使用 `pyinstaller` 工具进行打包。如果要打包,请确保能够正常运行项目。打包命令如下:
|
||||
```bash
|
||||
uv run pyinstaller --onefile --windowed --name=EVA_duty_arrange_tool --hidden-import=ortools --collect-all ortools --additional-hooks-dir=. main.py
|
||||
```
|
||||
|
||||
> **注意**:由于 `ortools` 库包含大量 DLL 依赖,需要使用 `--collect-all ortools` 参数来收集所有必要的动态链接库。`--additional-hooks-dir=.` 参数指定使用项目根目录下的 `hook-ortools.py` 文件来确保正确打包。
|
||||
|
||||
## 数学原理
|
||||
本项目将值班排班问题建模为了一个[组合优化](https://zh.wikipedia.org/wiki/%E7%BB%84%E5%90%88%E4%BC%98%E5%8C%96)问题,使用 Google 的 OR-Tools 求解器中的 SCIP 求解器进行求解。
|
||||
|
||||
### 问题描述
|
||||
|
||||
在本问题中,优化目标是一个涉及多个方面的量化指标:
|
||||
- **目标1**:每一班同学数量的平均程度
|
||||
- **目标2**:每一班技术部老人数量接近期望值
|
||||
- **目标3**:每一班技术部小朋友数量接近期望值
|
||||
- **目标4**:每一班人资部小朋友数量接近期望值
|
||||
- **目标5**:每一班各部门人数的平均程度
|
||||
|
||||
在本问题中,主要约束是:
|
||||
1. 让每位同学每周的班次数符合意愿(特别地,选择3次的同学可以安排2-3次)
|
||||
2. 让每位同学只在自己有空的时间段值班
|
||||
3. 每班次的总人数在指定范围内
|
||||
4. 每班次技术部老人数量在指定范围内
|
||||
5. 每班次老人总数在指定范围内
|
||||
6. 每班次小朋友总数在指定范围内
|
||||
|
||||
### 数学建模
|
||||
|
||||
设一共有 $n$ 位同学,$m$ 个值班的班次,协会共有 $t=5$ 个部门(电脑部、电器部、人资部、财外部、文宣部),定义以下符号:
|
||||
|
||||
**决策变量:**
|
||||
- $x_{ij} \in \{0,1\}, \quad i=1,2,\dots,n,\quad j=1,2,\dots,m$ 表示第 $i$ 位同学是否值第 $j$ 班
|
||||
|
||||
**已知参数:**
|
||||
- $N_i \in \mathbb{N}, \quad i=1,2,\dots,n$ 表示第 $i$ 个同学每周愿意值班次数
|
||||
- $v_{ij} \in \{0,1\}, \quad i=1,2,\dots,n,\quad j=1,2,\dots,m$ 表示第 $i$ 位同学是否有空值第 $j$ 班
|
||||
- $\text{old}_i \in \{0,1\}, \quad i=1,2,\dots,n$ 表示第 $i$ 位同学是否是老人(非小朋友)
|
||||
- $d_{ik}\in\{0,1\}, \quad i=1,2,\dots,n,\quad k=1,2,\dots,t$ 表示第 $i$ 位同学是否属于第 $k$ 个部门
|
||||
- $\text{tech}_i = d_{i1} + d_{i2} \in \{0,1\}$ 表示第 $i$ 位同学是否属于技术部(电脑部或电器部)
|
||||
- $\text{hr}_i = d_{i3} \in \{0,1\}$ 表示第 $i$ 位同学是否属于人资部
|
||||
|
||||
**派生量:**
|
||||
- $M_j = \sum_{i=1}^{n} x_{ij}, \quad j=1,2,\dots,m$ 表示第 $j$ 班次实际安排的值班人数
|
||||
- $\bar{M} = \frac{\sum_{i=1}^{n}N_i}{m}$ 表示平均每班的人数
|
||||
|
||||
### 优化目标
|
||||
|
||||
为了处理多目标优化问题,我们采用**线性加权法**将多个目标组合成单一目标函数。引入归一化系数 $m_1=2.5, m_2=3, m_3=4, m_4=1, m_5=8$ 和权重 $w_1, w_2, w_3, w_4, w_5$,总目标函数为:
|
||||
|
||||
$$\min \quad Z = w_1 \cdot \frac{X_1}{m_1 \cdot M} + w_2 \cdot \frac{X_2}{m_2 \cdot M} + w_3 \cdot \frac{X_3}{m_3 \cdot M} + w_4 \cdot \frac{X_4}{m_4 \cdot M} + w_5 \cdot \frac{X_5}{m_5 \cdot M}$$
|
||||
|
||||
各目标定义如下:
|
||||
|
||||
**目标1:均衡班次人数**
|
||||
|
||||
$$X_1 = \sum_{j=1}^{m} a_j^{(1)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(1)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(1)} \ge M_j - \bar{M}, \quad a_j^{(1)} \ge \bar{M} - M_j, \quad \forall j$$
|
||||
|
||||
> 注:在组合优化问题中只能定义线性约束,不能直接使用绝对值。因此引入辅助变量 $a_j^{(1)}$ 并添加两个不等式约束,使得在优化过程中 $a_j^{(1)}$ 自动收敛到 $|M_j - \bar{M}|$。
|
||||
|
||||
**目标2:每班技术部老人数量接近期望值**
|
||||
|
||||
期望每班有 $m_2 = 3$ 位技术部老人,定义缺口:
|
||||
|
||||
$$X_2 = \sum_{j=1}^{m} a_j^{(2)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(2)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(2)} \ge \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \cdot \text{tech}_i - m_2$$
|
||||
$$a_j^{(2)} \ge m_2 - \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \cdot \text{tech}_i, \quad \forall j$$
|
||||
|
||||
**目标3:每班技术部小朋友数量接近期望值**
|
||||
|
||||
期望每班有 $m_3 = 4$ 位技术部小朋友,定义缺口:
|
||||
|
||||
$$X_3 = \sum_{j=1}^{m} a_j^{(3)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(3)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(3)} \ge \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{tech}_i - m_3$$
|
||||
$$a_j^{(3)} \ge m_3 - \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{tech}_i, \quad \forall j$$
|
||||
|
||||
**目标4:每班人资部小朋友数量接近期望值**
|
||||
|
||||
期望每班有 $m_4 = 1$ 位人资部小朋友,定义缺口:
|
||||
|
||||
$$X_4 = \sum_{j=1}^{m} a_j^{(4)}$$
|
||||
|
||||
其中辅助变量 $a_j^{(4)} \in [0,+\infty)$ 满足:
|
||||
$$a_j^{(4)} \ge \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{hr}_i - m_4$$
|
||||
$$a_j^{(4)} \ge m_4 - \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \cdot \text{hr}_i, \quad \forall j$$
|
||||
|
||||
**目标5:均衡各部门人数分布**
|
||||
|
||||
对每个班次 $j$ 和每个部门 $k$,定义该班次该部门的人数偏差:
|
||||
|
||||
$$X_5 = \sum_{j=1}^{m} \sum_{k=1}^{t} a_{jk}^{(5)}$$
|
||||
|
||||
其中 $\bar{M}_j = \frac{M_j}{t}$ 表示第 $j$ 班次各部门的平均人数,$C_{jk} = \sum_{i=1}^{n} x_{ij} \cdot d_{ik}$ 表示第 $j$ 班次第 $k$ 部门的实际人数,辅助变量 $a_{jk}^{(5)} \in [0,+\infty)$ 满足:
|
||||
|
||||
$$a_{jk}^{(5)} \ge C_{jk} - \bar{M}_j, \quad a_{jk}^{(5)} \ge \bar{M}_j - C_{jk}, \quad \forall j,k$$
|
||||
|
||||
### 约束条件
|
||||
|
||||
**基本约束:**
|
||||
|
||||
1. **意愿班次约束**:每位同学的值班次数必须符合其意愿
|
||||
$$\sum_{j=1}^{m}x_{ij} = N_i, \quad \forall i \text{ where } N_i \neq 3$$
|
||||
$$2 \le \sum_{j=1}^{m}x_{ij} \le 3, \quad \forall i \text{ where } N_i = 3$$
|
||||
|
||||
2. **时间可行性约束**:只在有空的时间段排班
|
||||
$$x_{ij} \le v_{ij}, \quad \forall i,j$$
|
||||
|
||||
**班次人数约束:**
|
||||
|
||||
3. **总人数约束**:每班次人数在 $[n_{\min}, n_{\max}]$ 范围内
|
||||
$$n_{\min} \le \sum_{i=1}^{n} x_{ij} \le n_{\max}, \quad \forall j$$
|
||||
|
||||
4. **技术部老人约束**:每班次技术部老人数在范围内
|
||||
$$n_{\text{tech\_old\_min}} \le \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \cdot \text{tech}_i \le n_{\text{tech\_old\_max}}, \quad \forall j$$
|
||||
|
||||
5. **老人总数约束**:每班次老人总数在范围内
|
||||
$$n_{\text{old\_min}} \le \sum_{i=1}^{n} x_{ij} \cdot \text{old}_i \le n_{\text{old\_max}}, \quad \forall j$$
|
||||
|
||||
6. **小朋友总数约束**:每班次小朋友总数在范围内
|
||||
$$n_{\text{new\_min}} \le \sum_{i=1}^{n} x_{ij} \cdot (1-\text{old}_i) \le n_{\text{new\_max}}, \quad \forall j$$
|
||||
|
||||
### 求解器
|
||||
|
||||
以上完成了整个排班问题的建模。本项目使用 Google OR-Tools 中的 **SCIP 求解器**(Solving Constraint Integer Programs)进行求解。SCIP 是一个强大的混合整数规划(MIP)求解器,特别适合处理这类组合优化问题。
|
||||
|
||||
OR-Tools 支持 `C++`、`Python`、`C#`、`Java` 等多种语言,并提供跨平台支持。在本项目中,我们使用其 Python 接口 `ortools.linear_solver.pywraplp` 进行建模和求解。当找到最优解时,求解器会输出详细的目标值和各个优化指标的统计信息。
|
||||
|
||||
## 维护指南
|
||||
- 如果你想更改 Excel 的读取、写入相关的功能,应该修改 `utils.py` 中的相关函数。
|
||||
- 如果你想更改软件的前端界面,应该修改 `main.py` 中 `MyWidget` 这个类相关的代码。
|
||||
- 如果你想更换排班问题的建模方式、更换求解器、增减限制条件,应该修改 `solve.py` 中的相关代码。
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
from PyInstaller.utils.hooks import collect_data_files, collect_dynamic_libs
|
||||
|
||||
# 收集 ortools 的所有数据文件和动态链接库
|
||||
datas = collect_data_files('ortools')
|
||||
binaries = collect_dynamic_libs('ortools')
|
||||
802
main.py
802
main.py
|
|
@ -1,402 +1,402 @@
|
|||
from sys import exit
|
||||
from PySide6 import QtCore, QtWidgets, QtGui
|
||||
from PySide6.QtGui import QFont
|
||||
from utils import read_excel, save_to_excel
|
||||
from solve import solve_program
|
||||
from datetime import datetime
|
||||
from traceback import format_exc
|
||||
|
||||
# 约束条件配置
|
||||
CONSTRAINTS_CONFIG = [
|
||||
("每班次人数:", "5", "8"),
|
||||
("每班次电脑或电器的老人数:", "", "2"),
|
||||
("每班次老人数:", "1", ""),
|
||||
("每班次小朋友数:", "2", "")
|
||||
]
|
||||
|
||||
# 权重条件配置
|
||||
WEIGHTS_CONFIG = [
|
||||
("目标 1 权重:每班人数平均程度", "1.0"),
|
||||
("目标 2 权重:每班技术部老人", "1.0"),
|
||||
("目标 3 权重:每班技术部小朋友", "1.0"),
|
||||
("目标 4 权重:每班人资部小朋友", "0.5"),
|
||||
("目标 5 权重:每班部门平均程度", "0.5")
|
||||
]
|
||||
|
||||
# 参数调优顺序和尝试值
|
||||
PARAM_CONFIGS = [
|
||||
('num_min', [5, 4, 3, 2, 1]),
|
||||
('num_max', [8, 9, 10, 11, 12, 13, 14, 15]),
|
||||
('num_old_min', [2, 1, 0]),
|
||||
('num_old_max', [3, 4, 5, 6, 7, 8]),
|
||||
('num_new_min', [1, 0]),
|
||||
('num_tech_old_min', [1, 0]),
|
||||
('num_tech_old_max', [1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
]
|
||||
|
||||
# 工作线程类,用于在后台执行求解任务
|
||||
class SolverThread(QtCore.QThread):
|
||||
# 定义信号用于线程与主界面通信
|
||||
log_signal = QtCore.Signal(str) # 发送日志消息
|
||||
finished_signal = QtCore.Signal(object, dict) # 发送求解结果 (vars, params)
|
||||
error_signal = QtCore.Signal(str) # 发送错误消息
|
||||
|
||||
def __init__(self, preference_mat, depart_mat, want_num_array, is_new_array,
|
||||
auto_mode, manual_params=None, parent=None):
|
||||
super().__init__(parent)
|
||||
self.preference_mat = preference_mat
|
||||
self.depart_mat = depart_mat
|
||||
self.want_num_array = want_num_array
|
||||
self.is_new_array = is_new_array
|
||||
self.auto_mode = auto_mode
|
||||
self.manual_params = manual_params or {}
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
vars = None
|
||||
final_params = {}
|
||||
|
||||
if self.auto_mode:
|
||||
self.log_signal.emit("自动调参开始...")
|
||||
|
||||
auto_params = {
|
||||
'num_min': None, 'num_max': None,
|
||||
'num_tech_old_min': None, 'num_tech_old_max': None,
|
||||
'num_old_min': None, 'num_old_max': None,
|
||||
'num_new_min': None, 'num_new_max': None,
|
||||
'weights': self.manual_params.get('weights', [1.0, 1.0, 1.0, 0.5, 0.5])
|
||||
}
|
||||
|
||||
# 逐步优化参数
|
||||
for param_name, try_values in PARAM_CONFIGS:
|
||||
value = None
|
||||
vars = None
|
||||
for try_value in try_values:
|
||||
self.log_signal.emit(f"尝试 {param_name} = {try_value}...")
|
||||
test_params = auto_params.copy()
|
||||
test_params[param_name] = try_value
|
||||
vars = solve_program(
|
||||
preference_mat=self.preference_mat,
|
||||
depart_mat=self.depart_mat,
|
||||
want_num_array=self.want_num_array,
|
||||
is_new_array=self.is_new_array,
|
||||
**test_params
|
||||
)
|
||||
if vars:
|
||||
value = try_value
|
||||
self.log_signal.emit(f"✓ {param_name} = {try_value} 成功")
|
||||
break
|
||||
else:
|
||||
self.log_signal.emit(f"✗ {param_name} = {try_value} 失败")
|
||||
if value:
|
||||
auto_params[param_name] = value
|
||||
else:
|
||||
break
|
||||
|
||||
final_params = auto_params
|
||||
|
||||
else:
|
||||
self.log_signal.emit("计算最优解中...")
|
||||
vars = solve_program(
|
||||
preference_mat=self.preference_mat,
|
||||
want_num_array=self.want_num_array,
|
||||
depart_mat=self.depart_mat,
|
||||
is_new_array=self.is_new_array,
|
||||
**self.manual_params
|
||||
)
|
||||
final_params = self.manual_params
|
||||
|
||||
# 发送完成信号
|
||||
self.finished_signal.emit(vars, final_params)
|
||||
|
||||
except Exception as e:
|
||||
self.error_signal.emit(format_exc())
|
||||
|
||||
class MyWidget(QtWidgets.QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.solver_thread = None # 用于存储求解线程
|
||||
|
||||
self.main_layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
bold_font = QFont()
|
||||
bold_font.setBold(True)
|
||||
|
||||
thin_font = QFont()
|
||||
thin_font.setBold(False)
|
||||
|
||||
# 选择文件部分
|
||||
self._excel_dir = None
|
||||
self.group_box_1 = QtWidgets.QGroupBox("Step 1. 选择问卷星导出的表格文件")
|
||||
self.group_box_1.setFont(bold_font)
|
||||
|
||||
self.openfile_layout = QtWidgets.QVBoxLayout()
|
||||
self.button_openfile = QtWidgets.QPushButton("选择文件")
|
||||
self.button_openfile.setFont(thin_font)
|
||||
self.button_openfile.clicked.connect(self.open_file)
|
||||
self.label_openfile = QtWidgets.QLabel("未选择文件")
|
||||
self.label_openfile.setFont(thin_font)
|
||||
|
||||
self.openfile_layout.addWidget(self.button_openfile)
|
||||
self.openfile_layout.addWidget(self.label_openfile)
|
||||
self.group_box_1.setLayout(self.openfile_layout)
|
||||
self.main_layout.addWidget(self.group_box_1)
|
||||
|
||||
# 限制条件部分
|
||||
self.group_box_2 = QtWidgets.QGroupBox("Step 2. 输入限制条件,权重参数均已归一化")
|
||||
self.group_box_2.setFont(bold_font)
|
||||
self.cond_layout_overall = QtWidgets.QVBoxLayout()
|
||||
self.group_box_2.setLayout(self.cond_layout_overall)
|
||||
|
||||
# 创建权重输入框
|
||||
self.weight_widgets = {}
|
||||
|
||||
for i, (label_text, value) in enumerate(WEIGHTS_CONFIG, 1):
|
||||
layout, edit = self._create_weight_row(label_text, value, thin_font)
|
||||
self.weight_widgets[f'layout_{i}'] = layout
|
||||
self.weight_widgets[f'edit_{i}'] = edit
|
||||
self.cond_layout_overall.addLayout(layout)
|
||||
|
||||
# 自动模式开关
|
||||
self._auto_mode = True
|
||||
self.cond_layout_0 = QtWidgets.QVBoxLayout()
|
||||
self.auto_switch = QtWidgets.QCheckBox("自动调参模式")
|
||||
self.auto_switch.setTristate(False) # 禁用三态模式
|
||||
self.auto_switch.setChecked(True)
|
||||
self.auto_switch.stateChanged.connect(self.on_switch_toggled)
|
||||
self.auto_switch.setFont(thin_font)
|
||||
|
||||
self.cond_layout_0.addWidget(self.auto_switch)
|
||||
self.cond_layout_overall.addLayout(self.cond_layout_0)
|
||||
|
||||
# 创建限制条件输入框
|
||||
self.constraint_widgets = {}
|
||||
|
||||
for i, (label_text, min_value, max_value) in enumerate(CONSTRAINTS_CONFIG, 1):
|
||||
layout, min_edit, max_edit = self._create_constraint_row(label_text, min_value, max_value, thin_font)
|
||||
self.constraint_widgets[f'layout_{i}'] = layout
|
||||
self.constraint_widgets[f'min_{i}'] = min_edit
|
||||
self.constraint_widgets[f'max_{i}'] = max_edit
|
||||
self.cond_layout_overall.addLayout(layout)
|
||||
|
||||
self.main_layout.addWidget(self.group_box_2)
|
||||
|
||||
# 处理文件部分
|
||||
self.group_box_3 = QtWidgets.QGroupBox("Step 3. 获取最优结果")
|
||||
self.group_box_3.setFont(bold_font)
|
||||
|
||||
self.button_solve = QtWidgets.QPushButton("开始排班!")
|
||||
self.button_solve.setFont(thin_font)
|
||||
self.text_solve = QtWidgets.QTextEdit(self)
|
||||
self.text_solve.setFont(thin_font)
|
||||
self.text_solve.setReadOnly(True) # 设置为只读模式
|
||||
|
||||
# 创建 QScrollArea 并将 QTextEdit 添加进去
|
||||
self.scroll_area = QtWidgets.QScrollArea(self)
|
||||
self.scroll_area.setWidget(self.text_solve) # 将 QTextEdit 设置为 QScrollArea 的内容
|
||||
self.scroll_area.setWidgetResizable(True) # 允许 QTextEdit 根据 QScrollArea 的大小自动调整
|
||||
|
||||
self.button_solve.clicked.connect(self.magic)
|
||||
|
||||
self.solve_layout = QtWidgets.QVBoxLayout()
|
||||
self.solve_layout.addWidget(self.scroll_area)
|
||||
self.solve_layout.addWidget(self.button_solve)
|
||||
self.group_box_3.setLayout(self.solve_layout)
|
||||
self.main_layout.addWidget(self.group_box_3)
|
||||
|
||||
def _create_constraint_row(self, label_text, min_value, max_value, font):
|
||||
"""创建一行限制条件输入框"""
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
|
||||
label = QtWidgets.QLabel(label_text, self)
|
||||
label.setFont(font)
|
||||
|
||||
# 创建输入框的辅助函数
|
||||
def create_input(value):
|
||||
edit = QtWidgets.QLineEdit(self)
|
||||
edit.setFont(font)
|
||||
edit.setValidator(QtGui.QIntValidator())
|
||||
edit.setPlaceholderText("无限制")
|
||||
if value:
|
||||
edit.setText(value)
|
||||
edit.setEnabled(False)
|
||||
return edit
|
||||
|
||||
min_edit = create_input(min_value)
|
||||
to_label = QtWidgets.QLabel("到", self)
|
||||
to_label.setFont(font)
|
||||
max_edit = create_input(max_value)
|
||||
|
||||
layout.addWidget(label)
|
||||
layout.addWidget(min_edit)
|
||||
layout.addWidget(to_label)
|
||||
layout.addWidget(max_edit)
|
||||
|
||||
return layout, min_edit, max_edit
|
||||
|
||||
def _create_weight_row(self, label_text, value, font):
|
||||
"""创建一行权重输入框"""
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
|
||||
label = QtWidgets.QLabel(label_text, self)
|
||||
label.setFont(font)
|
||||
|
||||
edit = QtWidgets.QLineEdit(self)
|
||||
edit.setFont(font)
|
||||
edit.setValidator(QtGui.QDoubleValidator(0.0, 1.0, 2, self))
|
||||
edit.setText(str(value))
|
||||
|
||||
layout.addWidget(label)
|
||||
layout.addWidget(edit)
|
||||
|
||||
return layout, edit
|
||||
|
||||
def open_file(self):
|
||||
file_path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "打开文件", "", "所有文件 (*.*);;文本文件 (*.txt)")
|
||||
if file_path:
|
||||
self.label_openfile.setText(f"选中文件: {file_path}")
|
||||
self._excel_dir = file_path
|
||||
|
||||
def on_switch_toggled(self, state):
|
||||
enabled = state == 0
|
||||
self._auto_mode = not enabled
|
||||
|
||||
for i in range(1, len(CONSTRAINTS_CONFIG) + 1):
|
||||
self.constraint_widgets[f'min_{i}'].setEnabled(enabled)
|
||||
self.constraint_widgets[f'max_{i}'].setEnabled(enabled)
|
||||
|
||||
@QtCore.Slot()
|
||||
def magic(self):
|
||||
try:
|
||||
self.text_solve.append(f"******** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ********")
|
||||
|
||||
# 读取文件
|
||||
if self._excel_dir is None:
|
||||
self.text_solve.append("请先选择文件!")
|
||||
return
|
||||
|
||||
# 禁用按钮,防止重复点击
|
||||
self.button_solve.setEnabled(False)
|
||||
self.button_solve.setText("计算中...")
|
||||
|
||||
self.text_solve.append("开始排班...")
|
||||
self.text_solve.append("读取文件中...")
|
||||
self.all_data, self.index_to_name_dict, preference_mat, depart_mat, want_num_array, is_new_array = read_excel(self._excel_dir)
|
||||
self.text_solve.append("读取文件成功!")
|
||||
|
||||
# 计算并打印统计信息
|
||||
is_tech_array = [depart_mat[i][0] == 1 or depart_mat[i][1] == 1 for i in range(len(depart_mat))]
|
||||
stu_num = len(self.index_to_name_dict)
|
||||
class_num = len(preference_mat[0])
|
||||
tech_sum = sum(want_num_array[i] for i in range(len(preference_mat))
|
||||
if not is_new_array[i] and is_tech_array[i])
|
||||
all_sum = sum(want_num_array)
|
||||
min_prefer = min(sum(preference_mat[i][j] for i in range(len(preference_mat)))
|
||||
for j in range(class_num))
|
||||
|
||||
self.text_solve.append("信息统计:")
|
||||
self.text_solve.append(f"\t学生总人数:{stu_num}")
|
||||
self.text_solve.append(f"\t班次总数:{class_num}")
|
||||
self.text_solve.append(f"\t电脑部或电器部的所有老人的意愿班次之和:{tech_sum}")
|
||||
self.text_solve.append(f"\t所有人的意愿班次之和:{all_sum}")
|
||||
self.text_solve.append(f"\t平均每班人数:{all_sum/20}")
|
||||
self.text_solve.append(f"\t所有班次中最少拥有意愿数:{min_prefer}")
|
||||
|
||||
def get_weight_value(key):
|
||||
text = self.weight_widgets[key].text()
|
||||
return float(text) if text else 0.0
|
||||
|
||||
def get_constraint_value(key):
|
||||
text = self.constraint_widgets[key].text()
|
||||
return int(text) if text else None
|
||||
|
||||
# 准备参数
|
||||
params = {
|
||||
'num_min': get_constraint_value('min_1'),
|
||||
'num_max': get_constraint_value('max_1'),
|
||||
'num_tech_old_min': get_constraint_value('min_2'),
|
||||
'num_tech_old_max': get_constraint_value('max_2'),
|
||||
'num_old_min': get_constraint_value('min_3'),
|
||||
'num_old_max': get_constraint_value('max_3'),
|
||||
'num_new_min': get_constraint_value('min_4'),
|
||||
'num_new_max': get_constraint_value('max_4'),
|
||||
'weights': [get_weight_value(f'edit_{i}') for i in range(1, len(WEIGHTS_CONFIG) + 1)]
|
||||
}
|
||||
|
||||
# 创建并启动求解线程
|
||||
self.solver_thread = SolverThread(
|
||||
preference_mat, depart_mat, want_num_array, is_new_array,
|
||||
self._auto_mode, params, self
|
||||
)
|
||||
|
||||
# 连接信号
|
||||
self.solver_thread.log_signal.connect(self.on_log_message)
|
||||
self.solver_thread.finished_signal.connect(self.on_solve_finished)
|
||||
self.solver_thread.error_signal.connect(self.on_solve_error)
|
||||
|
||||
# 启动线程
|
||||
self.solver_thread.start()
|
||||
|
||||
except Exception:
|
||||
self.text_solve.append("程序出现严重错误,请联系开发者解决问题!!!")
|
||||
self.text_solve.append(f"Error Details:\n{format_exc()}")
|
||||
self.button_solve.setEnabled(True)
|
||||
self.button_solve.setText("开始排班!")
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def on_log_message(self, message):
|
||||
"""接收线程发送的日志消息并实时显示"""
|
||||
self.text_solve.append(message)
|
||||
|
||||
@QtCore.Slot(object, dict)
|
||||
def on_solve_finished(self, vars, params):
|
||||
"""求解完成后的回调"""
|
||||
try:
|
||||
if vars is None:
|
||||
if self._auto_mode:
|
||||
self.text_solve.append("自动求解失败!请尝试手动调参!")
|
||||
else:
|
||||
self.text_solve.append("在目前限制条件下无解!请尝试更改限制条件!")
|
||||
else:
|
||||
if self._auto_mode:
|
||||
self.text_solve.append("自动计算成功!")
|
||||
self.text_solve.append("参数:")
|
||||
self.text_solve.append(f"\t每班人数:[{params['num_min']}, {params['num_max']}]")
|
||||
self.text_solve.append(f"\t每班电脑或电器的老人数:[{params['num_tech_old_min']}, {params['num_tech_old_max']}]")
|
||||
self.text_solve.append(f"\t每班老人数:[{params['num_old_min']}, {params['num_old_max']}]")
|
||||
self.text_solve.append(f"\t每班小朋友数:[{params['num_new_min']}, inf]")
|
||||
else:
|
||||
self.text_solve.append("计算最优解成功!")
|
||||
|
||||
# 保存结果到 excel
|
||||
self.text_solve.append("保存结果中...")
|
||||
save_dir = f"result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
|
||||
save_to_excel(vars, self.all_data, self.index_to_name_dict, save_dir)
|
||||
self.text_solve.append(f"保存结果成功!保存路径:{save_dir}")
|
||||
|
||||
except Exception:
|
||||
self.text_solve.append("保存结果时出现错误!")
|
||||
self.text_solve.append(f"Error Details:\n{format_exc()}")
|
||||
finally:
|
||||
# 恢复按钮状态
|
||||
self.button_solve.setEnabled(True)
|
||||
self.button_solve.setText("开始排班!")
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def on_solve_error(self, error_msg):
|
||||
"""处理求解过程中的错误"""
|
||||
self.text_solve.append("程序出现严重错误,请联系开发者解决问题!!!")
|
||||
self.text_solve.append(f"Error Details:\n{error_msg}")
|
||||
self.button_solve.setEnabled(True)
|
||||
self.button_solve.setText("开始排班!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QtWidgets.QApplication([])
|
||||
|
||||
widget = MyWidget()
|
||||
widget.setWindowTitle("EVA 值班排班软件")
|
||||
widget.resize(600, 600)
|
||||
widget.show()
|
||||
|
||||
from sys import exit
|
||||
from PySide6 import QtCore, QtWidgets, QtGui
|
||||
from PySide6.QtGui import QFont
|
||||
from utils import read_excel, save_to_excel
|
||||
from solve import solve_program
|
||||
from datetime import datetime
|
||||
from traceback import format_exc
|
||||
|
||||
# 约束条件配置
|
||||
CONSTRAINTS_CONFIG = [
|
||||
("每班次人数:", "5", "8"),
|
||||
("每班次电脑或电器的老人数:", "", "2"),
|
||||
("每班次老人数:", "1", ""),
|
||||
("每班次小朋友数:", "2", "")
|
||||
]
|
||||
|
||||
# 权重条件配置
|
||||
WEIGHTS_CONFIG = [
|
||||
("目标 1 权重:每班人数平均程度", "1.0"),
|
||||
("目标 2 权重:每班技术部老人", "1.0"),
|
||||
("目标 3 权重:每班技术部小朋友", "1.0"),
|
||||
("目标 4 权重:每班人资部小朋友", "0.5"),
|
||||
("目标 5 权重:每班部门平均程度", "0.5")
|
||||
]
|
||||
|
||||
# 参数调优顺序和尝试值
|
||||
PARAM_CONFIGS = [
|
||||
('num_min', [5, 4, 3, 2, 1]),
|
||||
('num_max', [8, 9, 10, 11, 12, 13, 14, 15]),
|
||||
('num_old_min', [2, 1, 0]),
|
||||
('num_old_max', [3, 4, 5, 6, 7, 8]),
|
||||
('num_new_min', [1, 0]),
|
||||
('num_tech_old_min', [1, 0]),
|
||||
('num_tech_old_max', [1, 2, 3, 4, 5, 6, 7, 8]),
|
||||
]
|
||||
|
||||
# 工作线程类,用于在后台执行求解任务
|
||||
class SolverThread(QtCore.QThread):
|
||||
# 定义信号用于线程与主界面通信
|
||||
log_signal = QtCore.Signal(str) # 发送日志消息
|
||||
finished_signal = QtCore.Signal(object, dict) # 发送求解结果 (vars, params)
|
||||
error_signal = QtCore.Signal(str) # 发送错误消息
|
||||
|
||||
def __init__(self, preference_mat, depart_mat, want_num_array, is_new_array,
|
||||
auto_mode, manual_params=None, parent=None):
|
||||
super().__init__(parent)
|
||||
self.preference_mat = preference_mat
|
||||
self.depart_mat = depart_mat
|
||||
self.want_num_array = want_num_array
|
||||
self.is_new_array = is_new_array
|
||||
self.auto_mode = auto_mode
|
||||
self.manual_params = manual_params or {}
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
vars = None
|
||||
final_params = {}
|
||||
|
||||
if self.auto_mode:
|
||||
self.log_signal.emit("自动调参开始...")
|
||||
|
||||
auto_params = {
|
||||
'num_min': None, 'num_max': None,
|
||||
'num_tech_old_min': None, 'num_tech_old_max': None,
|
||||
'num_old_min': None, 'num_old_max': None,
|
||||
'num_new_min': None, 'num_new_max': None,
|
||||
'weights': self.manual_params.get('weights', [1.0, 1.0, 1.0, 0.5, 0.5])
|
||||
}
|
||||
|
||||
# 逐步优化参数
|
||||
for param_name, try_values in PARAM_CONFIGS:
|
||||
value = None
|
||||
vars = None
|
||||
for try_value in try_values:
|
||||
self.log_signal.emit(f"尝试 {param_name} = {try_value}...")
|
||||
test_params = auto_params.copy()
|
||||
test_params[param_name] = try_value
|
||||
vars = solve_program(
|
||||
preference_mat=self.preference_mat,
|
||||
depart_mat=self.depart_mat,
|
||||
want_num_array=self.want_num_array,
|
||||
is_new_array=self.is_new_array,
|
||||
**test_params
|
||||
)
|
||||
if vars:
|
||||
value = try_value
|
||||
self.log_signal.emit(f"✓ {param_name} = {try_value} 成功")
|
||||
break
|
||||
else:
|
||||
self.log_signal.emit(f"✗ {param_name} = {try_value} 失败")
|
||||
if value:
|
||||
auto_params[param_name] = value
|
||||
else:
|
||||
break
|
||||
|
||||
final_params = auto_params
|
||||
|
||||
else:
|
||||
self.log_signal.emit("计算最优解中...")
|
||||
vars = solve_program(
|
||||
preference_mat=self.preference_mat,
|
||||
want_num_array=self.want_num_array,
|
||||
depart_mat=self.depart_mat,
|
||||
is_new_array=self.is_new_array,
|
||||
**self.manual_params
|
||||
)
|
||||
final_params = self.manual_params
|
||||
|
||||
# 发送完成信号
|
||||
self.finished_signal.emit(vars, final_params)
|
||||
|
||||
except Exception as e:
|
||||
self.error_signal.emit(format_exc())
|
||||
|
||||
class MyWidget(QtWidgets.QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.solver_thread = None # 用于存储求解线程
|
||||
|
||||
self.main_layout = QtWidgets.QVBoxLayout(self)
|
||||
|
||||
bold_font = QFont()
|
||||
bold_font.setBold(True)
|
||||
|
||||
thin_font = QFont()
|
||||
thin_font.setBold(False)
|
||||
|
||||
# 选择文件部分
|
||||
self._excel_dir = None
|
||||
self.group_box_1 = QtWidgets.QGroupBox("Step 1. 选择问卷星导出的表格文件")
|
||||
self.group_box_1.setFont(bold_font)
|
||||
|
||||
self.openfile_layout = QtWidgets.QVBoxLayout()
|
||||
self.button_openfile = QtWidgets.QPushButton("选择文件")
|
||||
self.button_openfile.setFont(thin_font)
|
||||
self.button_openfile.clicked.connect(self.open_file)
|
||||
self.label_openfile = QtWidgets.QLabel("未选择文件")
|
||||
self.label_openfile.setFont(thin_font)
|
||||
|
||||
self.openfile_layout.addWidget(self.button_openfile)
|
||||
self.openfile_layout.addWidget(self.label_openfile)
|
||||
self.group_box_1.setLayout(self.openfile_layout)
|
||||
self.main_layout.addWidget(self.group_box_1)
|
||||
|
||||
# 限制条件部分
|
||||
self.group_box_2 = QtWidgets.QGroupBox("Step 2. 输入限制条件,权重参数均已归一化")
|
||||
self.group_box_2.setFont(bold_font)
|
||||
self.cond_layout_overall = QtWidgets.QVBoxLayout()
|
||||
self.group_box_2.setLayout(self.cond_layout_overall)
|
||||
|
||||
# 创建权重输入框
|
||||
self.weight_widgets = {}
|
||||
|
||||
for i, (label_text, value) in enumerate(WEIGHTS_CONFIG, 1):
|
||||
layout, edit = self._create_weight_row(label_text, value, thin_font)
|
||||
self.weight_widgets[f'layout_{i}'] = layout
|
||||
self.weight_widgets[f'edit_{i}'] = edit
|
||||
self.cond_layout_overall.addLayout(layout)
|
||||
|
||||
# 自动模式开关
|
||||
self._auto_mode = True
|
||||
self.cond_layout_0 = QtWidgets.QVBoxLayout()
|
||||
self.auto_switch = QtWidgets.QCheckBox("自动调参模式")
|
||||
self.auto_switch.setTristate(False) # 禁用三态模式
|
||||
self.auto_switch.setChecked(True)
|
||||
self.auto_switch.stateChanged.connect(self.on_switch_toggled)
|
||||
self.auto_switch.setFont(thin_font)
|
||||
|
||||
self.cond_layout_0.addWidget(self.auto_switch)
|
||||
self.cond_layout_overall.addLayout(self.cond_layout_0)
|
||||
|
||||
# 创建限制条件输入框
|
||||
self.constraint_widgets = {}
|
||||
|
||||
for i, (label_text, min_value, max_value) in enumerate(CONSTRAINTS_CONFIG, 1):
|
||||
layout, min_edit, max_edit = self._create_constraint_row(label_text, min_value, max_value, thin_font)
|
||||
self.constraint_widgets[f'layout_{i}'] = layout
|
||||
self.constraint_widgets[f'min_{i}'] = min_edit
|
||||
self.constraint_widgets[f'max_{i}'] = max_edit
|
||||
self.cond_layout_overall.addLayout(layout)
|
||||
|
||||
self.main_layout.addWidget(self.group_box_2)
|
||||
|
||||
# 处理文件部分
|
||||
self.group_box_3 = QtWidgets.QGroupBox("Step 3. 获取最优结果")
|
||||
self.group_box_3.setFont(bold_font)
|
||||
|
||||
self.button_solve = QtWidgets.QPushButton("开始排班!")
|
||||
self.button_solve.setFont(thin_font)
|
||||
self.text_solve = QtWidgets.QTextEdit(self)
|
||||
self.text_solve.setFont(thin_font)
|
||||
self.text_solve.setReadOnly(True) # 设置为只读模式
|
||||
|
||||
# 创建 QScrollArea 并将 QTextEdit 添加进去
|
||||
self.scroll_area = QtWidgets.QScrollArea(self)
|
||||
self.scroll_area.setWidget(self.text_solve) # 将 QTextEdit 设置为 QScrollArea 的内容
|
||||
self.scroll_area.setWidgetResizable(True) # 允许 QTextEdit 根据 QScrollArea 的大小自动调整
|
||||
|
||||
self.button_solve.clicked.connect(self.magic)
|
||||
|
||||
self.solve_layout = QtWidgets.QVBoxLayout()
|
||||
self.solve_layout.addWidget(self.scroll_area)
|
||||
self.solve_layout.addWidget(self.button_solve)
|
||||
self.group_box_3.setLayout(self.solve_layout)
|
||||
self.main_layout.addWidget(self.group_box_3)
|
||||
|
||||
def _create_constraint_row(self, label_text, min_value, max_value, font):
|
||||
"""创建一行限制条件输入框"""
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
|
||||
label = QtWidgets.QLabel(label_text, self)
|
||||
label.setFont(font)
|
||||
|
||||
# 创建输入框的辅助函数
|
||||
def create_input(value):
|
||||
edit = QtWidgets.QLineEdit(self)
|
||||
edit.setFont(font)
|
||||
edit.setValidator(QtGui.QIntValidator())
|
||||
edit.setPlaceholderText("无限制")
|
||||
if value:
|
||||
edit.setText(value)
|
||||
edit.setEnabled(False)
|
||||
return edit
|
||||
|
||||
min_edit = create_input(min_value)
|
||||
to_label = QtWidgets.QLabel("到", self)
|
||||
to_label.setFont(font)
|
||||
max_edit = create_input(max_value)
|
||||
|
||||
layout.addWidget(label)
|
||||
layout.addWidget(min_edit)
|
||||
layout.addWidget(to_label)
|
||||
layout.addWidget(max_edit)
|
||||
|
||||
return layout, min_edit, max_edit
|
||||
|
||||
def _create_weight_row(self, label_text, value, font):
|
||||
"""创建一行权重输入框"""
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
|
||||
label = QtWidgets.QLabel(label_text, self)
|
||||
label.setFont(font)
|
||||
|
||||
edit = QtWidgets.QLineEdit(self)
|
||||
edit.setFont(font)
|
||||
edit.setValidator(QtGui.QDoubleValidator(0.0, 1.0, 2, self))
|
||||
edit.setText(str(value))
|
||||
|
||||
layout.addWidget(label)
|
||||
layout.addWidget(edit)
|
||||
|
||||
return layout, edit
|
||||
|
||||
def open_file(self):
|
||||
file_path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "打开文件", "", "所有文件 (*.*);;文本文件 (*.txt)")
|
||||
if file_path:
|
||||
self.label_openfile.setText(f"选中文件: {file_path}")
|
||||
self._excel_dir = file_path
|
||||
|
||||
def on_switch_toggled(self, state):
|
||||
enabled = state == 0
|
||||
self._auto_mode = not enabled
|
||||
|
||||
for i in range(1, len(CONSTRAINTS_CONFIG) + 1):
|
||||
self.constraint_widgets[f'min_{i}'].setEnabled(enabled)
|
||||
self.constraint_widgets[f'max_{i}'].setEnabled(enabled)
|
||||
|
||||
@QtCore.Slot()
|
||||
def magic(self):
|
||||
try:
|
||||
self.text_solve.append(f"******** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ********")
|
||||
|
||||
# 读取文件
|
||||
if self._excel_dir is None:
|
||||
self.text_solve.append("请先选择文件!")
|
||||
return
|
||||
|
||||
# 禁用按钮,防止重复点击
|
||||
self.button_solve.setEnabled(False)
|
||||
self.button_solve.setText("计算中...")
|
||||
|
||||
self.text_solve.append("开始排班...")
|
||||
self.text_solve.append("读取文件中...")
|
||||
self.all_data, self.index_to_name_dict, preference_mat, depart_mat, want_num_array, is_new_array = read_excel(self._excel_dir)
|
||||
self.text_solve.append("读取文件成功!")
|
||||
|
||||
# 计算并打印统计信息
|
||||
is_tech_array = [depart_mat[i][0] == 1 or depart_mat[i][1] == 1 for i in range(len(depart_mat))]
|
||||
stu_num = len(self.index_to_name_dict)
|
||||
class_num = len(preference_mat[0])
|
||||
tech_sum = sum(want_num_array[i] for i in range(len(preference_mat))
|
||||
if not is_new_array[i] and is_tech_array[i])
|
||||
all_sum = sum(want_num_array)
|
||||
min_prefer = min(sum(preference_mat[i][j] for i in range(len(preference_mat)))
|
||||
for j in range(class_num))
|
||||
|
||||
self.text_solve.append("信息统计:")
|
||||
self.text_solve.append(f"\t学生总人数:{stu_num}")
|
||||
self.text_solve.append(f"\t班次总数:{class_num}")
|
||||
self.text_solve.append(f"\t电脑部或电器部的所有老人的意愿班次之和:{tech_sum}")
|
||||
self.text_solve.append(f"\t所有人的意愿班次之和:{all_sum}")
|
||||
self.text_solve.append(f"\t平均每班人数:{all_sum/20}")
|
||||
self.text_solve.append(f"\t所有班次中最少拥有意愿数:{min_prefer}")
|
||||
|
||||
def get_weight_value(key):
|
||||
text = self.weight_widgets[key].text()
|
||||
return float(text) if text else 0.0
|
||||
|
||||
def get_constraint_value(key):
|
||||
text = self.constraint_widgets[key].text()
|
||||
return int(text) if text else None
|
||||
|
||||
# 准备参数
|
||||
params = {
|
||||
'num_min': get_constraint_value('min_1'),
|
||||
'num_max': get_constraint_value('max_1'),
|
||||
'num_tech_old_min': get_constraint_value('min_2'),
|
||||
'num_tech_old_max': get_constraint_value('max_2'),
|
||||
'num_old_min': get_constraint_value('min_3'),
|
||||
'num_old_max': get_constraint_value('max_3'),
|
||||
'num_new_min': get_constraint_value('min_4'),
|
||||
'num_new_max': get_constraint_value('max_4'),
|
||||
'weights': [get_weight_value(f'edit_{i}') for i in range(1, len(WEIGHTS_CONFIG) + 1)]
|
||||
}
|
||||
|
||||
# 创建并启动求解线程
|
||||
self.solver_thread = SolverThread(
|
||||
preference_mat, depart_mat, want_num_array, is_new_array,
|
||||
self._auto_mode, params, self
|
||||
)
|
||||
|
||||
# 连接信号
|
||||
self.solver_thread.log_signal.connect(self.on_log_message)
|
||||
self.solver_thread.finished_signal.connect(self.on_solve_finished)
|
||||
self.solver_thread.error_signal.connect(self.on_solve_error)
|
||||
|
||||
# 启动线程
|
||||
self.solver_thread.start()
|
||||
|
||||
except Exception:
|
||||
self.text_solve.append("程序出现严重错误,请联系开发者解决问题!!!")
|
||||
self.text_solve.append(f"Error Details:\n{format_exc()}")
|
||||
self.button_solve.setEnabled(True)
|
||||
self.button_solve.setText("开始排班!")
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def on_log_message(self, message):
|
||||
"""接收线程发送的日志消息并实时显示"""
|
||||
self.text_solve.append(message)
|
||||
|
||||
@QtCore.Slot(object, dict)
|
||||
def on_solve_finished(self, vars, params):
|
||||
"""求解完成后的回调"""
|
||||
try:
|
||||
if vars is None:
|
||||
if self._auto_mode:
|
||||
self.text_solve.append("自动求解失败!请尝试手动调参!")
|
||||
else:
|
||||
self.text_solve.append("在目前限制条件下无解!请尝试更改限制条件!")
|
||||
else:
|
||||
if self._auto_mode:
|
||||
self.text_solve.append("自动计算成功!")
|
||||
self.text_solve.append("参数:")
|
||||
self.text_solve.append(f"\t每班人数:[{params['num_min']}, {params['num_max']}]")
|
||||
self.text_solve.append(f"\t每班电脑或电器的老人数:[{params['num_tech_old_min']}, {params['num_tech_old_max']}]")
|
||||
self.text_solve.append(f"\t每班老人数:[{params['num_old_min']}, {params['num_old_max']}]")
|
||||
self.text_solve.append(f"\t每班小朋友数:[{params['num_new_min']}, inf]")
|
||||
else:
|
||||
self.text_solve.append("计算最优解成功!")
|
||||
|
||||
# 保存结果到 excel
|
||||
self.text_solve.append("保存结果中...")
|
||||
save_dir = f"result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
|
||||
save_to_excel(vars, self.all_data, self.index_to_name_dict, save_dir)
|
||||
self.text_solve.append(f"保存结果成功!保存路径:{save_dir}")
|
||||
|
||||
except Exception:
|
||||
self.text_solve.append("保存结果时出现错误!")
|
||||
self.text_solve.append(f"Error Details:\n{format_exc()}")
|
||||
finally:
|
||||
# 恢复按钮状态
|
||||
self.button_solve.setEnabled(True)
|
||||
self.button_solve.setText("开始排班!")
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def on_solve_error(self, error_msg):
|
||||
"""处理求解过程中的错误"""
|
||||
self.text_solve.append("程序出现严重错误,请联系开发者解决问题!!!")
|
||||
self.text_solve.append(f"Error Details:\n{error_msg}")
|
||||
self.button_solve.setEnabled(True)
|
||||
self.button_solve.setText("开始排班!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QtWidgets.QApplication([])
|
||||
|
||||
widget = MyWidget()
|
||||
widget.setWindowTitle("EVA 值班排班软件")
|
||||
widget.resize(600, 600)
|
||||
widget.show()
|
||||
|
||||
exit(app.exec())
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
[project]
|
||||
name = "eva-duty-arrange-tool"
|
||||
version = "2.0.0"
|
||||
description = "EVA 值班排班工具"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"openpyxl>=3.1.5",
|
||||
"ortools>=9.14.6206",
|
||||
"pandas>=2.3.3",
|
||||
"pyinstaller>=6.16.0",
|
||||
"pyside6>=6.10.0",
|
||||
]
|
||||
[project]
|
||||
name = "eva-duty-arrange-tool"
|
||||
version = "2.0.0"
|
||||
description = "EVA 值班排班工具"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"openpyxl>=3.1.5",
|
||||
"ortools>=9.14.6206",
|
||||
"pandas>=2.3.3",
|
||||
"pyinstaller>=6.16.0",
|
||||
"pyside6>=6.10.0",
|
||||
]
|
||||
|
|
|
|||
418
solve.py
418
solve.py
|
|
@ -1,210 +1,210 @@
|
|||
from ortools.linear_solver import pywraplp
|
||||
|
||||
def solve_program(preference_mat:list, depart_mat:list, want_num_array:list, is_new_array:list,
|
||||
num_min=None, num_max=None,
|
||||
num_tech_old_min=None, num_tech_old_max=None,
|
||||
num_old_min=None, num_old_max=None,
|
||||
num_new_min=None, num_new_max=None,
|
||||
weights=[1.0, 1.0, 1.0, 0.5, 0.5]
|
||||
):
|
||||
|
||||
is_old_array = [not is_new for is_new in is_new_array]
|
||||
is_tech_array = [depart_mat[i][0] == 1 or depart_mat[i][1] == 1 for i in range(len(depart_mat))]
|
||||
is_hr_array = [depart_mat[i][2] == 1 for i in range(len(depart_mat))]
|
||||
|
||||
# 使用 SCIP 求解器求解组合优化问题
|
||||
solver = pywraplp.Solver.CreateSolver("SCIP")
|
||||
if not solver:
|
||||
return
|
||||
|
||||
N = len(preference_mat) # 学生人数
|
||||
M = len(preference_mat[0]) # 班次数
|
||||
avg_num = sum(want_num_array) / M
|
||||
print(f"平均人数:{avg_num}")
|
||||
|
||||
# 各个目标的期望值/归一化系数
|
||||
m = [2.5, 3, 4, 1, 8] # [班次人数偏差, 技术部老人, 技术部小朋友, 人资部小朋友, 部门均衡]
|
||||
|
||||
# 创建决策变量:variables[i][j] 表示第 i 个学生是否选择第 j 个班次
|
||||
variables = [[solver.IntVar(0.0, 1.0, f"choice_{i}_{j}")
|
||||
for j in range(M)] for i in range(N)]
|
||||
|
||||
# 创建辅助变量用于优化目标1(均衡班次人数)
|
||||
aux_vars_x1 = [solver.NumVar(0.0, solver.infinity(), f"aux_x1_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标2(每班次技术部老人数量缺口)
|
||||
aux_vars_x2 = [solver.NumVar(0.0, solver.infinity(), f"aux_x2_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标3(每班次技术部小朋友数量缺口)
|
||||
aux_vars_x3 = [solver.NumVar(0.0, solver.infinity(), f"aux_x3_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标4(每班次人资部小朋友数量缺口)
|
||||
aux_vars_x4 = [solver.NumVar(0.0, solver.infinity(), f"aux_x4_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标5(均衡各部门人数)
|
||||
# 如果提供了部门信息,则创建相应的辅助变量
|
||||
aux_vars_x5 = []
|
||||
num_departments = 5 # 电脑部、电器部、人资部、财外部、文宣部
|
||||
# 为每个班次的每个部门创建辅助变量
|
||||
aux_vars_x5 = [[solver.NumVar(0.0, solver.infinity(), f"aux_x5_{j}_{k}")
|
||||
for k in range(num_departments)] for j in range(M)]
|
||||
|
||||
print("Number of variables =", solver.NumVariables())
|
||||
|
||||
# 约束:每个同学意愿一定要满足
|
||||
for i in range(N):
|
||||
for j in range(M):
|
||||
solver.Add(variables[i][j] <= preference_mat[i][j])
|
||||
|
||||
# 约束:辅助变量 X1 用于计算与平均人数的偏差(绝对值)
|
||||
for j in range(M):
|
||||
actual_num = sum(variables[i][j] for i in range(N))
|
||||
solver.Add(aux_vars_x1[j] >= actual_num - avg_num)
|
||||
solver.Add(aux_vars_x1[j] >= avg_num - actual_num)
|
||||
|
||||
# 约束:辅助变量 X2 用于计算每班次技术部老人数量超出期望值的部分
|
||||
# 辅助变量表示超出期望值(期望每班有m2个技术部老人,超过即计入)
|
||||
# 目标是让尽可能多的班次达到但不超过这个期望值
|
||||
tech_old_target = m[1] # 使用归一化系数作为期望值
|
||||
for j in range(M):
|
||||
tech_old_count = sum(variables[i][j] * is_old_array[i] * is_tech_array[i] for i in range(N))
|
||||
# 辅助变量捕获超出部分和不足部分
|
||||
solver.Add(aux_vars_x2[j] >= tech_old_count - tech_old_target)
|
||||
solver.Add(aux_vars_x2[j] >= tech_old_target - tech_old_count)
|
||||
|
||||
# 约束:辅助变量 X3 用于计算每班次技术部小朋友数量超出期望值的部分
|
||||
tech_new_target = m[2] # 使用归一化系数作为期望值
|
||||
for j in range(M):
|
||||
tech_new_count = sum(variables[i][j] * is_new_array[i] * is_tech_array[i] for i in range(N))
|
||||
solver.Add(aux_vars_x3[j] >= tech_new_count - tech_new_target)
|
||||
solver.Add(aux_vars_x3[j] >= tech_new_target - tech_new_count)
|
||||
|
||||
# 约束:辅助变量 X4 用于计算每班次人资部小朋友数量超出期望值的部分
|
||||
hr_new_target = m[3] # 使用归一化系数作为期望值
|
||||
for j in range(M):
|
||||
hr_new_count = sum(variables[i][j] * is_new_array[i] * is_hr_array[i] for i in range(N))
|
||||
solver.Add(aux_vars_x4[j] >= hr_new_count - hr_new_target)
|
||||
solver.Add(aux_vars_x4[j] >= hr_new_target - hr_new_count)
|
||||
|
||||
# 约束:辅助变量 X5 用于计算各部门人数与平均值的偏差(绝对值)
|
||||
if aux_vars_x5 is not None:
|
||||
for j in range(M):
|
||||
# 计算第 j 班次的总人数
|
||||
shift_total = sum(variables[i][j] for i in range(N))
|
||||
# 计算平均每个部门应有的人数
|
||||
avg_dept = shift_total / num_departments
|
||||
|
||||
# 对每个部门 k
|
||||
for k in range(num_departments):
|
||||
# 计算第 j 班次中第 k 个部门的实际人数
|
||||
dept_count = sum(variables[i][j] * depart_mat[i][k] for i in range(N))
|
||||
# 添加绝对值约束
|
||||
solver.Add(aux_vars_x5[j][k] >= dept_count - avg_dept)
|
||||
solver.Add(aux_vars_x5[j][k] >= avg_dept - dept_count)
|
||||
|
||||
# 约束:满足每位同学的意愿班次数
|
||||
for i in range(N):
|
||||
total_shifts = sum(variables[i])
|
||||
if want_num_array[i] == 3:
|
||||
solver.Add(total_shifts >= 2)
|
||||
solver.Add(total_shifts <= 3)
|
||||
else:
|
||||
solver.Add(total_shifts == want_num_array[i])
|
||||
|
||||
# 添加约束的辅助函数
|
||||
def add_shift_constraint(array, min_val, max_val):
|
||||
for j in range(M):
|
||||
shift_count = sum(variables[i][j] * array[i] for i in range(N))
|
||||
if min_val is not None:
|
||||
solver.Add(shift_count >= min_val)
|
||||
if max_val is not None:
|
||||
solver.Add(shift_count <= max_val)
|
||||
|
||||
# 约束:每个班次的总人数
|
||||
add_shift_constraint([1] * N, num_min, num_max)
|
||||
|
||||
# 约束:每班次电脑或电器的老人数量
|
||||
tech_old_array = [is_old_array[i] * is_tech_array[i] for i in range(N)]
|
||||
add_shift_constraint(tech_old_array, num_tech_old_min, num_tech_old_max)
|
||||
|
||||
# 约束:每班次老人数量
|
||||
add_shift_constraint(is_old_array, num_old_min, num_old_max)
|
||||
|
||||
# 约束:每班次小朋友数量
|
||||
add_shift_constraint(is_new_array, num_new_min, num_new_max)
|
||||
|
||||
# 构建多目标优化函数
|
||||
m1, m2, m3, m4, m5 = m[0], m[1], m[2], m[3], m[4]
|
||||
|
||||
# X1: 每班次人数与平均人数的偏差
|
||||
x1 = sum(aux_vars_x1)
|
||||
obj_x1 = x1 / (m1 * M) # 归一化处理,防止数值过大
|
||||
|
||||
# X2: 每班次技术部老人数量的缺口总和(优化目标是让每班都达到目标值)
|
||||
x2 = sum(aux_vars_x2)
|
||||
obj_x2 = x2 / (m2 * M) # 归一化处理,缺口越小越好
|
||||
|
||||
# X3: 每班次技术部小朋友数量的缺口总和
|
||||
x3 = sum(aux_vars_x3)
|
||||
obj_x3 = x3 / (m3 * M) # 归一化处理,缺口越小越好
|
||||
|
||||
# X4: 每班次人资部小朋友数量的缺口总和
|
||||
x4 = sum(aux_vars_x4)
|
||||
obj_x4 = x4 / (m4 * M) # 归一化处理,缺口越小越好
|
||||
|
||||
# X5: 每班次各部门人数的平均程度
|
||||
obj_x5 = 0
|
||||
if aux_vars_x5:
|
||||
x5 = sum(sum(aux_vars_x5[j]) for j in range(M))
|
||||
obj_x5 = x5 / (m5 * M) # 归一化处理
|
||||
|
||||
# 线性加权组合所有目标
|
||||
total_objective = (
|
||||
weights[0] * obj_x1 + weights[1] * obj_x2 + weights[2] * obj_x3 + weights[3] * obj_x4 + weights[4] * obj_x5
|
||||
)
|
||||
|
||||
print(f"优化目标权重: X1={weights[0]}, X2={weights[1]}, X3={weights[2]}, X4={weights[3]}, X5={weights[4]}")
|
||||
solver.Minimize(total_objective)
|
||||
|
||||
# 求解
|
||||
status = solver.Solve()
|
||||
|
||||
if status == pywraplp.Solver.OPTIMAL:
|
||||
print("Optimal solution found:")
|
||||
variables_return = [[variables[i][j].solution_value() for j in range(M)]
|
||||
for i in range(N)]
|
||||
aux_vars_x1_return = sum([aux_vars_x1[j].solution_value() for j in range(M)]) / M
|
||||
|
||||
print(f"Optimized objective value: {solver.Objective().Value()}")
|
||||
print(f"X1 (每班次人数平均偏差): {aux_vars_x1_return}")
|
||||
|
||||
# 输出各个优化目标的详细信息
|
||||
tech_old_array = [is_old_array[i] * is_tech_array[i] for i in range(N)]
|
||||
tech_new_array = [is_new_array[i] * is_tech_array[i] for i in range(N)]
|
||||
hr_new_array = [is_new_array[i] * is_hr_array[i] for i in range(N)]
|
||||
|
||||
x2_value = sum(sum(variables[i][j].solution_value() * tech_old_array[i] for i in range(N)) for j in range(M)) / M
|
||||
x3_value = sum(sum(variables[i][j].solution_value() * tech_new_array[i] for i in range(N)) for j in range(M)) / M
|
||||
x4_value = sum(sum(variables[i][j].solution_value() * hr_new_array[i] for i in range(N)) for j in range(M)) / M
|
||||
|
||||
aux_vars_x2_return = sum([aux_vars_x2[j].solution_value() for j in range(M)]) / M
|
||||
aux_vars_x3_return = sum([aux_vars_x3[j].solution_value() for j in range(M)]) / M
|
||||
aux_vars_x4_return = sum([aux_vars_x4[j].solution_value() for j in range(M)]) / M
|
||||
|
||||
print(f"X2 (每班平均技术部老人): {x2_value}, 缺口平均: {aux_vars_x2_return}")
|
||||
print(f"X3 (每班平均技术部小朋友): {x3_value}, 缺口平均: {aux_vars_x3_return}")
|
||||
print(f"X4 (每班平均人资部小朋友): {x4_value}, 缺口平均: {aux_vars_x4_return}")
|
||||
|
||||
if aux_vars_x5:
|
||||
x5_value = sum(sum(aux_vars_x5[j][k].solution_value() for k in range(num_departments)) for j in range(M))
|
||||
print(f"X5 (部门人数偏差): {x5_value}")
|
||||
|
||||
return variables_return
|
||||
else:
|
||||
print("No solution found.")
|
||||
return None
|
||||
from ortools.linear_solver import pywraplp
|
||||
|
||||
def solve_program(preference_mat:list, depart_mat:list, want_num_array:list, is_new_array:list,
|
||||
num_min=None, num_max=None,
|
||||
num_tech_old_min=None, num_tech_old_max=None,
|
||||
num_old_min=None, num_old_max=None,
|
||||
num_new_min=None, num_new_max=None,
|
||||
weights=[1.0, 1.0, 1.0, 0.5, 0.5]
|
||||
):
|
||||
|
||||
is_old_array = [not is_new for is_new in is_new_array]
|
||||
is_tech_array = [depart_mat[i][0] == 1 or depart_mat[i][1] == 1 for i in range(len(depart_mat))]
|
||||
is_hr_array = [depart_mat[i][2] == 1 for i in range(len(depart_mat))]
|
||||
|
||||
# 使用 SCIP 求解器求解组合优化问题
|
||||
solver = pywraplp.Solver.CreateSolver("SCIP")
|
||||
if not solver:
|
||||
return
|
||||
|
||||
N = len(preference_mat) # 学生人数
|
||||
M = len(preference_mat[0]) # 班次数
|
||||
avg_num = sum(want_num_array) / M
|
||||
print(f"平均人数:{avg_num}")
|
||||
|
||||
# 各个目标的期望值/归一化系数
|
||||
m = [2.5, 3, 4, 1, 8] # [班次人数偏差, 技术部老人, 技术部小朋友, 人资部小朋友, 部门均衡]
|
||||
|
||||
# 创建决策变量:variables[i][j] 表示第 i 个学生是否选择第 j 个班次
|
||||
variables = [[solver.IntVar(0.0, 1.0, f"choice_{i}_{j}")
|
||||
for j in range(M)] for i in range(N)]
|
||||
|
||||
# 创建辅助变量用于优化目标1(均衡班次人数)
|
||||
aux_vars_x1 = [solver.NumVar(0.0, solver.infinity(), f"aux_x1_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标2(每班次技术部老人数量缺口)
|
||||
aux_vars_x2 = [solver.NumVar(0.0, solver.infinity(), f"aux_x2_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标3(每班次技术部小朋友数量缺口)
|
||||
aux_vars_x3 = [solver.NumVar(0.0, solver.infinity(), f"aux_x3_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标4(每班次人资部小朋友数量缺口)
|
||||
aux_vars_x4 = [solver.NumVar(0.0, solver.infinity(), f"aux_x4_{j}")
|
||||
for j in range(M)]
|
||||
|
||||
# 创建辅助变量用于优化目标5(均衡各部门人数)
|
||||
# 如果提供了部门信息,则创建相应的辅助变量
|
||||
aux_vars_x5 = []
|
||||
num_departments = 5 # 电脑部、电器部、人资部、财外部、文宣部
|
||||
# 为每个班次的每个部门创建辅助变量
|
||||
aux_vars_x5 = [[solver.NumVar(0.0, solver.infinity(), f"aux_x5_{j}_{k}")
|
||||
for k in range(num_departments)] for j in range(M)]
|
||||
|
||||
print("Number of variables =", solver.NumVariables())
|
||||
|
||||
# 约束:每个同学意愿一定要满足
|
||||
for i in range(N):
|
||||
for j in range(M):
|
||||
solver.Add(variables[i][j] <= preference_mat[i][j])
|
||||
|
||||
# 约束:辅助变量 X1 用于计算与平均人数的偏差(绝对值)
|
||||
for j in range(M):
|
||||
actual_num = sum(variables[i][j] for i in range(N))
|
||||
solver.Add(aux_vars_x1[j] >= actual_num - avg_num)
|
||||
solver.Add(aux_vars_x1[j] >= avg_num - actual_num)
|
||||
|
||||
# 约束:辅助变量 X2 用于计算每班次技术部老人数量超出期望值的部分
|
||||
# 辅助变量表示超出期望值(期望每班有m2个技术部老人,超过即计入)
|
||||
# 目标是让尽可能多的班次达到但不超过这个期望值
|
||||
tech_old_target = m[1] # 使用归一化系数作为期望值
|
||||
for j in range(M):
|
||||
tech_old_count = sum(variables[i][j] * is_old_array[i] * is_tech_array[i] for i in range(N))
|
||||
# 辅助变量捕获超出部分和不足部分
|
||||
solver.Add(aux_vars_x2[j] >= tech_old_count - tech_old_target)
|
||||
solver.Add(aux_vars_x2[j] >= tech_old_target - tech_old_count)
|
||||
|
||||
# 约束:辅助变量 X3 用于计算每班次技术部小朋友数量超出期望值的部分
|
||||
tech_new_target = m[2] # 使用归一化系数作为期望值
|
||||
for j in range(M):
|
||||
tech_new_count = sum(variables[i][j] * is_new_array[i] * is_tech_array[i] for i in range(N))
|
||||
solver.Add(aux_vars_x3[j] >= tech_new_count - tech_new_target)
|
||||
solver.Add(aux_vars_x3[j] >= tech_new_target - tech_new_count)
|
||||
|
||||
# 约束:辅助变量 X4 用于计算每班次人资部小朋友数量超出期望值的部分
|
||||
hr_new_target = m[3] # 使用归一化系数作为期望值
|
||||
for j in range(M):
|
||||
hr_new_count = sum(variables[i][j] * is_new_array[i] * is_hr_array[i] for i in range(N))
|
||||
solver.Add(aux_vars_x4[j] >= hr_new_count - hr_new_target)
|
||||
solver.Add(aux_vars_x4[j] >= hr_new_target - hr_new_count)
|
||||
|
||||
# 约束:辅助变量 X5 用于计算各部门人数与平均值的偏差(绝对值)
|
||||
if aux_vars_x5 is not None:
|
||||
for j in range(M):
|
||||
# 计算第 j 班次的总人数
|
||||
shift_total = sum(variables[i][j] for i in range(N))
|
||||
# 计算平均每个部门应有的人数
|
||||
avg_dept = shift_total / num_departments
|
||||
|
||||
# 对每个部门 k
|
||||
for k in range(num_departments):
|
||||
# 计算第 j 班次中第 k 个部门的实际人数
|
||||
dept_count = sum(variables[i][j] * depart_mat[i][k] for i in range(N))
|
||||
# 添加绝对值约束
|
||||
solver.Add(aux_vars_x5[j][k] >= dept_count - avg_dept)
|
||||
solver.Add(aux_vars_x5[j][k] >= avg_dept - dept_count)
|
||||
|
||||
# 约束:满足每位同学的意愿班次数
|
||||
for i in range(N):
|
||||
total_shifts = sum(variables[i])
|
||||
if want_num_array[i] == 3:
|
||||
solver.Add(total_shifts >= 2)
|
||||
solver.Add(total_shifts <= 3)
|
||||
else:
|
||||
solver.Add(total_shifts == want_num_array[i])
|
||||
|
||||
# 添加约束的辅助函数
|
||||
def add_shift_constraint(array, min_val, max_val):
|
||||
for j in range(M):
|
||||
shift_count = sum(variables[i][j] * array[i] for i in range(N))
|
||||
if min_val is not None:
|
||||
solver.Add(shift_count >= min_val)
|
||||
if max_val is not None:
|
||||
solver.Add(shift_count <= max_val)
|
||||
|
||||
# 约束:每个班次的总人数
|
||||
add_shift_constraint([1] * N, num_min, num_max)
|
||||
|
||||
# 约束:每班次电脑或电器的老人数量
|
||||
tech_old_array = [is_old_array[i] * is_tech_array[i] for i in range(N)]
|
||||
add_shift_constraint(tech_old_array, num_tech_old_min, num_tech_old_max)
|
||||
|
||||
# 约束:每班次老人数量
|
||||
add_shift_constraint(is_old_array, num_old_min, num_old_max)
|
||||
|
||||
# 约束:每班次小朋友数量
|
||||
add_shift_constraint(is_new_array, num_new_min, num_new_max)
|
||||
|
||||
# 构建多目标优化函数
|
||||
m1, m2, m3, m4, m5 = m[0], m[1], m[2], m[3], m[4]
|
||||
|
||||
# X1: 每班次人数与平均人数的偏差
|
||||
x1 = sum(aux_vars_x1)
|
||||
obj_x1 = x1 / (m1 * M) # 归一化处理,防止数值过大
|
||||
|
||||
# X2: 每班次技术部老人数量的缺口总和(优化目标是让每班都达到目标值)
|
||||
x2 = sum(aux_vars_x2)
|
||||
obj_x2 = x2 / (m2 * M) # 归一化处理,缺口越小越好
|
||||
|
||||
# X3: 每班次技术部小朋友数量的缺口总和
|
||||
x3 = sum(aux_vars_x3)
|
||||
obj_x3 = x3 / (m3 * M) # 归一化处理,缺口越小越好
|
||||
|
||||
# X4: 每班次人资部小朋友数量的缺口总和
|
||||
x4 = sum(aux_vars_x4)
|
||||
obj_x4 = x4 / (m4 * M) # 归一化处理,缺口越小越好
|
||||
|
||||
# X5: 每班次各部门人数的平均程度
|
||||
obj_x5 = 0
|
||||
if aux_vars_x5:
|
||||
x5 = sum(sum(aux_vars_x5[j]) for j in range(M))
|
||||
obj_x5 = x5 / (m5 * M) # 归一化处理
|
||||
|
||||
# 线性加权组合所有目标
|
||||
total_objective = (
|
||||
weights[0] * obj_x1 + weights[1] * obj_x2 + weights[2] * obj_x3 + weights[3] * obj_x4 + weights[4] * obj_x5
|
||||
)
|
||||
|
||||
print(f"优化目标权重: X1={weights[0]}, X2={weights[1]}, X3={weights[2]}, X4={weights[3]}, X5={weights[4]}")
|
||||
solver.Minimize(total_objective)
|
||||
|
||||
# 求解
|
||||
status = solver.Solve()
|
||||
|
||||
if status == pywraplp.Solver.OPTIMAL:
|
||||
print("Optimal solution found:")
|
||||
variables_return = [[variables[i][j].solution_value() for j in range(M)]
|
||||
for i in range(N)]
|
||||
aux_vars_x1_return = sum([aux_vars_x1[j].solution_value() for j in range(M)]) / M
|
||||
|
||||
print(f"Optimized objective value: {solver.Objective().Value()}")
|
||||
print(f"X1 (每班次人数平均偏差): {aux_vars_x1_return}")
|
||||
|
||||
# 输出各个优化目标的详细信息
|
||||
tech_old_array = [is_old_array[i] * is_tech_array[i] for i in range(N)]
|
||||
tech_new_array = [is_new_array[i] * is_tech_array[i] for i in range(N)]
|
||||
hr_new_array = [is_new_array[i] * is_hr_array[i] for i in range(N)]
|
||||
|
||||
x2_value = sum(sum(variables[i][j].solution_value() * tech_old_array[i] for i in range(N)) for j in range(M)) / M
|
||||
x3_value = sum(sum(variables[i][j].solution_value() * tech_new_array[i] for i in range(N)) for j in range(M)) / M
|
||||
x4_value = sum(sum(variables[i][j].solution_value() * hr_new_array[i] for i in range(N)) for j in range(M)) / M
|
||||
|
||||
aux_vars_x2_return = sum([aux_vars_x2[j].solution_value() for j in range(M)]) / M
|
||||
aux_vars_x3_return = sum([aux_vars_x3[j].solution_value() for j in range(M)]) / M
|
||||
aux_vars_x4_return = sum([aux_vars_x4[j].solution_value() for j in range(M)]) / M
|
||||
|
||||
print(f"X2 (每班平均技术部老人): {x2_value}, 缺口平均: {aux_vars_x2_return}")
|
||||
print(f"X3 (每班平均技术部小朋友): {x3_value}, 缺口平均: {aux_vars_x3_return}")
|
||||
print(f"X4 (每班平均人资部小朋友): {x4_value}, 缺口平均: {aux_vars_x4_return}")
|
||||
|
||||
if aux_vars_x5:
|
||||
x5_value = sum(sum(aux_vars_x5[j][k].solution_value() for k in range(num_departments)) for j in range(M))
|
||||
print(f"X5 (部门人数偏差): {x5_value}")
|
||||
|
||||
return variables_return
|
||||
else:
|
||||
print("No solution found.")
|
||||
return None
|
||||
|
||||
284
utils.py
284
utils.py
|
|
@ -1,143 +1,143 @@
|
|||
import pandas as pd
|
||||
from datetime import datetime
|
||||
from random import choice
|
||||
|
||||
# 对于表格每一列:
|
||||
col_timestamp = 1 # i = 1 -> 时间戳
|
||||
col_name = 6 # i = 6 -> 姓名
|
||||
col_department = 7 # i = 7 -> 部门编号
|
||||
col_member = 8 # i = 8 -> 老人 / 小朋友
|
||||
col_dutystart = 9 # i = 9 -> 值班开始时间
|
||||
col_dutyend = 28 # i = 28 -> 值班结束时间
|
||||
col_dutyfreq = 29 # i = 29 -> 想要值班的次数
|
||||
|
||||
index_to_departments = { # 部门编号和部门名称的对应关系
|
||||
1: "电脑部",
|
||||
2: "电器部",
|
||||
3: "人资部",
|
||||
4: "财外部",
|
||||
5: "文宣部"
|
||||
}
|
||||
|
||||
index_to_type = { # 老人 / 小朋友和对应的编号
|
||||
1: "老人",
|
||||
2: "小朋友"
|
||||
}
|
||||
|
||||
def read_excel(file_path):
|
||||
df = pd.read_excel(file_path)
|
||||
|
||||
# 待返回的所有信息。N 为学生人数,M 为班次数
|
||||
index_to_name_dict = {} # 长度为 N 的字典,包含数组下标和学生姓名的对应关系
|
||||
preference_mat = [] # N x M 的二维数组,表示每位学生对每个班次的满意度
|
||||
depart_mat = [] # N x D 的二维数组,表示每位学生所属的部门(D 为部门数量)
|
||||
want_num_array = [] # 长度为 N 的数组,表示每位学生想要值班的次数
|
||||
is_new_array = [] # 长度为 N 的数组,表示每位学生是否是小朋友
|
||||
|
||||
'''
|
||||
考虑到原始填表信息中可能有某位同学多次提交的记录,先过滤一下冗余信息
|
||||
'''
|
||||
all_data = {} # 储存过滤后的数据
|
||||
time_format = "%Y/%m/%d %H:%M:%S"
|
||||
for index, row in df.iterrows():
|
||||
name = row.iloc[col_name]
|
||||
time_this = datetime.strptime(row.iloc[col_timestamp], time_format)
|
||||
if name not in all_data or time_this > datetime.strptime(all_data[name][col_timestamp], time_format):
|
||||
all_data[name] = row.tolist()
|
||||
|
||||
for index, (name, info_list) in enumerate(all_data.items()):
|
||||
index_to_name_dict[index] = name
|
||||
preference_mat.append(info_list[col_dutystart:col_dutyend + 1])
|
||||
depart_mat.append([1 if info_list[col_department] == i else 0 for i in range(1, 6)])
|
||||
want_num_array.append(info_list[col_dutyfreq])
|
||||
is_new_array.append(index_to_type[info_list[col_member]] == "小朋友")
|
||||
|
||||
return all_data, index_to_name_dict, preference_mat, depart_mat, want_num_array, is_new_array
|
||||
|
||||
def save_to_excel(variables, all_data, index_to_name_dict, file_path):
|
||||
|
||||
# 收集每个班次的值班人员信息
|
||||
all_result = []
|
||||
max_single_class_num = 0
|
||||
|
||||
for j in range(len(variables[0])):
|
||||
on_duty_list = []
|
||||
hr_new_index = []
|
||||
none_tech_new_index = []
|
||||
new_index = []
|
||||
all_index = []
|
||||
|
||||
for i in range(len(variables)):
|
||||
if variables[i][j] == 1:
|
||||
name = index_to_name_dict[i]
|
||||
department = index_to_departments[all_data[name][col_department]]
|
||||
member_type = index_to_type[all_data[name][col_member]]
|
||||
|
||||
single_stu_info = {
|
||||
"name": name,
|
||||
"department": department,
|
||||
"type": member_type,
|
||||
"duty_monitor": False
|
||||
}
|
||||
on_duty_list.append(single_stu_info)
|
||||
|
||||
idx = len(all_index)
|
||||
all_index.append(idx)
|
||||
if member_type == "小朋友":
|
||||
new_index.append(idx)
|
||||
if department in ["人资部", "财外部", "文宣部"]:
|
||||
none_tech_new_index.append(idx)
|
||||
if department == "人资部":
|
||||
hr_new_index.append(idx)
|
||||
|
||||
# 选择值班组长(优先级:人资部小朋友 > 非技术部小朋友 > 小朋友 > 所有人)
|
||||
if hr_new_index:
|
||||
duty_monitor_index = choice(hr_new_index)
|
||||
elif none_tech_new_index:
|
||||
duty_monitor_index = choice(none_tech_new_index)
|
||||
elif new_index:
|
||||
duty_monitor_index = choice(new_index)
|
||||
else:
|
||||
duty_monitor_index = choice(all_index)
|
||||
on_duty_list[duty_monitor_index]["duty_monitor"] = True
|
||||
|
||||
on_duty_list.sort(key=lambda x: x["department"])
|
||||
all_result.append(on_duty_list)
|
||||
max_single_class_num = max(max_single_class_num, len(on_duty_list))
|
||||
|
||||
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import PatternFill
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active if wb.active else wb.create_sheet(title="Sheet1")
|
||||
|
||||
# 设置表头
|
||||
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
|
||||
for idx, day in enumerate(weekdays, start=2):
|
||||
col = chr(ord('A') + idx - 1)
|
||||
ws[f'{col}1'] = day
|
||||
ws.column_dimensions[col].width = 25
|
||||
|
||||
# 设置班次标题和起始行
|
||||
shift_names = ["第一班", "第二班", "第三班"]
|
||||
start_index = []
|
||||
for shift_idx, shift_name in enumerate(shift_names):
|
||||
start_row = 2 + shift_idx * (max_single_class_num + 1)
|
||||
end_row = start_row + max_single_class_num
|
||||
ws.merge_cells(f'A{start_row}:A{end_row}')
|
||||
ws[f'A{start_row}'] = shift_name
|
||||
start_index.append(start_row)
|
||||
|
||||
# 填写值班人员信息
|
||||
yellow_fill = PatternFill(fill_type='solid', start_color='FFFF00', end_color='FFFF00')
|
||||
for duty_index, duty in enumerate(all_result):
|
||||
col = chr(ord('B') + duty_index // 3)
|
||||
for stu_index, stu in enumerate(duty):
|
||||
row = start_index[duty_index % 3] + stu_index
|
||||
cell = ws[f'{col}{row}']
|
||||
cell.value = f"{stu['name']} {stu['department']} {stu['type']}"
|
||||
if stu['duty_monitor']:
|
||||
cell.fill = yellow_fill
|
||||
|
||||
import pandas as pd
|
||||
from datetime import datetime
|
||||
from random import choice
|
||||
|
||||
# 对于表格每一列:
|
||||
col_timestamp = 1 # i = 1 -> 时间戳
|
||||
col_name = 6 # i = 6 -> 姓名
|
||||
col_department = 7 # i = 7 -> 部门编号
|
||||
col_member = 8 # i = 8 -> 老人 / 小朋友
|
||||
col_dutystart = 9 # i = 9 -> 值班开始时间
|
||||
col_dutyend = 28 # i = 28 -> 值班结束时间
|
||||
col_dutyfreq = 29 # i = 29 -> 想要值班的次数
|
||||
|
||||
index_to_departments = { # 部门编号和部门名称的对应关系
|
||||
1: "电脑部",
|
||||
2: "电器部",
|
||||
3: "人资部",
|
||||
4: "财外部",
|
||||
5: "文宣部"
|
||||
}
|
||||
|
||||
index_to_type = { # 老人 / 小朋友和对应的编号
|
||||
1: "老人",
|
||||
2: "小朋友"
|
||||
}
|
||||
|
||||
def read_excel(file_path):
|
||||
df = pd.read_excel(file_path)
|
||||
|
||||
# 待返回的所有信息。N 为学生人数,M 为班次数
|
||||
index_to_name_dict = {} # 长度为 N 的字典,包含数组下标和学生姓名的对应关系
|
||||
preference_mat = [] # N x M 的二维数组,表示每位学生对每个班次的满意度
|
||||
depart_mat = [] # N x D 的二维数组,表示每位学生所属的部门(D 为部门数量)
|
||||
want_num_array = [] # 长度为 N 的数组,表示每位学生想要值班的次数
|
||||
is_new_array = [] # 长度为 N 的数组,表示每位学生是否是小朋友
|
||||
|
||||
'''
|
||||
考虑到原始填表信息中可能有某位同学多次提交的记录,先过滤一下冗余信息
|
||||
'''
|
||||
all_data = {} # 储存过滤后的数据
|
||||
time_format = "%Y/%m/%d %H:%M:%S"
|
||||
for index, row in df.iterrows():
|
||||
name = row.iloc[col_name]
|
||||
time_this = datetime.strptime(row.iloc[col_timestamp], time_format)
|
||||
if name not in all_data or time_this > datetime.strptime(all_data[name][col_timestamp], time_format):
|
||||
all_data[name] = row.tolist()
|
||||
|
||||
for index, (name, info_list) in enumerate(all_data.items()):
|
||||
index_to_name_dict[index] = name
|
||||
preference_mat.append(info_list[col_dutystart:col_dutyend + 1])
|
||||
depart_mat.append([1 if info_list[col_department] == i else 0 for i in range(1, 6)])
|
||||
want_num_array.append(info_list[col_dutyfreq])
|
||||
is_new_array.append(index_to_type[info_list[col_member]] == "小朋友")
|
||||
|
||||
return all_data, index_to_name_dict, preference_mat, depart_mat, want_num_array, is_new_array
|
||||
|
||||
def save_to_excel(variables, all_data, index_to_name_dict, file_path):
|
||||
|
||||
# 收集每个班次的值班人员信息
|
||||
all_result = []
|
||||
max_single_class_num = 0
|
||||
|
||||
for j in range(len(variables[0])):
|
||||
on_duty_list = []
|
||||
hr_new_index = []
|
||||
none_tech_new_index = []
|
||||
new_index = []
|
||||
all_index = []
|
||||
|
||||
for i in range(len(variables)):
|
||||
if variables[i][j] == 1:
|
||||
name = index_to_name_dict[i]
|
||||
department = index_to_departments[all_data[name][col_department]]
|
||||
member_type = index_to_type[all_data[name][col_member]]
|
||||
|
||||
single_stu_info = {
|
||||
"name": name,
|
||||
"department": department,
|
||||
"type": member_type,
|
||||
"duty_monitor": False
|
||||
}
|
||||
on_duty_list.append(single_stu_info)
|
||||
|
||||
idx = len(all_index)
|
||||
all_index.append(idx)
|
||||
if member_type == "小朋友":
|
||||
new_index.append(idx)
|
||||
if department in ["人资部", "财外部", "文宣部"]:
|
||||
none_tech_new_index.append(idx)
|
||||
if department == "人资部":
|
||||
hr_new_index.append(idx)
|
||||
|
||||
# 选择值班组长(优先级:人资部小朋友 > 非技术部小朋友 > 小朋友 > 所有人)
|
||||
if hr_new_index:
|
||||
duty_monitor_index = choice(hr_new_index)
|
||||
elif none_tech_new_index:
|
||||
duty_monitor_index = choice(none_tech_new_index)
|
||||
elif new_index:
|
||||
duty_monitor_index = choice(new_index)
|
||||
else:
|
||||
duty_monitor_index = choice(all_index)
|
||||
on_duty_list[duty_monitor_index]["duty_monitor"] = True
|
||||
|
||||
on_duty_list.sort(key=lambda x: x["department"])
|
||||
all_result.append(on_duty_list)
|
||||
max_single_class_num = max(max_single_class_num, len(on_duty_list))
|
||||
|
||||
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import PatternFill
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active if wb.active else wb.create_sheet(title="Sheet1")
|
||||
|
||||
# 设置表头
|
||||
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
|
||||
for idx, day in enumerate(weekdays, start=2):
|
||||
col = chr(ord('A') + idx - 1)
|
||||
ws[f'{col}1'] = day
|
||||
ws.column_dimensions[col].width = 25
|
||||
|
||||
# 设置班次标题和起始行
|
||||
shift_names = ["第一班", "第二班", "第三班"]
|
||||
start_index = []
|
||||
for shift_idx, shift_name in enumerate(shift_names):
|
||||
start_row = 2 + shift_idx * (max_single_class_num + 1)
|
||||
end_row = start_row + max_single_class_num
|
||||
ws.merge_cells(f'A{start_row}:A{end_row}')
|
||||
ws[f'A{start_row}'] = shift_name
|
||||
start_index.append(start_row)
|
||||
|
||||
# 填写值班人员信息
|
||||
yellow_fill = PatternFill(fill_type='solid', start_color='FFFF00', end_color='FFFF00')
|
||||
for duty_index, duty in enumerate(all_result):
|
||||
col = chr(ord('B') + duty_index // 3)
|
||||
for stu_index, stu in enumerate(duty):
|
||||
row = start_index[duty_index % 3] + stu_index
|
||||
cell = ws[f'{col}{row}']
|
||||
cell.value = f"{stu['name']} {stu['department']} {stu['type']}"
|
||||
if stu['duty_monitor']:
|
||||
cell.fill = yellow_fill
|
||||
|
||||
wb.save(file_path)
|
||||
852
uv.lock
852
uv.lock
|
|
@ -1,426 +1,426 @@
|
|||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "absl-py"
|
||||
version = "2.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "altgraph"
|
||||
version = "0.17.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/de/a8/7145824cf0b9e3c28046520480f207df47e927df83aa9555fb47f8505922/altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406", size = 48418, upload-time = "2023-09-25T09:04:52.164Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/3f/3bc3f1d83f6e4a7fcb834d3720544ca597590425be5ba9db032b2bf322a2/altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff", size = 21212, upload-time = "2023-09-25T09:04:50.691Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "et-xmlfile"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eva-duty-arrange-tool"
|
||||
version = "2.0.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "openpyxl" },
|
||||
{ name = "ortools" },
|
||||
{ name = "pandas" },
|
||||
{ name = "pyinstaller" },
|
||||
{ name = "pyside6" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "openpyxl", specifier = ">=3.1.5" },
|
||||
{ name = "ortools", specifier = ">=9.14.6206" },
|
||||
{ name = "pandas", specifier = ">=2.3.3" },
|
||||
{ name = "pyinstaller", specifier = ">=6.16.0" },
|
||||
{ name = "pyside6", specifier = ">=6.10.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "immutabledict"
|
||||
version = "4.2.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ce/12/1da8e1a9050d0603ba65fb1796ed8860a705b906701c96e77f85cc7490be/immutabledict-4.2.2.tar.gz", hash = "sha256:cb6ed3090df593148f94cb407d218ca526fd2639694afdb553dc4f50ce6feeca", size = 6099, upload-time = "2025-10-12T13:32:59.755Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/63/7b/04ab6afa1ff7eb9ccb09049918c0407b205f5009092c0416147d163e4e2b/immutabledict-4.2.2-py3-none-any.whl", hash = "sha256:97c31d098a2c850e93a958badeef765e4736ed7942ec73e439facd764a3a7217", size = 4736, upload-time = "2025-10-12T13:32:58.326Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macholib"
|
||||
version = "1.16.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "altgraph" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/ee/af1a3842bdd5902ce133bd246eb7ffd4375c38642aeb5dc0ae3a0329dfa2/macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30", size = 59309, upload-time = "2023-09-25T09:10:16.155Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/5d/c059c180c84f7962db0aeae7c3b9303ed1d73d76f2bfbc32bc231c8be314/macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c", size = 38094, upload-time = "2023-09-25T09:10:14.188Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/b9/984c2b1ee61a8b803bf63582b4ac4242cf76e2dbd663efeafcb620cc0ccb/numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf", size = 20949588, upload-time = "2025-09-09T15:56:59.087Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/e4/07970e3bed0b1384d22af1e9912527ecbeb47d3b26e9b6a3bced068b3bea/numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7", size = 14177802, upload-time = "2025-09-09T15:57:01.73Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/c7/477a83887f9de61f1203bad89cf208b7c19cc9fef0cebef65d5a1a0619f2/numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6", size = 5106537, upload-time = "2025-09-09T15:57:03.765Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/47/93b953bd5866a6f6986344d045a207d3f1cfbad99db29f534ea9cee5108c/numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7", size = 6640743, upload-time = "2025-09-09T15:57:07.921Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/83/377f84aaeb800b64c0ef4de58b08769e782edcefa4fea712910b6f0afd3c/numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c", size = 14278881, upload-time = "2025-09-09T15:57:11.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/a5/bf3db6e66c4b160d6ea10b534c381a1955dfab34cb1017ea93aa33c70ed3/numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93", size = 16636301, upload-time = "2025-09-09T15:57:14.245Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/59/1287924242eb4fa3f9b3a2c30400f2e17eb2707020d1c5e3086fe7330717/numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae", size = 16053645, upload-time = "2025-09-09T15:57:16.534Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/93/b3d47ed882027c35e94ac2320c37e452a549f582a5e801f2d34b56973c97/numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86", size = 18578179, upload-time = "2025-09-09T15:57:18.883Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/d9/487a2bccbf7cc9d4bfc5f0f197761a5ef27ba870f1e3bbb9afc4bbe3fcc2/numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8", size = 6312250, upload-time = "2025-09-09T15:57:21.296Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/b5/263ebbbbcede85028f30047eab3d58028d7ebe389d6493fc95ae66c636ab/numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf", size = 12783269, upload-time = "2025-09-09T15:57:23.034Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/75/67b8ca554bbeaaeb3fac2e8bce46967a5a06544c9108ec0cf5cece559b6c/numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5", size = 10195314, upload-time = "2025-09-09T15:57:25.045Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/d0/0d1ddec56b162042ddfafeeb293bac672de9b0cfd688383590090963720a/numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc", size = 21048025, upload-time = "2025-09-09T15:57:27.257Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/9e/1996ca6b6d00415b6acbdd3c42f7f03ea256e2c3f158f80bd7436a8a19f3/numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc", size = 14301053, upload-time = "2025-09-09T15:57:30.077Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/24/43da09aa764c68694b76e84b3d3f0c44cb7c18cdc1ba80e48b0ac1d2cd39/numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b", size = 5229444, upload-time = "2025-09-09T15:57:32.733Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/14/50ffb0f22f7218ef8af28dd089f79f68289a7a05a208db9a2c5dcbe123c1/numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19", size = 6738039, upload-time = "2025-09-09T15:57:34.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/52/af46ac0795e09657d45a7f4db961917314377edecf66db0e39fa7ab5c3d3/numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30", size = 14352314, upload-time = "2025-09-09T15:57:36.255Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/b1/dc226b4c90eb9f07a3fff95c2f0db3268e2e54e5cce97c4ac91518aee71b/numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e", size = 16701722, upload-time = "2025-09-09T15:57:38.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/9d/9d8d358f2eb5eced14dba99f110d83b5cd9a4460895230f3b396ad19a323/numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3", size = 16132755, upload-time = "2025-09-09T15:57:41.16Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/27/b3922660c45513f9377b3fb42240bec63f203c71416093476ec9aa0719dc/numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea", size = 18651560, upload-time = "2025-09-09T15:57:43.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openpyxl"
|
||||
version = "3.1.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "et-xmlfile" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ortools"
|
||||
version = "9.14.6206"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "absl-py" },
|
||||
{ name = "immutabledict" },
|
||||
{ name = "numpy" },
|
||||
{ name = "pandas" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/72/2e/b0d7e7ee9d1a45001a05ca2f65ccc1ab28cee510e725e01e248496510ac1/ortools-9.14.6206-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:e38c8c4a184820cbfdb812a8d484f6506cf16993ce2a95c88bc1c9d23b17c63e", size = 22239884, upload-time = "2025-06-19T15:45:51.774Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/ad/964ee5341767dd9e2f13e76f0a36d45aa8d81ad776c80bdd6dedc8f2f462/ortools-9.14.6206-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db685073cbed9f8bfaa744f5e883f3dea57c93179b0abe1788276fd3b074fa61", size = 20211128, upload-time = "2025-06-19T15:45:54.829Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/93/d94a66cdfadeb2747d96f1c8d3f590d81c4ad47fd357dfc57de8d7a75bbe/ortools-9.14.6206-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4bfb8bffb29991834cf4bde7048ca8ee8caed73e8dd21e5ec7de99a33bbfea0", size = 25663650, upload-time = "2025-06-19T15:47:20.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/74/1d374bf510e9fb36bba82ecd3e09461cd8394afef3e418fa5b060f129401/ortools-9.14.6206-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eb464a698837e7f90ca5f9b3d748b6ddf553198a70032bc77824d1cd88695d2b", size = 27670004, upload-time = "2025-06-19T15:47:23.111Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/e3/5943467ae41efa06cff12b79bfd146c4a54903345f0cc5c896884829d14a/ortools-9.14.6206-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8f33deaeb7c3dda8ca1d29c5b9aa9c3a4f2ca9ecf34f12a1f809bb2995f41274", size = 27653302, upload-time = "2025-06-19T15:53:47.615Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/28/a896080fe6e13b4bdae74601f19c28b7ba05ec45f3adca3e992d6174ac57/ortools-9.14.6206-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:086e7c2dc4f23efffb20a5e20f618c7d6adb99b2d94f684cab482387da3bc434", size = 29503497, upload-time = "2025-06-19T15:53:51.174Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/ad/8d02013116cc5d51084fe24c5b73f5b349dd10925d2927d19d21a2068a4c/ortools-9.14.6206-cp312-cp312-win_amd64.whl", hash = "sha256:17c13b0bfde17ac57789ad35243edf1318ecd5db23cf949b75ab62480599f188", size = 20512174, upload-time = "2025-06-19T15:46:33.339Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/9c/fe6d5ca549c2fb5ed3e8e1d928a11f4509c024c974e1f6e2d75d206bc226/ortools-9.14.6206-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:8d0df7eef8ba53ad235e29018389259bad2e667d9594b9c2a412ed6a5756bd4e", size = 22259719, upload-time = "2025-06-19T15:45:57.504Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/0f/0b9858e7d5b31dfb23a1fe945d3e9fd5d2feba893190e53f70374ac7e084/ortools-9.14.6206-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:57dfe10844ce8331634d4723040fe249263fd490407346efc314c0bc656849b5", size = 20231092, upload-time = "2025-06-19T15:46:00.003Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/48/de4eff68cb4ea124c9d6edf68049d329a332aab36d011c2798ea1afb4c98/ortools-9.14.6206-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c0c2c00a6e5d5c462e76fdda7dbd40d0f9139f1df4211d34b36906696248020", size = 25662903, upload-time = "2025-06-19T15:47:26.368Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/44/970f72cd5e537fc10e20582dadbdd2f8b2b3c802ac812105c40119572ea7/ortools-9.14.6206-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:38044cf39952d93cbcc02f6acdbe0a9bd3628fbf17f0d7eb0374060fa028c22e", size = 27669250, upload-time = "2025-06-19T15:47:29.738Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/31/37e2eacc37e4448090f693d482316a67bf2b47f2aefae6d6236b4ed41924/ortools-9.14.6206-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:98564de773d709e1e49cb3c32f6917589c314f047786d88bd5f324c0eb7be96e", size = 27652453, upload-time = "2025-06-19T15:53:54.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/8f/0b1bb2a3268114b95381d5a1146c293259d6e45c69e4e3f2d2cf52617796/ortools-9.14.6206-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:80528b0ac72dc3de00cbeef2ce028517a476450b5877b1cda1b8ecb9fa98505e", size = 29503368, upload-time = "2025-06-19T15:53:57.989Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/ad/93c05084eec710c38bc952a19002aac31d4c26bb6f8fcbf1057ccc55254b/ortools-9.14.6206-cp313-cp313-win_amd64.whl", hash = "sha256:47b1b15dcb085d32c61621b790259193aefa9e4577abadf233d47fbe7d0b81ef", size = 20530387, upload-time = "2025-06-19T15:46:35.964Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/85/aeba0d90a3cee4a23ba74a4f2d4c27088923c8b77fa1b73a52ad34593be5/ortools-9.14.6206-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d26a0f9ed97ef9d3384a9069923585f5f974c3fde555a41f4d6381fbe7840bc4", size = 25704462, upload-time = "2025-06-19T15:47:33.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/83/2954b6aa032b77f49a478e0d9682ae8176abfb4bd33d935f0260ecb1741b/ortools-9.14.6206-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d40d8141667d47405f296a9f687058c566d7816586e9a672b59e9fcec8493133", size = 27687594, upload-time = "2025-06-19T15:47:36.241Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/9a/9e9866952841e9f4aadccb110c0012d6a76f01b8798432fac0971d60aac1/ortools-9.14.6206-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:aefea81ed81aa937873efc520381785ed65380e52917f492ab566f46bbb5660d", size = 27698487, upload-time = "2025-06-19T15:54:01.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/a5/97a86cdd52c961273981e9ab905a301b7f086593b597d8974c411decf61a/ortools-9.14.6206-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f044bb277db3ab6a1b958728fe1cf14ca87c3800d67d7b321d876b48269340f6", size = 29519050, upload-time = "2025-06-19T15:54:04.147Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pandas"
|
||||
version = "2.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "numpy" },
|
||||
{ name = "python-dateutil" },
|
||||
{ name = "pytz" },
|
||||
{ name = "tzdata" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pefile"
|
||||
version = "2023.2.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/78/c5/3b3c62223f72e2360737fd2a57c30e5b2adecd85e70276879609a7403334/pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc", size = 74854, upload-time = "2023-02-07T12:23:55.958Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/55/26/d0ad8b448476d0a1e8d3ea5622dc77b916db84c6aa3cb1e1c0965af948fc/pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6", size = 71791, upload-time = "2023-02-07T12:28:36.678Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "6.31.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/52/f3/b9655a711b32c19720253f6f06326faf90580834e2e83f840472d752bc8b/protobuf-6.31.1.tar.gz", hash = "sha256:d8cac4c982f0b957a4dc73a80e2ea24fab08e679c0de9deb835f4a12d69aca9a", size = 441797, upload-time = "2025-05-28T19:25:54.947Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/6f/6ab8e4bf962fd5570d3deaa2d5c38f0a363f57b4501047b5ebeb83ab1125/protobuf-6.31.1-cp310-abi3-win32.whl", hash = "sha256:7fa17d5a29c2e04b7d90e5e32388b8bfd0e7107cd8e616feef7ed3fa6bdab5c9", size = 423603, upload-time = "2025-05-28T19:25:41.198Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/3a/b15c4347dd4bf3a1b0ee882f384623e2063bb5cf9fa9d57990a4f7df2fb6/protobuf-6.31.1-cp310-abi3-win_amd64.whl", hash = "sha256:426f59d2964864a1a366254fa703b8632dcec0790d8862d30034d8245e1cd447", size = 435283, upload-time = "2025-05-28T19:25:44.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/c9/b9689a2a250264a84e66c46d8862ba788ee7a641cdca39bccf64f59284b7/protobuf-6.31.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:6f1227473dc43d44ed644425268eb7c2e488ae245d51c6866d19fe158e207402", size = 425604, upload-time = "2025-05-28T19:25:45.702Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/a1/7a5a94032c83375e4fe7e7f56e3976ea6ac90c5e85fac8576409e25c39c3/protobuf-6.31.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:a40fc12b84c154884d7d4c4ebd675d5b3b5283e155f324049ae396b95ddebc39", size = 322115, upload-time = "2025-05-28T19:25:47.128Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/b1/b59d405d64d31999244643d88c45c8241c58f17cc887e73bcb90602327f8/protobuf-6.31.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4ee898bf66f7a8b0bd21bce523814e6fbd8c6add948045ce958b73af7e8878c6", size = 321070, upload-time = "2025-05-28T19:25:50.036Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/af/ab3c51ab7507a7325e98ffe691d9495ee3d3aa5f589afad65ec920d39821/protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e", size = 168724, upload-time = "2025-05-28T19:25:53.926Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller"
|
||||
version = "6.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "altgraph" },
|
||||
{ name = "macholib", marker = "sys_platform == 'darwin'" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pefile", marker = "sys_platform == 'win32'" },
|
||||
{ name = "pyinstaller-hooks-contrib" },
|
||||
{ name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/94/1f62e95e4a28b64cfbb5b922ef3046f968b47170d37a1e1a029f56ac9cb4/pyinstaller-6.16.0.tar.gz", hash = "sha256:53559fe1e041a234f2b4dcc3288ea8bdd57f7cad8a6644e422c27bb407f3edef", size = 4008473, upload-time = "2025-09-13T20:07:01.733Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/0a/c42ce6e5d3de287f2e9432a074fb209f1fb72a86a72f3903849fdb5e4829/pyinstaller-6.16.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:7fd1c785219a87ca747c21fa92f561b0d2926a7edc06d0a0fe37f3736e00bd7a", size = 1027899, upload-time = "2025-09-13T20:05:59.2Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/d0/f18fedde32835d5a758f464c75924e2154065625f09d5456c3c303527654/pyinstaller-6.16.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:b756ddb9007b8141c5476b553351f9d97559b8af5d07f9460869bfae02be26b0", size = 727990, upload-time = "2025-09-13T20:06:03.583Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/db/c8bb47514ce857b24bf9294cf1ff74844b6a489fa0ab4ef6f923288c4e38/pyinstaller-6.16.0-py3-none-manylinux2014_i686.whl", hash = "sha256:0a48f55b85ff60f83169e10050f2759019cf1d06773ad1c4da3a411cd8751058", size = 739238, upload-time = "2025-09-13T20:06:07.69Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/3e/451dc784a8fcca0fe9f9b6b802d58555364a95b60f253613a2c83fc6b023/pyinstaller-6.16.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:73ba72e04fcece92e32518bbb1e1fb5ac2892677943dfdff38e01a06e8742851", size = 737142, upload-time = "2025-09-13T20:06:11.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/37/2f457479ef8fa2821cdb448acee2421dfb19fbe908bf5499d1930c164084/pyinstaller-6.16.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:b1752488248f7899281b17ca3238eefb5410521291371a686a4f5830f29f52b3", size = 734133, upload-time = "2025-09-13T20:06:15.477Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/c4/0f7daac4d062a4d1ac2571d8a8b9b5d6812094fcd914d139af591ca5e1ba/pyinstaller-6.16.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ba618a61627ee674d6d68e5de084ba17c707b59a4f2a856084b3999bdffbd3f0", size = 733817, upload-time = "2025-09-13T20:06:19.683Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/e4/b6127265b42bef883e8873d850becadf748bc5652e5a7029b059328f3c31/pyinstaller-6.16.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:c8b7ef536711617e12fef4673806198872033fa06fa92326ad7fd1d84a9fa454", size = 732912, upload-time = "2025-09-13T20:06:23.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/00/c6663107bdf814b2916e71563beabd09f693c47712213bc228994cb2cc65/pyinstaller-6.16.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d1ebf84d02c51fed19b82a8abb4df536923abd55bb684d694e1356e4ae2a0ce5", size = 732773, upload-time = "2025-09-13T20:06:27.352Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/14/cabe9bc5f60b95d2e70e7d045ab94b0015ff8f6c8b16e2142d3597e30749/pyinstaller-6.16.0-py3-none-win32.whl", hash = "sha256:6d5f8617f3650ff9ef893e2ab4ddbf3c0d23d0c602ef74b5df8fbef4607840c8", size = 1313878, upload-time = "2025-09-13T20:06:33.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/99/2005efbc297e7813c1d6f18484aa94a1a81ce87b6a5b497c563681f4c4ea/pyinstaller-6.16.0-py3-none-win_amd64.whl", hash = "sha256:bc10eb1a787f99fea613509f55b902fbd2d8b73ff5f51ff245ea29a481d97d41", size = 1374706, upload-time = "2025-09-13T20:06:39.95Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/f4/4dfcf69b86d60fcaae05a42bbff1616d48a91e71726e5ed795d773dae9b3/pyinstaller-6.16.0-py3-none-win_arm64.whl", hash = "sha256:d0af8a401de792c233c32c44b16d065ca9ab8262ee0c906835c12bdebc992a64", size = 1315923, upload-time = "2025-09-13T20:06:45.846Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2025.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/83/be0f57c0b77b66c33c2283ebd4ea341022b5a743e97c5fb3bebab82b38b9/pyinstaller_hooks_contrib-2025.9.tar.gz", hash = "sha256:56e972bdaad4e9af767ed47d132362d162112260cbe488c9da7fee01f228a5a6", size = 165189, upload-time = "2025-09-24T11:21:35.113Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/26/23b4cfc77d7f808c69f59070e1e8293a579ec281a547c61562357160b346/pyinstaller_hooks_contrib-2025.9-py3-none-any.whl", hash = "sha256:ccbfaa49399ef6b18486a165810155e5a8d4c59b41f20dc5da81af7482aaf038", size = 444283, upload-time = "2025-09-24T11:21:33.67Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyside6-addons" },
|
||||
{ name = "pyside6-essentials" },
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/98/84b16f78b5d92dd234fb1eb9890a350a5b0c83d985bb8c44a92f813a2d02/pyside6-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:c2cbc5dc2a164e3c7c51b3435e24203e90e5edd518c865466afccbd2e5872bb0", size = 558115, upload-time = "2025-10-08T09:47:09.246Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/76/0961c8c5653ecb60a6881b649dcb6b71a6be5bd1c8d441ecc48ac7f50b1a/pyside6-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ae8c3c8339cd7c3c9faa7cc5c52670dcc8662ccf4b63a6fed61c6345b90c4c01", size = 557762, upload-time = "2025-10-08T09:47:11.819Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/73/6187502fff8b6599443d15c46dd900b2ded24be5aacb2becce33f6faf566/pyside6-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:9f402f883e640048fab246d36e298a5e16df9b18ba2e8c519877e472d3602820", size = 558299, upload-time = "2025-10-08T09:47:14.255Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/67/94794ebaf198bbdb35cb77f19f38370f9b323b036ab149874bc33c38faab/pyside6-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:70a8bcc73ea8d6baab70bba311eac77b9a1d31f658d0b418e15eb6ea36c97e6f", size = 564367, upload-time = "2025-10-08T09:47:16.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/cc/552331d413c1b933d54ed45e33cc7ff29d0b239677975fe2528e7ac8bfbc/pyside6-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:4b709bdeeb89d386059343a5a706fc185cee37b517bda44c7d6b64d5fdaf3339", size = 548826, upload-time = "2025-10-08T09:47:18.399Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-addons"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyside6-essentials" },
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/47/23/9fbdec2ce16244ac3fe28e6d44c39c70465c93a03325939a792fd00fde7f/pyside6_addons-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:88e61e21ee4643cdd9efb39ec52f4dc1ac74c0b45c5b7fa453d03c094f0a8a5c", size = 322248256, upload-time = "2025-10-08T09:47:37.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/b8/d129210f2c7366b4e1bf5bb6230be42052b29e8ba1b1d7db6ef333cf5a39/pyside6_addons-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:08d4ed46c4c9a353a9eb84134678f8fdd4ce17fb8cce2b3686172a7575025464", size = 170238987, upload-time = "2025-10-08T09:47:51.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/ae/ede1edd009395092219f3437d2ee59f9ba93739c28c040542ed47c6cc831/pyside6_addons-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:15d32229d681be0bba1b936c4a300da43d01e1917ada5b57f9e03a387c245ab0", size = 165939425, upload-time = "2025-10-08T09:48:02.073Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/5d/a3c32f85ac7f905c95679967c0ddda0ba043c273b75623cc90d8185064e4/pyside6_addons-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:99d93a32c17c5f6d797c3b90dd58f2a8bae13abde81e85802c34ceafaee11859", size = 164814172, upload-time = "2025-10-08T09:48:12.891Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/2a/4ff71b09571202c8e1320c45276fc1d0cd81ee53107dfc17bb22d4243f88/pyside6_addons-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:92536427413f3b6557cf53f1a515cd766725ee46a170aff57ad2ff1dfce0ffb1", size = 34104251, upload-time = "2025-10-08T09:48:18.287Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-essentials"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/55/bad02ab890c8b8101abef0db4a2e5304be78a69e23a438e4d8555b664467/pyside6_essentials-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:003e871effe1f3e5b876bde715c15a780d876682005a6e989d89f48b8b93e93a", size = 105034090, upload-time = "2025-10-08T09:48:24.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/75/e17efc7eb900993e0e3925885635c6cf373c817196f09bcbcc102b00ac94/pyside6_essentials-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:1d5e013a8698e37ab8ef360e6960794eb5ef20832a8d562e649b8c5a0574b2d8", size = 76362150, upload-time = "2025-10-08T09:48:31.849Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/62/fbd1e81caafcda97b147c03f5b06cfaadd8da5fa8298f527d2ec648fa5b7/pyside6_essentials-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:b1dd0864f0577a448fb44426b91cafff7ee7cccd1782ba66491e1c668033f998", size = 75454169, upload-time = "2025-10-08T09:48:38.21Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/3a/d8211d17e6ca70f641c6ebd309f08ef18930acda60e74082c75875a274da/pyside6_essentials-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:fc167eb211dd1580e20ba90d299e74898e7a5a1306d832421e879641fc03b6fe", size = 74361794, upload-time = "2025-10-08T09:48:44.335Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/e9/0e22e3c10325c4ff09447fadb43f7962afb82cef0b65358f5704251c6b32/pyside6_essentials-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:6dd0936394cb14da2fd8e869899f5e0925a738b1c8d74c2f22503720ea363fb1", size = 55099467, upload-time = "2025-10-08T09:48:50.902Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "six" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2025.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pywin32-ctypes"
|
||||
version = "0.2.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "80.9.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shiboken6"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/78/3e730aea82089dd82b1e092bc265778bda329459e6ad9b7134eec5fff3f2/shiboken6-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:7a5f5f400ebfb3a13616030815708289c2154e701a60b9db7833b843e0bee543", size = 476535, upload-time = "2025-10-08T09:49:08Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/09/4ffa3284a17b6b765d45b41c9a7f1b2cde6c617c853ac6f170fb62bbbece/shiboken6-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:e612734da515d683696980107cdc0396a3ae0f07b059f0f422ec8a2333810234", size = 271098, upload-time = "2025-10-08T09:49:09.47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/29/00e26f33a0fb259c2edce9c761a7a438d7531ca514bdb1a4c072673bd437/shiboken6-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:b01377e68d14132360efb0f4b7233006d26aa8ae9bb50edf00960c2a5f52d148", size = 267698, upload-time = "2025-10-08T09:49:10.694Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/30/e4624a7e3f0dc9796b701079b77defcce0d32d1afc86bb1d0df04bc3d9e2/shiboken6-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:0bc5631c1bf150cbef768a17f5f289aae1cb4db6c6b0c19b2421394e27783717", size = 1234227, upload-time = "2025-10-08T09:49:12.774Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/e5/0ab862005ea87dc8647ba958a3099b3b0115fd6491c65da5c5a0f6364db1/shiboken6-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:dfc4beab5fec7dbbebbb418f3bf99af865d6953aa0795435563d4cbb82093b61", size = 1794775, upload-time = "2025-10-08T09:49:14.641Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2025.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
|
||||
]
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "absl-py"
|
||||
version = "2.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "altgraph"
|
||||
version = "0.17.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/de/a8/7145824cf0b9e3c28046520480f207df47e927df83aa9555fb47f8505922/altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406", size = 48418, upload-time = "2023-09-25T09:04:52.164Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/3f/3bc3f1d83f6e4a7fcb834d3720544ca597590425be5ba9db032b2bf322a2/altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff", size = 21212, upload-time = "2023-09-25T09:04:50.691Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "et-xmlfile"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d3/38/af70d7ab1ae9d4da450eeec1fa3918940a5fafb9055e934af8d6eb0c2313/et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54", size = 17234, upload-time = "2024-10-25T17:25:40.039Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eva-duty-arrange-tool"
|
||||
version = "2.0.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "openpyxl" },
|
||||
{ name = "ortools" },
|
||||
{ name = "pandas" },
|
||||
{ name = "pyinstaller" },
|
||||
{ name = "pyside6" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "openpyxl", specifier = ">=3.1.5" },
|
||||
{ name = "ortools", specifier = ">=9.14.6206" },
|
||||
{ name = "pandas", specifier = ">=2.3.3" },
|
||||
{ name = "pyinstaller", specifier = ">=6.16.0" },
|
||||
{ name = "pyside6", specifier = ">=6.10.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "immutabledict"
|
||||
version = "4.2.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ce/12/1da8e1a9050d0603ba65fb1796ed8860a705b906701c96e77f85cc7490be/immutabledict-4.2.2.tar.gz", hash = "sha256:cb6ed3090df593148f94cb407d218ca526fd2639694afdb553dc4f50ce6feeca", size = 6099, upload-time = "2025-10-12T13:32:59.755Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/63/7b/04ab6afa1ff7eb9ccb09049918c0407b205f5009092c0416147d163e4e2b/immutabledict-4.2.2-py3-none-any.whl", hash = "sha256:97c31d098a2c850e93a958badeef765e4736ed7942ec73e439facd764a3a7217", size = 4736, upload-time = "2025-10-12T13:32:58.326Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macholib"
|
||||
version = "1.16.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "altgraph" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/ee/af1a3842bdd5902ce133bd246eb7ffd4375c38642aeb5dc0ae3a0329dfa2/macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30", size = 59309, upload-time = "2023-09-25T09:10:16.155Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/5d/c059c180c84f7962db0aeae7c3b9303ed1d73d76f2bfbc32bc231c8be314/macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c", size = 38094, upload-time = "2023-09-25T09:10:14.188Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/19/95b3d357407220ed24c139018d2518fab0a61a948e68286a25f1a4d049ff/numpy-2.3.3.tar.gz", hash = "sha256:ddc7c39727ba62b80dfdbedf400d1c10ddfa8eefbd7ec8dcb118be8b56d31029", size = 20576648, upload-time = "2025-09-09T16:54:12.543Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/51/5d/bb7fc075b762c96329147799e1bcc9176ab07ca6375ea976c475482ad5b3/numpy-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cfdd09f9c84a1a934cde1eec2267f0a43a7cd44b2cca4ff95b7c0d14d144b0bf", size = 20957014, upload-time = "2025-09-09T15:56:29.966Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/0e/c6211bb92af26517acd52125a237a92afe9c3124c6a68d3b9f81b62a0568/numpy-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb32e3cf0f762aee47ad1ddc6672988f7f27045b0783c887190545baba73aa25", size = 14185220, upload-time = "2025-09-09T15:56:32.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/f2/07bb754eb2ede9073f4054f7c0286b0d9d2e23982e090a80d478b26d35ca/numpy-2.3.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396b254daeb0a57b1fe0ecb5e3cff6fa79a380fa97c8f7781a6d08cd429418fe", size = 5113918, upload-time = "2025-09-09T15:56:34.175Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/0a/afa51697e9fb74642f231ea36aca80fa17c8fb89f7a82abd5174023c3960/numpy-2.3.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:067e3d7159a5d8f8a0b46ee11148fc35ca9b21f61e3c49fbd0a027450e65a33b", size = 6647922, upload-time = "2025-09-09T15:56:36.149Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/f5/122d9cdb3f51c520d150fef6e87df9279e33d19a9611a87c0d2cf78a89f4/numpy-2.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c02d0629d25d426585fb2e45a66154081b9fa677bc92a881ff1d216bc9919a8", size = 14281991, upload-time = "2025-09-09T15:56:40.548Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/64/7de3c91e821a2debf77c92962ea3fe6ac2bc45d0778c1cbe15d4fce2fd94/numpy-2.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9192da52b9745f7f0766531dcfa978b7763916f158bb63bdb8a1eca0068ab20", size = 16641643, upload-time = "2025-09-09T15:56:43.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/e4/961a5fa681502cd0d68907818b69f67542695b74e3ceaa513918103b7e80/numpy-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cd7de500a5b66319db419dc3c345244404a164beae0d0937283b907d8152e6ea", size = 16056787, upload-time = "2025-09-09T15:56:46.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/26/92c912b966e47fbbdf2ad556cb17e3a3088e2e1292b9833be1dfa5361a1a/numpy-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93d4962d8f82af58f0b2eb85daaf1b3ca23fe0a85d0be8f1f2b7bb46034e56d7", size = 18579598, upload-time = "2025-09-09T15:56:49.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/b6/fc8f82cb3520768718834f310c37d96380d9dc61bfdaf05fe5c0b7653e01/numpy-2.3.3-cp312-cp312-win32.whl", hash = "sha256:5534ed6b92f9b7dca6c0a19d6df12d41c68b991cef051d108f6dbff3babc4ebf", size = 6320800, upload-time = "2025-09-09T15:56:52.499Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/ee/de999f2625b80d043d6d2d628c07d0d5555a677a3cf78fdf868d409b8766/numpy-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:497d7cad08e7092dba36e3d296fe4c97708c93daf26643a1ae4b03f6294d30eb", size = 12786615, upload-time = "2025-09-09T15:56:54.422Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/6e/b479032f8a43559c383acb20816644f5f91c88f633d9271ee84f3b3a996c/numpy-2.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:ca0309a18d4dfea6fc6262a66d06c26cfe4640c3926ceec90e57791a82b6eee5", size = 10195936, upload-time = "2025-09-09T15:56:56.541Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/b9/984c2b1ee61a8b803bf63582b4ac4242cf76e2dbd663efeafcb620cc0ccb/numpy-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f5415fb78995644253370985342cd03572ef8620b934da27d77377a2285955bf", size = 20949588, upload-time = "2025-09-09T15:56:59.087Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/e4/07970e3bed0b1384d22af1e9912527ecbeb47d3b26e9b6a3bced068b3bea/numpy-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d00de139a3324e26ed5b95870ce63be7ec7352171bc69a4cf1f157a48e3eb6b7", size = 14177802, upload-time = "2025-09-09T15:57:01.73Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/c7/477a83887f9de61f1203bad89cf208b7c19cc9fef0cebef65d5a1a0619f2/numpy-2.3.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:9dc13c6a5829610cc07422bc74d3ac083bd8323f14e2827d992f9e52e22cd6a6", size = 5106537, upload-time = "2025-09-09T15:57:03.765Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/47/93b953bd5866a6f6986344d045a207d3f1cfbad99db29f534ea9cee5108c/numpy-2.3.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d79715d95f1894771eb4e60fb23f065663b2298f7d22945d66877aadf33d00c7", size = 6640743, upload-time = "2025-09-09T15:57:07.921Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/83/377f84aaeb800b64c0ef4de58b08769e782edcefa4fea712910b6f0afd3c/numpy-2.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:952cfd0748514ea7c3afc729a0fc639e61655ce4c55ab9acfab14bda4f402b4c", size = 14278881, upload-time = "2025-09-09T15:57:11.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/a5/bf3db6e66c4b160d6ea10b534c381a1955dfab34cb1017ea93aa33c70ed3/numpy-2.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5b83648633d46f77039c29078751f80da65aa64d5622a3cd62aaef9d835b6c93", size = 16636301, upload-time = "2025-09-09T15:57:14.245Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/59/1287924242eb4fa3f9b3a2c30400f2e17eb2707020d1c5e3086fe7330717/numpy-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b001bae8cea1c7dfdb2ae2b017ed0a6f2102d7a70059df1e338e307a4c78a8ae", size = 16053645, upload-time = "2025-09-09T15:57:16.534Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/93/b3d47ed882027c35e94ac2320c37e452a549f582a5e801f2d34b56973c97/numpy-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e9aced64054739037d42fb84c54dd38b81ee238816c948c8f3ed134665dcd86", size = 18578179, upload-time = "2025-09-09T15:57:18.883Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/d9/487a2bccbf7cc9d4bfc5f0f197761a5ef27ba870f1e3bbb9afc4bbe3fcc2/numpy-2.3.3-cp313-cp313-win32.whl", hash = "sha256:9591e1221db3f37751e6442850429b3aabf7026d3b05542d102944ca7f00c8a8", size = 6312250, upload-time = "2025-09-09T15:57:21.296Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/b5/263ebbbbcede85028f30047eab3d58028d7ebe389d6493fc95ae66c636ab/numpy-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f0dadeb302887f07431910f67a14d57209ed91130be0adea2f9793f1a4f817cf", size = 12783269, upload-time = "2025-09-09T15:57:23.034Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/75/67b8ca554bbeaaeb3fac2e8bce46967a5a06544c9108ec0cf5cece559b6c/numpy-2.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:3c7cf302ac6e0b76a64c4aecf1a09e51abd9b01fc7feee80f6c43e3ab1b1dbc5", size = 10195314, upload-time = "2025-09-09T15:57:25.045Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/d0/0d1ddec56b162042ddfafeeb293bac672de9b0cfd688383590090963720a/numpy-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:eda59e44957d272846bb407aad19f89dc6f58fecf3504bd144f4c5cf81a7eacc", size = 21048025, upload-time = "2025-09-09T15:57:27.257Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/9e/1996ca6b6d00415b6acbdd3c42f7f03ea256e2c3f158f80bd7436a8a19f3/numpy-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:823d04112bc85ef5c4fda73ba24e6096c8f869931405a80aa8b0e604510a26bc", size = 14301053, upload-time = "2025-09-09T15:57:30.077Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/24/43da09aa764c68694b76e84b3d3f0c44cb7c18cdc1ba80e48b0ac1d2cd39/numpy-2.3.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:40051003e03db4041aa325da2a0971ba41cf65714e65d296397cc0e32de6018b", size = 5229444, upload-time = "2025-09-09T15:57:32.733Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/14/50ffb0f22f7218ef8af28dd089f79f68289a7a05a208db9a2c5dcbe123c1/numpy-2.3.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6ee9086235dd6ab7ae75aba5662f582a81ced49f0f1c6de4260a78d8f2d91a19", size = 6738039, upload-time = "2025-09-09T15:57:34.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/52/af46ac0795e09657d45a7f4db961917314377edecf66db0e39fa7ab5c3d3/numpy-2.3.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94fcaa68757c3e2e668ddadeaa86ab05499a70725811e582b6a9858dd472fb30", size = 14352314, upload-time = "2025-09-09T15:57:36.255Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/b1/dc226b4c90eb9f07a3fff95c2f0db3268e2e54e5cce97c4ac91518aee71b/numpy-2.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da1a74b90e7483d6ce5244053399a614b1d6b7bc30a60d2f570e5071f8959d3e", size = 16701722, upload-time = "2025-09-09T15:57:38.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9d/9d/9d8d358f2eb5eced14dba99f110d83b5cd9a4460895230f3b396ad19a323/numpy-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2990adf06d1ecee3b3dcbb4977dfab6e9f09807598d647f04d385d29e7a3c3d3", size = 16132755, upload-time = "2025-09-09T15:57:41.16Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/27/b3922660c45513f9377b3fb42240bec63f203c71416093476ec9aa0719dc/numpy-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ed635ff692483b8e3f0fcaa8e7eb8a75ee71aa6d975388224f70821421800cea", size = 18651560, upload-time = "2025-09-09T15:57:43.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/8e/3ab61a730bdbbc201bb245a71102aa609f0008b9ed15255500a99cd7f780/numpy-2.3.3-cp313-cp313t-win32.whl", hash = "sha256:a333b4ed33d8dc2b373cc955ca57babc00cd6f9009991d9edc5ddbc1bac36bcd", size = 6442776, upload-time = "2025-09-09T15:57:45.793Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/3a/e22b766b11f6030dc2decdeff5c2fb1610768055603f9f3be88b6d192fb2/numpy-2.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4384a169c4d8f97195980815d6fcad04933a7e1ab3b530921c3fef7a1c63426d", size = 12927281, upload-time = "2025-09-09T15:57:47.492Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/42/c2e2bc48c5e9b2a83423f99733950fbefd86f165b468a3d85d52b30bf782/numpy-2.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:75370986cc0bc66f4ce5110ad35aae6d182cc4ce6433c40ad151f53690130bf1", size = 10265275, upload-time = "2025-09-09T15:57:49.647Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/01/342ad585ad82419b99bcf7cebe99e61da6bedb89e213c5fd71acc467faee/numpy-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cd052f1fa6a78dee696b58a914b7229ecfa41f0a6d96dc663c1220a55e137593", size = 20951527, upload-time = "2025-09-09T15:57:52.006Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/d8/204e0d73fc1b7a9ee80ab1fe1983dd33a4d64a4e30a05364b0208e9a241a/numpy-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:414a97499480067d305fcac9716c29cf4d0d76db6ebf0bf3cbce666677f12652", size = 14186159, upload-time = "2025-09-09T15:57:54.407Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/af/f11c916d08f3a18fb8ba81ab72b5b74a6e42ead4c2846d270eb19845bf74/numpy-2.3.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:50a5fe69f135f88a2be9b6ca0481a68a136f6febe1916e4920e12f1a34e708a7", size = 5114624, upload-time = "2025-09-09T15:57:56.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/11/0ed919c8381ac9d2ffacd63fd1f0c34d27e99cab650f0eb6f110e6ae4858/numpy-2.3.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:b912f2ed2b67a129e6a601e9d93d4fa37bef67e54cac442a2f588a54afe5c67a", size = 6642627, upload-time = "2025-09-09T15:57:58.206Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/83/deb5f77cb0f7ba6cb52b91ed388b47f8f3c2e9930d4665c600408d9b90b9/numpy-2.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e318ee0596d76d4cb3d78535dc005fa60e5ea348cd131a51e99d0bdbe0b54fe", size = 14296926, upload-time = "2025-09-09T15:58:00.035Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/cc/70e59dcb84f2b005d4f306310ff0a892518cc0c8000a33d0e6faf7ca8d80/numpy-2.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce020080e4a52426202bdb6f7691c65bb55e49f261f31a8f506c9f6bc7450421", size = 16638958, upload-time = "2025-09-09T15:58:02.738Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/5a/b2ab6c18b4257e099587d5b7f903317bd7115333ad8d4ec4874278eafa61/numpy-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6687dc183aa55dae4a705b35f9c0f8cb178bcaa2f029b241ac5356221d5c021", size = 16071920, upload-time = "2025-09-09T15:58:05.029Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/f1/8b3fdc44324a259298520dd82147ff648979bed085feeacc1250ef1656c0/numpy-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d8f3b1080782469fdc1718c4ed1d22549b5fb12af0d57d35e992158a772a37cf", size = 18577076, upload-time = "2025-09-09T15:58:07.745Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/a1/b87a284fb15a42e9274e7fcea0dad259d12ddbf07c1595b26883151ca3b4/numpy-2.3.3-cp314-cp314-win32.whl", hash = "sha256:cb248499b0bc3be66ebd6578b83e5acacf1d6cb2a77f2248ce0e40fbec5a76d0", size = 6366952, upload-time = "2025-09-09T15:58:10.096Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/5f/1816f4d08f3b8f66576d8433a66f8fa35a5acfb3bbd0bf6c31183b003f3d/numpy-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:691808c2b26b0f002a032c73255d0bd89751425f379f7bcd22d140db593a96e8", size = 12919322, upload-time = "2025-09-09T15:58:12.138Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/de/072420342e46a8ea41c324a555fa90fcc11637583fb8df722936aed1736d/numpy-2.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:9ad12e976ca7b10f1774b03615a2a4bab8addce37ecc77394d8e986927dc0dfe", size = 10478630, upload-time = "2025-09-09T15:58:14.64Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/df/ee2f1c0a9de7347f14da5dd3cd3c3b034d1b8607ccb6883d7dd5c035d631/numpy-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9cc48e09feb11e1db00b320e9d30a4151f7369afb96bd0e48d942d09da3a0d00", size = 21047987, upload-time = "2025-09-09T15:58:16.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/92/9453bdc5a4e9e69cf4358463f25e8260e2ffc126d52e10038b9077815989/numpy-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:901bf6123879b7f251d3631967fd574690734236075082078e0571977c6a8e6a", size = 14301076, upload-time = "2025-09-09T15:58:20.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/77/1447b9eb500f028bb44253105bd67534af60499588a5149a94f18f2ca917/numpy-2.3.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:7f025652034199c301049296b59fa7d52c7e625017cae4c75d8662e377bf487d", size = 5229491, upload-time = "2025-09-09T15:58:22.481Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/f9/d72221b6ca205f9736cb4b2ce3b002f6e45cd67cd6a6d1c8af11a2f0b649/numpy-2.3.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:533ca5f6d325c80b6007d4d7fb1984c303553534191024ec6a524a4c92a5935a", size = 6737913, upload-time = "2025-09-09T15:58:24.569Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/5f/d12834711962ad9c46af72f79bb31e73e416ee49d17f4c797f72c96b6ca5/numpy-2.3.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0edd58682a399824633b66885d699d7de982800053acf20be1eaa46d92009c54", size = 14352811, upload-time = "2025-09-09T15:58:26.416Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/0d/fdbec6629d97fd1bebed56cd742884e4eead593611bbe1abc3eb40d304b2/numpy-2.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:367ad5d8fbec5d9296d18478804a530f1191e24ab4d75ab408346ae88045d25e", size = 16702689, upload-time = "2025-09-09T15:58:28.831Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/09/0a35196dc5575adde1eb97ddfbc3e1687a814f905377621d18ca9bc2b7dd/numpy-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8f6ac61a217437946a1fa48d24c47c91a0c4f725237871117dea264982128097", size = 16133855, upload-time = "2025-09-09T15:58:31.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/ca/c9de3ea397d576f1b6753eaa906d4cdef1bf97589a6d9825a349b4729cc2/numpy-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:179a42101b845a816d464b6fe9a845dfaf308fdfc7925387195570789bb2c970", size = 18652520, upload-time = "2025-09-09T15:58:33.762Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/c2/e5ed830e08cd0196351db55db82f65bc0ab05da6ef2b72a836dcf1936d2f/numpy-2.3.3-cp314-cp314t-win32.whl", hash = "sha256:1250c5d3d2562ec4174bce2e3a1523041595f9b651065e4a4473f5f48a6bc8a5", size = 6515371, upload-time = "2025-09-09T15:58:36.04Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/c7/b0f6b5b67f6788a0725f744496badbb604d226bf233ba716683ebb47b570/numpy-2.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:b37a0b2e5935409daebe82c1e42274d30d9dd355852529eab91dab8dcca7419f", size = 13112576, upload-time = "2025-09-09T15:58:37.927Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/b9/33bba5ff6fb679aa0b1f8a07e853f002a6b04b9394db3069a1270a7784ca/numpy-2.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:78c9f6560dc7e6b3990e32df7ea1a50bbd0e2a111e05209963f5ddcab7073b0b", size = 10545953, upload-time = "2025-09-09T15:58:40.576Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openpyxl"
|
||||
version = "3.1.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "et-xmlfile" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/f9/88d94a75de065ea32619465d2f77b29a0469500e99012523b91cc4141cd1/openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050", size = 186464, upload-time = "2024-06-28T14:03:44.161Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/da/977ded879c29cbd04de313843e76868e6e13408a94ed6b987245dc7c8506/openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2", size = 250910, upload-time = "2024-06-28T14:03:41.161Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ortools"
|
||||
version = "9.14.6206"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "absl-py" },
|
||||
{ name = "immutabledict" },
|
||||
{ name = "numpy" },
|
||||
{ name = "pandas" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/72/2e/b0d7e7ee9d1a45001a05ca2f65ccc1ab28cee510e725e01e248496510ac1/ortools-9.14.6206-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:e38c8c4a184820cbfdb812a8d484f6506cf16993ce2a95c88bc1c9d23b17c63e", size = 22239884, upload-time = "2025-06-19T15:45:51.774Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/ad/964ee5341767dd9e2f13e76f0a36d45aa8d81ad776c80bdd6dedc8f2f462/ortools-9.14.6206-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db685073cbed9f8bfaa744f5e883f3dea57c93179b0abe1788276fd3b074fa61", size = 20211128, upload-time = "2025-06-19T15:45:54.829Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/93/d94a66cdfadeb2747d96f1c8d3f590d81c4ad47fd357dfc57de8d7a75bbe/ortools-9.14.6206-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4bfb8bffb29991834cf4bde7048ca8ee8caed73e8dd21e5ec7de99a33bbfea0", size = 25663650, upload-time = "2025-06-19T15:47:20.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/74/1d374bf510e9fb36bba82ecd3e09461cd8394afef3e418fa5b060f129401/ortools-9.14.6206-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eb464a698837e7f90ca5f9b3d748b6ddf553198a70032bc77824d1cd88695d2b", size = 27670004, upload-time = "2025-06-19T15:47:23.111Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/e3/5943467ae41efa06cff12b79bfd146c4a54903345f0cc5c896884829d14a/ortools-9.14.6206-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8f33deaeb7c3dda8ca1d29c5b9aa9c3a4f2ca9ecf34f12a1f809bb2995f41274", size = 27653302, upload-time = "2025-06-19T15:53:47.615Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/28/a896080fe6e13b4bdae74601f19c28b7ba05ec45f3adca3e992d6174ac57/ortools-9.14.6206-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:086e7c2dc4f23efffb20a5e20f618c7d6adb99b2d94f684cab482387da3bc434", size = 29503497, upload-time = "2025-06-19T15:53:51.174Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/38/ad/8d02013116cc5d51084fe24c5b73f5b349dd10925d2927d19d21a2068a4c/ortools-9.14.6206-cp312-cp312-win_amd64.whl", hash = "sha256:17c13b0bfde17ac57789ad35243edf1318ecd5db23cf949b75ab62480599f188", size = 20512174, upload-time = "2025-06-19T15:46:33.339Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/9c/fe6d5ca549c2fb5ed3e8e1d928a11f4509c024c974e1f6e2d75d206bc226/ortools-9.14.6206-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:8d0df7eef8ba53ad235e29018389259bad2e667d9594b9c2a412ed6a5756bd4e", size = 22259719, upload-time = "2025-06-19T15:45:57.504Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/0f/0b9858e7d5b31dfb23a1fe945d3e9fd5d2feba893190e53f70374ac7e084/ortools-9.14.6206-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:57dfe10844ce8331634d4723040fe249263fd490407346efc314c0bc656849b5", size = 20231092, upload-time = "2025-06-19T15:46:00.003Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/48/de4eff68cb4ea124c9d6edf68049d329a332aab36d011c2798ea1afb4c98/ortools-9.14.6206-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c0c2c00a6e5d5c462e76fdda7dbd40d0f9139f1df4211d34b36906696248020", size = 25662903, upload-time = "2025-06-19T15:47:26.368Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c9/44/970f72cd5e537fc10e20582dadbdd2f8b2b3c802ac812105c40119572ea7/ortools-9.14.6206-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:38044cf39952d93cbcc02f6acdbe0a9bd3628fbf17f0d7eb0374060fa028c22e", size = 27669250, upload-time = "2025-06-19T15:47:29.738Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/31/37e2eacc37e4448090f693d482316a67bf2b47f2aefae6d6236b4ed41924/ortools-9.14.6206-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:98564de773d709e1e49cb3c32f6917589c314f047786d88bd5f324c0eb7be96e", size = 27652453, upload-time = "2025-06-19T15:53:54.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/8f/0b1bb2a3268114b95381d5a1146c293259d6e45c69e4e3f2d2cf52617796/ortools-9.14.6206-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:80528b0ac72dc3de00cbeef2ce028517a476450b5877b1cda1b8ecb9fa98505e", size = 29503368, upload-time = "2025-06-19T15:53:57.989Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/ad/93c05084eec710c38bc952a19002aac31d4c26bb6f8fcbf1057ccc55254b/ortools-9.14.6206-cp313-cp313-win_amd64.whl", hash = "sha256:47b1b15dcb085d32c61621b790259193aefa9e4577abadf233d47fbe7d0b81ef", size = 20530387, upload-time = "2025-06-19T15:46:35.964Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/85/aeba0d90a3cee4a23ba74a4f2d4c27088923c8b77fa1b73a52ad34593be5/ortools-9.14.6206-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d26a0f9ed97ef9d3384a9069923585f5f974c3fde555a41f4d6381fbe7840bc4", size = 25704462, upload-time = "2025-06-19T15:47:33.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/83/2954b6aa032b77f49a478e0d9682ae8176abfb4bd33d935f0260ecb1741b/ortools-9.14.6206-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d40d8141667d47405f296a9f687058c566d7816586e9a672b59e9fcec8493133", size = 27687594, upload-time = "2025-06-19T15:47:36.241Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/9a/9e9866952841e9f4aadccb110c0012d6a76f01b8798432fac0971d60aac1/ortools-9.14.6206-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:aefea81ed81aa937873efc520381785ed65380e52917f492ab566f46bbb5660d", size = 27698487, upload-time = "2025-06-19T15:54:01.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/a5/97a86cdd52c961273981e9ab905a301b7f086593b597d8974c411decf61a/ortools-9.14.6206-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f044bb277db3ab6a1b958728fe1cf14ca87c3800d67d7b321d876b48269340f6", size = 29519050, upload-time = "2025-06-19T15:54:04.147Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pandas"
|
||||
version = "2.3.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "numpy" },
|
||||
{ name = "python-dateutil" },
|
||||
{ name = "pytz" },
|
||||
{ name = "tzdata" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/4b/18b035ee18f97c1040d94debd8f2e737000ad70ccc8f5513f4eefad75f4b/pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713", size = 11544671, upload-time = "2025-09-29T23:21:05.024Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/94/72fac03573102779920099bcac1c3b05975c2cb5f01eac609faf34bed1ca/pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8", size = 10680807, upload-time = "2025-09-29T23:21:15.979Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/87/9472cf4a487d848476865321de18cc8c920b8cab98453ab79dbbc98db63a/pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d", size = 11709872, upload-time = "2025-09-29T23:21:27.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/07/284f757f63f8a8d69ed4472bfd85122bd086e637bf4ed09de572d575a693/pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac", size = 12306371, upload-time = "2025-09-29T23:21:40.532Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/81/a3afc88fca4aa925804a27d2676d22dcd2031c2ebe08aabd0ae55b9ff282/pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c", size = 12765333, upload-time = "2025-09-29T23:21:55.77Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/0f/b4d4ae743a83742f1153464cf1a8ecfafc3ac59722a0b5c8602310cb7158/pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493", size = 13418120, upload-time = "2025-09-29T23:22:10.109Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/c7/e54682c96a895d0c808453269e0b5928a07a127a15704fedb643e9b0a4c8/pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee", size = 10993991, upload-time = "2025-09-29T23:25:04.889Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/ca/3f8d4f49740799189e1395812f3bf23b5e8fc7c190827d55a610da72ce55/pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5", size = 12048227, upload-time = "2025-09-29T23:22:24.343Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/5a/f43efec3e8c0cc92c4663ccad372dbdff72b60bdb56b2749f04aa1d07d7e/pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21", size = 11411056, upload-time = "2025-09-29T23:22:37.762Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/b1/85331edfc591208c9d1a63a06baa67b21d332e63b7a591a5ba42a10bb507/pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78", size = 11645189, upload-time = "2025-09-29T23:22:51.688Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/23/78d645adc35d94d1ac4f2a3c4112ab6f5b8999f4898b8cdf01252f8df4a9/pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110", size = 12121912, upload-time = "2025-09-29T23:23:05.042Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/da/d10013df5e6aaef6b425aa0c32e1fc1f3e431e4bcabd420517dceadce354/pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86", size = 12712160, upload-time = "2025-09-29T23:23:28.57Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/17/e756653095a083d8a37cbd816cb87148debcfcd920129b25f99dd8d04271/pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc", size = 13199233, upload-time = "2025-09-29T23:24:24.876Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/fd/74903979833db8390b73b3a8a7d30d146d710bd32703724dd9083950386f/pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0", size = 11540635, upload-time = "2025-09-29T23:25:52.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/00/266d6b357ad5e6d3ad55093a7e8efc7dd245f5a842b584db9f30b0f0a287/pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593", size = 10759079, upload-time = "2025-09-29T23:26:33.204Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/05/d01ef80a7a3a12b2f8bbf16daba1e17c98a2f039cbc8e2f77a2c5a63d382/pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c", size = 11814049, upload-time = "2025-09-29T23:27:15.384Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/b2/0e62f78c0c5ba7e3d2c5945a82456f4fac76c480940f805e0b97fcbc2f65/pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b", size = 12332638, upload-time = "2025-09-29T23:27:51.625Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/33/dd70400631b62b9b29c3c93d2feee1d0964dc2bae2e5ad7a6c73a7f25325/pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6", size = 12886834, upload-time = "2025-09-29T23:28:21.289Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d3/18/b5d48f55821228d0d2692b34fd5034bb185e854bdb592e9c640f6290e012/pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3", size = 13409925, upload-time = "2025-09-29T23:28:58.261Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/3d/124ac75fcd0ecc09b8fdccb0246ef65e35b012030defb0e0eba2cbbbe948/pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5", size = 11109071, upload-time = "2025-09-29T23:32:27.484Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/9c/0e21c895c38a157e0faa1fb64587a9226d6dd46452cac4532d80c3c4a244/pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec", size = 12048504, upload-time = "2025-09-29T23:29:31.47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/82/b69a1c95df796858777b68fbe6a81d37443a33319761d7c652ce77797475/pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7", size = 11410702, upload-time = "2025-09-29T23:29:54.591Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/88/702bde3ba0a94b8c73a0181e05144b10f13f29ebfc2150c3a79062a8195d/pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450", size = 11634535, upload-time = "2025-09-29T23:30:21.003Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/1e/1bac1a839d12e6a82ec6cb40cda2edde64a2013a66963293696bbf31fbbb/pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5", size = 12121582, upload-time = "2025-09-29T23:30:43.391Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/91/483de934193e12a3b1d6ae7c8645d083ff88dec75f46e827562f1e4b4da6/pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788", size = 12699963, upload-time = "2025-09-29T23:31:10.009Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/44/5191d2e4026f86a2a109053e194d3ba7a31a2d10a9c2348368c63ed4e85a/pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87", size = 13202175, upload-time = "2025-09-29T23:31:59.173Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pefile"
|
||||
version = "2023.2.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/78/c5/3b3c62223f72e2360737fd2a57c30e5b2adecd85e70276879609a7403334/pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc", size = 74854, upload-time = "2023-02-07T12:23:55.958Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/55/26/d0ad8b448476d0a1e8d3ea5622dc77b916db84c6aa3cb1e1c0965af948fc/pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6", size = 71791, upload-time = "2023-02-07T12:28:36.678Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "6.31.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/52/f3/b9655a711b32c19720253f6f06326faf90580834e2e83f840472d752bc8b/protobuf-6.31.1.tar.gz", hash = "sha256:d8cac4c982f0b957a4dc73a80e2ea24fab08e679c0de9deb835f4a12d69aca9a", size = 441797, upload-time = "2025-05-28T19:25:54.947Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/6f/6ab8e4bf962fd5570d3deaa2d5c38f0a363f57b4501047b5ebeb83ab1125/protobuf-6.31.1-cp310-abi3-win32.whl", hash = "sha256:7fa17d5a29c2e04b7d90e5e32388b8bfd0e7107cd8e616feef7ed3fa6bdab5c9", size = 423603, upload-time = "2025-05-28T19:25:41.198Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/3a/b15c4347dd4bf3a1b0ee882f384623e2063bb5cf9fa9d57990a4f7df2fb6/protobuf-6.31.1-cp310-abi3-win_amd64.whl", hash = "sha256:426f59d2964864a1a366254fa703b8632dcec0790d8862d30034d8245e1cd447", size = 435283, upload-time = "2025-05-28T19:25:44.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/c9/b9689a2a250264a84e66c46d8862ba788ee7a641cdca39bccf64f59284b7/protobuf-6.31.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:6f1227473dc43d44ed644425268eb7c2e488ae245d51c6866d19fe158e207402", size = 425604, upload-time = "2025-05-28T19:25:45.702Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/a1/7a5a94032c83375e4fe7e7f56e3976ea6ac90c5e85fac8576409e25c39c3/protobuf-6.31.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:a40fc12b84c154884d7d4c4ebd675d5b3b5283e155f324049ae396b95ddebc39", size = 322115, upload-time = "2025-05-28T19:25:47.128Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/b1/b59d405d64d31999244643d88c45c8241c58f17cc887e73bcb90602327f8/protobuf-6.31.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4ee898bf66f7a8b0bd21bce523814e6fbd8c6add948045ce958b73af7e8878c6", size = 321070, upload-time = "2025-05-28T19:25:50.036Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/af/ab3c51ab7507a7325e98ffe691d9495ee3d3aa5f589afad65ec920d39821/protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e", size = 168724, upload-time = "2025-05-28T19:25:53.926Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller"
|
||||
version = "6.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "altgraph" },
|
||||
{ name = "macholib", marker = "sys_platform == 'darwin'" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pefile", marker = "sys_platform == 'win32'" },
|
||||
{ name = "pyinstaller-hooks-contrib" },
|
||||
{ name = "pywin32-ctypes", marker = "sys_platform == 'win32'" },
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/94/1f62e95e4a28b64cfbb5b922ef3046f968b47170d37a1e1a029f56ac9cb4/pyinstaller-6.16.0.tar.gz", hash = "sha256:53559fe1e041a234f2b4dcc3288ea8bdd57f7cad8a6644e422c27bb407f3edef", size = 4008473, upload-time = "2025-09-13T20:07:01.733Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/0a/c42ce6e5d3de287f2e9432a074fb209f1fb72a86a72f3903849fdb5e4829/pyinstaller-6.16.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:7fd1c785219a87ca747c21fa92f561b0d2926a7edc06d0a0fe37f3736e00bd7a", size = 1027899, upload-time = "2025-09-13T20:05:59.2Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/d0/f18fedde32835d5a758f464c75924e2154065625f09d5456c3c303527654/pyinstaller-6.16.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:b756ddb9007b8141c5476b553351f9d97559b8af5d07f9460869bfae02be26b0", size = 727990, upload-time = "2025-09-13T20:06:03.583Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/db/c8bb47514ce857b24bf9294cf1ff74844b6a489fa0ab4ef6f923288c4e38/pyinstaller-6.16.0-py3-none-manylinux2014_i686.whl", hash = "sha256:0a48f55b85ff60f83169e10050f2759019cf1d06773ad1c4da3a411cd8751058", size = 739238, upload-time = "2025-09-13T20:06:07.69Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/3e/451dc784a8fcca0fe9f9b6b802d58555364a95b60f253613a2c83fc6b023/pyinstaller-6.16.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:73ba72e04fcece92e32518bbb1e1fb5ac2892677943dfdff38e01a06e8742851", size = 737142, upload-time = "2025-09-13T20:06:11.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/37/2f457479ef8fa2821cdb448acee2421dfb19fbe908bf5499d1930c164084/pyinstaller-6.16.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:b1752488248f7899281b17ca3238eefb5410521291371a686a4f5830f29f52b3", size = 734133, upload-time = "2025-09-13T20:06:15.477Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/c4/0f7daac4d062a4d1ac2571d8a8b9b5d6812094fcd914d139af591ca5e1ba/pyinstaller-6.16.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ba618a61627ee674d6d68e5de084ba17c707b59a4f2a856084b3999bdffbd3f0", size = 733817, upload-time = "2025-09-13T20:06:19.683Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/e4/b6127265b42bef883e8873d850becadf748bc5652e5a7029b059328f3c31/pyinstaller-6.16.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:c8b7ef536711617e12fef4673806198872033fa06fa92326ad7fd1d84a9fa454", size = 732912, upload-time = "2025-09-13T20:06:23.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/00/c6663107bdf814b2916e71563beabd09f693c47712213bc228994cb2cc65/pyinstaller-6.16.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d1ebf84d02c51fed19b82a8abb4df536923abd55bb684d694e1356e4ae2a0ce5", size = 732773, upload-time = "2025-09-13T20:06:27.352Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/14/cabe9bc5f60b95d2e70e7d045ab94b0015ff8f6c8b16e2142d3597e30749/pyinstaller-6.16.0-py3-none-win32.whl", hash = "sha256:6d5f8617f3650ff9ef893e2ab4ddbf3c0d23d0c602ef74b5df8fbef4607840c8", size = 1313878, upload-time = "2025-09-13T20:06:33.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/99/2005efbc297e7813c1d6f18484aa94a1a81ce87b6a5b497c563681f4c4ea/pyinstaller-6.16.0-py3-none-win_amd64.whl", hash = "sha256:bc10eb1a787f99fea613509f55b902fbd2d8b73ff5f51ff245ea29a481d97d41", size = 1374706, upload-time = "2025-09-13T20:06:39.95Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/f4/4dfcf69b86d60fcaae05a42bbff1616d48a91e71726e5ed795d773dae9b3/pyinstaller-6.16.0-py3-none-win_arm64.whl", hash = "sha256:d0af8a401de792c233c32c44b16d065ca9ab8262ee0c906835c12bdebc992a64", size = 1315923, upload-time = "2025-09-13T20:06:45.846Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2025.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/83/be0f57c0b77b66c33c2283ebd4ea341022b5a743e97c5fb3bebab82b38b9/pyinstaller_hooks_contrib-2025.9.tar.gz", hash = "sha256:56e972bdaad4e9af767ed47d132362d162112260cbe488c9da7fee01f228a5a6", size = 165189, upload-time = "2025-09-24T11:21:35.113Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/26/23b4cfc77d7f808c69f59070e1e8293a579ec281a547c61562357160b346/pyinstaller_hooks_contrib-2025.9-py3-none-any.whl", hash = "sha256:ccbfaa49399ef6b18486a165810155e5a8d4c59b41f20dc5da81af7482aaf038", size = 444283, upload-time = "2025-09-24T11:21:33.67Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyside6-addons" },
|
||||
{ name = "pyside6-essentials" },
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/98/84b16f78b5d92dd234fb1eb9890a350a5b0c83d985bb8c44a92f813a2d02/pyside6-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:c2cbc5dc2a164e3c7c51b3435e24203e90e5edd518c865466afccbd2e5872bb0", size = 558115, upload-time = "2025-10-08T09:47:09.246Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/76/0961c8c5653ecb60a6881b649dcb6b71a6be5bd1c8d441ecc48ac7f50b1a/pyside6-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ae8c3c8339cd7c3c9faa7cc5c52670dcc8662ccf4b63a6fed61c6345b90c4c01", size = 557762, upload-time = "2025-10-08T09:47:11.819Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/73/6187502fff8b6599443d15c46dd900b2ded24be5aacb2becce33f6faf566/pyside6-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:9f402f883e640048fab246d36e298a5e16df9b18ba2e8c519877e472d3602820", size = 558299, upload-time = "2025-10-08T09:47:14.255Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/67/94794ebaf198bbdb35cb77f19f38370f9b323b036ab149874bc33c38faab/pyside6-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:70a8bcc73ea8d6baab70bba311eac77b9a1d31f658d0b418e15eb6ea36c97e6f", size = 564367, upload-time = "2025-10-08T09:47:16.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/cc/552331d413c1b933d54ed45e33cc7ff29d0b239677975fe2528e7ac8bfbc/pyside6-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:4b709bdeeb89d386059343a5a706fc185cee37b517bda44c7d6b64d5fdaf3339", size = 548826, upload-time = "2025-10-08T09:47:18.399Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-addons"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyside6-essentials" },
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/47/23/9fbdec2ce16244ac3fe28e6d44c39c70465c93a03325939a792fd00fde7f/pyside6_addons-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:88e61e21ee4643cdd9efb39ec52f4dc1ac74c0b45c5b7fa453d03c094f0a8a5c", size = 322248256, upload-time = "2025-10-08T09:47:37.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/b8/d129210f2c7366b4e1bf5bb6230be42052b29e8ba1b1d7db6ef333cf5a39/pyside6_addons-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:08d4ed46c4c9a353a9eb84134678f8fdd4ce17fb8cce2b3686172a7575025464", size = 170238987, upload-time = "2025-10-08T09:47:51.446Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cf/ae/ede1edd009395092219f3437d2ee59f9ba93739c28c040542ed47c6cc831/pyside6_addons-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:15d32229d681be0bba1b936c4a300da43d01e1917ada5b57f9e03a387c245ab0", size = 165939425, upload-time = "2025-10-08T09:48:02.073Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/5d/a3c32f85ac7f905c95679967c0ddda0ba043c273b75623cc90d8185064e4/pyside6_addons-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:99d93a32c17c5f6d797c3b90dd58f2a8bae13abde81e85802c34ceafaee11859", size = 164814172, upload-time = "2025-10-08T09:48:12.891Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/2a/4ff71b09571202c8e1320c45276fc1d0cd81ee53107dfc17bb22d4243f88/pyside6_addons-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:92536427413f3b6557cf53f1a515cd766725ee46a170aff57ad2ff1dfce0ffb1", size = 34104251, upload-time = "2025-10-08T09:48:18.287Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-essentials"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/55/bad02ab890c8b8101abef0db4a2e5304be78a69e23a438e4d8555b664467/pyside6_essentials-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:003e871effe1f3e5b876bde715c15a780d876682005a6e989d89f48b8b93e93a", size = 105034090, upload-time = "2025-10-08T09:48:24.944Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/75/e17efc7eb900993e0e3925885635c6cf373c817196f09bcbcc102b00ac94/pyside6_essentials-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:1d5e013a8698e37ab8ef360e6960794eb5ef20832a8d562e649b8c5a0574b2d8", size = 76362150, upload-time = "2025-10-08T09:48:31.849Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/62/fbd1e81caafcda97b147c03f5b06cfaadd8da5fa8298f527d2ec648fa5b7/pyside6_essentials-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:b1dd0864f0577a448fb44426b91cafff7ee7cccd1782ba66491e1c668033f998", size = 75454169, upload-time = "2025-10-08T09:48:38.21Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/3a/d8211d17e6ca70f641c6ebd309f08ef18930acda60e74082c75875a274da/pyside6_essentials-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:fc167eb211dd1580e20ba90d299e74898e7a5a1306d832421e879641fc03b6fe", size = 74361794, upload-time = "2025-10-08T09:48:44.335Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/e9/0e22e3c10325c4ff09447fadb43f7962afb82cef0b65358f5704251c6b32/pyside6_essentials-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:6dd0936394cb14da2fd8e869899f5e0925a738b1c8d74c2f22503720ea363fb1", size = 55099467, upload-time = "2025-10-08T09:48:50.902Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "six" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2025.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pywin32-ctypes"
|
||||
version = "0.2.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "80.9.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shiboken6"
|
||||
version = "6.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/78/3e730aea82089dd82b1e092bc265778bda329459e6ad9b7134eec5fff3f2/shiboken6-6.10.0-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:7a5f5f400ebfb3a13616030815708289c2154e701a60b9db7833b843e0bee543", size = 476535, upload-time = "2025-10-08T09:49:08Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/09/4ffa3284a17b6b765d45b41c9a7f1b2cde6c617c853ac6f170fb62bbbece/shiboken6-6.10.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:e612734da515d683696980107cdc0396a3ae0f07b059f0f422ec8a2333810234", size = 271098, upload-time = "2025-10-08T09:49:09.47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/29/00e26f33a0fb259c2edce9c761a7a438d7531ca514bdb1a4c072673bd437/shiboken6-6.10.0-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:b01377e68d14132360efb0f4b7233006d26aa8ae9bb50edf00960c2a5f52d148", size = 267698, upload-time = "2025-10-08T09:49:10.694Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/30/e4624a7e3f0dc9796b701079b77defcce0d32d1afc86bb1d0df04bc3d9e2/shiboken6-6.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:0bc5631c1bf150cbef768a17f5f289aae1cb4db6c6b0c19b2421394e27783717", size = 1234227, upload-time = "2025-10-08T09:49:12.774Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/e5/0ab862005ea87dc8647ba958a3099b3b0115fd6491c65da5c5a0f6364db1/shiboken6-6.10.0-cp39-abi3-win_arm64.whl", hash = "sha256:dfc4beab5fec7dbbebbb418f3bf99af865d6953aa0795435563d4cbb82093b61", size = 1794775, upload-time = "2025-10-08T09:49:14.641Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2025.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
|
||||
]
|
||||
|
|
|
|||
200
使用手册.md
200
使用手册.md
|
|
@ -1,100 +1,100 @@
|
|||
# EVA 值班排班工具使用手册 - v2.0.0
|
||||
|
||||
## 前言
|
||||
这是浙江大学学生E志者协会“排班工具软件”的使用手册,将简要地介绍该软件的使用方法和注意事项。请注意,这是面向使用者而非开发者的手册,如果想了解该工具的开发流程和所使用的技术,请移步至[此仓库](https://git.zjueva.net/happywind/EVA_duty_arrange_tool)的说明手册。
|
||||
|
||||
## 软件运行环境 & 基本情况
|
||||
- 本软件只能在 Windows 系统上运行。
|
||||
- 本软件在部分版本的 Win10 和 Win11 系统上均测试过,能够正常运行。但是不排除可能出现缺少相关 dll 文件而无法运行的情况,如果出现请联系开发者解决。
|
||||
- 本软件将排班问题建模为**多目标组合优化问题**,使用 Google OR-Tools 的 SCIP 求解器求解。
|
||||
- 优化目标包括:
|
||||
1. 各班次人数尽可能平均
|
||||
2. 每班技术部老人数量接近期望值(3人)
|
||||
3. 每班技术部小朋友数量接近期望值(4人)
|
||||
4. 每班人资部小朋友数量接近期望值(1人)
|
||||
5. 每班各部门人数尽可能均衡
|
||||
- 在指定的限制条件下,若有解,则得到的一定是**全局最优解**。
|
||||
|
||||
## 软件使用方法
|
||||
|
||||
双击运行可执行文件,会看到如下软件界面:
|
||||
|
||||
<div style="text-align: center;">
|
||||
<img src="./pics/screen.jpg" style="width:50%;">
|
||||
</div>
|
||||
|
||||
进行以下三个步骤:
|
||||
|
||||
1. 选择待输入的问卷星结果 Excel 表格。对于选择的 Excel 表格,有以下**格式要求**:
|
||||
- 第 1 行,即表头的名称不会影响软件运行,但需要保证每一列的数据的格式和含义正确
|
||||
- 第 1 列为序号,不会用到,但需要有
|
||||
- 第 2 列为提交答卷时间,格式为 "year/month/day hour:min:sec"
|
||||
- 第 3 列为填表所用时间,不会用到,但需要有
|
||||
- 第 4 列为来源,不会用到,但需要有
|
||||
- 第 5 列为来源详情,不会用到,但需要有
|
||||
- 第 6 列为 IP,不会用到,但需要有
|
||||
- 第 7 列为姓名,这是每一位同学的唯一标识
|
||||
- 第 8 列为部门序号,用一个数字表示,映射关系如下:
|
||||
```python
|
||||
index_to_departments = { # 部门编号和部门名称的对应关系
|
||||
1: "电脑部",
|
||||
2: "电器部",
|
||||
3: "人资部",
|
||||
4: "财外部",
|
||||
5: "文宣部"
|
||||
}
|
||||
```
|
||||
- 第 9 列标识老人还是小朋友,用一个数字表示,映射关系如下:
|
||||
```python
|
||||
index_to_type = { # 老人/小朋友和对应的编号
|
||||
1: "老人",
|
||||
2: "小朋友"
|
||||
}
|
||||
```
|
||||
- 第 10 ~ 29 列,表示对于每个班次的意愿(1 代表有时间,0 代表没时间)。因为从周一第一班到周日第二班一共有 20 班,所以总共有 20 列。
|
||||
- 第 30 列,表示愿意排几班,用一个数字表示。
|
||||
|
||||
**我们提供了一个名为“问卷星结果_样例输入.xlsx”的文件,以作为正确输入格式的参考,以及一个名为“问卷星结果_较极端案例.xlsx”的文件,以作为程序运行的测试。**
|
||||
|
||||
**本软件可以自动处理同一名同学多次填写问卷的情况**,只要保证多次填写中“姓名”保持一致即可,软件将会自动选择最后一次填写的结果作为最终意愿。由于“姓名”是每位同学的唯一标识符,如果出现了某位同学“姓名”填错的情况,需要手动删除该姓名的记录。
|
||||
|
||||
如果出现了**两位同学撞名的情况**,需要在填表时“姓名”后加上后缀以作区分,比如“王五1”和“王五2”,否则就会当作一个人来看待。
|
||||
|
||||
2. 设置优化参数
|
||||
|
||||
软件界面的 Step 2 部分包含两类参数:
|
||||
|
||||
### 2.1 权重参数(始终可设置)
|
||||
|
||||
软件提供了 5 个优化目标的权重设置,用于调整各个目标的重要程度:
|
||||
- **目标 1 权重**:每班人数平均程度(默认 1.0)
|
||||
- **目标 2 权重**:每班技术部老人数量(默认 1.0)
|
||||
- **目标 3 权重**:每班技术部小朋友数量(默认 1.0)
|
||||
- **目标 4 权重**:每班人资部小朋友数量(默认 0.5)
|
||||
- **目标 5 权重**:每班部门平均程度(默认 0.5)
|
||||
|
||||
权重值范围建议为 0.0 - 5.0,权重越大表示该目标越重要。所有权重参数均已归一化处理。
|
||||
|
||||
### 2.2 约束条件(自动/手动模式)
|
||||
|
||||
**自动调参模式(推荐):**
|
||||
- 勾选"自动调参模式"复选框
|
||||
- 软件会自动尝试不同的约束参数组合,实时显示尝试过程
|
||||
- 从严格到宽松逐步调整参数,找到第一个可行解
|
||||
- 无需手动设置约束条件,约束输入框会被禁用
|
||||
|
||||
**手动模式:**
|
||||
- 取消勾选"自动调参模式"
|
||||
- 可手动设置以下约束条件:
|
||||
- **每班次人数**:最少和最多人数(建议 5-8 人)
|
||||
- **每班次电脑或电器的老人数**:技术部老人数量范围(建议最多 2 人)
|
||||
- **每班次老人数**:所有老人数量范围(建议最少 1 人)
|
||||
- **每班次小朋友数**:所有小朋友数量范围(建议最少 2 人)
|
||||
- 留空表示该项无限制
|
||||
- **注意**:约束条件设置过严可能导致无解,需要适当放宽限制
|
||||
|
||||
3. 开始排班并查看进度
|
||||
|
||||
点击"开始排班!"按钮开始计算:
|
||||
- 输出结果以 Excel 表格形式保存,文件名为 `result_<当前时间戳>.xlsx`
|
||||
- **在输出结果中,组长会被标黄**
|
||||
# EVA 值班排班工具使用手册 - v2.0.0
|
||||
|
||||
## 前言
|
||||
这是浙江大学学生E志者协会“排班工具软件”的使用手册,将简要地介绍该软件的使用方法和注意事项。请注意,这是面向使用者而非开发者的手册,如果想了解该工具的开发流程和所使用的技术,请移步至[此仓库](https://git.zjueva.net/happywind/EVA_duty_arrange_tool)的说明手册。
|
||||
|
||||
## 软件运行环境 & 基本情况
|
||||
- 本软件只能在 Windows 系统上运行。
|
||||
- 本软件在部分版本的 Win10 和 Win11 系统上均测试过,能够正常运行。但是不排除可能出现缺少相关 dll 文件而无法运行的情况,如果出现请联系开发者解决。
|
||||
- 本软件将排班问题建模为**多目标组合优化问题**,使用 Google OR-Tools 的 SCIP 求解器求解。
|
||||
- 优化目标包括:
|
||||
1. 各班次人数尽可能平均
|
||||
2. 每班技术部老人数量接近期望值(3人)
|
||||
3. 每班技术部小朋友数量接近期望值(4人)
|
||||
4. 每班人资部小朋友数量接近期望值(1人)
|
||||
5. 每班各部门人数尽可能均衡
|
||||
- 在指定的限制条件下,若有解,则得到的一定是**全局最优解**。
|
||||
|
||||
## 软件使用方法
|
||||
|
||||
双击运行可执行文件,会看到如下软件界面:
|
||||
|
||||
<div style="text-align: center;">
|
||||
<img src="./pics/screen.jpg" style="width:50%;">
|
||||
</div>
|
||||
|
||||
进行以下三个步骤:
|
||||
|
||||
1. 选择待输入的问卷星结果 Excel 表格。对于选择的 Excel 表格,有以下**格式要求**:
|
||||
- 第 1 行,即表头的名称不会影响软件运行,但需要保证每一列的数据的格式和含义正确
|
||||
- 第 1 列为序号,不会用到,但需要有
|
||||
- 第 2 列为提交答卷时间,格式为 "year/month/day hour:min:sec"
|
||||
- 第 3 列为填表所用时间,不会用到,但需要有
|
||||
- 第 4 列为来源,不会用到,但需要有
|
||||
- 第 5 列为来源详情,不会用到,但需要有
|
||||
- 第 6 列为 IP,不会用到,但需要有
|
||||
- 第 7 列为姓名,这是每一位同学的唯一标识
|
||||
- 第 8 列为部门序号,用一个数字表示,映射关系如下:
|
||||
```python
|
||||
index_to_departments = { # 部门编号和部门名称的对应关系
|
||||
1: "电脑部",
|
||||
2: "电器部",
|
||||
3: "人资部",
|
||||
4: "财外部",
|
||||
5: "文宣部"
|
||||
}
|
||||
```
|
||||
- 第 9 列标识老人还是小朋友,用一个数字表示,映射关系如下:
|
||||
```python
|
||||
index_to_type = { # 老人/小朋友和对应的编号
|
||||
1: "老人",
|
||||
2: "小朋友"
|
||||
}
|
||||
```
|
||||
- 第 10 ~ 29 列,表示对于每个班次的意愿(1 代表有时间,0 代表没时间)。因为从周一第一班到周日第二班一共有 20 班,所以总共有 20 列。
|
||||
- 第 30 列,表示愿意排几班,用一个数字表示。
|
||||
|
||||
**我们提供了一个名为“问卷星结果_样例输入.xlsx”的文件,以作为正确输入格式的参考,以及一个名为“问卷星结果_较极端案例.xlsx”的文件,以作为程序运行的测试。**
|
||||
|
||||
**本软件可以自动处理同一名同学多次填写问卷的情况**,只要保证多次填写中“姓名”保持一致即可,软件将会自动选择最后一次填写的结果作为最终意愿。由于“姓名”是每位同学的唯一标识符,如果出现了某位同学“姓名”填错的情况,需要手动删除该姓名的记录。
|
||||
|
||||
如果出现了**两位同学撞名的情况**,需要在填表时“姓名”后加上后缀以作区分,比如“王五1”和“王五2”,否则就会当作一个人来看待。
|
||||
|
||||
2. 设置优化参数
|
||||
|
||||
软件界面的 Step 2 部分包含两类参数:
|
||||
|
||||
### 2.1 权重参数(始终可设置)
|
||||
|
||||
软件提供了 5 个优化目标的权重设置,用于调整各个目标的重要程度:
|
||||
- **目标 1 权重**:每班人数平均程度(默认 1.0)
|
||||
- **目标 2 权重**:每班技术部老人数量(默认 1.0)
|
||||
- **目标 3 权重**:每班技术部小朋友数量(默认 1.0)
|
||||
- **目标 4 权重**:每班人资部小朋友数量(默认 0.5)
|
||||
- **目标 5 权重**:每班部门平均程度(默认 0.5)
|
||||
|
||||
权重值范围建议为 0.0 - 5.0,权重越大表示该目标越重要。所有权重参数均已归一化处理。
|
||||
|
||||
### 2.2 约束条件(自动/手动模式)
|
||||
|
||||
**自动调参模式(推荐):**
|
||||
- 勾选"自动调参模式"复选框
|
||||
- 软件会自动尝试不同的约束参数组合,实时显示尝试过程
|
||||
- 从严格到宽松逐步调整参数,找到第一个可行解
|
||||
- 无需手动设置约束条件,约束输入框会被禁用
|
||||
|
||||
**手动模式:**
|
||||
- 取消勾选"自动调参模式"
|
||||
- 可手动设置以下约束条件:
|
||||
- **每班次人数**:最少和最多人数(建议 5-8 人)
|
||||
- **每班次电脑或电器的老人数**:技术部老人数量范围(建议最多 2 人)
|
||||
- **每班次老人数**:所有老人数量范围(建议最少 1 人)
|
||||
- **每班次小朋友数**:所有小朋友数量范围(建议最少 2 人)
|
||||
- 留空表示该项无限制
|
||||
- **注意**:约束条件设置过严可能导致无解,需要适当放宽限制
|
||||
|
||||
3. 开始排班并查看进度
|
||||
|
||||
点击"开始排班!"按钮开始计算:
|
||||
- 输出结果以 Excel 表格形式保存,文件名为 `result_<当前时间戳>.xlsx`
|
||||
- **在输出结果中,组长会被标黄**
|
||||
|
|
|
|||
Loading…
Reference in New Issue