0

What is the proper and fail-safe way to open non py file from not current directory?


To be more specific, I have a method, which validates API response with JSON schema, contained in file schema.json:

def foo():
    json_data = collect_json_data()
    schema = json.load(open('./schema/schema.json'))
    jsonschema.validate(json_data, schema)

And got the following project structure:

D:\projects\project-pytest\.  
│   .gitignore
│   LICENSE
│   README.md
│   requirenments.txt
│   runner_01.cmd
│   structure.txt
│   
├───tests
│   │   runner_02.cmd
│   │   file_with_tests.py
│   │     
│   ├───schema
│   │       schema.json

My goal is to run tests not only from the directory project-pytest\tests\ by exectuting command python -m pytest file_with_tests.py, but also from parent directory, by executing runner_01.cmd, with command python -m pytest -v .\tests\file_with_tests.py inside.

Now the second way fails with FileNotFoundError: [Errno 2] No such file or directory: './schema/schema.json'.

I tried using import os:

schema_path = os.path.abspath('schema.json')  
schema = json.load(open(schema_path))  

but in this case absolute path ignores schema.json parent directory - FileNotFoundError: [Errno 2] No such file or directory: 'D:\\Git\\testarea-pytest\\schema.json'.


How should I open my schema.json placed in different sub-directory and be able to run commands:
python -m pytest -v .\tests\file_with_tests.py from project-pytest folder
and
python -m pytest -v file_with_tests.py from project-pytest\tests\ folder
without failing test because of FileNotFoundError.

ornichola
  • 19
  • 1
  • 1
  • 6
  • Try and open your schema.json using the absolute path? You can find an absolute path when running any script using a solution like this one: https://stackoverflow.com/questions/5137497/find-current-directory-and-files-directory. So you can either hard code the path or find it by using the solution in the stackoverflow post. – rmilletich Feb 06 '18 at 19:38
  • @RobertMilletich my goal is exaclty to avoid any hardcode and make fail-safe solution. I also tried trick `schema_path = os.path.join(os.getcwd(), 'schema', 'schema.json')`, but it outputs same error `FileNotFoundError: [Errno 2] No such file or directory: 'D:\\Git\\testarea-pytest\\schema\\schema.json'`, if I run command from root project folder. However it works, if I run comand from ./tests/ folder. But I need solution, that fits both ways. – ornichola Feb 06 '18 at 20:30
  • Your current working directory in the tests folder would be the tests folder, which is why the script works when you run it from that directory. What I would do it define the absolute path to schema.json at runtime. For example, when you run something like python (absolute path to) file_with_tests.py from any directory, you should be able to get the absolute path of the test directory using dir_path = os.path.dirname(os.path.realpath(\__file\__)). From here, define the absolute path to schema.json using path_to_json = os.path.join(dir_path, os.path.join('schema', 'schema.json')). – rmilletich Feb 06 '18 at 20:48
  • @RobertMilletich, I tried `schema_path = os.path.join(os.path.dirname('schema.json'), 'schema', 'schema.json')`, and got same result as described above - `FileNotFoundError: [Errno 2] No such file or directory: 'D:\\Git\\testarea-pytest\\schema\\schema.json'`, if I run command from root project folder. However it works, if I run comand from `./tests/` folder. – ornichola Feb 07 '18 at 07:54

2 Answers2

0

If you are happy in making your project a package, pkgutil.get_data() can help abstracting from the resource location in the filesystem.

See here.

progmatico
  • 4,714
  • 1
  • 16
  • 27
0

Fixed problem to achieve my goals from the other side - I changed my runner_01.cmd from this:

python -m pytest -v file_with_tests.py 

to this:

cd ./tests/
python -m pytest -v file_with_tests.py

Now tests can be runned from project folder and also from the tests folder by simple cmd script runners. Can't definetely say is this a kludge or not, but users are happy.

ornichola
  • 19
  • 1
  • 1
  • 6