DigitalOcean Functions Challenge를 완료하기 위한 Python CLI 작성
23109 단어 digitaloceanpythonserverlessapi
전주곡
내 에서 계속하기 위해 동일한 작업을 수행하는 Python CLI 작성에 대해 자세히 설명하겠습니다DigitalOcean Functions Challenge.
코드
이전에 작성한 Go 코드와 마찬가지로 이 예제에서는 모든 것을 main.py
에 집어넣었습니다. 따라서 시작하려면 간단하게 main.py 파일을 만들고 Pipenv과 함께 사용하고 싶은 처음 몇 가지 종속 항목을 설치했습니다. 그래서:
pipenv install requests structlog click
Requests Python 응용 프로그램에서 웹과 인터페이스해야 할 때 항상 사용합니다.
Structlog은 Python 애플리케이션용으로 선택한 구조화된 로깅 패키지입니다.
Click은 Python 애플리케이션용으로 선택한 CLI 프레임워크입니다.
이렇게 하면 이제 Pipfile과 Pipfile.lock이 있고 실제 개발을 수행할 수 있습니다.
먼저 요청 및 응답 클래스를 정의하고 싶었고 이전 예제에서 알고 있는 내용을 알고 있었기 때문에 클래스를 작성할 수 있었습니다.
#!/usr/bin/env python3
import logging
import sys
import requests
import structlog
import click
class Request:
"""
The Request class will contain all of our methods to handle a request to the DigitalOcean Function Challenge api.
Attributes
----------
API_URL : str
The API_URL attribute is a static string to hold the URL of the API to access.
name: str
The name attribute is the name of the Sammy that we wish to create.
t : str
The "t" attribute is the type of the Sammy that we wish to create. This attribute is named "t" to avoid
conflicting with the "type" keywork.
log : structlog.BoundLogger
The log attribute is not an attribute to be dealt with directly, rather the _get_log(self) method will retrieve
the bound logger for us.
Methods
-------
_set_name(name: str)
This method sets the value of the name attribute.
_set_type(t: str)
This method sets the value of the t attribute.
_set_log()
This method gets the application logger and sets it to the log attribute.
_get_url() -> str
This method returns the value of the API_URL attribute.
_get_name() -> str
This method returns the value of the name attribute.
_get_type() -> str
This method returns the value of the t attribute.
_build_headers() -> dict
This static method returns a dictionary to be used as a request header.
_build_request_body() -> dict
This method returns a dictionary to be used as the request body.
do() -> requests.Response
This method is the primary class method and is used to perform the HTTP POST request.
"""
def __init__(self, name: str, t: str):
"""
Parameters
----------
:param name: str
The name to give to your new Sammy.
:param t: str
The type to give to your new Sammy.
"""
self.API_URL = "https://functionschallenge.digitalocean.com/api/sammy"
self.name = None
self.t = None
self.log: structlog.BoundLogger = None
self._set_name(name)
self._set_type(t)
self._set_log()
def _set_name(self, name: str):
"""This method sets the value of the name attribute.
Parameters
----------
:param name: str
The name of the new sammy to create.
"""
self.name = name
def _set_type(self, t: str):
"""This method sets the value of the t attribute.
Input validation is handled at the CLI layer. We will need to do further input validation if we don't do the
validation at the CLI layer.
Parameters
----------
:param t: str
The type of the new sammy to create.
"""
self.t = t
def _set_log(self):
"""This method gets the application logger and sets it to the log attribute."""
self.log = structlog.stdlib.get_logger()
def _get_url(self) -> str:
"""This method returns the value of the API_URL attribute."""
return self.API_URL
def _get_name(self) -> str:
"""This method returns the value of the name attribute."""
return self.name
def _get_type(self) -> str:
"""This method returns the value of the t attribute."""
return self.t
def _build_request_body(self) -> dict:
"""This method returns a dictionary to be used as the request body."""
return {
"name": self.name,
"type": self.t,
}
@staticmethod
def _build_headers() -> dict:
"""This static method returns a dictionary to be used as a request header."""
return {
"Accept": "application/json",
"Content-Type": "application/json"
}
def do(self) -> requests.Response:
"""This method is the primary class method and is used to perform the HTTP POST request."""
return requests.post(url=self._get_url(), json=self._build_request_body(), headers=self._build_headers())
class Response:
"""
The Response class will contain all of our methods to handle a response from the DigitalOcean Functions Challenge
api.
Attributes
----------
resp : requests:Response
The actual response that is retrieved from performing the do() function from our Request class.
log: : structlog.BoundLogger
The log attribute is not an attribute to be dealt with directly, rather the _get_log(self) method will retrieve
the bound logger for us.
Methods
-------
_set_log() -> None
Gets the application logger.
_get_status_code() -> int
Gets the HTTP status code from the requests.Response object the class was initialized with.
_has_errors() -> bool
A helper to let us know if errors exist in the requests.Response object the class was initialized with.
do() -> None
The primary method of this class. Do is used to print the information from the response to the terminal.
"""
def __init__(self, resp: requests.Response):
"""
Parameters
----------
:param resp: requests.Response
A response object from our Request class do() method.
"""
self.resp = resp
self.log: structlog.BoundLogger = None
self._set_log()
def _set_log(self):
"""Gets the application logger."""
self.log = structlog.stdlib.get_logger()
def _get_status_code(self) -> int:
"""Gets the HTTP status code from the requests.Response object the class was initialized with."""
return self.resp.status_code
def _has_errors(self) -> bool:
"""A helper to let us know if errors exist in the requests.Response object the class was initialized with."""
respj: dict = self.resp.json()
if "errors" in respj:
return True
else:
return False
def do(self) -> None:
"""The primary method of this class. Do is used to print the information from the response to the terminal."""
if self._has_errors():
for e in self.resp.json()["errors"]:
for ee in self.resp.json()["errors"][e]:
self.log.error(ee)
return
else:
self.log.info(self.resp.json()["message"])
참고: 파일 맨 위에 있는 shebang을 확인하십시오. 저는 개인적으로 파일을 직접 호출할 수 있도록 Python 애플리케이션으로 이 작업을 수행하는 것을 좋아합니다. 하지만 이 작업을 수행할 때 실행할 적절한 권한을 파일에 제공해야 합니다. 내 경우(유닉스 계열 OS에서) 실행을 허용하기 위해 실행
chmod +x main.py
만 하면 되었습니다.이제 요청과 응답을 처리할 몇 가지 클래스가 있습니다.
나는 structlog가 나를 위해 좀 더 json-y를 처리하기를 원했기 때문에 다음과 같이 로거 구성 기능을 추가해야 했습니다.
...
def configure_logger():
"""Basic application level logging configuration"""
logging.basicConfig(
format="%(message)s",
stream=sys.stdout,
level=logging.INFO,
)
structlog.configure(
processors=[
structlog.processors.add_log_level,
structlog.processors.JSONRenderer(),
],
logger_factory=structlog.stdlib.LoggerFactory(),
)
이제 로거가 구성되었으므로 CLI를 사용하여 모두 가져오기만 하면 됩니다.
@click.command()
@click.option('-n', '--name', "name", help='The name to give to your new Sammy.')
@click.option('-t', '--type', "t", type=click.Choice([
"sammy",
"punk",
"dinosaur",
"retro",
"pizza",
"robot",
"pony",
"bootcamp",
"xray"
], case_sensitive=False), help='The type to give to your new Sammy.')
def main(name, t):
configure_logger()
req = Request(name, t)
response = req.do()
resp = Response(response)
resp.do()
if __name__ == "__main__":
main()
참고: 다시 말하지만
if __name__ == "__main__"
문에 주목하세요. 이것은 "파일이 직접 호출되면 이 작업을 수행하십시오"라는 줄입니다.실제로 이 모든
main()
기능은 (일부 클릭 데코레이터의 도움으로) 유형에 대한 name
플래그, t
플래그를 설정한 다음 설계한 대로 기능을 실행하는 것입니다.새 앱을 실행하는 것은
./main.py --name <my name> --type <my type>
와 같이 간단합니다.평소와 같이 전체 파일을 보려면 다음 저장소에서 자유롭게 확인하십시오.
https://github.com/j4ng5y/digitalocean-functions-challenge/tree/main/python
Reference
이 문제에 관하여(DigitalOcean Functions Challenge를 완료하기 위한 Python CLI 작성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/j4ng5y/writing-a-python-cli-to-complete-the-digitalocean-functions-challenge-1e29텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)