Nhấp vào con trăn

Trong quá trình làm việc của mình, bạn có thể đã gặp phải một số tập lệnh dòng lệnh tự chế tùy chỉnh được ghi lại kém, kiểm tra kém [nếu có] và khó sử dụng cho người dùng cuối, bất kể nhiệm vụ mà nó thực hiện quan trọng đến đâu. Thông thường, mọi người không sử dụng bất kỳ phân tích đối số dòng lệnh[1] nào hoặc phân tích đối số họ sử dụng đã lỗi thời. Đừng hiểu sai ý tôi, ví dụ: tôi không có gì chống lại getopt hoặc thư viện argparse tích hợp trong Python, nhưng có những lựa chọn thay thế tốt hơn

Nhập nhấp chuột [hay còn được gọi là “Bộ công cụ tạo giao diện dòng lệnh”]. một thư viện toàn diện, tôi dám nói là khuôn khổ, để tạo các ứng dụng CLI đẹp mắt, thực tế tự ghi lại tài liệu. Click chủ yếu sử dụng các công cụ trang trí và chức năng để xác định các lệnh và đối số của chúng, sẽ được gọi tự động khi xử lý lệnh

Phần hay là lệnh chính ở trên vẫn có thể sử dụng được như một chức năng thông thường. Đây là một tính năng quan trọng. nó sẽ làm cho việc kiểm tra các đối số CLI không chỉ khả thi mà còn khá dễ dàng và ít đau đớn hơn nhiều so với cách khác. Thư viện nhấp chuột thậm chí còn cung cấp rất nhiều công cụ để làm cho các ứng dụng nhấp chuột thử nghiệm trở thành một trải nghiệm ít đau đớn hơn nhiều so với các ứng dụng khác. [2]

Hy vọng rằng sau khi đọc qua mục blog này, bạn sẽ có thể tạo các ứng dụng dòng lệnh tuyệt vời đã được kiểm tra kỹ lưỡng, ghi chép đầy đủ và dễ sử dụng cho người dùng cuối. Và ngay cả khi chỉ có bạn sử dụng tập lệnh kết quả, bạn sẽ cảm ơn quá khứ của mình vì đã để lại một ứng dụng tốt hơn

Nếu bạn là kiểu người thường xuyên viết các tập lệnh bỏ đi sẽ được chạy một hoặc hai lần, thì nhấp chuột có vẻ như là quá mức cần thiết, tuy nhiên, mã cần thiết vẫn ít hơn nếu bạn phân tích cú pháp các đối số theo cách thủ công. Và này, có lẽ nó không phải là thứ bỏ đi, nhưng bây giờ đã nhiều tháng hoặc nhiều năm trôi qua, và bạn thậm chí không nhớ kịch bản của chính mình hoạt động như thế nào

Các lệnh độc lập

Trường hợp sử dụng nhấp chuột đơn giản nhất là viết một ứng dụng nhận một số tùy chọn và/hoặc đối số, thực hiện điều gì đó và trả về mã từ 0 đến 255, trong đó số 0 có nghĩa là - theo quy ước - rằng việc thực thi đã thành công và không

Vì vậy, đối với ví dụ bên dưới, hãy tạo một tập lệnh đơn giản lấy tên tệp JSON làm đầu vào, đọc nó, sắp xếp đầu ra theo một khóa nhất định và xuất kết quả JSON. Hãy gọi tập lệnh CLI này là json_sorter. py


import json, sys, click

@click.command[help="JSON sorter"]
@click.option["-i", "--input", "infile", type=click.File[], default=sys.stdin, help="Input file name"]
@click.option["-o", "--output", "outfile", type=click.File["w"], default=sys.stdout, help="Output file name"]
@click.option["-k", "--key", default="key", show_default=True, help="Sorting key"]
def main[infile, outfile, key]:
    data = json.load[infile]
    data.sort[key=lambda obj: obj.get[key, 0]]
    json.dump[data, outfile]
    outfile.write['\n']

if __name__ == "__main__":
    exit[main[]]

Sau đó, chúng tôi có thể thực thi tập lệnh này bằng cách cung cấp cho nó một tệp đầu vào và để tập lệnh xuất kết quả ra bàn điều khiển


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]

Hoặc đơn giản là lấy dữ liệu đầu vào từ đầu vào tiêu chuẩn và hiển thị nó trên đầu ra tiêu chuẩn


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]


Hãy nghiên cứu ví dụ trên và xem điều gì đang xảy ra. Điều đầu tiên người ta có thể nhận thấy là nhấp chuột sử dụng rất nhiều trang trí. Đó là bởi vì khi chúng ta định nghĩa một lệnh [được đại diện bởi hàm main], hệ thống con nhấp chuột sẽ gọi hàm này với các tùy chọn và đối số được truyền cho nó

Trong trường hợp này, chúng tôi nhận được một tệp đầu vào và đầu ra mà nhấp chuột sẽ tự động mở cho chúng tôi sau khi kiểm tra xem nó có tồn tại không, có thể truy cập được không, v.v. Điều này khá thuận tiện vì chúng tôi không phải thực hiện các kiểm tra này theo cách thủ công. Nhưng tôi lạc đề

