tradedangerous 12.0.4__tar.gz → 12.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tradedangerous might be problematic. Click here for more details.

Files changed (100) hide show
  1. {tradedangerous-12.0.4/tradedangerous.egg-info → tradedangerous-12.0.5}/PKG-INFO +1 -1
  2. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/cache.py +227 -103
  3. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/version.py +1 -1
  4. {tradedangerous-12.0.4 → tradedangerous-12.0.5/tradedangerous.egg-info}/PKG-INFO +1 -1
  5. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/LICENSE +0 -0
  6. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/README.md +0 -0
  7. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/pyproject.toml +0 -0
  8. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/setup.cfg +0 -0
  9. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/setup.py +0 -0
  10. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_bootstrap_commands.py +0 -0
  11. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_bootstrap_plugins.py +0 -0
  12. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_cache.py +0 -0
  13. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_commands.py +0 -0
  14. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_fs.py +0 -0
  15. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_peek.py +0 -0
  16. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_tools.py +0 -0
  17. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_trade.py +0 -0
  18. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_trade_run.py +0 -0
  19. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tests/test_utils.py +0 -0
  20. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/trade.py +0 -0
  21. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/__init__.py +0 -0
  22. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/cli.py +0 -0
  23. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/TEMPLATE.py +0 -0
  24. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/__init__.py +0 -0
  25. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/buildcache_cmd.py +0 -0
  26. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/buy_cmd.py +0 -0
  27. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/commandenv.py +0 -0
  28. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/exceptions.py +0 -0
  29. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/export_cmd.py +0 -0
  30. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/import_cmd.py +0 -0
  31. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/local_cmd.py +0 -0
  32. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/market_cmd.py +0 -0
  33. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/nav_cmd.py +0 -0
  34. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/olddata_cmd.py +0 -0
  35. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/parsing.py +0 -0
  36. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/rares_cmd.py +0 -0
  37. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/run_cmd.py +0 -0
  38. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/sell_cmd.py +0 -0
  39. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/shipvendor_cmd.py +0 -0
  40. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/station_cmd.py +0 -0
  41. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/trade_cmd.py +0 -0
  42. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/commands/update_cmd.py +0 -0
  43. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/corrections.py +0 -0
  44. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/csvexport.py +0 -0
  45. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/__init__.py +0 -0
  46. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/adapter.py +0 -0
  47. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/config.py +0 -0
  48. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/engine.py +0 -0
  49. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/lifecycle.py +0 -0
  50. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/locks.py +0 -0
  51. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/orm_models.py +0 -0
  52. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/paths.py +0 -0
  53. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/db/utils.py +0 -0
  54. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/edscupdate.py +0 -0
  55. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/edsmupdate.py +0 -0
  56. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/formatting.py +0 -0
  57. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/fs.py +0 -0
  58. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/gui.py +0 -0
  59. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/mapping.py +0 -0
  60. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/mfd/__init__.py +0 -0
  61. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/mfd/saitek/__init__.py +0 -0
  62. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/mfd/saitek/directoutput.py +0 -0
  63. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/mfd/saitek/x52pro.py +0 -0
  64. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/checkpricebounds.py +0 -0
  65. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/clipboard.py +0 -0
  66. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/coord64.py +0 -0
  67. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/derp-sentinel.py +0 -0
  68. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/diff-system-csvs.py +0 -0
  69. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/eddb.py +0 -0
  70. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/eddn.py +0 -0
  71. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/edsc.py +0 -0
  72. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/edsm.py +0 -0
  73. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/importeddbstats.py +0 -0
  74. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/prices-json-exp.py +0 -0
  75. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/misc/progress.py +0 -0
  76. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/plugins/__init__.py +0 -0
  77. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/plugins/edcd_plug.py +0 -0
  78. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/plugins/eddblink_plug.py +0 -0
  79. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/plugins/edmc_batch_plug.py +0 -0
  80. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/plugins/spansh_plug.py +0 -0
  81. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/prices.py +0 -0
  82. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/submit-distances.py +0 -0
  83. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/templates/Added.csv +0 -0
  84. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/templates/Category.csv +0 -0
  85. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/templates/RareItem.csv +0 -0
  86. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/templates/TradeDangerous.sql +0 -0
  87. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/tools.py +0 -0
  88. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/tradecalc.py +0 -0
  89. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/tradedb.py +0 -0
  90. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/tradeenv.py +0 -0
  91. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/tradeexcept.py +0 -0
  92. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/transfers.py +0 -0
  93. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous/utils.py +0 -0
  94. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous.egg-info/SOURCES.txt +0 -0
  95. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous.egg-info/dependency_links.txt +0 -0
  96. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous.egg-info/entry_points.txt +0 -0
  97. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous.egg-info/not-zip-safe +0 -0
  98. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous.egg-info/requires.txt +0 -0
  99. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradedangerous.egg-info/top_level.txt +0 -0
  100. {tradedangerous-12.0.4 → tradedangerous-12.0.5}/tradegui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tradedangerous
