我使用argparse
模块通过命令行创建地址对象。但是当我提供无效参数(即应该引发异常的参数)时,不会引发异常。更糟糕的是,没有记录任何内容(除非我创建了一个有效的对象)。
所以,这有效:
-n Patrick -a "151 Piedmont Ave" -c "Winston Salem" -s "NC" -z 27101
这不是:
-l ERROR -n Patrick -a "151 Piedmont Ave" -c "Winston Salem" -s "NC" -z 271
我哪里错了?
注意:这是作业,因此对于绝对答案的指导将不胜感激。
"""
property_address.py
"""
import re
import logging
import argparse
LOG_FILENAME = 'property_address.log'
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(funcName)s - %(message)s"
DEFAULT_LOG_LEVEL = "debug"
LEVELS = {'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL
}
def start_logging(filename=LOG_FILENAME, level=None):
logging.basicConfig(filename=filename, level=level, filemode='w', format=LOG_FORMAT)
logging.info('Starting up the property address program')
class ZipCodeError(Exception):
"Custom exception for invalid zip codes."
pass
class StateError(Exception):
"Custom exception for invalid state abbreviation."
pass
class Address(object):
"""
An address object.
"""
def __init__(self, name, street_address, city, state, zip_code):
self._name = name
self._street_address = street_address
self._city = city
self._state = state
self._zip_code = zip_code
logging.info('Instantiated an address')
@property
def name(self):
return self._name
@property
def street_address(self):
return self._street_address
@property
def city(self):
return self._city
@property
def state(self):
return self._state
@state.setter
def state(self, value):
"Validate that states are abbreviated as US Postal style."
state_valid = re.compile(r'[A-Z]{2}$')
if re.match(state_valid, value):
self._state = value
else:
message = 'STATE Exception: State not in correct format'
logging.error(message)
raise StateError()
@property
def zip_code(self):
return self._zip_code
@zip_code.setter
def zip_code(self, value):
"Validate zip codes are five digits."
zip_valid = re.compile(r'\d{5}$')
if re.match(zip_valid, value):
self._zip_code = value
else:
message = 'ZIP CODE Exception: Zip code not in correct format'
logging.error(message)
raise ZipCodeError()
def __str__(self):
return self._name
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Set attributes for property address.')
parser.add_argument(
'-l',
'--level',
dest='level',
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
default='INFO',
help='Sets the log level to DEBUG, INFO, WARNING, ERROR, and CRITICAL')
parser.add_argument(
'-n',
'--name',
dest='name',
action='store',
required=True,
help='Sets the name value of the Address object')
parser.add_argument(
'-a',
'--address',
dest='address',
action='store',
required=True,
help='Sets the street_address value of the Address object')
parser.add_argument(
'-c',
'--city',
dest='city',
action='store',
required=True,
help='Sets the city value of the Address object')
parser.add_argument(
'-s',
'--state',
dest='state',
action='store',
required=True,
help='Sets the state value of the Address object')
parser.add_argument(
'-z',
'--zip_code',
dest='zip_code',
action='store',
required=True,
help='Sets the zip_code value of the Address object')
args = parser.parse_args()
# Start our logger
start_logging(level=(args.level))
# Create our Address object
a = Address(args.name, args.address, args.city, args.state, args.zip_code)
答案 0 :(得分:1)
您要分配给Address.__init__
{ self._zip_code
,其中绕过了setter 。因此,最小的修复是使用:
self.zip_code = zip_code
# ^ note no underscore
这意味着调用了setter并进行了检查。
除此之外,你的属性之间存在不一致; state
和zip_code
一旦设置就可以更改,但其他是只读的。如果这不是所需的行为,我会在没有setter的情况下删除属性的getter,并在__init__
中直接访问所有内容(即没有下划线)。
或者,如果您确实希望它们都是只读的,请删除setter并将其测试放在__init__
中。
最后一个选项是在解析时测试参数,而不是在类中测试;见例如Specify format for input arguments argparse python。
如果您仍然希望课程测试其参数(当他们不通过argparse
时),您可以考虑为@staticmethod
公开在你的班级中进行测试,然后在setter
中调用:
class Address:
...
@staticmethod
def valid_zip_code(zip_code, zip_valid=re.compile(r'\d{5}$')):
if not re.match(zip_valid, zip_code):
raise ZipCodeError
return zip_code
@zip_code.setter
def zip_code(self, new_zip):
new_zip = self.valid_zip_code(new_zip)
self._zip_code = new_zip
...
parser.add_argument('-z', ..., type=Address.valid_zip_code)