paint-brush
Cách tạo chương trình Python CLI để quản lý Trello Board (Phần 1)từ tác giả@elainechan01
2,360 lượt đọc
2,360 lượt đọc

Cách tạo chương trình Python CLI để quản lý Trello Board (Phần 1)

từ tác giả Elaine Yun Ru Chan19m2023/08/15
Read on Terminal Reader

dài quá đọc không nổi

Như đã nêu trên Wikipedia, “Giao diện dòng lệnh (CLI) là phương tiện tương tác với thiết bị hoặc chương trình máy tính bằng các lệnh từ người dùng hoặc máy khách và phản hồi từ thiết bị hoặc chương trình, dưới dạng các dòng văn bản.” Nói cách khác, chương trình CLI là chương trình mà người dùng sử dụng dòng lệnh để tương tác với chương trình bằng cách cung cấp hướng dẫn để thực thi. Nhiều phần mềm hàng ngày được gói dưới dạng chương trình CLI. Lấy ví dụ về trình soạn thảo văn bản vim - một công cụ đi kèm với bất kỳ hệ thống UNIX nào có thể được kích hoạt đơn giản bằng cách chạy vim <FILE> trong thiết bị đầu cuối. Liên quan đến Google Cloud CLI, hãy đi sâu vào giải phẫu của chương trình CLI.
featured image - Cách tạo chương trình Python CLI để quản lý Trello Board (Phần 1)
Elaine Yun Ru Chan HackerNoon profile picture
0-item

Tuyên bố miễn trừ trách nhiệm: Hướng dẫn này giả định rằng người đọc đã có kiến thức cơ bản về Python, API, Git và Bài kiểm tra đơn vị.

Tôi đã xem qua nhiều phần mềm CLI khác nhau với những hình ảnh động thú vị nhất và điều đó khiến tôi băn khoăn - liệu tôi có thể nâng cấp dự án trường học oẳn tù tì 'tối giản' của mình không?


Hi, chúng ta hãy chơi! Chọn máy bay chiến đấu của bạn (oẳn tù tì, kéo): đá

Chương trình CLI là gì?

Như đã nêu trên Wikipedia, “Giao diện dòng lệnh (CLI) là phương tiện tương tác với thiết bị hoặc chương trình máy tính bằng các lệnh từ người dùng hoặc máy khách và phản hồi từ thiết bị hoặc chương trình, dưới dạng các dòng văn bản.”


Nói cách khác, chương trình CLI là chương trình mà người dùng sử dụng dòng lệnh để tương tác với chương trình bằng cách cung cấp hướng dẫn để thực thi.


Nhiều phần mềm hàng ngày được gói dưới dạng chương trình CLI. Lấy ví dụ về trình soạn thảo văn bản vim - một công cụ đi kèm với bất kỳ hệ thống UNIX nào có thể được kích hoạt đơn giản bằng cách chạy vim <FILE> trong thiết bị đầu cuối.


Liên quan đến Google Cloud CLI , hãy đi sâu vào giải phẫu của một chương trình CLI.

Tranh luận

Đối số (Tham số) là các mục thông tin được cung cấp cho một chương trình. Nó thường được gọi là đối số vị trí vì chúng được xác định bởi vị trí của chúng.


Ví dụ: khi chúng tôi muốn đặt thuộc tính project trong phần cốt lõi, chúng tôi chạy gcloud config set project <PROJECT_ID>


Đáng chú ý, chúng ta có thể dịch điều này thành

Lý lẽ

Nội dung

Đối số 0

gcloud

Đối số 1

cấu hình

lệnh

Các lệnh là một mảng các đối số cung cấp hướng dẫn cho máy tính.


Dựa trên ví dụ trước, chúng tôi đặt thuộc tính project trong phần cốt lõi bằng cách chạy gcloud config set project <PROJECT_ID>


Nói cách khác, set là một lệnh.

Lệnh tùy chọn

Thông thường, các lệnh là bắt buộc nhưng chúng ta có thể tạo ra các ngoại lệ. Dựa trên trường hợp sử dụng của chương trình, chúng ta có thể xác định các lệnh tùy chọn.


