Python 345

Python aiocache 로 비동기 Slack API 요청 캐싱하기

슬랙 API를 사용하면서 동일한 요청을 반복적으로 해야 할 때가 있습니다. 예를 들어 슬랙의 특정 메시지를 조회하여 데이터를 가져오는 경우가 있을 수 있죠. 하지만 슬랙 API는 사용량 제한이 있기 때문에, 같은 요청을 반복하는 대신 캐싱을 통해 효율적으로 처리할 수 있습니다. 오늘은 aiocache 라이브러리를 사용해 비동기 함수에 대한 캐시 구현 방법을 소개해 보겠습니다.  문제 상황slack_sdk 에서 제공하는 AsyncWebClient 를 이용하여 특정 메시지의 댓글을 가져오겠습니다. 이를 위해서는 conversations_replies 메서드를 사용합니다. async def fetch_messages( client: AsyncWebClient, channel_id: str, t..

Python Pillow를 이용해 이미지에 텍스트 추가하기

Pillow는 Python에서 이미지를 다룰 수 있게 해주는 라이브러리입니다. 원래는 Python Imaging Library(PIL)라는 이름으로 시작했는데, 현재는 Pillow라는 이름으로 널리 사용되고 있죠. 이 라이브러리는 이미지를 생성, 수정, 변환, 필터링하는 등 다양한 이미지 처리 기능을 제공합니다.   위의 이미지는 Pillow를 이용해 만든 이미지입니다. 이번 글에서는 위의 이미지 처럼 정사각형 이미지에 텍스트를 입히는 과정을 3단계로 설명하겠습니다 :)  1단계, 네모 박스에 색상 채우기먼저 Pillow를 사용해 이미지를 생성하는 것부터 시작하겠습니다. 아래 예제 코드를 통해 이미지의 크기와 배경색을 지정해주면, 네모난 박스에 원하는 색상을 채워줄 수 있습니다.from PIL impor..

Sqlalchemy 의 scalar 메서드들을 살펴보자

Scalar 메서드는 쿼리를 통해 가져온 결과를, 단일 데이터 요소(ex. ORM)로 반환하는 데 사용하는 sqlalchemy.engine.Result 클래스의 메서드입니다. 이번 글에서는 SQLAlchemy에서 제공하는 Scalar 메서드들에 대해 알아보고, 각 메서드들의 적합한 예시를 함께 살펴보겠습니다. 🥸 scalar() scalar() 메서드는 쿼리 결과의 첫 번째 행의 값을 반환합니다. 만약 결과가 없으면 None을 반환합니다. scalar() 메서드는 주로 결과가 최대 하나만 있을 것으로 예상되거나, 여러 결과 중 첫 번째 값만 필요한 경우에 사용됩니다. 예시: 특정 조건을 만족하는 첫 번째 사용자의 이름 조회 first_user_name = session.query(User.name).fi..

FastAPI 의 jsonable_encoder 들여다보기

jsonable_encoder 이란? FastAPI 에서 제공하는 인코더 함수로, 보통은 클라이언트로 전송하기 전에 응답하는 객체를 json 으로 인코딩할 수 있도록 변환해 주는 역할을 합니다. (참고로 json 으로 변환해 주는 것은 아닙니다!) 실제로 FastAPI 는 jsonable_encoder 를 어떻게 사용할까요? 아래 코드는 요청이 유효하지 않을 때 에러를 응답하는 함수입니다. # fastapi.exception_handlers.py async def request_validation_exception_handler( request: Request, exc: RequestValidationError ) -> JSONResponse: return JSONResponse( status_code=..

네이버 클라우드 플랫폼(NCP)으로 Python 서버 배포하기

