Werkzeug: get_content_type()의 Python3 ν˜Έν™˜μ„± 문제

에 λ§Œλ“  2014λ…„ 12μ›” 04일  Β·  10μ½”λ©˜νŠΈ  Β·  좜처: pallets/werkzeug

λ‚΄κ°€ μž₯κ³ λ₯Ό μ‚¬μš© django_extensions ν•˜λŠ” μš©λ„ μ‚¬μš©ν•˜λŠ” 경우 디버깅 WERKZEUG runserver_plus . WerkzeugλŠ” Python3을 μ‚¬μš©ν•  λ•Œ λ‹€μŒ 역좔적을 μ‚¬μš©ν•˜μ—¬ get_content_type() μ—μ„œ ν­λ°œν•˜λŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

Traceback (most recent call last):
  File "/Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py", line 177, in run_wsgi
    execute(self.server.app)
  File "/Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py", line 165, in execute
    application_iter = app(environ, start_response)
  File "/Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/debug/__init__.py", line 173, in __call__
    response = self.get_resource(request, arg)
  File "/Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/debug/__init__.py", line 154, in get_resource
    return Response(f.read(), mimetype=mimetype)
  File "/Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/wrappers.py", line 749, in __init__
    mimetype = get_content_type(mimetype, self.charset)
  File "/Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/utils.py", line 224, in get_content_type
    if mimetype.startswith('text/') or \
TypeError: startswith first arg must be bytes or a tuple of bytes, not str

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

μ•ˆλ…•ν•˜μ„Έμš”, μœ„μ™€ 같이 django-extensions νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš©ν•  λ•Œ 자주 λ°œμƒν•©λ‹ˆλ‹€. 거의 2λ…„ λ™μ•ˆ κ±΄λ“œλ¦° 적이 μ—†λŠ”λ° μ—°κ²°λœ MR을 λ³‘ν•©ν•˜λŠ” 데 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆκΉŒ?

λͺ¨λ“  10 λŒ“κΈ€

문제λ₯Ό ν•΄κ²°ν•˜λŠ” PR 제좜

이것이 Werkzeug의 잘λͺ»μΈμ§€ Djangoκ°€ 응닡에 잘λͺ»λœ λ¬Έμžμ—΄ μœ ν˜•μ„ μ‚¬μš©ν•˜λŠ”μ§€ ν™•μ‹€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ ipdb의 전체 역좔적이며 Djangoκ°€ μ–΄λ””μ—μ„œλ‚˜ ν˜ΈμΆœλ˜λŠ” 것을 λ³Ό 수 μ—†μŠ΅λ‹ˆλ‹€. μ™„μ „ν•œ stackstaceλŠ” werkzeugμ—λ§Œ μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

ipdb> w
  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py(692)inner()
    690         make_server(hostname, port, application, threaded,
    691                     processes, request_handler,
--> 692                     passthrough_errors, ssl_context).serve_forever()
    693 
    694     if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py(436)serve_forever()
    434         self.shutdown_signal = False
    435         try:
--> 436             HTTPServer.serve_forever(self)
    437         except KeyboardInterrupt:
    438             pass

  /usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/socketserver.py(238)serve_forever()
    236                                        poll_interval)
    237                 if self in r:
--> 238                     self._handle_request_noblock()
    239 
    240                 self.service_actions()

  /usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/socketserver.py(305)_handle_request_noblock()
    303         if self.verify_request(request, client_address):
    304             try:
--> 305                 self.process_request(request, client_address)
    306             except:
    307                 self.handle_error(request, client_address)

  /usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/socketserver.py(331)process_request()
    329 
    330         """
--> 331         self.finish_request(request, client_address)
    332         self.shutdown_request(request)
    333 

  /usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/socketserver.py(344)finish_request()
    342     def finish_request(self, request, client_address):
    343         """Finish one request by instantiating RequestHandlerClass."""
--> 344         self.RequestHandlerClass(request, client_address, self)
    345 
    346     def shutdown_request(self, request):

  /usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/socketserver.py(669)__init__()
    667         self.setup()
    668         try:
--> 669             self.handle()
    670         finally:
    671             self.finish()

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py(200)handle()
    198         rv = None
    199         try:
--> 200             rv = BaseHTTPRequestHandler.handle(self)
    201         except (socket.error, socket.timeout) as e:
    202             self.connection_dropped(e)

  /usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/http/server.py(398)handle()
    396         self.close_connection = 1
    397 
--> 398         self.handle_one_request()
    399         while not self.close_connection:
    400             self.handle_one_request()

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py(235)handle_one_request()
    233             self.close_connection = 1
    234         elif self.parse_request():
--> 235             return self.run_wsgi()
    236 
    237     def send_response(self, code, message=None):

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py(177)run_wsgi()
    175 
    176         try:
--> 177             execute(self.server.app)
    178         except (socket.error, socket.timeout) as e:
    179             self.connection_dropped(e, environ)

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/serving.py(165)execute()
    163 
    164         def execute(app):
--> 165             application_iter = app(environ, start_response)
    166             try:
    167                 for data in application_iter:

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/debug/__init__.py(173)__call__()
    171             frame = self.frames.get(request.args.get('frm', type=int))
    172             if cmd == 'resource' and arg:
--> 173                 response = self.get_resource(request, arg)
    174             elif cmd == 'paste' and traceback is not None and \
    175                  secret == self.secret:

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/debug/__init__.py(154)get_resource()
    152             f = open(filename, 'rb')
    153             try:
--> 154                 return Response(f.read(), mimetype=mimetype)
    155             finally:
    156                 f.close()

  /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/wrappers.py(749)__init__()
    747                 mimetype = self.default_mimetype
    748             if mimetype is not None:
--> 749                 mimetype = get_content_type(mimetype, self.charset)
    750             content_type = mimetype
    751         if content_type is not None:

> /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/utils.py(224)get_content_type()
    222     #     charset = charset.decode('utf-8')
    223     import ipdb; ipdb.set_trace()
--> 224     if mimetype.startswith('text/') or \
    225        mimetype == 'application/xml' or \
    226        (mimetype.startswith('application/') and

ipdb> type(mimetype), type(charset)
(<class 'bytes'>, <class 'str'>)

λ¬Έμ œλŠ” μœ„μ˜ 2개 ν”„λ ˆμž„μ— μžˆλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€.

ipdb> up
> /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/wrappers.py(749)__init__()
    748             if mimetype is not None:
--> 749                 mimetype = get_content_type(mimetype, self.charset)
    750             content_type = mimetype

ipdb> up
> /Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/debug/__init__.py(154)get_resource()
    153             try:
--> 154                 return Response(f.read(), mimetype=mimetype)
    155             finally:

ipdb> l
    149         if isfile(filename):
    150             mimetype = mimetypes.guess_type(filename)[0] \
    151                 or 'application/octet-stream'
    152             f = open(filename, 'rb')
    153             try:
--> 154                 return Response(f.read(), mimetype=mimetype)
    155             finally:
    156                 f.close()
    157         return Response('Not Found', status=404)
    158 
    159     def __call__(self, environ, start_response):

ipdb> mimetypes.guess_type(filename)[0]
b'text/javascript'

μ΄μƒν•œ 점은 guess_type κ°€ λ°”μ΄νŠΈ λŒ€ λ¬Έμžμ—΄μ„ λ°˜ν™˜ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. μ‰˜μ—μ„œ λ™μΌν•œ 파일의 μœ ν˜•μ„ μΆ”μΈ‘ν•˜λ €κ³  ν•  λ•Œ λ¬Έμžμ—΄μ΄ ν‘œμ‹œλ©λ‹ˆλ‹€.

>>> mimetype = mimetypes.guess_type('/Volumes/Data/Users/miki725/.virtualenvs/test-py3/lib/python3.4/site-packages/werkzeug/debug/shared/jquery.js')[0]
>>> type(mimetype)
<class 'str'>

get_content_type() λŒ€μ‹  μ—¬κΈ°μ—μ„œ mimetype을 λ³€ν™˜ν•˜λ„λ‘ PR을 μ‘°μ •ν•΄μ•Ό ν•©λ‹ˆκΉŒ?

μ΄μƒν•œ 점은 guess_type이 λ°”μ΄νŠΈ λŒ€ λ¬Έμžμ—΄μ„ λ°˜ν™˜ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

κ·€ν•˜μ˜ PR은 문제λ₯Ό ν•΄κ²°ν•˜μ§€λ§Œ κ·€ν•˜κ°€ λ§ν–ˆλ“―μ΄ 이런 일이 λ°œμƒν•΄μ„œλŠ” μ•ˆλ©λ‹ˆλ‹€.

guess_type 호좜이 λ°œμƒν•˜λŠ” ν”„λ ˆμž„μ˜ 파일 이름은 λ¬΄μ—‡μž…λ‹ˆκΉŒ?

λ¬Έμžμ—΄. μ•„λ§ˆλ„ guess_type λŠ” 파일 이름과 λ™μΌν•œ μœ ν˜•μ„ λ°˜ν™˜ν•˜μ§€λ§Œ λΆ„λͺ…νžˆ κ·Έλ ‡μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš”, μœ„μ™€ 같이 django-extensions νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš©ν•  λ•Œ 자주 λ°œμƒν•©λ‹ˆλ‹€. 거의 2λ…„ λ™μ•ˆ κ±΄λ“œλ¦° 적이 μ—†λŠ”λ° μ—°κ²°λœ MR을 λ³‘ν•©ν•˜λŠ” 데 λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆκΉŒ?

μ΅œκ·Όμ— 같은 λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. μ €μ—κ²ŒλŠ” μžλ°” 슀크립트 νŒŒμΌμ—μ„œ λ°œμƒν•©λ‹ˆλ‹€. 디버깅 ν›„ λ‚΄ λ¬Έμ œκ°€ django-pipelineμ΄λΌλŠ” 것을 λ°œκ²¬ν–ˆμŠ΅λ‹ˆλ‹€. types_map μˆ˜μ •ν•˜κ³  λ‹€μŒμ„ μ„€μ •ν•©λ‹ˆλ‹€. https://github.com/jazzband/django-pipeline/blob/master/pipeline/conf.py#L81 -L87 μ—¬κΈ° https://github.com/jazzband/django-pipeline/blob/master/pipeline/utils.py#L42 -L43 .. :S :S ... ν•΄κ²°ν•˜λ €λ©΄ νŒŒμ΄ν”„λΌμΈ μ„€μ •μ—μ„œ MIMETYPESλ₯Ό μ˜¬λ°”λ₯΄κ²Œ μ„€μ •ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€. .

PR 병합을 μž¬κ³ ν•΄μ•Ό ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

이것이 λˆ„κ΅°κ°€μ—κ²Œ 도움이 되기λ₯Ό λ°”λžλ‹ˆλ‹€... ν–‰λ³΅ν•œ 디버깅!

Django-PipelinesλŠ” mimetype μœ ν˜• 맡에 λ°”μ΄νŠΈλ₯Ό 넣지 μ•Šλ„λ‘ μˆ˜μ •λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. Django-ExtensionsλŠ” 아무 μž‘μ—…λ„ μˆ˜ν–‰ν•˜μ§€ μ•ŠλŠ” κ²ƒμœΌλ‘œ λ³΄μ΄μ§€λ§Œ μ΄λŠ” λ‹€λ₯Έ 쒅속성이 μ˜€μž‘λ™ν•˜κ³  μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€. λ‚˜μœ 데이터λ₯Ό μΆ”κ°€ν•˜λŠ” λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ ν•΄κ²°ν•΄μ•Ό ν•œλ‹€κ³  μƒκ°ν•˜μ—¬ 이것을 λ‹«μŠ΅λ‹ˆλ‹€. λˆ„κ΅°κ°€κ°€ mimetypes μœ ν˜• λ§΅μ—μ„œ λ°”μ΄νŠΈλ₯Ό μ˜ˆμƒν•΄μ•Ό ν•˜λŠ” ν•©λ‹Ήν•œ 이유λ₯Ό κ²Œμ‹œν•  수 μžˆλ‹€λ©΄ μž¬κ³ ν•˜κ² μŠ΅λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