Quay lại lệnh gcloud config , như đã nêu trong tài liệu chính thức của họ, gcloud config là một nhóm lệnh cho phép bạn sửa đổi các thuộc tính. Việc sử dụng là như vậy:

 gcloud config GROUP | COMMAND [GCLOUD_WIDE_FLAG … ]

theo đó LỆNH có thể là set , list , v.v. (Lưu ý rằng GROUP là config )

Tùy chọn

Các tùy chọn là các loại tham số được ghi lại để sửa đổi hành vi của một lệnh. Chúng là các cặp khóa-giá trị được biểu thị bằng '-' hoặc '--'.


Quay lại việc sử dụng nhóm lệnh gcloud config , (các) tùy chọn, trong trường hợp này, là GCLOUD_WIDE_FLAG .


Ví dụ: giả sử rằng chúng tôi muốn hiển thị cách sử dụng và mô tả chi tiết của lệnh, chúng tôi chạy gcloud config set –help . Nói cách khác, --help là tùy chọn.


Một ví dụ khác là khi chúng tôi muốn đặt thuộc tính vùng trong phần tính toán của một dự án cụ thể, chúng tôi chạy gcloud config set compute <ZONE_NAME> –project=<PROJECT_ID> . Nói cách khác, --project là một tùy chọn chứa giá trị <PROJECT_ID> .


Cũng cần lưu ý rằng vị trí của họ thường không quan trọng.

Tùy chọn bắt buộc

Các tùy chọn, giống như tên của nó, thường là tùy chọn, nhưng cũng có thể được điều chỉnh để trở thành bắt buộc.


Ví dụ: khi chúng tôi muốn tạo một cụm dataproc, chúng tôi chạy gcloud dataproc clusters create <CLUSTER_NAME> –region=<REGION> . Và như đã nêu trong tài liệu sử dụng của họ:

 gcloud dataproc clusters create (CLUSTER: –region=REGION)

Cờ --region là bắt buộc nếu nó chưa được định cấu hình trước đó.

Tùy chọn ngắn so với Tùy chọn dài

Các tùy chọn ngắn bắt đầu bằng - theo sau là một ký tự chữ và số, trong khi các tùy chọn dài bắt đầu bằng -- theo sau là nhiều ký tự. Hãy coi các tùy chọn ngắn là lối tắt khi người dùng chắc chắn về những gì họ muốn trong khi các tùy chọn dài dễ đọc hơn.


Bạn đã chọn đá! Bây giờ máy tính sẽ thực hiện lựa chọn của nó.

Chúng ta sẽ đạt được gì thông qua hướng dẫn này?

Vì vậy, tôi đã nói dối… Chúng tôi sẽ không cố gắng nâng cấp chương trình CLI oẳn tù tì.

Thay vào đó, chúng ta hãy xem xét một kịch bản trong thế giới thực:

Đề cương và Mục tiêu

Nhóm của bạn sử dụng Trello để theo dõi các vấn đề và tiến độ của dự án. Nhóm của bạn đang tìm kiếm một cách đơn giản hơn để tương tác với bảng - tương tự như việc tạo kho lưu trữ GitHub mới thông qua thiết bị đầu cuối. Nhóm đã nhờ bạn tạo một chương trình CLI với yêu cầu cơ bản này là có thể thêm thẻ mới vào cột 'Việc cần làm' trên bảng.


Dựa trên yêu cầu đã đề cập, hãy phác thảo chương trình CLI của chúng tôi bằng cách xác định các yêu cầu của nó:


Yêu cầu chức năng

  • Người dùng có thể thêm một thẻ mới vào một cột trên bảng
    • Đầu vào bắt buộc: cột, tên thẻ
    • Đầu vào tùy chọn: mô tả thẻ, nhãn thẻ (chọn từ hiện có)

Những yêu cầu phi lý

  • Chương trình nhắc người dùng cung cấp quyền truy cập vào tài khoản Trello (ủy quyền)
  • Chương trình nhắc người dùng đặt bảng Trello nào sẽ hoạt động (cấu hình)

