Metadata-Version: 2.4
Name: kkinput
Version: 0.1.0
Summary: 终端交互式输入校验：输入不规范就重复提示，直到拿到合法的值
Author: Python卡皮巴拉
License-Expression: MIT
Keywords: input,terminal,cli,validation,prompt
Classifier: Programming Language :: Python :: 3
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-dateutil>=2.8
Dynamic: license-file

# kkinput

终端里收集用户输入，输入不规范就一直问，直到拿到合法的值。

写终端程序时，取输入最烦的不是 `input()` 本身，而是**它从来不挑食**。
用户随手敲个回车、把年龄填成 `abc`、把日期写成「明天」，你还得自己套一层
`while True` 加一堆 `try / except` 去兜，兜不完全还得重来。
`kkinput` 把这件事收进一个调用：传进去一个「值对象」，它负责生成提示语、
校验输入、不合格就再问一遍。

## 安装

```bash
pip install kkinput
```

## 30 秒上手

```python
from kkinput import kk_input, IntValue, StrValue, ChoiceValue, BooleanValue, DatetimeValue
from datetime import datetime

age = kk_input(IntValue('年龄', min_value=1, max_value=120), loop=True)
nick = kk_input(StrValue('昵称', default='游客', max_length=8), loop=True)
fruit = kk_input(ChoiceValue('水果', choices=['苹果', '香蕉', '橘子']), loop=True)
again = kk_input(BooleanValue('再来一次', default=True), loop=True)
deadline = kk_input(DatetimeValue('截止时间', end=datetime(2027, 1, 1)), loop=True)
```

跑起来就是这个样子——用户填错，程序只是把要求再说一遍，不会崩：

```text
请输入年龄：abc
年龄必须是数字
请输入年龄：200
年龄必须在1~120之间
请输入年龄：30

请从下列选项中，选择相应水果：
0: 苹果
1: 香蕉
2: 橘子

请输入水果的选项：9
水果必须在可选范围内
请输入水果的选项：2
```

## 内置值类型

| 类型 | 校验内容 | 额外参数 | 合法时返回 |
| --- | --- | --- | --- |
| `StrValue` | 字符串，可限制长度 | `max_length` | `str` |
| `IntValue` | 整数，可限制区间 | `min_value` / `max_value` | `int` |
| `FloatValue` | 浮点数，可限制区间 | `min_value` / `max_value` | `float` |
| `BooleanValue` | 只认 `y` / `n` | — | `bool` |
| `ChoiceValue` | 必须落在备选项里 | `choices` | `int`（选项序号） |
| `DatetimeValue` | 能被解析的日期时间，可限制区间 | `start` / `end` | `datetime` |

三种公共参数所有类型都支持：

- `name`：字段名，用在提示语和报错里；
- `default`：默认值，用户直接敲回车就采用它；
- `placeholder`：完全自定义提示语，给了就不再自动生成。

> `ChoiceValue` 返回的是**选项序号**，不是选项本身。要拿到选项文字，
> 用 `choices[result]`。

## 关于 loop

`loop=True`：值不合法就一直重问，直到问出一个合法的。

`loop=False`（默认）：只问一次，不合法就返回 `None`。

两种模式都**不会抛异常**——包括用户直接按了 Ctrl+C 之外的各种奇怪输入。
所以调用方只需要判断返回值是不是 `None`，不需要写 `try / except`：

```python
port = kk_input(IntValue('端口', min_value=1, max_value=65535))
if port is None:
    print('没取到端口，用默认的 8080')
    port = 8080
```

## 自己加一种值类型

继承 `BaseValue`，实现 `valid()` 就够了。约定是：**校验不过就 `print` 提示并返回
`None`，通过就返回转换后的值**。

```python
from kkinput import BaseValue, kk_input


class IpValue(BaseValue):
    def valid(self, result):
        super_result = super().valid(result)   # 先走公共逻辑：空值取默认值
        if super_result is not None:
            return super_result

        parts = result.split('.')
        if len(parts) != 4 or not all(p.isdigit() and 0 <= int(p) <= 255 for p in parts):
            print(f'{self.name}必须是合法的 IPv4 地址')
            return None

        return result


ip = kk_input(IpValue('设备地址'), loop=True)
```

## 依赖

- Python >= 3.9
- [python-dateutil](https://pypi.org/project/python-dateutil/)

## 许可

MIT

## 关于作者
微信公众号：Python卡皮巴拉

🌟【Python卡皮巴拉】—— 你的Python修炼秘籍，代码界的“神兽”驾到！🌟
