Big update, AppVeyor_Test
This commit is contained in:
		
							parent
							
								
									aec570d055
								
							
						
					
					
						commit
						e71faf0b92
					
				
					 65 changed files with 2141 additions and 1355 deletions
				
			
		
							
								
								
									
										1
									
								
								.env
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.env
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| FLASK_APP="ed_lrr_gui.web:app" | ||||
							
								
								
									
										15
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -17,9 +17,12 @@ build | |||
| .history | ||||
| .tox | ||||
| pip-wheel-metadata | ||||
| .eggs/ | ||||
| exe/ | ||||
| installer/Output/ | ||||
| workspace.code-workspace   | ||||
| ed_lrr_gui/web/jobs.db | ||||
| ed_lrr_gui/web/ed_lrr_web_ui.db | ||||
| .eggs/ | ||||
| exe/ | ||||
| installer/Output/ | ||||
| workspace.code-workspace   | ||||
| ed_lrr_gui/web/jobs.db | ||||
| ed_lrr_gui/web/ed_lrr_web_ui.db | ||||
| __version__.py | ||||
| .nox/ | ||||
| dist_vis.py | ||||
|  |  | |||
							
								
								
									
										132
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										132
									
								
								CHANGELOG.md
									
										
									
									
									
								
							|  | @ -1,12 +1,12 @@ | |||