Yêu cầu tùy chọn

  • Người dùng có thể thêm một cột mới vào bảng
  • Người dùng có thể thêm nhãn mới vào bảng
  • Người dùng có thể thấy chế độ xem đơn giản/chi tiết của tất cả các cột


Dựa trên những điều trên, chúng ta có thể chính thức hóa các lệnh và tùy chọn của chương trình CLI của mình như sau:

Xem bảng chi tiết cấu trúc CLI dựa trên yêu cầu


Ps Đừng lo lắng về hai cột cuối cùng, chúng ta sẽ tìm hiểu về nó sau…


Đối với ngăn xếp công nghệ của chúng tôi, chúng tôi sẽ gắn bó với điều này:


bài kiểm tra đơn vị

  • người khó tính
  • pytest-mock
  • cli-test-helpers

Trello

  • py-trello (Trello trình bao bọc cho Trello SDK)

CLI

  • người đánh máy
  • giàu có
  • đơn-thuật-đơn

Tiện ích (Khác)

  • python-dotenv

Mốc thời gian

Chúng tôi sẽ giải quyết dự án này theo từng phần và đây là một đoạn nhỏ về những gì bạn có thể mong đợi:


Phần 1

  • Triển khai logic nghiệp vụ py-trello

Phần 2

  • Triển khai logic nghiệp vụ CLI
  • Phân phối chương trình CLI dưới dạng gói

Phần 3

  • Thực hiện các yêu cầu chức năng tùy chọn
  • cập nhật gói


Máy tính đã chọn kéo! Hãy xem ai là người chiến thắng trong trận chiến này…

Bắt đầu nào

Cấu trúc thư mục

Mục tiêu là phân phối chương trình CLI dưới dạng gói trên PyPI . Vì vậy, một thiết lập như vậy là cần thiết:

 trellocli/ __init__.py __main__.py models.py cli.py trelloservice.py tests/ test_cli.py test_trelloservice.py README.md pyproject.toml .env .gitignore


Đây là phần đi sâu vào từng tệp và/hoặc thư mục:

  • trellocli : đóng vai trò là tên gói được người dùng sử dụng, ví dụ: pip install trellocli
    • __init__.py : đại diện cho thư mục gốc của gói, tuân thủ thư mục dưới dạng gói Python
    • __main__.py : xác định điểm vào và cho phép người dùng chạy các mô-đun mà không cần chỉ định đường dẫn tệp bằng cách sử dụng cờ -m , ví dụ: python -m <module_name> để thay thế python -m <parent_folder>/<module_name>.py
    • models.py : lưu trữ các lớp được sử dụng trên toàn cầu, ví dụ: các mô hình mà các phản hồi API dự kiến sẽ tuân theo
    • cli.py : lưu trữ logic nghiệp vụ cho các lệnh và tùy chọn CLI
    • trelloservice.py : lưu trữ logic nghiệp vụ để tương tác với py-trello
  • tests : lưu trữ các bài kiểm tra đơn vị cho chương trình
    • test_cli.py : lưu trữ các bài kiểm tra đơn vị để triển khai CLI
    • test_trelloservice.py : lưu trữ các bài kiểm tra đơn vị để tương tác với py-trello
  • README.md : lưu trữ tài liệu cho chương trình
  • pyproject.toml : lưu trữ các cấu hình và yêu cầu của gói
  • .env : lưu trữ các biến môi trường
  • .gitignore : chỉ định các tệp bị bỏ qua (không được theo dõi) trong quá trình kiểm soát phiên bản


Để có giải thích chi tiết hơn về việc xuất bản các gói Python, đây là một bài viết hay để xem: Cách xuất bản Gói Python mã nguồn mở lên PyPI của Geir Arne Hjelle

Cài đặt

Trước khi bắt đầu, chúng ta hãy chạm vào cơ sở thiết lập gói.


Bắt đầu với tệp __init__.py trong gói của chúng tôi, đây sẽ là nơi lưu trữ các biến và hằng số của gói, chẳng hạn như tên và phiên bản ứng dụng. Trong trường hợp của chúng tôi, chúng tôi muốn khởi tạo như sau:

  • tên ứng dụng
  • phiên bản
  • Các hằng SUCCESS và ERROR
 # trellocli/__init__.py __app_name__ = "trellocli" __version__ = "0.1.0" ( SUCCESS, TRELLO_WRITE_ERROR, TRELLO_READ_ERROR ) = range(3) ERRORS = { TRELLO_WRITE_ERROR: "Error when writing to Trello", TRELLO_READ_ERROR: "Error when reading from Trello" }