Trang trí đầu tiên [bấm vào. lệnh] xác định rằng chức năng chính thực sự sẽ là một lệnh nhấp chuột. Trình trang trí này sau đó sẽ tạo một đối tượng lệnh mới [xem lớp click. Lệnh để biết thêm chi tiết]. Đối số trợ giúp rất quan trọng vì nhấp chuột sẽ, trừ khi được chỉ định khác, tự động thêm tùy chọn trợ giúp [--help] vào tập lệnh


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.

Tiếp theo, chúng tôi xác định ba tùy chọn. tệp đầu vào, tệp đầu ra và khóa để sắp xếp các đối tượng JSON dựa trên


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]

Hãy xem xét tùy chọn đầu vào chi tiết hơn một chút. Chúng tôi xác định một tùy chọn ngắn - một tùy chọn dài --input và infile là tên của đối số hàm mà tùy chọn này đại diện. Cả hai điều này đều không bắt buộc; . Nhấp chuột sẽ sử dụng tên tùy chọn để xác định chúng

Tham số mặc định cho chúng ta biết giá trị mặc định là gì. Nếu không được cung cấp, giá trị mặc định sẽ luôn là Không có. Thay vào đó, nếu chúng tôi muốn nhấp để đưa ra lỗi cho một tùy chọn bị thiếu, chúng tôi có thể sử dụng đối số required=True

Tham số loại cho tùy chọn biết giá trị thô do dòng lệnh cung cấp sẽ được xử lý như thế nào. Nếu không được cung cấp, chỉ cần giá trị chuỗi sẽ được chuyển đến hàm. Loại có thể gọi được, như hàm, hàm tạo lớp hoặc loại nhấp chuột tùy chỉnh, như nhấp chuột. Tệp, sẽ mở tệp sau khi kiểm tra xem nó có tồn tại không, có thể mở được không, v.v.

Tham số phổ biến cuối cùng là trợ giúp, giống như trong trường hợp của lệnh, sẽ là chuỗi trợ giúp cho tùy chọn dòng lệnh đã cho. Cho đến nay, nó khá dễ dàng, nhưng có rất nhiều tùy chọn khác cho phép bạn tinh chỉnh cách các tùy chọn được xử lý. Chúng được mô tả chi tiết trong tài liệu nhấp chuột, được viết rất hay và hữu ích

Cho đến nay, nó khá dễ dàng, nhưng nhiều tùy chọn khác cho phép bạn tinh chỉnh cách các tùy chọn được xử lý. Những điều này được mô tả chi tiết trong tài liệu nhấp chuột, được viết rất hay và hữu ích

Nhiều lệnh

Đôi khi một tập lệnh cần có nhiều lệnh có thể được gọi riêng. Có thể bạn có một tập lệnh có thể thực hiện nhiều thao tác trên cùng một dữ liệu hoặc có thể bạn muốn toàn bộ mã của mình có một điểm vào duy nhất

Để làm điều này, chúng tôi sử dụng nhấp chuột. Nhóm đối tượng. Đối tượng nhóm chỉ là một tập hợp các lệnh có thể được gọi từ dòng lệnh chỉ bằng cách chuyển tên lệnh. Hãy xem xét ví dụ json_ops. py


import json, sys, click

main = click.Group[help="JSON tools"]

@main.command["key", help="Get key from JSON object"]
@click.option["-i", "--input", "infile", type=click.File[], default=sys.stdin, help="Input file name"]
@click.option["-o", "--output", "outfile", type=click.File["w"], default=sys.stdout, help="Output file name"]
@click.option["-k", "--key", required=True, help="Sorting key"]
def main_get_key[infile, outfile, key]:
    data = json.load[infile]
    data = data[key]
    json.dump[data, outfile]

@main.command["list-key", help="Get key from JSON list objects"]
@click.option["-i", "--input", "infile", type=click.File[], default=sys.stdin, help="Input file name"]
@click.option["-o", "--output", "outfile", type=click.File["w"], default=sys.stdout, help="Output file name"]
@click.option["-k", "--key", required=True, help="Sorting key"]
def main_get_list_key[infile, outfile, key]:
    data = json.load[infile]
    data = [obj[key] for obj in data if key in obj]
    json.dump[data, outfile]

if __name__ == "__main__":
    exit[main[]]

 

Tập lệnh này có hai lệnh rất giống nhau. cái đầu tiên lấy một đối tượng JSON và trích xuất khóa đã cho từ nó, trong khi cái thứ hai hoạt động trên một danh sách và trích xuất một khóa đã cho từ mỗi đối tượng bên trong nó và tạo danh sách các khóa đó

Hai sự khác biệt duy nhất là nhấp chuột. Nhóm đối tượng được khai báo [sẽ được gọi khi chúng ta muốn gọi lệnh] và đối tượng đó thay vì @click. lệnh chúng tôi sử dụng @main. lệnh để xác định các lệnh con. Tham số đầu tiên [e. g. , key] sẽ là tên của lệnh

Thí dụ


