Description
Describe the bug
The current implementation for MySqlContainer
to check if the database is running is like below:
wait_for_logs(
self,
re.compile(".*: ready for connections.*: ready for connections.*", flags=re.DOTALL | re.MULTILINE).search,
)
It expects for two pair of "ready for connections" logs to appear in the logs output. This works for vanilla MySQL Docker image but fails for any custom ones, for instance, an image that has a custom database initilization which is something standard and explained how in the official Docker Hub for MySQL section 'Initializing a fresh instance'.
Below is a example of a custom MySQL docker image:
FROM mysql:latest as builder
# Modify the entrypoint to only initialize the database
RUN sed -i 's/exec "\$@"/echo "not running \$@"/' /usr/local/bin/docker-entrypoint.sh
ENV MYSQL_ROOT_PASSWORD=test
# Copy data for initialization and settings
COPY sql/ /docker-entrypoint-initdb.d/
COPY ./bigtext.txt /var/lib/mysql-files/
COPY my.cnf /etc/mysql/my.cnf
# Run the entrypoint script to initialize the database
RUN /usr/local/bin/docker-entrypoint.sh mysqld
FROM mysql:latest
# Copying settings
COPY my.cnf /etc/mysql/my.cnf
# Copy the initialized database from the first stage
COPY --from=builder /var/lib/mysql /var/lib/mysql
# Copy the health table
COPY health-check.sql /health-check.sql
# Override the normal startup to load health-check after database initialization
ENTRYPOINT ["docker-entrypoint.sh", "mysqld", "--init-file", "/health-check.sql"]
And the initialization logs output for this image is like below:
docker run --rm -v ./tmp:/var/lib/mysql -eMYSQL_RANDOM_ROOT_PASSWORD=true sakila-extended-source-db:latest
2024-10-01 17:06:45+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-10-01 17:06:46+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2024-10-01 17:06:46+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
2024-10-01T17:06:46.171337Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-10-01T17:06:46.312696Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 1
2024-10-01T17:06:46.314299Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:06:46.317485Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:06:46.396872Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:06:46.517414Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-10-01T17:06:46.517454Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-10-01T17:06:46.519802Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-10-01T17:06:46.525651Z 7 [ERROR] [MY-000061] [Server] 1049 Unknown database 'sakila'.
2024-10-01T17:06:46.526937Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2024-10-01T17:06:46.526956Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
Logs from vanilla mysql:latest
image:
docker run --rm -v ./tmp:/var/lib/mysql -eMYSQL_RANDOM_ROOT_PASSWORD=true mysql:latest core -> feature/monorepo-cleanup + ? !
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 9.0.1-1.el9 started.
2024-10-01 17:04:05+00:00 [Note] [Entrypoint]: Initializing database files
2024-10-01T17:04:05.565798Z 0 [System] [MY-015017] [Server] MySQL Server Initialization - start.
2024-10-01T17:04:05.566683Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 9.0.1) initializing of server in progress as process 81
2024-10-01T17:04:05.568354Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:04:05.575007Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:04:05.689247Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:04:06.519129Z 6 [Warning] [MY-010453] [Server] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
2024-10-01T17:04:08.317899Z 0 [System] [MY-015018] [Server] MySQL Server Initialization - end.
2024-10-01 17:04:08+00:00 [Note] [Entrypoint]: Database files initialized
2024-10-01 17:04:08+00:00 [Note] [Entrypoint]: Starting temporary server
2024-10-01T17:04:08.364408Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-10-01T17:04:08.507157Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 124
2024-10-01T17:04:08.508364Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:04:08.515275Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:04:08.594411Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:04:08.718336Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-10-01T17:04:08.718374Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-10-01T17:04:08.720619Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-10-01T17:04:08.729333Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: /var/run/mysqld/mysqlx.sock
2024-10-01T17:04:08.729354Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1' socket: '/var/run/mysqld/mysqld.sock' port: 0 MySQL Community Server - GPL.
2024-10-01 17:04:08+00:00 [Note] [Entrypoint]: Temporary server started.
'/var/lib/mysql/mysql.sock' -> '/var/run/mysqld/mysqld.sock'
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leapseconds' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/tzdata.zi' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
2024-10-01 17:04:09+00:00 [Note] [Entrypoint]: GENERATED ROOT PASSWORD: uLXlPdWc6VAglkpK99BoRXuNgH8c7z9s
2024-10-01 17:04:09+00:00 [Note] [Entrypoint]: Stopping temporary server
2024-10-01T17:04:09.444930Z 10 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 9.0.1).
2024-10-01T17:04:10.277268Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 9.0.1) MySQL Community Server - GPL.
2024-10-01T17:04:10.277290Z 0 [System] [MY-015016] [Server] MySQL Server - end.
2024-10-01 17:04:10+00:00 [Note] [Entrypoint]: Temporary server stopped
2024-10-01 17:04:10+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
2024-10-01T17:04:10.475599Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2024-10-01T17:04:10.622838Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 9.0.1) starting as process 1
2024-10-01T17:04:10.623975Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2024-10-01T17:04:10.626794Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2024-10-01T17:04:10.705627Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2024-10-01T17:04:10.831741Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2024-10-01T17:04:10.831785Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2024-10-01T17:04:10.834154Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2024-10-01T17:04:10.842164Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2024-10-01T17:04:10.842236Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '9.0.1' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
In the vanilla there are twice the pair "ready for connections" which makes the regular expression match, but it fails for the custom one. Of course, another approach would be to create a custom testcontainers docker image class but actually this isn't a good idea because the logs for MySql can change anytime and as soon as the official image gets updated testcontainers MySql image class may fail to properly check if the container has started or not.
To Reproduce
Create a docker image like the Dockerfile above and use it in test using testcontainers like below
>>> import sqlalchemy
>>> from testcontainers.mysql import MySqlContainer
>>> with MySqlContainer('mysql-custom:latest') as mysql:
... engine = sqlalchemy.create_engine(mysql.get_connection_url())
... with engine.begin() as connection:
... result = connection.execute(sqlalchemy.text("select version()"))
... version, = result.fetchone()
The test will timeout on waiting for the container to start even that it has already started.
I monkey patched the implementation on my local project like below and worked well. The approach below is more reliable as it relies on standard Mysql tooling to check if the service is running or not, also it make use of testcontainers builtin constructs where both tends to be more future-proof.
File modules/mysql/testcontainers/mysql/__init__.py
...
# this code overwrite the method `_connect` of class `MySqlContainer` specified in the file above.
def _connect(self) -> None:
def check_if_is_running():
escaped_single_password = self.password.replace("'", "'\"'\"'")
result = self.exec(
[
"sh",
"-c",
f"mysql -u {self.username} -p{escaped_single_password} -h {self.get_container_host_ip()} -P {self.port} -e 'SELECT VERSION();'"
]
)
if result.exit_code != 0:
raise ConnectionError(f"Failed to connect to MySQL: {result.output}")
wait_for(check_if_is_running)
I have it running and tested on my project and I would be happy to submit a PR.
Runtime environment
Provide a summary of your runtime environment. Which operating system, python version, and docker version are you using? What is the version of testcontainers-python
you are using? You can run the following commands to get the relevant information.
# Get the operating system information (on a unix os).
$ uname -a
Darwin ****** 24.1.0 Darwin Kernel Version 24.1.0: Tue Sep 17 07:49:16 PDT 2024; root:xnu-11215.40.59~38/RELEASE_ARM64_T6030 arm6
# Get the python version.
$ python --version
Python 3.11.9
# Get the docker version and other docker information.
$ docker info
Client:
Version: 27.2.0
Context: desktop-linux
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.16.2-desktop.1
Path: /Users/*****/.docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.29.2-desktop.2
Path: /Users/*****/.docker/cli-plugins/docker-compose
debug: Get a shell into any image or container (Docker Inc.)
Version: 0.0.34
Path: /Users/*****/.docker/cli-plugins/docker-debug
desktop: Docker Desktop commands (Alpha) (Docker Inc.)
Version: v0.0.15
Path: /Users/*****/.docker/cli-plugins/docker-desktop
dev: Docker Dev Environments (Docker Inc.)
Version: v0.1.2
Path: /Users/*****/.docker/cli-plugins/docker-dev
extension: Manages Docker extensions (Docker Inc.)
Version: v0.2.25
Path: /Users/*****/.docker/cli-plugins/docker-extension
feedback: Provide feedback, right in your terminal! (Docker Inc.)
Version: v1.0.5
Path: /Users/*****/.docker/cli-plugins/docker-feedback
init: Creates Docker-related starter files for your project (Docker Inc.)
Version: v1.3.0
Path: /Users/*****/.docker/cli-plugins/docker-init
sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc.)
Version: 0.6.0
Path: /Users/*****/.docker/cli-plugins/docker-sbom
scout: Docker Scout (Docker Inc.)
Version: v1.13.0
Path: /Users/*****/.docker/cli-plugins/docker-scout
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 25
Server Version: 27.2.0
Storage Driver: overlayfs
driver-type: io.containerd.snapshotter.v1
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 8fc6bcff51318944179630522a095cc9dbf9f353
runc version: v1.1.13-0-g58aa920
init version: de40ad0
Security Options:
seccomp
Profile: unconfined
cgroupns
Kernel Version: 6.10.4-linuxkit
Operating System: Docker Desktop
OSType: linux
Architecture: aarch64
CPUs: 12
Total Memory: 17.3GiB
Name: docker-desktop
ID: 98c933e7-9d31-46e1-a51e-eda5f0f7dc99
Docker Root Dir: /var/lib/docker
Debug Mode: false
HTTP Proxy: http.docker.internal:3128
HTTPS Proxy: http.docker.internal:3128
No Proxy: hubproxy.docker.internal
Labels:
com.docker.desktop.address=unix:///Users/*****/Library/Containers/com.docker.docker/Data/docker-cli.sock
Experimental: false
Insecure Registries:
hubproxy.docker.internal:5555
127.0.0.0/8
Live Restore Enabled: false
# Get all python packages.
$ pip freeze
aiohappyeyeballs==2.4.0
aiohttp==3.10.5
aiohttp-cors==0.7.0
aiosignal==1.3.1
alabaster==0.7.16
annotated-types==0.7.0
anytree==2.12.1
appnope==0.1.4
argcomplete==3.5.0
astroid==2.15.8
asttokens==2.4.1
attrs==24.2.0
azure-core==1.30.2
azure-storage-blob==12.22.0
azure-storage-file-datalake==12.16.0
Babel==2.15.0
bandit==1.7.9
bcrypt==4.2.0
blis==0.7.11
boto3==1.34.78
botocore==1.34.156
cachetools==5.4.0
catalogue==2.0.10
certifi==2024.7.4
cffi==1.17.0
charset-normalizer==3.3.2
click==8.1.7
cloudpathlib==0.18.1
colorful==0.5.6
comm==0.2.2
confection==0.1.5
contourpy==1.2.1
coverage==7.6.1
cryptography==42.0.8
cx_Oracle==8.3.0
cycler==0.12.1
cymem==2.0.8
databricks-sql-connector==3.3.0
de-core-news-md @ https://github.com/explosion/spacy-models/releases/download/de_core_news_md-3.7.0/de_core_news_md-3.7.0-py3-none-any.whl#sha256=1426896f135b7e6314637faa9025a3e580c9ba2785372ccffe723dc20b41c493
de-core-news-sm @ https://github.com/explosion/spacy-models/releases/download/de_core_news_sm-3.7.0/de_core_news_sm-3.7.0-py3-none-any.whl#sha256=d88c737eb7eb766f730f6a2dcb99dfcdb81623e1e0d89a9c638a2182ac19c52e
debugpy==1.8.5
decorator==5.1.1
deepdiff==6.7.1
defusedxml==0.7.1
dill==0.3.8
diskcache==5.6.3
distlib==0.3.8
docker==7.1.0
docutils==0.17.1
dtaidistance==2.3.12
ed25519==1.5
elastic-transport==8.13.1
elasticsearch==8.14.0
en-core-web-md @ https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.7.1/en_core_web_md-3.7.1-py3-none-any.whl#sha256=6a0f857a2b4d219c6fa17d455f82430b365bf53171a2d919b9376e5dc9be032e
en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.7.1/en_core_web_sm-3.7.1-py3-none-any.whl#sha256=86cc141f63942d4b2c5fcee06630fd6f904788d2f0ab005cce45aadb8fb73889
et-xmlfile==1.1.0
executing==2.0.1
Faker==24.4.0
ff3==1.0.2
filelock==3.15.4
flake8==4.0.1
fonttools==4.53.1
frozendict==2.4.4
frozenlist==1.4.1
future==1.0.0
geohash2==1.1
geojson==3.1.0
google-api-core==2.19.2
google-auth==2.34.0
googleapis-common-protos==1.65.0
greenlet==3.0.3
grpcio==1.66.1
gssapi==1.8.3
hotxlfp==0.0.15
ibm-db-sa==0.4.0
ibm_db==3.2.3
idna==3.7
imagesize==1.4.1
importlib_resources==6.4.0
iniconfig==2.0.0
ipykernel==6.29.5
ipython==8.26.0
isodate==0.6.1
isort==5.13.2
ja-core-news-sm @ https://github.com/explosion/spacy-models/releases/download/ja_core_news_sm-3.7.0/ja_core_news_sm-3.7.0-py3-none-any.whl#sha256=1191e5bbffcc90670146616c274a64850e54d12070bc5846e78a094f2f6fcfca
jedi==0.19.1
Jinja2==3.1.4
jmespath==1.0.1
joblib==1.4.2
jsonschema==4.23.0
jsonschema-specifications==2023.12.1
jupyter_client==8.6.2
jupyter_core==5.7.2
kiwisolver==1.4.5
langcodes==3.4.0
language_data==1.2.0
lazy-object-proxy==1.10.0
Levenshtein==0.25.1
libnfs @ git+https://github.com/sahlberg/libnfs-python.git@b3cab5a6c34dbafc5e58137d7f91f892c0d46dc5
lz4==4.3.3
marisa-trie==1.2.0
markdown-it-py==3.0.0
MarkupSafe==2.1.5
matplotlib==3.9.1.post1
matplotlib-inline==0.1.7
mccabe==0.6.1
mdurl==0.1.2
mimesis==15.1.0
moto==5.0.12
msgpack==1.0.8
multidict==6.1.0
murmurhash==1.0.10
mysql-connector-python==8.4.0
mysqlclient==2.2.4
nest-asyncio==1.6.0
networkx==3.3
nl-core-news-lg @ https://github.com/explosion/spacy-models/releases/download/nl_core_news_lg-3.7.0/nl_core_news_lg-3.7.0-py3-none-any.whl#sha256=02194e98105584a6e5008a523a94a5d6e4da2feb0964741646c507c8e20730d4
nl-core-news-md @ https://github.com/explosion/spacy-models/releases/download/nl_core_news_md-3.7.0/nl_core_news_md-3.7.0-py3-none-any.whl#sha256=9b0bacc6d15202bbbd3a9585003d9edec44c6a1f1d819b51e8bc6a6d0b4458a8
nl-core-news-sm @ https://github.com/explosion/spacy-models/releases/download/nl_core_news_sm-3.7.0/nl_core_news_sm-3.7.0-py3-none-any.whl#sha256=9255c3ce9e639f0a7aa8e898f4514e6ad803284858241385e045f99637753770
numpy==1.26.4
numpydoc==1.5.0
oauthlib==3.2.2
odbcinst==1.0.1
opencensus==0.11.4
opencensus-context==0.1.3
openpyxl==3.1.5
ordered-set==4.1.0
packaging==24.1
pandas==2.1.4
paramiko==3.4.0
parso==0.8.4
pbr==6.0.0
pexpect==4.9.0
phonenumbers==8.13.42
pillow==10.4.0
pipx==1.6.0
platformdirs==4.2.2
pluggy==1.5.0
ply==3.11
preshed==3.0.9
presidio-analyzer==2.2.353
presidio-anonymizer==2.2.353
prometheus_client==0.20.0
prompt_toolkit==3.0.47
proto-plus==1.24.0
protobuf==5.27.3
psutil==6.0.0
psycopg2-binary==2.9.9
ptyprocess==0.7.0
pure-sasl==0.6.2
pure_eval==0.2.3
py-cpuinfo==9.0.0
py-spy==0.3.14
pyarrow==14.0.2
pyasn1==0.6.1
pyasn1_modules==0.4.1
pycodestyle==2.8.0
pycparser==2.22
pycryptodome==3.20.0
pydantic==2.8.2
pydantic_core==2.20.1
pyfarmhash==0.3.2
pyflakes==2.4.0
Pygments==2.18.0
PyHive==0.7.0
pylint==2.17.7
Pympler==1.1
PyMySQL==1.1.1
PyNaCl==1.5.0
pyodbc==5.1.0
pyOpenSSL==24.2.1
pyparsing==3.1.2
PyRSMQ==0.5.1
pytest==7.4.4
pytest-azurepipelines==1.0.5
pytest-benchmark==4.0.0
pytest-cov==4.1.0
pytest-env==1.1.3
pytest-nunit==1.0.7
python-dateutil==2.9.0.post0
python-Levenshtein==0.25.1
pytz==2024.1
PyYAML==6.0.2
pyzmq==26.1.0
rapidfuzz==3.9.6
ray==2.10.0
redis==5.0.8
referencing==0.35.1
regex==2024.7.24
requests==2.32.3
requests-file==2.1.0
responses==0.25.3
rich==13.7.1
rpds-py==0.20.0
rsa==4.9
ruff==0.5.6
s3transfer==0.10.2
scikit-learn==1.5.1
scipy==1.13.1
seaborn==0.13.2
shapely==2.0.5
shellingham==1.5.4
six==1.16.0
smart-open==7.0.4
snowballstemmer==2.2.0
spacy==3.7.5
spacy-legacy==3.0.12
spacy-loggers==1.0.5
Sphinx==4.5.0
sphinx-autoapi==1.9.0
sphinx-rtd-theme==1.3.0
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
SQLAlchemy==2.0.32
srsly==2.4.8
sshtunnel==0.4.0
stack-data==0.6.3
stevedore==5.2.0
SudachiDict-core==20240716
SudachiPy==0.6.8
testcontainers==4.8.1
thinc==8.2.5
threadpoolctl==3.5.0
thrift==0.16.0
thrift-sasl==0.4.3
tldextract==5.1.2
tomlkit==0.13.0
tornado==6.4.1
tqdm==4.66.5
traitlets==5.14.3
typer==0.12.3
typing_extensions==4.12.2
tzdata==2024.1
Unidecode==1.3.8
urllib3==2.2.2
userpath==1.9.2
virtualenv==20.26.4
wasabi==1.1.3
wcwidth==0.2.13
weasel==0.4.1
Werkzeug==3.0.3
wrapt==1.16.0
xmltodict==0.13.0
yarl==1.11.1