Chuyển sang tệp __main__.py , luồng chính của chương trình của bạn sẽ được lưu trữ tại đây. Trong trường hợp của chúng tôi, chúng tôi sẽ lưu trữ điểm vào chương trình CLI, giả sử rằng sẽ có một chức năng có thể gọi được trong cli.py .

 # trellocli/__main__.py from trellocli import cli def main(): # we'll modify this later - after the implementation of `cli.py` pass if __name__ == "__main__": main()


Bây giờ gói đã được thiết lập, hãy xem cập nhật tệp README.md của chúng tôi (tài liệu chính). Không có một cấu trúc cụ thể nào mà chúng ta phải tuân theo, nhưng một README tốt sẽ bao gồm những phần sau:

  • Tổng quan
  • Cài đặt và yêu cầu
  • Bắt đầu và sử dụng

Một bài đăng tuyệt vời khác để đọc nếu bạn muốn tìm hiểu sâu hơn: Cách viết một README hay của merlos


Đây là cách tôi muốn cấu trúc README cho dự án này

 <!--- README.md --> # Overview # Getting Started # Usage # Architecture ## Data Flow ## Tech Stack # Running Tests # Next Steps # References


Bây giờ hãy để nguyên bộ xương - chúng ta sẽ quay lại vấn đề này sau.


Tiếp tục, hãy định cấu hình siêu dữ liệu của gói dựa trên tài liệu chính thức

 # pyproject.toml [project] name = "trellocli_<YOUR_USERNAME>" version = "0.1.0" authors = [ { name = "<YOUR_NAME>", email = "<YOUR_EMAIL>" } ] description = "Program to modify your Trello boards from your computer's command line" readme = "README.md" requires-python = ">=3.7" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] dependencies = [] [project.urls] "Homepage" = ""


Lưu ý cách có các trình giữ chỗ mà bạn phải sửa đổi, ví dụ: tên người dùng, tên của bạn…


Một lưu ý khác, hiện tại chúng tôi sẽ để trống URL trang chủ. Chúng tôi sẽ thực hiện các thay đổi sau khi xuất bản nó lên GitHub. Hiện tại, chúng tôi cũng sẽ để trống phần phụ thuộc và thêm vào khi chúng tôi thực hiện.


Tiếp theo trong danh sách sẽ là tệp .env của chúng tôi, nơi chúng tôi lưu trữ các biến môi trường của mình, chẳng hạn như khóa và bí mật API. Điều quan trọng cần lưu ý là Git không nên theo dõi tệp này vì nó chứa thông tin nhạy cảm.


Trong trường hợp của chúng tôi, chúng tôi sẽ lưu trữ thông tin đăng nhập Trello của mình tại đây. Để tạo Power-Up trong Trello, hãy làm theo hướng dẫn này . Cụ thể hơn, dựa trên việc sử dụng py-trello , vì chúng tôi dự định sử dụng OAuth cho ứng dụng của mình, chúng tôi sẽ cần những thứ sau để tương tác với Trello:

  • Khóa API (cho ứng dụng của chúng tôi)
  • Bí mật API (cho ứng dụng của chúng tôi)
  • Mã thông báo (mã thông báo của người dùng để cấp quyền truy cập vào dữ liệu của họ)


Khi bạn đã truy xuất Khóa API và Bí mật của mình, hãy lưu trữ chúng trong tệp .env như vậy

 # .env TRELLO_API_KEY=<your_api_key> TRELLO_API_SECRET=<your_api_secret>


Cuối cùng nhưng không kém phần quan trọng, hãy sử dụng mẫu Python .gitignore có thể tìm thấy tại đây . Lưu ý rằng điều này rất quan trọng để đảm bảo rằng tệp .env của chúng tôi không bao giờ bị theo dõi - nếu tại một thời điểm nào đó, tệp .env của chúng tôi bị theo dõi, ngay cả khi chúng tôi đã xóa tệp ở các bước sau, thì thiệt hại vẫn được thực hiện và các tác nhân độc hại có thể lần theo dấu vết trước đó bản vá cho thông tin nhạy cảm.


Bây giờ, quá trình thiết lập đã hoàn tất, hãy đẩy các thay đổi của chúng tôi lên GitHub. Tùy thuộc vào siêu dữ liệu được chỉ định trong pyproject.toml , hãy nhớ cập nhật GIẤY PHÉP và URL trang chủ của bạn cho phù hợp. Để tham khảo về cách viết các cam kết tốt hơn: Viết các cam kết tốt hơn, Xây dựng các dự án tốt hơn của Victoria Dye


Các bước đáng chú ý khác:

bài kiểm tra đơn vị

Trước khi chúng tôi bắt đầu viết các bài kiểm tra của mình, điều quan trọng cần lưu ý là vì chúng tôi đang làm việc với một API nên chúng tôi sẽ triển khai các bài kiểm tra giả để có thể kiểm tra chương trình của mình mà không gặp rủi ro về thời gian ngừng hoạt động của API. Đây là một bài viết tuyệt vời khác về thử nghiệm mô phỏng bằng Python thực: Mocking APIs bên ngoài trong Python


Dựa trên các yêu cầu chức năng, mối quan tâm chính của chúng tôi là cho phép người dùng thêm thẻ mới. Tham khảo phương thức trong py-trello : add_card . Để có thể làm như vậy, chúng ta phải gọi phương thức add_card từ lớp List , phương thức này có thể được truy xuất từ hàm get_list từ lớp Board , phương thức này có thể được truy xuất…


Bạn nắm được ý chính - chúng ta sẽ cần rất nhiều phương pháp trợ giúp để đến đích cuối cùng, hãy diễn đạt thành lời:

  • Kiểm tra để truy xuất mã thông báo của khách hàng
  • Kiểm tra để lấy bảng
  • Kiểm tra để lấy một bảng
  • Kiểm tra để lấy danh sách từ bảng
  • Kiểm tra để lấy một danh sách
  • Kiểm tra để lấy nhãn từ bảng
  • Kiểm tra để truy xuất nhãn
  • Kiểm tra để thêm thẻ
  • Kiểm tra để thêm nhãn vào thẻ


Cũng cần lưu ý rằng khi viết bài kiểm tra đơn vị, chúng tôi muốn bài kiểm tra của mình càng rộng càng tốt - Nó có xử lý lỗi tốt không? Liệu nó bao gồm mọi khía cạnh của chương trình của chúng tôi?


Tuy nhiên, chỉ với mục đích của hướng dẫn này, chúng tôi sẽ đơn giản hóa mọi thứ bằng cách chỉ kiểm tra các trường hợp thành công.


Trước khi đi sâu vào mã, hãy sửa đổi tệp pyproject.toml của chúng tôi để bao gồm các phụ thuộc cần thiết cho việc viết/chạy thử nghiệm đơn vị.

 # pyproject.toml [project] dependencies = [ "pytest==7.4.0", "pytest-mock==3.11.1" ]


Tiếp theo, hãy kích hoạt virtualenv của chúng tôi và chạy pip install . để cài đặt các phụ thuộc.


Khi đã xong, cuối cùng chúng ta hãy viết một số bài kiểm tra. Nói chung, các thử nghiệm của chúng tôi phải bao gồm một phản hồi giả được trả về, một bản vá cho chức năng mà chúng tôi đang thử kiểm tra bằng cách sửa giá trị trả về bằng phản hồi giả và cuối cùng là một lệnh gọi đến hàm. Thử nghiệm mẫu để truy xuất mã thông báo truy cập của người dùng như sau:

 # tests/test_trelloservice.py # module imports from trellocli import SUCCESS from trellocli.trelloservice import TrelloService from trellocli.models import * # dependencies imports # misc imports def test_get_access_token(mocker): """Test to check success retrieval of user's access token""" mock_res = GetOAuthTokenResponse( token="test", token_secret="test", status_code=SUCCESS ) mocker.patch( "trellocli.trelloservice.TrelloService.get_user_oauth_token", return_value=mock_res ) trellojob = TrelloService() res = trellojob.get_user_oauth_token() assert res.status_code == SUCCESS


