|
363 | 363 | " if config is None:\n", |
364 | 364 | " dotenv_storage_driver = storage_driver or cls.get_default_storage_driver()\n", |
365 | 365 | " if dotenv_storage_driver.exists('.env'): # unlike dotenv.find_dotenv, stay relative!\n", |
366 | | - " with dotenv_storage_driver.open('.env') as ofile:\n", |
| 366 | + " with dotenv_storage_driver.open('.env') as ifile:\n", |
367 | 367 | " config = dotenv.dotenv_values(stream=ifile)\n", |
368 | 368 | " \n", |
369 | 369 | " if config is None:\n", |
|
634 | 634 | "outputs": [], |
635 | 635 | "source": [ |
636 | 636 | "#| hide\n", |
637 | | - "# test loading out of CWD\n", |
| 637 | + "# test non-os FS with fallback .env path (=$PWD/.env)\n", |
638 | 638 | "\n", |
| 639 | + "memfs_fallback = MemoryFS()\n", |
639 | 640 | "\n", |
640 | | - "'''\n", |
641 | | - "possibly due to jupyter environment blackmagicfuddery, mocking builtins.open DOES NOT WORK!\n", |
642 | | - "take the easy way out and mock an actual file!\n", |
643 | | - "'''\n", |
644 | | - "import tempfile\n", |
645 | | - "import os.path as _p\n", |
| 641 | + "with memfs_fallback.open('schema.json', 'w') as ofile:\n", |
| 642 | + " ofile.write(json.dumps(example_properties_schema))\n", |
| 643 | + " \n", |
| 644 | + "with memfs_fallback.open('.env', 'w') as ofile:\n", |
| 645 | + " ofile.write('\\n'.join([\n", |
| 646 | + " 'string_value_with_enum=only',\n", |
| 647 | + " 'MY_INTEGER_VALUE=9989998',\n", |
| 648 | + " 'A_NUMERIC_VALUE=1167.89',\n", |
| 649 | + " ]))\n", |
646 | 650 | "\n", |
647 | 651 | "OLD_DRIVER = ConfigValidator.DEFAULT_STORAGE_DRIVER\n", |
648 | | - "ConfigValidator.DEFAULT_STORAGE_DRIVER = None\n", |
649 | | - "\n", |
650 | | - "with tempfile.TemporaryDirectory() as tempdir:\n", |
651 | | - "\n", |
652 | | - " orig_dir = os.getcwd()\n", |
653 | | - " os.chdir(tempdir)\n", |
654 | | - "\n", |
655 | | - " dotenv_path = '.flag-env1'\n", |
656 | | - " with open(dotenv_path, 'wt') as f:\n", |
657 | | - " f.write('WINTER=COLD\\n')\n", |
658 | | - "\n", |
659 | | - " json_schema_path = 'flag.schema.json'\n", |
660 | | - " with open(json_schema_path, 'wt') as f:\n", |
661 | | - " schema = {\"type\": \"object\", \"properties\": {\"WINTER\": {\"type\": \"string\"}, \"SUMMER\": {\"type\": \"string\", \"default\": \"HOT\"}}}\n", |
662 | | - " json.dump(schema, f)\n", |
663 | | - "\n", |
664 | | - " dotenv_abspath = _p.join(tempdir, dotenv_path)\n", |
665 | | - " json_schema_abspath = _p.join(tempdir, json_schema_path)\n", |
666 | | - "\n", |
667 | | - " validated_config = ConfigValidator.load_dotenv(\n", |
668 | | - " json_schema=json_schema_path,\n", |
669 | | - " dotenv_path=dotenv_path\n", |
670 | | - " )\n", |
671 | | - " test_eq(validated_config, {'WINTER': 'COLD', 'SUMMER': 'HOT'})\n", |
672 | | - " os.chdir(orig_dir)\n", |
673 | | - "\n", |
674 | | - " # test ConfigValidator continues to use the working directory on first invocation\n", |
675 | | - " validated_config2 = ConfigValidator.load_dotenv(\n", |
676 | | - " json_schema=json_schema_path,\n", |
677 | | - " dotenv_path=dotenv_abspath\n", |
678 | | - " )\n", |
679 | | - " test_eq(validated_config, validated_config2)\n", |
680 | | - "\n", |
681 | | - " validated_config3 = ConfigValidator.load_dotenv(\n", |
682 | | - " json_schema=json_schema_abspath,\n", |
683 | | - " dotenv_path=dotenv_abspath\n", |
684 | | - " )\n", |
685 | | - " test_eq(validated_config, validated_config2)\n", |
686 | | - "\n", |
| 652 | + "ConfigValidator.DEFAULT_STORAGE_DRIVER = memfs_fallback\n", |
687 | 653 | "\n", |
| 654 | + "validated_config5 = ConfigValidator.load_dotenv(\n", |
| 655 | + " json_schema='schema.json'\n", |
| 656 | + ")\n", |
| 657 | + " \n", |
688 | 658 | "ConfigValidator.DEFAULT_STORAGE_DRIVER = OLD_DRIVER" |
689 | 659 | ] |
690 | 660 | }, |
691 | 661 | { |
692 | 662 | "cell_type": "code", |
693 | 663 | "execution_count": null, |
694 | 664 | "metadata": {}, |
695 | | - "outputs": [], |
| 665 | + "outputs": [ |
| 666 | + { |
| 667 | + "ename": "ResourceNotFound", |
| 668 | + "evalue": "resource 'special-bespoke-location/my-own.env' not found", |
| 669 | + "output_type": "error", |
| 670 | + "traceback": [ |
| 671 | + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", |
| 672 | + "\u001b[0;31mResourceNotFound\u001b[0m Traceback (most recent call last)", |
| 673 | + "Cell \u001b[0;32mIn[97], line 11\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m memfs\u001b[38;5;241m.\u001b[39mopen(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mfoo.schema.json\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mw\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;28;01mas\u001b[39;00m ofile:\n\u001b[1;32m 5\u001b[0m ofile\u001b[38;5;241m.\u001b[39mwrite(json\u001b[38;5;241m.\u001b[39mdumps({\n\u001b[1;32m 6\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtype\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mobject\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 7\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mproperties\u001b[39m\u001b[38;5;124m'\u001b[39m: {\n\u001b[1;32m 8\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA_NUMERIC_VALUE\u001b[39m\u001b[38;5;124m'\u001b[39m: { \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtype\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnumber\u001b[39m\u001b[38;5;124m'\u001b[39m },\n\u001b[1;32m 9\u001b[0m }\n\u001b[1;32m 10\u001b[0m }))\n\u001b[0;32m---> 11\u001b[0m validated_dotenv \u001b[38;5;241m=\u001b[39m \u001b[43mConfigValidator\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload_dotenv\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 12\u001b[0m \u001b[43m \u001b[49m\u001b[43mjson_schema\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mfoo.schema.json\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 13\u001b[0m \u001b[43m \u001b[49m\u001b[43mdotenv_path\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mspecial-bespoke-location/my-own.env\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 14\u001b[0m \u001b[43m \u001b[49m\u001b[43mstorage_driver\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmemfs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 15\u001b[0m \u001b[43m)\u001b[49m\n\u001b[1;32m 16\u001b[0m test_eq(validated_dotenv, {\n\u001b[1;32m 17\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mA_NUMERIC_VALUE\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;241m1167.89\u001b[39m,\n\u001b[1;32m 18\u001b[0m })\n\u001b[1;32m 20\u001b[0m test_fail(validator\u001b[38;5;241m.\u001b[39mload_dotenv, kwargs\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdotenv_path\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnon-existent-location-own.env\u001b[39m\u001b[38;5;124m'\u001b[39m})\n", |
| 674 | + "Cell \u001b[0;32mIn[80], line 143\u001b[0m, in \u001b[0;36mConfigValidator.load_dotenv\u001b[0;34m(cls, json_schema, dotenv_path, storage_driver, override)\u001b[0m\n\u001b[1;32m 141\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m dotenv_path:\n\u001b[1;32m 142\u001b[0m dotenv_storage_driver \u001b[38;5;241m=\u001b[39m storage_driver \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mcls\u001b[39m\u001b[38;5;241m.\u001b[39m_get_maybe_abspath_driver(dotenv_path)\n\u001b[0;32m--> 143\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[43mdotenv_storage_driver\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mopen\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdotenv_path\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m ifile:\n\u001b[1;32m 144\u001b[0m config \u001b[38;5;241m=\u001b[39m dotenv\u001b[38;5;241m.\u001b[39mdotenv_values(stream\u001b[38;5;241m=\u001b[39mifile)\n\u001b[1;32m 146\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m config \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", |
| 675 | + "File \u001b[0;32m~/Desktop/experiment/python-schematized-config/venv/lib/python3.10/site-packages/fs/base.py:1228\u001b[0m, in \u001b[0;36mFS.open\u001b[0;34m(self, path, mode, buffering, encoding, errors, newline, **options)\u001b[0m\n\u001b[1;32m 1226\u001b[0m validate_open_mode(mode)\n\u001b[1;32m 1227\u001b[0m bin_mode \u001b[38;5;241m=\u001b[39m mode\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mt\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m-> 1228\u001b[0m bin_file \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mopenbin\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmode\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbin_mode\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mbuffering\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbuffering\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1229\u001b[0m io_stream \u001b[38;5;241m=\u001b[39m iotools\u001b[38;5;241m.\u001b[39mmake_stream(\n\u001b[1;32m 1230\u001b[0m path,\n\u001b[1;32m 1231\u001b[0m bin_file,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1237\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39moptions\n\u001b[1;32m 1238\u001b[0m )\n\u001b[1;32m 1239\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m io_stream\n", |
| 676 | + "File \u001b[0;32m~/Desktop/experiment/python-schematized-config/venv/lib/python3.10/site-packages/fs/memoryfs.py:513\u001b[0m, in \u001b[0;36mMemoryFS.openbin\u001b[0;34m(self, path, mode, buffering, **options)\u001b[0m\n\u001b[1;32m 511\u001b[0m parent_dir_entry \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_get_dir_entry(dir_path)\n\u001b[1;32m 512\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m parent_dir_entry \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m parent_dir_entry\u001b[38;5;241m.\u001b[39mis_dir:\n\u001b[0;32m--> 513\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m errors\u001b[38;5;241m.\u001b[39mResourceNotFound(path)\n\u001b[1;32m 515\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m _mode\u001b[38;5;241m.\u001b[39mcreate:\n\u001b[1;32m 516\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m file_name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m parent_dir_entry:\n", |
| 677 | + "\u001b[0;31mResourceNotFound\u001b[0m: resource 'special-bespoke-location/my-own.env' not found" |
| 678 | + ] |
| 679 | + } |
| 680 | + ], |
696 | 681 | "source": [ |
697 | 682 | "#| hide\n", |
698 | 683 | "# test using custom json schema\n", |
|
775 | 760 | "})" |
776 | 761 | ] |
777 | 762 | }, |
| 763 | + { |
| 764 | + "cell_type": "code", |
| 765 | + "execution_count": null, |
| 766 | + "metadata": {}, |
| 767 | + "outputs": [], |
| 768 | + "source": [ |
| 769 | + "#| hide\n", |
| 770 | + "# test loading out of CWD\n", |
| 771 | + "\n", |
| 772 | + "\n", |
| 773 | + "'''\n", |
| 774 | + "possibly due to jupyter environment blackmagicfuddery, mocking builtins.open DOES NOT WORK!\n", |
| 775 | + "take the easy way out and mock an actual file!\n", |
| 776 | + "'''\n", |
| 777 | + "import tempfile\n", |
| 778 | + "import os.path as _p\n", |
| 779 | + "\n", |
| 780 | + "OLD_DRIVER = ConfigValidator.DEFAULT_STORAGE_DRIVER\n", |
| 781 | + "ConfigValidator.DEFAULT_STORAGE_DRIVER = None\n", |
| 782 | + "\n", |
| 783 | + "with tempfile.TemporaryDirectory() as tempdir:\n", |
| 784 | + "\n", |
| 785 | + " orig_dir = os.getcwd()\n", |
| 786 | + " os.chdir(tempdir)\n", |
| 787 | + "\n", |
| 788 | + " dotenv_path = '.flag-env1'\n", |
| 789 | + " with open(dotenv_path, 'wt') as f:\n", |
| 790 | + " f.write('WINTER=COLD\\n')\n", |
| 791 | + "\n", |
| 792 | + " json_schema_path = 'flag.schema.json'\n", |
| 793 | + " with open(json_schema_path, 'wt') as f:\n", |
| 794 | + " schema = {\"type\": \"object\", \"properties\": {\"WINTER\": {\"type\": \"string\"}, \"SUMMER\": {\"type\": \"string\", \"default\": \"HOT\"}}}\n", |
| 795 | + " json.dump(schema, f)\n", |
| 796 | + "\n", |
| 797 | + " dotenv_abspath = _p.join(tempdir, dotenv_path)\n", |
| 798 | + " json_schema_abspath = _p.join(tempdir, json_schema_path)\n", |
| 799 | + "\n", |
| 800 | + " validated_config = ConfigValidator.load_dotenv(\n", |
| 801 | + " json_schema=json_schema_path,\n", |
| 802 | + " dotenv_path=dotenv_path\n", |
| 803 | + " )\n", |
| 804 | + " test_eq(validated_config, {'WINTER': 'COLD', 'SUMMER': 'HOT'})\n", |
| 805 | + " os.chdir(orig_dir)\n", |
| 806 | + "\n", |
| 807 | + " # test ConfigValidator continues to use the working directory on first invocation\n", |
| 808 | + " validated_config2 = ConfigValidator.load_dotenv(\n", |
| 809 | + " json_schema=json_schema_path,\n", |
| 810 | + " dotenv_path=dotenv_abspath\n", |
| 811 | + " )\n", |
| 812 | + " test_eq(validated_config, validated_config2)\n", |
| 813 | + "\n", |
| 814 | + " validated_config3 = ConfigValidator.load_dotenv(\n", |
| 815 | + " json_schema=json_schema_abspath,\n", |
| 816 | + " dotenv_path=dotenv_abspath\n", |
| 817 | + " )\n", |
| 818 | + " test_eq(validated_config, validated_config2)\n", |
| 819 | + "\n", |
| 820 | + "ConfigValidator.DEFAULT_STORAGE_DRIVER = OLD_DRIVER" |
| 821 | + ] |
| 822 | + }, |
778 | 823 | { |
779 | 824 | "cell_type": "code", |
780 | 825 | "execution_count": null, |
|
869 | 914 | ], |
870 | 915 | "metadata": { |
871 | 916 | "kernelspec": { |
872 | | - "display_name": "Python 3 (ipykernel)", |
| 917 | + "display_name": "python3", |
873 | 918 | "language": "python", |
874 | 919 | "name": "python3" |
875 | | - }, |
876 | | - "language_info": { |
877 | | - "codemirror_mode": { |
878 | | - "name": "ipython", |
879 | | - "version": 3 |
880 | | - }, |
881 | | - "file_extension": ".py", |
882 | | - "mimetype": "text/x-python", |
883 | | - "name": "python", |
884 | | - "nbconvert_exporter": "python", |
885 | | - "pygments_lexer": "ipython3", |
886 | | - "version": "3.10.8" |
887 | 920 | } |
888 | 921 | }, |
889 | 922 | "nbformat": 4, |
|
0 commit comments