Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
02574c4
[fix] fix #1834 : durations filter wasn't working
Dec 4, 2025
e798b04
[improve] add range filter to reduce time of computation
Dec 4, 2025
78809dd
[fix] fix title query for waypoints in Iitnévert
Dec 5, 2025
dacb3ee
[fix] fix langs filter not working
Dec 8, 2025
3129ac4
[fix] fixed incorrect join with area association
Dec 8, 2025
fec12b3
[fix] fix title filter when no other filters
Dec 8, 2025
19c2da4
[fix] fix lang filter
Dec 9, 2025
468136c
[clean] remove debug log
Dec 10, 2025
fb23ddd
[new feature] add job handling for journey queries to monitor their p…
Dec 10, 2025
adaeebd
[lint] fix linter -> func names in lower case
Dec 10, 2025
dbb7763
Merge branch 'gp/Recette'
Dec 10, 2025
af30a28
[fix] fix search doc missing for coverage
Dec 10, 2025
029bd4b
[CI] set -xe in script
lgourdin Dec 12, 2025
f38b991
[refactor] Use of Elastic Search filters in reachable routes instead …
Dec 15, 2025
3bb3318
[fix] fix sort + when no results found
Dec 17, 2025
7d3e912
[lint] fix flake8 linter
Dec 18, 2025
249f7ae
Merge branch 'main' of https://git.smart-origin.com/SmartOrigin/c2c_v…
Dec 18, 2025
4abff59
Merge branch 'gp/refactor'
Dec 18, 2025
023db80
[fix] fix too restrictive offset and limit for navitia reachable docs
Jan 6, 2026
c922e2d
[improve] return error id when 404 for navitia/journeys route
Jan 9, 2026
5880724
[clean] fix noqa, translate french comms to english, remove use of f …
Jan 12, 2026
649fbdf
Merge branch 'gp/recette3'
Jan 12, 2026
260c375
[doc] update SO README
lgourdin Jan 13, 2026
ce567e8
[fix] fix codacy issues
Jan 16, 2026
a3f3f8c
[clean] remove unused route
Jan 22, 2026
ec6e6ba
[fix] fix update_navitia_coverage script for prod usage
Jan 22, 2026
8b855f4
Merge branch 'gp/recette4'
Jan 22, 2026
3f2d576
[clean] fix unused variable
Jan 22, 2026
eee337f
[clean] remove useless parameters
Jan 26, 2026
226957b
[doc] add coverage doc
Jan 26, 2026
7bca72f
[clean] remove useless class
Jan 26, 2026
64ecacf
[refactor] use of BASE_URL constant for navitia api
Jan 26, 2026
80e4b57
[clean] remove archive coverage class as coverages are not meant to b…
Jan 26, 2026
d210b92
[doc] update S/O readme
Jan 26, 2026
f591613
[fix] fix coverage insert (no archive class)
Jan 28, 2026
899a7a1
[fix] fix update_navitia_coverage script deletion part
Jan 28, 2026
fc431ad
[fix] fix chunks size being above ES max result window
Jan 29, 2026
ebd713d
[fix] add a constant chunk_size instead to prevent circular import wi…
Jan 29, 2026
d5e56fd
Merge branch 'master' into lg/refactor_cd
lgourdin Feb 13, 2026
3cfdb14
[docker] gunicorn worker timeout
lgourdin Mar 9, 2026
1a947c2
[env] default image backend not working
lgourdin Mar 9, 2026
d28cae5
[SQUASH][GP] tests and linting
lgourdin Mar 9, 2026
0ff3982
[CI] fstrings in navitia url generation for waypoints
lgourdin Mar 9, 2026
01b4b68
[scripts][es] add create_index script
lgourdin Mar 9, 2026
c7b5d10
[SQUASH][GP][improve] replace chunk size by ES_MAX_RESULT_WINDOW con…
lgourdin Mar 9, 2026
fab54ce
[SQUASH][GP][improve] add a default case for trip duration
lgourdin Mar 9, 2026
170277a
[ghci] support navitia api key secrets for tests
lgourdin Mar 9, 2026
8e1fa06
[chore] cleanup s/o config
lgourdin Mar 9, 2026
4db858f
[CI] prevent alembic trigger from failing if running without GH secre…
lgourdin Mar 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Navitia API Key : 400.000 queries each month
NAVITIA_API_KEY=""
NAVITIA_API_KEY="test-key"