Lưu ý trong mã mẫu của tôi rằng GetOAuthTokenResponse là một mô hình chưa được đặt trong models.py . Nó cung cấp cấu trúc để viết mã sạch hơn, chúng ta sẽ thấy nó hoạt động sau.


Để chạy thử nghiệm của chúng tôi, chỉ cần chạy python -m pytest . Lưu ý rằng các bài kiểm tra của chúng tôi sẽ thất bại như thế nào, nhưng không sao - cuối cùng nó sẽ ổn thôi.


Góc thử thách 💡 Bạn thử tự viết thêm test xem sao? Vui lòng tham khảobản vá này để xem thử nghiệm của tôi trông như thế nào


Bây giờ, hãy xây dựng trelloservice của chúng ta. Bắt đầu với việc thêm một phụ thuộc mới, đó là trình bao bọc py-trello .

 # pyproject.toml dependencies = [ "pytest==7.4.0", "pytest-mock==3.11.1", "py-trello==0.19.0" ]


Một lần nữa, chạy pip install . để cài đặt các phụ thuộc.

người mẫu

Bây giờ, hãy bắt đầu bằng cách xây dựng các mô hình của chúng tôi - để điều chỉnh các phản hồi mà chúng tôi mong đợi trong trelloservice . Đối với phần này, tốt nhất bạn nên tham khảo các bài kiểm tra đơn vị của chúng tôi và mã nguồn py-trello để hiểu loại giá trị trả về mà chúng tôi có thể mong đợi.


Ví dụ: giả sử rằng chúng tôi muốn truy xuất mã thông báo truy cập của người dùng, tham khảo hàm create_oauth_token của py-trello ( mã nguồn ), chúng tôi biết giá trị trả về sẽ giống như thế này

 # trellocli/models.py # module imports # dependencies imports # misc imports from typing import NamedTuple class GetOAuthTokenResponse(NamedTuple): token: str token_secret: str status_code: int


Mặt khác, hãy lưu ý các quy ước đặt tên mâu thuẫn. Ví dụ: mô-đun py-trello có một lớp có tên List . Giải pháp thay thế cho vấn đề này là cung cấp bí danh trong quá trình nhập.

 # trellocli/models.py # dependencies imports from trello import List as Trellolist


Vui lòng sử dụng cơ hội này để điều chỉnh các mô hình theo nhu cầu của chương trình của bạn. Ví dụ: giả sử bạn chỉ yêu cầu một thuộc tính từ giá trị trả về, bạn có thể cấu trúc lại mô hình của mình để trích xuất giá trị đã nói từ giá trị trả về thay vì lưu trữ toàn bộ.

 # trellocli/models.py class GetBoardName(NamedTuple): """Model to store board id Attributes id (str): Extracted board id from Board value type """ id: str


Góc thử thách 💡 Bạn thử tự viết thêm các mẫu nữa xem sao? Vui lòng tham khảobản vá này để xem mô hình của tôi trông như thế nào

Logic kinh doanh

Cài đặt

Mô hình ngừng hoạt động, hãy chính thức bắt đầu mã hóa trelloservice . Một lần nữa, chúng ta nên tham khảo các bài kiểm tra đơn vị mà chúng tôi đã tạo - giả sử rằng danh sách các bài kiểm tra hiện tại không cung cấp phạm vi bảo hiểm đầy đủ cho dịch vụ, luôn quay lại và thêm các bài kiểm tra khác khi cần.