$ echo '{"key": 123, "values": [123, 456, 789]}' | python3 json_ops.py key -k values
[123, 456, 789]
$ echo '[{"key": 1}, {"key": 2}, {"key": 3}]' | python3 json_ops.py list-key -k "key"
[1, 2, 3]

Bây giờ đoạn mã trên có rất nhiều lần lặp lại; . Với key thì cũng dễ hiểu thôi, tuy tên giống nhau nhưng về ngữ nghĩa thì không hoàn toàn giống nhau. trong trường hợp đầu tiên, nó là khóa của đối tượng JSON, trong khi ở trường hợp thứ hai, nó là khóa của các đối tượng JSON bên trong danh sách. Nhưng làm cách nào để chúng tôi 'đánh dấu' các tùy chọn đó là chung cho cả hai lệnh phụ? . nhóm trang trí, chúng ta có thể cấu trúc lại mã


@click.group[help="JSON tools"]
@click.option["-i", "--input", "infile", type=click.File[], default=sys.stdin, help="Input file name"]
@click.option["-o", "--output", "outfile", type=click.File["w"], default=sys.stdout, help="Output file name"]
def main[infile, outfile]:
    pass

@main.result_callback[]
def main_cb[operation, infile, outfile]:
    data = json.load[infile]
    data = operation[data]
    json.dump[data, outfile]

@main.command["key", help="Get key from JSON object"]
@click.option["-k", "--key", required=True, help="Sorting key"]
def main_get_key[key]:
    return lambda data: data[key]

@main.command["list-key", help="Get key from JSON list objects"]
@click.option["-k", "--key", required=True, help="Sorting key"]
def main_get_key[key]:
    return lambda data: [obj[key] for obj in data if key in obj]


Và để gọi nó

________số 8_______

Một lần nữa, hãy nhìn vào những gì đang xảy ra. Đầu tiên, chúng tôi sử dụng nhấp chuột. nhóm giống như cách chúng tôi đã sử dụng nhấp chuột. yêu cầu. Trong trường hợp này, các tùy chọn --input và --output phải được gọi trước các lệnh phụ. Giá trị của các tùy chọn này sẽ được chuyển đến hàm chính, hàm này sẽ được thực thi trước chính các lệnh phụ

Tình cờ đây cũng là lý do chúng ta muốn trì hoãn làm bất kỳ công việc nào càng lâu càng tốt. chức năng nhóm sẽ được gọi sớm, ngay cả trước khi tùy chọn trợ giúp được đánh giá. Vì vậy, trừ khi chúng tôi muốn chạy một cái gì đó ngay cả trước khi trợ giúp chạy, chúng tôi cần phải lười biếng nhất có thể và chỉ thực hiện xử lý khi kết thúc. Một nhấp chuột triết lý thường theo sau chính nó

Ví dụ: tệp bên ngoài sẽ không được mở - và do đó được tạo - cho đến khi thao tác ghi đầu tiên được gọi trên đối tượng tệp. Hành vi có thể được kiểm soát bởi tùy chọn lười biếng. nhấp chuột. File[lazy=True] sẽ trì hoãn việc mở tệp càng nhiều càng tốt trong khi nhấp. File[lazy=False] sẽ buộc phải mở tệp ngay lập tức. Nếu không được chỉ định, như trong ví dụ của chúng tôi, nhấp chuột sẽ tự quyết định khi lười biếng tạo ra hoặc không có ý nghĩa

Bây giờ hãy xem cách chúng ta định nghĩa một lệnh


@main.command["key", help="Get key from JSON object"]
@click.option["-k", "--key", required=True, help="Sorting key"]
def main_get_key[key]:
    return lambda data: data[key]

Ở đây, chúng tôi không thực hiện thao tác thực tế mà trả về một hàm có thể xử lý dữ liệu và trả về một giá trị. Trong trường hợp này, chúng ta chỉ cần trả về một hàm trả về khóa đã cho của từ điển đã truyền. Sau này, chúng ta sẽ có thể sử dụng chức năng này để thực hiện bất kỳ thao tác nào chúng ta muốn trên dữ liệu

Để làm được điều này, chúng ta cần xác định cách xử lý kết quả của các hàm lệnh phụ. Chúng ta có thể sử dụng trình trang trí result_callback[] của đối tượng nhóm


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
0

Ở đây, chúng tôi nói với nhóm chính rằng chúng tôi muốn bất kỳ kết quả nào được trả về bởi các lệnh phụ sau khi chúng được thực thi sẽ được chuyển đến hàm main_cb được trang trí. Hàm này sau đó sẽ được gọi với kết quả là hàm của lệnh con trả về cộng với các đối số tương ứng với các tùy chọn khác nhau [infile và outfile]. Trong trường hợp của chúng tôi, điều đó có nghĩa là kết xuất đối tượng kết quả vào một tệp [hoặc đầu ra tiêu chuẩn, nếu tùy chọn không được cung cấp]

Đây là phần thực tế của công việc. chúng tôi tải nội dung trong tệp, thực hiện thao tác trên dữ liệu đã tải và kết xuất kết quả vào một tệp mới

Và một cách tự nhiên, tùy chọn --help cũng hoạt động ở đây, cho cả tập lệnh và các lệnh riêng lẻ


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
1

