Python 28

pip-audit과 GitHub Actions를 활용한 취약 라이브러리 탐지 파이프라인 구축하기

흔히 파이썬을 사용해서 개발을 하다보면 `pip install`을 사용해서 다양한 라이브러리들을 설치하게 된다. 그리고 이렇게 설치한 라이브러리들에서 취약점이 발견되고, 이에 대해서 신규 패치가 나왔을 때, 이를 자동으로 탐지하고 취약점이 있는 라이브러리가 현재 프로젝트 내에서 사용 중인지 여부를 자동적으로 알려주는 기능의 필요성을 개발을 진행하면서 여러차례 느끼게 되었다. 물론, 비슷한 기능을 가진 GitHub DependencyBot이 있으나, dependency bot를 사용해서 의존성 업데이트를 진행할 때에는 가끔씩 의존성 충돌 문제로 인해 업데이트가 실패하는 등의 문제가 발생할 수 있다. 또한, 취약점 패키지를 발견했을때 즉시 알림을 주는 기능 역시 활성화를 시켜도 가끔씩 제대로 작동을 안하는 ..

Python 2023.10.09

소스코드 레벨에서 비교하는 Python List와 Set의 차이

Python에서 Set과 List List는 순서가 있고 mutable한 객체 집합이며, Set은 순서가 없고 mutable한 고유한 객체 집합이다. 두 자료구조 사이의 가장 큰 차이는 1) 객체의 중복 허용 여부와 2) 순서를 가지고 있는가 이다. 순서가 중요할 때에는 List를 사용하며, 객체의 중복을 배제하고 싶을 때에는 Set을 사용하는 것이 좋다. 그런데, 만약 중복이 없는 배열이 필요한 상황에서는 list와 set 중 어느 것을 사용하는 것이 좋을까? 둘 중 하나를 고르는 것이 실질적으로 어플리케이션의 성능에 큰 차이를 가져올 수 있을까? CPython 소스코드 레벨로 이해하는 List CPython 소스코드를 보게되면 List는 PyObject의 array의 포인터를 가지는 형태의 구조체로 ..

Python 2023.10.09

Python Dictionary 구조 CPython 소스 코드 레벨부터 파악하기

Python Dictionary는 어떻게 구현되었을까? 딕셔너리는 파이썬 프로그래밍에서 자주 사용되는 자료구조로, key-value pair 구조로 이루어져 있다. 그 구조는 마치 자바의 HashMap이나 Javascript의 JSON과 비슷한데, 그렇다면 저레벨 수준에서 구현은 어떠할까? 기본적으로 dict 타입은 저레벨 구현까지 내려가보면 해시 테이블로 구현되어 있다. 해시 테이블은 (Key, Value)로 데이터를 저장하는 자료구조 중 하나로 빠르게 데이터를 검색할 수 있는 자료구조이다. 해시 테이블이 빠른 검색속도를 제공하는 이유는 내부적으로 배열(버킷)을 사용하여 데이터를 저장하기 때문이다. 해시 테이블은 각각의 Key값에 해시 함수를 적용해 배열의 고유한 index를 생성하고, 이 index를..

Python 2023.10.09

Flask에서 async 기반 API 구현하기

Flask에서 async API 만들기? 일반적으로 Flask는 wsgi와 연동되도록 synchronous하게 동작하는 것을 기대하고 구현되었기 때문에 async 함수 없이 구현하는 것이 일반적인 패턴이다. 그러나 경우에 따라 필요에 의해 Flask 서버에 비동기 non-blocking I/O 기반 기능을 추가해야 할 경우가 발생하게 된다. 애초에 async 함수로 구현되는 FastAPI에서는 그다지 할 필요가 없는 고민이긴 하다. 어찌되었든, Flask에서 비동기를 사용하고 싶다면 어떤 방법으로 문제를 해결할 수 있을까? 가장 간단한 방법으로는 `asyncio`를 사용해서 비동기적인 I/O 기능을 할 수 있도록 만들고, 이를 Flask 코드와 연결시키면 된다. 눈치 챈 사람들도 있겠지만, 파이썬에서 함..

Python/Flask 2023.10.09

FastAPI + SQLAlchemy 로 N+1 쿼리 해결하기

N+1쿼리란 ORM에서 성능 이슈가 발생하면 가장 흔한 원인으로 `N+1 Problem`이 언급된다. N+1 Problem은 쿼리 1번으로 N건의 데이터를 가져왔는데 원하는 데이터를 얻기 위해 이 N건의 데이터를 데이터 수 만큼 반복해서 2차적으로 쿼리를 수행하는 문제이다. 이러한 문제가 발생하는 이유는 Object Mapper에서 데이터를 가져올 때 찾고자하는 객체에 대한 정보를 먼저 로딩하는데, 이때 해당 객체의 멤버 변수 등으로 연결되어 있는 다른 클래스와 매핑된 테이블 내의 데이터를 JOIN을 통해 가져오지 못하고 나중에 N건의 객체에 대해 각각 다시 쿼리를 보내서 해당하는 데이터를 가져오는 것이다. Java Spring에서는 Join Fetch 등의 방법을 통해서 이러한 N+1 쿼리 문제를 해결..

