Development
- 헷갈리는 CORS 를 한방에 정리해 보자 2021.11.17
- 애플 M1 환경에서 cocoapod 를 통한 pod install 실패 대응 방법 2021.10.23 17
- 플러터(Flutter), 안드로이드 라이센스 동의시 발생하는 Exception in thread "main" java.lang.NoClassDefFoundError 에 대응하는 방법 2021.08.07
- 파이썬 장고 Python Django 단위 테스트의 TransactionManagementError의 원인과 해결 / Trouble shooting for Python Django unit test error named TransactionmanagementError 2021.07.08
헷갈리는 CORS 를 한방에 정리해 보자
애플 M1 환경에서 cocoapod 를 통한 pod install 실패 대응 방법
간만에 Swift 환경으로 넘어오니 묵혀있던 애플 M1 환경에서의 에러 공습이 시작되었습니다. cocoapod 설치까지는 잘 진행되었으나 필요한 의존성을 Podfile에 기술하고 설치하는 작업에서 문제가 생겼습니다. 설치하고자 한 의존성은 Alamofire 였습니다.
# Podfile
target 'ch6' do
use_frameworks!
pod 'Alamofire', '~> 5.4'
end
에러 메세지도 한번 보고나서 트러블 슈팅을 진행해 보겠습니다. M1 을 쓰기 전이었다면 다른 케이스를 먼저 의심했겠지만, M1을 쓰기 시작한 후부터 이런 단순한 작업에서 에러가 발생하면 일단 M1 환경 문제로 보는 습관이 생겼습니다 ㅎㅎ
% pod install
Analyzing dependencies
/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/library.rb:275: [BUG] Bus Error at 0x00000001012d4000
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.arm64e-darwin20]
-- Crash Report log information --------------------------------------------
See Crash Report log file under the one of following:
* ~/Library/Logs/DiagnosticReports
* /Library/Logs/DiagnosticReports
for more details.
Don't forget to include the above Crash Report log file in bug reports.
-- Control frame information -----------------------------------------------
c:0049 p:---- s:0307 e:000306 CFUNC :attach
c:0048 p:0258 s:0301 e:000300 METHOD /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/library.rb:275
c:0047 p:0050 s:0281 e:000280 CLASS /Library/Ruby/Gems/2.6.0/gems/ethon-0.14.0/lib/ethon/libc.rb:17
...
..
..
...
653 /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/autopointer.rb
654 /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/variadic.rb
655 /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/enum.rb
656 /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/version.rb
657 /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi/ffi.rb
658 /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi.rb
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: https://www.ruby-lang.org/bugreport.html
[IMPORTANT]
Don't forget to include the Crash Report log file under
DiagnosticReports directory in bug reports.
zsh: abort pod install
이제 정답을 찾기 위해 열심히 구글링을 했고 두가지 정도의 방법을 찾았습니다.
방법#1. cocoapod 를 실행하는 터미널을 Rosetta 로 실행하기
M1 에서 호환성 문제를 해결하기 위해 가장 먼저 사용해 볼 수 있는 것이 Rosetta 입니다. iTerm 을 터미널 클라이언트로 쓰고 있기 때문에 "파인더 > 응용프로그램"에서 iTerm을 찾아 속성에서 Rosetta 를 켜주면 됩니다.
이제 동작중인 터미널을 종료하고 pod install 을 다시 수행해봅니다. 하지만 여전히 에러가 발생합니다.
% pod install
Analyzing dependencies
[!] Automatically assigning platform `iOS` with version `15.0` on target `ch6` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
Traceback (most recent call last):
45: from /usr/local/bin/pod:23:in `<main>'
44: from /usr/local/bin/pod:23:in `load'
43: from /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.11.2/bin/pod:55:in `<top (required)>'
42: from /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.11.2/lib/cocoapods/command.rb:52:in `run'
41: from /Library/Ruby/Gems/2.6.0/gems/claide-1.0.3/lib/claide/command.rb:334:in `run'
...
..
..
...
1: from /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': dlopen(/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle, 9): no suitable image found. Did find: (LoadError)
/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle: mach-o, but wrong architecture
/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle: mach-o, but wrong architecture - /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle
36: from /usr/local/bin/pod:23:in `<main>'
35: from /usr/local/bin/pod:23:in `load'
...
..
..
...
3: from /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi.rb:2:in `<top (required)>'
2: from /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi.rb:5:in `rescue in <top (required)>'
1: from /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': dlopen(/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle, 9): no suitable image found. Did find: (LoadError)
/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle: mach-o, but wrong architecture
/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle: mach-o, but wrong architecture - /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.3/lib/ffi_c.bundle
에러 메세지를 참고하여 ffi에 문제가 있다는 것을 확인하고 재설치를 진행해 봅니다. 이후 다시 pod install 을 수행하면 문제가 해결된다고 합니다. 제 경우는 아쉽게도...
% sudo gem install ffi
% pod install
방법#2. Ruby FFI 라이브러리 업데이트 후 재설치
에러 메세지에 아키텍쳐 관련한 내용이 계속 나오는 것에 착안하여 사람들이 올려둔 방법중 아키텍쳐 관련된 것들을 사용해 보았습니다. ffi를 설치할 때 아키텍쳐를 x86_64 로 지정하여 설치하는 방식입니다. (M1은 arm 기반이라 arch 명령을 수행해보면 arm64 라고 나옵니다)
% sudo arch -x86_64 gem install ffi
Password:
Fetching ffi-1.15.4.gem
Building native extensions. This could take a while...
Successfully installed ffi-1.15.4
Parsing documentation for ffi-1.15.4
Installing ri documentation for ffi-1.15.4
Done installing documentation for ffi after 9 seconds
1 gem installed
설치만 하면 pod install 이 동작할까요? 아닙니다. 그냥 pod install 명령을 사용하면 아키텍쳐가 arm64 로 인식되기 때문에 여전히 아키텍쳐 관련한 호환성 문제가 발생합니다. 대신 명령 앞에 아키텍쳐를 지정해서 실행해 보도록 하겠습니다.
% arch -x86_64 pod install
Analyzing dependencies
Downloading dependencies
Installing Alamofire (5.4.4)
Generating Pods project
Integrating client project
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.
잘 되는군요. :-)
플러터(Flutter), 안드로이드 라이센스 동의시 발생하는 Exception in thread "main" java.lang.NoClassDefFoundError 에 대응하는 방법
플러터 환경을 새로 준비하다보면 이전에 맛보지(?) 못했던 다양한 에러를 만나곤 합니다. 특히 Java의 버전이 달라진 경우에 이같은 문제가 더 자주 발생합니다. 새로운 애플실리콘 M1 Mac 환경에서 플러터 개발 환경을 새로 셋업하다 만난 Java 에러에 대하여 해결 방법을 정리해 봅니다.
플러터 환경설치시 활용하게 되는 닥터(doctor)는 부족한 환경 설정을 쉽게 진단해주고 어떤 대응을 해야 하는지 알려주는 도구입니다. 문제는 가끔 여기서 알려준 대응 방법을 실행하는 것 자체가 문제가 되는 경우입니다. 오늘 겪은 이슈는 새롭게 플러터 환경 설정시 필요한 안드로이드 라이센스에 대한 동의 과정에서 발생했습니다.
플러터 닥터의 메세지 살펴보기
안드로이드 스튜디오, 플러터 SDK를 설치한 후 flutter doctor를 수행하여 추가로 진행해야 하는 작업을 살펴보았습니다. 안드로이드 라이센스에 대한 동의가 필요하다고 하여 이 부분에 대한 안내에 따라 명령을 수행했습니다. 이전에 다른 노트북에서도 큰 문제 없이 안내된 명령을 복붙하는 것으로 충분했기에 안내된 명령을 실행했습니다. 그런데...
% flutter doctor --android-licenses
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73)
at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 5 more
이전에 만나보지 못했던 새로운 경험... 그것도 굉장히 기본적인 문제가 있는 것처럼 보이는 에러가 똬악 나타났습니다. Java 익셉션이라니... 더 이상의 안내가 없었기 때문에 구글링을 열심히 하여 몇 가지 단서를 찾았고 그 중 하나는 "안드로이드 SDK 커맨드라인 도구"의 설치 부재시 발생할 수 있다는 것이었습니다.
안드로이드 SDK의 커맨드라인 툴킷 설치하기
안드로이드 SDK의 커맨드라인 툴킷을 설치하는 가장 간단한 방법은 안드로이드 스튜디오의 셋팅 메뉴를 이용하는 방법입니다. 안드로이드 스튜디오를 실행하고 왼쪽 <Customize> 메뉴를 선택하면 아랫쪽에 <All settings...> 메뉴가 보입니다. 메뉴를 선택합니다.
설정 화면이 열리면 <Appearance & Behavior> - <System Settings> - <Android SDK>메뉴를 선택하고 우측의 탭에서 <SDK Tools>를 선택합니다. 예상대로 커맨드라인 툴킷이 설치되어 있지 않은 것이 보입니다. 체크후 설치를 진행해 봅니다.
안드로이드 라이센스 동의 작업 다시 해보기
100MB 정도 되는 패키지를 다운로드하고 설치하는 과정은 금세 끝납니다. 설치가 완료되었다면 다시 터미널 화면으로 이동하여 플러터 닥터를 이용해 안드로이드 라이센스 동의를 해보니 문제 없이 수행이 됩니다. 참고로 간혹 특정한 동의가 자동으로 되지 않는 경우가 있는데 라이센스 동의 명령을 이용시 상세 내용을 조회하면서 동의를 해주면 모든 라이센스에 동의가 진행됩니다.
% flutter doctor --android-licenses
All SDK package licenses accepted.======] 100% Computing updates...
이제 다시 한 번 플러터 닥터를 수행하여 필요한 절차를 살펴보겠습니다. 에러가 표시되던 Android toolchain 항목에 그린라이트가 들어온 것이 확인되네요!
파이썬 장고 Python Django 단위 테스트의 TransactionManagementError의 원인과 해결 / Trouble shooting for Python Django unit test error named TransactionmanagementError
파이썬 장고가 제공하는 단위 테스트는 코드 배포전에 에러를 검출해 볼 수 있는 방법으로 무척 유용합니다. 젠킨스 빌드시에도 활용하여 자칫 로컬 환경과 원격 빌드/운영 환경의 차이에도 대응할 수 있어 장애를 막는 지름길이 되기도 합니다.
파이썬 장고의 단위 테스트를 구성해서 잘 사용하던 중, 갑자기 (원인은 알 수 없습니다 ㅜㅜ) TransactionManagementError와 함께 테스트가 지속적으로 실패하기 시작하여 열심히 구글링하고 삽질한 내용을 간략히 정리해 봅니다.
장고 단위 테스트를 사용하기 위해서는 아래와 같은 코드를 만들게 됩니다. 참고로 코드는 장고 공식 문서에서 가져왔습니다. 이때, 실제 테스트를 수행하는 클래스는 매개변수로 TestCase 클래스의 인스턴스를 받게 됩니다. 아래의 코드에서는 TestCase 클래스를 가져왔네요.
import unittest
from django.test import Client
class SimpleTest(unittest.TestCase):
def setUp(self):
# Every test needs a client.
self.client = Client()
def test_details(self):
# Issue a GET request.
response = self.client.get('/customer/details/')
# Check that the response is 200 OK.
self.assertEqual(response.status_code, 200)
# Check that the rendered context contains 5 customers.
self.assertEqual(len(response.context['customers']), 5)
코드를 보면 실제 테스트 함수들이 클래스 내에 기술이 되어 있습니다. 제 경우 문제는 테스트 함수들이 데이터베이스에 대한 질의를 수행하는 코드를 호출하면서 발생했습니다. 일반적인 TestCase의 서브 클래스로는 데이터베이스 관련 코드를 수행하고 테스트 결과를 돌려주는데 문제가 있었습니다. 테스트가 수행되면서 발생한 에러는 아래와 같습니다.
raise TransactionManagementError(
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
이 에러 메세지가 참 얄미운게 내용이 좀 뭉뚱그려져 있습니다. 굉장히 명확한 에러이기 때문에 TestCase 클래스를 트랜잭션을 지원하는 것으로 변경하라고 하면 되었을 것을 저렇게 표현하고 있어서 애를 먹게 만들더군요. 이 문제에 대한 첫번째 접근은 장고 공식문서에서 가이드하는 TransactionTestCase 클래스의 사용입니다.
제 경우는 장고 REST Framework 를 사용하고 있던 관계로 이쪽에서 필요한 클래스의 변경 작업을 진행했습니다. 기존에 에러가 발생하던 테스트 코드에서는 REST Framework가 제공하는 test 패키지의 APITestCase 클래스를 쓰고 있었습니다. 이 클래스를 APITransactionTestCase로 변경하니 에러가 말끔히 사라지고 테스트도 정상적으로 수행되기 시작했습니다.
# 기존
from rest_framework.test import APITestCase
# 변경
from rest_framework.test import APITransactionTestCase
TransactionManagementError로 검색을 하다보면 여러가지 문제 상황과 이에 대한 대처법들이 소개되고 있습니다. 가령 1) 테스트 테이블에 데이터를 피딩하는 과정에 문제였고 이를 수정하여 해결 했다는 분도 계셨고, 2) 테스트가 수행하는 코드 내에 try~except 구문이 사용되는 경우 transaction.atomic() 을 이용해서 코드를 변경해야 된다는 글도 있었습니다.
다양한 트러블슈팅 사례와 방법이 있는 것을 보면 에러 메세지가 조금 더 친절하게 출력되면서 원인을 빠르게 확인할 수 있었으면 어땠을까 하는 생각이 듭니다. 그래도 트러블슈팅을 하면서 또 파이썬에 대해, 장고에 대해 조금 더 알 수 있었기에 의미 없는 시간은 아니었던 것 같습니다!
파이썬과 관련하여 최근에 겪었던 다른 이슈들과 해결 방법은 아래의 글을 참고해 보시기 바랍니다!