3
- Version: 12.0.4
3
+ Version: 12.0.5
4
4
  Summary: Trade-Dangerous is a set of powerful trading tools for Elite Dangerous, organized around one of the most powerful trade run optimizers available.
5
5
  Home-page: https://github.com/eyeonus/Trade-Dangerous
6
6
  Author: eyeonus
@@ -33,7 +33,7 @@ import typing
33
33
 
34
34
 
35
35
  from functools import partial as partial_fn
36
- from sqlalchemy import func, Integer, Float, DateTime
36
+ from sqlalchemy import func, Integer, Float, DateTime, tuple_
37
37
  from sqlalchemy import inspect as sa_inspect
38
38
  from sqlalchemy.orm import Session
39
39
  from sqlalchemy.types import DateTime as SA_DateTime
@@ -756,25 +756,27 @@ def processPricesFile(
756
756
  SA.StationItem.station_id.in_([sid for (sid,) in stations])
757
757
  ).delete(synchronize_session=False)
758
758
 
759
+ # Remove zeroed pairs
760
+ removedItems = 0
759
761
  if zeros:
760
762
  session.query(SA.StationItem).filter(
761
763
  tuple_(SA.StationItem.station_id, SA.StationItem.item_id).in_(zeros)
762
764
  ).delete(synchronize_session=False)
763
- removedItems = len(zeros)
765
+ removedItems = len(zeros)
764
766
 
767
+ # Upsert items
765
768
  if items:
