Inflearn brand logo image

인프런 커뮤니티 질문&답변

moljin님의 프로필 이미지
moljin

작성한 질문수

FastAPI: Python으로 3배 빠르게, 2배 정확한, 10배 빠른 API 만들기

25강에서 에러발생: 해결방법 알려주세요

해결된 질문

작성

·

48

·

수정됨

0

그림1.png.webp

💡 질문하기 전에 먼저 확인해보세요!

UnicodeDecodeError: 'cp949' codec can't decode byte 0xed in position 3465: illegal multibyte sequence

 

유니코드 관련에러가 발생합니다. utf-8 관련 설정에 문제가 있어보이는데, 해결방법을 구합니다. 별것을 다해본것 같은데 해결이 되질 않습니다.

 

코드는 알려주신데로 아래와 같이 수정했습니다.

# /alembic.ini 파일 sqlalchemy.url = sqlite+aiosqlite:///./sql_app.db

# /alembic/env.py 파일
import asyncio # 추가
from logging.config import fileConfig
import os # 경로 작업 위해 추가
import sys # 경로 작업 위해 추가

from sqlalchemy import engine_from_config
from sqlalchemy import pool
# ✨ 추가: 비동기 엔진 설정을 위해 async_engine_from_config 사용 ✨
from sqlalchemy.ext.asyncio import async_engine_from_config

from alembic import context

# --- ✨ 추가: 프로젝트 루트 경로 추가 (env.py가 app 모듈을 찾도록) ✨ ---
# env.py 파일의 부모 디렉토리의 부모 디렉토리 (즉, 프로젝트 루트)를 sys.path에 추가
sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), "..")))
# --------------------------------------------------------------

# --- ✨ 추가: Base 및 모델 임포트 ✨ ---
from app.database import Base  # database.py의 Base 임포트
import app.sql_models.task    # task 모델 모듈 임포트 (Base.metadata가 인식하도록)
# 만약 다른 모델 파일들이 있다면 모두 임포트해주는 것이 안전합니다.
# -----------------------------------------------------------------------------

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
if config.config_file_name is not None:
    fileConfig(config.config_file_name)

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
# target_metadata = None
# --- ✨변경: target_metadata 설정 ✨ ---
target_metadata = Base.metadata # 우리의 모델 메타데이터 지정!
# --------------------------------

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.

# ✨ 추가 ✨-----------------------------------------------------------------
def do_run_migrations(connection):
    # context 설정 및 마이그레이션 실행 (run_sync 내부에서 호출될 함수)
    context.configure(connection=connection, target_metadata=target_metadata)
    with context.begin_transaction():
        context.run_migrations()
# ---------------------------------------------------------------------------


# ... (run_migrations_offline 함수는 보통 그대로 둠) ...
def run_migrations_offline() -> None:
    """Run migrations in 'offline' mode.

    This configures the context with just a URL
    and not an Engine, though an Engine is acceptable
    here as well.  By skipping the Engine creation
    we don't even need a DBAPI to be available.

    Calls to context.execute() here emit the given string to the
    script output.

    """
    url = config.get_main_option("sqlalchemy.url")
    context.configure(
        url=url,
        target_metadata=target_metadata,
        literal_binds=True,
        dialect_opts={"paramstyle": "named"},
    )

    with context.begin_transaction():
        context.run_migrations()


# --- ✨ 변경: run_migrations_online 함수 비동기 방식으로 수정 ✨ ---
async def run_migrations_online() -> None:
    """Run migrations in 'online' mode for an async application."""
    # config 섹션에서 비동기 엔진 생성
    connectable = async_engine_from_config(
        config.get_section(config.config_ini_section),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
        future=True, # SQLAlchemy 2.0 스타일 사용
    )

    # 비동기적으로 DB 연결
    async with connectable.connect() as connection:
        # 동기적인 마이그레이션 함수(do_run_migrations)를
        # 비동기 연결의 run_sync 메서드 내에서 실행
        await connection.run_sync(do_run_migrations)

    # 엔진 연결 종료
    await connectable.dispose()
# -----------------------------------------------------------------

'''  # ✨ 위의 것으로 수정
def run_migrations_online() -> None:
    """Run migrations in 'online' mode.

    In this scenario we need to create an Engine
    and associate a connection with the context.

    """
    connectable = engine_from_config(
        config.get_section(config.config_ini_section, {}),
        prefix="sqlalchemy.",
        poolclass=pool.NullPool,
    )

    with connectable.connect() as connection:
        context.configure(
            connection=connection, target_metadata=target_metadata
        )

        with context.begin_transaction():
            context.run_migrations()
'''

if context.is_offline_mode():
    run_migrations_offline()
else:
    # ✨ run_migrations_online() # 아래로 변경
    # 온라인 모드일 경우 비동기 함수 실행
    asyncio.run(run_migrations_online())

 

답변 3

0

moljin님의 프로필 이미지
moljin
질문자

프로젝트 전체를 다시 만들고... 주석도 전부 삭제하고...진행했더니 잘됩니다.

어디가 문제인지는 확인할 수 없었지만...

app의 파일을 만드는 과정에 뭔가 utf-8로 작성되지 않은 부분이 있었을런지 모르겠습니다. 물론 새로 완전히 프로젝트를 만들기 전에 모든 파일이 utf-8이 적용되었다는 것을 확인을 했었는데,,,,

 