# Maximum distance between a waypoint and a stop, in meters
MAX_DISTANCE_WAYPOINT_TO_STOPAREA=5000
Expand All @@ -8,4 +8,4 @@ MAX_DISTANCE_WAYPOINT_TO_STOPAREA=5000
WALKING_SPEED=1.12

# Maximum number of stops associated with a waypoint
MAX_STOP_AREA_FOR_1_WAYPOINT=5
MAX_STOP_AREA_FOR_1_WAYPOINT=5
12 changes: 10 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,16 @@ jobs:
/tmp/elasticsearch/bin/elasticsearch --daemonize --path.data /tmp
sleep 30 # ElasticSearch takes few seconds to start, make sure it is available when the build script runs
- run: curl -v http://localhost:9200
- name: Run tests
run: export $(cat .env | grep -v "^#" | xargs) && pytest --cov-report term --cov-report xml --cov=c2corg_api
- name: Run tests (with secrets)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Les tests devraient tourner de la même manière, qui que ce soit qui fasse la PR
Il faudrait trouver une manière de lancer les tests navitia sans que la pipeline nécessite le secret de navitia

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ce n'est pas vraiment possible de tester l'API sans clef d'accès... Et cette différence est due à votre bot qui pour une raison que j'ignore ne peut pas avoir accès au secret. On peut toujours enlever les tests qui nécessitent la clef si vous le demandez.

# Accept running on pull requests except if from dependabot
if: ${{ github.event_name != 'pull_request' || github.actor != 'dependabot[bot]' }}
env:
NAVITIA_API_KEY: ${{ secrets.NAVITIA_API_KEY }}
run: export $(cat .env | grep -v "^#" | grep -v "^NAVITIA_API_KEY" | xargs) && pytest --cov-report term --cov-report xml --cov=c2corg_api
- name: Run tests (without secrets)
# secrets are not available for PR from forks, and dependabot PRs
if: ${{ github.event_name == 'pull_request' && github.actor == 'dependabot[bot]' }}
run: export $(cat .env | grep -v "^#" | xargs) && pytest --cov-report term --cov-report xml --cov=c2corg_api -k "not test_navitia"
- name: Send coverage to codacy
# secrets are not available for PR from forks, and dependabot PRs
if: ${{ github.event_name != 'pull_request' && github.actor != 'dependabot[bot]' }}
Expand Down
19 changes: 15 additions & 4 deletions c2corg_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ def delete_waypoint_stopareas(connection, waypoint_id):
def process_new_waypoint(mapper, connection, geometry):
"""Processes a new waypoint to find its public transports after
inserting it into documents_geometries."""

# When GHCI runs without access to GH secrets
# (eg. for PR triggered by dependabot)
# return immediatly by matching test key from .env
api_key = os.getenv("NAVITIA_API_KEY")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cela me paraît être une mauvaise pratique de changer le comportement du code en fonction de:

  • De qui le lance
  • S'il s'agit de tests ou pas

ça me paraît préférable de gérer ça au niveau des tests

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c'est exactement ce bout de code qui permet de gérer ça au niveau des tests : la fonction dans laquelle on se trouve est un trigger, et il n'est donc pas possible de l'exclure des tests directement puisqu'elle est appelée par alembic sur la création de waypoint.
C'est pour cela qu'on se base sur une "magic value" pour ne pas exécuter la fonction dans le cas où on est en mode test.
L'avantage, c'est que si on a par exemple une mauvaise clef d'API, la fonction va quand même s'exécuter et lever une erreur. On exclut une unique valeur.
Sans ce bout de code, on aurait du mal à gérer ça au niveau des tests puisque justement ce n'est pas un test. À moins d'enlever les tests qui créent des waypoints ou d'ajouter une autre "mock" value quelque part.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je précise que l'inconvénient, c'est que les tests avec la vraie clef consomment quelques requêtes navitia, même si c'est normalement assez peu

if api_key == "test-key":
return

# Check if document is a waypoint
waypoint_id = geometry.document_id

Expand All @@ -147,7 +155,6 @@ def process_new_waypoint(mapper, connection, geometry):
max_stop_area_for_1_waypoint = int(
os.getenv("MAX_STOP_AREA_FOR_1_WAYPOINT")
)
api_key = os.getenv("NAVITIA_API_KEY")
max_duration = int(max_distance_waypoint_to_stoparea / walking_speed)