Theo thông lệ, hãy đưa tất cả các câu lệnh nhập vào đầu trang. Sau đó, tạo lớp TrelloService và các phương thức giữ chỗ như mong đợi. Ý tưởng là chúng ta sẽ khởi tạo một phiên bản dùng chung của dịch vụ trong cli.py và gọi các phương thức của nó tương ứng. Hơn nữa, chúng tôi đang hướng tới khả năng mở rộng, do đó cần có phạm vi bảo hiểm rộng rãi.

 # trellocli/trelloservice.py # module imports from trellocli import TRELLO_READ_ERROR, TRELLO_WRITE_ERROR, SUCCESS from trellocli.models import * # dependencies imports from trello import TrelloClient # misc imports class TrelloService: """Class to implement the business logic needed to interact with Trello""" def __init__(self) -> None: pass def get_user_oauth_token() -> GetOAuthTokenResponse: pass def get_all_boards() -> GetAllBoardsResponse: pass def get_board() -> GetBoardResponse: pass def get_all_lists() -> GetAllListsResponse: pass def get_list() -> GetListResponse: pass def get_all_labels() -> GetAllLabelsResponse: pass def get_label() -> GetLabelResponse: pass def add_card() -> AddCardResponse: pass


Xin lưu ý rằng lần này khi chúng tôi chạy thử nghiệm, các thử nghiệm của chúng tôi sẽ vượt qua như thế nào. Trên thực tế, điều này sẽ giúp chúng tôi đảm bảo rằng chúng tôi đi đúng hướng. Quy trình làm việc phải là mở rộng các chức năng của chúng tôi, chạy thử nghiệm, kiểm tra đạt/không đạt và cấu trúc lại cho phù hợp.

Ủy quyền và khởi tạo TrelloClient

Hãy bắt đầu với hàm __init__ . Ý tưởng là gọi hàm get_user_oauth_token tại đây và khởi tạo TrelloClient . Một lần nữa, nhấn mạnh nhu cầu chỉ lưu trữ thông tin nhạy cảm như vậy trong tệp .env , chúng tôi sẽ sử dụng phần phụ thuộc python-dotenv để truy xuất thông tin nhạy cảm. Sau khi sửa đổi tệp pyproject.toml của chúng tôi cho phù hợp, hãy bắt đầu thực hiện các bước ủy quyền.

 # trellocli/trelloservice.py class TrelloService: """Class to implement the business logic needed to interact with Trello""" def __init__(self) -> None: self.__load_oauth_token_env_var() self.__client = TrelloClient( api_key=os.getenv("TRELLO_API_KEY"), api_secret=os.getenv("TRELLO_API_SECRET"), token=os.getenv("TRELLO_OAUTH_TOKEN") ) def __load_oauth_token_env_var(self) -> None: """Private method to store user's oauth token as an environment variable""" load_dotenv() if not os.getenv("TRELLO_OAUTH_TOKEN"): res = self.get_user_oauth_token() if res.status_code == SUCCESS: dotenv_path = find_dotenv() set_key( dotenv_path=dotenv_path, key_to_set="TRELLO_OAUTH_TOKEN", value_to_set=res.token ) else: print("User denied access.") self.__load_oauth_token_env_var() def get_user_oauth_token(self) -> GetOAuthTokenResponse: """Helper method to retrieve user's oauth token Returns GetOAuthTokenResponse: user's oauth token """ try: res = create_oauth_token() return GetOAuthTokenResponse( token=res["oauth_token"], token_secret=res["oauth_token_secret"], status_code=SUCCESS ) except: return GetOAuthTokenResponse( token="", token_secret="", status_code=TRELLO_AUTHORIZATION_ERROR )


Trong quá trình triển khai này, chúng tôi đã tạo một phương thức trợ giúp để xử lý mọi lỗi có thể thấy trước, ví dụ: khi người dùng nhấp vào Deny trong khi ủy quyền. Hơn nữa, nó được thiết lập để yêu cầu ủy quyền của người dùng một cách đệ quy cho đến khi trả về phản hồi hợp lệ, vì thực tế là chúng tôi không thể tiếp tục trừ khi người dùng cho phép ứng dụng của chúng tôi truy cập dữ liệu tài khoản của họ.


Góc thử thách 💡 Thông báo TRELLO_AUTHORIZATION_ERROR ? Bạn có thể khai báo lỗi này là hằng số gói không? Tham khảo Thiết lập để biết thêm thông tin

Chức năng trợ giúp