Python/FastAPI 2023.10.09

FastAPI와 SQLAlchemy로 ORM 사용하기

ORM이란? ORM(Object Relational Model)은 사물을 추상화시켜 이해하려는 OOP적 사고방식과 DataModel을 정형화하여 관리하려는 RDB 사이를 연결할 계층의 역할로 제시된 패러다임으로 RDB의 모델을 OOP에 Entity 형태로 투영시키는 방식을 사용한다. 이는 시스템에 따라, 사용하는 Database 및 DB Connector 에 따라 달라질 수 있는 데이터 매핑 구조를 객체지향형태로 통일시켜, SQL 구조의 Database를 OOP 구조의 형태로 매핑시키려는 패러다임이다. OOP 적 구조와 SQL 구조의 차이는 데이터를 다루는 방법에서 나타난다. OOP 적 구조에서 모든 데이터는 객체이며, 각 객체는 독립된 데이터와 독립된 함수를 지닌다. 반면 SQL 에서 데이터는 테이블단..

Python/FastAPI 2023.10.09

Flask - "The browser (or proxy) sent a request that this server could not understand."

tl;dr: 이 에러는 플라스크에서 request body의 데이터에 대해 미리 정의한 key로 접근하는데에 실패하면서 발생하는 에러이다. "The browser (or proxy) sent a request that this server could not understand" Flask를 사용해서 파일 업로드 및 data form을 받는 웹 서버를 구현할 때에 가끔씩 다음과 같은 메세지를 리턴 받는 경우가 발생한다: The browser (or proxy) sent a request that this server could not understand. 서버 로그를 확인해보면 다음과 같은 내용이 있을 것이다: werkzeug.exceptions.BadRequestKeyError: 400 Bad Reque..

Python/Flask 2023.10.09

gunicorn과 nginx를 사용해서 Flask 앱 배포하기

1. 들어가기 전에 1-1. WSGI란? WSGI(Web Server Gateway Interface)란 CGI(Common Gateway Interface)의 일종으로, 프레임워크의 웹 서버이다. 비슷한 개념으로 ASGI(Asynchronous Server Gateway Interface)가 있는데, 대표적인 예제로는 FastAPI의 배포에 사용되는 uvicorn이 있다. WSGI Middleware 는 Middleware 라는 이름처럼 Web Application 의 실행 전과 후에 이러한 기능들을 추가해주며, 그 자체로도 WSGI Application 이다. Design Pattern 의 Decorator Pattern 을 생각하면 이해가 쉽다. 양파 껍질 처럼 Web Application 을 감싸..

Python 2023.10.09

flask - "ImportError: cannot import name ‘parse_rule’ from ‘werkzeug.routing’" 해결법

기본적으로 해당 에러는 flask 내의 wekzeug의 버전 및 호환성과 관련된 이슈이다. 해당 문제의 가장 빠른 해결 방법은 flask와 werkzeug의 버전을 바꾸는 것이다. pip3 install werkzeug==2.1.2 pip3 install flask==2.1.3 위와 같이 werkzeug와 flask를 2.2.2가 아닌 2.1.x 버전으로 다시 설치를 하게 되면 정상적으로 작동하게 된다. 관련 링크: https://jtuto.com/importerror-cannot-import-name-parse_rule-from-werkzeug-routing/ [SOLVED] ImportError: cannot import name 'parse_rule' from 'werkzeug.routing' - ..

Python 2022.10.01

파이썬에서 파일 크기 알아내기

파이썬의 대표 모듈들 중 하나인 os를 사용하면 파일의 stat을 가져올 수 있다. 그리고 가져온 file stat을 통해서 파일의 크기를 가져올 수가 있게 된다. import os path = '/User/Yeonwoo/Desktop/test_file.txt' file_stats = os.stat(path) file_size = file_stats.st_size 위의 코드를 통해서 가져온 파일 크기의 경우 바이트 단위이기 때문에 KB로 바꾸고 싶다면 1024로 나누어야 하고, MB로 바꾸고 싶다면 1048576 (1024 * 1024)로 나누어야 한다. 추가로, 위의 코드에서 path를 절대경로가 아닌 상대경로로 하면 NotImplementedError가 발생하게 된다. 따라서, os.abspath 등..

Python 2022.09.14