Bối cảnh và đối tượng người dùng

Đôi khi chỉ trả về một cái gì đó từ các lệnh phụ là không đủ và phải được xử lý trong chức năng lệnh phụ. Chúng ta thường cần truyền một số đối tượng mà chúng ta đã xác định cho các lệnh con. Nhập nhấp chuột. Bối cảnh. Đối tượng ngữ cảnh này sẽ chứa thông tin ngữ cảnh của việc thực thi lệnh. các đối tượng do người dùng xác định, các tùy chọn được định cấu hình, lệnh hiện đang được thực thi, v.v. Hiện tại, chúng tôi chỉ quan tâm đến đối tượng do người dùng định nghĩa

Hãy viết lại ví dụ trên để sử dụng một đối tượng như vậy. Chúng tôi muốn một cái gì đó chứa tệp đầu vào, tệp đầu ra và một phương thức có thể chuyển đổi dữ liệu đó và sau đó ghi ngay vào tệp đầu ra. Vì vậy, hãy để lớp này được gọi là UserContext


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
2

 

Đây là một đối tượng thực sự đơn giản. nó có hai tệp là thành viên và một quy trình sẽ thực hiện giống như bộ xử lý hậu kỳ của chúng tôi trong ví dụ trước. Chúng tôi thực hiện một thao tác trên dữ liệu đã tải và ghi kết quả vào tệp đầu ra

Chúng ta cần khởi tạo nó với nhóm trước


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
3

Lưu ý rằng chúng ta vẫn còn lười biếng. chúng tôi chỉ lưu trữ các tùy chọn chúng tôi có nhưng chưa làm bất cứ điều gì với nó. Đối tượng này sau đó sẽ được sử dụng từ các lệnh


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
4

 

Điều khác biệt duy nhất là thay vì trả về lambda, chúng tôi chuyển nó tới UserContext. phương thức xử lý, sẽ làm mọi thứ khác

Đường ống lệnh

Bây giờ, giả sử chúng ta giới thiệu một lệnh phụ mới gọi là tổng cho ví dụ đầu tiên


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
5



Điều này sẽ đơn giản cộng mọi dữ liệu trong danh sách JSON lại với nhau. Hàm này sẽ giả định rằng dữ liệu sẽ là một danh sách chứa các số.


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
6

 

Nhưng điều gì sẽ xảy ra nếu chúng ta có một JSON phức tạp hơn, chẳng hạn như một danh sách các đối tượng. Chúng tôi muốn có thể lấy khóa từ một đối tượng JSON và tính tổng trên đó hoặc có thể tính tổng các trường đã cho trên một đối tượng. Để làm điều này, chúng tôi cần tạo một tệp cho bất kỳ bước ngay lập tức nào hoặc kết hợp các kết quả lại với nhau


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
7

 
Cả hai đều khá khó sử dụng và không dễ sử dụng. Sẽ thật tuyệt nếu có thể gọi các lệnh cùng nhau, như thế này


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
8

Tin tốt là chúng ta không phải làm bất cứ điều gì cầu kỳ, chỉ cần sửa đổi một số chức năng. Đầu tiên, hãy xem chúng ta cần làm gì với chức năng chính


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' > test-order.json
$ python3 json_sorter.py -i test-order.json
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
9

Hai điều xảy ra ở đây. chain=True báo cho nhóm biết rằng nhiều lệnh có thể được thực hiện nối tiếp nhau, trong khi invoke_without_command=True báo cho nhấp chuột rằng nhóm có thể được gọi mà không cần bất kỳ lệnh phụ nào. Với tùy chọn thứ hai, chúng ta có thể gọi tập lệnh mà không cần bất kỳ lệnh con nào. Trong trường hợp của chúng tôi, điều này sẽ không làm gì khác ngoài việc sao chép đầu vào sang đầu ra

Bây giờ vì chúng tôi thực thi nhiều lệnh thay vì một lệnh, nên chúng tôi không chỉ thực hiện thao tác cho một lệnh con được gọi, mà tất cả chúng, trong một danh sách


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
0

 
Chúng tôi chỉ đơn giản thực hiện các hoạt động theo thứ tự chúng tôi nhận được và thế là xong. Chúng tôi có chính xác những gì chúng tôi muốn lúc đầu. Cá nhân tôi nghĩ rằng đó là một cách khá đơn giản và tao nhã để đạt được kết quả linh hoạt và hữu ích như vậy

Tùy chọn và đối số

Bây giờ hãy nói về các tùy chọn và đối số. Chúng tôi đã thấy một số trường hợp sử dụng rất cơ bản trong đó chúng tôi muốn mở hai tệp và một số chuỗi cho tên khóa được chuyển. Tuy nhiên, các tùy chọn mạnh hơn nhiều so với điều này và có thể làm được nhiều việc

Đầu tiên, hãy phân biệt quyền chọn và đối số. Các tùy chọn thường trông giống như --option value hoặc cho các tùy chọn ngắn -o value. Thứ tự mà chúng được đưa ra không quan trọng, trong khi các đối số được đưa ra theo trình tự sau khi các tùy chọn đã được xử lý. Lấy ví dụ sau


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
1

