programing

argparse가있는 디렉토리 경로 유형

nasanasas 2021. 1. 8. 08:18
반응형

argparse가있는 디렉토리 경로 유형


내 파이썬 스크립트는 명령 줄에 전달 된 디렉토리에서 파일을 읽어야합니다. 명령 줄에 전달 된 디렉터리가 존재하고 읽을 수 있는지 확인하기 위해 argparse와 함께 사용하도록 아래와 같이 Readable_dir 유형을 정의했습니다. 또한 기본값 (아래 예의 / tmp / non_existent_dir)도 디렉토리 인수에 지정되었습니다. 여기서 문제는 argparse가 명령 줄에서 디렉토리 인수가 명시 적으로 전달되는 상황에서도 기본값으로 Readable_dir ()을 호출한다는 것입니다. 이로 인해 명령 줄에서 디렉토리가 명시 적으로 전달되는 컨텍스트에 기본 경로 / tmp / non_existent_dir이 존재하지 않으므로 스크립트가 중단됩니다. 기본값을 지정하지 않고이 인수를 필수로 설정하여이 문제를 해결할 수 있습니다.

#!/usr/bin/python
import argparse
import os

def readable_dir(prospective_dir):
  if not os.path.isdir(prospective_dir):
    raise Exception("readable_dir:{0} is not a valid path".format(prospective_dir))
  if os.access(prospective_dir, os.R_OK):
    return prospective_dir
  else:
    raise Exception("readable_dir:{0} is not a readable dir".format(prospective_dir))

parser = argparse.ArgumentParser(description='test', fromfile_prefix_chars="@")
parser.add_argument('-l', '--launch_directory', type=readable_dir, default='/tmp/non_existent_dir')
args = parser.parse_args()

유형 대신 사용자 지정 작업을 만들 수 있습니다.

import argparse
import os
import tempfile
import shutil
import atexit

class readable_dir(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        prospective_dir=values
        if not os.path.isdir(prospective_dir):
            raise argparse.ArgumentTypeError("readable_dir:{0} is not a valid path".format(prospective_dir))
        if os.access(prospective_dir, os.R_OK):
            setattr(namespace,self.dest,prospective_dir)
        else:
            raise argparse.ArgumentTypeError("readable_dir:{0} is not a readable dir".format(prospective_dir))

ldir = tempfile.mkdtemp()
atexit.register(lambda dir=ldir: shutil.rmtree(ldir))

parser = argparse.ArgumentParser(description='test', fromfile_prefix_chars="@")
parser.add_argument('-l', '--launch_directory', action=readable_dir, default=ldir)
args = parser.parse_args()
print (args)

그러나 이것은 나에게 약간 수상한 것처럼 보입니다. 디렉토리가 제공되지 않으면 처음에 디렉토리에 액세스 할 수 있는지 확인하는 목적을 무력화하는 것처럼 보이는 읽을 수없는 디렉토리를 전달합니다.

코멘트에 지적 밖으로, 그것은가 좋을 수도 있습니다
raise argparse.ArgumentError(self, ...)보다는 argparse.ArgumentTypeError.

편집하다

내가 아는 한 기본 인수의 유효성을 검사 할 방법이 없습니다. 나는 가정 argparse개발자 당신이 기본을 제공하는 경우, 다음이 유효해야한다고 생각했습니다. 여기서 가장 빠르고 쉬운 방법은 인수를 구문 분석 한 후 즉시 유효성을 검사하는 것입니다. 작업을 수행하기 위해 임시 디렉토리를 얻으려는 것 같습니다. 이 경우 tempfile모듈을 사용하여 새 디렉터리를 가져올 수 있습니다 .이를 반영하기 위해 위의 답변을 업데이트했습니다. 임시 디렉터리를 만들고 기본 인수로 사용하고 ( tempfile이미 생성 한 디렉터리가 쓰기 가능함을 보장 함) 프로그램이 종료 될 때 삭제되도록 등록합니다.


몇 달 전에 파이썬 표준 라이브러리 메일 링리스트에 "경로 인수"에 대한 패치를 제출 했습니다 .

PathType클래스를 사용하면 다음 인수 유형을 지정하여 기존 디렉토리 일치시킬 수 있습니다 . 다른 모든 항목은 오류 메시지를 표시합니다.

type = PathType(exists=True, type='dir')

다음은 특정 파일 / 디렉토리 권한을 요구하도록 쉽게 수정할 수있는 코드입니다.

from argparse import ArgumentTypeError as err
import os

class PathType(object):
    def __init__(self, exists=True, type='file', dash_ok=True):
        '''exists:
                True: a path that does exist
                False: a path that does not exist, in a valid parent directory
                None: don't care
           type: file, dir, symlink, None, or a function returning True for valid paths
                None: don't care
           dash_ok: whether to allow "-" as stdin/stdout'''

        assert exists in (True, False, None)
        assert type in ('file','dir','symlink',None) or hasattr(type,'__call__')

        self._exists = exists
        self._type = type
        self._dash_ok = dash_ok

    def __call__(self, string):
        if string=='-':
            # the special argument "-" means sys.std{in,out}
            if self._type == 'dir':
                raise err('standard input/output (-) not allowed as directory path')
            elif self._type == 'symlink':
                raise err('standard input/output (-) not allowed as symlink path')
            elif not self._dash_ok:
                raise err('standard input/output (-) not allowed')
        else:
            e = os.path.exists(string)
            if self._exists==True:
                if not e:
                    raise err("path does not exist: '%s'" % string)

                if self._type is None:
                    pass
                elif self._type=='file':
                    if not os.path.isfile(string):
                        raise err("path is not a file: '%s'" % string)
                elif self._type=='symlink':
                    if not os.path.symlink(string):
                        raise err("path is not a symlink: '%s'" % string)
                elif self._type=='dir':
                    if not os.path.isdir(string):
                        raise err("path is not a directory: '%s'" % string)
                elif not self._type(string):
                    raise err("path not valid: '%s'" % string)
            else:
                if self._exists==False and e:
                    raise err("path exists: '%s'" % string)

                p = os.path.dirname(os.path.normpath(string)) or '.'
                if not os.path.isdir(p):
                    raise err("parent path is not a directory: '%s'" % p)
                elif not os.path.exists(p):
                    raise err("parent directory does not exist: '%s'" % p)

        return string

스크립트가 유효하지 않으면 작동하지 않으면 launch_directory필수 인수로 만들어야합니다.

parser.add_argument('launch_directory', type=readable_dir)

BTW, 당신은 사용해야하는 argparse.ArgumentTypeError대신 Exception에서 readable_dir().

참조 URL : https://stackoverflow.com/questions/11415570/directory-path-types-with-argparse

반응형