이 글은 FastAPI 로 구현된 Python 서버를 네이버 클라우드 플랫폼(이하 NCP)으로 마이그레이션 한 후기입니다. 들어가기 전에 저는 현재 글또 9기 운영진으로 지난 8 기서부터 또봇이라고 하는 슬랙 앱(봇)을 만들어 운영하고 있습니다. 처음 또봇을 클라우드 환경에서 배포할 때에는 `클라우드 타입`이라는 호스팅 서비스를 이용했는데요. 클라우드 타입은 클릭 몇 번으로 아주 간편하게 서버 배포를 해주는 호스팅 서비스입니다. 게다가 무료죠(였죠) 약 1년 동안 잘 사용하던 클라우드 타입이 이번 12월 부터 유료화를 도입했고, 기존 무료 호스팅은 하루 1번 강제 종료라는,, 아주 크리티컬 한 제약이 추가되었습니다. ㅠㅠ 저는 서버가 강제종료되기 전에 서둘러 다른 클라우드 서비스를 찾기 시작했습니다. 그..

Python threading.local 와 ContextVar 비교

threading.local 와 ContextVar 는 둘 다 데이터를 격리하고 동적으로 할당한다는 점에서 유사한 목적을 가지고 있지만 사용되는 상황과 특징이 조금 다르다. 이 글에서는 둘의 공통점과 차이점을 예제 코드와 함께 비교해보고자 한다. threading.local threading.local 은 각 스레드마다 고유한 데이터를 가질 수 있게 해준다. 아래 예제 코드를 살펴보자. import threading # threading.local 객체 생성 thread_local_data = threading.local() def 스레드_울음소리(): thread_local_data.value = "끼룩끼룩!" def 스레드_동물호출(): value = getattr(thread_local_data, ..

Python JSON 직렬화 TypeError 핸들링하기

json 변환 시 타입에러 발생 아래와 같이 Decimal 타입을 json 으로 변환하는 코드가 있다고 해보자. import json from decimal import Decimal data = {"value": Decimal("123.456")} json_str = json.dumps(data) print(json_str) 이를 실행하면 다음의 에러가 발생한다. raise TypeError(f'Object of type {o.__class__.__name__} ' TypeError: Object of type Decimal is not JSON serializable 왜냐하면 json 라이브러리는 기본적으로 다음 타입들만 직렬화를 지원하기 때문이다. dict list, tuple str int, fl..

Django 에서 middleware 추가하기

Django 에서 middleware 추가하기 장고에서 미들웨어를 추가하는 방법에는 함수형과 클래스형이 있는데 이 글에서는 클래스형에 대해서 설명하겠다. 먼저 미들웨어 클래스를 정의하고 __init__ 메서드와 __call__ 메서드를 다음과 같이 추가하자. from django.http import HttpRequest, HttpResponse class CustomMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request: HttpRequest) -> HttpResponse: some_function() # 요청에 영향을 줄 수 있는 로직 response = self.g..

Sqlalchemy 에서 joinedload 할 때, The unique() method must be ... 에러 해결방법

Sqlalchemy 로 ORM 영역에서 join 을 하려고 할 때 joinedload 를 자주 사용한다. 그런데 joinedload 방식은 복수의 ORM 객체를 불러올 때에 다음처럼 에러가 발생할 수 있다. sqlalchemy.exc.InvalidRequestError: The unique() method must be invoked on this Result, as it contains results that include joined eager loads against collections 결론부터 말하자면 메시지의 내용대로 unique() 를 추가하면 된다. 아래처럼 말이다. ... res = await session.execute(stmt) res.scalars().all() # X res.sca..

Pydantic 옵션 하나로 ORM 을 DTO 모델로 변환하기

ORM 에서 DTO 로 모델 변환하기 ORM(Object-Relational Mapping) 객체를 통해 DB의 데이터를 가져왔다면 이를 DTO(Data Transfer Object)를 통해 다른 레이어로 전달하고 싶을 것이다. 이 글에서는 Pydantic 의 from_attributes=True 옵션을 활용하여 손쉽게 DTO를 생성하는 방법을 설명하고자 한다. 본론에 앞서 우선 ORM을 DTO로 변환하는 다양한 방법들을 살펴보자. (본론으로 넘어가고 싶다면 생략해도 좋다) 예를 들어 아래처럼 ORM과 DTO 모델이 명시되어 있다고 해보자. from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declar..