alessandro trinca tornidor commited on
Commit
d7027f5
·
1 Parent(s): 7024f75

ci: add docker and docker compose support

Browse files
.gitignore CHANGED
@@ -283,3 +283,7 @@ fabric.properties
283
  # node_modules
284
  node_modules
285
  */node_modules/*/*
 
 
 
 
 
283
  # node_modules
284
  node_modules
285
  */node_modules/*/*
286
+
287
+ # mongodb
288
+ mongo/*
289
+ mongodb/*
Dockerfile ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM registry.gitlab.com/aletrn/my_ghost_writer_base:0.4.0
2
+
3
+ LABEL authors="trincadev"
4
+
5
+ # Include global arg in this stage of the build
6
+ ARG WORKDIR_ROOT="/var/task"
7
+ ENV VIRTUAL_ENV=${WORKDIR_ROOT}/.venv PATH="${WORKDIR_ROOT}/.venv/bin:$PATH"
8
+ ENV WRITE_TMP_ON_DISK=""
9
+ ENV MOUNT_GRADIO_APP=""
10
+ ENV VITE__STATIC_INDEX_URL="/static"
11
+ ENV VITE__INDEX_URL="/"
12
+ ENV HOME_USER=/home/python
13
+
14
+ # Set working directory to function root directory
15
+ WORKDIR ${WORKDIR_ROOT}
16
+ # workaround for missing /home folder
17
+ RUN ls -ld ${HOME_USER}
18
+ RUN ls -lA ${HOME_USER}
19
+
20
+ COPY --chown=python:python requirements_poetry.txt pyproject.toml poetry.lock README.md ${WORKDIR_ROOT}/
21
+ COPY --chown=python:python ./lite.koboldai.net ${WORKDIR_ROOT}/lite.koboldai.net
22
+ COPY --chown=python:python ./my_ghost_writer ${WORKDIR_ROOT}/my_ghost_writer
23
+ COPY --chown=python:python ./static ${WORKDIR_ROOT}/static
24
+ # RUN . ${WORKDIR_ROOT}/.venv && which python && echo "# install samgis #" && pip install .
25
+ RUN if [ "${WRITE_TMP_ON_DISK}" != "" ]; then mkdir {WRITE_TMP_ON_DISK}; fi
26
+ RUN if [ "${WRITE_TMP_ON_DISK}" != "" ]; then ls -l {WRITE_TMP_ON_DISK}; fi
27
+
28
+ RUN ls -l /usr/bin/which
29
+ RUN /usr/bin/which python
30
+ RUN python --version
31
+ RUN pip list
32
+ RUN echo "PATH: ${PATH}."
33
+ RUN echo "WORKDIR_ROOT: ${WORKDIR_ROOT}."
34
+ RUN ls -l ${WORKDIR_ROOT}
35
+ RUN ls -ld ${WORKDIR_ROOT}
36
+ RUN ls -l ${WORKDIR_ROOT}/
37
+ RUN python -c "import sys; print(sys.path)"
38
+ RUN python -c "import fastapi"
39
+ RUN python -c "import uvicorn"
40
+ RUN python -c "import pymongo"
41
+ RUN python -c "import requests"
42
+ RUN df -h
43
+ RUN ls -l ${WORKDIR_ROOT}/my_ghost_writer/app.py
44
+ RUN ls -l ${WORKDIR_ROOT}/lite.koboldai.net/index.html
45
+
46
+ USER 999
47
+ EXPOSE 7860
48
+
49
+ CMD ["uvicorn", "my_ghost_writer.app:app", "--host", "0.0.0.0", "--port", "7860"]
50
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD curl -f http://localhost:7860/health
README.md CHANGED
@@ -12,6 +12,7 @@ A simple helper for writers.
12
  * Use NLP to stem words for more accurate results
13
  * Support for uploading or typing in text
14
  * User-friendly interface with a simple editor and display of word frequencies
 
15
 
16
  ## Technologies Used
17
 
@@ -44,7 +45,9 @@ If using the webserver with the module (`python -m ghost_writer.app.py`) it's ne
44
  * `index.css`
45
  * `API_MODE` to avoid mounting the static folder. This will define only the API endpoints
46
  * `/health`
 
47
  * `/words-frequency`
 
48
 
49
  ### Installation script
50
 
@@ -80,6 +83,28 @@ docker run --env=MONGO_MAJOR=8.0 \
80
  -d mongo:8-noble
81
  ```
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  ## Contributing
84
 
85
  Pull requests are welcome! Please make sure to test your changes thoroughly before submitting a pull request.
 
12
  * Use NLP to stem words for more accurate results
13
  * Support for uploading or typing in text
14
  * User-friendly interface with a simple editor and display of word frequencies
15
+ * WIP: thesaurus, powered by [wordsapi](https://www.wordsapi.com/) (you need to get your own wordsapi API key)
16
 
17
  ## Technologies Used
18
 
 
45
  * `index.css`
46
  * `API_MODE` to avoid mounting the static folder. This will define only the API endpoints
47
  * `/health`
48
+ * `/health-mongo`
49
  * `/words-frequency`
50
+ * `/thesaurus-wordsapi`
51
 
52
  ### Installation script
53
 
 
83
  -d mongo:8-noble
84
  ```
85
 
86
+ ## Docker
87
+
88
+ To build the project with docker:
89
+
90
+ ```
91
+ DOCKER_VERSION=$(grep version pyproject.toml |head -1|cut -d'=' -f2|cut -d'"' -f2);
92
+ docker build . --progress=plain --tag registry.gitlab.com/aletrn/my_ghost_writer:${DOCKER_VERSION}
93
+ docker build . -f dockerfiles/dockerfile_my_ghost_writer_base --progress=plain --tag registry.gitlab.com/aletrn/my_ghost_writer_base:${DOCKER_VERSION}
94
+ ```
95
+
96
+ To run the docker container (you still need to configure the mongodb endpoint to use the single my_ghost_writer container):
97
+ ```
98
+ docker run -d --name my_ghost_writer -p 7860:7860 -e WORDSAPI_KEY=${WORDSAPI_KEY} -e ME_CONFIG_MONGODB_USE_OK=TRUE registry.gitlab.com/aletrn/my_ghost_writer:0.4.0; docker logs -f my_ghost_writer
99
+ ```
100
+
101
+ To source more than one env variable, you can use this command:
102
+ ```
103
+ set -o allexport && source <(cat ./.env) && set +o allexport;
104
+ ```
105
+
106
+ Instead to simple
107
+
108
  ## Contributing
109
 
110
  Pull requests are welcome! Please make sure to test your changes thoroughly before submitting a pull request.
docker-compose.yaml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ services:
2
+ my_ghost_writer:
3
+ env_file:
4
+ - ./.env
5
+ - ./.env_source
6
+ build:
7
+ context: .
8
+ tags:
9
+ - registry.gitlab.com/aletrn/my_ghost_writer:0.4.0
10
+ ports:
11
+ - "7860:7860"
12
+ environment:
13
+ ME_CONFIG_MONGODB_URL: mongodb://mongo:27017/
14
+
15
+ mongo:
16
+ environment:
17
+ - MONGO_MAJOR=8.0
18
+ - HOME=/data/db
19
+ image: "mongo:8-noble"
20
+ volumes:
21
+ - ./mongo:/data
22
+ - /data/configdb
23
+ - /data/db
24
+ ports:
25
+ - "27017:27017"
26
+ restart: always
dockerfiles/dockerfile_my_ghost_writer_base ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Include global ARGs at the dockerfile top
2
+ ARG ARCH="x86_64"
3
+ ARG WORKDIR_ROOT="/var/task"
4
+ ARG FASTAPI_STATIC="${WORKDIR_ROOT}/static"
5
+ ARG PYTHONPATH="${WORKDIR_ROOT}:${PYTHONPATH}:/usr/local/lib/python3/dist-packages"
6
+ ARG POETRY_NO_INTERACTION=1
7
+ ARG POETRY_VIRTUALENVS_IN_PROJECT=1
8
+ ARG POETRY_VIRTUALENVS_CREATE=1
9
+ ARG POETRY_CACHE_DIR=/tmp/poetry_cache
10
+ ARG HOME_USER=/home/python
11
+
12
+ FROM python:3.13-bookworm AS builder_global
13
+ LABEL authors="trincadev"
14
+
15
+ ARG ARCH
16
+ ARG WORKDIR_ROOT
17
+ ARG PYTHONPATH
18
+ ARG POETRY_NO_INTERACTION
19
+ ARG POETRY_VIRTUALENVS_IN_PROJECT
20
+ ARG POETRY_VIRTUALENVS_CREATE
21
+ ARG POETRY_CACHE_DIR
22
+
23
+ RUN echo "ARCH: $ARCH ..."
24
+ RUN echo "WORKDIR_ROOT: ${WORKDIR_ROOT} ..."
25
+ RUN echo "PYTHONPATH: ${PYTHONPATH} ..."
26
+ RUN echo "HOME_USER: ${HOME_USER} ..."
27
+ RUN echo "==========================="
28
+
29
+ RUN echo "ARG POETRY_CACHE_DIR: ${POETRY_CACHE_DIR} ..."
30
+ RUN echo "ARG PYTHONPATH: $PYTHONPATH ..."
31
+ RUN echo "arg dep:"
32
+
33
+ RUN ls -ld ${HOME_USER}
34
+ RUN ls -l ${HOME_USER}
35
+ RUN groupadd -g 999 python && useradd -r -u 999 -g python python
36
+ # Set working directory to function root directory
37
+ RUN mkdir ${WORKDIR_ROOT} && chown python:python ${WORKDIR_ROOT}
38
+ WORKDIR ${WORKDIR_ROOT}
39
+ COPY --chown=python:python requirements_poetry.txt pyproject.toml poetry.lock README.md ${WORKDIR_ROOT}/
40
+ COPY --chown=python:python ../lite.koboldai.net ${WORKDIR_ROOT}/lite.koboldai.net
41
+ COPY --chown=python:python ../my_ghost_writer ${WORKDIR_ROOT}/my_ghost_writer
42
+
43
+ # poetry installation path is NOT within ${WORKDIR_ROOT}: not needed for runtime docker image
44
+ RUN python -m pip install -r ${WORKDIR_ROOT}/requirements_poetry.txt
45
+
46
+ RUN which poetry && poetry --version && poetry config --list
47
+ RUN poetry config virtualenvs.path ${WORKDIR_ROOT}
48
+ RUN echo "# poetry config --list #" && poetry config --list
49
+ RUN poetry install --with webserver --no-cache
50
+
51
+ FROM python:3.13-slim-bookworm AS runtime
52
+
53
+ ARG ARCH
54
+ ARG WORKDIR_ROOT
55
+ ARG HOME_USER
56
+
57
+ ENV VIRTUAL_ENV=${WORKDIR_ROOT}/.venv PATH="${WORKDIR_ROOT}/.venv/bin:$PATH"
58
+
59
+ # workaround for missing /home folder
60
+ RUN mkdir -p /home
61
+ RUN groupadd -g 999 python && useradd -r -u 999 -g python python
62
+ RUN ls -l /home
63
+ RUN ls -ld /home
64
+ RUN mkdir -p ${HOME_USER} ${HOME_USER}/.config && chown python:python -R ${HOME_USER}
65
+ RUN ls -ld ${HOME_USER}
66
+ RUN ls -lA ${HOME_USER}
67
+ RUN mkdir ${WORKDIR_ROOT} && chown python:python ${WORKDIR_ROOT}
68
+
69
+ COPY --from=builder_global ${WORKDIR_ROOT}/.venv ${WORKDIR_ROOT}/.venv
70
+ RUN . ${WORKDIR_ROOT}/.venv && which python && pip list
71
+
72
+ RUN echo "new WORKDIR_ROOT after hidden venv copy => ${WORKDIR_ROOT}"
73
+ RUN ls -ld ${WORKDIR_ROOT}/
74
+ RUN ls -lA ${WORKDIR_ROOT}/
my_ghost_writer/app.py CHANGED
@@ -4,7 +4,6 @@ import json
4
  from datetime import datetime
5
 
6
  import requests
7
- import starlette.status
8
  import uvicorn
9
  from asgi_correlation_id import CorrelationIdMiddleware
10
  from fastapi import FastAPI, Request
@@ -16,21 +15,22 @@ from pymongo import __version__ as pymongo_version
16
  from pymongo.errors import PyMongoError
17
 
18
  from my_ghost_writer import pymongo_operations_rw, exception_handlers
19
- from my_ghost_writer.constants import (app_logger, ALLOWED_ORIGIN_LIST, API_MODE, DOMAIN, IS_TESTING, LOG_LEVEL, PORT,
20
- STATIC_FOLDER, WORDSAPI_KEY, WORDSAPI_URL, RAPIDAPI_HOST, MONGO_USE_OK, MONGO_HEALTHCHECK_SLEEP)
 
21
  from my_ghost_writer.pymongo_utils import mongodb_health_check
22
  from my_ghost_writer.text_parsers import text_stemming
23
  from my_ghost_writer.type_hints import RequestTextFrequencyBody, RequestQueryThesaurusWordsapiBody
24
 
25
 
26
  async def mongo_health_check_background_task():
27
- app_logger.info(f"starting task, MONGO_USE_OK:{MONGO_USE_OK}...")
28
- while MONGO_USE_OK:
29
  try:
30
  db_ok["mongo_ok"] = health_mongo() == "Mongodb: still alive..."
31
  except PyMongoError:
32
  db_ok["mongo_ok"] = False
33
- await asyncio.sleep(MONGO_HEALTHCHECK_SLEEP)
34
 
35
 
36
  async def lifespan(app: FastAPI):
@@ -52,7 +52,7 @@ app.add_middleware(
52
  allow_credentials=True,
53
  allow_methods=["GET", "POST"]
54
  )
55
- db_ok = {"mongo_ok": MONGO_USE_OK}
56
 
57
 
58
  @app.middleware("http")
@@ -75,7 +75,7 @@ def health():
75
  @app.get("/health-mongo")
76
  def health_mongo() -> str:
77
  app_logger.info(f"pymongo driver version:{pymongo_version}!")
78
- if MONGO_USE_OK:
79
  try:
80
  db_ok["mongo_ok"] = mongodb_health_check()
81
  return "Mongodb: still alive..."
@@ -83,7 +83,7 @@ def health_mongo() -> str:
83
  app_logger.error(str(pme))
84
  db_ok["mongo_ok"] = False
85
  raise HTTPException("mongo not ok!")
86
- return f"MONGO_USE_OK:{MONGO_USE_OK}..."
87
 
88
 
89
  @app.post("/words-frequency")
@@ -184,6 +184,14 @@ except Exception as ex_mount_static:
184
  if not API_MODE:
185
  app_logger.exception(f"since API_MODE is {API_MODE} we will raise the exception!")
186
  raise ex_mount_static
 
 
 
 
 
 
 
 
187
 
188
  # add the CorrelationIdMiddleware AFTER the @app.middleware("http") decorated function to avoid missing request id
189
  app.add_middleware(CorrelationIdMiddleware)
 
4
  from datetime import datetime
5
 
6
  import requests
 
7
  import uvicorn
8
  from asgi_correlation_id import CorrelationIdMiddleware
9
  from fastapi import FastAPI, Request
 
15
  from pymongo.errors import PyMongoError
16
 
17
  from my_ghost_writer import pymongo_operations_rw, exception_handlers
18
+ from my_ghost_writer.constants import (app_logger, ALLOWED_ORIGIN_LIST, API_MODE, DOMAIN, IS_TESTING, STATIC_FOLDER,
19
+ WORDSAPI_KEY, WORDSAPI_URL, RAPIDAPI_HOST, ME_CONFIG_MONGODB_USE_OK, ME_CONFIG_MONGODB_HEALTHCHECK_SLEEP,
20
+ STATIC_FOLDER_LITEKOBOLDAINET, LOG_LEVEL, PORT)
21
  from my_ghost_writer.pymongo_utils import mongodb_health_check
22
  from my_ghost_writer.text_parsers import text_stemming
23
  from my_ghost_writer.type_hints import RequestTextFrequencyBody, RequestQueryThesaurusWordsapiBody
24
 
25
 
26
  async def mongo_health_check_background_task():
27
+ app_logger.info(f"starting task, ME_CONFIG_MONGODB_USE_OK:{ME_CONFIG_MONGODB_USE_OK}...")
28
+ while ME_CONFIG_MONGODB_USE_OK:
29
  try:
30
  db_ok["mongo_ok"] = health_mongo() == "Mongodb: still alive..."
31
  except PyMongoError:
32
  db_ok["mongo_ok"] = False
33
+ await asyncio.sleep(ME_CONFIG_MONGODB_HEALTHCHECK_SLEEP)
34
 
35
 
36
  async def lifespan(app: FastAPI):
 
52
  allow_credentials=True,
53
  allow_methods=["GET", "POST"]
54
  )
55
+ db_ok = {"mongo_ok": ME_CONFIG_MONGODB_USE_OK}
56
 
57
 
58
  @app.middleware("http")
 
75
  @app.get("/health-mongo")
76
  def health_mongo() -> str:
77
  app_logger.info(f"pymongo driver version:{pymongo_version}!")
78
+ if ME_CONFIG_MONGODB_USE_OK:
79
  try:
80
  db_ok["mongo_ok"] = mongodb_health_check()
81
  return "Mongodb: still alive..."
 
83
  app_logger.error(str(pme))
84
  db_ok["mongo_ok"] = False
85
  raise HTTPException("mongo not ok!")
86
+ return f"ME_CONFIG_MONGODB_USE_OK:{ME_CONFIG_MONGODB_USE_OK}..."
87
 
88
 
89
  @app.post("/words-frequency")
 
184
  if not API_MODE:
185
  app_logger.exception(f"since API_MODE is {API_MODE} we will raise the exception!")
186
  raise ex_mount_static
187
+ try:
188
+ app.mount("/lite.koboldai.net", StaticFiles(directory=STATIC_FOLDER_LITEKOBOLDAINET, html=True), name="lite.koboldai.net")
189
+ except Exception as ex_mount_static1:
190
+ app_logger.error(
191
+ f"Failed to mount static folder: {STATIC_FOLDER_LITEKOBOLDAINET}, exception: {ex_mount_static1}, API_MODE: {API_MODE}!")
192
+ if not API_MODE:
193
+ app_logger.exception(f"since API_MODE is {API_MODE} we will raise the exception!")
194
+ raise ex_mount_static1
195
 
196
  # add the CorrelationIdMiddleware AFTER the @app.middleware("http") decorated function to avoid missing request id
197
  app.add_middleware(CorrelationIdMiddleware)
my_ghost_writer/constants.py CHANGED
@@ -9,7 +9,9 @@ from my_ghost_writer import session_logger
9
  load_dotenv()
10
  PROJECT_ROOT_FOLDER = Path(__file__).parent.parent
11
  STATIC_FOLDER = PROJECT_ROOT_FOLDER / "static"
 
12
  STATIC_FOLDER = Path(os.getenv("STATIC_FOLDER", str(STATIC_FOLDER)))
 
13
  DOMAIN=os.getenv("DOMAIN", "localhost")
14
  PORT=int(os.getenv("PORT", 7860))
15
  ALLOWED_ORIGIN_LIST = os.getenv('ALLOWED_ORIGIN', f'http://{DOMAIN}:{PORT}').split(",")
@@ -21,16 +23,13 @@ N_WORDS_GRAM = int(os.getenv("N_WORDS_GRAM", 2))
21
  WORDSAPI_KEY = os.getenv("WORDSAPI_KEY")
22
  WORDSAPI_URL = os.getenv("WORDSAPI_URL", "https://wordsapiv1.p.rapidapi.com/words")
23
  RAPIDAPI_HOST = os.getenv("RAPIDAPI_HOST", "wordsapiv1.p.rapidapi.com")
24
- MONGO_USE_OK = bool(os.getenv("MONGO_USE_OK", ""))
25
- MONGO_CONNECTION_STRING_LOCAL = "mongodb://localhost:27017"
26
- MONGO_CONNECTION_STRING = os.getenv("MONGO_CONNECTION_STRING", MONGO_CONNECTION_STRING_LOCAL)
27
- MONGO_CONNECTION_TIMEOUT_LOCAL = int(os.getenv("MONGO_CONNECTION_TIMEOUT_LOCAL", 200))
28
- MONGO_CONNECTION_TIMEOUT_REMOTE = int(os.getenv("MONGO_CONNECTION_TIMEOUT_REMOTE", 3000))
29
- MONGO_CONNECTION_TIMEOUT = int(os.getenv(
30
- "MONGO_CONNECTION_TIMEOUT",
31
- MONGO_CONNECTION_TIMEOUT_LOCAL if MONGO_CONNECTION_STRING == MONGO_CONNECTION_STRING_LOCAL else MONGO_CONNECTION_TIMEOUT_REMOTE
32
- ))
33
- MONGO_HEALTHCHECK_SLEEP = int(os.getenv("MONGO_HEALTHCHECK_SLEEP", 900))
34
  DEFAULT_DBNAME_THESAURUS = "thesaurus"
35
  DEFAULT_COLLECTION_THESAURUS =os.getenv("DEFAULT_COLLECTION_THESAURUS", "wordsapi")
36
  session_logger.setup_logging(json_logs=LOG_JSON_FORMAT, log_level=LOG_LEVEL)
 
9
  load_dotenv()
10
  PROJECT_ROOT_FOLDER = Path(__file__).parent.parent
11
  STATIC_FOLDER = PROJECT_ROOT_FOLDER / "static"
12
+ STATIC_FOLDER_LITEKOBOLDAINET = PROJECT_ROOT_FOLDER / "lite.koboldai.net"
13
  STATIC_FOLDER = Path(os.getenv("STATIC_FOLDER", str(STATIC_FOLDER)))
14
+ STATIC_FOLDER_LITEKOBOLDAINET = Path(os.getenv("STATIC_FOLDER_LITEKOBOLDAINET", str(STATIC_FOLDER_LITEKOBOLDAINET)))
15
  DOMAIN=os.getenv("DOMAIN", "localhost")
16
  PORT=int(os.getenv("PORT", 7860))
17
  ALLOWED_ORIGIN_LIST = os.getenv('ALLOWED_ORIGIN', f'http://{DOMAIN}:{PORT}').split(",")
 
23
  WORDSAPI_KEY = os.getenv("WORDSAPI_KEY")
24
  WORDSAPI_URL = os.getenv("WORDSAPI_URL", "https://wordsapiv1.p.rapidapi.com/words")
25
  RAPIDAPI_HOST = os.getenv("RAPIDAPI_HOST", "wordsapiv1.p.rapidapi.com")
26
+ ME_CONFIG_MONGODB_USE_OK = bool(os.getenv("ME_CONFIG_MONGODB_USE_OK", ""))
27
+ ME_CONFIG_MONGODB_URL_LOCAL = "mongodb://localhost:27017"
28
+ ME_CONFIG_MONGODB_URL = os.getenv("ME_CONFIG_MONGODB_URL", ME_CONFIG_MONGODB_URL_LOCAL)
29
+ ME_CONFIG_MONGODB_TIMEOUT_LOCAL = int(os.getenv("ME_CONFIG_MONGODB_TIMEOUT_LOCAL", 200))
30
+ ME_CONFIG_MONGODB_TIMEOUT_REMOTE = int(os.getenv("ME_CONFIG_MONGODB_TIMEOUT_REMOTE", 3000))
31
+ ME_CONFIG_MONGODB_TIMEOUT = int(os.getenv( "ME_CONFIG_MONGODB_TIMEOUT", ME_CONFIG_MONGODB_TIMEOUT_LOCAL if ME_CONFIG_MONGODB_URL == ME_CONFIG_MONGODB_URL_LOCAL else ME_CONFIG_MONGODB_TIMEOUT_REMOTE))
32
+ ME_CONFIG_MONGODB_HEALTHCHECK_SLEEP = int(os.getenv("ME_CONFIG_MONGODB_HEALTHCHECK_SLEEP", 900))
 
 
 
33
  DEFAULT_DBNAME_THESAURUS = "thesaurus"
34
  DEFAULT_COLLECTION_THESAURUS =os.getenv("DEFAULT_COLLECTION_THESAURUS", "wordsapi")
35
  session_logger.setup_logging(json_logs=LOG_JSON_FORMAT, log_level=LOG_LEVEL)
my_ghost_writer/pymongo_utils.py CHANGED
@@ -1,10 +1,10 @@
1
  from pymongo import MongoClient
2
 
3
- from my_ghost_writer.constants import DEFAULT_DBNAME_THESAURUS, MONGO_CONNECTION_STRING, DEFAULT_COLLECTION_THESAURUS, MONGO_CONNECTION_TIMEOUT, app_logger
4
 
5
 
6
  def get_client() -> MongoClient:
7
- client = MongoClient(MONGO_CONNECTION_STRING, timeoutMS=MONGO_CONNECTION_TIMEOUT)
8
  return client
9
 
10
 
 
1
  from pymongo import MongoClient
2
 
3
+ from my_ghost_writer.constants import DEFAULT_DBNAME_THESAURUS, ME_CONFIG_MONGODB_URL, DEFAULT_COLLECTION_THESAURUS, ME_CONFIG_MONGODB_TIMEOUT, app_logger
4
 
5
 
6
  def get_client() -> MongoClient:
7
+ client = MongoClient(ME_CONFIG_MONGODB_URL, timeoutMS=ME_CONFIG_MONGODB_TIMEOUT)
8
  return client
9
 
10
 
poetry.lock CHANGED
@@ -18,7 +18,7 @@ version = "4.9.0"
18
  description = "High level compatibility layer for multiple asynchronous event loop implementations"
19
  optional = false
20
  python-versions = ">=3.9"
21
- groups = ["main", "test", "webserver"]
22
  files = [
23
  {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"},
24
  {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"},
@@ -66,6 +66,108 @@ files = [
66
  {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"},
67
  ]
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  [[package]]
70
  name = "click"
71
  version = "8.1.8"
@@ -179,7 +281,7 @@ version = "2.7.0"
179
  description = "DNS toolkit"
180
  optional = false
181
  python-versions = ">=3.9"
182
- groups = ["test", "webserver"]
183
  files = [
184
  {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"},
185
  {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"},
@@ -200,7 +302,7 @@ version = "1.2.2"
200
  description = "Backport of PEP 654 (exception groups)"
201
  optional = false
202
  python-versions = ">=3.7"
203
- groups = ["main", "test", "webserver"]
204
  markers = "python_version == \"3.10\""
205
  files = [
206
  {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
@@ -237,7 +339,7 @@ version = "0.14.0"
237
  description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
238
  optional = false
239
  python-versions = ">=3.7"
240
- groups = ["main", "test", "webserver"]
241
  files = [
242
  {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
243
  {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -249,7 +351,7 @@ version = "1.0.8"
249
  description = "A minimal low-level HTTP client."
250
  optional = false
251
  python-versions = ">=3.8"
252
- groups = ["main", "test"]
253
  files = [
254
  {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"},
255
  {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"},
@@ -271,7 +373,7 @@ version = "0.28.1"
271
  description = "The next generation HTTP client."
272
  optional = false
273
  python-versions = ">=3.8"
274
- groups = ["main", "test"]
275
  files = [
276
  {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
277
  {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
@@ -523,7 +625,7 @@ version = "4.13.2"
523
  description = "PyMongo - the Official MongoDB Python driver"
524
  optional = false
525
  python-versions = ">=3.9"
526
- groups = ["test", "webserver"]
527
  files = [
528
  {file = "pymongo-4.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:01065eb1838e3621a30045ab14d1a60ee62e01f65b7cf154e69c5c722ef14d2f"},
529
  {file = "pymongo-4.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ab0325d436075f5f1901cde95afae811141d162bc42d9a5befb647fda585ae6"},
@@ -597,21 +699,6 @@ snappy = ["python-snappy"]
597
  test = ["pytest (>=8.2)", "pytest-asyncio (>=0.24.0)"]
598
  zstd = ["zstandard"]
599
 
600
- [[package]]
601
- name = "pymongo-inmemory"
602
- version = "0.5.0"
603
- description = "A mongo mocking library with an ephemeral MongoDB running in memory."
604
- optional = false
605
- python-versions = "<4.0,>=3.9"
606
- groups = ["test"]
607
- files = [
608
- {file = "pymongo_inmemory-0.5.0-py3-none-any.whl", hash = "sha256:ebad4ccc9d9bed859ad25932f039aadb476f29c6945df57fdba0f9171f6626a1"},
609
- {file = "pymongo_inmemory-0.5.0.tar.gz", hash = "sha256:2af2a6bab1cda9a27f524737ce6d3c9ff8cb9e52c224537e5742d610c4aa677e"},
610
- ]
611
-
612
- [package.dependencies]
613
- pymongo = "*"
614
-
615
  [[package]]
616
  name = "pytest"
617
  version = "8.3.5"
@@ -773,13 +860,35 @@ files = [
773
  {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"},
774
  ]
775
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
776
  [[package]]
777
  name = "sniffio"
778
  version = "1.3.1"
779
  description = "Sniff out which async library your code is running under"
780
  optional = false
781
  python-versions = ">=3.7"
782
- groups = ["main", "test", "webserver"]
783
  files = [
784
  {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
785
  {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@@ -900,7 +1009,7 @@ files = [
900
  {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"},
901
  {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"},
902
  ]
903
- markers = {main = "python_version < \"3.13\"", test = "python_version < \"3.13\""}
904
 
905
  [[package]]
906
  name = "typing-inspection"
@@ -917,6 +1026,24 @@ files = [
917
  [package.dependencies]
918
  typing-extensions = ">=4.12.0"
919
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
920
  [[package]]
921
  name = "uvicorn"
922
  version = "0.34.2"
@@ -940,4 +1067,4 @@ standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)
940
  [metadata]
941
  lock-version = "2.1"
942
  python-versions = ">=3.10,<4.0.0"
943
- content-hash = "a31dd577fbe56afb94b935a7ec1feb8e146f5677cd9edb8869296d272afed9cc"
 
18
  description = "High level compatibility layer for multiple asynchronous event loop implementations"
19
  optional = false
20
  python-versions = ">=3.9"
21
+ groups = ["test", "webserver"]
22
  files = [
23
  {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"},
24
  {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"},
 
66
  {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"},
67
  ]
68
 
69
+ [[package]]
70
+ name = "charset-normalizer"
71
+ version = "3.4.2"
72
+ description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
73
+ optional = false
74
+ python-versions = ">=3.7"
75
+ groups = ["main"]
76
+ files = [
77
+ {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"},
78
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"},
79
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"},
80
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"},
81
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"},
82
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"},
83
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"},
84
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"},
85
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"},
86
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"},
87
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"},
88
+ {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"},
89
+ {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"},
90
+ {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"},
91
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"},
92
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"},
93
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"},
94
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"},
95
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"},
96
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"},
97
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"},
98
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"},
99
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"},
100
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"},
101
+ {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"},
102
+ {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"},
103
+ {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"},
104
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"},
105
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"},
106
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"},
107
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"},
108
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"},
109
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"},
110
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"},
111
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"},
112
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"},
113
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"},
114
+ {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"},
115
+ {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"},
116
+ {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"},
117
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"},
118
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"},
119
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"},
120
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"},
121
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"},
122
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"},
123
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"},
124
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"},
125
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"},
126
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"},
127
+ {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"},
128
+ {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"},
129
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"},
130
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"},
131
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"},
132
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"},
133
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"},
134
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"},
135
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"},
136
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"},
137
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"},
138
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"},
139
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"},
140
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"},
141
+ {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"},
142
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"},
143
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"},
144
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"},
145
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"},
146
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"},
147
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"},
148
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"},
149
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"},
150
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"},
151
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"},
152
+ {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"},
153
+ {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"},
154
+ {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"},
155
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"},
156
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"},
157
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"},
158
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"},
159
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"},
160
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"},
161
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"},
162
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"},
163
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"},
164
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"},
165
+ {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"},
166
+ {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"},
167
+ {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"},
168
+ {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"},
169
+ ]
170
+
171
  [[package]]
172
  name = "click"
173
  version = "8.1.8"
 
281
  description = "DNS toolkit"
282
  optional = false
283
  python-versions = ">=3.9"
284
+ groups = ["webserver"]
285
  files = [
286
  {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"},
287
  {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"},
 
302
  description = "Backport of PEP 654 (exception groups)"
303
  optional = false
304
  python-versions = ">=3.7"
305
+ groups = ["test", "webserver"]
306
  markers = "python_version == \"3.10\""
307
  files = [
308
  {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
 
339
  description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
340
  optional = false
341
  python-versions = ">=3.7"
342
+ groups = ["test", "webserver"]
343
  files = [
344
  {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
345
  {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
 
351
  description = "A minimal low-level HTTP client."
352
  optional = false
353
  python-versions = ">=3.8"
354
+ groups = ["test"]
355
  files = [
356
  {file = "httpcore-1.0.8-py3-none-any.whl", hash = "sha256:5254cf149bcb5f75e9d1b2b9f729ea4a4b883d1ad7379fc632b727cec23674be"},
357
  {file = "httpcore-1.0.8.tar.gz", hash = "sha256:86e94505ed24ea06514883fd44d2bc02d90e77e7979c8eb71b90f41d364a1bad"},
 
373
  description = "The next generation HTTP client."
374
  optional = false
375
  python-versions = ">=3.8"
376
+ groups = ["test"]
377
  files = [
378
  {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
379
  {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
 
625
  description = "PyMongo - the Official MongoDB Python driver"
626
  optional = false
627
  python-versions = ">=3.9"
628
+ groups = ["webserver"]
629
  files = [
630
  {file = "pymongo-4.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:01065eb1838e3621a30045ab14d1a60ee62e01f65b7cf154e69c5c722ef14d2f"},
631
  {file = "pymongo-4.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ab0325d436075f5f1901cde95afae811141d162bc42d9a5befb647fda585ae6"},
 
699
  test = ["pytest (>=8.2)", "pytest-asyncio (>=0.24.0)"]
700
  zstd = ["zstandard"]
701
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
702
  [[package]]
703
  name = "pytest"
704
  version = "8.3.5"
 
860
  {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"},
861
  ]
862
 
863
+ [[package]]
864
+ name = "requests"
865
+ version = "2.32.4"
866
+ description = "Python HTTP for Humans."
867
+ optional = false
868
+ python-versions = ">=3.8"
869
+ groups = ["main"]
870
+ files = [
871
+ {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"},
872
+ {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"},
873
+ ]
874
+
875
+ [package.dependencies]
876
+ certifi = ">=2017.4.17"
877
+ charset_normalizer = ">=2,<4"
878
+ idna = ">=2.5,<4"
879
+ urllib3 = ">=1.21.1,<3"
880
+
881
+ [package.extras]
882
+ socks = ["PySocks (>=1.5.6,!=1.5.7)"]
883
+ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
884
+
885
  [[package]]
886
  name = "sniffio"
887
  version = "1.3.1"
888
  description = "Sniff out which async library your code is running under"
889
  optional = false
890
  python-versions = ">=3.7"
891
+ groups = ["test", "webserver"]
892
  files = [
893
  {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
894
  {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
 
1009
  {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"},
1010
  {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"},
1011
  ]
1012
+ markers = {main = "python_version == \"3.10\"", test = "python_version < \"3.13\""}
1013
 
1014
  [[package]]
1015
  name = "typing-inspection"
 
1026
  [package.dependencies]
1027
  typing-extensions = ">=4.12.0"
1028
 
1029
+ [[package]]
1030
+ name = "urllib3"
1031
+ version = "2.5.0"
1032
+ description = "HTTP library with thread-safe connection pooling, file post, and more."
1033
+ optional = false
1034
+ python-versions = ">=3.9"
1035
+ groups = ["main"]
1036
+ files = [
1037
+ {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"},
1038
+ {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"},
1039
+ ]
1040
+
1041
+ [package.extras]
1042
+ brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
1043
+ h2 = ["h2 (>=4,<5)"]
1044
+ socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
1045
+ zstd = ["zstandard (>=0.18.0)"]
1046
+
1047
  [[package]]
1048
  name = "uvicorn"
1049
  version = "0.34.2"
 
1067
  [metadata]
1068
  lock-version = "2.1"
1069
  python-versions = ">=3.10,<4.0.0"
1070
+ content-hash = "b578e3a1f51339d719e4a980386129cba38f47c0f8b9f4a2ce405885125624b3"
pyproject.toml CHANGED
@@ -1,7 +1,7 @@
1
  [project]
2
  name = "my-ghost-writer"
3
- version = "0.3.0"
4
- description = "A simple help for writers"
5
  authors = [
6
  {name = "alessandro trinca tornidor",email = "[email protected]"}
7
  ]
@@ -12,14 +12,13 @@ dependencies = [
12
  "nltk (>=3.9.1,<4.0.0)",
13
  "python-dotenv (>=1.1.0,<2.0.0)",
14
  "structlog (>=25.2.0,<26.0.0)",
15
- "httpx (>=0.28.1,<0.29.0)"
16
  ]
17
 
18
  [tool.poetry.group.test]
19
  optional = true
20
 
21
  [tool.poetry.group.test.dependencies]
22
- pymongo-inmemory = "^0.5.0"
23
  pytest = "^8.3.5"
24
  pytest-cov = "^6.1.1"
25
  httpx = "^0.28.1"
 
1
  [project]
2
  name = "my-ghost-writer"
3
+ version = "0.4.0"
4
+ description = "A simple webapp supporting writers"
5
  authors = [
6
  {name = "alessandro trinca tornidor",email = "[email protected]"}
7
  ]
 
12
  "nltk (>=3.9.1,<4.0.0)",
13
  "python-dotenv (>=1.1.0,<2.0.0)",
14
  "structlog (>=25.2.0,<26.0.0)",
15
+ "requests (>=2.32.4,<3.0.0)"
16
  ]
17
 
18
  [tool.poetry.group.test]
19
  optional = true
20
 
21
  [tool.poetry.group.test.dependencies]
 
22
  pytest = "^8.3.5"
23
  pytest-cov = "^6.1.1"
24
  httpx = "^0.28.1"
requirements_poetry.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ poetry==2.1.3
template.env CHANGED
@@ -4,11 +4,11 @@ ALLOWED_ORIGIN=http://localhost:7860,http://localhost:8000
4
  WORDSAPI_KEY=
5
  WORDSAPI_URL=https://wordsapiv1.p.rapidapi.com/words
6
  RAPIDAPI_HOST=wordsapiv1.p.rapidapi.com
7
- MONGO_USE_OK=
8
- MONGO_CONNECTION_STRING_LOCAL=mongodb://localhost:27017
9
- MONGO_CONNECTION_STRING=mongodb://localhost:27017
10
- MONGO_CONNECTION_TIMEOUT_LOCAL=200
11
- MONGO_CONNECTION_TIMEOUT_REMOTE=3000
12
- MONGO_CONNECTION_TIMEOUT=
13
- MONGO_HEALTHCHECK_SLEEP=900
14
  DEFAULT_COLLECTION_THESAURUS=wordsapi
 
4
  WORDSAPI_KEY=
5
  WORDSAPI_URL=https://wordsapiv1.p.rapidapi.com/words
6
  RAPIDAPI_HOST=wordsapiv1.p.rapidapi.com
7
+ ME_CONFIG_MONGODB_USE_OK=
8
+ ME_CONFIG_MONGODB_URL_LOCAL=mongodb://localhost:27017
9
+ ME_CONFIG_MONGODB_URL=mongodb://localhost:27017
10
+ ME_CONFIG_MONGODB_TIMEOUT_LOCAL=200
11
+ ME_CONFIG_MONGODB_TIMEOUT_REMOTE=3000
12
+ ME_CONFIG_MONGODB_TIMEOUT=
13
+ ME_CONFIG_MONGODB_HEALTHCHECK_SLEEP=900
14
  DEFAULT_COLLECTION_THESAURUS=wordsapi
tests/test_app.py CHANGED
@@ -148,7 +148,7 @@ class TestAppEndpoints(unittest.TestCase):
148
 
149
  def test_mongo_health_check_background_task(self):
150
  # Patch sleep and health_mongo to exit after one loop
151
- with patch("my_ghost_writer.app.MONGO_USE_OK", True), \
152
  patch("my_ghost_writer.app.health_mongo", return_value="Mongodb: still alive..."), \
153
  patch("my_ghost_writer.app.asyncio.sleep", side_effect=Exception("stop")):
154
  with self.assertRaises(Exception):
 
148
 
149
  def test_mongo_health_check_background_task(self):
150
  # Patch sleep and health_mongo to exit after one loop
151
+ with patch("my_ghost_writer.app.ME_CONFIG_MONGODB_USE_OK", True), \
152
  patch("my_ghost_writer.app.health_mongo", return_value="Mongodb: still alive..."), \
153
  patch("my_ghost_writer.app.asyncio.sleep", side_effect=Exception("stop")):
154
  with self.assertRaises(Exception):
tests/test_pymongo_utils.py CHANGED
@@ -9,8 +9,8 @@ class TestPymongoUtils(unittest.TestCase):
9
  def test_get_client(self, mock_mongo_client):
10
  client = pymongo_utils.get_client()
11
  mock_mongo_client.assert_called_with(
12
- pymongo_utils.MONGO_CONNECTION_STRING,
13
- timeoutMS=pymongo_utils.MONGO_CONNECTION_TIMEOUT
14
  )
15
  self.assertEqual(client, mock_mongo_client.return_value)
16
 
 
9
  def test_get_client(self, mock_mongo_client):
10
  client = pymongo_utils.get_client()
11
  mock_mongo_client.assert_called_with(
12
+ pymongo_utils.ME_CONFIG_MONGODB_URL,
13
+ timeoutMS=pymongo_utils.ME_CONFIG_MONGODB_TIMEOUT
14
  )
15
  self.assertEqual(client, mock_mongo_client.return_value)
16