766
- for item in items:
767
- (
768
- station_id,
769
- item_id,
770
- modified,
771
- demand_price,
772
- demand_units,
773
- demand_level,
774
- supply_price,
775
- supply_units,
776
- supply_level,
777
- ) = item
769
+ for (
770
+ station_id,
771
+ item_id,
772
+ modified,
773
+ demand_price,
774
+ demand_units,
775
+ demand_level,
776
+ supply_price,
777
+ supply_units,
778
+ supply_level,
779
+ ) in items:
778
780
  obj = SA.StationItem(
779
781
  station_id=station_id,
780
782
  item_id=item_id,
@@ -818,6 +820,7 @@ def processPricesFile(
818
820
 
819
821
 
820
822
 
823
+
821
824
  ######################################################################
822
825
 
823
826
 
@@ -878,22 +881,9 @@ def processImportFile(
878
881
  """
879
882
  Import a CSV file into the given table.
880
883
 
881
- - RareItem.csv:
882
- Skips FK marker columns:
883
- * !name@System.system_id
884
- * name@Station.station_id
885
- * name@Category.category_id
886
- Looks up system_id (transient), station_id, category_id via cached helpers.
887
- NOTE: system_id is NOT a RareItem column and is not passed to the model.
888
-
889
- - System.csv:
890
- Skips 'name@Added.added_id' from active columns; resolves Added by name,
891
- defaulting to "EDSM" when blank.
892
-
893
- - All tables:
894
- Uses parse_ts() for datetimes.
895
- Enforces unq: unique headers.
896
- Commits per tradedangerous.db.utils.get_import_batch_size(session).
884
+ Applies header parsing, uniqueness checks, foreign key lookups,
885
+ in-row deprecation correction (warnings only at -vv via DEBUG1), and upserts via SQLAlchemy ORM.
886
+ Commits in batches for large datasets.
897
887
  """
898
888
 
899
889
  tdenv.DEBUG0("Processing import file '{}' for table '{}'", str(importPath), tableName)
@@ -902,121 +892,258 @@ def processImportFile(
902
892
  if line_callback:
903
893
  line_callback = partial_fn(line_callback, **call_args)
904
894
 
905
- uniquePfx = "unq:"
906
- uniqueLen = len(uniquePfx)
895
+ # --- batch size config from environment or fallback ---
896
+ env_batch = os.environ.get("TD_LISTINGS_BATCH")
897
+ if env_batch:
898
+ try:
899
+ max_transaction_items = int(env_batch)
900
+ except ValueError:
901
+ tdenv.WARN("Invalid TD_LISTINGS_BATCH value %r, falling back to defaults.", env_batch)
902
+ max_transaction_items = None
903
+ else:
904
+ max_transaction_items = None
905
+
906
+ if max_transaction_items is None:
907
+ if session.bind.dialect.name in ("mysql", "mariadb"):
908
+ max_transaction_items = 50 * 1024
909
+ else:
910
+ max_transaction_items = 250 * 1024
907
911
 
908
- # Backend-aware batch policy (SQLite=None→single commit; MariaDB defaults to 50k; env override respected)
909
- max_transaction_items = get_import_batch_size(session, profile="csv") # from tradedangerous.db.utils
910
- transaction_items = 0
912
+ transaction_items = 0 # track how many rows inserted before committing
911
913
 
912
914
  with importPath.open("r", encoding="utf-8") as importFile:
913
915
  csvin = csv.reader(importFile, delimiter=",", quotechar="'", doublequote=True)
914
916
 
915
- # header
917
+ # Read header row
916
918
  columnDefs = next(csvin)
917
919
  columnCount = len(columnDefs)
918
920
 
919
- activeColumns: list[str] = [] # headers that map directly to ORM fields
920
- kept_indices: list[int] = [] # original header indices that we KEEP (aligns values)
921
- uniqueIndexes: list[int] = [] # indexes into activeColumns (post-skip)
922
- fk_col_indices: dict[str, int] = {} # special FK headers their original indices
921
+ # --- Process headers: extract column names, track indices ---
922
+ activeColumns: list[str] = [] # Final columns we'll use (after "unq:" stripping)
923
+ kept_indices: list[int] = [] # Indices into CSV rows we keep (aligned to activeColumns)
924
+ uniqueIndexes: list[int] = [] # Indexes (into activeColumns) of unique keys
925
+ fk_col_indices: dict[str, int] = {} # Special handling for FK resolution
926
+
927
+ uniquePfx = "unq:"
928
+ uniqueLen = len(uniquePfx)
929
+
930
+ # map of header (without "unq:") -> original CSV index, for correction by name
931
+ header_index: dict[str, int] = {}
923
932
 
924
- # --- preprocess header ---
925
933
  for cIndex, cName in enumerate(columnDefs):
926
934
  colName, _, srcKey = cName.partition("@")
935
+ baseName = colName[uniqueLen:] if colName.startswith(uniquePfx) else colName
936
+ header_index[baseName] = cIndex
927
937
 
928
- # --- System.csv ---
938
+ # Special-case: System-added
929
939
  if tableName == "System":
930
940
  if cName == "name":
931
- srcKey = "" # plain field
941
+ srcKey = ""
932
942
  elif cName == "name@Added.added_id":
933
- # We'll resolve Added by name separately; skip from active columns.
934
943
  fk_col_indices["added"] = cIndex
935
- continue # do NOT keep this header/value
944
+ continue
936
945
 
937
- # --- RareItem.csv (skip FK headers; remember positions) ---
946
+ # Foreign key columns for RareItem
938
947
  if tableName == "RareItem":
939
948
  if cName == "!name@System.system_id":
940
949
  fk_col_indices["system"] = cIndex
941
- continue # do NOT keep this header/value
950
+ continue
942
951
  if cName == "name@Station.station_id":
943
952
  fk_col_indices["station"] = cIndex
944
- continue # do NOT keep this header/value
953
+ continue
945
954
  if cName == "name@Category.category_id":
946
955
  fk_col_indices["category"] = cIndex
947
- continue # do NOT keep this header/value
956
+ continue
948
957
 
949
- # unique index marker (e.g., "unq:name")
958
+ # Handle unique constraint tracking
950
959
  if colName.startswith(uniquePfx):
951
960
  uniqueIndexes.append(len(activeColumns))
952
- colName = colName[uniqueLen:]
961
+ colName = baseName
953
962
 
954
- # keep normal columns and remember their source index
955
963
  activeColumns.append(colName)
956
964
  kept_indices.append(cIndex)
957
965
 
958
- # optional deprecation checker
959
- deprecationFn = getattr(sys.modules[__name__], "deprecationCheck" + tableName, None)
960
-
961
966
  importCount = 0
962
- uniqueIndex = {}
967
+ uniqueIndex: dict[str, int] = {}
963
968
 
969
+ # helpers for correction + visibility-gated warning
970
+ DELETED = corrections.DELETED
971
+
972
+ def _warn(line_no: int, msg: str) -> None:
973
+ # Gate deprecation chatter to -vv (DEBUG1)
974
+ tdenv.DEBUG1("{}:{} WARNING {}", importPath, line_no, msg)
975
+
976
+ def _apply_row_corrections(table_name: str, row: list[str], line_no: int) -> bool:
977
+ """
978
+ Returns True if the row should be skipped (deleted in tolerant mode), False otherwise.
979
+ Mutates 'row' in place with corrected values.
980
+ """
981
+ try:
982
+ if table_name == "System":
983
+ idx = header_index.get("name")
984
+ if idx is not None:
985
+ orig = row[idx]
986
+ corr = corrections.correctSystem(orig)
987
+ if corr is DELETED:
988
+ if tdenv.ignoreUnknown:
989
+ _warn(line_no, f'System "{orig}" is marked as DELETED and should not be used.')
990
+ return True
991
+ raise DeletedKeyError(importPath, line_no, "System", orig)
992
+ if corr != orig:
993
+ _warn(line_no, f'System "{orig}" is deprecated and should be replaced with "{corr}".')
994
+ row[idx] = corr
995
+
996
+ elif table_name == "Station":
997
+ s_idx = header_index.get("system")
998
+ n_idx = header_index.get("name")
999
+ if s_idx is not None and n_idx is not None:
1000
+ s_orig = row[s_idx]
1001
+ s_corr = corrections.correctSystem(s_orig)
1002
+ if s_corr is DELETED:
1003
+ if tdenv.ignoreUnknown:
1004
+ _warn(line_no, f'System "{s_orig}" is marked as DELETED and should not be used.')
1005
+ return True
1006
+ raise DeletedKeyError(importPath, line_no, "System", s_orig)
1007
+ if s_corr != s_orig:
1008
+ _warn(line_no, f'System "{s_orig}" is deprecated and should be replaced with "{s_corr}".')
1009
+ row[s_idx] = s_corr
1010
+ n_orig = row[n_idx]
1011
+ n_corr = corrections.correctStation(s_corr, n_orig)
1012
+ if n_corr is DELETED:
1013
+ if tdenv.ignoreUnknown:
1014
+ _warn(line_no, f'Station "{n_orig}" is marked as DELETED and should not be used.')
1015
+ return True
1016
+ raise DeletedKeyError(importPath, line_no, "Station", n_orig)
1017
+ if n_corr != n_orig:
1018
+ _warn(line_no, f'Station "{n_orig}" is deprecated and should be replaced with "{n_corr}".')
1019
+ row[n_idx] = n_corr
1020
+
1021
+ elif table_name == "Category":
1022
+ idx = header_index.get("name")
1023
+ if idx is not None:
1024
+ orig = row[idx]
1025
+ corr = corrections.correctCategory(orig)
1026
+ if corr is DELETED:
1027
+ if tdenv.ignoreUnknown:
1028
+ _warn(line_no, f'Category "{orig}" is marked as DELETED and should not be used.')
1029
+ return True
1030
+ raise DeletedKeyError(importPath, line_no, "Category", orig)
1031
+ if corr != orig:
1032
+ _warn(line_no, f'Category "{orig}" is deprecated and should be replaced with "{corr}".')
1033
+ row[idx] = corr
1034
+
1035
+ elif table_name == "Item":
1036
+ cat_idx = header_index.get("category")
1037
+ name_idx = header_index.get("name")
1038
+ if cat_idx is not None:
1039
+ c_orig = row[cat_idx]
1040
+ c_corr = corrections.correctCategory(c_orig)
1041
+ if c_corr is DELETED:
1042
+ if tdenv.ignoreUnknown:
1043
+ _warn(line_no, f'Category "{c_orig}" is marked as DELETED and should not be used.')
1044
+ return True
1045
+ raise DeletedKeyError(importPath, line_no, "Category", c_orig)
1046
+ if c_corr != c_orig:
1047
+ _warn(line_no, f'Category "{c_orig}" is deprecated and should be replaced with "{c_corr}".')
1048
+ row[cat_idx] = c_corr
1049
+ if name_idx is not None:
1050
+ i_orig = row[name_idx]
1051
+ i_corr = corrections.correctItem(i_orig)
1052
+ if i_corr is DELETED:
1053
+ if tdenv.ignoreUnknown:
1054
+ _warn(line_no, f'Item "{i_orig}" is marked as DELETED and should not be used.')
1055
+ return True
1056
+ raise DeletedKeyError(importPath, line_no, "Item", i_orig)
1057
+ if i_corr != i_orig:
1058
+ _warn(line_no, f'Item "{i_orig}" is deprecated and should be replaced with "{i_corr}".')
1059
+ row[name_idx] = i_corr
1060
+
1061
+ # RareItem: we only correct category (FK lookup uses names) to improve hit rate.
1062
+ elif table_name == "RareItem":
1063
+ cat_idx = header_index.get("category")
1064
+ if cat_idx is not None:
1065
+ c_orig = row[cat_idx]
1066
+ c_corr = corrections.correctCategory(c_orig)
1067
+ if c_corr is DELETED:
1068
+ if tdenv.ignoreUnknown:
1069
+ _warn(line_no, f'Category "{c_orig}" is marked as DELETED and should not be used.')
1070
+ return True
1071
+ raise DeletedKeyError(importPath, line_no, "Category", c_orig)
1072
+ if c_corr != c_orig:
1073
+ _warn(line_no, f'Category "{c_orig}" is deprecated and should be replaced with "{c_corr}".')
1074
+ row[cat_idx] = c_corr
1075
+
1076
+ except BuildCacheBaseException:
1077
+ # strict mode path bubbles up; caller will handle
1078
+ raise
1079
+ return False # do not skip
1080
+
1081
+ # --- Read data lines ---
964
1082
  for linein in csvin:
965
1083
  if line_callback:
966
1084
  line_callback()
967
1085
  if not linein:
968
1086
  continue
1087
+
969
1088
  lineNo = csvin.line_num
970
1089
 
971
1090
  if len(linein) != columnCount:
972
- tdenv.NOTE(
973
- "Wrong number of columns ({}:{}): {}",
974
- importPath,
975
- lineNo,
976
- ", ".join(linein),
977
- )
1091
+ tdenv.NOTE("Wrong number of columns ({}:{}): {}", importPath, lineNo, ", ".join(linein))
978
1092
  continue
979
1093
 
980
1094
  tdenv.DEBUG1(" Values: {}", ", ".join(linein))
981
1095
 
982
- # deprecation checks
983
- if deprecationFn:
984
- try:
985
- deprecationFn(importPath, lineNo, linein)
986
- except DeletedKeyError as e:
987
- if not tdenv.ignoreUnknown:
988
- raise e
989
- e.category = "WARNING"
990
- tdenv.NOTE("{}", e)
1096
+ # --- Apply corrections BEFORE uniqueness; may skip if deleted in tolerant mode
1097
+ try:
1098
+ if _apply_row_corrections(tableName, linein, lineNo):
991
1099
  continue
992
- except DeprecatedKeyError as e:
993
- if not tdenv.ignoreUnknown:
994
- raise e
995
- e.category = "WARNING"
996
- tdenv.NOTE("{}", e)
997
- # Do NOT skip — correction is available
998
-
1100
+ except DeletedKeyError:
1101
+ if not tdenv.ignoreUnknown:
1102
+ # strict: fail hard
1103
+ raise
1104
+ # tolerant: already warned in _apply_row_corrections; skip row
1105
+ continue
999
1106
 
1000
- # Build values aligned to activeColumns (skip the FK columns we excluded)
1107
+ # Extract and clean values to use (from corrected line)
1001
1108
  activeValues = [linein[i] for i in kept_indices]
1002
1109
 
1003
- # unique index enforcement over activeColumns
1004
- if uniqueIndexes:
1005
- keyValues = [str(activeValues[i]).upper() for i in uniqueIndexes]
1006
- key = ":!:".join(keyValues)
1007
- prevLineNo = uniqueIndex.get(key, 0)
1008
- if prevLineNo:
1009
- key_disp = "/".join(keyValues)
1010
- raise DuplicateKeyError(importPath, lineNo, "entry", key_disp, prevLineNo)
1011
- uniqueIndex[key] = lineNo
1110
+ # --- Uniqueness check (after correction) ---
1111
+ try:
1112
+ if uniqueIndexes:
1113
+ keyValues = [str(activeValues[i]).upper() for i in uniqueIndexes]
1114
+ key = ":!:".join(keyValues)
1115
+ prevLineNo = uniqueIndex.get(key, 0)
1116
+ if prevLineNo:
1117
+ key_disp = "/".join(keyValues)
1118
+ if tdenv.ignoreUnknown:
1119
+ e = DuplicateKeyError(importPath, lineNo, "entry", key_disp, prevLineNo)
1120
+ e.category = "WARNING"
1121
+ tdenv.NOTE("{}", e)
1122
+ continue
1123
+ raise DuplicateKeyError(importPath, lineNo, "entry", key_disp, prevLineNo)
1124
+ uniqueIndex[key] = lineNo
1125
+ except Exception as e:
1126
+ # Keep processing the file, don’t tear down the loop
1127
+ tdenv.WARN(
1128
+ "*** INTERNAL ERROR: {err}\n"
1129
+ "CSV File: {file}:{line}\n"
1130
+ "Table: {table}\n"
1131
+ "Params: {params}\n".format(
1132
+ err=str(e),
1133
+ file=str(importPath),
1134
+ line=lineNo,
1135
+ table=tableName,
1136
+ params=linein,
1137
+ )
1138
+ )
1139
+ session.rollback()
1140
+ continue
1012
1141
 
1013
1142
  try:
1014
- # Base rowdict from non-FK columns only
1015
1143
  rowdict = dict(zip(activeColumns, activeValues))
1016
1144
 
1017
- # --- RareItem foreign key lookups ---
1145
+ # Foreign key lookups — RareItem
1018
1146
  if tableName == "RareItem":
1019
- # Resolve system (transient; only for station lookup)
1020
1147
  sys_id = None
1021
1148
  if "system" in fk_col_indices:
1022
1149
  sys_name = linein[fk_col_indices["system"]]
@@ -1025,7 +1152,6 @@ def processImportFile(
1025
1152
  except ValueError:
1026
1153
  tdenv.WARN("Unknown System '{}' in {}", sys_name, importPath)
1027
1154
 
1028
- # Station (requires system context)
1029
1155
  if "station" in fk_col_indices:
1030
1156
  stn_name = linein[fk_col_indices["station"]]
1031
1157
  if sys_id is not None:
@@ -1036,7 +1162,6 @@ def processImportFile(
1036
1162
  else:
1037
1163
  tdenv.WARN("Station lookup skipped (no system_id) for '{}'", stn_name)
1038
1164
 
1039
- # Category
1040
1165
  if "category" in fk_col_indices:
1041
1166
  cat_name = linein[fk_col_indices["category"]]
1042
1167
  try:
@@ -1044,7 +1169,7 @@ def processImportFile(
1044
1169
  except ValueError:
1045
1170
  tdenv.WARN("Unknown Category '{}' in {}", cat_name, importPath)
1046
1171
 
1047
- # --- System foreign key lookup (Added), default "EDSM" if blank ---
1172
+ # Foreign key lookups System.added
1048
1173
  if tableName == "System" and "added" in fk_col_indices:
1049
1174
  added_val = linein[fk_col_indices["added"]] or "EDSM"
1050
1175
  try:
@@ -1053,24 +1178,21 @@ def processImportFile(
1053
1178
  rowdict["added_id"] = None
1054
1179
  tdenv.WARN("Unknown Added value '{}' in {}", added_val, importPath)
1055
1180
 
1056
- # --- type coercion ---
1181
+ # --- Type coercion for common types ---
1057
1182
  for key, val in list(rowdict.items()):
1058
1183
  if val in ("", None):
1059
1184
  rowdict[key] = None
1060
1185
  continue
1061
- # ints
1062
1186
  if key.endswith("_id") or key.endswith("ID") or key in ("cost", "max_allocation"):
1063
1187
  try:
1064
1188
  rowdict[key] = int(val)
1065
1189
  except ValueError:
1066
1190
  rowdict[key] = None
1067
- # floats
1068
1191
  elif key in ("pos_x", "pos_y", "pos_z", "ls_from_star"):
1069
1192
  try:
1070
1193
  rowdict[key] = float(val)
1071
1194
  except ValueError:
1072
1195
  rowdict[key] = None
1073
- # datetimes
1074
1196
  elif "time" in key or key == "modified":
1075
1197
  parsed = parse_ts(val)
1076
1198
  if parsed:
@@ -1084,24 +1206,22 @@ def processImportFile(
1084
1206
  val,
1085
1207
  )
1086
1208
  rowdict[key] = None
1087
- # strings (incl. TriState flags) left as-is
1088
1209
 
1089
- # reserved word remaps
1210
+ # Special handling for SQL reserved word `class`
1090
1211
  if tableName == "Upgrade" and "class" in rowdict:
1091
1212
  rowdict["class_"] = rowdict.pop("class")
1092
1213
  if tableName == "FDevOutfitting" and "class" in rowdict:
1093
1214
  rowdict["class_"] = rowdict.pop("class")
1094
-
1095
- # ensure we never pass system_id to RareItem (not a column)
1096
1215
  if tableName == "RareItem" and "system_id" in rowdict:
1097
1216
  rowdict.pop("system_id", None)
1098
1217
 
1218
+ # ORM insert/merge
1099
1219
  Model = getattr(SA, tableName)
1100
1220
  obj = Model(**rowdict)
1101
1221
  session.merge(obj)
1102
1222
  importCount += 1
1103
1223
 
1104
- # batched commit (only if enabled for this backend)
1224
+ # Batch commit
1105
1225
  if max_transaction_items:
1106
1226
  transaction_items += 1
1107
1227
  if transaction_items >= max_transaction_items:
@@ -1110,6 +1230,7 @@ def processImportFile(
1110
1230
  transaction_items = 0
1111
1231
 
1112
1232
  except Exception as e:
1233
+ # Log all import errors — but keep going
1113
1234
  tdenv.WARN(
1114
1235
  "*** INTERNAL ERROR: {err}\n"
1115
1236
  "CSV File: {file}:{line}\n"
@@ -1124,10 +1245,13 @@ def processImportFile(
1124
1245
  )
1125
1246
  session.rollback()
1126
1247
 
1248
+ # Final commit after file done
1127
1249
  session.commit()
1128
1250
  tdenv.DEBUG0("{count} {table}s imported", count=importCount, table=tableName)
1129
1251
 
1130
1252
 
1253
+
1254
+
1131
1255
  def buildCache(tdb, tdenv):
1132
1256
  """
1133
1257
  Rebuilds the database from source files.
@@ -12,5 +12,5 @@
12
12
  """just keeper of current version"""
13
13
 
14
14
  # TODO: remember to update tests when version changes
15
- __version__ = '12.0.4'
15
+ __version__ = '12.0.5'
16
16
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tradedangerous
3
- Version: 12.0.4
3
+ Version: 12.0.5
4
4
  Summary: Trade-Dangerous is a set of powerful trading tools for Elite Dangerous, organized around one of the most powerful trade run optimizers available.
5
5
  Home-page: https://github.com/eyeonus/Trade-Dangerous
6
6
  Author: eyeonus
File without changes