Giờ thì phần ủy quyền đã hoàn tất, hãy chuyển sang các chức năng của trình trợ giúp, bắt đầu bằng việc truy xuất bảng Trello của người dùng.

 # trellocli/trelloservice.py def get_all_boards(self) -> GetAllBoardsResponse: """Method to list all boards from user's account Returns GetAllBoardsResponse: array of user's trello boards """ try: res = self.__client.list_boards() return GetAllBoardsResponse( res=res, status_code=SUCCESS ) except: return GetAllBoardsResponse( res=[], status_code=TRELLO_READ_ERROR ) def get_board(self, board_id: str) -> GetBoardResponse: """Method to retrieve board Required Args board_id (str): board id Returns GetBoardResponse: trello board """ try: res = self.__client.get_board(board_id=board_id) return GetBoardResponse( res=res, status_code=SUCCESS ) except: return GetBoardResponse( res=None, status_code=TRELLO_READ_ERROR )


Đối với việc truy xuất các danh sách (cột), chúng ta sẽ phải kiểm tra lớp Board của py-trello , hay nói cách khác, chúng ta phải chấp nhận một tham số mới của loại giá trị Board .

 # trellocli/trelloservice.py def get_all_lists(self, board: Board) -> GetAllListsResponse: """Method to list all lists (columns) from the trello board Required Args board (Board): trello board Returns GetAllListsResponse: array of trello lists """ try: res = board.all_lists() return GetAllListsResponse( res=res, status_code=SUCCESS ) except: return GetAllListsResponse( res=[], status_code=TRELLO_READ_ERROR ) def get_list(self, board: Board, list_id: str) -> GetListResponse: """Method to retrieve list (column) from the trello board Required Args board (Board): trello board list_id (str): list id Returns GetListResponse: trello list """ try: res = board.get_list(list_id=list_id) return GetListResponse( res=res, status_code=SUCCESS ) except: return GetListResponse( res=None, status_code=TRELLO_READ_ERROR )


Góc thử thách 💡 Bạn có thể tự triển khai hàm get_all_labelsget_label không? Sửa lại lớp Board của py-trello . Vui lòng tham khảobản vá này để xem triển khai của tôi trông như thế nào

Chức năng thêm thẻ mới

Cuối cùng nhưng không kém phần quan trọng, cuối cùng chúng tôi đã đạt được mục tiêu mà chúng tôi đã hướng tới trong suốt thời gian qua - thêm một thẻ mới. Hãy nhớ rằng chúng ta sẽ không sử dụng tất cả các hàm đã khai báo trước đó ở đây - mục tiêu của các hàm trợ giúp là tăng khả năng mở rộng.

 # trellocli/trelloservice.py def add_card( self, col: Trellolist, name: str, desc: str = "", labels: List[Label] = [] ) -> AddCardResponse: """Method to add a new card to a list (column) on the trello board Required Args col (Trellolist): trello list name (str): card name Optional Args desc (str): card description labels (List[Label]): list of labels to be added to the card Returns AddCardResponse: newly-added card """ try: # create new card new_card = col.add_card(name=name) # add optional description if desc: new_card.set_description(description=desc) # add optional labels if labels: for label in labels: new_card.add_label(label=label) return AddCardResponse( res=new_card, status_code=SUCCESS ) except: return AddCardResponse( res=new_card, status_code=TRELLO_WRITE_ERROR )


🎉 Giờ thì mọi việc đã hoàn tất, hãy nhớ cập nhật README của bạn cho phù hợp và đẩy mã của bạn lên GitHub.


Chúc mừng! Bạn đã thắng. Chơi lại (y/N)?

Gói (lại

Cảm ơn bạn đã đồng hành cùng tôi :) Thông qua hướng dẫn này, bạn đã học thành công cách triển khai chế độ mô phỏng khi viết bài kiểm tra đơn vị, mô hình cấu trúc để tạo sự gắn kết, đọc qua mã nguồn để tìm các chức năng chính và triển khai logic nghiệp vụ bằng cách sử dụng trình bao bọc của bên thứ ba.


Hãy theo dõi Phần 2, nơi chúng ta sẽ đi sâu vào việc triển khai chính chương trình CLI.


Trong thời gian chờ đợi, chúng ta hãy giữ liên lạc nhé 👀