강사님이 남겨놓으신 주석들이 너무 많아 어딘가에서 영향을 주었을 것 같다는 생각이 들어 모두 제거하고 순수 코딩만 남겨놓았습니다.

 

그랬더니... 잘 진행되더군요... ㅎㅎㅎ

0

해여님의 프로필 이미지
해여
지식공유자

안녕하세요! 강사해여입니다.

에러로그를 보니 Windows 기본 인코딩(cp949)으로 alembic.ini 같은 텍스트 파일을 읽다가, UTF-8로 저장된 파일을 만나 생기는 오류로 생각됩니다. (한글/이모지가 문제에요!)

 

다음의 두 방법을 사용해보세요!

  1. alembic.ini의 내용을 영문으로 바꾸는 방법

  2. 파이썬을 UTF-8 모드로 실행(ini에 한글을 유지하고 싶다면)

    • PowerShell(영구): setx PYTHONUTF8 1 후 새 터미널 열기
      현재 셸만: $env:PYTHONUTF8=1

    • 또는 실행 시:
      python -X utf8 -m alembic revision --autogenerate -m "Create tasks table"

참고 1.
fileConfig(config.config_file_name)부분이 alembic.ini를 cp949로 읽는 경우 다음과 같이 수정할 수도 있습니다!

 

from logging.config import fileConfig

# ...

if config.config_file_name is not None:
    # ✨ 인코딩 명시!
    fileConfig(
        config.config_file_name,
        disable_existing_loggers=False,
        encoding="utf-8",
    )

참고 2.
PyCharm에서 영구 적용 방법

  1. Terminal 환경변수 설정

  • File → Settings → Tools → Terminal → Environment variables
    PYTHONUTF8=1, PYTHONIOENCODING=utf-8 추가 → 터미널 재시작.

  1. Run/Debug Configuration에도 적용(별도 실행 구성으로 돌릴 때)

  • 우측 상단 Run/Debug Configurations 열기 → 사용하는 구성 선택
    Environment variablesPYTHONUTF8=1 추가.

  1. 파일 인코딩 기본값을 UTF-8로

  • File → Settings → Editor → File Encodings
    Global/Project/Default encoding 모두 UTF-8로 맞추고 alembic.ini 다시 저장.
    상태바(오른쪽 아래)에서 현재 파일 인코딩이 UTF-8인지도 확인하세요.

     

감사합니다!

 

강사 해여드림

moljin님의 프로필 이미지
moljin
질문자

그 방법도 모두 해봤는데 모두 안됬습니다. encoding="utf-8", 이 부분도....

참고 2방법도 해봤습니다. 그래도 안됬었습니다.

 

그래서 프로젝트를 완전히 새로 작성했습니다.

주석도 모두 삭제하고... 정확히 어디가 문제여서 오류가 났었는지 확인은 안됐지만,,,

두가지를 의심해봅니다.

  1. 파일을 만들고 저장하는 과정에 어딘가 utf-8이 적용이 안된 부분이 있었을 수 있다는 것(물론 그부분도 다 확인해봤었는데 문제는 발견되지 않았지만)

  2. 두번째는 주석이 너무 많아 어디선가 utf-8에 장애를 일을 켰을 수도 있다는 생각이 듭니다. 특히 sql_model/task.py에 있는 주석들이 테이블을 만드는 과정에 영향을 미치지 않았을까하는 생각은 듭니다. 그 부분만 삭제를 하고 테스트를 해보지는 않아서 그것도 확실치는 않지만,,,

여튼 완전히 프로젝트를 다시 만들고 진행했더니 오류가 싸악 사라졌습니다.

 

0

안녕하세요, 인프런 AI 인턴입니다. moljin님.

UTF-8 관련 설정 문제로 인해 UnicodeDecodeError가 발생하고 있는 것 같습니다. 이 오류는 주로 파일 인코딩이 잘못되어 발생합니다. 해당 오류를 해결하기 위한 몇 가지 방법을 제안드리겠습니다.

  1. 파일 인코딩 확인:
    파일을 UTF-8로 다시 저장해야 합니다. 사용하는 텍스트 에디터(예: VS Code, Sublime Text 등)에서 파일 인코딩을 확인하시고, CP949로 저장된 파일을 UTF-8로 변환해 저장해 보세요.

  2. 파일 열기 시 인코딩 지정하기:
    Python에서 파일을 열 때 인코딩을 명시적으로 지정할 수 있습니다. 예를 들어 다음과 같이 open 함수를 사용할 때 인코딩을 설정합니다.

    with open('파일명.txt', 'r', encoding='utf-8') as file:
       content = file.read()
    

    이렇게 하면 Python이 파일을 UTF-8로 읽어들이도록 합니다.

  3. 기타 해결 방법:
    다른 환경이나 운영체제에서 작업 중인 경우, 해당 환경이 UTF-8을 기본으로 지원하지 않을 수 있습니다. 이 경우도 파일 인코딩을 명시적으로 지정해 주시면 대부분의 문제가 해결됩니다.

관련하여 Q&A 게시판의 이전 질문 중 강사님이 인코딩 문제를 해결한 부분이 있으니, 참고해 보시면 도움이 될 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

moljin님의 프로필 이미지
moljin

작성한 질문수

질문하기