# increase number of retrieved stop areas,
Expand Down Expand Up @@ -226,7 +233,7 @@ def process_new_waypoint(mapper, connection, geometry):
stop_id = place["id"]

# Get informations of stopareas to know its transports
stop_info_url = "https://api.navitia.io/v1/places/%d", stop_id
stop_info_url = f"https://api.navitia.io/v1/places/{stop_id}"
stop_info_response = requests.get(
stop_info_url, headers=navitia_headers
)
Expand Down Expand Up @@ -619,8 +626,12 @@ def _update_route_duration(connection, route_id, calculated_duration_in_days):
),
{"duration": calculated_duration_in_days, "route_id": route_id},
)
if (calculated_duration_in_days is None):
calculated_duration_in_days_str = "None"
else:
calculated_duration_in_days_str = "%f", calculated_duration_in_days
log.info(
"Route %d: Database updated with calculated_duration = %f days.",
"Route %d: Database updated with calculated_duration = %s days.",
route_id,
calculated_duration_in_days
calculated_duration_in_days_str
)
61 changes: 61 additions & 0 deletions c2corg_api/scripts/es/create_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env python
"""
Creates (or recreates) the ES index with the correct mappings.
Must be run before fill_index.py when building the index from scratch.

Usage: python create_index.py <config>.ini
"""
import sys
import logging

from pyramid.paster import get_appsettings, setup_logging
from pyramid.scripts.common import parse_vars

from c2corg_api.search import configure_es_from_config, elasticsearch_config, \
search_documents
from c2corg_api.search.mapping import analysis_settings


def main(argv=sys.argv):
if len(argv) < 2:
print('Usage: %s <config_uri> [var=value]' % argv[0])
sys.exit(1)

config_uri = argv[1]
options = parse_vars(argv[2:])
setup_logging(config_uri)
logging.getLogger('sqlalchemy.engine').setLevel(logging.ERROR)

settings = get_appsettings(config_uri, options=options)
configure_es_from_config(settings)

client = elasticsearch_config['client']
index_name = elasticsearch_config['index']

# Delete index if it exists (to fix potentially wrong mappings)
if client.indices.exists(index=index_name):
print('Deleting existing index: {}'.format(index_name))
client.indices.delete(index=index_name)

# Create index with analysis settings
print('Creating index: {}'.format(index_name))
client.indices.create(index=index_name, body={
'settings': {
'analysis': analysis_settings
}
})

# Apply the correct mapping for every document type
# (if we let ES infer types by directly running fill_index.py,
# we could run into type errors on some fields like
# a mapping geom -> double instead of geo_point).
for doc_type, search_class in search_documents.items():
print('Applying mapping for doc_type: {}'.format(doc_type))
search_class._doc_type.mapping.save(index_name)

print('Done. Index "{}" created with correct mappings.'.format(index_name))
print('You can now run fill_index.py safely.')


if __name__ == '__main__':
main()
6 changes: 5 additions & 1 deletion c2corg_api/scripts/es/fill_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pyramid.paster import (
get_appsettings,
setup_logging,
)
)

from pyramid.scripts.common import parse_vars
from datetime import datetime, timedelta
Expand Down Expand Up @@ -90,3 +90,7 @@ def progress(count, total_count):

duration = datetime.now() - status['start_time']
print('Done (duration: {0})'.format(duration))


if __name__ == "__main__":
main()
9 changes: 3 additions & 6 deletions c2corg_api/search/advanced_search.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
from c2corg_api.search.mapping_types import meta_param_keys
from c2corg_api.search.search_filters import build_query

# the chunk size for each elastic search request
# should be <= ES_MAX_RESULT_WINDOW
CHUNK_SIZE = 10000


def get_search_documents(url_params, meta_params, doc_type):
"""Returns a function that when called with a base-query returns all
Expand Down Expand Up @@ -89,13 +85,14 @@ def get_all_filtered_docs(


def chunk_ids(ids_set):
from c2corg_api.views.document import ES_MAX_RESULT_WINDOW
"""
Yield successive chunks of IDs from a set/list.
chunk size is ES_MAX_RESULT_WINDOW
"""
ids_list = list(ids_set)
for i in range(0, len(ids_list), CHUNK_SIZE):
yield ids_list[i:i + CHUNK_SIZE]
for i in range(0, len(ids_list), ES_MAX_RESULT_WINDOW):
yield ids_list[i:i + ES_MAX_RESULT_WINDOW]


def contains_search_params(url_params):
Expand Down
Loading
Loading