Trong trường hợp này --option opt1 và -s opt2 là các tùy chọn và được xác định bởi @click đã trình bày trước đó. trình trang trí tùy chọn, trong khi arg1, arg2 và arg3 là các đối số được xác định bằng @click. tranh luận

Tranh luận

Hãy lấy một ví dụ đơn giản nhất [tôi sẽ bỏ qua bản soạn sẵn từ đây trở đi, vì vậy bạn sẽ phải tự mình thực hiện các thao tác nhập và gọi chính]


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
2

Nếu chúng tôi yêu cầu trợ giúp về tập lệnh này, chúng tôi sẽ thấy phần sau


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
3

Ở đây chúng tôi chỉ lấy một đối số bắt buộc duy nhất với kiểu float và chỉ cần in nó. Bây giờ chúng ta có thể tính tổng của một số, chính là số đó. Vì vậy, tập lệnh đã đúng về mặt kỹ thuật cho trường hợp chúng ta có một số duy nhất và tất cả chúng ta đều biết rằng đúng về mặt kỹ thuật là loại chính xác tốt nhất

Nhưng nó không hữu ích lắm. Hãy mở rộng ví dụ một chút và cũng cho phép các số không, trong trường hợp đó tổng bằng không


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
4

Ah, người bạn cũ của chúng tôi, được yêu cầu. Ở đây, theo mặc định, một đối số là bắt buộc, vì vậy chúng ta phải chỉ định required=False nếu chúng ta muốn có một đối số tùy chọn. Nếu không được cung cấp, chúng tôi sẽ nhận được Không một lần nữa, vì vậy chúng tôi phải đảm bảo rằng chúng tôi in số float trong cả hai trường hợp

Bây giờ, giả sử chúng ta thực sự muốn điều này hữu ích và chấp nhận số lượng đối số tùy ý [không bao gồm]


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
5

Trong trường hợp này, theo mặc định, không cần đối số. Harga[3]  cho đối số biết có bao nhiêu đối số được yêu cầu. -1 là trường hợp đặc biệt, nó có nghĩa là bất kỳ số lượng đối số nào. Ngẫu nhiên, chúng ta cũng có thể thêm đối số required=True, vì vậy ít nhất một đối số được chuyển

tùy chọn đặc biệt

Có thể có các loại tùy chọn đặc biệt hữu ích trong các tình huống khác nhau

Giả sử chúng ta muốn triển khai ví dụ trên, nhưng thay vì sử dụng các đối số, chúng ta muốn sử dụng các tùy chọn. Giả sử rằng tùy chọn là -n / --number. Trong trường hợp này, chúng ta cần nhiều tùy chọn bằng cách sử dụng tham số multiple=True


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
6

Lưu ý rằng không giống như trước đây, khi không có số nào được chuyển, chúng tôi nhận được một bộ dữ liệu trống thay vì giá trị Không có, vì vậy chúng tôi có thể sử dụng tổng ngay lập tức

Một điều khác mà chúng tôi có thể muốn là một tùy chọn không cần giá trị, nơi chúng tôi chỉ quan tâm đến việc liệu nó có được xác định hay không. Đây được gọi là cờ và có thể được xác định bằng hai phương pháp khác nhau. Đầu tiên là bằng cách sử dụng tham số is_flag=True


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
7

 

Đôi khi chúng ta muốn có hai tùy chọn cho cùng một giá trị, một tùy chọn đại diện cho giá trị thực, giá trị còn lại là giá trị sai. Trong trường hợp trên, chúng tôi muốn có tùy chọn --sum để tính tổng và tùy chọn [4] --product có nghĩa là


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
8

Nếu chúng tôi chỉ định -p hoặc --product, chúng tôi sẽ lấy True làm đối số, nếu chúng tôi không chỉ định gì, -s hoặc --sum chúng tôi sẽ nhận được một khoản tiền

Các loại tùy chọn và đối số

Bây giờ chúng ta đã biết thêm một chút về các lệnh, nhóm, tùy chọn và đối số, hãy nói về các loại. Theo mặc định, khi nhấp chuột phân tích cú pháp đối số tùy chọn hoặc lệnh, giá trị sẽ được chuyển dưới dạng chuỗi mà không cần xử lý thêm. Đây không phải lúc nào cũng là điều chúng ta muốn, như chúng ta đã thấy trước đây

Các loại có hai "hương vị" khác nhau. " có thể gọi, sẽ xử lý giá trị và sau đó trả về chúng, và các lớp loại chuyên dụng, có thể làm được nhiều hơn một chút. Callables rất đơn giản. chuyển một hàm hoặc loại nhận giá trị làm tham số và trả về kết quả đã xử lý. Giả sử chúng ta muốn chuyển đổi các số trong ví dụ trên một cách im lặng thành Không có khi chúng không thể được chuyển đổi thành số float [giả sử chúng ta chuyển bốn thay vì 4 cho tùy chọn]


$ echo '[{"key": 98, "value": 123}, {"key": 76, "value": 456}]' | \
python3 json_sorter.py
[{"key": 76, "value": 456}, {"key": 98, "value": 123}]
9