| ## [Unreleased] | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.24.0] - 2019-10-23 | ||||
| ## [v0.14.0] - 2019-10-23 | ||||
| ### Features | ||||
| - **tests:** Add pytest.ini for pytest-qt [eb43ca8](https://gitlab.com/Earthnuker/ed_lrr/commit/eb43ca8) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.23.0] - 2019-10-23 | ||||
| ## [v0.13.0] - 2019-10-23 | ||||
| ### Documentation | ||||
| - **readme:** Update README with more infos [634af75](https://gitlab.com/Earthnuker/ed_lrr/commit/634af75) | ||||
| 
 | ||||
|  | @ -14,22 +14,22 @@ | |||
| - **setup.py:** Update add dependencies for HTTP API [45c11da](https://gitlab.com/Earthnuker/ed_lrr/commit/45c11da) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.22.0] - 2019-10-23 | ||||
| ## [v0.12.0] - 2019-10-23 | ||||
| ### Features | ||||
| - **tox:** Add more python versions to test against [3115f9d](https://gitlab.com/Earthnuker/ed_lrr/commit/3115f9d) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.21.0] - 2019-10-23 | ||||
| ## [v0.11.0] - 2019-10-23 | ||||
| ### Features | ||||
| - **html_export:** Add basic HTML-Export using Jinja2 template [bb2ee8c](https://gitlab.com/Earthnuker/ed_lrr/commit/bb2ee8c) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.20.0] - 2019-10-23 | ||||
| ## [v0.10.0] - 2019-10-23 | ||||
| ### Features | ||||
| - **route_progress:** minor change to progress dialog message [35fc135](https://gitlab.com/Earthnuker/ed_lrr/commit/35fc135) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.19.1] - 2019-10-23 | ||||
| ## [v0.9.4] - 2019-10-23 | ||||
| ### Bug Fixes | ||||
| - **config:** Add missing defaults [30dbd24](https://gitlab.com/Earthnuker/ed_lrr/commit/30dbd24) | ||||
| 
 | ||||
|  | @ -37,17 +37,17 @@ | |||
| - Update CHANGELOG.md and README.md [38acfc7](https://gitlab.com/Earthnuker/ed_lrr/commit/38acfc7) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.19.0] - 2019-09-28 | ||||
| ## [v0.9.3] - 2019-09-28 | ||||
| ### Features | ||||
| - **config:** impelemt save and load to GUI [65fe131](https://gitlab.com/Earthnuker/ed_lrr/commit/65fe131) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.18.0] - 2019-09-28 | ||||
| ## [v0.9.2] - 2019-09-28 | ||||
| ### Features | ||||
| - **GUI:** implement preprocessing [f34d37a](https://gitlab.com/Earthnuker/ed_lrr/commit/f34d37a) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.17.0] - 2019-09-28 | ||||
| ## [v0.9.1] - 2019-09-28 | ||||
| ### Documentation | ||||
| - Update TODO list in readme [4663d4e](https://gitlab.com/Earthnuker/ed_lrr/commit/4663d4e) | ||||
| 
 | ||||
|  | @ -55,17 +55,17 @@ | |||
| - **installer:** switch from LZMA to LZMA2 [3ee952e](https://gitlab.com/Earthnuker/ed_lrr/commit/3ee952e) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.16.0] - 2019-09-28 | ||||
| ## [v0.9.0] - 2019-09-28 | ||||
| ### Features | ||||
| - **build scripts:** skip .history folder when building UI files [92bd1b1](https://gitlab.com/Earthnuker/ed_lrr/commit/92bd1b1) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.15.0] - 2019-09-28 | ||||
| ## [v0.8.1] - 2019-09-28 | ||||
| ### Features | ||||
| - **config:** update config format [9ec4687](https://gitlab.com/Earthnuker/ed_lrr/commit/9ec4687) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.14.0] - 2019-09-28 | ||||
| ## [v0.8.0] - 2019-09-28 | ||||
| ### Features | ||||
| - **UI:** made dropdowns non-editable [37f5547](https://gitlab.com/Earthnuker/ed_lrr/commit/37f5547) | ||||
| 
 | ||||
|  | @ -73,12 +73,12 @@ | |||
| - Alsways compile in release mode [e9bcd3e](https://gitlab.com/Earthnuker/ed_lrr/commit/e9bcd3e) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.13.0] - 2019-09-28 | ||||
| ## [v0.7.1] - 2019-09-28 | ||||
| ### Features | ||||
| - **config:** finish integrating new configuration system [a8d6a32](https://gitlab.com/Earthnuker/ed_lrr/commit/a8d6a32) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.12.0] - 2019-09-28 | ||||
| ## [v0.7.0] - 2019-09-28 | ||||
| ### Features | ||||
| - **Router:** finish implementing route computation progress display [93f655c](https://gitlab.com/Earthnuker/ed_lrr/commit/93f655c) | ||||
| 
 | ||||
|  | @ -88,12 +88,12 @@ | |||
| - **CI:** rename main executable before building installer [dc0e3fc](https://gitlab.com/Earthnuker/ed_lrr/commit/dc0e3fc) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.11.0] - 2019-09-28 | ||||
| ## [v0.6.2] - 2019-09-28 | ||||
| ### Features | ||||
| - **GUI:** Integrate route computation Job [f4e6bd3](https://gitlab.com/Earthnuker/ed_lrr/commit/f4e6bd3) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.10.0] - 2019-09-28 | ||||
| ## [v0.6.1] - 2019-09-28 | ||||
| ### Features | ||||
| - **GUI:** Integrate new config system [22ca2d2](https://gitlab.com/Earthnuker/ed_lrr/commit/22ca2d2) | ||||
| 
 | ||||
|  | @ -101,12 +101,12 @@ | |||
| - re-export config from main GUI module [0d89106](https://gitlab.com/Earthnuker/ed_lrr/commit/0d89106) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.9.0] - 2019-09-28 | ||||
| ## [v0.6.0] - 2019-09-28 | ||||
| ### Features | ||||
| - **cli:** Add config editor [8b0b56f](https://gitlab.com/Earthnuker/ed_lrr/commit/8b0b56f) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.8.0] - 2019-09-28 | ||||
| ## [v0.5.1] - 2019-09-28 | ||||
| ### Features | ||||
| - **router:** Implement route computation job with progress dualog [2c000da](https://gitlab.com/Earthnuker/ed_lrr/commit/2c000da) | ||||
| 
 | ||||
|  | @ -114,7 +114,7 @@ | |||
| - **setup.py:** Pull version info from git, unify scripts (one script for GUI and CLI) [a630851](https://gitlab.com/Earthnuker/ed_lrr/commit/a630851) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.7.0] - 2019-09-28 | ||||
| ## [v0.5.0] - 2019-09-28 | ||||
| ### Documentation | ||||
| - Update README.md [66267e7](https://gitlab.com/Earthnuker/ed_lrr/commit/66267e7) | ||||
| 
 | ||||
|  | @ -125,67 +125,67 @@ | |||
| - Update icon generator and regenerate icon [7838480](https://gitlab.com/Earthnuker/ed_lrr/commit/7838480) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.6.0] - 2019-09-28 | ||||
| ## [v0.4.1] - 2019-09-28 | ||||
| ### Features | ||||
| - **router:** Start implementing route pruning support [88a0378](https://gitlab.com/Earthnuker/ed_lrr/commit/88a0378) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.5.0] - 2019-09-28 | ||||
| ## [v0.4.0] - 2019-09-28 | ||||
| ### Features | ||||
| - **config:** Update config system to use profig [b1143c3](https://gitlab.com/Earthnuker/ed_lrr/commit/b1143c3) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.4.0] - 2019-09-28 | ||||
| ## [v0.3.0] - 2019-09-28 | ||||
| ### Features | ||||
| - **build system:** Remove build.py (switched to tox), add output to build_gui.py [fb3a130](https://gitlab.com/Earthnuker/ed_lrr/commit/fb3a130) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.3.0] - 2019-09-28 | ||||
| ## [v0.2.0] - 2019-09-28 | ||||
| ### Features | ||||
| - **router:** Add dialog to display computed route [d498746](https://gitlab.com/Earthnuker/ed_lrr/commit/d498746) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.11] - 2019-09-21 | ||||
| ## [v0.1.12] - 2019-09-21 | ||||
| ### Bug Fixes | ||||
| - switch inno setup version in appveyor [fe3534e](https://gitlab.com/Earthnuker/ed_lrr/commit/fe3534e) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.10] - 2019-09-21 | ||||
| ## [v0.1.11] - 2019-09-21 | ||||
| ### Bug Fixes | ||||
| - typo in appveyor.yml [09e6f0a](https://gitlab.com/Earthnuker/ed_lrr/commit/09e6f0a) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.9] - 2019-09-21 | ||||
| ## [v0.1.10] - 2019-09-21 | ||||
| ### Bug Fixes | ||||
| - disable confirmation for conda install [eaddb18](https://gitlab.com/Earthnuker/ed_lrr/commit/eaddb18) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.8] - 2019-09-21 | ||||
| ## [v0.1.9] - 2019-09-21 | ||||
| ### Bug Fixes | ||||
| - add missing conda channel [6d9f1ef](https://gitlab.com/Earthnuker/ed_lrr/commit/6d9f1ef) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.7] - 2019-09-21 | ||||
| ## [v0.1.8] - 2019-09-21 | ||||
| ### Bug Fixes | ||||
| - add missing dependencies to appveyor.yml [e8beb55](https://gitlab.com/Earthnuker/ed_lrr/commit/e8beb55) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.6] - 2019-09-20 | ||||
| ## [v0.1.7] - 2019-09-20 | ||||
| ### Bug Fixes | ||||
| - fix nuikta call to clean build directory [fa485be](https://gitlab.com/Earthnuker/ed_lrr/commit/fa485be) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.5] - 2019-09-20 | ||||
| ## [v0.1.6] - 2019-09-20 | ||||
| ### Bug Fixes | ||||
| - fix nuikta call to download without confirmation [11efe30](https://gitlab.com/Earthnuker/ed_lrr/commit/11efe30) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.4] - 2019-09-20 | ||||
| ## [v0.1.5] - 2019-09-20 | ||||
| ### Bug Fixes | ||||
| - fixed appveyor.yml [59390fe](https://gitlab.com/Earthnuker/ed_lrr/commit/59390fe) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.3] - 2019-09-20 | ||||
| ## [v0.1.4] - 2019-09-20 | ||||
| ### Bug Fixes | ||||
| - fixed tox.ini [6bb7e1e](https://gitlab.com/Earthnuker/ed_lrr/commit/6bb7e1e) | ||||
| 
 | ||||
|  | @ -193,7 +193,7 @@ | |||
| - small wording change [3779911](https://gitlab.com/Earthnuker/ed_lrr/commit/3779911) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.2] - 2019-08-31 | ||||
| ## [v0.1.3] - 2019-08-31 | ||||
| ### Bug Fixes | ||||
| - **setup:** fix setup script to include subdirectories [4a392d9](https://gitlab.com/Earthnuker/ed_lrr/commit/4a392d9) | ||||
| 
 | ||||
|  | @ -208,12 +208,12 @@ | |||
| - **formatting:** ran `cargo fmt` and `cargo clippy`, fixed all warnings [fb3f79b](https://gitlab.com/Earthnuker/ed_lrr/commit/fb3f79b) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.1] - 2019-08-05 | ||||
| ## [v0.1.2] - 2019-08-05 | ||||
| ### Bug Fixes | ||||
| - **router:** Fixed some syntax errors created by botched merge [4b14643](https://gitlab.com/Earthnuker/ed_lrr/commit/4b14643) | ||||
| 
 | ||||
| 
 | ||||
| ## [v0.2.0] - 2019-08-05 | ||||
| ## [v0.1.1] - 2019-08-05 | ||||
| ### Features | ||||
| - **GUI:** Implement route plotting and fuzzy search [c290d5e](https://gitlab.com/Earthnuker/ed_lrr/commit/c290d5e) | ||||
| 
 | ||||
|  | @ -225,40 +225,40 @@ | |||
| 
 | ||||
| ## v0.0.0 - 2019-07-15 | ||||
| 
 | ||||
| [Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.24.0...HEAD | ||||
| [v0.24.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.23.0...v0.24.0 | ||||
| [v0.23.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.22.0...v0.23.0 | ||||
| [v0.22.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.21.0...v0.22.0 | ||||
| [v0.21.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.20.0...v0.21.0 | ||||
| [v0.20.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.19.1...v0.20.0 | ||||
| [v0.19.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.19.0...v0.19.1 | ||||
| [v0.19.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.18.0...v0.19.0 | ||||
| [v0.18.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.17.0...v0.18.0 | ||||
| [v0.17.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.16.0...v0.17.0 | ||||
| [v0.16.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.15.0...v0.16.0 | ||||
| [v0.15.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.14.0...v0.15.0 | ||||
| [Unreleased]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.14.0...HEAD | ||||
| [v0.14.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.13.0...v0.14.0 | ||||
| [v0.13.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.12.0...v0.13.0 | ||||
| [v0.12.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.11.0...v0.12.0 | ||||
| [v0.11.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.10.0...v0.11.0 | ||||
| [v0.10.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.9.0...v0.10.0 | ||||
| [v0.9.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.8.0...v0.9.0 | ||||
| [v0.8.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.7.0...v0.8.0 | ||||
| [v0.7.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.6.0...v0.7.0 | ||||
| [v0.6.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.5.0...v0.6.0 | ||||
| [v0.5.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.4.0...v0.5.0 | ||||
| [v0.10.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.9.4...v0.10.0 | ||||
| [v0.9.4]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.9.3...v0.9.4 | ||||
| [v0.9.3]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.9.2...v0.9.3 | ||||
| [v0.9.2]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.9.1...v0.9.2 | ||||
| [v0.9.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.9.0...v0.9.1 | ||||
| [v0.9.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.8.1...v0.9.0 | ||||
| [v0.8.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.8.0...v0.8.1 | ||||
| [v0.8.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.7.1...v0.8.0 | ||||
| [v0.7.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.7.0...v0.7.1 | ||||
| [v0.7.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.6.2...v0.7.0 | ||||
| [v0.6.2]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.6.1...v0.6.2 | ||||
| [v0.6.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.6.0...v0.6.1 | ||||
| [v0.6.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.5.1...v0.6.0 | ||||
| [v0.5.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.5.0...v0.5.1 | ||||
| [v0.5.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.4.1...v0.5.0 | ||||
| [v0.4.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.4.0...v0.4.1 | ||||
| [v0.4.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.3.0...v0.4.0 | ||||
| [v0.3.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.11...v0.3.0 | ||||
| [v0.2.11]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.10...v0.2.11 | ||||
| [v0.2.10]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.9...v0.2.10 | ||||
| [v0.2.9]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.8...v0.2.9 | ||||
| [v0.2.8]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.7...v0.2.8 | ||||
| [v0.2.7]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.6...v0.2.7 | ||||
| [v0.2.6]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.5...v0.2.6 | ||||
| [v0.2.5]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.4...v0.2.5 | ||||
| [v0.2.4]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.3...v0.2.4 | ||||
| [v0.2.3]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.2...v0.2.3 | ||||
| [v0.2.2]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.1...v0.2.2 | ||||
| [v0.2.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.0...v0.2.1 | ||||
| [v0.2.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.0...v0.2.0 | ||||
| [v0.3.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.2.0...v0.3.0 | ||||
| [v0.2.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.12...v0.2.0 | ||||
| [v0.1.12]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.11...v0.1.12 | ||||
| [v0.1.11]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.10...v0.1.11 | ||||
| [v0.1.10]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.9...v0.1.10 | ||||
| [v0.1.9]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.8...v0.1.9 | ||||
| [v0.1.8]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.7...v0.1.8 | ||||
| [v0.1.7]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.6...v0.1.7 | ||||
| [v0.1.6]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.5...v0.1.6 | ||||
| [v0.1.5]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.4...v0.1.5 | ||||
| [v0.1.4]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.3...v0.1.4 | ||||
| [v0.1.3]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.2...v0.1.3 | ||||
| [v0.1.2]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.1...v0.1.2 | ||||
| [v0.1.1]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.1.0...v0.1.1 | ||||
| [v0.1.0]: https://gitlab.com/Earthnuker/ed_lrr/compare/v0.0.0...v0.1.0 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| include rust/Cargo.toml | ||||
| include rust/.cargo/config | ||||
| recursive-include rust/src * | ||||
| recursive-include ed_lrr_gui * | ||||
| recursive-include ed_lrr_gui * | ||||
|  |  | |||
|  | @ -80,4 +80,3 @@ then you can run `ed_lrr -h` from your command prompt to get help | |||
| - Luigi based Task queue for distributed routing | ||||
| - Full route tree computation | ||||
|   - overlap elimination | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										32
									
								
								appveyor.yml
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								appveyor.yml
									
										
									
									
									
								
							|  | @ -1,26 +1,20 @@ | |||
| image: Visual Studio 2019 | ||||
| platform: x64 | ||||
| version: 0.1.{build} | ||||
| branches: | ||||
|   only: | ||||
|   - pyqt_gui | ||||
|   - WIP | ||||
| 
 | ||||
| environment: | ||||
|   VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat | ||||
|   VCVARSARG: x64 | ||||
|   MINICONDA: C:\Miniconda3-x64 | ||||
|   INNO: C:\Program Files (x86)\Inno Setup 6 | ||||
| 
 | ||||
| build: off | ||||
| 
 | ||||
| artifacts: | ||||
|   - path: exe\__main__.dist\ | ||||
|     name: ED_LRR | ||||
|     type: zip | ||||
| 
 | ||||
|   - path: installer\Output\*.exe | ||||
|     name: Setup | ||||
|     type: file | ||||
|   matrix: | ||||
|   - PY_VERSION: "3.5" | ||||
|   - PY_VERSION: "3.6" | ||||
|   - PY_VERSION: "3.7" | ||||
|   - PY_VERSION: "3.8" | ||||
| 
 | ||||
| install: | ||||
|   - set PATH=%MINICONDA%\\Library\\bin;%MINICONDA%\\Scripts;%USERPROFILE%\\.cargo\\bin;%PATH% | ||||
|  | @ -30,14 +24,12 @@ install: | |||
|   - if defined VCVARS call "%VCVARS%" %VCVARSARG% | ||||
|   - conda activate | ||||
|   - conda update -y -n base -c defaults conda | ||||
|   - conda install -y -c conda-forge pycrypto nuitka | ||||
|   - pip install PyQt5 setuptools_rust | ||||
|   - pip install nox | ||||
| 
 | ||||
| test_script: | ||||
|   - python build_gui.py | ||||
|   - pip install .[dev] | ||||
|   - python -m nuitka --plugin-enable=multiprocessing --remove-output --plugin-enable=qt-plugins --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py | ||||
|   - rename exe\__main__.dist\__main__.exe ED_LRR.exe | ||||
|   - cd installer | ||||
|   - iscc /QP ED_LRR.iss | ||||
|   - ps: nox -s test-$env:PY_VERSION | ||||
| 
 | ||||
| build_script: | ||||
|   - ps: nox -s build-$env:PY_VERSION | ||||
|   - ps: Get-ChildItem .\installer\Output\*.exe | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } | ||||
|   - ps: Get-ChildItem .\dist\* | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name.Insert($_.Name.Length,".zip") } | ||||
							
								
								
									
										39
									
								
								benchmark.py
									
										
									
									
									
								
							
							
						
						
									
										39
									
								
								benchmark.py
									
										
									
									
									
								
							|  | @ -1,39 +0,0 @@ | |||
| from datetime import datetime | ||||
| import time | ||||
| import json | ||||
| import statistics as stats | ||||
| from pprint import pprint | ||||
| import os | ||||
| import _ed_lrr | ||||
| 
 | ||||
| NUM_LOOPS=5 | ||||
| 
 | ||||
| results={} | ||||
| 
 | ||||
| def time_run(w,s,file="benchmark.json", loops=None): | ||||
|     global results,NUM_LOOPS | ||||
|     if loops is None: | ||||
|         loops=NUM_LOOPS | ||||
|     for _ in range(loops): | ||||
|         t_start = time.time() | ||||
|         ret = _ed_lrr.route(s,48,None,'bfs',True,False,False,False,0.0,None,r"D:\devel\rust\ED_LRR\stars.csv",w,lambda *args,**kwargs: None) | ||||
|         t_end = time.time() | ||||
|         results.setdefault(w,[]).append({'ret':len(ret),'time':t_end - t_start}) | ||||
|     with open(file, "w") as of: | ||||
|         json.dump(results, of,indent=2) | ||||
| 
 | ||||
| t_start = datetime.today() | ||||
| 
 | ||||
| for w in [1,2,4,7,8,0]: | ||||
|     time_run(w,['Ix','72']) | ||||
| 
 | ||||
| print("Benchmark took:", datetime.today() - t_start) | ||||
| 
 | ||||
| 
 | ||||
| for workers,results in results.items(): | ||||
|     t_total=sum([res['time'] for res in results])/len(results) | ||||
|     avg_len=sum([res['ret'] for res in results])/len(results) | ||||
|     times.append([int(workers),timedelta(seconds=t_total),avg_len]) | ||||
| 
 | ||||
| for k,v,l in sorted(times,key=lambda rec:rec[1]): | ||||
|     print(k,v,l) | ||||
|  | @ -1,12 +0,0 @@ | |||
| import ujson as json | ||||
| from datetime import timedelta | ||||
| data=json.load(open("benchmark.json")) | ||||
| 
 | ||||
| times=[] | ||||
| 
 | ||||
| for workers,results in data.items(): | ||||
|     t_total=sum([res['time'] for res in results])/len(results) | ||||
|     avg_len=sum([res['ret'] for res in results])/len(results) | ||||
|     times.append([int(workers),timedelta(seconds=t_total),avg_len]) | ||||
| for k,v,l in sorted(times,key=lambda rec:rec[1]): | ||||
|     print(k,v,l) | ||||
|  | @ -1,9 +1,11 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from PyQt5 import uic | ||||
| import os | ||||
| 
 | ||||
| 
 | ||||
| ui_path = os.path.dirname(os.path.abspath(__file__)) | ||||
| for root, folders, files in os.walk(ui_path): | ||||
|     if "site-packages" in root: | ||||
|         continue | ||||
|     if ".history" in folders: | ||||
|         folders.remove(".history") | ||||
|     for file in files: | ||||
|  |  | |||
							
								
								
									
										16
									
								
								celery/celery_rabbitmq_setup.ps1
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								celery/celery_rabbitmq_setup.ps1
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| #RABBITMQ | ||||
| rabbitmqctl stop_app | ||||
| rabbitmqctl reset | ||||
| rabbitmqctl start_app | ||||
| rabbitmqctl add_user ed_lrr ed_lrr  | ||||
| rabbitmqctl add_vhost ed_lrr | ||||
| rabbitmqctl set_user_tags ed_lrr ed_lrr | ||||
| rabbitmqctl set_permissions -p ed_lrr ed_lrr ".*" ".*" ".*" | ||||
| rabbitmqctl set_permissions guest ".*" ".*" ".*" | ||||
| rabbitmqctl set_permissions -p ed_lrr guest ".*" ".*" ".*" | ||||
| Write-Host RabbitMQ setup done | ||||
| #Celery | ||||
| Write-Host starting Celery | ||||
| celery worker -l info | ||||
| 
 | ||||
| #celery -A celery_test flower --presistent --broker=pyamqp://ed_lrr:ed_lrr@localhost/ed_lrr --broker_api=http://ed_lrr:ed_lrr@localhost:15672/api/ | ||||
							
								
								
									
										32
									
								
								celery/celery_test.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								celery/celery_test.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from celery import Celery | ||||
| import _ed_lrr | ||||
| import os | ||||
| 
 | ||||
| os.environ.setdefault("CELERY_CONFIG_MODULE", "celeryconfig") | ||||
| app = Celery("ed_lrr") | ||||
| app.config_from_envvar("CELERY_CONFIG_MODULE") | ||||
| 
 | ||||
| 
 | ||||
| @app.task(bind=True) | ||||
| def route(self, hops, jmp_range): | ||||
|     def callback(state): | ||||
|         print("PRC: ", state.get("prc_done", 0.0)) | ||||
|         self.update_state(state="PROGRESS", meta=state) | ||||
| 
 | ||||
|     self.update_state(state="RUNNING", meta={}) | ||||
|     return _ed_lrr.route( | ||||
|         hops, | ||||
|         jmp_range, | ||||
|         None, | ||||
|         "bfs", | ||||
|         True, | ||||
|         False, | ||||
|         False, | ||||
|         False, | ||||
|         0.0, | ||||
|         None, | ||||
|         r"C:\Users\Earthnuker\AppData\Local\ED_LRR\data\stars.csv", | ||||
|         0, | ||||
|         callback, | ||||
|     ) | ||||
							
								
								
									
										14
									
								
								celery/celery_worker.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								celery/celery_worker.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import time | ||||
| from celery_test import route | ||||
| import sys | ||||
| 
 | ||||
| if len(sys.argv) > 1: | ||||
|     job = route.AsyncResult(sys.argv[1]) | ||||
|     if job.ready(): | ||||
|         print([job, job.state, len(job.info), len(job.result)]) | ||||
|     else: | ||||
|         print([job, job.state, job.info, job.result]) | ||||
|     exit(0) | ||||
| jobs = [route.delay(["Ix", "Colonia"], 48)] | ||||
| print(jobs) | ||||
							
								
								
									
										18
									
								
								celery/celeryconfig.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								celery/celeryconfig.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| import os | ||||
| 
 | ||||
| os.environ["FORKED_BY_MULTIPROCESSING"] = "1" | ||||
| broker_url = "pyamqp://ed_lrr:ed_lrr@localhost/ed_lrr" | ||||
| broker_api = "http://guest:guest@localhost:15672/api/" | ||||
| imports = ("celery_test",) | ||||
| result_backend = "file://celery_results/" | ||||
| result_persistent = True | ||||
| task_track_started = True | ||||
| task_time_limit = 60 * 60 | ||||
| result_extended = True | ||||
| result_expires = None | ||||
| worker_direct = True | ||||
| worker_max_tasks_per_child = 10 | ||||
| worker_max_memory_per_child = 4 * 1024 * 1024  # 4GB | ||||
| worker_state_db = "ed_lrr.state" | ||||
| worker_send_task_events = True | ||||
| worker_log_color = True | ||||
|  | @ -1,9 +0,0 @@ | |||
| from celery import Celery | ||||
| import _ed_lrr | ||||
| app = Celery('ed_lrr',backend = 'db+sqlite:///ed_lrr_results.sqlite', broker='pyamqp://ed_lrr:ed_lrr@localhost/ed_lrr') | ||||
| 
 | ||||
| @app.task(bind=True) | ||||
| def route(self,hops,jmp_range): | ||||
|     def callback(state): | ||||
|         self.update_state(state="PROGRESS", meta=state) | ||||
|     return _ed_lrr.route(hops,jmp_range,None,'bfs',True,False,False,False,0.0,None,r"C:\Users\Earthnuker\AppData\Local\ED_LRR\data\stars.csv",0,callback) | ||||
|  | @ -1,18 +0,0 @@ | |||
| import time | ||||
| from celery_test import route | ||||
| 
 | ||||
| jobs = [route.delay(["Ix", "Colonia"], 48), route.delay(["Colonia", "Sol"], 48)] | ||||
| while True: | ||||
|     for job in jobs: | ||||
|         if job.ready(): | ||||
|             print([job, job.state, len(job.info)]) | ||||
|         else: | ||||
|             print([job, job.state, job.info]) | ||||
|     print("="*10) | ||||
|     time.sleep(1) | ||||
| 
 | ||||
| # 02c77491-9abd-4a88-ab2c-acdf2981086b | ||||
| # d56b0ca8-067d-45a6-be9b-bb9e74f196cd | ||||
| 
 | ||||
| # celery -A celery_test flower --presistent --broker=pyamqp://ed_lrr:ed_lrr@localhost/ed_lrr --broker_api=http://ed_lrr:ed_lrr@localhost:15672/api/ | ||||
| 
 | ||||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import contextlib | ||||
| import csv | ||||
| import datetime | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import heapq | ||||
| import sys | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from _ed_lrr import * | ||||
| 
 | ||||
| from .preprocess import Preprocessor | ||||
|  |  | |||
|  | @ -1,17 +1,19 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import sys | ||||
| import multiprocessing as MP | ||||
| import queue | ||||
| import ctypes | ||||
| import os | ||||
| from datetime import datetime | ||||
| from math import floor | ||||
| import click | ||||
| from tqdm import tqdm | ||||
| from click_default_group import DefaultGroup | ||||
| import requests as RQ | ||||
| from urllib.parse import urljoin | ||||
| from ed_lrr_gui import Router, Preprocessor, cfg | ||||
| from _ed_lrr import find_sys | ||||
| from _ed_lrr import PyRouter | ||||
| 
 | ||||
| from dotenv import load_dotenv | ||||
| load_dotenv() | ||||
| 
 | ||||
| CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"]) | ||||
| 
 | ||||
|  | @ -43,9 +45,8 @@ def main(ctx): | |||
|     MP.freeze_support() | ||||
|     if ctx.invoked_subcommand != "config": | ||||
|         os.makedirs(cfg["folders.data_dir"], exist_ok=True) | ||||
|     if ctx.invoked_subcommand is None: | ||||
|         ctx.invoke(gui) | ||||
|         return | ||||
|     if ctx.invoked_subcommand==None: | ||||
|         click.forward(gui_main) | ||||
|     return | ||||
| 
 | ||||
| 
 | ||||
|  | @ -55,18 +56,20 @@ def main(ctx): | |||
| @click.option("--debug", "-d", is_flag=True, help="Run using debug server") | ||||
| def web(host, port, debug): | ||||
|     "Run web interface." | ||||
|     from gevent import monkey | ||||
|     monkey.patch_all() | ||||
|     from gevent.pywsgi import WSGIServer | ||||
|     from ed_lrr_gui.web import app | ||||
| 
 | ||||
|     with app.test_client() as c: | ||||
|         c.get("/")  # Force before_first_request hook to run | ||||
|     if debug: | ||||
|         app.debug=True | ||||
|         app.debug = True | ||||
|         app.run(host=host, port=port, debug=True) | ||||
|         return | ||||
|     print("Listening on {}:{}".format(host, port)) | ||||
|     server = WSGIServer((host, port), app) | ||||
|     server.serve_forever() | ||||
|     else: | ||||
|         print("Listening on {}:{}".format(host, port)) | ||||
|         server = WSGIServer((host, port), app) | ||||
|         server.serve_forever() | ||||
| 
 | ||||
| 
 | ||||
| @main.command() | ||||
|  | @ -175,7 +178,7 @@ def download(url, folder): | |||
|             unit_divisor=1024, | ||||
|             unit_scale=True, | ||||
|             ascii=True, | ||||
|             smoothing=0 | ||||
|             smoothing=0, | ||||
|         ) as pbar: | ||||
|             with open(download_path, "wb") as of: | ||||
|                 resp = RQ.get( | ||||
|  | @ -224,7 +227,7 @@ def preprocess(systems, bodies, output): | |||
|         preproc.start() | ||||
|         state = {} | ||||
|         pstate = {} | ||||
|         while not (preproc.queue.empty() and preproc.is_alive() == False): | ||||
|         while not (preproc.queue.empty() and not preproc.is_alive()): | ||||
|             try: | ||||
|                 event = preproc.queue.get(True, 0.1) | ||||
|                 state.update(event) | ||||
|  | @ -309,7 +312,7 @@ def preprocess(systems, bodies, output): | |||
|     "-m", | ||||
|     default=cfg["route.mode"], | ||||
|     help="Search mode", | ||||
|     type=click.Choice(["bfs","bfs_old", "a-star", "greedy"]), | ||||
|     type=click.Choice(["bfs", "bfs_old", "a-star", "greedy"]), | ||||
|     show_default=True, | ||||
| ) | ||||
| @click.option( | ||||
|  | @ -358,7 +361,7 @@ def route(**kwargs): | |||
|         kwargs["factor"], | ||||
|         None, | ||||
|         kwargs["path"], | ||||
|         kwargs["workers"] | ||||
|         kwargs["workers"], | ||||
|     ] | ||||
|     with click.progressbar( | ||||
|         length=100, | ||||
|  | @ -429,5 +432,9 @@ def precompute(*args, **kwargs): | |||
|     raise NotImplementedError | ||||
| 
 | ||||
| 
 | ||||
| def gui_main(): | ||||
|     return gui(False) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import pathlib | ||||
| from collections import namedtuple | ||||
| import profig | ||||
|  | @ -9,6 +10,8 @@ config_dir.mkdir(parents=True, exist_ok=True) | |||
| config_file = config_dir / "config.ini" | ||||
| config_file.touch() | ||||
| 
 | ||||
| config_dir = str(config_dir) | ||||
| 
 | ||||
| cfg = profig.Config(str(config_file), strict=True) | ||||
| 
 | ||||
| cfg.init( | ||||
|  | @ -55,8 +58,8 @@ cfg.init("folders.data_dir", os.path.join(config_dir, "data"), comment="Data dir | |||
| 
 | ||||
| cfg.init("GUI.theme", "dark", comment="GUI theme to use") | ||||
| 
 | ||||
| cfg.init("web.port",3777,comment="Port to bind to") | ||||
| cfg.init("web.host","0.0.0.0",comment="Address to bind to") | ||||
| cfg.init("web.debug",False,comment="Run using debug server") | ||||
| cfg.init("web.port", 3777, comment="Port to bind to") | ||||
| cfg.init("web.host", "0.0.0.0", comment="Address to bind to") | ||||
| cfg.init("web.debug", False, comment="Run using debug server") | ||||
| 
 | ||||
| cfg.sync() | ||||
|  |  | |||
|  | @ -1 +1,2 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from .main import main | ||||
|  |  | |||
|  | @ -15,7 +15,9 @@ class Ui_ED_LRR(object): | |||
|         ED_LRR.setObjectName("ED_LRR") | ||||
|         ED_LRR.setEnabled(True) | ||||
|         ED_LRR.resize(577, 500) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(ED_LRR.sizePolicy().hasHeightForWidth()) | ||||
|  | @ -26,10 +28,14 @@ class Ui_ED_LRR(object): | |||
|         ED_LRR.setDocumentMode(False) | ||||
|         ED_LRR.setTabShape(QtWidgets.QTabWidget.Rounded) | ||||
|         self.centralwidget = QtWidgets.QWidget(ED_LRR) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) | ||||
|         sizePolicy.setHeightForWidth( | ||||
|             self.centralwidget.sizePolicy().hasHeightForWidth() | ||||
|         ) | ||||
|         self.centralwidget.setSizePolicy(sizePolicy) | ||||
|         self.centralwidget.setObjectName("centralwidget") | ||||
|         self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) | ||||
|  | @ -49,27 +55,39 @@ class Ui_ED_LRR(object): | |||
|         self.formLayout.setObjectName("formLayout") | ||||
|         self.lbl_bodies_dl = QtWidgets.QLabel(self.tab_download) | ||||
|         self.lbl_bodies_dl.setObjectName("lbl_bodies_dl") | ||||
|         self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_dl) | ||||
|         self.formLayout.setWidget( | ||||
|             1, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_dl | ||||
|         ) | ||||
|         self.lbl_systems_dl = QtWidgets.QLabel(self.tab_download) | ||||
|         self.lbl_systems_dl.setObjectName("lbl_systems_dl") | ||||
|         self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl) | ||||
|         self.formLayout.setWidget( | ||||
|             3, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_dl | ||||
|         ) | ||||
|         self.inp_bodies_dl = QtWidgets.QComboBox(self.tab_download) | ||||
|         self.inp_bodies_dl.setEditable(True) | ||||
|         self.inp_bodies_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) | ||||
|         self.inp_bodies_dl.setObjectName("inp_bodies_dl") | ||||
|         self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl) | ||||
|         self.formLayout.setWidget( | ||||
|             1, QtWidgets.QFormLayout.FieldRole, self.inp_bodies_dl | ||||
|         ) | ||||
|         self.inp_systems_dl = QtWidgets.QComboBox(self.tab_download) | ||||
|         self.inp_systems_dl.setEditable(True) | ||||
|         self.inp_systems_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) | ||||
|         self.inp_systems_dl.setObjectName("inp_systems_dl") | ||||
|         self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl) | ||||
|         self.formLayout.setWidget( | ||||
|             3, QtWidgets.QFormLayout.FieldRole, self.inp_systems_dl | ||||
|         ) | ||||
|         self.gridLayout = QtWidgets.QGridLayout() | ||||
|         self.gridLayout.setObjectName("gridLayout") | ||||
|         self.inp_bodies_dest_dl = QtWidgets.QComboBox(self.tab_download) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth()) | ||||
|         sizePolicy.setHeightForWidth( | ||||
|             self.inp_bodies_dest_dl.sizePolicy().hasHeightForWidth() | ||||
|         ) | ||||
|         self.inp_bodies_dest_dl.setSizePolicy(sizePolicy) | ||||
|         self.inp_bodies_dest_dl.setEditable(False) | ||||
|         self.inp_bodies_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) | ||||
|  | @ -85,10 +103,14 @@ class Ui_ED_LRR(object): | |||
|         self.btn_systems_dest_browse_dl.setObjectName("btn_systems_dest_browse_dl") | ||||
|         self.gridLayout_2.addWidget(self.btn_systems_dest_browse_dl, 0, 1, 1, 1) | ||||
|         self.inp_systems_dest_dl = QtWidgets.QComboBox(self.tab_download) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth()) | ||||
|         sizePolicy.setHeightForWidth( | ||||
|             self.inp_systems_dest_dl.sizePolicy().hasHeightForWidth() | ||||
|         ) | ||||
|         self.inp_systems_dest_dl.setSizePolicy(sizePolicy) | ||||
|         self.inp_systems_dest_dl.setEditable(False) | ||||
|         self.inp_systems_dest_dl.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) | ||||
|  | @ -111,57 +133,79 @@ class Ui_ED_LRR(object): | |||
|         self.formLayout_3.setObjectName("formLayout_3") | ||||
|         self.lbl_bodies_pp = QtWidgets.QLabel(self.tab_preprocess) | ||||
|         self.lbl_bodies_pp.setObjectName("lbl_bodies_pp") | ||||
|         self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_pp) | ||||
|         self.formLayout_3.setWidget( | ||||
|             0, QtWidgets.QFormLayout.LabelRole, self.lbl_bodies_pp | ||||
|         ) | ||||
|         self.gr_bodies_pp = QtWidgets.QGridLayout() | ||||
|         self.gr_bodies_pp.setObjectName("gr_bodies_pp") | ||||
|         self.btn_bodies_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) | ||||
|         self.btn_bodies_browse_pp.setObjectName("btn_bodies_browse_pp") | ||||
|         self.gr_bodies_pp.addWidget(self.btn_bodies_browse_pp, 0, 1, 1, 1) | ||||
|         self.inp_bodies_pp = QtWidgets.QComboBox(self.tab_preprocess) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.inp_bodies_pp.sizePolicy().hasHeightForWidth()) | ||||
|         sizePolicy.setHeightForWidth( | ||||
|             self.inp_bodies_pp.sizePolicy().hasHeightForWidth() | ||||
|         ) | ||||
|         self.inp_bodies_pp.setSizePolicy(sizePolicy) | ||||
|         self.inp_bodies_pp.setEditable(False) | ||||
|         self.inp_bodies_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) | ||||
|         self.inp_bodies_pp.setObjectName("inp_bodies_pp") | ||||
|         self.gr_bodies_pp.addWidget(self.inp_bodies_pp, 0, 0, 1, 1) | ||||
|         self.formLayout_3.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp) | ||||
|         self.formLayout_3.setLayout( | ||||
|             0, QtWidgets.QFormLayout.FieldRole, self.gr_bodies_pp | ||||
|         ) | ||||
|         self.lbl_systems_pp = QtWidgets.QLabel(self.tab_preprocess) | ||||
|         self.lbl_systems_pp.setObjectName("lbl_systems_pp") | ||||
|         self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_pp) | ||||
|         self.formLayout_3.setWidget( | ||||
|             1, QtWidgets.QFormLayout.LabelRole, self.lbl_systems_pp | ||||
|         ) | ||||
|         self.gr_systems_pp = QtWidgets.QGridLayout() | ||||
|         self.gr_systems_pp.setObjectName("gr_systems_pp") | ||||
|         self.btn_systems_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) | ||||
|         self.btn_systems_browse_pp.setObjectName("btn_systems_browse_pp") | ||||
|         self.gr_systems_pp.addWidget(self.btn_systems_browse_pp, 0, 1, 1, 1) | ||||
|         self.inp_systems_pp = QtWidgets.QComboBox(self.tab_preprocess) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.inp_systems_pp.sizePolicy().hasHeightForWidth()) | ||||
|         sizePolicy.setHeightForWidth( | ||||
|             self.inp_systems_pp.sizePolicy().hasHeightForWidth() | ||||
|         ) | ||||
|         self.inp_systems_pp.setSizePolicy(sizePolicy) | ||||
|         self.inp_systems_pp.setEditable(False) | ||||
|         self.inp_systems_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) | ||||
|         self.inp_systems_pp.setObjectName("inp_systems_pp") | ||||
|         self.gr_systems_pp.addWidget(self.inp_systems_pp, 0, 0, 1, 1) | ||||
|         self.formLayout_3.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp) | ||||
|         self.formLayout_3.setLayout( | ||||
|             1, QtWidgets.QFormLayout.FieldRole, self.gr_systems_pp | ||||
|         ) | ||||
|         self.lbl_out_pp = QtWidgets.QLabel(self.tab_preprocess) | ||||
|         self.lbl_out_pp.setObjectName("lbl_out_pp") | ||||
|         self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lbl_out_pp) | ||||
|         self.gr_out_grid_pp = QtWidgets.QGridLayout() | ||||
|         self.gr_out_grid_pp.setObjectName("gr_out_grid_pp") | ||||
|         self.btn_out_browse_pp = QtWidgets.QPushButton(self.tab_preprocess) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.btn_out_browse_pp.sizePolicy().hasHeightForWidth()) | ||||
|         sizePolicy.setHeightForWidth( | ||||
|             self.btn_out_browse_pp.sizePolicy().hasHeightForWidth() | ||||
|         ) | ||||
|         self.btn_out_browse_pp.setSizePolicy(sizePolicy) | ||||
|         self.btn_out_browse_pp.setObjectName("btn_out_browse_pp") | ||||
|         self.gr_out_grid_pp.addWidget(self.btn_out_browse_pp, 0, 1, 1, 1) | ||||
|         self.inp_out_pp = QtWidgets.QComboBox(self.tab_preprocess) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.inp_out_pp.sizePolicy().hasHeightForWidth()) | ||||
|  | @ -170,10 +214,14 @@ class Ui_ED_LRR(object): | |||
|         self.inp_out_pp.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) | ||||
|         self.inp_out_pp.setObjectName("inp_out_pp") | ||||
|         self.gr_out_grid_pp.addWidget(self.inp_out_pp, 0, 0, 1, 1) | ||||
|         self.formLayout_3.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp) | ||||
|         self.formLayout_3.setLayout( | ||||
|             2, QtWidgets.QFormLayout.FieldRole, self.gr_out_grid_pp | ||||
|         ) | ||||
|         self.btn_preprocess = QtWidgets.QPushButton(self.tab_preprocess) | ||||
|         self.btn_preprocess.setObjectName("btn_preprocess") | ||||
|         self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.btn_preprocess) | ||||
|         self.formLayout_3.setWidget( | ||||
|             3, QtWidgets.QFormLayout.LabelRole, self.btn_preprocess | ||||
|         ) | ||||
|         self.tabs.addTab(self.tab_preprocess, "") | ||||
|         self.tab_route = QtWidgets.QWidget() | ||||
|         self.tab_route.setObjectName("tab_route") | ||||
|  | @ -181,14 +229,18 @@ class Ui_ED_LRR(object): | |||
|         self.formLayout_2.setObjectName("formLayout_2") | ||||
|         self.lbl_sys_lst = QtWidgets.QLabel(self.tab_route) | ||||
|         self.lbl_sys_lst.setObjectName("lbl_sys_lst") | ||||
|         self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lbl_sys_lst) | ||||
|         self.formLayout_2.setWidget( | ||||
|             0, QtWidgets.QFormLayout.LabelRole, self.lbl_sys_lst | ||||
|         ) | ||||
|         self.gr_sys = QtWidgets.QGridLayout() | ||||
|         self.gr_sys.setObjectName("gr_sys") | ||||
|         self.btn_sys_lst_browse = QtWidgets.QPushButton(self.tab_route) | ||||
|         self.btn_sys_lst_browse.setObjectName("btn_sys_lst_browse") | ||||
|         self.gr_sys.addWidget(self.btn_sys_lst_browse, 0, 1, 1, 1) | ||||
|         self.inp_sys_lst = QtWidgets.QComboBox(self.tab_route) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.inp_sys_lst.sizePolicy().hasHeightForWidth()) | ||||
|  | @ -221,32 +273,44 @@ class Ui_ED_LRR(object): | |||
|         self.formLayout_2.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.gr_mode) | ||||
|         self.chk_permute = QtWidgets.QCheckBox(self.tab_route) | ||||
|         self.chk_permute.setObjectName("chk_permute") | ||||
|         self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.chk_permute) | ||||
|         self.formLayout_2.setWidget( | ||||
|             4, QtWidgets.QFormLayout.LabelRole, self.chk_permute | ||||
|         ) | ||||
|         self.gridLayout_4 = QtWidgets.QGridLayout() | ||||
|         self.gridLayout_4.setObjectName("gridLayout_4") | ||||
|         self.chk_permute_keep_last = QtWidgets.QCheckBox(self.tab_route) | ||||
|         self.chk_permute_keep_last.setObjectName("chk_permute_keep_last") | ||||
|         self.gridLayout_4.addWidget(self.chk_permute_keep_last, 0, 3, 1, 1) | ||||
|         self.chk_permute_keep_first = QtWidgets.QCheckBox(self.tab_route) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.chk_permute_keep_first.sizePolicy().hasHeightForWidth()) | ||||
|         sizePolicy.setHeightForWidth( | ||||
|             self.chk_permute_keep_first.sizePolicy().hasHeightForWidth() | ||||
|         ) | ||||
|         self.chk_permute_keep_first.setSizePolicy(sizePolicy) | ||||
|         self.chk_permute_keep_first.setTristate(False) | ||||
|         self.chk_permute_keep_first.setObjectName("chk_permute_keep_first") | ||||
|         self.gridLayout_4.addWidget(self.chk_permute_keep_first, 0, 2, 1, 1) | ||||
|         self.lbl_keep = QtWidgets.QLabel(self.tab_route) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.lbl_keep.sizePolicy().hasHeightForWidth()) | ||||
|         self.lbl_keep.setSizePolicy(sizePolicy) | ||||
|         self.lbl_keep.setObjectName("lbl_keep") | ||||
|         self.gridLayout_4.addWidget(self.lbl_keep, 0, 1, 1, 1) | ||||
|         self.formLayout_2.setLayout(4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4) | ||||
|         self.formLayout_2.setLayout( | ||||
|             4, QtWidgets.QFormLayout.FieldRole, self.gridLayout_4 | ||||
|         ) | ||||
|         self.lst_sys = QtWidgets.QTreeWidget(self.tab_route) | ||||
|         sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) | ||||
|         sizePolicy = QtWidgets.QSizePolicy( | ||||
|             QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding | ||||
|         ) | ||||
|         sizePolicy.setHorizontalStretch(0) | ||||
|         sizePolicy.setVerticalStretch(0) | ||||
|         sizePolicy.setHeightForWidth(self.lst_sys.sizePolicy().hasHeightForWidth()) | ||||
|  | @ -353,17 +417,27 @@ class Ui_ED_LRR(object): | |||
| 
 | ||||
|     def retranslateUi(self, ED_LRR): | ||||
|         _translate = QtCore.QCoreApplication.translate | ||||
|         ED_LRR.setWindowTitle(_translate("ED_LRR", "Elite: Dangerous Long Range Route Plotter")) | ||||
|         ED_LRR.setWindowTitle( | ||||
|             _translate("ED_LRR", "Elite: Dangerous Long Range Route Plotter") | ||||
|         ) | ||||
|         self.lbl_bodies_dl.setText(_translate("ED_LRR", "bodies.json")) | ||||
|         self.lbl_systems_dl.setText(_translate("ED_LRR", "systemsWithCoordinates.json")) | ||||
|         self.inp_bodies_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/bodies.json")) | ||||
|         self.inp_systems_dl.setCurrentText(_translate("ED_LRR", "https://www.edsm.net/dump/systemsWithCoordinates.json")) | ||||
|         self.inp_bodies_dl.setCurrentText( | ||||
|             _translate("ED_LRR", "https://www.edsm.net/dump/bodies.json") | ||||
|         ) | ||||
|         self.inp_systems_dl.setCurrentText( | ||||
|             _translate( | ||||
|                 "ED_LRR", "https://www.edsm.net/dump/systemsWithCoordinates.json" | ||||
|             ) | ||||
|         ) | ||||
|         self.btn_bodies_dest_browse_dl.setText(_translate("ED_LRR", "...")) | ||||
|         self.btn_systems_dest_browse_dl.setText(_translate("ED_LRR", "...")) | ||||
|         self.btn_download.setText(_translate("ED_LRR", "Download")) | ||||
|         self.label.setText(_translate("ED_LRR", "Download path")) | ||||
|         self.label_2.setText(_translate("ED_LRR", "Download path")) | ||||
|         self.tabs.setTabText(self.tabs.indexOf(self.tab_download), _translate("ED_LRR", "Download")) | ||||
|         self.tabs.setTabText( | ||||
|             self.tabs.indexOf(self.tab_download), _translate("ED_LRR", "Download") | ||||
|         ) | ||||
|         self.lbl_bodies_pp.setText(_translate("ED_LRR", "bodies.json")) | ||||
|         self.btn_bodies_browse_pp.setText(_translate("ED_LRR", "...")) | ||||
|         self.lbl_systems_pp.setText(_translate("ED_LRR", "systemsWithCoordinates.json")) | ||||
|  | @ -371,7 +445,9 @@ class Ui_ED_LRR(object): | |||
|         self.lbl_out_pp.setText(_translate("ED_LRR", "Output")) | ||||
|         self.btn_out_browse_pp.setText(_translate("ED_LRR", "...")) | ||||
|         self.btn_preprocess.setText(_translate("ED_LRR", "Preprocess")) | ||||
|         self.tabs.setTabText(self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess")) | ||||
|         self.tabs.setTabText( | ||||
|             self.tabs.indexOf(self.tab_preprocess), _translate("ED_LRR", "Preprocess") | ||||
|         ) | ||||
|         self.lbl_sys_lst.setText(_translate("ED_LRR", "System List")) | ||||
|         self.btn_sys_lst_browse.setText(_translate("ED_LRR", "...")) | ||||
|         self.btn_add.setText(_translate("ED_LRR", "Add")) | ||||
|  | @ -393,8 +469,12 @@ class Ui_ED_LRR(object): | |||
|         self.chk_primary.setText(_translate("ED_LRR", "Primary Stars Only")) | ||||
|         self.lbl_mode.setText(_translate("ED_LRR", "Mode")) | ||||
|         self.btn_go.setText(_translate("ED_LRR", "GO!")) | ||||
|         self.tabs.setTabText(self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route")) | ||||
|         self.tabs.setTabText(self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log")) | ||||
|         self.tabs.setTabText( | ||||
|             self.tabs.indexOf(self.tab_route), _translate("ED_LRR", "Route") | ||||
|         ) | ||||
|         self.tabs.setTabText( | ||||
|             self.tabs.indexOf(self.tab_log), _translate("ED_LRR", "Log") | ||||
|         ) | ||||
|         self.menu_file.setTitle(_translate("ED_LRR", "File")) | ||||
|         self.menuWindow.setTitle(_translate("ED_LRR", "Window")) | ||||
|         self.menuStyle.setTitle(_translate("ED_LRR", "Style")) | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import csv | ||||
| import gzip | ||||
| import multiprocessing as MP | ||||
|  | @ -474,7 +475,7 @@ class ED_LRR(Ui_ED_LRR): | |||
|             greedyness, | ||||
|             precomp, | ||||
|             path, | ||||
|             os.cpu_count()-1 | ||||
|             os.cpu_count() - 1, | ||||
|         ) | ||||
|         if not self.current_job: | ||||
|             self.bar_status.showMessage("Computing Route...") | ||||
|  | @ -492,7 +493,7 @@ class ED_LRR(Ui_ED_LRR): | |||
|                 greedyness, | ||||
|                 precomp, | ||||
|                 path, | ||||
|                 os.cpu_count()-1 | ||||
|                 os.cpu_count() - 1, | ||||
|             ) | ||||
|         else: | ||||
|             self.error("there is already a job running!") | ||||
|  |  | |||
|  | @ -25,7 +25,9 @@ class Ui_diag_route(object): | |||
|         self.lst_route.setAlternatingRowColors(True) | ||||
|         self.lst_route.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) | ||||
|         self.lst_route.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem) | ||||
|         self.lst_route.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) | ||||
|         self.lst_route.setHorizontalScrollMode( | ||||
|             QtWidgets.QAbstractItemView.ScrollPerPixel | ||||
|         ) | ||||
|         self.lst_route.setItemsExpandable(False) | ||||
|         self.lst_route.setAllColumnsShowFocus(False) | ||||
|         self.lst_route.setObjectName("lst_route") | ||||
|  | @ -53,7 +55,11 @@ class Ui_diag_route(object): | |||
|         self.lst_route.headerItem().setText(0, _translate("diag_route", "Num")) | ||||
|         self.lst_route.headerItem().setText(1, _translate("diag_route", "System")) | ||||
|         self.lst_route.headerItem().setText(2, _translate("diag_route", "Body")) | ||||
|         self.lst_route.headerItem().setText(3, _translate("diag_route", "Distance (Ls)")) | ||||
|         self.chk_copy.setText(_translate("diag_route", "Auto-copy next hop to clipboard")) | ||||
|         self.lst_route.headerItem().setText( | ||||
|             3, _translate("diag_route", "Distance (Ls)") | ||||
|         ) | ||||
|         self.chk_copy.setText( | ||||
|             _translate("diag_route", "Auto-copy next hop to clipboard") | ||||
|         ) | ||||
|         self.btn_close.setText(_translate("diag_route", "Close")) | ||||
|         self.btn_export.setText(_translate("diag_route", "Export")) | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import jinja2 | ||||
| import os | ||||
| 
 | ||||
|  | @ -10,6 +11,7 @@ def dist(p1, p2): | |||
|         s += (c1 - c2) ** 2 | ||||
|     return s ** 0.5 | ||||
| 
 | ||||
| 
 | ||||
| colors = { | ||||
|     "O": "#0000FF", | ||||
|     "B": "#140AF0", | ||||
|  |  | |||
|  | @ -155,4 +155,4 @@ | |||
|     </script> | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
| </html> | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import queue | ||||
| from collections import namedtuple | ||||
| from datetime import datetime, timedelta | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import queue | ||||
| from collections import namedtuple | ||||
| from datetime import datetime, timedelta | ||||
|  | @ -20,7 +21,7 @@ class Router(Process): | |||
|         self.queue.put({"status": state}) | ||||
| 
 | ||||
|     def run(self): | ||||
|         print("Route(): ",self.args,self.kwargs) | ||||
|         print("Route(): ", self.args, self.kwargs) | ||||
|         route = _ed_lrr.route(*self.args, **self.kwargs) | ||||
|         self.queue.put({"return": route}) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1 +1,2 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from .app import app, templates, db | ||||
|  |  | |||
|  | @ -1,28 +1,22 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from flask import ( | ||||
|     Flask, | ||||
|     jsonify, | ||||
|     session, | ||||
|     render_template, | ||||
|     redirect, | ||||
|     url_for, | ||||
|     send_from_directory, | ||||
|     request, | ||||
|     flash, | ||||
|     current_app | ||||
|     current_app, | ||||
| ) | ||||
| from flask.json.tag import JSONTag | ||||
| from flask.cli import AppGroup | ||||
| import uuid | ||||
| import pickle | ||||
| import os | ||||
| import time | ||||
| import random | ||||
| import base64 | ||||
| import gevent | ||||
| import click | ||||
| from functools import wraps | ||||
| from concurrent.futures.process import BrokenProcessPool | ||||
| from datetime import datetime, timedelta | ||||
| from decimal import Decimal | ||||
| from multiprocessing import Queue | ||||
| from webargs import fields, validate | ||||
| from webargs.flaskparser import use_kwargs | ||||
| 
 | ||||
|  | @ -50,11 +44,9 @@ from flask_login import ( | |||
| 
 | ||||
| from flask_debugtoolbar import DebugToolbarExtension | ||||
| 
 | ||||
| from werkzeug.http import HTTP_STATUS_CODES | ||||
| from sqlalchemy_utils import generic_repr, JSONType, PasswordType, UUIDType | ||||
| from sqlalchemy.ext.declarative import declarative_base | ||||
| from sqlalchemy.orm import scoped_session, sessionmaker, relationship, backref | ||||
| from sqlalchemy.types import Float, String, DateTime | ||||
| from sqlalchemy.orm import relationship | ||||
| from sqlalchemy.types import DateTime | ||||
| from jinja2.exceptions import TemplateNotFound | ||||
| from .forms import RouteForm, LoginForm, RegisterForm, ChangePasswordForm | ||||
| from .utils import prepare_route, BootsrapRenderer, is_safe_url | ||||
|  | @ -65,22 +57,24 @@ templates = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates" | |||
| app = Flask(__name__, template_folder=templates) | ||||
| app.config.from_pyfile("config.py") | ||||
| 
 | ||||
| executor = Executor(app) | ||||
| db = SQLAlchemy(app) | ||||
| bootstrap = Bootstrap(app) | ||||
| csrf = CSRFProtect(app) | ||||
| nav = Nav(app) | ||||
| login_manager = LoginManager(app) | ||||
| app.executor = executor = Executor(app) | ||||
| app.db = db = SQLAlchemy(app) | ||||
| app.bootstrap = bootstrap = Bootstrap(app) | ||||
| app.csrf = csfr = CSRFProtect(app) | ||||
| app.nav = nav = Nav(app) | ||||
| app.login_manager = login_manager = LoginManager(app) | ||||
| login_manager.login_view = "login" | ||||
| login_manager.session_protection = "strong" | ||||
| admin = Admin(app, name="ED_LRR", template_mode="bootstrap3") | ||||
| app.debug=True | ||||
| toolbar = DebugToolbarExtension(app) | ||||
| app.debug = True | ||||
| app.toolbar = toolbar = DebugToolbarExtension(app) | ||||
| 
 | ||||
| 
 | ||||
| def wants_json_response(): | ||||
|     return request.accept_mimetypes['application/json'] >= \ | ||||
|         request.accept_mimetypes['text/html'] | ||||
|     return ( | ||||
|         request.accept_mimetypes["application/json"] | ||||
|         >= request.accept_mimetypes["text/html"] | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| @app.errorhandler(422) | ||||
|  | @ -89,30 +83,34 @@ def wants_json_response(): | |||
| @app.errorhandler(404) | ||||
| def handle_error(err): | ||||
|     if wants_json_response(): | ||||
|         return jsonify(error=str(err),code=err.code), err.code | ||||
|     templates=["error/{}.html".format(err.code),"error/default.html"] | ||||
|         return jsonify(error=str(err), code=err.code), err.code | ||||
|     templates = ["error/{}.html".format(err.code), "error/default.html"] | ||||
|     try: | ||||
|         print(dir(err)) | ||||
|         return render_template(templates,error=err),err.code | ||||
|         return render_template(templates, error=err), err.code | ||||
|     except TemplateNotFound: | ||||
|         return err.get_response() | ||||
| 
 | ||||
| 
 | ||||
| def role_required(*roles): | ||||
|     def wrapper(fn): | ||||
|         @wraps(fn) | ||||
|         def decorated_view(*args, **kwargs): | ||||
|             if not current_user.is_authenticated(): | ||||
|                return current_app.login_manager.unauthorized() | ||||
|             has_role=False | ||||
|             user=current_app.login_manager.reload_user() | ||||
|                 return current_app.login_manager.unauthorized() | ||||
|             has_role = False | ||||
|             user = current_app.login_manager.reload_user() | ||||
|             for role in roles: | ||||
|                 has_role|=user.has_role(role) | ||||
|                 has_role |= user.has_role(role) | ||||
|             if not has_role: | ||||
|                 return current_app.login_manager.unauthorized() | ||||
|             return fn(*args, **kwargs) | ||||
| 
 | ||||
|         return decorated_view | ||||
| 
 | ||||
|     return wrapper | ||||
| 
 | ||||
| 
 | ||||
| @login_manager.user_loader | ||||
| def load_user(user_name): | ||||
|     return User.query.get(user_name) | ||||
|  | @ -120,7 +118,7 @@ def load_user(user_name): | |||
| 
 | ||||
| @login_manager.request_loader | ||||
| def load_user_from_header(header_val): | ||||
|     for api_key in [request.args.get('api_key'),request.headers.get('X-API-Key')]: | ||||
|     for api_key in [request.args.get("api_key"), request.headers.get("X-API-Key")]: | ||||
|         if api_key: | ||||
|             user = User.query.filter_by(api_key=api_key).one_or_none() | ||||
|             if user: | ||||
|  | @ -130,20 +128,21 @@ def load_user_from_header(header_val): | |||
| 
 | ||||
| 
 | ||||
| def left_nav(): | ||||
|     links=[View("Home", "index"),View("Route", "route"),View("Jobs", "status",job_id=None)] | ||||
|     if current_user.has_role('admin') or current_user.has_role('worker_host'): | ||||
|         links.insert(2,View("Workers","worker")) | ||||
|     return Navbar( | ||||
|         "E:D LRR", | ||||
|         *links | ||||
|     ) | ||||
|     links = [ | ||||
|         View("Home", "index"), | ||||
|         View("Route", "route"), | ||||
|         View("Jobs", "status", job_id=None), | ||||
|     ] | ||||
|     if current_user.has_role("admin") or current_user.has_role("worker_host"): | ||||
|         links.insert(2, View("Workers", "worker")) | ||||
|     return Navbar("E:D LRR", *links) | ||||
| 
 | ||||
| 
 | ||||
| def right_nav(): | ||||
|     links = [View("Login", "login"), View("Register", "register")] | ||||
|     if current_user.is_authenticated: | ||||
|         links = [View("Change Password", "change_password"), View("Logout", "logout")] | ||||
|     if current_user.has_role('admin'): | ||||
|     if current_user.has_role("admin"): | ||||
|         links = [View("Admin", "admin.index")] + links | ||||
|     return Navbar("", *links) | ||||
| 
 | ||||
|  | @ -158,16 +157,15 @@ def compute_route(args, kwargs): | |||
| 
 | ||||
| 
 | ||||
| class AnonymousUser(AnonymousUserMixin): | ||||
|      | ||||
|     def has_role(self,role): | ||||
|     def has_role(self, role): | ||||
|         return False | ||||
| 
 | ||||
|     @property | ||||
|     def roles(self): | ||||
|         return [] | ||||
|      | ||||
| 
 | ||||
|     @roles.setter | ||||
|     def __set_roles(self,value): | ||||
|     def __set_roles(self, value): | ||||
|         raise NotImplementedError | ||||
| 
 | ||||
| 
 | ||||
|  | @ -180,52 +178,68 @@ class Worker(db.Model): | |||
|         UUIDType(binary=False, native=False), primary_key=True, default=uuid.uuid4 | ||||
|     ) | ||||
|     name = db.Column(db.String, unique=True) | ||||
|     current_job=db.Column(UUIDType(binary=False, native=False),db.ForeignKey("job.id"), nullable=True,default=None) | ||||
|     job = relationship('Job',backref="workers") | ||||
|     last_active = db.Column(DateTime, nullable=True,default=None) | ||||
|     owner_name = db.Column( | ||||
|         db.String, db.ForeignKey("user.name"), nullable=True,index=True | ||||
|     current_job = db.Column( | ||||
|         UUIDType(binary=False, native=False), | ||||
|         db.ForeignKey("job.id"), | ||||
|         nullable=True, | ||||
|         default=None, | ||||
|     ) | ||||
|     owner = relationship("User",backref="workers") | ||||
|     job = relationship("Job", backref="workers") | ||||
|     last_active = db.Column(DateTime, nullable=True, default=None) | ||||
|     owner_name = db.Column( | ||||
|         db.String, db.ForeignKey("user.name"), nullable=True, index=True | ||||
|     ) | ||||
|     owner = relationship("User", backref="workers") | ||||
| 
 | ||||
| user_roles = db.Table('user_roles', | ||||
|     db.Column('user_name', db.String, db.ForeignKey('user.name'),primary_key=True), | ||||
|     db.Column('role_name', db.String, db.ForeignKey('role.name'),primary_key=True) | ||||
| 
 | ||||
| user_roles = db.Table( | ||||
|     "user_roles", | ||||
|     db.Column("user_name", db.String, db.ForeignKey("user.name"), primary_key=True), | ||||
|     db.Column("role_name", db.String, db.ForeignKey("role.name"), primary_key=True), | ||||
| ) | ||||
| 
 | ||||
| class Role(db.Model): | ||||
|     name = db.Column(db.String, unique=True,index=True,primary_key=True) | ||||
| 
 | ||||
|     def __init__(self,name): | ||||
|         self.name=name | ||||
| class Role(db.Model): | ||||
|     name = db.Column(db.String, unique=True, index=True, primary_key=True) | ||||
| 
 | ||||
|     def __init__(self, name): | ||||
|         self.name = name | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return self.name | ||||
| 
 | ||||
| 
 | ||||
| class User(db.Model, UserMixin): | ||||
|     name = db.Column(db.String, unique=True,index=True,primary_key=True) | ||||
|     name = db.Column(db.String, unique=True, index=True, primary_key=True) | ||||
|     is_active = db.Column(db.Boolean, default=False) | ||||
|     api_key = db.Column( | ||||
|         UUIDType(binary=False, native=False), nullable=True, default=uuid.uuid4,index=True | ||||
|         UUIDType(binary=False, native=False), | ||||
|         nullable=True, | ||||
|         default=uuid.uuid4, | ||||
|         index=True, | ||||
|     ) | ||||
|     password = db.Column(PasswordType(schemes=["pbkdf2_sha512"], max_length=256)) | ||||
|     created = db.Column(DateTime, default=datetime.today) | ||||
| 
 | ||||
|     roles = db.relationship("Role",secondary="user_roles") | ||||
|     roles = db.relationship("Role", secondary="user_roles") | ||||
| 
 | ||||
|     def add_roles(self,roles): | ||||
|     def add_roles(self, roles): | ||||
|         for role_name in roles: | ||||
|             role=Role.query.filter_by(name=role_name).one() | ||||
|             if not role in self.roles: | ||||
|             role = Role.query.filter_by(name=role_name).one() | ||||
|             if role not in self.roles: | ||||
|                 self.roles.append(role) | ||||
|         db.session.commit() | ||||
| 
 | ||||
|     def has_role(self,role_name): | ||||
|         return Role.query.join(User.roles).filter(User.name==self.name,Role.name==role_name).count()>0 | ||||
|         return ret | ||||
|          | ||||
|     def has_role(self, role_name): | ||||
|         return ( | ||||
|             Role.query.join(User.roles) | ||||
|             .filter(User.name == self.name, Role.name == role_name) | ||||
|             .count() | ||||
|             > 0 | ||||
|         ) | ||||
| 
 | ||||
|     def reset_api_key(self): | ||||
|         self.api_key=uuid,uuid4() | ||||
|         self.api_key = uuid.uuid4() | ||||
|         db.session.add(self) | ||||
|         db.session.comiit() | ||||
| 
 | ||||
|  | @ -241,24 +255,23 @@ class Job(db.Model): | |||
|         UUIDType(binary=False, native=False), primary_key=True, default=uuid.uuid4 | ||||
|     ) | ||||
|     user_name = db.Column( | ||||
|         db.String, db.ForeignKey("user.name"), nullable=True,index=True | ||||
|         db.String, db.ForeignKey("user.name"), nullable=True, index=True | ||||
|     ) | ||||
|     func = db.Column(db.String) | ||||
|     args = db.Column(JSONType) | ||||
|     kwargs = db.Column(JSONType) | ||||
|     state = db.Column(JSONType, default={}) | ||||
|     priority = db.Column(db.Integer, default=0,nullable=True) | ||||
|     priority = db.Column(db.Integer, default=0, nullable=True) | ||||
|     created = db.Column(DateTime, default=datetime.today) | ||||
|     finished = db.Column(DateTime, nullable=True, default=None) | ||||
|     started = db.Column(DateTime, nullable=True, default=None) | ||||
|     last_update = db.Column(DateTime, nullable=True, default=None) | ||||
|     user = relationship("User",backref="jobs") | ||||
|     user = relationship("User", backref="jobs") | ||||
|     # ============================================================ | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         return str(self.id) | ||||
| 
 | ||||
|      | ||||
|     @property | ||||
|     def future(self): | ||||
|         fut = executor.futures._futures.get(self.id) | ||||
|  | @ -266,20 +279,26 @@ class Job(db.Model): | |||
| 
 | ||||
|     @property | ||||
|     def sort_key(self): | ||||
|         state_priorities={"Queued":0,"Starting":1,"Error":1,"Stalled":1,"Running":1} | ||||
|         status_key=state_priorities.get(self.status[1],-1)+1 | ||||
|         user=1-int(self.user is not None) | ||||
|         return (user,-status_key,self.priority,self.created) | ||||
|         state_priorities = { | ||||
|             "Queued": 0, | ||||
|             "Starting": 1, | ||||
|             "Error": 1, | ||||
|             "Stalled": 1, | ||||
|             "Running": 1, | ||||
|         } | ||||
|         status_key = state_priorities.get(self.status[1], -1) + 1 | ||||
|         user = 1 - int(self.user is not None) | ||||
|         return (user, -status_key, self.priority, self.created) | ||||
| 
 | ||||
|     @property | ||||
|     def age(self): | ||||
|         dt=datetime.today()-self.created | ||||
|         dt = datetime.today() - self.created | ||||
|         return dt - dt % timedelta(seconds=1) | ||||
| 
 | ||||
|     @classmethod | ||||
|     def next(cls): | ||||
|         for job in sorted(cls.query.all(),key=lambda v:v.sort_key): | ||||
|             if job.status[1] in ['Done']: | ||||
|     def get_next(cls): | ||||
|         for job in sorted(cls.query.all(), key=lambda v: v.sort_key): | ||||
|             if job.status[1] in ["Done"]: | ||||
|                 continue | ||||
|             return job | ||||
|         return None | ||||
|  | @ -287,15 +306,15 @@ class Job(db.Model): | |||
| 
 | ||||
|     @property | ||||
|     def status(self): | ||||
|         states=[ | ||||
|             ("primary", "Done"), | ||||
|             ("danger", "Error"), | ||||
|             ("info", "Stalled"), | ||||
|             ("success", "Running"), | ||||
|             ("secondary", "Starting"), | ||||
|             ("warning", "Queued") | ||||
|         ] | ||||
|         #return states[self.id.int%len(states)] | ||||
|         # [ | ||||
|         #     ("primary", "Done"), | ||||
|         #     ("danger", "Error"), | ||||
|         #     ("info", "Stalled"), | ||||
|         #     ("success", "Running"), | ||||
|         #     ("secondary", "Starting"), | ||||
|         #     ("warning", "Queued"), | ||||
|         # ] | ||||
|         # return states[self.id.int%len(states)] | ||||
|         if self.state.get("result"): | ||||
|             return ("primary", "Done") | ||||
|         if self.state.get("error"): | ||||
|  | @ -391,7 +410,7 @@ class Job(db.Model): | |||
|                 ).total_seconds() | ||||
|                 if time_since_last_upd < 5.0: | ||||
|                     return | ||||
|             state = dict() | ||||
|             state = {} | ||||
|             state.update(self.state) | ||||
|             state.update({"progress": cb_state}) | ||||
|             self.state = state | ||||
|  | @ -403,7 +422,7 @@ class Job(db.Model): | |||
| 
 | ||||
|     def done(self, future): | ||||
|         print(self.id, "DONE") | ||||
|         state = dict() | ||||
|         state = {} | ||||
|         state.update(self.state) | ||||
|         executor.futures.pop(self.id) | ||||
|         exc = future.exception() | ||||
|  | @ -420,24 +439,25 @@ class Job(db.Model): | |||
| 
 | ||||
| 
 | ||||
| db.create_all() | ||||
| for role in ['admin','user','worker_host']: | ||||
| for role in ["admin", "user", "worker_host"]: | ||||
|     if Role.query.filter_by(name=role).one_or_none() is None: | ||||
|         db.session.add(Role(role)) | ||||
| 
 | ||||
| def create_user(name,password,roles,active=False): | ||||
|     user=User.query.filter_by(name=name).one_or_none() | ||||
| 
 | ||||
| def create_user(name, password, roles, active=False): | ||||
|     user = User.query.filter_by(name=name).one_or_none() | ||||
|     if user: | ||||
|         db.session.delete(user) | ||||
|     user=User(name=name,password=password,is_active=active) | ||||
|     user = User(name=name, password=password, is_active=active) | ||||
|     user.add_roles(roles) | ||||
|     db.session.add(user) | ||||
|     db.session.commit() | ||||
|     return user | ||||
| 
 | ||||
| create_user('admin','admin',['admin','user'],True) | ||||
| create_user('user','user',['user'],True) | ||||
| create_user('host','host',['user','worker_host'],True) | ||||
| 
 | ||||
| # create_user("admin", "admin", ["admin", "user"], True) | ||||
| # create_user("user", "user", ["user"], True) | ||||
| # create_user("host", "host", ["user", "worker_host"], True) | ||||
| 
 | ||||
| 
 | ||||
| class SQLAView(ModelView): | ||||
|  | @ -449,7 +469,7 @@ class SQLAView(ModelView): | |||
|     column_display_pk = True | ||||
| 
 | ||||
|     def is_accessible(self): | ||||
|         return current_user.is_authenticated and current_user.has_role('admin') | ||||
|         return current_user.is_authenticated and current_user.has_role("admin") | ||||
| 
 | ||||
|     def inaccessible_callback(self, name, **kwargs): | ||||
|         return redirect(url_for("login")) | ||||
|  | @ -458,7 +478,7 @@ class SQLAView(ModelView): | |||
| class UserView(SQLAView): | ||||
|     from wtforms import PasswordField | ||||
| 
 | ||||
|     column_list = ("name", "active", "password", "api_key","roles") | ||||
|     column_list = ("name", "active", "password", "api_key", "roles") | ||||
|     column_formatters = { | ||||
|         "password": lambda view, context, model, name: "", | ||||
|         "api_key": lambda view, context, model, name: model.api_key or "", | ||||
|  | @ -469,9 +489,7 @@ class UserView(SQLAView): | |||
| class JobView(SQLAView): | ||||
|     # Job.id,Job.user,Job.func,Job.args,Job.kwargs,Job.state,Job.created,Job.finished,Job.started,Job.last_update | ||||
|     column_list = ("id", "status", "user", "created", "started", "finished") | ||||
|     column_formatters = { | ||||
|         "status": lambda view, context, model, name: model.status[1], | ||||
|     } | ||||
|     column_formatters = {"status": lambda view, context, model, name: model.status[1]} | ||||
| 
 | ||||
| 
 | ||||
| class WorkerView(SQLAView): | ||||
|  | @ -485,6 +503,7 @@ class WorkerView(SQLAView): | |||
|     #     "status": lambda view, context, model, name: model.status[1], | ||||
|     # } | ||||
| 
 | ||||
| 
 | ||||
| admin.add_view(JobView(Job, db.session)) | ||||
| admin.add_view(UserView(User, db.session)) | ||||
| admin.add_view(SQLAView(Worker, db.session)) | ||||
|  | @ -531,7 +550,7 @@ def api_route(_=None, **args): | |||
|         args["factor"], | ||||
|         None, | ||||
|         r"D:\devel\rust\ED_LRR\stars.csv", | ||||
|         app.config['ROUTE_WORKERS'] | ||||
|         app.config["ROUTE_WORKERS"], | ||||
|     ) | ||||
|     return jsonify({"id": submit_job(ed_lrr.route, *args)}) | ||||
| 
 | ||||
|  | @ -544,7 +563,7 @@ def api_status(): | |||
| 
 | ||||
| @app.route("/api/whoami") | ||||
| def api_whoami(): | ||||
|     return jsonify({'name':current_user.name}) | ||||
|     return jsonify({"name": current_user.name}) | ||||
| 
 | ||||
| 
 | ||||
| @app.route("/api/status/<uuid:job_id>") | ||||
|  | @ -573,21 +592,21 @@ def route(): | |||
|     return render_template("form.html", form=form, title="Plot Route") | ||||
| 
 | ||||
| 
 | ||||
| @app.route("/status/",defaults={'job_id':None}) | ||||
| @app.route("/status/", defaults={"job_id": None}) | ||||
| @app.route("/status/<uuid:job_id>") | ||||
| @login_required | ||||
| def status(job_id=None): | ||||
|     if job_id is not None: | ||||
|         job=Job.query.get_or_404(str(job_id)) | ||||
|         job = Job.query.get_or_404(str(job_id)) | ||||
|         return render_template("job.html", job=job) | ||||
|     return render_template( | ||||
|         "status.html", Job=Job, state=request.args.get("state") | ||||
|     ) | ||||
|     return render_template("status.html", Job=Job, state=request.args.get("state")) | ||||
| 
 | ||||
| 
 | ||||
| @app.route("/") | ||||
| def index(): | ||||
|     return render_template("index.html") | ||||
| 
 | ||||
| 
 | ||||
| @app.route("/login", methods=["GET", "POST"]) | ||||
| def login(): | ||||
|     if current_user.is_authenticated: | ||||
|  | @ -602,9 +621,9 @@ def login(): | |||
|             flash("Account is deactivated!", "warning") | ||||
|             return redirect(url_for("login")) | ||||
|         login_user(user, remember=form.data["remember"]) | ||||
|         next = request.args.get('next') | ||||
|         next = request.args.get("next") | ||||
|         if not is_safe_url(next): | ||||
|             next=None | ||||
|             next = None | ||||
|         return redirect(next or url_for("status")) | ||||
|     return render_template("form.html", form=form, title="Login") | ||||
| 
 | ||||
|  | @ -614,7 +633,7 @@ def register(): | |||
|     form = RegisterForm() | ||||
|     if form.validate_on_submit(): | ||||
|         if User.query.filter_by(name=form.data["username"]).one_or_none() is not None: | ||||
|             flash('Username already exists','danger') | ||||
|             flash("Username already exists", "danger") | ||||
|             return render_template("form.html", form=form, title="Register") | ||||
|         user = User() | ||||
|         user.name = form.data["username"] | ||||
|  | @ -641,11 +660,13 @@ def change_password(): | |||
|         return redirect(url_for("status")) | ||||
|     return render_template("form.html", form=form, title="Register") | ||||
| 
 | ||||
| 
 | ||||
| @app.route("/workers/") | ||||
| @login_required | ||||
| def worker(): | ||||
|     return render_template("workers.html") | ||||
| 
 | ||||
| 
 | ||||
| @app.route("/logout") | ||||
| def logout(): | ||||
|     logout_user() | ||||
|  | @ -654,12 +675,38 @@ def logout(): | |||
| 
 | ||||
| @app.before_first_request | ||||
| def resume_jobs(): | ||||
|     print(Job.next()) | ||||
|     print("NEXT:", Job.get_next()) | ||||
|     with app.test_request_context(): | ||||
|         for job in Job.query.all(): | ||||
|             if job.status[1] != "Done": | ||||
|                 print("Restarting {} with state {}".format(job.id, job.status[1])) | ||||
|                 job.start() | ||||
| 
 | ||||
| 
 | ||||
| user_cli = AppGroup('user', help="Manage users") | ||||
| job_cli = AppGroup('job', help="Manage Jobs") | ||||
| worker_cli = AppGroup('worker', help="Manage Workers") | ||||
| 
 | ||||
| 
 | ||||
| @app.cli.command("gevent") | ||||
| def cmd_gevent(): | ||||
|     return | ||||
| 
 | ||||
| 
 | ||||
| @user_cli.command("create") | ||||
| @click.argument("name") | ||||
| @click.option("-i", "--inactive", help="Crate account as inactive", is_flag=True, default=False) | ||||
| @click.option("-r", "--role", help="Assign role to account", default=["user"], multiple=True) | ||||
| @click.password_option("-p", "--password", help="Password for user") | ||||
| def cmd_create_user(name, role, password, inactive): | ||||
|     "Create a new user" | ||||
|     create_user(name, password, role, not inactive) | ||||
|     print("User created!") | ||||
| 
 | ||||
| 
 | ||||
| app.cli.add_command(user_cli) | ||||
| app.cli.add_command(job_cli) | ||||
| app.cli.add_command(worker_cli) | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     app.run(host="127.0.0.1", port=3777, debug=True) | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import os | ||||
| 
 | ||||
| SECRET_KEY = "ED_LRR_WEBAPP" | ||||
|  | @ -8,11 +9,11 @@ SQLALCHEMY_TRACK_MODIFICATIONS = False | |||
| ROUTE_WORKERS = 0 | ||||
| 
 | ||||
| EXECUTOR_TYPE = "process" | ||||
| EXECUTOR_MAX_WORKERS = os.cpu_count()-1 | ||||
| EXECUTOR_MAX_WORKERS = os.cpu_count() - 1 | ||||
| EXECUTOR_FUTURES_MAX_LENGTH = 500 | ||||
| 
 | ||||
| FLASK_ADMIN_SWATCH = "Darkly" | ||||
| 
 | ||||
| DEBUG_TB_TEMPLATE_EDITOR_ENABLED = True | ||||
| 
 | ||||
| MAIL_DEFAULT_SENDER = '"ED_LRR Admin" <ed_lrr@gmail.com>' | ||||
| MAIL_DEFAULT_SENDER = '"ED_LRR Admin" <ed_lrr@gmail.com>' | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from flask_wtf import FlaskForm | ||||
| from wtforms import ( | ||||
|     StringField, | ||||
|  | @ -14,6 +15,7 @@ from wtforms.widgets.html5 import NumberInput | |||
| from wtforms.widgets import TextInput | ||||
| from wtforms.validators import ValidationError | ||||
| 
 | ||||
| 
 | ||||
| class StringListField(Field): | ||||
|     widget = TextInput() | ||||
| 
 | ||||
|  | @ -61,7 +63,7 @@ class RouteForm(FlaskForm): | |||
|         default=50, | ||||
|         widget=NumberInput(min=0, max=100, step=1), | ||||
|     ) | ||||
|      | ||||
| 
 | ||||
|     priority = FloatField( | ||||
|         "Priority (0=max, 100=min)", | ||||
|         [validators.NumberRange(0, 100)], | ||||
|  |  | |||
|  | @ -20,4 +20,4 @@ table { | |||
|     border: 1px solid #eee; | ||||
|     width: 512px; | ||||
|     height: 512px; | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -2,4 +2,4 @@ | |||
| 
 | ||||
| {% block body %} | ||||
|   <p>Hello world</p> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -45,4 +45,4 @@ | |||
|         {# application content needs to be provided in the app_content block #} | ||||
|         {% block app_content %}{% endblock %} | ||||
|     </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -3,4 +3,4 @@ | |||
| {% block app_content %} | ||||
|     <h1>404 Not Found</h1> | ||||
|     <p><a href="{{ url_for('index') }}"><button type="button" class="btn btn-secondary">Back</button></a></p> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -13,4 +13,4 @@ | |||
|             {{ wtf.quick_form(form) }} | ||||
|         </div> | ||||
|     </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -7,4 +7,4 @@ | |||
|             Number of Jobs: {{current_user.jobs|count}} | ||||
|         </div> | ||||
|     </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -128,4 +128,4 @@ | |||
|         {% endif %} | ||||
|     </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -84,4 +84,4 @@ | |||
|             {% endfor %} | ||||
|         </table> | ||||
|     </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -11,4 +11,4 @@ | |||
|             {% endif %} | ||||
|         </div> | ||||
|     </div> | ||||
| {% endblock %} | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -1,13 +1,15 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from flask_nav.renderers import Renderer | ||||
| from dominate import tags | ||||
| from urllib.parse import urlparse,urljoin | ||||
| from urllib.parse import urlparse, urljoin | ||||
| from flask import request | ||||
| 
 | ||||
| 
 | ||||
| def is_safe_url(target): | ||||
|     ref_url = urlparse(request.host_url) | ||||
|     test_url = urlparse(urljoin(request.host_url, target)) | ||||
|     return test_url.scheme in ('http', 'https') and \ | ||||
|            ref_url.netloc == test_url.netloc | ||||
|     return test_url.scheme in ("http", "https") and ref_url.netloc == test_url.netloc | ||||
| 
 | ||||
| 
 | ||||
| def dist(p1, p2): | ||||
|     s = 0 | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import requests as RQ | ||||
| import _ed_lrr as ed_lrr | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import svgwrite | ||||
| import random | ||||
| import time | ||||
|  |  | |||
|  | @ -1,2 +1,2 @@ | |||
| <?xml version="1.0" encoding="utf-8" ?> | ||||
| <svg baseProfile="full" height="100%" version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[.background { fill: #222; }]]></style></defs><rect class="background" height="100%" width="100%" x="0" y="0" /><line stroke="#eee" stroke-width="2" x1="188.02404486871725" x2="103.25754783979495" y1="121.5830171153579" y2="270.7955072425374" /><line stroke="#eee" stroke-width="2" x1="103.25754783979495" x2="528.9775215438594" y1="270.7955072425374" y2="470.2261757479043" /><line stroke="#eee" stroke-width="2" x1="528.9775215438594" x2="452.58130125271924" y1="470.2261757479043" y2="180.96408784515882" /><line stroke="#eee" stroke-width="2" x1="452.58130125271924" x2="338.3400040874068" y1="180.96408784515882" y2="208.34132172072512" /><circle cx="188.02404486871725" cy="121.5830171153579" fill="#eee" r="3.3185498772945903" stroke="#eee" stroke-width="2" /><circle cx="188.02404486871725" cy="121.5830171153579" fill="#eee" fill-opacity="0" r="22.429593602379832" stroke="#eee" stroke-width="2" /><circle cx="173.80179554276944" cy="104.23901834695114" fill="#eee" r="2.52050830126476" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" r="3.4944547782059745" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" fill-opacity="0" r="19.2697560241313" stroke="#eee" stroke-width="2" /><circle cx="115.03444741085107" cy="255.5433554690071" fill="#eee" r="3.7601015027223985" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" fill-opacity="0" r="30.13693855048052" stroke="#eee" stroke-width="2" /><circle cx="89.02212054970202" cy="244.23260689141011" fill="#eee" r="3.0119075514208307" stroke="#eee" stroke-width="2" /><circle cx="528.9775215438594" cy="470.2261757479043" fill="#eee" r="4.420763662755435" stroke="#eee" stroke-width="2" /><circle cx="528.9775215438594" cy="470.2261757479043" fill="#eee" fill-opacity="0" r="22.44577790309402" stroke="#ea0" stroke-width="2" /><circle cx="549.9596596985477" cy="462.25354606049257" fill="#ea0" r="3.680925358835544" stroke="#ea0" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" r="3.8758250081323116" stroke="#eee" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="21.8231723987879" stroke="#ea0" stroke-width="2" /><circle cx="430.78831758434035" cy="179.8166052191519" fill="#ea0" r="2.827892086263464" stroke="#ea0" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="37.812297120687795" stroke="#eee" stroke-width="2" /><circle cx="472.57653937753463" cy="213.0570818761791" fill="#eee" r="2.6102231928654778" stroke="#eee" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="55.938220307034" stroke="#eee" stroke-width="2" /><circle cx="506.1669380410402" cy="197.01600427617765" fill="#eee" r="3.252701491079807" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" r="4.603865384638267" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" fill-opacity="0" r="20.00878719559634" stroke="#eee" stroke-width="2" /><circle cx="329.11968037233845" cy="190.58358550160054" fill="#eee" r="2.132876938772122" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" fill-opacity="0" r="39.144105385654704" stroke="#eee" stroke-width="2" /><circle cx="301.84139133159863" cy="222.48742554279568" fill="#eee" r="2.3674072974299003" stroke="#eee" stroke-width="2" /></svg> | ||||
| <svg baseProfile="full" height="100%" version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[.background { fill: #222; }]]></style></defs><rect class="background" height="100%" width="100%" x="0" y="0" /><line stroke="#eee" stroke-width="2" x1="188.02404486871725" x2="103.25754783979495" y1="121.5830171153579" y2="270.7955072425374" /><line stroke="#eee" stroke-width="2" x1="103.25754783979495" x2="528.9775215438594" y1="270.7955072425374" y2="470.2261757479043" /><line stroke="#eee" stroke-width="2" x1="528.9775215438594" x2="452.58130125271924" y1="470.2261757479043" y2="180.96408784515882" /><line stroke="#eee" stroke-width="2" x1="452.58130125271924" x2="338.3400040874068" y1="180.96408784515882" y2="208.34132172072512" /><circle cx="188.02404486871725" cy="121.5830171153579" fill="#eee" r="3.3185498772945903" stroke="#eee" stroke-width="2" /><circle cx="188.02404486871725" cy="121.5830171153579" fill="#eee" fill-opacity="0" r="22.429593602379832" stroke="#eee" stroke-width="2" /><circle cx="173.80179554276944" cy="104.23901834695114" fill="#eee" r="2.52050830126476" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" r="3.4944547782059745" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" fill-opacity="0" r="19.2697560241313" stroke="#eee" stroke-width="2" /><circle cx="115.03444741085107" cy="255.5433554690071" fill="#eee" r="3.7601015027223985" stroke="#eee" stroke-width="2" /><circle cx="103.25754783979495" cy="270.7955072425374" fill="#eee" fill-opacity="0" r="30.13693855048052" stroke="#eee" stroke-width="2" /><circle cx="89.02212054970202" cy="244.23260689141011" fill="#eee" r="3.0119075514208307" stroke="#eee" stroke-width="2" /><circle cx="528.9775215438594" cy="470.2261757479043" fill="#eee" r="4.420763662755435" stroke="#eee" stroke-width="2" /><circle cx="528.9775215438594" cy="470.2261757479043" fill="#eee" fill-opacity="0" r="22.44577790309402" stroke="#ea0" stroke-width="2" /><circle cx="549.9596596985477" cy="462.25354606049257" fill="#ea0" r="3.680925358835544" stroke="#ea0" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" r="3.8758250081323116" stroke="#eee" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="21.8231723987879" stroke="#ea0" stroke-width="2" /><circle cx="430.78831758434035" cy="179.8166052191519" fill="#ea0" r="2.827892086263464" stroke="#ea0" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="37.812297120687795" stroke="#eee" stroke-width="2" /><circle cx="472.57653937753463" cy="213.0570818761791" fill="#eee" r="2.6102231928654778" stroke="#eee" stroke-width="2" /><circle cx="452.58130125271924" cy="180.96408784515882" fill="#eee" fill-opacity="0" r="55.938220307034" stroke="#eee" stroke-width="2" /><circle cx="506.1669380410402" cy="197.01600427617765" fill="#eee" r="3.252701491079807" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" r="4.603865384638267" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" fill-opacity="0" r="20.00878719559634" stroke="#eee" stroke-width="2" /><circle cx="329.11968037233845" cy="190.58358550160054" fill="#eee" r="2.132876938772122" stroke="#eee" stroke-width="2" /><circle cx="338.3400040874068" cy="208.34132172072512" fill="#eee" fill-opacity="0" r="39.144105385654704" stroke="#eee" stroke-width="2" /><circle cx="301.84139133159863" cy="222.48742554279568" fill="#eee" r="2.3674072974299003" stroke="#eee" stroke-width="2" /></svg> | ||||
|  |  | |||
| Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB | 
|  | @ -1,2 +1,2 @@ | |||
| <?xml version="1.0" encoding="utf-8" ?> | ||||
| <svg baseProfile="full" height="100%" version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[.background { fill: #222; }]]></style></defs><rect class="background" height="100%" width="100%" x="0" y="0" /><line stroke="#eee" stroke-width="2" x1="94.01202243435863" x2="51.628773919897476" y1="60.79150855767895" y2="135.3977536212687" /><line stroke="#eee" stroke-width="2" x1="51.628773919897476" x2="264.4887607719297" y1="135.3977536212687" y2="235.11308787395214" /><line stroke="#eee" stroke-width="2" x1="264.4887607719297" x2="226.29065062635962" y1="235.11308787395214" y2="90.48204392257941" /><line stroke="#eee" stroke-width="2" x1="226.29065062635962" x2="169.1700020437034" y1="90.48204392257941" y2="104.17066086036256" /><circle cx="94.01202243435863" cy="60.79150855767895" fill="#eee" r="5.53091646215765" stroke="#eee" stroke-width="2" /><circle cx="51.628773919897476" cy="135.3977536212687" fill="#eee" r="6.358738772326545" stroke="#eee" stroke-width="2" /><circle cx="264.4887607719297" cy="235.11308787395214" fill="#0ae" r="9.400253756805997" stroke="#0ae" stroke-width="2" /><circle cx="226.29065062635962" cy="90.48204392257941" fill="#eee" r="6.236611100792434" stroke="#eee" stroke-width="2" /><circle cx="169.1700020437034" cy="104.17066086036256" fill="#eee" r="9.41158619939395" stroke="#eee" stroke-width="2" /></svg> | ||||
| <svg baseProfile="full" height="100%" version="1.1" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"><![CDATA[.background { fill: #222; }]]></style></defs><rect class="background" height="100%" width="100%" x="0" y="0" /><line stroke="#eee" stroke-width="2" x1="94.01202243435863" x2="51.628773919897476" y1="60.79150855767895" y2="135.3977536212687" /><line stroke="#eee" stroke-width="2" x1="51.628773919897476" x2="264.4887607719297" y1="135.3977536212687" y2="235.11308787395214" /><line stroke="#eee" stroke-width="2" x1="264.4887607719297" x2="226.29065062635962" y1="235.11308787395214" y2="90.48204392257941" /><line stroke="#eee" stroke-width="2" x1="226.29065062635962" x2="169.1700020437034" y1="90.48204392257941" y2="104.17066086036256" /><circle cx="94.01202243435863" cy="60.79150855767895" fill="#eee" r="5.53091646215765" stroke="#eee" stroke-width="2" /><circle cx="51.628773919897476" cy="135.3977536212687" fill="#eee" r="6.358738772326545" stroke="#eee" stroke-width="2" /><circle cx="264.4887607719297" cy="235.11308787395214" fill="#0ae" r="9.400253756805997" stroke="#0ae" stroke-width="2" /><circle cx="226.29065062635962" cy="90.48204392257941" fill="#eee" r="6.236611100792434" stroke="#eee" stroke-width="2" /><circle cx="169.1700020437034" cy="104.17066086036256" fill="#eee" r="9.41158619939395" stroke="#eee" stroke-width="2" /></svg> | ||||
|  |  | |||
| Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB | 
|  | @ -11,7 +11,7 @@ OutputBaseFilename="ED_LRR Setup" | |||
| ChangesEnvironment = true | ||||
| 
 | ||||
| [Files] | ||||
| Source: "..\exe\__main__.dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs | ||||
| Source: "{#SourceFolder}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs | ||||
| 
 | ||||
| [Icons] | ||||
| Name: "{group}\ED_LRR"; Filename: "{app}\ED_LRR.exe"; WorkingDir: "{app}" | ||||
|  |  | |||
							
								
								
									
										107
									
								
								noxfile.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								noxfile.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| import nox | ||||
| from nox.logger import logger | ||||
| import os | ||||
| import shutil | ||||
| 
 | ||||
| to_append = [] | ||||
| 
 | ||||
| path = os.environ.get("PATH", "").split(os.pathsep) | ||||
| while True: | ||||
|     python = shutil.which("python", path=os.pathsep.join(path)) | ||||
|     if python is None: | ||||
|         break | ||||
|     python = os.path.dirname(python) | ||||
|     for elem in path: | ||||
|         if elem.startswith(python): | ||||
|             path.remove(elem) | ||||
|             to_append.append(elem) | ||||
| 
 | ||||
| path += to_append | ||||
| 
 | ||||
| path = os.pathsep.join(path) | ||||
| os.environ["PATH"] = path | ||||
| 
 | ||||
| versions = ["3.{}".format(s) for s in [5, 6, 7, 8]] | ||||
| 
 | ||||
| versions += ["3"] | ||||
| 
 | ||||
| nox.options.keywords = "test" | ||||
| 
 | ||||
| 
 | ||||
| @nox.session(venv_backend="conda") | ||||
| def devenv(session): | ||||
|     """Set up development environment""" | ||||
|     global path | ||||
|     location = os.path.abspath(session._runner.venv.location_name) | ||||
|     session.env["PATH"] = os.pathsep.join([location, path, location]) | ||||
|     session.conda_install("pycrypto", "ujson") | ||||
|     session.install("--no-cache-dir", "-e", ".[all]") | ||||
|     logger.warning(f'Devenv set up, now run "conda activate {location}"') | ||||
| 
 | ||||
| 
 | ||||
| @nox.session(python=versions, venv_backend="conda") | ||||
| def test(session): | ||||
|     """Run the test suite.""" | ||||
|     global path | ||||
|     location = os.path.abspath(session._runner.venv.location_name) | ||||
|     python = os.path.join(location, "python.exe") | ||||
|     # friendly_name = session._runner.friendly_name | ||||
|     cargo_args = ["--manifest-path", "./rust/Cargo.toml"] | ||||
|     session.env["PATH"] = os.pathsep.join([location, path, location]) | ||||
|     # ================================================ | ||||
|     session.run(python, "-VV", external=True) | ||||
|     session.run("cargo", "clean", *cargo_args, external=True) | ||||
|     session.run("cargo", "clean", *(cargo_args + ["--release"]), external=True) | ||||
|     session.run("cargo", "test", *cargo_args, external=True) | ||||
|     session.conda_install("pycrypto", "ujson") | ||||
|     session.install("--no-cache-dir", "setuptools_rust") | ||||
|     session.install("--no-cache-dir", ".[all]") | ||||
|     session.run("py.test", "-v", *(session.posargs or [])) | ||||
|     # if session.python: | ||||
|     #     session.notify(f"build-{session.python}") | ||||
| 
 | ||||
| 
 | ||||
| @nox.session(python=versions, venv_backend="conda") | ||||
| def build(session): | ||||
|     "Build installer and zip" | ||||
|     global path | ||||
|     location = session._runner.venv.location_name | ||||
|     python = os.path.join(location, "python.exe") | ||||
|     location = os.path.abspath(location) | ||||
|     cargo_args = ["--manifest-path", "./rust/Cargo.toml"] | ||||
|     session.env["PATH"] = os.pathsep.join([location, path, location]) | ||||
|     # ================================================ | ||||
|     session.run(python, "-VV", external=True) | ||||
|     session.run("cargo", "clean", *cargo_args, external=True) | ||||
|     session.run("cargo", "clean", *(cargo_args + ["--release"]), external=True) | ||||
|     session.conda_install("pycrypto", "ujson") | ||||
|     session.install("--no-cache-dir", ".[gui,web,build]") | ||||
|     session.run( | ||||
|         "pyinstaller", | ||||
|         "-y", | ||||
|         "--console", | ||||
|         "--noupx", | ||||
|         "--clean", | ||||
|         "--hidden-import", | ||||
|         "pkg_resources.py2_warn", | ||||
|         "--name", | ||||
|         f"ED_LRR_{session.python}", | ||||
|         "--specpath", | ||||
|         "build", | ||||
|         "ed_lrr_gui/__main__.py", | ||||
|         external=True, | ||||
|         silent=True, | ||||
|     ) | ||||
|     if session.python: | ||||
|         source_path = os.path.abspath(f"./dist/ED_LRR_{session.python}") | ||||
|     else: | ||||
|         source_path = os.path.abspath(f"./dist/ED_LRR") | ||||
|     source_path = source_path.strip(os.sep) | ||||
|     session.run( | ||||
|         "iscc", | ||||
|         f'/FED_LRR_{session.python}', | ||||
|         f'/DSourceFolder={source_path}', | ||||
|         "installer/ED_LRR.iss", | ||||
|         external=True, | ||||
|         silent=True, | ||||
|     ) | ||||
|  | @ -1,2 +1,3 @@ | |||
| [build-system] | ||||
| requires = ["setuptools", "wheel", "setuptools-rust"] | ||||
| requires = ["setuptools", "wheel","setuptools_rust"] | ||||
| build-backend = "setuptools.build_meta" | ||||
|  |  | |||
|  | @ -1,3 +0,0 @@ | |||
| [pytest] | ||||
| qt_api=pyqt5 | ||||
| addopts = --cov=ed_lrr_gui --cov-report html | ||||
							
								
								
									
										413
									
								
								rust/Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										413
									
								
								rust/Cargo.lock
									
										
									
										generated
									
									
									
								
							|  | @ -1,19 +1,11 @@ | |||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| [[package]] | ||||
| name = "ahash" | ||||
| version = "0.2.18" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "aho-corasick" | ||||
| version = "0.7.6" | ||||
| version = "0.7.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -21,16 +13,11 @@ name = "atty" | |||
| version = "0.2.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "autocfg" | ||||
| version = "0.1.7" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "autocfg" | ||||
| version = "1.0.0" | ||||
|  | @ -38,12 +25,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 
 | ||||
| [[package]] | ||||
| name = "backtrace" | ||||
| version = "0.3.43" | ||||
| version = "0.3.44" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
|  | @ -53,7 +40,7 @@ version = "0.1.32" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -61,7 +48,7 @@ name = "better-panic" | |||
| version = "0.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
|  | @ -70,10 +57,15 @@ name = "bincode" | |||
| version = "1.2.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "bitflags" | ||||
| version = "1.2.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "block-buffer" | ||||
| version = "0.7.3" | ||||
|  | @ -81,7 +73,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| dependencies = [ | ||||
|  "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
|  | @ -95,13 +87,13 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "bstr" | ||||
| version = "0.2.10" | ||||
| version = "0.2.11" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -111,7 +103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 
 | ||||
| [[package]] | ||||
| name = "byteorder" | ||||
| version = "1.3.2" | ||||
| version = "1.3.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -131,10 +123,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| dependencies = [ | ||||
|  "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cloudabi" | ||||
| version = "0.0.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "console" | ||||
| version = "0.9.2" | ||||
|  | @ -143,44 +143,27 @@ dependencies = [ | |||
|  "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "const-random" | ||||
| version = "0.1.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "const-random-macro" | ||||
| version = "0.1.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "crossbeam-channel" | ||||
| version = "0.4.0" | ||||
| version = "0.4.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "crossbeam-utils" | ||||
| version = "0.7.0" | ||||
| version = "0.7.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
|  | @ -190,28 +173,48 @@ name = "csv" | |||
| version = "1.1.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "csv-core" | ||||
| version = "0.1.6" | ||||
| version = "0.1.10" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ctor" | ||||
| version = "0.1.12" | ||||
| version = "0.1.13" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "derivative" | ||||
| version = "2.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "dict_derive" | ||||
| version = "0.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -228,19 +231,21 @@ version = "0.2.0" | |||
| dependencies = [ | ||||
|  "better-panic 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "derivative 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "dict_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "humantime 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "pyo3 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "pyo3 0.9.0-alpha.1 (git+https://github.com/PyO3/pyo3)", | ||||
|  "rstar 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "simd-json 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -248,14 +253,6 @@ name = "encode_unicode" | |||
| version = "0.3.6" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "float-cmp" | ||||
| version = "0.5.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "fnv" | ||||
| version = "1.0.6" | ||||
|  | @ -269,16 +266,6 @@ dependencies = [ | |||
|  "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "getrandom" | ||||
| version = "0.1.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ghost" | ||||
| version = "0.1.1" | ||||
|  | @ -286,33 +273,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "halfbrown" | ||||
| version = "0.1.10" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hashbrown" | ||||
| version = "0.6.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hermit-abi" | ||||
| version = "0.1.6" | ||||
| version = "0.1.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -337,7 +306,7 @@ dependencies = [ | |||
|  "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
|  | @ -346,7 +315,7 @@ name = "inventory" | |||
| version = "0.1.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ctor 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "inventory-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
|  | @ -358,7 +327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -378,16 +347,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 
 | ||||
| [[package]] | ||||
| name = "libc" | ||||
| version = "0.2.66" | ||||
| version = "0.2.67" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "lock_api" | ||||
| version = "0.3.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "maybe-uninit" | ||||
| version = "2.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "memchr" | ||||
| version = "2.3.0" | ||||
| version = "2.3.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "num-traits" | ||||
|  | @ -397,29 +376,60 @@ dependencies = [ | |||
|  "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "num_cpus" | ||||
| version = "1.12.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "opaque-debug" | ||||
| version = "0.2.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "paste" | ||||
| version = "0.1.6" | ||||
| name = "parking_lot" | ||||
| version = "0.10.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "parking_lot_core" | ||||
| version = "0.7.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "paste" | ||||
| version = "0.1.7" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "paste-impl 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "paste-impl" | ||||
| version = "0.1.6" | ||||
| version = "0.1.7" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -439,7 +449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -452,43 +462,43 @@ dependencies = [ | |||
| 
 | ||||
| [[package]] | ||||
| name = "pyo3" | ||||
| version = "0.8.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| version = "0.9.0-alpha.1" | ||||
| source = "git+https://github.com/PyO3/pyo3#74b22eb651aac14cd64524219943b77cf7e700ac" | ||||
| dependencies = [ | ||||
|  "indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "inventory 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "pyo3cls 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "paste 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "pyo3cls 0.9.0-alpha.1 (git+https://github.com/PyO3/pyo3)", | ||||
|  "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "pyo3-derive-backend" | ||||
| version = "0.8.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| version = "0.9.0-alpha.1" | ||||
| source = "git+https://github.com/PyO3/pyo3#74b22eb651aac14cd64524219943b77cf7e700ac" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "pyo3cls" | ||||
| version = "0.8.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| version = "0.9.0-alpha.1" | ||||
| source = "git+https://github.com/PyO3/pyo3#74b22eb651aac14cd64524219943b77cf7e700ac" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "pyo3-derive-backend 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "pyo3-derive-backend 0.9.0-alpha.1 (git+https://github.com/PyO3/pyo3)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -499,14 +509,19 @@ dependencies = [ | |||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "redox_syscall" | ||||
| version = "0.1.56" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex" | ||||
| version = "1.3.3" | ||||
| version = "1.3.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
|  | @ -515,12 +530,12 @@ name = "regex-automata" | |||
| version = "0.1.8" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex-syntax" | ||||
| version = "0.6.13" | ||||
| version = "0.6.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -542,32 +557,37 @@ name = "ryu" | |||
| version = "1.0.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "scopeguard" | ||||
| version = "1.1.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde" | ||||
| version = "1.0.104" | ||||
| version = "1.0.105" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde_derive" | ||||
| version = "1.0.104" | ||||
| version = "1.0.105" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "serde_json" | ||||
| version = "1.0.45" | ||||
| version = "1.0.48" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -583,31 +603,18 @@ dependencies = [ | |||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "simd-json" | ||||
| version = "0.2.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "float-cmp 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "halfbrown 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "spin" | ||||
| version = "0.5.2" | ||||
| name = "smallvec" | ||||
| version = "1.2.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "strsim" | ||||
| version = "0.9.3" | ||||
| version = "0.10.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "syn" | ||||
| version = "1.0.14" | ||||
| version = "1.0.15" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  | @ -620,7 +627,7 @@ name = "termios" | |||
| version = "0.3.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| dependencies = [ | ||||
|  "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
|  "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
|  | @ -651,11 +658,6 @@ name = "version_check" | |||
| version = "0.9.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasi" | ||||
| version = "0.9.0+wasi-snapshot-preview1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi" | ||||
| version = "0.3.8" | ||||
|  | @ -676,41 +678,37 @@ version = "0.4.0" | |||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| 
 | ||||
| [metadata] | ||||
| "checksum ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" | ||||
| "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" | ||||
| "checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" | ||||
| "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" | ||||
| "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" | ||||
| "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" | ||||
| "checksum backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "7f80256bc78f67e7df7e36d77366f636ed976895d91fe2ab9efa3973e8fe8c4f" | ||||
| "checksum backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536" | ||||
| "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" | ||||
| "checksum better-panic 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d12a680cc74d8c4a44ee08be4a00dedf671b089c2440b2e3fdaa776cd468476" | ||||
| "checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" | ||||
| "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | ||||
| "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" | ||||
| "checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" | ||||
| "checksum bstr 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8a65814ca90dfc9705af76bb6ba3c6e2534489a72270e797e603783bb4990b" | ||||
| "checksum bstr 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "502ae1441a0a5adb8fbd38a5955a6416b9493e92b465de5e4a9bde6a539c2c48" | ||||
| "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" | ||||
| "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" | ||||
| "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" | ||||
| "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" | ||||
| "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" | ||||
| "checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" | ||||
| "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" | ||||
| "checksum console 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45e0f3986890b3acbc782009e2629dfe2baa430ac091519ce3be26164a2ae6c0" | ||||
| "checksum const-random 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" | ||||
| "checksum const-random-macro 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" | ||||
| "checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" | ||||
| "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" | ||||
| "checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" | ||||
| "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" | ||||
| "checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" | ||||
| "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" | ||||
| "checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" | ||||
| "checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" | ||||
| "checksum ctor 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "47c5e5ac752e18207b12e16b10631ae5f7f68f8805f335f9b817ead83d9ffce1" | ||||
| "checksum derivative 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1b94d2eb97732ec84b4e25eaf37db890e317b80e921f168c82cb5282473f8151" | ||||
| "checksum dict_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d7ee5676aa48357bd5e8bcf095167e6678837232a7b85bce424f46cd93a2c60" | ||||
| "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" | ||||
| "checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" | ||||
| "checksum float-cmp 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75224bec9bfe1a65e2d34132933f2de7fe79900c96a0174307554244ece8150e" | ||||
| "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" | ||||
| "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" | ||||
| "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" | ||||
| "checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" | ||||
| "checksum halfbrown 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f28ee31ba5bb3a3251606db26de2e807552c5f295429d03f756bdc4e00f54c7a" | ||||
| "checksum hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" | ||||
| "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" | ||||
| "checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" | ||||
| "checksum humantime 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da" | ||||
| "checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8" | ||||
| "checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75" | ||||
|  | @ -719,41 +717,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" | ||||
| "checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" | ||||
| "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | ||||
| "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" | ||||
| "checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" | ||||
| "checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" | ||||
| "checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" | ||||
| "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" | ||||
| "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" | ||||
| "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" | ||||
| "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" | ||||
| "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" | ||||
| "checksum paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "423a519e1c6e828f1e73b720f9d9ed2fa643dce8a7737fb43235ce0b41eeaa49" | ||||
| "checksum paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" | ||||
| "checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" | ||||
| "checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" | ||||
| "checksum paste 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "63e1afe738d71b1ebab5f1207c055054015427dbfc7bbe9ee1266894156ec046" | ||||
| "checksum paste-impl 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc4a7f6f743211c5aab239640a65091535d97d43d92a52bca435a640892bb" | ||||
| "checksum pdqselect 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27" | ||||
| "checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" | ||||
| "checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" | ||||
| "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" | ||||
| "checksum pyo3 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1bfe257586436fbe1296d917f14a167d4253d0873bf43e2c9b9bdd58a3f9f35" | ||||
| "checksum pyo3-derive-backend 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4882d8237fd8c7373cc25cb802fe0dab9ff70830fd56f47ef6c7f3f287fcc057" | ||||
| "checksum pyo3cls 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fdf321cfab555f7411298733c86d21e5136f5ded13f5872fabf9de3337beecda" | ||||
| "checksum pyo3 0.9.0-alpha.1 (git+https://github.com/PyO3/pyo3)" = "<none>" | ||||
| "checksum pyo3-derive-backend 0.9.0-alpha.1 (git+https://github.com/PyO3/pyo3)" = "<none>" | ||||
| "checksum pyo3cls 0.9.0-alpha.1 (git+https://github.com/PyO3/pyo3)" = "<none>" | ||||
| "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" | ||||
| "checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" | ||||
| "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" | ||||
| "checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" | ||||
| "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" | ||||
| "checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" | ||||
| "checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" | ||||
| "checksum rstar 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0650eaaa56cbd1726fd671150fce8ac6ed9d9a25d1624430d7ee9d196052f6b6" | ||||
| "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" | ||||
| "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" | ||||
| "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" | ||||
| "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" | ||||
| "checksum serde_json 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "eab8f15f15d6c41a154c1b128a22f2dfabe350ef53c40953d84e36155c91192b" | ||||
| "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" | ||||
| "checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" | ||||
| "checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" | ||||
| "checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" | ||||
| "checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" | ||||
| "checksum simd-json 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fb65296b57a8709ea32a87cefc0e1099cdd407ee3aed89114af11c74ab86f7bf" | ||||
| "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" | ||||
| "checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" | ||||
| "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" | ||||
| "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" | ||||
| "checksum strsim 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" | ||||
| "checksum syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a0294dc449adc58bb6592fff1a23d3e5e6e235afc6a0ffca2657d19e7bbffe5" | ||||
| "checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" | ||||
| "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" | ||||
| "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" | ||||
| "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" | ||||
| "checksum unindent 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "63f18aa3b0e35fed5a0048f029558b1518095ffe2a0a31fb87c93dece93a4993" | ||||
| "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" | ||||
| "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" | ||||
| "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" | ||||
| "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" | ||||
| "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | ||||
|  |  | |||
|  | @ -20,18 +20,20 @@ codegen-units = 1 | |||
| lto = true | ||||
| 
 | ||||
| [dependencies] | ||||
| pyo3 = { version = "0.8.5", features = ["extension-module"] } | ||||
| pyo3 = { git = "https://github.com/PyO3/pyo3", features = ["extension-module"] } | ||||
| csv = "1.1.3" | ||||
| serde = { version = "1.0.104", features = ["derive"] } | ||||
| serde = { version = "1.0.105", features = ["derive"] } | ||||
| humantime = "2.0.0" | ||||
| permutohedron = "0.2.4" | ||||
| serde_json = "1.0.45" | ||||
| serde_json = "1.0.48" | ||||
| fnv = "1.0.6" | ||||
| bincode = "1.2.1" | ||||
| sha3 = "0.8.2" | ||||
| byteorder = "1.3.2" | ||||
| strsim = "0.9.3" | ||||
| byteorder = "1.3.4" | ||||
| strsim = "0.10.0" | ||||
| rstar = "0.7.1" | ||||
| crossbeam-channel = "0.4.0" | ||||
| simd-json = "0.2.3" | ||||
| crossbeam-channel = "0.4.2" | ||||
| better-panic = "0.2.0" | ||||
| derivative = "2.0.2" | ||||
| dict_derive = "0.2.0" | ||||
| num_cpus = "1.12.0" | ||||
|  |  | |||
|  | @ -1,125 +1,145 @@ | |||
| use crate::route::Router; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::cmp::Ordering; | ||||
| use std::collections::HashMap; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| pub fn find_matches( | ||||
|     path: &PathBuf, | ||||
|     names: Vec<String>, | ||||
|     exact: bool | ||||
| ) -> Result<HashMap<String, (f64, Option<System>)>, String> { | ||||
|     let mut best: HashMap<String, (f64, Option<System>)> = HashMap::new(); | ||||
|     for name in &names { | ||||
|         best.insert(name.to_string(), (0.0, None)); | ||||
|     } | ||||
|     let mut reader = match csv::ReaderBuilder::new().from_path(path) { | ||||
|         Ok(rdr) => rdr, | ||||
|         Err(e) => { | ||||
|             return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); | ||||
|         } | ||||
|     }; | ||||
|     let systems = reader.deserialize::<SystemSerde>(); | ||||
|     for sys in systems { | ||||
|         let sys = sys.unwrap(); | ||||
|         for name in &names { | ||||
|             best.entry(name.clone()).and_modify(|ent| { | ||||
|                 if (exact)&&(&sys.system==name) { | ||||
|                     *ent = (1.0, Some(sys.clone().build())) | ||||
|                 } else { | ||||
|                     let d1 = strsim::normalized_levenshtein(&sys.system, &name); | ||||
|                     let d2 = strsim::normalized_levenshtein(&sys.body, &name); | ||||
|                     if d1 > ent.0 { | ||||
|                         *ent = (d1, Some(sys.clone().build())) | ||||
|                     } else if d2 > ent.0 { | ||||
|                         *ent = (d2, Some(sys.clone().build())) | ||||
|                     } | ||||
|                 } | ||||
|                 
 | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|     Ok(best) | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone,Copy, Serialize, Deserialize)] | ||||
| pub struct TreeNode { | ||||
|     pub id: u32, | ||||
|     pub pos: [f32; 3], | ||||
|     pub mult: f32, | ||||
| } | ||||
| 
 | ||||
| impl TreeNode { | ||||
|     pub fn get(&self,router:&Router) -> Option<System> { | ||||
|         let mut cache = router.cache.as_ref().unwrap().lock().unwrap(); | ||||
|         cache.get(self.id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||||
| pub struct SystemSerde { | ||||
|     pub id: u32, | ||||
|     pub star_type: String, | ||||
|     pub system: String, | ||||
|     pub body: String, | ||||
|     pub mult: f32, | ||||
|     pub distance: u32, | ||||
|     pub x: f32, | ||||
|     pub y: f32, | ||||
|     pub z: f32, | ||||
| } | ||||
| 
 | ||||
| impl SystemSerde { | ||||
|     pub fn build(self) -> System { | ||||
|         System { | ||||
|             id: self.id, | ||||
|             star_type: self.star_type, | ||||
|             system: self.system, | ||||
|             body: self.body, | ||||
|             mult: self.mult, | ||||
|             distance: self.distance, | ||||
|             pos: [self.x, self.y, self.z], | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn to_node(&self) -> TreeNode { | ||||
|         TreeNode { | ||||
|             id: self.id, | ||||
|             pos: [self.x, self.y, self.z], | ||||
|             mult: self.mult, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Deserialize, Serialize)] | ||||
| pub struct System { | ||||
|     pub id: u32, | ||||
|     pub star_type: String, | ||||
|     pub system: String, | ||||
|     pub body: String, | ||||
|     pub mult: f32, | ||||
|     pub distance: u32, | ||||
|     pub pos: [f32; 3], | ||||
| } | ||||
| 
 | ||||
| impl System { | ||||
|     pub fn to_node(&self) -> TreeNode { | ||||
|         TreeNode { | ||||
|             id: self.id, | ||||
|             pos: self.pos, | ||||
|             mult: self.mult, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Ord for System { | ||||
|     fn cmp(&self, other: &Self) -> Ordering { | ||||
|         self.id.cmp(&other.id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialOrd for System { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
| use crate::route::Router; | ||||
| use dict_derive::IntoPyObject; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::cmp::Ordering; | ||||
| use std::collections::HashMap; | ||||
| use std::num::ParseIntError; | ||||
| use std::path::PathBuf; | ||||
| use std::str::FromStr; | ||||
| 
 | ||||
| pub enum SysEntry { | ||||
|     ID(u32), | ||||
|     Name(String) | ||||
| } | ||||
| 
 | ||||
| impl SysEntry { | ||||
|     pub fn parse(s: &str) -> Self { | ||||
|         if let Ok(n) = s.parse() { | ||||
|             SysEntry::ID(n) | ||||
|         } else { | ||||
|             SysEntry::Name(s.to_owned()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn find_matches( | ||||
|     path: &PathBuf, | ||||
|     names: Vec<String>, | ||||
|     exact: bool, | ||||
| ) -> Result<HashMap<String, (f64, Option<System>)>, String> { | ||||
|     let mut best: HashMap<String, (f64, Option<System>)> = HashMap::new(); | ||||
|     if names.is_empty() { | ||||
|         return Ok(best); | ||||
|     } | ||||
|     for name in &names { | ||||
|         best.insert(name.to_string(), (0.0, None)); | ||||
|     } | ||||
|     let mut reader = match csv::ReaderBuilder::new().from_path(path) { | ||||
|         Ok(rdr) => rdr, | ||||
|         Err(e) => { | ||||
|             return Err(format!("Error opening {}: {}", path.to_str().unwrap(), e).to_string()); | ||||
|         } | ||||
|     }; | ||||
|     let systems = reader.deserialize::<SystemSerde>(); | ||||
|     for sys in systems { | ||||
|         let sys = sys.unwrap(); | ||||
|         for name in &names { | ||||
|             best.entry(name.clone()).and_modify(|ent| { | ||||
|                 if (exact) && (&sys.system == name) { | ||||
|                     *ent = (1.0, Some(sys.clone().build())) | ||||
|                 } else { | ||||
|                     let d1 = strsim::normalized_levenshtein(&sys.system, &name); | ||||
|                     let d2 = strsim::normalized_levenshtein(&sys.body, &name); | ||||
|                     if d1 > ent.0 { | ||||
|                         *ent = (d1, Some(sys.clone().build())) | ||||
|                     } else if d2 > ent.0 { | ||||
|                         *ent = (d2, Some(sys.clone().build())) | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|     Ok(best) | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, Serialize, Deserialize)] | ||||
| pub struct TreeNode { | ||||
|     pub id: u32, | ||||
|     pub pos: [f32; 3], | ||||
|     pub mult: f32, | ||||
| } | ||||
| 
 | ||||
| impl TreeNode { | ||||
|     pub fn get(&self, router: &Router) -> Option<System> { | ||||
|         let mut cache = router.cache.as_ref().unwrap().lock().unwrap(); | ||||
|         cache.get(self.id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Serialize, Deserialize, IntoPyObject)] | ||||
| pub struct SystemSerde { | ||||
|     pub id: u32, | ||||
|     pub star_type: String, | ||||
|     pub system: String, | ||||
|     pub body: String, | ||||
|     pub mult: f32, | ||||
|     pub distance: u32, | ||||
|     pub x: f32, | ||||
|     pub y: f32, | ||||
|     pub z: f32, | ||||
| } | ||||
| 
 | ||||
| impl SystemSerde { | ||||
|     pub fn build(self) -> System { | ||||
|         System { | ||||
|             id: self.id, | ||||
|             star_type: self.star_type, | ||||
|             system: self.system, | ||||
|             body: self.body, | ||||
|             mult: self.mult, | ||||
|             distance: self.distance, | ||||
|             pos: [self.x, self.y, self.z], | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn to_node(&self) -> TreeNode { | ||||
|         TreeNode { | ||||
|             id: self.id, | ||||
|             pos: [self.x, self.y, self.z], | ||||
|             mult: self.mult, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Deserialize, Serialize)] | ||||
| pub struct System { | ||||
|     pub id: u32, | ||||
|     pub star_type: String, | ||||
|     pub system: String, | ||||
|     pub body: String, | ||||
|     pub mult: f32, | ||||
|     pub distance: u32, | ||||
|     pub pos: [f32; 3], | ||||
| } | ||||
| 
 | ||||
| impl System { | ||||
|     pub fn to_node(&self) -> TreeNode { | ||||
|         TreeNode { | ||||
|             id: self.id, | ||||
|             pos: self.pos, | ||||
|             mult: self.mult, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Ord for System { | ||||
|     fn cmp(&self, other: &Self) -> Ordering { | ||||
|         self.id.cmp(&other.id) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialOrd for System { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,68 +1,83 @@ | |||
| use serde::Deserialize; | ||||
| use serde_json::Result; | ||||
| use serde_json; | ||||
| use std::fs::File; | ||||
| use std::io::Seek; | ||||
| use std::io::{BufRead, BufReader, BufWriter, SeekFrom}; | ||||
| use std::path::PathBuf; | ||||
| use std::str; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct Coords { | ||||
|     x: f32, | ||||
|     y: f32, | ||||
|     z: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct Body { | ||||
|     name: String, | ||||
|     #[serde(rename = "type")] | ||||
|     body_type: String, | ||||
|     subType: String, | ||||
|     #[serde(rename = "distanceToArrival")] | ||||
|     distance: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct System { | ||||
|     coords: Coords, | ||||
|     name: String, | ||||
|     bodies: Vec<Body>, | ||||
| } | ||||
| 
 | ||||
| fn main() -> std::io::Result<()> { | ||||
|     better_panic::install(); | ||||
|     let mut buffer = String::new(); | ||||
|     let mut bz2_reader = std::process::Command::new("bzip2").args( | ||||
|         &["-d","-c",r#"E:\EDSM\galaxy.json.bz2"#] | ||||
|     ).stdout(std::process::Stdio::piped()) | ||||
|     .spawn() | ||||
|     .expect("Failed to spawn execute bzip2!"); | ||||
|     let mut reader = BufReader::new(bz2_reader.stdout.as_mut().expect("Failed to open stdout of child process")); | ||||
|     let mut count = 0; | ||||
|     while let Ok(n) = reader.read_line(&mut buffer) { | ||||
|         if n==0 { | ||||
|             break; | ||||
|         } | ||||
|         buffer = buffer | ||||
|             .trim() | ||||
|             .trim_end_matches(|c| c == ',') | ||||
|             .trim() | ||||
|             .to_string(); | ||||
|         if let Ok(sys) = serde_json::from_str::<System>(&buffer) { | ||||
|             for b in &sys.bodies { | ||||
|                 if b.body_type == "Star" { | ||||
|                     count += 1; | ||||
|                     if (count % 100_000) == 0 { | ||||
|                         println!("{}: {:?}", count, b); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         buffer.clear(); | ||||
|     } | ||||
|     println!("Total: {}", count); | ||||
|     Ok(()) | ||||
| } | ||||
| use serde::Deserialize; | ||||
| use serde_json; | ||||
| use std::io::{BufRead, BufReader}; | ||||
| use std::str; | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct Coords { | ||||
|     x: f32, | ||||
|     y: f32, | ||||
|     z: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct Body { | ||||
|     name: String, | ||||
|     #[serde(rename = "type")] | ||||
|     body_type: String, | ||||
|     #[serde(rename = "subType")] | ||||
|     sub_type: String, | ||||
|     #[serde(rename = "distanceToArrival")] | ||||
|     distance: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct System { | ||||
|     coords: Coords, | ||||
|     name: String, | ||||
|     bodies: Vec<Body>, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* | ||||
| pub id: u32, | ||||
| pub star_type: String, | ||||
| pub system: String, | ||||
| pub body: String, | ||||
| pub mult: f32, | ||||
| pub distance: u32, | ||||
| pub x: f32, | ||||
| pub y: f32, | ||||
| pub z: f32, | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| fn main() -> std::io::Result<()> { | ||||
|     better_panic::install(); | ||||
|     let mut buffer = String::new(); | ||||
|     let mut bz2_reader = std::process::Command::new("bzip2") | ||||
|         .args(&["-d", "-c", r#"E:\EDSM\galaxy.json.bz2"#]) | ||||
|         .stdout(std::process::Stdio::piped()) | ||||
|         .spawn() | ||||
|         .expect("Failed to spawn execute bzip2!"); | ||||
|     let mut reader = BufReader::new( | ||||
|         bz2_reader | ||||
|             .stdout | ||||
|             .as_mut() | ||||
|             .expect("Failed to open stdout of child process"), | ||||
|     ); | ||||
|     let mut count = 0; | ||||
|     while let Ok(n) = reader.read_line(&mut buffer) { | ||||
|         if n == 0 { | ||||
|             break; | ||||
|         } | ||||
|         buffer = buffer | ||||
|             .trim() | ||||
|             .trim_end_matches(|c| c == ',') | ||||
|             .trim() | ||||
|             .to_string(); | ||||
|         if let Ok(sys) = serde_json::from_str::<System>(&buffer) { | ||||
|             for b in &sys.bodies { | ||||
|                 if b.body_type == "Star" { | ||||
|                     count += 1; | ||||
|                     if (count % 100_000) == 0 { | ||||
|                         println!("{}: {:?}", count, b); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         buffer.clear(); | ||||
|     } | ||||
|     println!("Total: {}", count); | ||||
|     Ok(()) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										603
									
								
								rust/src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										603
									
								
								rust/src/lib.rs
									
										
									
									
									
								
							|  | @ -1,221 +1,382 @@ | |||
| #![deny(warnings)] | ||||
| mod common; | ||||
| mod preprocess; | ||||
| mod route; | ||||
| use std::path::PathBuf; | ||||
| use common::find_matches; | ||||
| use pyo3::exceptions::*; | ||||
| use pyo3::prelude::*; | ||||
| use pyo3::types::{PyDict, PyList}; | ||||
| 
 | ||||
| enum SysEntry { | ||||
|     ID(u32), | ||||
|     Name(String), | ||||
| } | ||||
| 
 | ||||
| impl From<&str> for SysEntry { | ||||
|     fn from(s: &str) -> SysEntry { | ||||
|         if let Ok(n) = s.parse() { | ||||
|             SysEntry::ID(n) | ||||
|         } else { | ||||
|             SysEntry::Name(s.to_owned()) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn resolve(entries: &Vec<SysEntry>, path: &PathBuf) -> Result<Vec<u32>,String> { | ||||
|     let mut names: Vec<String> = Vec::new(); | ||||
|     let mut ids: Vec<u32> = Vec::new(); | ||||
|     let mut ret: Vec<u32> = Vec::new(); | ||||
|     for ent in entries { | ||||
|         match ent { | ||||
|             SysEntry::Name(name) => names.push(name.to_owned()), | ||||
|             SysEntry::ID(id) => ids.push(*id), | ||||
|         } | ||||
|     }; | ||||
|     let name_ids = find_matches(path, names, false)?; | ||||
|     for ent in entries { | ||||
|         match ent { | ||||
|             SysEntry::Name(name) => { | ||||
|                 let ent_res=name_ids.get(&name.to_owned()).ok_or(format!("System {} not found",name))?; | ||||
|                 let sys=ent_res.1.as_ref().ok_or(format!("System {} not found",name))?; | ||||
|                 if ent_res.0<0.75 { | ||||
|                     println!("WARNING: {} match to {} with low confidence ({}%)",name,sys.system,ent_res.0*100.0); | ||||
|                 } | ||||
|                 ret.push(sys.id); | ||||
|             } | ||||
|             SysEntry::ID(id) => ret.push(*id), | ||||
|         } | ||||
|     } | ||||
|     return Ok(ret); | ||||
| } | ||||
| 
 | ||||
| #[pymodule] | ||||
| pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { | ||||
|     better_panic::install(); | ||||
|     /// preprocess(infile_systems, infile_bodies, outfile, callback)
 | ||||
|     /// --
 | ||||
|     ///
 | ||||
|     /// Preprocess bodies.json and systemsWithCoordinates.json into stars.csv
 | ||||
|     #[pyfn(m, "preprocess")] | ||||
|     fn ed_lrr_preprocess( | ||||
|         py: Python<'static>, | ||||
|         infile_systems: String, | ||||
|         infile_bodies: String, | ||||
|         outfile: String, | ||||
|         callback: PyObject, | ||||
|     ) -> PyResult<PyObject> { | ||||
|         use preprocess::*; | ||||
|         let state = PyDict::new(py); | ||||
|         let state_dict = PyDict::new(py); | ||||
|         callback.call(py, (state_dict,), None).unwrap(); | ||||
|         let callback_wrapped = move |state: &PreprocessState| { | ||||
|             // println!("SEND: {:?}",state);
 | ||||
|             state_dict.set_item("file", state.file.clone())?; | ||||
|             state_dict.set_item("total", state.total)?; | ||||
|             state_dict.set_item("count", state.count)?; | ||||
|             state_dict.set_item("done", state.done)?; | ||||
|             state_dict.set_item("message", state.message.clone())?; | ||||
|             callback.call(py, (state_dict,), None) | ||||
|         }; | ||||
|         preprocess_files( | ||||
|             &PathBuf::from(infile_bodies), | ||||
|             &PathBuf::from(infile_systems), | ||||
|             &PathBuf::from(outfile), | ||||
|             &callback_wrapped, | ||||
|         ) | ||||
|         .unwrap(); | ||||
|         Ok(state.to_object(py)) | ||||
|     } | ||||
| 
 | ||||
|     ///find_sys(sys_names, sys_list_path)
 | ||||
|     /// --
 | ||||
|     ///
 | ||||
|     /// Find system by name
 | ||||
|     #[pyfn(m, "find_sys")] | ||||
|     fn find_sys(py: Python, sys_names: Vec<String>, sys_list: String) -> PyResult<PyObject> { | ||||
|         let path = PathBuf::from(sys_list); | ||||
|         match find_matches(&path, sys_names,false) { | ||||
|             Ok(vals) => { | ||||
|                 let ret = PyDict::new(py); | ||||
|                 for (key, (diff, sys)) in vals { | ||||
|                     let ret_dict = PyDict::new(py); | ||||
|                     if let Some(val) = sys { | ||||
|                         let pos = PyList::new(py, val.pos.iter()); | ||||
|                         ret_dict.set_item("star_type", val.star_type.clone())?; | ||||
|                         ret_dict.set_item("system", val.system.clone())?; | ||||
|                         ret_dict.set_item("body", val.body.clone())?; | ||||
|                         ret_dict.set_item("distance", val.distance)?; | ||||
|                         ret_dict.set_item("pos", pos)?; | ||||
|                         ret_dict.set_item("id", val.id)?; | ||||
|                         ret.set_item(key, (diff, ret_dict).to_object(py))?; | ||||
|                     } | ||||
|                 } | ||||
|                 Ok(ret.to_object(py)) | ||||
|             } | ||||
|             Err(e) => Err(PyErr::new::<ValueError, _>(e)), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// route(hops, range, prune, mode, primary, permute, keep_first, keep_last, greedyness, precomp, path, num_workers, callback)
 | ||||
|     /// --
 | ||||
|     ///
 | ||||
|     /// Compute a Route using the suplied parameters
 | ||||
|     #[pyfn(m, "route")] | ||||
|     #[allow(clippy::too_many_arguments)] | ||||
|     fn py_route( | ||||
|         py: Python<'static>, | ||||
|         hops: Vec<&str>, | ||||
|         range: f32, | ||||
|         prune: Option<(usize, f32)>, | ||||
|         mode: String, | ||||
|         primary: bool, | ||||
|         permute: bool, | ||||
|         keep_first: bool, | ||||
|         keep_last: bool, | ||||
|         greedyness: Option<f32>, | ||||
|         precomp: Option<String>, | ||||
|         path: String, | ||||
|         num_workers: Option<usize>, | ||||
|         callback: PyObject, | ||||
|     ) -> PyResult<PyObject> { | ||||
|         use route::*; | ||||
|         let num_workers=num_workers.unwrap_or(1); | ||||
|         let mode = match Mode::parse(&mode) { | ||||
|             Ok(val) => val, | ||||
|             Err(e) => { | ||||
|                 return Err(PyErr::new::<ValueError, _>(e)); | ||||
|             } | ||||
|         }; | ||||
|         let state_dict = PyDict::new(py); | ||||
|         { | ||||
|             let cb_res = callback.call(py, (state_dict,), None); | ||||
|             if cb_res.is_err() { | ||||
|                 println!("Error: {:?}",cb_res); | ||||
|             } | ||||
|         } | ||||
|         let callback_wrapped = move |state: &SearchState| { | ||||
|             state_dict.set_item("mode", state.mode.clone())?; | ||||
|             state_dict.set_item("system", state.system.clone())?; | ||||
|             state_dict.set_item("body", state.body.clone())?; | ||||
|             state_dict.set_item("depth", state.depth)?; | ||||
|             state_dict.set_item("queue_size", state.queue_size)?; | ||||
|             state_dict.set_item("d_rem", state.d_rem)?; | ||||
|             state_dict.set_item("d_total", state.d_total)?; | ||||
|             state_dict.set_item("prc_done", state.prc_done)?; | ||||
|             state_dict.set_item("n_seen", state.n_seen)?; | ||||
|             state_dict.set_item("prc_seen", state.prc_seen)?; | ||||
|             state_dict.set_item("from", state.from.clone())?; | ||||
|             state_dict.set_item("to", state.to.clone())?; | ||||
|             let cb_res=callback.call(py, (state_dict,), None); | ||||
|             if cb_res.is_err() { | ||||
|                 println!("Error: {:?}",cb_res); | ||||
|             } | ||||
|             cb_res | ||||
|         }; | ||||
|         let hops: Vec<SysEntry> = hops.iter().cloned().map(SysEntry::from).collect(); | ||||
|         println!("Resolving systems..."); | ||||
|         let hops: Vec<u32> = match resolve(&hops,&PathBuf::from(&path)) { | ||||
|             Ok(ids) => ids, | ||||
|             Err(err_msg) => { | ||||
|                 return Err(PyErr::new::<ValueError, _>(err_msg)); | ||||
|             } | ||||
|         }; | ||||
|         let opts = RouteOpts { | ||||
|             systems: hops, | ||||
|             range: Some(range), | ||||
|             file_path: PathBuf::from(path), | ||||
|             precomp_file: precomp.map(PathBuf::from), | ||||
|             callback: Box::new(callback_wrapped), | ||||
|             mode, | ||||
|             factor: greedyness, | ||||
|             precompute: false, | ||||
|             permute, | ||||
|             keep_first, | ||||
|             keep_last, | ||||
|             primary, | ||||
|             prune, | ||||
|             workers: num_workers | ||||
|         }; | ||||
|         let none = ().to_object(py); | ||||
|         match route(opts) { | ||||
|             Ok(Some(route)) => { | ||||
|                 let hops = route.iter().map(|hop| { | ||||
|                     let pos = PyList::new(py, hop.pos.iter()); | ||||
|                     let elem = PyDict::new(py); | ||||
|                     elem.set_item("star_type", hop.star_type.clone()).unwrap(); | ||||
|                     elem.set_item("system", hop.system.clone()).unwrap(); | ||||
|                     elem.set_item("body", hop.body.clone()).unwrap(); | ||||
|                     elem.set_item("distance", hop.distance).unwrap(); | ||||
|                     elem.set_item("pos", pos).unwrap(); | ||||
|                     elem | ||||
|                 }); | ||||
|                 let lst = PyList::new(py, hops); | ||||
|                 Ok(lst.to_object(py)) | ||||
|             } | ||||
|             Ok(None) => Ok(none), | ||||
|             Err(e) => Err(PyErr::new::<ValueError, _>(e)), | ||||
|         } | ||||
|     } | ||||
|     Ok(()) | ||||
| } | ||||
| // #![deny(warnings)]
 | ||||
| mod common; | ||||
| mod preprocess; | ||||
| mod route; | ||||
| 
 | ||||
| #[macro_use] | ||||
| extern crate derivative; | ||||
| use crate::common::SystemSerde; | ||||
| use crate::common::{find_matches, SysEntry}; | ||||
| use crate::route::{Router, SearchState}; | ||||
| use pyo3::exceptions::*; | ||||
| use pyo3::prelude::*; | ||||
| use pyo3::types::{PyDict, PyList, PyTuple}; | ||||
| use pyo3::PyObjectProtocol; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| /* | ||||
| 
 | ||||
| pub id: u32, | ||||
| pub star_type: String, | ||||
| pub system: String, | ||||
| pub body: String, | ||||
| pub mult: f32, | ||||
| pub distance: u32, | ||||
| pub x: f32, | ||||
| pub y: f32, | ||||
| pub z: f32, | ||||
| */ | ||||
| 
 | ||||
| impl SystemSerde { | ||||
|     fn fill_dict(&self, dict: &PyDict) -> PyResult<()> { | ||||
|         dict.clear(); | ||||
|         dict.set_item("id", self.id)?; | ||||
|         dict.set_item("star_type", self.star_type.clone())?; | ||||
|         dict.set_item("system", self.system.clone())?; | ||||
|         dict.set_item("body", self.body.clone())?; | ||||
|         dict.set_item("mult", self.mult)?; | ||||
|         dict.set_item("distance", self.distance)?; | ||||
|         dict.set_item("x", self.x)?; | ||||
|         dict.set_item("y", self.y)?; | ||||
|         dict.set_item("z", self.z)?; | ||||
|         return Ok(()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[pyclass(dict)] | ||||
| #[derive(Derivative)] | ||||
| #[derivative(Debug)] | ||||
| #[text_signature = "(callback, workers, /)"] | ||||
| struct PyRouter { | ||||
|     router: Router, | ||||
|     stars_path: String, | ||||
| } | ||||
| 
 | ||||
| #[pymethods] | ||||
| impl PyRouter { | ||||
|     #[new] | ||||
|     #[args(callback = "None")] | ||||
|     fn new(callback: Option<PyObject>, py: Python<'static>) -> PyResult<Self> { | ||||
|         let cb_func = move |state: &SearchState| { | ||||
|             return match callback.as_ref() { | ||||
|                 Some(cb) => cb.call(py, (state.clone(),), None), | ||||
|                 None => Ok(py.None()), | ||||
|             }; | ||||
|         }; | ||||
| 
 | ||||
|         let router = match Router::new(Box::new(cb_func)) { | ||||
|             Ok(router) => router, | ||||
|             Err(err_msg) => { | ||||
|                 return Err(PyErr::new::<ValueError, _>(err_msg)); | ||||
|             } | ||||
|         }; | ||||
|         let ret = PyRouter { | ||||
|             router, | ||||
|             stars_path: String::from(""), | ||||
|         }; | ||||
|         Ok(ret) | ||||
|     } | ||||
| 
 | ||||
|     #[args(filter_func = "None")] | ||||
|     #[text_signature = "(path, /)"] | ||||
|     fn load(&mut self, path: String, py: Python<'static>) -> PyResult<PyObject> { | ||||
|         self.stars_path = path; | ||||
|         return Ok(py.None()); | ||||
|     } | ||||
| 
 | ||||
|     #[args(greedyness = "0.5", num_workers = "0", beam_width = "0")] | ||||
|     #[text_signature = "(hops, range, greedyness, beam_width, num_workers, /)"] | ||||
|     fn route( | ||||
|         &mut self, | ||||
|         hops: &PyList, | ||||
|         range: f32, | ||||
|         greedyness: f32, | ||||
|         beam_width: usize, | ||||
|         num_workers: usize, | ||||
|         py: Python, | ||||
|     ) -> PyResult<PyObject> { | ||||
|         let route_res = self.router.load(&PathBuf::from(self.stars_path.clone())); | ||||
|         if let Err(err_msg) = route_res { | ||||
|             return Err(PyErr::new::<ValueError, _>(err_msg)); | ||||
|         }; | ||||
|         let mut sys_entries: Vec<SysEntry> = Vec::new(); | ||||
|         for hop in hops { | ||||
|             if let Ok(id) = hop.extract() { | ||||
|                 sys_entries.push(SysEntry::ID(id)); | ||||
|             } else { | ||||
|                 sys_entries.push(SysEntry::parse(hop.extract()?)); | ||||
|             } | ||||
|         } | ||||
|         println!("Resolving systems..."); | ||||
|         let ids: Vec<u32> = match resolve(&sys_entries, &self.router.path) { | ||||
|             Ok(ids) => ids, | ||||
|             Err(err_msg) => { | ||||
|                 return Err(PyErr::new::<ValueError, _>(err_msg)); | ||||
|             } | ||||
|         }; | ||||
|         match self | ||||
|             .router | ||||
|             .computer_route(&ids, range, greedyness, beam_width, num_workers) | ||||
|         { | ||||
|             // TODO: return list of dicts (or objects)
 | ||||
|             Ok(route) => Ok(route.len().to_object(py)), | ||||
|             Err(err_msg) => Err(PyErr::new::<RuntimeError, _>(err_msg)), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[args(hops = "*")] | ||||
|     #[text_signature = "(sys_1, sys_2, ..., /)"] | ||||
|     fn resolve_systems(&self, hops: &PyTuple, py: Python) -> PyResult<PyObject> { | ||||
|         let mut sys_entries: Vec<SysEntry> = Vec::new(); | ||||
|         for hop in hops { | ||||
|             if let Ok(id) = hop.extract() { | ||||
|                 sys_entries.push(SysEntry::ID(id)); | ||||
|             } else { | ||||
|                 sys_entries.push(SysEntry::parse(hop.extract()?)); | ||||
|             } | ||||
|         } | ||||
|         println!("Resolving systems..."); | ||||
|         let ids: Vec<u32> = match resolve(&sys_entries, &PathBuf::from(self.stars_path.clone())) { | ||||
|             Ok(ids) => ids, | ||||
|             Err(err_msg) => { | ||||
|                 return Err(PyErr::new::<ValueError, _>(err_msg)); | ||||
|             } | ||||
|         }; | ||||
|         let ret: Vec<(_, u32)> = hops.into_iter().zip(ids.into_iter()).collect(); | ||||
|         Ok(PyDict::from_sequence(py, ret.to_object(py))?.to_object(py)) | ||||
|     } | ||||
| 
 | ||||
|     #[staticmethod] | ||||
|     fn preprocess_edsm() -> PyResult<()> { | ||||
|         unimplemented!() | ||||
|     } | ||||
| 
 | ||||
|     #[staticmethod] | ||||
|     fn preprocess_galaxy() -> PyResult<()> { | ||||
|         unimplemented!() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[pyproto] | ||||
| impl PyObjectProtocol for PyRouter { | ||||
|     fn __str__(&self) -> PyResult<String> { | ||||
|         Ok(format!("{:?}", &self)) | ||||
|     } | ||||
| 
 | ||||
|     fn __repr__(&self) -> PyResult<String> { | ||||
|         Ok(format!("{:?}", &self)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn resolve(entries: &Vec<SysEntry>, path: &PathBuf) -> Result<Vec<u32>, String> { | ||||
|     let mut names: Vec<String> = Vec::new(); | ||||
|     let mut ids: Vec<u32> = Vec::new(); | ||||
|     let mut ret: Vec<u32> = Vec::new(); | ||||
|     for ent in entries { | ||||
|         match ent { | ||||
|             SysEntry::Name(name) => names.push(name.to_owned()), | ||||
|             SysEntry::ID(id) => ids.push(*id), | ||||
|         } | ||||
|     } | ||||
|     if !path.exists() { | ||||
|         return Err(format!( | ||||
|             "Source file \"{:?}\" does not exist!", | ||||
|             path.display() | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     let name_ids = find_matches(path, names, false)?; | ||||
|     for ent in entries { | ||||
|         match ent { | ||||
|             SysEntry::Name(name) => { | ||||
|                 let ent_res = name_ids | ||||
|                     .get(&name.to_owned()) | ||||
|                     .ok_or(format!("System {} not found", name))?; | ||||
|                 let sys = ent_res | ||||
|                     .1 | ||||
|                     .as_ref() | ||||
|                     .ok_or(format!("System {} not found", name))?; | ||||
|                 if ent_res.0 < 0.75 { | ||||
|                     println!( | ||||
|                         "WARNING: {} match to {} with low confidence ({:.2}%)", | ||||
|                         name, | ||||
|                         sys.system, | ||||
|                         ent_res.0 * 100.0 | ||||
|                     ); | ||||
|                 } | ||||
|                 ret.push(sys.id); | ||||
|             } | ||||
|             SysEntry::ID(id) => ret.push(*id), | ||||
|         } | ||||
|     } | ||||
|     return Ok(ret); | ||||
| } | ||||
| 
 | ||||
| #[pymodule] | ||||
| pub fn _ed_lrr(_py: Python, m: &PyModule) -> PyResult<()> { | ||||
|     better_panic::install(); | ||||
| 
 | ||||
|     m.add_class::<PyRouter>()?; | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| 
 | ||||
| /// Preprocess bodies.json and systemsWithCoordinates.json into stars.csv
 | ||||
|     #[pyfn(m, "preprocess")] | ||||
|     #[text_signature = "(infile_systems, infile_bodies, outfile, callback, /)"] | ||||
|     fn ed_lrr_preprocess( | ||||
|         py: Python<'static>, | ||||
|         infile_systems: String, | ||||
|         infile_bodies: String, | ||||
|         outfile: String, | ||||
|         callback: PyObject, | ||||
|     ) -> PyResult<PyObject> { | ||||
|         use preprocess::*; | ||||
|         let state = PyDict::new(py); | ||||
|         let state_dict = PyDict::new(py); | ||||
|         callback.call(py, (state_dict,), None).unwrap(); | ||||
|         let callback_wrapped = move |state: &PreprocessState| { | ||||
|             // println!("SEND: {:?}",state);
 | ||||
|             state_dict.set_item("file", state.file.clone())?; | ||||
|             state_dict.set_item("total", state.total)?; | ||||
|             state_dict.set_item("count", state.count)?; | ||||
|             state_dict.set_item("done", state.done)?; | ||||
|             state_dict.set_item("message", state.message.clone())?; | ||||
|             callback.call(py, (state_dict,), None) | ||||
|         }; | ||||
|         preprocess_files( | ||||
|             &PathBuf::from(infile_bodies), | ||||
|             &PathBuf::from(infile_systems), | ||||
|             &PathBuf::from(outfile), | ||||
|             &callback_wrapped, | ||||
|         ) | ||||
|         .unwrap(); | ||||
|         Ok(state.to_object(py)) | ||||
|     } | ||||
| 
 | ||||
|     /// Find system by name
 | ||||
|     #[pyfn(m, "find_sys")] | ||||
|     #[text_signature = "(sys_names, sys_list_path, /)"] | ||||
|     fn find_sys(py: Python, sys_names: Vec<String>, sys_list: String) -> PyResult<PyObject> { | ||||
|         let path = PathBuf::from(sys_list); | ||||
|         match find_matches(&path, sys_names, false) { | ||||
|             Ok(vals) => { | ||||
|                 let ret = PyDict::new(py); | ||||
|                 for (key, (diff, sys)) in vals { | ||||
|                     let ret_dict = PyDict::new(py); | ||||
|                     if let Some(val) = sys { | ||||
|                         let pos = PyList::new(py, val.pos.iter()); | ||||
|                         ret_dict.set_item("star_type", val.star_type.clone())?; | ||||
|                         ret_dict.set_item("system", val.system.clone())?; | ||||
|                         ret_dict.set_item("body", val.body.clone())?; | ||||
|                         ret_dict.set_item("distance", val.distance)?; | ||||
|                         ret_dict.set_item("pos", pos)?; | ||||
|                         ret_dict.set_item("id", val.id)?; | ||||
|                         ret.set_item(key, (diff, ret_dict).to_object(py))?; | ||||
|                     } | ||||
|                 } | ||||
|                 Ok(ret.to_object(py)) | ||||
|             } | ||||
|             Err(e) => Err(PyErr::new::<ValueError, _>(e)), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Compute a Route using the suplied parameters
 | ||||
|     #[pyfn(m, "route")] | ||||
|     #[text_signature = "(hops, range, mode, primary, permute, keep_first, keep_last, greedyness, precomp, path, num_workers, callback, /)"] | ||||
|     #[allow(clippy::too_many_arguments)] | ||||
|     fn py_route( | ||||
|         py: Python<'static>, | ||||
|         hops: Vec<&str>, | ||||
|         range: f32, | ||||
|         mode: String, | ||||
|         primary: bool, | ||||
|         permute: bool, | ||||
|         keep_first: bool, | ||||
|         keep_last: bool, | ||||
|         greedyness: Option<f32>, | ||||
|         precomp: Option<String>, | ||||
|         path: String, | ||||
|         num_workers: Option<usize>, | ||||
|         callback: PyObject, | ||||
|     ) -> PyResult<PyObject> { | ||||
|         use route::*; | ||||
|         let num_workers = num_workers.unwrap_or(1); | ||||
|         let mode = match Mode::parse(&mode) { | ||||
|             Ok(val) => val, | ||||
|             Err(e) => { | ||||
|                 return Err(PyErr::new::<ValueError, _>(e)); | ||||
|             } | ||||
|         }; | ||||
|         let state_dict = PyDict::new(py); | ||||
|         { | ||||
|             let cb_res = callback.call(py, (state_dict,), None); | ||||
|             if cb_res.is_err() { | ||||
|                 println!("Error: {:?}", cb_res); | ||||
|             } | ||||
|         } | ||||
|         let callback_wrapped = move |state: &SearchState| { | ||||
|             state_dict.set_item("mode", state.mode.clone())?; | ||||
|             state_dict.set_item("system", state.system.clone())?; | ||||
|             state_dict.set_item("body", state.body.clone())?; | ||||
|             state_dict.set_item("depth", state.depth)?; | ||||
|             state_dict.set_item("queue_size", state.queue_size)?; | ||||
|             state_dict.set_item("d_rem", state.d_rem)?; | ||||
|             state_dict.set_item("d_total", state.d_total)?; | ||||
|             state_dict.set_item("prc_done", state.prc_done)?; | ||||
|             state_dict.set_item("n_seen", state.n_seen)?; | ||||
|             state_dict.set_item("prc_seen", state.prc_seen)?; | ||||
|             state_dict.set_item("from", state.from.clone())?; | ||||
|             state_dict.set_item("to", state.to.clone())?; | ||||
|             let cb_res = callback.call(py, (state_dict,), None); | ||||
|             if cb_res.is_err() { | ||||
|                 println!("Error: {:?}", cb_res); | ||||
|             } | ||||
|             cb_res | ||||
|         }; | ||||
|         let hops: Vec<SysEntry> = (hops.iter().map(|v| SysEntry::from_str(&v)).collect::<Result<Vec<SysEntry>,_>>())?; | ||||
|         println!("Resolving systems..."); | ||||
|         let hops: Vec<u32> = match resolve(&hops, &PathBuf::from(&path)) { | ||||
|             Ok(ids) => ids, | ||||
|             Err(err_msg) => { | ||||
|                 return Err(PyErr::new::<ValueError, _>(err_msg)); | ||||
|             } | ||||
|         }; | ||||
|         let opts = RouteOpts { | ||||
|             systems: hops, | ||||
|             range: Some(range), | ||||
|             file_path: PathBuf::from(path), | ||||
|             precomp_file: precomp.map(PathBuf::from), | ||||
|             callback: Box::new(callback_wrapped), | ||||
|             mode, | ||||
|             factor: greedyness, | ||||
|             precompute: false, | ||||
|             permute, | ||||
|             keep_first, | ||||
|             keep_last, | ||||
|             primary, | ||||
|             workers: num_workers, | ||||
|         }; | ||||
|         match route(opts) { | ||||
|             Ok(Some(route)) => { | ||||
|                 let hops = route.iter().map(|hop| { | ||||
|                     let pos = PyList::new(py, hop.pos.iter()); | ||||
|                     let elem = PyDict::new(py); | ||||
|                     elem.set_item("star_type", hop.star_type.clone()).unwrap(); | ||||
|                     elem.set_item("system", hop.system.clone()).unwrap(); | ||||
|                     elem.set_item("body", hop.body.clone()).unwrap(); | ||||
|                     elem.set_item("distance", hop.distance).unwrap(); | ||||
|                     elem.set_item("pos", pos).unwrap(); | ||||
|                     elem | ||||
|                 }); | ||||
|                 let lst = PyList::new(py, hops); | ||||
|                 Ok(lst.to_object(py)) | ||||
|             } | ||||
|             Ok(None) => Ok(py.None()), | ||||
|             Err(e) => Err(PyErr::new::<ValueError, _>(e)), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| */ | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ fn process_systems( | |||
|     ret | ||||
| } | ||||
| 
 | ||||
| fn build_index(path: &PathBuf) -> std::io::Result<()> { | ||||
| pub fn build_index(path: &PathBuf) -> std::io::Result<()> { | ||||
|     let mut wtr = BufWriter::new(File::create(path.with_extension("idx"))?); | ||||
|     let mut idx: Vec<u64> = Vec::new(); | ||||
|     let mut records = (csv::Reader::from_path(path)?).into_deserialize::<SystemSerde>(); | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| use crate::common::{System, SystemSerde, TreeNode}; | ||||
| use core::cmp::Ordering; | ||||
| use crossbeam_channel::{ | ||||
|     bounded, unbounded, Receiver, SendError, Sender, TryIter, | ||||
| }; | ||||
| use crossbeam_channel::{bounded, unbounded, Receiver, SendError, Sender, TryIter}; | ||||
| use derivative::Derivative; | ||||
| use dict_derive::IntoPyObject; | ||||
| use crate::preprocess::build_index; | ||||
| use fnv::{FnvHashMap, FnvHashSet}; | ||||
| use humantime::format_duration; | ||||
| use permutohedron::LexicalPermutation; | ||||
|  | @ -19,9 +20,25 @@ use std::thread; | |||
| use std::thread::JoinHandle; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| const STATUS_INVERVAL: u128 = 500; //ms
 | ||||
| const STATUS_INVERVAL: u128 = 5000; //ms
 | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| struct Weight { | ||||
|     // TODO: implement
 | ||||
|     star_type: FnvHashMap<String, f32>, | ||||
|     dist_from_start: f32, | ||||
|     dist_to_goal: f32, | ||||
|     dist_to_point: Vec<(f32, [f32; 3])>, | ||||
| } | ||||
| 
 | ||||
| impl Weight { | ||||
|     fn calc(&self, node: &TreeNode, dst: &TreeNode, src: &TreeNode) -> f32 { | ||||
|         let d_start = dist(&node.pos, &src.pos); | ||||
|         let d_goal = dist(&node.pos, &dst.pos); | ||||
|         return 0.0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, IntoPyObject)] | ||||
| pub struct SearchState { | ||||
|     pub mode: String, | ||||
|     pub system: String, | ||||
|  | @ -48,7 +65,6 @@ pub struct RouteOpts { | |||
|     pub keep_last: bool, | ||||
|     pub factor: Option<f32>, | ||||
|     pub mode: Mode, | ||||
|     pub prune: Option<(usize, f32)>, | ||||
|     pub systems: Vec<u32>, | ||||
|     pub callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, | ||||
|     pub workers: usize, | ||||
|  | @ -58,9 +74,20 @@ pub struct RouteOpts { | |||
| #[allow(non_camel_case_types)] | ||||
| pub enum Mode { | ||||
|     BFS, | ||||
|     BFS_old, | ||||
|     BiDir, // TODO: implement bidirectional BFS
 | ||||
|     Greedy, | ||||
|     AStar, | ||||
|     Shortest, // TODO: A-Star with distance as weight
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| #[allow(non_camel_case_types)] | ||||
| pub enum PrecomputeMode { | ||||
|     Full, | ||||
|     Route_From, | ||||
|     Route_To, | ||||
|     None | ||||
| } | ||||
| 
 | ||||
| impl Mode { | ||||
|  | @ -68,9 +95,9 @@ impl Mode { | |||
|         let s = s.to_lowercase(); | ||||
|         match s.as_ref() { | ||||
|             "bfs" => Ok(Mode::BFS), | ||||
|             "bfs_old" => Ok(Mode::BFS_old), | ||||
|             "greedy" => Ok(Mode::Greedy), | ||||
|             "astar" => Ok(Mode::AStar), | ||||
|             "bidir" => Ok(Mode::BiDir), | ||||
|             val => Err(format!("Invalid Mode: {}", val)), | ||||
|         } | ||||
|     } | ||||
|  | @ -162,9 +189,25 @@ pub struct LineCache { | |||
| 
 | ||||
| impl LineCache { | ||||
|     pub fn new(path: &PathBuf) -> Option<Arc<Mutex<Self>>> { | ||||
|         //TODO: Verify match between index file and csv file
 | ||||
|         let idx_path = path.with_extension("idx"); | ||||
|         let cache = | ||||
|             bincode::deserialize_from(&mut BufReader::new(File::open(idx_path).ok()?)).ok()?; | ||||
|         if !idx_path.exists() { | ||||
|             eprintln!("No index found for {:?}, building...", path); | ||||
|             build_index(path).map_err(|e| { | ||||
|                 eprintln!("Error creating index for {:?}: {}", path, e); | ||||
|             }).ok()?; | ||||
|         } | ||||
|         let cache = bincode::deserialize_from(&mut BufReader::new( | ||||
|             File::open(idx_path) | ||||
|                 .map_err(|e| { | ||||
|                     eprintln!("Error opening index for {:?}: {}", path, e); | ||||
|                 }) | ||||
|                 .ok()?, | ||||
|         )) | ||||
|         .map_err(|e| { | ||||
|             eprintln!("Reading index for {:?}: {}", path, e); | ||||
|         }) | ||||
|         .ok()?; | ||||
|         let reader = csv::Reader::from_path(path).ok()?; | ||||
|         let ret = Self { reader, cache }; | ||||
|         Some(Arc::new(Mutex::new(ret))) | ||||
|  | @ -206,6 +249,7 @@ struct WorkUnit { | |||
|     node: TreeNode, | ||||
|     depth: usize, | ||||
|     parent_id: Option<u32>, | ||||
|     range: f32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
|  | @ -218,30 +262,8 @@ enum WorkerSet { | |||
|     }, | ||||
| } | ||||
| 
 | ||||
| fn neighbor_worker( | ||||
|     tree: &LargeNodeRTree<TreeNode>, | ||||
|     search_range: f32, | ||||
|     rx: Receiver<Option<WorkUnit>>, | ||||
|     tx: Sender<WorkUnit>, | ||||
| ) { | ||||
|     while let Ok(Some(unit)) = rx.recv() { | ||||
|         let range=search_range*unit.node.mult; | ||||
|         tree.locate_within_distance(unit.node.pos, range*range) | ||||
|             .cloned() | ||||
|             .for_each(|nb| { | ||||
|                 let wu = WorkUnit { | ||||
|                     node: nb, | ||||
|                     depth: unit.depth + 1, | ||||
|                     parent_id: Some(unit.node.id), | ||||
|                 }; | ||||
|                 tx.send(wu).unwrap(); | ||||
|             }); | ||||
|     } | ||||
|     drop(tx); | ||||
| } | ||||
| 
 | ||||
| impl WorkerSet { | ||||
|     fn new(tree: Arc<LargeNodeRTree<TreeNode>>, search_range: f32, num_workers: usize) -> Self { | ||||
|     fn new(tree: Arc<LargeNodeRTree<TreeNode>>, num_workers: usize) -> Self { | ||||
|         if num_workers == 0 { | ||||
|             return WorkerSet::Empty; | ||||
|         } | ||||
|  | @ -254,7 +276,7 @@ impl WorkerSet { | |||
|                     let tx = result_tx.clone(); | ||||
|                     let tree = tree.clone(); | ||||
|                     move || { | ||||
|                         neighbor_worker(&tree, search_range, rx, tx); | ||||
|                         Self::work(&tree, rx, tx); | ||||
|                     } | ||||
|                 }) | ||||
|             }) | ||||
|  | @ -266,29 +288,62 @@ impl WorkerSet { | |||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     fn close(self) -> Result<(),String> { | ||||
|         if let WorkerSet::Workers{mut handles,tx,rx} = self { | ||||
|             let t_start=Instant::now(); | ||||
|     fn work(tree: &LargeNodeRTree<TreeNode>, rx: Receiver<Option<WorkUnit>>, tx: Sender<WorkUnit>) { | ||||
|         while let Ok(Some(unit)) = rx.recv() { | ||||
|             let range = unit.range * unit.node.mult; | ||||
|             tree.locate_within_distance(unit.node.pos, range * range) | ||||
|                 .cloned() | ||||
|                 .for_each(|nb| { | ||||
|                     let wu = WorkUnit { | ||||
|                         node: nb, | ||||
|                         depth: unit.depth + 1, | ||||
|                         parent_id: Some(unit.node.id), | ||||
|                         range: unit.range, | ||||
|                     }; | ||||
|                     tx.send(wu).unwrap(); | ||||
|                 }); | ||||
|         } | ||||
|         drop(tx); | ||||
|     } | ||||
| 
 | ||||
|     fn resize(self, tree: Arc<LargeNodeRTree<TreeNode>>, num: usize) -> Result<Self, String> { | ||||
|         self.close()?; | ||||
|         return Ok(WorkerSet::new(tree.clone(), num)); | ||||
|     } | ||||
| 
 | ||||
|     // fn replace(self, tree: Arc<LargeNodeRTree<TreeNode>>) -> Result<Self, String> {
 | ||||
|     //     let num=self.num();
 | ||||
|     //     return self.resize(tree.clone(),num);
 | ||||
|     // }
 | ||||
| 
 | ||||
|     fn close(self) -> Result<(), String> { | ||||
|         if let WorkerSet::Workers { | ||||
|             mut handles, | ||||
|             tx, | ||||
|             rx, | ||||
|         } = self | ||||
|         { | ||||
|             let t_start = Instant::now(); | ||||
|             loop { | ||||
|                 if (rx.len()==0) && (tx.len()==0) { | ||||
|                 if (rx.len() == 0) && (tx.len() == 0) { | ||||
|                     break; | ||||
|                 } | ||||
|                 rx.try_iter().for_each(|_| {}); | ||||
|             }; | ||||
|             } | ||||
|             for _ in &handles { | ||||
|                 match tx.send(None) { | ||||
|                     Ok(_) => {}, | ||||
|                     Ok(_) => {} | ||||
|                     Err(e) => { | ||||
|                         return Err(format!("{:?}",e)); | ||||
|                         return Err(format!("{:?}", e)); | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|             } | ||||
|             drop(tx); | ||||
|             while let Some(handle)= handles.pop() { | ||||
|             while let Some(handle) = handles.pop() { | ||||
|                 handle.join().unwrap(); | ||||
|             } | ||||
|             drop(rx); | ||||
|             println!("cleared in {}",format_duration(t_start.elapsed())); | ||||
|             println!("cleared in {}", format_duration(t_start.elapsed())); | ||||
|         } | ||||
|         return Ok(()); | ||||
|     } | ||||
|  | @ -296,12 +351,12 @@ impl WorkerSet { | |||
|     fn queue_size(&self) -> usize { | ||||
|         match self { | ||||
|             WorkerSet::Empty => 0, | ||||
|             WorkerSet::Workers{rx,tx,..} => tx.len() + rx.len() | ||||
|             WorkerSet::Workers { rx, tx, .. } => tx.len() + rx.len(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn queue_empty(&self) -> bool { | ||||
|         return self.queue_size()==0; | ||||
|         return self.queue_size() == 0; | ||||
|     } | ||||
| 
 | ||||
|     fn send(&self, wu: WorkUnit) -> Result<(), SendError<Option<WorkUnit>>> { | ||||
|  | @ -331,14 +386,10 @@ impl WorkerSet { | |||
| 
 | ||||
|     // impl Iterator<Item = &TreeNode>
 | ||||
| 
 | ||||
|     fn iter(&self) -> Result<TryIter<WorkUnit>,String> { | ||||
|     fn iter(&self) -> Result<TryIter<WorkUnit>, String> { | ||||
|         match self { | ||||
|             WorkerSet::Empty => { | ||||
|                 Err("can't iterate on empty WorkerSet".to_string()) | ||||
|             } | ||||
|             WorkerSet::Workers { rx, .. } => { | ||||
|                 Ok(rx.try_iter()) | ||||
|             } | ||||
|             WorkerSet::Empty => Err("can't iterate on empty WorkerSet".to_string()), | ||||
|             WorkerSet::Workers { rx, .. } => Ok(rx.try_iter()), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -351,28 +402,43 @@ impl WorkerSet { | |||
|     // }
 | ||||
| } | ||||
| 
 | ||||
| #[derive(Derivative)] | ||||
| #[derivative(Debug)] | ||||
| pub struct Router { | ||||
|     #[derivative(Debug = "ignore")] | ||||
|     tree: Arc<LargeNodeRTree<TreeNode>>, | ||||
|     #[derivative(Debug = "ignore")] | ||||
|     scoopable: FnvHashSet<u32>, | ||||
|     #[derivative(Debug = "ignore")] | ||||
|     pub route_tree: Option<FnvHashMap<u32, u32>>, | ||||
|     #[derivative(Debug = "ignore")] | ||||
|     pub cache: Option<Arc<Mutex<LineCache>>>, | ||||
|     range: f32, | ||||
|     primary_only: bool, | ||||
|     path: PathBuf, | ||||
|     prune: Option<(usize, f32)>, | ||||
|     pub path: PathBuf, | ||||
|     #[derivative(Debug = "ignore")] | ||||
|     workers: WorkerSet, | ||||
|     callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, | ||||
|     #[derivative(Debug = "ignore")] | ||||
|     pub callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, | ||||
| } | ||||
| 
 | ||||
| impl Router { | ||||
|     pub fn new( | ||||
|         path: &PathBuf, | ||||
|         range: f32, | ||||
|         prune: Option<(usize, f32)>, | ||||
|         primary_only: bool, | ||||
|         num_workers: usize, | ||||
|         callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, | ||||
|     ) -> Result<Self, String> { | ||||
|     pub fn new(callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>) -> Result<Self, String> { | ||||
|         let ret = Self { | ||||
|             tree: Arc::new(LargeNodeRTree::default()), | ||||
|             scoopable: FnvHashSet::default(), | ||||
|             route_tree: None, | ||||
|             cache: None, | ||||
|             callback, | ||||
|             workers: WorkerSet::Empty, | ||||
|             path: PathBuf::from(""), | ||||
|         }; | ||||
|         Ok(ret) | ||||
|     } | ||||
| 
 | ||||
|     pub fn load(&mut self, path: &PathBuf) -> Result<(), String> { | ||||
|         if self.path == path.to_path_buf() { | ||||
|             return Ok(()); | ||||
|         } | ||||
|         self.tree = Arc::new(LargeNodeRTree::default()); // clear R*-Tree
 | ||||
|         let mut scoopable = FnvHashSet::default(); | ||||
|         let mut reader = match csv::ReaderBuilder::new().from_path(path) { | ||||
|             Ok(rdr) => rdr, | ||||
|  | @ -386,9 +452,9 @@ impl Router { | |||
|             .deserialize::<SystemSerde>() | ||||
|             .filter_map(|res| { | ||||
|                 let sys = res.expect("Failed to read"); | ||||
|                 if primary_only && sys.distance != 0 { | ||||
|                 if sys.distance != 0 { | ||||
|                     return None; | ||||
|                 }; | ||||
|                 } | ||||
|                 if sys.mult > 1.0f32 { | ||||
|                     scoopable.insert(sys.id); | ||||
|                 } else { | ||||
|  | @ -408,37 +474,28 @@ impl Router { | |||
|             format_duration(t_load.elapsed()) | ||||
|         ); | ||||
|         let t_load = Instant::now(); | ||||
|         let tree = Arc::new(LargeNodeRTree::bulk_load_with_params(systems)); | ||||
|         let workers = WorkerSet::new(Arc::clone(&tree), range, num_workers); | ||||
|         self.tree = Arc::new(LargeNodeRTree::bulk_load_with_params(systems)); | ||||
|         self.path = path.to_path_buf(); | ||||
|         self.cache = LineCache::new(&path.to_path_buf()); | ||||
|         self.scoopable = scoopable; | ||||
|         println!("R*-Tree built in {}", format_duration(t_load.elapsed())); | ||||
|         let ret = Self { | ||||
|             tree, | ||||
|             scoopable, | ||||
|             route_tree: None, | ||||
|             range, | ||||
|             primary_only, | ||||
|             cache: LineCache::new(path), | ||||
|             path: path.clone(), | ||||
|             callback, | ||||
|             prune, | ||||
|             workers, | ||||
|         }; | ||||
|         Ok(ret) | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn start_workers(&mut self, num: usize) -> Result<(), String> { | ||||
|         let mut w = WorkerSet::Empty; | ||||
|         std::mem::swap(&mut self.workers, &mut w); | ||||
|         self.workers = w.resize(self.tree.clone(), num)?; | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn from_file( | ||||
|         filename: &PathBuf, | ||||
|         callback: Box<dyn Fn(&SearchState) -> PyResult<PyObject>>, | ||||
|     ) -> Result<(PathBuf, Self), String> { | ||||
|     ) -> Result<(PathBuf, f32, Self), String> { | ||||
|         let mut reader = BufReader::new(match File::open(&filename) { | ||||
|             Ok(fh) => fh, | ||||
|             Err(e) => { | ||||
|                 return Err(format!( | ||||
|                     "Error opening file {}: {}", | ||||
|                     filename.display(), | ||||
|                     e | ||||
|                 )) | ||||
|             } | ||||
|             Err(e) => return Err(format!("Error opening file {}: {}", filename.display(), e)), | ||||
|         }); | ||||
|         println!("Loading {}", filename.display()); | ||||
|         let (primary, range, file_hash, path, route_tree): ( | ||||
|  | @ -449,13 +506,7 @@ impl Router { | |||
|             FnvHashMap<u32, u32>, | ||||
|         ) = match bincode::deserialize_from(&mut reader) { | ||||
|             Ok(res) => res, | ||||
|             Err(e) => { | ||||
|                 return Err(format!( | ||||
|                     "Error loading file {}: {}", | ||||
|                     filename.display(), | ||||
|                     e | ||||
|                 )) | ||||
|             } | ||||
|             Err(e) => return Err(format!("Error loading file {}: {}", filename.display(), e)), | ||||
|         }; | ||||
|         if hash_file(&path) != file_hash { | ||||
|             return Err("File hash mismatch!".to_string()); | ||||
|  | @ -463,16 +514,14 @@ impl Router { | |||
|         let cache = LineCache::new(&path); | ||||
|         Ok(( | ||||
|             path.clone(), | ||||
|             range, | ||||
|             Self { | ||||
|                 tree: Arc::new(RTree::default()), | ||||
|                 scoopable: FnvHashSet::default(), | ||||
|                 route_tree: Some(route_tree), | ||||
|                 range, | ||||
|                 cache, | ||||
|                 primary_only: primary, | ||||
|                 path, | ||||
|                 callback, | ||||
|                 prune: None, | ||||
|                 workers: WorkerSet::Empty, | ||||
|             }, | ||||
|         )) | ||||
|  | @ -482,8 +531,16 @@ impl Router { | |||
|         self.tree.locate_within_distance(*center, radius * radius) | ||||
|     } | ||||
| 
 | ||||
|     fn neighbours(&self, node: &TreeNode) -> impl Iterator<Item = &TreeNode> { | ||||
|         self.points_in_sphere(&node.pos, node.mult * self.range) | ||||
|     fn neighbours(&self, node: &TreeNode, range: f32) -> impl Iterator<Item = &TreeNode> { | ||||
|         self.points_in_sphere(&node.pos, node.mult * range) | ||||
|     } | ||||
| 
 | ||||
|     fn neighbours_r(&self, node: &TreeNode, range: f32) -> impl Iterator<Item = &TreeNode> { | ||||
|         let pos = node.pos.clone(); | ||||
|         self.points_in_sphere(&node.pos, range * 4.0) | ||||
|             .filter(move |s| { | ||||
|                 return s.dist2(&pos) < (range * s.mult) * (range * s.mult); | ||||
|             }) | ||||
|     } | ||||
| 
 | ||||
|     fn valid(&self, id: u32) -> bool { | ||||
|  | @ -492,11 +549,13 @@ impl Router { | |||
|     } | ||||
| 
 | ||||
|     pub fn best_multiroute( | ||||
|         &self, | ||||
|         &mut self, | ||||
|         waypoints: &[System], | ||||
|         range: f32, | ||||
|         keep: (bool, bool), | ||||
|         mode: Mode, | ||||
|         factor: f32, | ||||
|         beam_width: usize, | ||||
|         num_workers: usize, | ||||
|     ) -> Result<Vec<System>, String> { | ||||
|         let mut best_score: f32 = std::f32::MAX; | ||||
|         let mut waypoints = waypoints.to_owned(); | ||||
|  | @ -529,16 +588,33 @@ impl Router { | |||
|             } | ||||
|         } | ||||
|         println!("Best permutation: {:?}", best_permutation_waypoints); | ||||
|         self.multiroute(&best_permutation_waypoints, mode, factor) | ||||
|         self.multiroute( | ||||
|             &best_permutation_waypoints, | ||||
|             range, | ||||
|             factor, | ||||
|             beam_width, | ||||
|             num_workers, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     pub fn multiroute( | ||||
|         &self, | ||||
|         &mut self, | ||||
|         waypoints: &[System], | ||||
|         mode: Mode, | ||||
|         range: f32, | ||||
|         factor: f32, | ||||
|         beam_width: usize, | ||||
|         num_workers: usize, | ||||
|     ) -> Result<Vec<System>, String> { | ||||
|         if self.tree.size() == 0 { | ||||
|             return Err("No Systems loaded, pleased load some with the 'load' method!".to_string()); | ||||
|         } | ||||
|         if factor < 0.0 || factor > 1.0 { | ||||
|             return Err("Factor needs to be between 0.0 (BFS) and 1.0 (Greedy Search)".to_string()); | ||||
|         } | ||||
|         let mut route: Vec<System> = Vec::new(); | ||||
|         if factor == 0.0 { | ||||
|             self.start_workers(num_workers)?; | ||||
|         } | ||||
|         for pair in waypoints.windows(2) { | ||||
|             match pair { | ||||
|                 [src, dst] => { | ||||
|  | @ -549,16 +625,11 @@ impl Router { | |||
|                     ); | ||||
|                     println!( | ||||
|                         "Jump Range: {} Ly, Distance: {} Ly, Estimated Jumps: {}", | ||||
|                         self.range, | ||||
|                         range, | ||||
|                         d_total, | ||||
|                         d_total / self.range | ||||
|                         d_total / range | ||||
|                     ); | ||||
|                     let block = match mode { | ||||
|                         Mode::BFS => self.route_bfs(&src, &dst)?, | ||||
|                         Mode::BFS_old => self.route_bfs_old(&src, &dst)?, | ||||
|                         Mode::Greedy => self.route_greedy(&src, &dst)?, | ||||
|                         Mode::AStar => self.route_astar(&src, &dst, factor)?, | ||||
|                     }; | ||||
|                     let block = self.route_astar(&src, &dst, factor, beam_width, range)?; | ||||
|                     if route.is_empty() { | ||||
|                         for sys in block.iter() { | ||||
|                             route.push(sys.clone()); | ||||
|  | @ -582,9 +653,14 @@ impl Router { | |||
|         src: &System, | ||||
|         dst: &System, | ||||
|         factor: f32, | ||||
|         beam_width: usize, | ||||
|         range: f32, | ||||
|     ) -> Result<Vec<System>, String> { | ||||
|         if factor == 0.0 { | ||||
|             return self.route_bfs(src, dst); | ||||
|             return self.route_bfs(src, dst, range, beam_width); | ||||
|         } | ||||
|         if factor == 1.0 { | ||||
|             return self.route_greedy(src, dst, range, beam_width); | ||||
|         } | ||||
|         let src_name = src.system.clone(); | ||||
|         let dst_name = dst.system.clone(); | ||||
|  | @ -614,8 +690,8 @@ impl Router { | |||
|         let mut found = false; | ||||
|         let mut queue: Vec<(usize, usize, TreeNode)> = Vec::new(); | ||||
|         queue.push(( | ||||
|             0,                                                 // depth
 | ||||
|             (start_sys.distp(goal_sys) / self.range) as usize, // h
 | ||||
|             0,                                            // depth
 | ||||
|             (start_sys.distp(goal_sys) / range) as usize, // h
 | ||||
|             start_sys.to_node(), | ||||
|         )); | ||||
|         seen.insert(start_sys.id); | ||||
|  | @ -647,7 +723,7 @@ impl Router { | |||
|                     break; | ||||
|                 } | ||||
|                 queue.extend( | ||||
|                     self.neighbours(&node) | ||||
|                     self.neighbours(&node, range) | ||||
|                         .filter(|nb| (self.valid(nb.id) || (nb.id == goal_sys.id))) | ||||
|                         .filter(|nb| seen.insert(nb.id)) | ||||
|                         .map(|nb| { | ||||
|  | @ -656,14 +732,14 @@ impl Router { | |||
|                             if d_g < d_rem { | ||||
|                                 d_rem = d_g; | ||||
|                             } | ||||
|                             (depth + 1, (d_g / self.range) as usize, *nb) | ||||
|                             (depth + 1, (d_g / (range * 4.0)) as usize, *nb) | ||||
|                         }), | ||||
|                 ); | ||||
|                 queue.sort_by(|b, a| { | ||||
|                     let (a_0, a_1) = (a.0 as f32, a.1 as f32); | ||||
|                     let (b_0, b_1) = (b.0 as f32, b.1 as f32); | ||||
|                     let v_a = a_0 + a_1 * factor; | ||||
|                     let v_b = b_0 + b_1 * factor; | ||||
|                     let v_a = a_0 * (1.0 - factor) + a_1 * factor; | ||||
|                     let v_b = b_0 * (1.0 - factor) + b_1 * factor; | ||||
|                     fcmp(v_a, v_b) | ||||
|                 }); | ||||
|                 // queue.reverse();
 | ||||
|  | @ -693,7 +769,13 @@ impl Router { | |||
|         Ok(v) | ||||
|     } | ||||
| 
 | ||||
|     pub fn route_greedy(&self, src: &System, dst: &System) -> Result<Vec<System>, String> { | ||||
|     pub fn route_greedy( | ||||
|         &self, | ||||
|         src: &System, | ||||
|         dst: &System, | ||||
|         range: f32, | ||||
|         beam_width: usize, | ||||
|     ) -> Result<Vec<System>, String> { | ||||
|         let src_name = src.system.clone(); | ||||
|         let dst_name = dst.system.clone(); | ||||
|         let start_sys = src; | ||||
|  | @ -750,7 +832,7 @@ impl Router { | |||
|                     break; | ||||
|                 } | ||||
|                 queue.extend( | ||||
|                     self.neighbours(&node) | ||||
|                     self.neighbours(&node, range) | ||||
|                         .filter(|nb| (self.valid(nb.id) || (nb.id == goal_sys.id))) | ||||
|                         .filter(|nb| seen.insert(nb.id)) | ||||
|                         .map(|nb| { | ||||
|  | @ -762,8 +844,7 @@ impl Router { | |||
|                             (d_g, depth + 1, nb.clone()) | ||||
|                         }), | ||||
|                 ); | ||||
|                 queue.sort_by(|a, b| fcmp(a.0, b.0).then(a.1.cmp(&b.1))); | ||||
|                 queue.reverse(); | ||||
|                 queue.sort_by(|a, b| fcmp(b.0, a.0).then(b.1.cmp(&a.1))); | ||||
|             } | ||||
|             if queue.is_empty() { | ||||
|                 break; | ||||
|  | @ -787,7 +868,18 @@ impl Router { | |||
|         Ok(v) | ||||
|     } | ||||
| 
 | ||||
|     pub fn precompute(&mut self, src: &System) -> Result<(), String> { | ||||
|     pub fn precompute_all(&mut self, range:f32) -> Result<(),String> { | ||||
|         // TODO: implement all-pairs shortest path based on optimized BFS
 | ||||
|         unimplemented!(); | ||||
|     } | ||||
| 
 | ||||
|     pub fn precompute_to(&mut self, dst: &System, range: f32) -> Result<(), String> { | ||||
|         // TODO: -> precompute to
 | ||||
|         unimplemented!(); | ||||
|     } | ||||
| 
 | ||||
|     pub fn precompute(&mut self, src: &System, range: f32) -> Result<(), String> { | ||||
|         // TODO: -> precompute from
 | ||||
|         let total = self.tree.size() as f32; | ||||
|         let t_start = Instant::now(); | ||||
|         let mut prev = FnvHashMap::default(); | ||||
|  | @ -809,7 +901,7 @@ impl Router { | |||
|             std::io::stdout().flush().unwrap(); | ||||
|             while let Some((d, sys)) = queue.pop_front() { | ||||
|                 queue_next.extend( | ||||
|                     self.neighbours(&sys) | ||||
|                     self.neighbours(&sys, range) | ||||
|                         // .filter(|&nb| self.valid(nb))
 | ||||
|                         .filter(|&nb| seen.insert(nb.id)) | ||||
|                         .map(|nb| { | ||||
|  | @ -822,17 +914,23 @@ impl Router { | |||
|             depth += 1; | ||||
|         } | ||||
|         self.route_tree = Some(prev); | ||||
|         let file_hash = hash_file(&self.path); | ||||
|         let file_hash_hex = file_hash | ||||
|             .iter() | ||||
|             .map(|v| format!("{:02x}", v)) | ||||
|             .collect::<Vec<String>>() | ||||
|             .join(""); | ||||
|         let ofn = format!( | ||||
|             "{}_{}{}.router", | ||||
|             "{}_{}_{}.router", | ||||
|             src.system.replace("*", "").replace(" ", "_"), | ||||
|             self.range, | ||||
|             if self.primary_only { "_primary" } else { "" } | ||||
|             range, | ||||
|             file_hash_hex | ||||
|         ); | ||||
|         let mut out_fh = BufWriter::new(File::create(&ofn).unwrap()); | ||||
|         let data = ( | ||||
|             self.primary_only, | ||||
|             self.range, | ||||
|             hash_file(&self.path), | ||||
|             self.tree.size(), | ||||
|             range, | ||||
|             file_hash, | ||||
|             self.path.clone(), | ||||
|             self.route_tree.as_ref().unwrap(), | ||||
|         ); | ||||
|  | @ -913,6 +1011,9 @@ impl Router { | |||
|     } | ||||
| 
 | ||||
|     pub fn route_to(&self, dst: &System) -> Result<Vec<System>, String> { | ||||
|         if self.route_tree.is_none() { | ||||
|             return Err("Can't computer route without a precomputed route-tree".to_owned()); | ||||
|         } | ||||
|         let prev = self.route_tree.as_ref().unwrap(); | ||||
|         if !prev.contains_key(&dst.id) { | ||||
|             return Err(format!("System-ID {} not found", dst.id).to_string()); | ||||
|  | @ -943,9 +1044,15 @@ impl Router { | |||
|         Ok(v) | ||||
|     } | ||||
| 
 | ||||
|     pub fn route_bfs(&self, start_sys: &System, goal_sys: &System) -> Result<Vec<System>, String> { | ||||
|     pub fn route_bfs( | ||||
|         &self, | ||||
|         start_sys: &System, | ||||
|         goal_sys: &System, | ||||
|         range: f32, | ||||
|         beam_width: usize, | ||||
|     ) -> Result<Vec<System>, String> { | ||||
|         if self.workers.is_empty() { | ||||
|             return self.route_bfs_old(start_sys, goal_sys); | ||||
|             return self.route_bfs_serial(start_sys, goal_sys, range, beam_width); | ||||
|         } | ||||
|         println!("Running BFS with {} worker(s)", self.workers.num()); | ||||
|         let t_start = Instant::now(); | ||||
|  | @ -959,8 +1066,9 @@ impl Router { | |||
|             node: start_sys.to_node(), | ||||
|             parent_id: None, | ||||
|             depth: 0, | ||||
|             range, | ||||
|         }; | ||||
|         if wu.node.id==goal_sys.id { | ||||
|         if wu.node.id == goal_sys.id { | ||||
|             return Ok(vec![goal_sys.clone()]); | ||||
|         } | ||||
|         let mut found = false; | ||||
|  | @ -968,7 +1076,7 @@ impl Router { | |||
|         let d_total = dist(&start_sys.pos, &goal_sys.pos); | ||||
|         let mut d_rem = d_total; | ||||
|         let mut state = SearchState { | ||||
|             mode: "BFS".into(), | ||||
|             mode: format!("BFS_parallel({})", self.workers.num()), | ||||
|             depth: 0, | ||||
|             queue_size: 0, | ||||
|             d_rem, | ||||
|  | @ -1019,14 +1127,18 @@ impl Router { | |||
|                     } | ||||
|                 }) | ||||
|                 .collect(); | ||||
|             if nbs.is_empty() && workers.queue_empty() && seen.len()>1 { | ||||
|             if nbs.is_empty() && workers.queue_empty() && seen.len() > 1 { | ||||
|                 break; | ||||
|             } | ||||
|             // nbs.sort_by(|a, b| {
 | ||||
|             //     let d_a=a.node.dist2(&goal_sys.pos);
 | ||||
|             //     let d_b=b.node.dist2(&goal_sys.pos);
 | ||||
|             //     return a.depth.cmp(&b.depth).then(fcmp(d_a,d_b));
 | ||||
|             // });
 | ||||
|             if beam_width != 0 && nbs.len() > beam_width { | ||||
|                 nbs.sort_by(|a, b| { | ||||
|                     let d_a = a.node.dist2(&goal_sys.pos); | ||||
|                     let d_b = b.node.dist2(&goal_sys.pos); | ||||
|                     return fcmp(d_a, d_b); | ||||
|                 }); | ||||
|                 nbs = nbs.iter().take(beam_width).cloned().collect(); | ||||
|             } | ||||
| 
 | ||||
|             while let Some(wu) = nbs.pop() { | ||||
|                 if let Some(parent_id) = wu.parent_id { | ||||
|                     prev.insert(wu.node.id, parent_id); | ||||
|  | @ -1065,25 +1177,24 @@ impl Router { | |||
|         Ok(v) | ||||
|     } | ||||
| 
 | ||||
|     pub fn route_bfs_old( | ||||
|     pub fn route_bfs_serial( | ||||
|         &self, | ||||
|         start_sys: &System, | ||||
|         goal_sys: &System, | ||||
|         range: f32, | ||||
|         beam_width: usize, | ||||
|     ) -> Result<Vec<System>, String> { | ||||
|         if start_sys.id==goal_sys.id { | ||||
|         if start_sys.id == goal_sys.id { | ||||
|             return Ok(vec![goal_sys.clone()]); | ||||
|         } | ||||
|         let t_start = Instant::now(); | ||||
|         println!("Running BFS"); | ||||
|         if self.prune.is_some() { | ||||
|             println!("WARNING: search pruning is not implemented!"); | ||||
|         } | ||||
|         let src_name = start_sys.system.clone(); | ||||
|         let dst_name = goal_sys.system.clone(); | ||||
|         let d_total = dist(&start_sys.pos, &goal_sys.pos); | ||||
|         let mut d_rem = d_total; | ||||
|         let mut state = SearchState { | ||||
|             mode: "BFS_old".into(), | ||||
|             mode: "BFS_serial".into(), | ||||
|             depth: 0, | ||||
|             queue_size: 0, | ||||
|             d_rem, | ||||
|  | @ -1120,7 +1231,7 @@ impl Router { | |||
|                     state.d_rem = d_rem; | ||||
|                     state.n_seen = seen.len(); | ||||
|                     state.prc_seen = ((seen.len() * 100) as f32) / total; | ||||
|                     { | ||||
|                     if !queue.is_empty() { | ||||
|                         let s = queue.get(0).unwrap().get(&self).unwrap(); | ||||
|                         state.system = s.system.clone(); | ||||
|                         state.body = s.body.clone(); | ||||
|  | @ -1134,7 +1245,7 @@ impl Router { | |||
|                     t_last = Instant::now(); | ||||
|                 } | ||||
|                 let valid_nbs = self | ||||
|                     .neighbours(&node) | ||||
|                     .neighbours(&node, range) | ||||
|                     .filter(|nb| (self.valid(nb.id) || (nb.id == goal_sys.id))) | ||||
|                     .filter(|nb| seen.insert(nb.id)) | ||||
|                     .map(|nb| { | ||||
|  | @ -1147,7 +1258,25 @@ impl Router { | |||
|                     }); | ||||
|                 queue_next.extend(valid_nbs); | ||||
|             } | ||||
|             std::mem::swap(&mut queue, &mut queue_next); | ||||
| 
 | ||||
|             if beam_width != 0 { | ||||
|                 let mut q = Vec::new(); | ||||
|                 while let Some(v) = queue_next.pop_front() { | ||||
|                     q.push(v); | ||||
|                 } | ||||
|                 q.sort_by(|a, b| { | ||||
|                     let d_a = a.dist2(&goal_sys.pos); | ||||
|                     let d_b = b.dist2(&goal_sys.pos); | ||||
|                     return fcmp(d_a, d_b); | ||||
|                 }); | ||||
|                 queue.clear(); | ||||
|                 for v in q.iter().take(beam_width).cloned() { | ||||
|                     queue.push_back(v); | ||||
|                 } | ||||
|                 queue_next.clear(); | ||||
|             } else { | ||||
|                 std::mem::swap(&mut queue, &mut queue_next); | ||||
|             } | ||||
|             if found { | ||||
|                 break; | ||||
|             } | ||||
|  | @ -1179,67 +1308,21 @@ impl Router { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn route(opts: RouteOpts) -> Result<Option<Vec<System>>, String> { | ||||
|     // TODO: implement pruning (check if dist to target improved by at least $n*jump_range$ Ly in the last $m$ steps)
 | ||||
|     if opts.systems.is_empty() { | ||||
|         if opts.precomp_file.is_some() { | ||||
|             return Err("Error: Please specify exatly one system".to_owned()); | ||||
|         } else if opts.precompute { | ||||
|             return Err("Error: Please specify at least one system".to_owned()); | ||||
|         } else { | ||||
|             return Err("Error: Please specify at least two systems".to_owned()); | ||||
|         }; | ||||
| impl Router { | ||||
|     pub fn computer_route( | ||||
|         &mut self, | ||||
|         sys_ids: &[u32], | ||||
|         range: f32, | ||||
|         factor: f32, | ||||
|         beam_width: usize, | ||||
|         num_workers: usize, | ||||
|     ) -> Result<Vec<System>, String> { | ||||
|         let id_map = self.get_systems_by_ids(sys_ids)?; | ||||
|         let hops: Vec<System> = sys_ids | ||||
|             .iter() | ||||
|             .map(|id| id_map.get(&id).unwrap()) | ||||
|             .cloned() | ||||
|             .collect(); | ||||
|         self.multiroute(&hops, range, factor, beam_width, num_workers) | ||||
|     } | ||||
|     let mut router: Router = if opts.precomp_file.is_some() { | ||||
|         let (_, ret) = | ||||
|             Router::from_file(&opts.precomp_file.clone().unwrap(), Box::new(opts.callback))?; | ||||
|         ret | ||||
|     } else if opts.range.is_some() { | ||||
|         Router::new( | ||||
|             &opts.file_path, | ||||
|             opts.range.unwrap(), | ||||
|             opts.prune, | ||||
|             opts.primary, | ||||
|             opts.workers, | ||||
|             Box::new(opts.callback), | ||||
|         )? | ||||
|     } else { | ||||
|         Router::new( | ||||
|             &opts.file_path, | ||||
|             opts.range.unwrap(), | ||||
|             opts.prune, | ||||
|             opts.primary, | ||||
|             opts.workers, | ||||
|             opts.callback, | ||||
|         )? | ||||
|     }; | ||||
|     let mut systems: Vec<System> = Vec::new(); | ||||
|     let sys_ht = router.get_systems_by_ids(&opts.systems)?; | ||||
|     for sys in opts.systems { | ||||
|         systems.push(sys_ht.get(&sys).unwrap().clone()); | ||||
|     } | ||||
|     if opts.precompute { | ||||
|         for sys in systems { | ||||
|             router.route_tree = None; | ||||
|             router.precompute(&sys)?; | ||||
|         } | ||||
|         return Ok(None); | ||||
|     } | ||||
|     let route = if router.route_tree.is_some() { | ||||
|         router.route_to(systems.first().unwrap())? | ||||
|     } else if opts.permute { | ||||
|         router.best_multiroute( | ||||
|             &systems, | ||||
|             (opts.keep_first, opts.keep_last), | ||||
|             opts.mode, | ||||
|             opts.factor.unwrap_or(1.0), | ||||
|         )? | ||||
|     } else { | ||||
|         router.multiroute(&systems, opts.mode, opts.factor.unwrap_or(1.0))? | ||||
|     }; | ||||
|     router.workers.close()?; | ||||
|     if route.is_empty() { | ||||
|         return Err("No route found!".to_string()); | ||||
|     } | ||||
|     Ok(Some(route)) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										11
									
								
								setup.cfg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								setup.cfg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| [flake8] | ||||
| exclude = .nox,.git,__pycache__,build,dist,.history | ||||
| verbose = 1 | ||||
| 
 | ||||
| [tool:pytest] | ||||
| qt_api = pyqt5 | ||||
| console_output_style = progress | ||||
| addopts = --benchmark-skip --flake8 | ||||
| testpaths = tests | ||||
| python_files = test_*.py | ||||
| python_functions = test_* | ||||
							
								
								
									
										157
									
								
								setup.py
									
										
									
									
									
								
							
							
						
						
									
										157
									
								
								setup.py
									
										
									
									
									
								
							|  | @ -1,82 +1,115 @@ | |||
| import sys | ||||
| import distutils.cmd | ||||
| import distutils.log | ||||
| # -*- coding: utf-8 -*- | ||||
| from setuptools import find_packages, setup | ||||
| from setuptools_rust import Binding, RustExtension, Strip | ||||
| 
 | ||||
| with open("README.md", "r") as fh: | ||||
| with open('README.md', 'r') as fh: | ||||
|     long_description = fh.read() | ||||
| 
 | ||||
| extras_require = { | ||||
|     'build': ['pyinstaller', 'pywin32'], | ||||
|     'test': [ | ||||
|         'pytest', | ||||
|         'pytest-cov', | ||||
|         'pytest-dependency', | ||||
|         'pytest-benchmark[histogram]', | ||||
|         'pytest-metadata', | ||||
|         'pytest-flake8', | ||||
|         'pytest-flask', | ||||
|         'pytest-mock', | ||||
|         'pytest-flask-sqlalchemy', | ||||
|         'pytest-steps', | ||||
|         'flake8-bugbear', | ||||
|         'flake8-comprehensions', | ||||
|         'cohesion', | ||||
|         'hypothesis', | ||||
|         'flaky' | ||||
|     ], | ||||
|     'dev': [ | ||||
|         'black; python_version >= "3.6"', | ||||
|         'jinja2', | ||||
|         'tsp', | ||||
|         'flake8', | ||||
|         'flake8-bugbear', | ||||
|         'flake8-comprehensions', | ||||
|         'cohesion', | ||||
|         'pre-commit', | ||||
|         'ipython', | ||||
|         'flask-konch', | ||||
|         'setuptools_rust' | ||||
|     ], | ||||
|     'gui': ['PyQt5', 'pyperclip'], | ||||
|     'web': [ | ||||
|         'flask', | ||||
|         'gevent', | ||||
|         'webargs', | ||||
|         'flask-executor', | ||||
|         'flask-wtf', | ||||
|         'flask-user', | ||||
|         'flask-debugtoolbar', | ||||
|         'flask-bootstrap4', | ||||
|         'flask-sqlalchemy', | ||||
|         'flask-nav', | ||||
|         'flask-admin', | ||||
|         'sqlalchemy_utils[password]', | ||||
|         'python-dotenv', | ||||
|     ], | ||||
| } | ||||
| extras_require['all'] = sorted(set(sum(extras_require.values(), []))) | ||||
| 
 | ||||
| setup( | ||||
|     name="ed_lrr_gui", | ||||
|     version_format="{tag}.dev{commitcount}+{gitsha}", | ||||
|     author="Daniel Seiller", | ||||
|     author_email="earthnuker@gmail.com", | ||||
|     description="Elite: Dangerous long range route plotter", | ||||
|     use_scm_version={'write_to': '__version__.py'}, | ||||
|     name='ed_lrr_gui', | ||||
|     author='Daniel Seiller', | ||||
|     author_email='earthnuker@gmail.com', | ||||
|     description='Elite: Dangerous long range route plotter', | ||||
|     long_description=long_description, | ||||
|     long_description_content_type="text/markdown", | ||||
|     url="none yet", | ||||
|     long_description_content_type='text/markdown', | ||||
|     url='https://gitlab.com/Earthnuker/ed_lrr/-/tree/pyqt_gui', | ||||
|     rust_extensions=[ | ||||
|         RustExtension( | ||||
|             "_ed_lrr", | ||||
|             path="rust/Cargo.toml", | ||||
|             '_ed_lrr', | ||||
|             path='rust/Cargo.toml', | ||||
|             binding=Binding.PyO3, | ||||
|             rustc_flags=["--emit=asm"], | ||||
|             rustc_flags=['--emit=asm'], | ||||
|             strip=Strip.No, | ||||
|             debug=False, | ||||
|             native=True, | ||||
|             quiet=True, | ||||
|         ) | ||||
|     ], | ||||
|     packages=find_packages(), | ||||
|     entry_points={"console_scripts": ["ed_lrr = ed_lrr_gui.__main__:main"]}, | ||||
|     install_requires=[ | ||||
|         "appdirs", | ||||
|         "PyYAML", | ||||
|         "requests", | ||||
|         "python-dateutil", | ||||
|         "pyperclip", | ||||
|         "click", | ||||
|         "tqdm", | ||||
|         "PyQt5", | ||||
|         "click-default-group", | ||||
|         "profig", | ||||
|         "ujson", | ||||
|         "colorama", | ||||
|         "svgwrite", | ||||
|     ], | ||||
|     setup_requires=[ | ||||
|         "setuptools", | ||||
|         "setuptools-rust", | ||||
|         "wheel", | ||||
|         "pytest-runner", | ||||
|         "setuptools-git-version", | ||||
|     ], | ||||
|     extras_require={ | ||||
|         "test": ["pytest", "pytest-cov", "pytest-dependency"], | ||||
|         "dev": ["black", "jinja2", "tsp"], | ||||
|         "web": [ | ||||
|             "flask", | ||||
|             "gevent", | ||||
|             "webargs", | ||||
|             "flask-executor", | ||||
|             "flask-wtf", | ||||
|             "flask-user", | ||||
|             "flask-debugtoolbar", | ||||
|             "flask-bootstrap4", | ||||
|             "flask-sqlalchemy", | ||||
|             "flask-nav", | ||||
|             "flask-admin", | ||||
|             "sqlalchemy_utils[password]", | ||||
|         ], | ||||
|     entry_points={ | ||||
|         'console_scripts': ['ed_lrr = ed_lrr_gui.__main__:main'], | ||||
|         'gui_scripts': ['ed_lrr_gui = ed_lrr_gui.__main__:gui_main'] | ||||
|     }, | ||||
|     install_requires=[ | ||||
|         'appdirs', | ||||
|         'PyYAML', | ||||
|         'requests', | ||||
|         'python-dateutil', | ||||
|         'click', | ||||
|         'tqdm', | ||||
|         'click-default-group', | ||||
|         'profig', | ||||
|         'ujson', | ||||
|         'colorama', | ||||
|         'svgwrite', | ||||
|     ], | ||||
|     setup_requires=['setuptools', 'setuptools-rust', | ||||
|                     'setuptools-scm', 'wheel'], | ||||
|     dependency_links=['https://github.com/Nuitka/Nuitka/archive/develop.zip'], | ||||
|     extras_require=extras_require, | ||||
|     classifiers=[ | ||||
|         "License :: OSI Approved :: MIT License", | ||||
|         "Programming Language :: Rust", | ||||
|         "Programming Language :: Python", | ||||
|         "Programming Language :: Python :: 3", | ||||
|         "Programming Language :: Python :: 3.7", | ||||
|         "Programming Language :: Python :: Implementation :: CPython", | ||||
|         "Operating System :: OS Independent", | ||||
|         'License :: OSI Approved :: MIT License', | ||||
|         'Programming Language :: Rust', | ||||
|         'Programming Language :: Python', | ||||
|         'Programming Language :: Python :: 3', | ||||
|         'Programming Language :: Python :: 3.5', | ||||
|         'Programming Language :: Python :: 3.6', | ||||
|         'Programming Language :: Python :: 3.7', | ||||
|         'Programming Language :: Python :: 3.8', | ||||
|         'Programming Language :: Python :: Implementation :: CPython', | ||||
|         'Operating System :: Windows', | ||||
|         'Operating System :: Linux', | ||||
|     ], | ||||
|     include_package_data=True, | ||||
|     zip_safe=False, | ||||
|  |  | |||
							
								
								
									
										120
									
								
								tests/conftest.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								tests/conftest.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,120 @@ | |||
| import pytest | ||||
| import random | ||||
| import csv | ||||
| from tempfile import mkstemp | ||||
| from pathlib import Path | ||||
| 
 | ||||
| 
 | ||||
| def get_mult(star_type): | ||||
|     if star_type.startswith("Neutron"): | ||||
|         return 4.0 | ||||
|     if star_type.startswith("White Dwarf"): | ||||
|         return 1.5 | ||||
|     return 1.0 | ||||
| 
 | ||||
| 
 | ||||
| def gen_pos(p_distrib): | ||||
|     p = [] | ||||
|     for v in p_distrib: | ||||
|         v = random.triangular(-v, v) | ||||
|         p.append(v) | ||||
|     return p | ||||
| 
 | ||||
| 
 | ||||
| def make_stars(num, p_distrib): | ||||
|     star_types = [ | ||||
|         "A (Blue-White) Star", | ||||
|         "A (Blue-White super giant) Star", | ||||
|         "B (Blue-White) Star", | ||||
|         "B (Blue-White super giant) Star", | ||||
|         "Black Hole", | ||||
|         "CJ Star", | ||||
|         "CN Star", | ||||
|         "C Star", | ||||
|         "F (White) Star", | ||||
|         "F (White super giant) Star", | ||||
|         "G (White-Yellow) Star", | ||||
|         "G (White-Yellow super giant) Star", | ||||
|         "Herbig Ae/Be Star", | ||||
|         "K (Yellow-Orange giant) Star", | ||||
|         "K (Yellow-Orange) Star", | ||||
|         "L (Brown dwarf) Star", | ||||
|         "M (Red dwarf) Star", | ||||
|         "M (Red giant) Star", | ||||
|         "M (Red super giant) Star", | ||||
|         "MS-type Star", | ||||
|         "Neutron Star", | ||||
|         "O (Blue-White) Star", | ||||
|         "star_type", | ||||
|         "S-type Star", | ||||
|         "Supermassive Black Hole", | ||||
|         "T (Brown dwarf) Star", | ||||
|         "T Tauri Star", | ||||
|         "White Dwarf (DAB) Star", | ||||
|         "White Dwarf (DA) Star", | ||||
|         "White Dwarf (DAV) Star", | ||||
|         "White Dwarf (DAZ) Star", | ||||
|         "White Dwarf (DB) Star", | ||||
|         "White Dwarf (DBV) Star", | ||||
|         "White Dwarf (DBZ) Star", | ||||
|         "White Dwarf (DC) Star", | ||||
|         "White Dwarf (DCV) Star", | ||||
|         "White Dwarf (DQ) Star", | ||||
|         "White Dwarf (D) Star", | ||||
|         "Wolf-Rayet C Star", | ||||
|         "Wolf-Rayet NC Star", | ||||
|         "Wolf-Rayet N Star", | ||||
|         "Wolf-Rayet O Star", | ||||
|         "Wolf-Rayet Star", | ||||
|         "Y (Brown dwarf) Star", | ||||
|     ] | ||||
|     id_n = 0 | ||||
|     while id_n < num: | ||||
|         name = "System {}".format(id_n) | ||||
|         body = "System {} Star {}".format(id_n, 0) | ||||
|         distance = 0 | ||||
|         star_type = random.choice(star_types) | ||||
|         mult = get_mult(star_type) | ||||
|         x, y, z = gen_pos(p_distrib) | ||||
|         s_type = random.choice(star_types) | ||||
|         record = [id_n, s_type, name, body, mult, distance] | ||||
|         record.extend((x, y, z)) | ||||
|         yield record | ||||
|         id_n += 1 | ||||
|         for sub_id in range(random.randint(0, 4)): | ||||
|             star_type = random.choice(star_types) | ||||
|             mult = get_mult(star_type) | ||||
|             distance = random.randint(100, 10000) | ||||
|             body = "System {} Star {}".format(id_n, sub_id + 1) | ||||
|             s_type = random.choice(star_types) | ||||
|             record = [id_n, s_type, name, body, mult, distance] | ||||
|             record.extend((x, y, z)) | ||||
|             yield record | ||||
|             id_n += 1 | ||||
| 
 | ||||
| 
 | ||||
| @pytest.fixture(scope="module") | ||||
| def stars_path(): | ||||
|     num_stars = int(1e7) | ||||
|     p_distrib = [5000, 5000, 500] | ||||
|     tmpfile, filename = mkstemp(suffix=".csv", prefix="stars_", text=True) | ||||
|     filename = Path(filename) | ||||
|     tmpfile = open(tmpfile, "w", encoding="utf-8") | ||||
|     fields = ["id", "star_type", "system", "body", "mult"] | ||||
|     fields += ["distance", "x", "y", "z"] | ||||
|     csv_writer = csv.DictWriter(tmpfile, fields) | ||||
|     rows = (dict(zip(fields, row)) for row in make_stars(num_stars, p_distrib)) | ||||
|     csv_writer.writeheader() | ||||
|     csv_writer.writerows(rows) | ||||
|     tmpfile.close() | ||||
|     while True: | ||||
|         sys_ids = random.choices(range(num_stars), k=10) | ||||
|         if len(set(sys_ids)) == len(sys_ids): | ||||
|             break | ||||
|     rand_sys = list(map("System {}".format, sys_ids)) | ||||
|     yield str(filename.resolve()), rand_sys | ||||
|     if filename.exists(): | ||||
|         filename.unlink() | ||||
|     idx = filename.with_suffix(".idx") | ||||
|     if idx.exists(): | ||||
|         idx.unlink() | ||||
							
								
								
									
										45
									
								
								tests/test_benchmark.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								tests/test_benchmark.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| import pytest | ||||
| import os | ||||
| from math import log2, ceil | ||||
| 
 | ||||
| 
 | ||||
| def resolve_systems(r, *names): | ||||
|     ret = [] | ||||
|     mapping = r.resolve_systems(*names) | ||||
|     for name in names: | ||||
|         ret.append(mapping.get(name)) | ||||
|     return ret | ||||
| 
 | ||||
| 
 | ||||
| @pytest.fixture(scope="module") | ||||
| def ed_lrr_router(stars_path): | ||||
|     stars_path, systems = stars_path | ||||
|     from ed_lrr_gui import PyRouter | ||||
| 
 | ||||
|     r = PyRouter(lambda status: None) | ||||
|     r.load(stars_path) | ||||
|     system_ids = resolve_systems(r, *systems) | ||||
|     return r, system_ids | ||||
| 
 | ||||
| 
 | ||||
| argvalues = [(0, 0)] | ||||
| argvalues += [(2 ** n, 0) for n in range(17)] | ||||
| argvalues += [(0, g) for g in (0.25, 0.5, 0.75, 1)] | ||||
| ids = [] | ||||
| for width, greedyness in argvalues: | ||||
|     ids.append("beam_width:{}-greedyness:{}".format(width, greedyness)) | ||||
| 
 | ||||
| n_workers = [0] | ||||
| n_workers += [2**n for n in range(ceil(log2(os.cpu_count()))+1)] | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.parametrize("workers", n_workers, | ||||
|                          ids=lambda v: "workers:{}".format(v)) | ||||
| @pytest.mark.parametrize(argnames=("width", "greedyness"), | ||||
|                          argvalues=argvalues, ids=ids) | ||||
| @pytest.mark.parametrize("r_range", [48.0], ids=lambda v: "range:{}".format(v)) | ||||
| def test_benchmark(benchmark, ed_lrr_router, | ||||
|                    r_range, workers, greedyness, width): | ||||
|     r, system_ids = ed_lrr_router | ||||
|     args = system_ids, r_range, greedyness, width, workers | ||||
|     benchmark(r.route, *args) | ||||
|  | @ -1,24 +1,78 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| import random | ||||
| import pytest | ||||
| 
 | ||||
| stars_csv = "D:\\devel\\rust\\ED_LRR\\stars.csv" | ||||
| import os | ||||
| from flaky import flaky | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.dependency() | ||||
| def test_import(): | ||||
|     import _ed_lrr | ||||
| if not hasattr(random, "choices"): | ||||
| 
 | ||||
|     def choices(population, *, k=1): | ||||
|         return [random.choice(population) for _ in range(k)] | ||||
| 
 | ||||
|     random.choices = choices | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.dependency(depends=["test_import"]) | ||||
| def test_search_works(): | ||||
|     import _ed_lrr | ||||
| @pytest.fixture(scope="module") | ||||
| def py_router(stars_path): | ||||
|     from ed_lrr_gui import PyRouter | ||||
| 
 | ||||
|     system_names = ["Ix", "Sol", "Colonia", "Sagittarius A*"] | ||||
|     systems = _ed_lrr.find_sys(system_names, stars_csv) | ||||
|     print(systems) | ||||
|     stars_path, names = stars_path | ||||
|     router = PyRouter(lambda status: None) | ||||
|     router.load(stars_path) | ||||
|     resolved_systems = router.resolve_systems(*names) | ||||
|     for name in names: | ||||
|         err = "Failed to resolve {}".format(name) | ||||
|         assert name in resolved_systems, err | ||||
|     yield router, resolved_systems | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.dependency(depends=["test_import"]) | ||||
| def test_zero_range_fails(): | ||||
|     import _ed_lrr | ||||
| class Test_ED_LRR(object):  # noqa: H601 | ||||
|     @pytest.mark.dependency() | ||||
|     @flaky(max_runs=10, min_passes=5) | ||||
|     def test_load_and_resolve(self, stars_path): | ||||
|         stars_path, names = stars_path | ||||
|         from ed_lrr_gui import PyRouter | ||||
| 
 | ||||
|     # _ed_lrr.route() | ||||
|         router = PyRouter(lambda status: None) | ||||
|         router.load(stars_path) | ||||
|         resolved_systems = router.resolve_systems(*names) | ||||
|         for name in names: | ||||
|             err = "Failed to resolve {}".format(name) | ||||
|             assert name in resolved_systems, err | ||||
| 
 | ||||
|     @pytest.mark.dependency(depends=["Test_ED_LRR::test_load_and_resolve"]) | ||||
|     @flaky(max_runs=10, min_passes=5) | ||||
|     def test_zero_range_fails(self, py_router): | ||||
|         r, resolved_systems = py_router | ||||
|         waypoints = random.choices(list(resolved_systems.values()), k=2) | ||||
|         err = pytest.raises(RuntimeError, r.route, waypoints, 0) | ||||
|         err.match(r"No route from .* to .* found!") | ||||
| 
 | ||||
|     beam_widths = [256, 512, 1024, 0] | ||||
|     greedyness = [0, 0.5, 1] | ||||
|     n_workers = [0, os.cpu_count()] | ||||
|     ranges = [30, 50] | ||||
| 
 | ||||
|     @pytest.mark.dependency(depends=["Test_ED_LRR::test_load_and_resolve"]) | ||||
|     @flaky(max_runs=10, min_passes=2) | ||||
|     @pytest.mark.parametrize("workers", n_workers, | ||||
|                              ids=lambda v: "workers:{}".format(v)) | ||||
|     @pytest.mark.parametrize("jump_range", ranges, | ||||
|                              ids=lambda v: "range:{}".format(v)) | ||||
|     @pytest.mark.parametrize( | ||||
|         "greedyness", greedyness, ids=lambda v: "greedyness:{}".format(v) | ||||
|     ) | ||||
|     @pytest.mark.parametrize( | ||||
|         "beam_width", beam_widths, ids=lambda v: "beam_width:{}".format(v) | ||||
|     ) | ||||
|     def test_route(self, py_router, jump_range, | ||||
|                    workers, greedyness, beam_width): | ||||
|         r, resolved_systems = py_router | ||||
|         waypoints = random.choices(list(resolved_systems.values()), k=2) | ||||
|         args = waypoints, jump_range, greedyness, beam_width, workers | ||||
|         err = "Failed to route for waypoints: {}".format(waypoints) | ||||
|         route_len = r.route(*args) | ||||
|         assert route_len != 0, err | ||||
|         del r | ||||
|         # TODO: verify hop distance and inclusion of waypoints | ||||
|  |  | |||
|  | @ -1,18 +1,22 @@ | |||
| import pytest | ||||
| # -*- coding: utf-8 -*- | ||||
| # import pytest | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.dependency() | ||||
| def test_import(): | ||||
|     import ed_lrr_gui | ||||
|     from ed_lrr_gui.main import main | ||||
|     import ed_lrr_gui.gui as ED_LRR_GUI | ||||
| # class Test_GUI(object): | ||||
| #     pass | ||||
| 
 | ||||
| # @pytest.mark.dependency() | ||||
| # def test_import(): | ||||
| #     import ed_lrr_gui | ||||
| #     from ed_lrr_gui.main import main | ||||
| #     import ed_lrr_gui.gui as ED_LRR_GUI | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.dependency(depends=["test_import"]) | ||||
| def test_search_works(): | ||||
|     import ed_lrr_gui | ||||
| # @pytest.mark.dependency(depends=["test_import"]) | ||||
| # def test_search_works(): | ||||
| #     import ed_lrr_gui | ||||
| 
 | ||||
| 
 | ||||
| @pytest.mark.dependency(depends=["test_import"]) | ||||
| def test_zero_range_fails(): | ||||
|     import ed_lrr_gui | ||||
| # @pytest.mark.dependency(depends=["test_import"]) | ||||
| # def test_zero_range_fails(): | ||||
| #     import ed_lrr_gui | ||||
|  |  | |||
							
								
								
									
										21
									
								
								tests/test_web.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/test_web.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| import pytest | ||||
| 
 | ||||
| 
 | ||||
| @pytest.fixture | ||||
| def app(): | ||||
|     from ed_lrr_gui.web import app as flask_app | ||||
|     yield flask_app | ||||
| 
 | ||||
| 
 | ||||
| @pytest.fixture | ||||
| def db(): | ||||
|     from ed_lrr_gui.web import db as flask_db | ||||
|     yield flask_db | ||||
| 
 | ||||
| 
 | ||||
| class Test_DB(object):  # noqa: H601 | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| class Test_Webapp(object):  # noqa: H601 | ||||
|     pass | ||||
							
								
								
									
										50
									
								
								tox.ini
									
										
									
									
									
								
							
							
						
						
									
										50
									
								
								tox.ini
									
										
									
									
									
								
							|  | @ -1,50 +0,0 @@ | |||
| [tox] | ||||
| envlist = py35-build,py36-build,py37-build,py38-build | ||||
| requires = | ||||
|     tox-conda | ||||
| 
 | ||||
| [testenv] | ||||
| platform = win32 | ||||
| description = Build ED_LRR | ||||
| recreate = True | ||||
| skip_install = True | ||||
| skipsdist = True | ||||
| deps =  | ||||
|     PyQt5 | ||||
|     setuptools_rust | ||||
|     build: https://github.com/Nuitka/Nuitka/archive/develop.zip | ||||
| conda_deps =  | ||||
|     pycrypto | ||||
|     ujson | ||||
|     dev: ipython | ||||
| passenv = | ||||
|     CARGO_HOME | ||||
|     RUSTUP_HOME | ||||
|     INCLUDE | ||||
|     LIB | ||||
|     MSSdk | ||||
|     DISTUTILS_USE_SDK | ||||
| whitelist_externals = | ||||
|     cargo | ||||
|     iscc | ||||
|     cmd | ||||
|     powershell | ||||
|     conda | ||||
| conda_channels = | ||||
|     conda-forge | ||||
| commands = | ||||
|     python build_gui.py | ||||
|      | ||||
|     build: python -m pip install .[web] | ||||
|     build: python -m nuitka --remove-output --plugin-enable=multiprocessing --plugin-enable=qt-plugins --plugin-enable=gevent --standalone --assume-yes-for-downloads --follow-imports --output-dir=exe ed_lrr_gui\__main__.py | ||||
|     build: cmd /c rename exe\__main__.dist\__main__.exe ED_LRR.exe | ||||
|     build: iscc /F"ED_LRR_{envname}" /Qp installer/ED_LRR.iss | ||||
|      | ||||
|     install: python -m pip install -e .[dev,web,test] | ||||
| 
 | ||||
|     dev: python -m pip install -e .[dev,web,test] | ||||
|     dev: cmd /c echo install done now run "conda activate {envdir}" | ||||
|      | ||||
|     test: python -m pip install .[dev,web,test] | ||||
|     test: cargo test | ||||
|     test: pytest | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue