프로그래밍/C, C++, Java, Python

Python Path.relative_to 사용법

포도알77 2026. 6. 13. 10:16

Python Path.relative_to 사용법

pathlib.PurePath.relative_to()는 기준 경로를 기준으로 상대 경로를 계산할 때 쓰는 메서드다. 다만 os.path.relpath()처럼 아무 경로나 자동으로 상대화하는 함수는 아니다. Python 3.14 공식 문서는 이 메서드를 문자열 기반의 lexical 연산으로 설명하고, 조건이 맞지 않으면 ValueError를 발생시킨다고 명시한다.

실무 기준은 세 가지다. 기준 경로가 실제로 현재 경로의 상위 경로인지, 심볼릭 링크를 먼저 정리해야 하는지, 그리고 Python 3.12 이상에서 walk_up=True가 필요한지다. 이 글은 Python 3.14 공식 문서를 기준으로 Path.relative_to()를 안전하게 쓰는 판단 기준만 정리한다.

Path.relative_to는 언제 쓰면 될까?

다음 조건이면 Path.relative_to()가 잘 맞는다.

  • 두 경로의 관계를 문자열 규칙으로 확인할 수 있다.
  • 기준 경로가 현재 경로의 실제 상위 경로인지 명확하다.
  • pathlib.Path 기반 코드에서 상대 경로 표현만 간단히 만들고 싶다.

반대로 임의의 두 경로를 억지로라도 상대 경로로 만들고 싶다면 이 메서드의 동작을 먼저 이해해야 한다. Python 공식 문서는 입력 경로의 anchor가 다르거나 상하 관계가 맞지 않으면 ValueError가 난다고 설명한다.

기본 동작은 무엇일까?

Python 3.14 문서의 시그니처는 PurePath.relative_to(other, walk_up=False)다. 기본값에서는 현재 경로가 other로 시작해야 하며, 그렇지 않으면 예외가 발생한다.

from pathlib import Path

config_path = Path("/srv/app/config/settings.toml")

print(config_path.relative_to("/srv"))
# app/config/settings.toml

print(config_path.relative_to("/usr"))
# ValueError

즉 이 메서드는 "가능하면 상대 경로를 만들어 준다"보다 "정해진 포함 관계가 맞는지 확인하면서 잘라낸다"에 가깝다. 그래서 배포 경로 검증, 업로드 루트 검증, 로그 경로 정규화 같은 코드에서 더 예측 가능하다.

walk_up=True는 언제 필요할까?

Python 공식 문서는 3.12부터 walk_up 매개변수가 추가됐다고 밝힌다. 이 값을 True로 두면 하위 경로 관계가 아니더라도 .. 조각을 추가해서 상대 경로를 만들 수 있다.

from pathlib import Path

path = Path("/srv/app/config/settings.toml")

print(path.relative_to("/srv/app", walk_up=True))
# config/settings.toml

print(path.relative_to("/srv/log", walk_up=True))
# ../app/config/settings.toml

이 옵션은 "같은 파일시스템 anchor 안에서 상대 표현이 필요하다"는 조건이 분명할 때만 쓰는 편이 좋다. anchor가 다르면 여전히 ValueError가 발생할 수 있다.

심볼릭 링크가 있으면 왜 resolve()를 먼저 보라고 할까?

Python 문서는 relative_to()가 실제 파일시스템을 확인하지 않는 lexical 연산이라고 설명한다. 따라서 경로 문자열에 심볼릭 링크가 섞여 있으면 눈에 보이는 상하 관계와 실제 경로 구조가 다를 수 있다.

공식 문서는 이런 경우 필요하면 먼저 resolve()를 호출해 심볼릭 링크를 해석하라고 권고한다. 경로 접근 제어, 허용 디렉터리 검사, 파일 업로드 저장 경로 검증처럼 보안상 경계가 중요한 코드라면 이 순서가 특히 중요하다.

from pathlib import Path

base = Path("/srv/data").resolve()
target = Path("/srv/data/current/../reports/today.csv").resolve()

relative = target.relative_to(base)
print(relative)

os.path.relpath와는 무엇이 다를까?

Python 3.14 문서는 비교 표에서 os.path.relpath()에 대응하는 pathlib 도구로 PurePath.relative_to()를 제시하면서도, 두 동작이 완전히 같지는 않다고 별도 각주로 설명한다.

공식 문서 기준으로 os.path.relpath()는 내부적으로 절대 경로화와 .. 정리를 수행하는 반면, relative_to()는 lexical 연산이어서 입력 anchor가 다르거나 절대/상대 경로 타입이 섞이면 ValueError를 낸다. 즉 "실패하면 예외로 드러나는 더 엄격한 API"로 이해하는 편이 맞다.

실무에서는 어떤 기준이 무난할까?

  • 상위 경로 포함 관계를 검증하면서 상대 경로를 만들고 싶다면 Path.relative_to()가 적합하다.
  • 심볼릭 링크나 .. 조각이 섞일 수 있으면 먼저 resolve() 여부를 판단한다.
  • Python 3.11 이하 호환이 필요하면 walk_up를 전제로 설계하면 안 된다.
  • 경로 관계가 성립하지 않을 수 있다면 try/except ValueError로 실패 경로를 분기한다.

대부분의 서비스 코드에서는 "루트 디렉터리 아래에 있는지 확인한 뒤 상대 경로만 저장" 같은 패턴에 가장 잘 맞는다. 반면 사용자가 넘긴 임의의 두 경로를 무조건 상대화하는 용도라면 예외 처리 전략을 먼저 세워야 한다.

FAQ

Path.relative_to는 파일이 실제로 존재해야 동작할까?

아니다. Python 공식 문서는 이 메서드가 파일시스템을 확인하지 않는 lexical 연산이라고 설명한다. 따라서 경로 문자열만으로 계산되며, 존재 여부를 따로 검사하지 않는다.

walk_up=True를 쓰면 항상 상대 경로를 만들 수 있을까?

항상 그렇지는 않다. Python 공식 문서는 입력 경로의 anchor가 다르거나 절대/상대 경로 타입이 다르면 ValueError가 발생할 수 있다고 설명한다.

보안 검증 코드에서 어떤 순서가 안전할까?

심볼릭 링크 가능성이 있으면 먼저 resolve()로 실제 경로를 정규화한 뒤 relative_to()로 허용 루트 내부인지 확인하는 편이 더 안전하다. Python 공식 문서도 심볼릭 링크가 있을 수 있으면 resolve()를 먼저 호출하라고 안내한다.

참고 자료

반응형
페이스북으로 공유카카오톡으로 공유카카오스토리로 공유트위터로 공유URL 복사