├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── files.yml ├── init.py ├── paradoxReader.py ├── poetry.lock ├── pyproject.toml └── test /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: joshnygaard 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/settings.json 2 | input/ 3 | output/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Josh Nygaard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # paradox-reader 2 | Python module to read Paradox ```.txt``` files used in Crusader Kings II, Europa Universalis IV, Stellaris, and Hearts of Iron IV 3 | 4 | ## What it Does 5 | This code will read a Paradox ```.txt``` file so that it can be used within a Python script. It can also save the read ```.txt``` as a JSON file. 6 | 7 | ## Why 8 | My originally goal was to create some kind of tool for creating random Stellaris empires given a specific government type or personality. Instead of manually writing a JSON or YAML file of the criteria of each government or personality, it made sense to find a way to read the criteria straight from the relevant .txt files. 9 | 10 | ## How Does it do That 11 | Given a file this script will use regular expression substitutions to translate the ```.txt``` file text into valid JSON. The Paradox .txt file format is fairly permissive so several choices had to be made to jerry-rig it into Python: 12 | * Duplicate keys are turned into lists 13 | ``` 14 | allow = { 15 | is_country_type = default 16 | OR = { 17 | AND = { 18 | has_ethic = "ethic_fanatic_militarist" 19 | OR = { 20 | has_ethic = "ethic_spiritualist" 21 | has_ethic = "ethic_egalitarian" 22 | has_ethic = "ethic_xenophile" 23 | } 24 | } 25 | AND = { 26 | has_ethic = "ethic_fanatic_xenophile" 27 | has_ethic = "ethic_militarist" 28 | } 29 | } 30 | } 31 | ``` 32 | Turns into: 33 | ```json 34 | "allow": { 35 | "is_country_type": "default", 36 | "OR": { 37 | "AND": [ 38 | { 39 | "has_ethic": "ethic_fanatic_militarist", 40 | "OR": { 41 | "has_ethic": [ 42 | "ethic_spiritualist", 43 | "ethic_egalitarian", 44 | "ethic_xenophile" 45 | ] 46 | } 47 | }, 48 | { 49 | "has_ethic": [ 50 | "ethic_fanatic_xenophile", 51 | "ethic_militarist" 52 | ] 53 | } 54 | ] 55 | } 56 | } 57 | ``` 58 | * Greater than and less than comparisions get turned into objects: 59 | ``` 60 | happened = { 61 | num_owned_planets > 1 62 | } 63 | ``` 64 | Turns into 65 | ```json 66 | "num_owned_planets": { 67 | "value": 1, 68 | "operand": ">" 69 | } 70 | ``` 71 | 72 | ## Disclaimers 73 | I am in no way affiliated with Paradox, nor do I have any knowledge on how they use these ```.txt``` files. Therefore I make no guarantees that this will correctly translate any given file, this has only been tested on a few files from Stellaris. 74 | -------------------------------------------------------------------------------- /files.yml: -------------------------------------------------------------------------------- 1 | - /Users/joshnygaard/Documents/Paradox Interactive//Stellaris/user_empire_designs.txt 2 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/species_classes 3 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/gfx/portraits/portraits 4 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/species_names 5 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/traits 6 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/governments/authorities 7 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/governments 8 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/planet_classes 9 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/graphical_culture 10 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/ethics 11 | - /Users/joshnygaard/Library/Application Support/Steam/steamapps/common/Stellaris/common/governments/civics -------------------------------------------------------------------------------- /init.py: -------------------------------------------------------------------------------- 1 | from shutil import copy, copytree 2 | import sys 3 | import yaml 4 | 5 | def main(): 6 | with open('files.yml', 'r') as stream: 7 | file_names = yaml.safe_load(stream) 8 | 9 | copy(file_names[0], './input/') 10 | for index in range(1, len(file_names)): 11 | copytree(file_names[index], './input/', dirs_exist_ok=True) 12 | 13 | if __name__ == "__main__": 14 | main() 15 | -------------------------------------------------------------------------------- /paradoxReader.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | from os import listdir 4 | from os.path import isfile, join, isdir, basename 5 | import re 6 | import sys 7 | import time 8 | from tqdm import tqdm 9 | 10 | def main(): 11 | start_time = time.time() 12 | args = _get_args() 13 | 14 | if isdir(args.file_name): 15 | successful = 0 16 | files = [f for f in listdir(args.file_name) if isfile(join(args.file_name, f)) and str.endswith(f, '.txt')] 17 | for file_name in tqdm(files): 18 | result = decode(join(args.file_name, file_name), args.intermediate, args.no_json) 19 | if result is not None: 20 | successful += 1 21 | 22 | print("{} out of {} succesful".format(successful, len(files))) 23 | 24 | else: 25 | decode(args.file_name, args.intermediate, args.no_json) 26 | print("--- %s seconds ---" % (time.time() - start_time)) 27 | 28 | 29 | def _get_args(): 30 | parser = argparse.ArgumentParser() 31 | parser.add_argument('file_name') 32 | parser.add_argument('--intermediate', '-i', help="Save the intermediate code. Useful for debugging", action="store_true", default=False) 33 | parser.add_argument('--no_json', '-n', action="store_true", default=False) 34 | 35 | return parser.parse_args() 36 | 37 | 38 | def decode(file_path, save_intermediate, no_json): 39 | try: 40 | file = open(file_path, 'r') 41 | except FileNotFoundError: 42 | print('ERROR: Unable to find file: ' + file_path) 43 | return None 44 | 45 | file_name = basename(file_path) 46 | 47 | data = file.read() 48 | data = re.sub(r'#.*', '', data) # Remove comments 49 | data = re.sub(r'(?<=^[^\"\n])*(?<=[0-9\.\-a-zA-Z])+(\s)(?=[0-9\.\-a-zA-Z])+(?=[^\"\n]*$)', '\n', data, flags=re.MULTILINE) # Seperate one line lists 50 | data = re.sub(r'[\t ]', '', data) # Remove tabs and spaces 51 | 52 | definitions = re.findall(r'(@\w+)=(.+)', data) # replace @variables with value 53 | 54 | if definitions: 55 | for definition in definitions: 56 | data = re.sub(r'^@.+', '', data, flags=re.MULTILINE) 57 | data = re.sub(definition[0], definition[1], data) 58 | 59 | data = re.sub(r'\n{2,}', '\n', data) # Remove excessive new lines 60 | data = re.sub(r'\n', '', data, count=1) # Remove the first new line 61 | data = re.sub(r'{(?=\w)', '{\n', data) # reformat one-liners 62 | data = re.sub(r'(?<=\w)}', '\n}', data) # reformat one-liners 63 | data = re.sub(r'^[\w-]+(?=[\=\n><])', r'"\g<0>"', data, flags=re.MULTILINE) # Add quotes around keys 64 | data = re.sub(r'([^><])=', r'\1:', data) # Replace = with : but not >= or <= 65 | data = re.sub(r'(?<=:)(?!-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)(?!\".*\")[^{\n]+', r'"\g<0>"', data) # Add quotes around string values 66 | data = re.sub(r':"yes"', ':true', data) # Replace yes with true 67 | data = re.sub(r':"no"', ':false', data) # Replace no with false 68 | data = re.sub(r'([<>]=?)(.+)', r':{"value":\g<2>,"operand":"\g<1>"}', data) # Handle < > >= <= 69 | data = re.sub(r'(?]', data) # make lists 72 | data = re.sub(r'""', r'","', data) # Add commas to lists 73 | data = re.sub(r'{("\w+"(,"\w+")*)}', r'[\g<1>]', data) 74 | data = re.sub(r'((\"hsv\")({\d\.\d{1,3}(,\d\.\d{1,3}){2}})),', r'{\g<2>:\g<3>},', data) # fix hsv objects 75 | data = re.sub(r':{([^}{:]*)}', r':[\1]', data) # if there's no : between list elements need to replace {} with [] 76 | data = re.sub(r'\[(\w+)\]', r'"\g<1>"', data) 77 | data = re.sub(r'\",:{', '":{', data) # Fix user_empire_designs 78 | data = '{' + data + '}' 79 | 80 | file_name = basename(file_path) 81 | 82 | if save_intermediate: 83 | with open('./output/' + file_name + '.intermediate', 'w') as output: 84 | output.write(data) 85 | 86 | try: 87 | json_data = json.loads(data, object_pairs_hook=_handle_duplicates) 88 | except json.decoder.JSONDecodeError: 89 | # print('ERROR: Unable to parse {}'.format(file_name)) 90 | # print('Dumping intermediate code into file: {}_{:.0f}.intermediate'.format(file_name, time.time())) 91 | 92 | with open('./output/{}_{:.0f}.intermediate'.format(file_name, time.time()), 'w') as output: 93 | output.write(data) 94 | 95 | return None 96 | 97 | with open('./output/' + file_name + '.json', 'w') as file: 98 | json.dump(json_data, file, indent=2) 99 | 100 | return data 101 | 102 | 103 | def _handle_duplicates(ordered_pairs): 104 | d = {} 105 | for k, v in ordered_pairs: 106 | if k in d: 107 | if isinstance(d[k], list): 108 | d[k].append(v) 109 | else: 110 | d[k] = [d[k], v] 111 | else: 112 | d[k] = v 113 | return d 114 | 115 | 116 | if __name__ == "__main__": 117 | main() 118 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "colorama" 5 | version = "0.4.6" 6 | description = "Cross-platform colored terminal text." 7 | optional = false 8 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 9 | files = [ 10 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 11 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 12 | ] 13 | 14 | [[package]] 15 | name = "pyyaml" 16 | version = "6.0.1" 17 | description = "YAML parser and emitter for Python" 18 | optional = false 19 | python-versions = ">=3.6" 20 | files = [ 21 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, 22 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, 23 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, 24 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, 25 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, 26 | {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, 27 | {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, 28 | {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, 29 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, 30 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, 31 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, 32 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, 33 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, 34 | {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, 35 | {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, 36 | {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, 37 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, 38 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, 39 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, 40 | {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, 41 | {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, 42 | {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, 43 | {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, 44 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, 45 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, 46 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, 47 | {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, 48 | {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, 49 | {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, 50 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, 51 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, 52 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, 53 | {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, 54 | {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, 55 | {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, 56 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, 57 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, 58 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, 59 | {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, 60 | {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, 61 | {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, 62 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, 63 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, 64 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, 65 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, 66 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, 67 | {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, 68 | {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, 69 | {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, 70 | {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, 71 | ] 72 | 73 | [[package]] 74 | name = "tqdm" 75 | version = "4.66.1" 76 | description = "Fast, Extensible Progress Meter" 77 | optional = false 78 | python-versions = ">=3.7" 79 | files = [ 80 | {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, 81 | {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, 82 | ] 83 | 84 | [package.dependencies] 85 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 86 | 87 | [package.extras] 88 | dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] 89 | notebook = ["ipywidgets (>=6)"] 90 | slack = ["slack-sdk"] 91 | telegram = ["requests"] 92 | 93 | [metadata] 94 | lock-version = "2.0" 95 | python-versions = "^3.12" 96 | content-hash = "84f850b336f42fe60acb76a411fb41bd2c23e1a5d9f20dfe9a15414a71c07084" 97 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "paradox-reader" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["jnygaard "] 6 | readme = "README.md" 7 | 8 | [tool.poetry.dependencies] 9 | python = "^3.12" 10 | pyyaml = "^6.0.1" 11 | tqdm = "^4.66.1" 12 | 13 | 14 | [build-system] 15 | requires = ["poetry-core"] 16 | build-backend = "poetry.core.masonry.api" 17 | -------------------------------------------------------------------------------- /test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for file in ./input/* 4 | do 5 | pipenv run python paradoxReader.py "$file" 6 | done --------------------------------------------------------------------------------