Mặt khác, các lớp loại hữu ích hơn nhiều và nhấp chuột đi kèm với rất nhiều loại được xác định trước. Hãy cùng tham quan nhanh các loại này

Sự lựa chọn

Loại Lựa chọn dành cho khi có một hoặc nhiều giá trị tiềm năng có thể được chọn. Bất cứ điều gì không có trong danh sách các lựa chọn chấp nhận được sẽ tạo ra lỗi. Ví dụ về tổng hoặc tích có thể được viết lại để sử dụng một lựa chọn thay vì tùy chọn cờ


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
0

Trong ví dụ trên, nếu chúng ta chỉ định -t sum hoặc -t product, chúng ta sẽ nhận được tổng hoặc tích của các số tương ứng. Tham số case_sensitive=False cho biết lựa chọn - như tên ngụ ý - không phân biệt chữ hoa chữ thường

Các loại tích hợp khác

Các loại tham số tích hợp khác bao gồm

  • nhấp chuột. DateTime định dạng ngày hoặc ngày giờ theo mặc định tuân theo YYYY-MM-DD HH. MM. SS hoặc các định dạng tương tự có thể được tùy chỉnh. ‍
  • nhấp chuột. UUID sẽ phân tích cú pháp bất kỳ UUID hợp lệ nào và chuyển đổi nó thành uuid. Ví dụ đối tượng UUID. ‍
  • nhấp chuột. Tệp đã được hiển thị trước đây trong các ví dụ. Nó sẽ cố gắng mở một tệp để đọc, viết hoặc cả hai. ‍
  • nhấp chuột. Đường dẫn sẽ không mở tệp nhưng thực hiện các kiểm tra khác nhau đối với tham số đã cho [e. g. , kiểm tra xem tệp có tồn tại không, kiểm tra xem đó có phải là tệp chứ không phải thư mục, v.v. ]

các loại tùy chỉnh

Trong nhiều trường hợp, người ta có thể sử dụng các loại này, nhưng đôi khi chúng ta cần xử lý dữ liệu theo những cách phức tạp. Đối với các trường hợp đơn giản hơn, như chúng ta đã thấy trước đây, có thể sử dụng một hàm với một tham số duy nhất. Tuy nhiên, việc triển khai loại tham số nhấp chuột mới theo cách "thích hợp" cho phép chúng tôi kiểm soát nhiều hơn cách các tùy chọn này được xử lý

Giả sử rằng chúng tôi muốn mở rộng mã ban đầu của mình để tự động đọc tệp JSON từ tùy chọn tệp đã cho và chuyển trực tiếp dữ liệu đã tải. Đối với bất kỳ lỗi nào chúng tôi gặp phải, chúng tôi muốn nhấp để thông báo cho người dùng rằng tệp đó là tệp JSON không hợp lệ


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
1

Đầu tiên, chúng tôi kế thừa từ lần nhấp. Tùy chọn tệp, vì chúng tôi muốn làm việc trên các tệp JSON có thể đọc được. Tệp Json. phương thức chuyển đổi sẽ được gọi khi tùy chọn đang được chuyển đổi. Tham số giá trị sẽ là giá trị tùy chọn chưa được xử lý và tham số param sẽ là phiên bản đối số hoặc tùy chọn [có thể là một lần nhấp. Tùy chọn hoặc một cú nhấp chuột. Ví dụ đối số]. Cuối cùng, tham số ctx là bối cảnh thực hiện nhấp chuột hiện đang hoạt động [nhấp chuột. đối tượng ngữ cảnh]

Một điều thú vị nữa là tiếng gọi tự. không thành công, điều này sẽ làm tăng ngoại lệ dành riêng cho lần nhấp. Sau đó, ngoại lệ này sẽ được sử dụng để hiển thị lỗi nếu đầu vào không phải là tệp JSON hợp lệ, e. g


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
2

Lập luận và giá trị môi trường

Đôi khi, chúng tôi gặp tình huống mà chúng tôi có thể muốn cho phép người dùng đưa ra một số hoặc tất cả các đối số dưới dạng biến môi trường. Hoặc có thể chúng tôi có một số tùy chọn không thay đổi nhiều và chúng tôi muốn đặt một biến môi trường rồi sử dụng tập lệnh mà không chỉ định lặp đi lặp lại cùng một tham số

Để hiển thị điều này, hãy viết một tập lệnh nhỏ lấy tên người dùng, xử lý tệp /etc/passwd và in ra trình bao được người dùng sử dụng. Như một phụ lục. nếu bạn không quen thuộc với các hệ thống dựa trên UNIX, thì tệp /etc/passwd là một tệp được phân tách bằng dấu hai chấm chứa, trong số những thứ khác, tên người dùng, mã định danh số duy nhất của họ và trình bao bắt đầu khi người dùng đăng nhập và . Nó rất giống với tệp CSV tiêu chuẩn không có thật

Trong Python, một gói tích hợp tiện dụng có thể tra cứu người dùng trong tệp văn bản này. mô-đun pwd. Chức năng chúng tôi muốn là pwd. getpwnam, tra cứu một mục dựa trên tên và trả về một đối tượng có dữ liệu cần thiết. Để biết thêm thông tin, đọc

Tại thời điểm này, chúng ta sẽ có thể tạo chương trình cần thiết với những gì chúng ta đã học được cho đến nay


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
3

Điều này sẽ hiển thị shell cho bất kỳ người dùng nào chúng tôi muốn. Khi tôi chạy ứng dụng này, tôi nhận được đầu ra sau. ű


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
4

Cho đến nay, thật nhàm chán, nhưng điều gì sẽ xảy ra nếu chúng ta thường chỉ muốn kiểm tra vỏ của chính mình, vì lý do gì? . Sẽ thật tuyệt nếu chúng ta có thể sử dụng biến môi trường này làm biến môi trường mặc định. Tất nhiên, chúng ta có thể sử dụng default=os. tuy nhiên, tham số envvar["USER"] sẽ giải quyết biến môi trường quá sớm. Vì vậy, hãy yêu cầu click sử dụng biến môi trường khi có thể


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
5

Bằng cách này, nếu tôi không cung cấp tên người dùng, tôi sẽ nhận được trình bao của riêng mình


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
6

Trường hợp sử dụng thông thường của tôi cho việc này là khi tôi có một số tham số thường được để lại để sử dụng giá trị mặc định, nhưng đôi khi tôi muốn thay đổi nó. Có lẽ tôi đang chuyển cấu hình cho tập lệnh của mình. Tập lệnh này luôn giống nhau, nhưng khi tôi đang thử nghiệm, tôi muốn sử dụng một cấu hình thay thế. Thêm một tham số mỗi khi tôi gọi tập lệnh sẽ rất cồng kềnh, vì vậy tôi chỉ cần đặt biến môi trường

Thí dụ


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
7

Trong trường hợp này, theo mặc định, chúng tôi sử dụng ~/. tập tin cấu hình script-config, nhưng có thể ghi đè lên nó bằng một tùy chọn hoặc một biến môi trường


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
8

 

Nhắc theo mặc định

Như thể những tùy chọn có thể tự động làm cho chúng tôi là không đủ, còn có tùy chọn cho biết nhấp chuột để hỏi người dùng theo mặc định về lời nhắc cho một giá trị. Giả sử chúng tôi muốn hỏi người dùng tên người dùng nếu tên người dùng không được chỉ định


$ python3 json_sorter.py --help
Usage: json_sorter.py [OPTIONS]

  JSON sorter

Options:
  -i, --input FILENAME   Input file name
  -o, --output FILENAME  Output file name
  -k, --key TEXT         Sorting key  [default: key]
  --help                 Show this message and exit.
9

Điều này cũng dễ dàng thực hiện bằng cách nhấp chuột, sử dụng tham số nhắc cho nhấp chuột. lựa chọn


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]
0

Cũng có thể nhắc mật khẩu mà không cần phải quảng cáo nhiều. chỉ cần sử dụng tham số hide_input=True


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]
1

Hoàn thành vỏ tự động

Tính năng này là yêu thích của tôi, mặc dù tôi không sử dụng nó nhiều. Nhưng khi bạn có một tập lệnh lớn với nhiều tùy chọn mà bạn không sử dụng đủ thường xuyên để ghi nhớ và không muốn tiếp cận tài liệu mỗi khi bạn cần biết điều gì đó, thì sẽ rất hữu ích khi có một số loại chức năng tự động hoàn thành

Viết chức năng như vậy theo cách thủ công không phải là một nhiệm vụ đơn giản, nhưng may mắn thay, click cung cấp một cách để thực hiện. Hiện tại, ba vỏ được hỗ trợ. bash, cá và zsh. Vì bash là shell phổ biến nhất, chúng tôi sẽ sử dụng nó làm ví dụ

Trước khi tiếp tục, tôi phải đề cập đến một hạn chế của tính năng tự động hoàn thành. nó dường như chỉ hoạt động khi tập lệnh được cài đặt, ví dụ: nếu chúng ta có tập lệnh có tên getuser được cài đặt vào đường dẫn được liệt kê trong biến môi trường PATH

Gọi tập lệnh có bộ biến môi trường đặc biệt sẽ tạo tập lệnh tự động hoàn thành


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]
2

Sau đó, tập lệnh được tạo có thể được lưu trữ trong một tệp hoặc được tạo mỗi khi cần trong. tập tin bashrc


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]
3

Thậm chí tốt hơn, chúng ta có thể viết phần hoàn thành của riêng mình khá dễ dàng. Giả sử chúng tôi chỉ muốn tự động hoàn thành các tệp có phần mở rộng nhất định. Vì vậy, trong json_ops, chúng tôi muốn tự động điền tên thư mục và tên tệp kết thúc bằng. json

Tự động hoàn thành tùy chọn được xử lý trong các lớp loại nhấp chuột


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]
4

Phương thức shell_complete[] sẽ trả về tất cả các giá trị đã hoàn thành tiềm năng dựa trên tham số chưa hoàn thành. Đây sẽ là một phần của đối số đã được nhập cho đến nay, một tiền tố cho tất cả các giá trị tiềm năng

Vì vậy, những gì ở trên làm gì? . Nếu danh sách tệp kết quả chỉ chứa một thư mục, chúng tôi cần coi đó là tiền tố vì thư mục không phải là "giải pháp" hợp lệ và cần được xử lý thêm

Mặc dù phương pháp này có vẻ hơi phức tạp, nhưng nó vẫn đơn giản hơn nhiều so với thực hiện thủ công. Và trong hầu hết các trường hợp, chúng ta không cần sử dụng nhiều, nhưng nó luôn là điều nên ghi nhớ

Tích hợp công cụ thiết lập

Một điều khác tôi thường khuyên là tạo một thiết lập. py cho kịch bản. File setup này nhiều lúc có vẻ hơi nhiều nhưng chỉ vài thứ cần thiết thôi. tên cho dự án, phiên bản, gói hoặc mô-đun Python để cài đặt và có khả năng là bất kỳ phụ thuộc nào

Tích hợp tập lệnh bằng cách nhấp vào đây thực sự dễ dàng. giống như nó sẽ là khác. Hãy xem xét thiết lập này. py cho ứng dụng json_ops của chúng tôi


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]
5

Phần thú vị là entry_points. Chủ đề về điểm vào nằm ngoài phạm vi của bài đăng trên blog này, nhưng bài đăng trên blog này giải thích chi tiết về nó. Đối với mục đích của chúng tôi, mọi thứ trong phần console_scripts sẽ được chuyển đổi khi cài đặt thành tập lệnh. the"json-ops = json_ops. main", có nghĩa là chúng ta sẽ có một tệp thực thi có tên json-ops trong đường dẫn tệp thực thi [e. g. /usr/bin nếu chúng tôi đã cài đặt nó với quyền root hoặc ~/. local/bin nếu chúng tôi đã cài đặt nó với tư cách người dùng]

Hạn chế

Giống như tất cả mọi thứ, nhấp chuột có một số hạn chế. Một trong những điều rõ ràng nhất mà tôi gặp phải cho đến nay là thiếu các nhóm tùy chọn loại trừ lẫn nhau


@click.option[
    "-i",
    "--input",
    "infile",
    type=click.File[],
    default=sys.stdin,
    help="Input file name"
]
6

Đáng buồn thay, mã ở trên, sẽ cho phép --path hoặc --file được chỉ định, nhưng không phải cả hai cùng một lúc, hiện không thể giải được bằng các công cụ nhấp tích hợp sẵn;

Và thế là xong nhé mọi người

Mặc dù có nhiều thứ khác để nhấp mà chúng tôi chưa đề cập đến, chẳng hạn như xử lý đầu vào của người dùng, xử lý ngoại lệ hoặc các chức năng tiện ích khác nhau, nhưng phạm vi của một bài đăng trên blog không đủ để bao hàm tiện ích rất linh hoạt này. Người ta có thể triển khai hầu hết mọi tập lệnh, nhỏ hay lớn, bằng cách sử dụng nhấp chuột. Với các công cụ được cung cấp, việc tạo các tập lệnh chuyên nghiệp/có giao diện, ngay cả khi chúng chỉ được sử dụng một hoặc hai lần, thật dễ dàng

Cá nhân, bây giờ, tôi thậm chí không sử dụng bất cứ thứ gì khác. Làm việc với argparse hoặc getopt không hề đơn giản hơn và chúng không cung cấp thêm chức năng nào. Và làm việc trực tiếp với sys. argv không được khuyến nghị vì cuối cùng bạn sẽ luôn thực hiện lại bánh xe. Hay đúng hơn, nhấp vào

Nhấp chuột [] trong Python là gì?

nhấp vào 8. 1. 3 . Đó là “Bộ công cụ tạo giao diện dòng lệnh”. a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It's the “Command Line Interface Creation Kit”.

Làm cách nào để cài đặt nhấp vào Python?

Làm cách nào để cài đặt nhấp vào Linux? .
Mở thiết bị đầu cuối hoặc trình bao Linux của bạn
Gõ “pip install click” [không có dấu ngoặc kép], nhấn Enter
Nếu nó không hoạt động, hãy thử "pip3 install click" hoặc “ python -m pip install click “
Đợi quá trình cài đặt kết thúc thành công

Nhấp chuột PIP là gì?

PicClick là trang web cho phép bạn tìm kiếm trực quan trên eBay . Nó nhanh hơn tìm kiếm trên eBay và trả về một trang hình ảnh cuộn vô hạn trong vài giây. Thay vì một danh sách hoặc chế độ xem thư viện trên chính eBay, nó cho phép người dùng quét hàng trăm kết quả tìm kiếm để thu hút sự chú ý vào các mục quan tâm.

Sự khác biệt giữa nhấp chuột và Argparse là gì?

Argparse được thiết kế để phân tích các đối số và cung cấp khả năng tùy chỉnh mở rộng tài liệu trợ giúp cli. Click được thiết kế để tự động xử lý các tác vụ lệnh cli phổ biến và nhanh chóng xây dựng menu trợ giúp tiêu chuẩn

Chủ Đề