2017-12-04 10 views
1

"data_source_type"및 "data_source_path"라는 속성이있는 간단한 "DataSource"클래스를 작성하려고합니다. "data_source_type"이 ENUM이고 "data_source_path"가 문자열 인 경우 "data_source_type"에 따라 "ValidFilePath"또는 "ValidHttpURL"과 같은 적절한 유효성 검사를 "data_source_path"로 설정하려고합니다."Python 설명자"를 사용하는 조건부 동적 유효성 검사기

IF-ELSE를 작성하고 스파게티 데이터 소스 클래스를 사용하고 싶지는 않지만 "Python 설명자"또는 SRP (Single Responsibility Principle)를 고려하고 기능 프로그래밍을 지원하는 기타 우아한 Python 구문을 활용하고 싶습니다. 구성.

data_source.py 줄 번호 51

1 import re 
2 from enum import Enum 
3 import os 
4 
5 
6 class ValidFilePath(object): 
7  def __set__(self, obj, val): 
8   if not os.path.exists(): 
9    raise ValueError("Please enter a valid file path") 
10    self.__url = val 
11 
12  def __get__(self, obj, objtype): 
13   return self.__url 
14 
15 
16 class ValidHttpURL(object): 
17  def __set__(self, obj, val): 
18   if (val is None or re.compile(
19     r'^https?://' # http:// or https:// 
20     r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' # domain... 
21     r'localhost|' # localhost... 
22     r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip 
23     r'(?::\d+)?' # optional port 
24     r'(?:/?|[/?]\S+)$', re.IGNORECASE).search(val) is None): 
25    raise ValueError("Please set an valid HTTP(S) URL") 
26    self.__url = val 
27 
28  def __get__(self, obj, objtype): 
29   return self.__url 
30 
31 
32 class DataSourceType(Enum): 
33  HTTP = 100, 
34  LOCAL_FILE = 200, 
35  HDFS_FILE = 300 
36 
37 
38 class ValidDataSourceType(object): 
39  def __set__(self, obj, val): 
40   if val is None or not DataSourceType.__contains__(DataSourceType[val]): 
41    raise ValueError("Please set a valid Data Source Type Enum, " 
42        " possible values are -> ", [e.name for e in DataSourceType]) 
43   self.__data_source_type = DataSourceType[val] 
44 
45  def __get__(self, obj, objtype): 
46   return self.__data_source_type 
47 
48 
49 class DataSource(object): 
50  data_source_type = ValidDataSourceType() 
51  data_source_path = ValidHttpURL() 

나는 "data_source_type는"

예상에 따라 적절한 검증 설명을 설정할 지금은 뒀다 "ValidHttpURL"의 등 행동

ds1 = DataSource() 
ds1.data_source_type = 'HTTP' 
ds1.data_source_path = 'http://www.google.com' 
ds2 = DataSource() 
ds2.data_source_type = 'LOCAL_FILE' 
ds2.data_source_path = '/var/www/index.html' 
print("All is well") 

실제 행동

01 23,516,
ds1 = DataSource() 
ds1.data_source_type = 'HTTP' 
ds1.data_source_path = 'http://www.google.com' 
ds2 = DataSource() 
ds2.data_source_type = 'LOCAL_FILE' 
ds2.data_source_path = '/var/www/index.html' 

**ValueError: Please set an valid HTTP(S) URL** 

*** 업데이트] 답변의 **** 그래서

1 import os 
    2 import re 
    3 from enum import Enum 
    4 from weakref import WeakKeyDictionary 
    5 
    6 
    7 def valid_file_path(value): 
    8  if not os.path.exists(value): 
    9   raise ValueError(value, " is not present. Please make sure the file exists") 
10  return value 
11 
12 
13 def valid_http_url(value): 
14  if (value is None or re.compile(
15    r'^https?://' # http:// or https:// 
16    r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' # domain... 
17    r'localhost|' # localhost... 
18    r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip 
19    r'(?::\d+)?' # optional port 
20    r'(?:/?|[/?]\S+)$', re.IGNORECASE).search(value) is None): 
21   raise ValueError("Please set an valid HTTP(S) URL") 
22  return value 
23 
24 
25 class DataSourceType(Enum): 
26  NOT_DEFINED = (0, None) 
27  HTTP = (100, valid_http_url) 
28  LOCAL_FILE = (200, valid_file_path) 
29 
30  def __init__(self, enum_id, enum_validator): 
31   self._id = enum_id 
32   self._validator = enum_validator 
33 
34  @property 
35  def validator(self): 
36   return self._validator 
37 
38 
39 class ValidDataSourceType(object): 
40  def __init__(self): 
41   self.default = DataSourceType.NOT_DEFINED 
42   self.values = WeakKeyDictionary() 
43 
44  def __get__(self, instance, owner): 
45   return self.values.get(instance, self.default) 
46 
47  def __set__(self, instance, value): 
48   if value is None or not DataSourceType.__contains__(DataSourceType[value]): 
49    raise ValueError("Please set a valid Data Source Type Enum, " 
50        " possible values are -> ", [e.name for e in DataSourceType]) 
51   self.values[instance] = DataSourceType[value] 
52 
53  def __delete__(self, instance): 
54   del self.values[instance] 
55 
56 
57 class ValidDataSourcePath(object): 
58  def __init__(self, default_data_source_type_field='data_source_type'): 
59   self._default = '' 
60   self._default_data_source_type_field = default_data_source_type_field 
61   self.values = WeakKeyDictionary() 
62 
63  def __get__(self, instance, owner): 
64   return self.values.get(instance, self._default) 
65 
66  def __set__(self, instance, *value): 
67   data_source_type_field = self._default_data_source_type_field 
68   value_to_set = None 
69 
70   if value and len(value) == 1 and isinstance(value[0], str): # user sent only the value 
71    value_to_set = value[0] 
72   if value and len(value) == 1 and isinstance(value[0], tuple): # user sent the value , and the validation field 
73    value_to_set = value[0][0] 
74    data_source_type_field = value[0][1] 
75 
76   _data_source_type = getattr(instance, data_source_type_field, None) 
77   if not _data_source_type: 
78    raise ValueError(" Valid source path depends on ValidDataSourceType , " 
79        " please make sure you have an attribute named ValidDataSourceType") 
80   _data_source_type.validator(value_to_set) 
81   self.values[instance] = value_to_set 
82 
83 
84 class DataSource(object): 
85  data_source_type = ValidDataSourceType() 
86  data_source_path = ValidDataSourcePath() 
87 
88 
89 class SomeOtherDomainModel(object): 
90  data_source_type_ext = ValidDataSourceType() 
91  data_source_path = ValidDataSourcePath() 
92 
93 
94 print(" **************** Scenario 1 - Start **************** ") 
95 ds1 = DataSource() 
96 ds1.data_source_type = 'HTTP' 
97 ds1.data_source_path = "http://www.google.com" 
98 print(ds1.data_source_path) 
99 print(" **************** Scenario 1 - End **************** ") 
100 
101 print(" **************** Scenario 2 - Start **************** ") 
102 ds2 = SomeOtherDomainModel() 
103 ds2.data_source_type_ext = 'HTTP' 
104 ds2.data_source_path = ("http://www.yahoo.com", 'data_source_type_ext') 
105 print(ds2.data_source_path) 
106 print(" **************** Scenario 2 - Start **************** ") 
+1

내 대답의 기본 사항 (기회가있을 때 전체 답장을 게시합니다.) : 1) 원본 형식 개체에는 이름과 유효성 검사기가 포함되어야합니다. 열거 형은 Python (https://docs.python.org/3/library/enum.html#planet)에서이를 허용합니다. 2) 소스 경로를 소스 유형에 저장된 유효성 검사기를 통해 실행되는 간단한 특성으로 만듭니다. –

+0

@ jacob-zimmerman 제안 사항은 있지만 문제는 62 번과 63 번 라인에서 업데이트합니다. 71 번 라인에서 ENUM의 설명자를 아직 생성하지 않았으므로이를 연결할 수 없습니다. – Manjesh

+1

아니요, 대신 실제'@ 속성 '을 사용합니다 'data_source_type'입니다. 커스텀 서술자를 정말로 사용하고 싶다면'ValidDataSourcePath'가'obj'에'data_source_type'을 가지고 있다고 가정하고 그것을 자체적으로 저장하는 대신에 사용하십시오. 해커예요.하지만 다른 건 생각할 수 없어요. –

답변

1

은, 위의 내 의견을 구축, 여기에 데이터 소스가 검증 클래스 그냥해야한다는 생각과 함께, (@property 사용) 보일 것이다 방법 대신에 더 설명되는 경로가 유효 (그리고 좋아하면 오류가 발생합니다) 여부 부울을 반환하는 함수 :

class DataSource(object): 
    data_source_type = ValidDataSourceType() 

    @property 
    def data_source_path(self): 
     # can put in a check to make sure _data_source_path exists 
     return _data_source_path 

    @data_source_path.setter 
    def data_source_path(self, path): 
     if self.data_source_type.validator(path): 
      self._data_source_path = path 

기술자와 주위 (내가 알아야 할 일을하기가 어려울 수 있습니다; 나는 문자 적으로 wrote the book), 더 간단한 해결책을 찾을 수있을 때 피해야한다. 그래서 validator를 술어 함수로 바꾸었다. 또한 사용자 지정 설명자 대신 @property을 사용하는 데 부끄러운 일이 없습니다.

+0

속성에 대한 직접적인 종속성을 구축하고 싶지 않았습니다. 시나리오는 유효성 검사기로 명명 된 속성에 의해 런타임에 인스턴스 멤버가 유효성 검사를 제공 할 수 있습니다. 나는 그것을 작동 시켰고, 질문에서 대답을 업데이트하고, 당신에게 추천이나 제안이 있다면 제공 해주시기 바랍니다. – Manjesh

+0

글쎄, 보시다시피 두 사람이 함께 일하기 때문에 두 사람 사이에 * 어떤 종류의 연결이 있어야합니다. 귀하의 솔루션은 아마도 당신이 할 수있는 최선의 방법 일 것입니다. –