0

Referring to the question here Relative paths in Python. I have similar problem to that.

My project structure:

proj
 |
 |--config
 |    |--ENV
 |
 |--folder1
 |    |--UI
 |       |--test2.py 
 |
 |--test1.py

I want to access the ENV file using test1.py and test2.py but I was to use relative address so that I don't have to change the code every time I move my project.

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'config/ENV')

code above works fine at test1.py but fails at test2.py because now dirname is changed.

I am looking code that I can use on both file. Currently I only have one idea is to split the address on the basis of \ find proj and append config/ENV is there any better and cleaner way to do it?

C:\Users\User1\proj\config/ENV  -- at test1.py

C:\Users\User1\proj\folder1\UI\config/ENV  --  at test2.py

My Current solution:

dirname = os.path.dirname(__file__)
PROJECT_NAME = "proj"
x = dirname[:dirname.find(PROJECT_NAME) + len(PROJECT_NAME)]
filename = os.path.join(x, 'config/ENV')
ooo
  • 512
  • 1
  • 7
  • 27
  • @spectras link suggest to have different path (using ../..) in my case I have to change the code each time I try to access ENV file from different entry point as my project have multiple entry point. – ooo Aug 18 '20 at 08:38
  • You would use the `__file__` technique to get the full path to project root. From there your can add your path, always the same. – spectras Aug 18 '20 at 09:05

1 Answers1

1
My Project
    some_file.py

    Resources
        bg.png
        music.mp3

    Folder
        another_file.py

If you want to access your resources from some_file.py, the relative path would be ./Resources/... but if you want to use resources from another_file.py you would do ../Resources/....

So in your case if you want to access ENV file from test1.py, its relative location would be ./config/ENV, but if you want to access it from test2.py, its relative location would be ../../config/ENV.

Remember ../ means going up one level and ./ means the same level.

Edits:
Here you've the fixed path config/ENV. Passing that fixed path in relative_path() gives you the relative path address.

# proj
#   config
#     ENV
#
#   folder1
#     config
#       some_other_file.txt
#
#     UI
#       test2.py
# 
#   test1.py


import os

def relative_path(path):
    # Get the parent directory of the
    # file that you need the relative
    # path for.
    my_dir = path.split('/')[0]
    
    # Recursively match the directory
    # in the given path. if the match
    # not found go up one level.
    def match_dir(c_path):
        c_path = os.path.split(c_path)[0]
        
        if my_dir in os.listdir(c_path) and (
            os.path.isfile(
                os.path.join(c_path, path)
            )
        ):
            # this whole if-block can be omitted
            # if the folder you're trying to access
            # is on the same level, this just prepends
            # with './'. I added this just for
            # aesthetic reason.
            if os.path.basename(__file__) in os.listdir(c_path):
                return './' + path
                
            return path
            
        return "../" + match_dir(c_path)
    
    
    return match_dir(
        os.path.realpath(__file__)
    )


# Getting relative path from test2.py
print(relative_path("config/ENV"))
print(relative_path("config/some_other_file.txt"))

# Try running this from test1.py
print(relative_path("config/ENV")) # './config/ENV'

This isn't very much optimized. Just a general idea.

Tsubasa
  • 1,389
  • 11
  • 21
  • yes I know that but I want to run same code on both the files test1 and test2 – ooo Aug 18 '20 at 08:01
  • actually there are multiple entry point in my project and ENV need to read once so I am looking for code that can work no matter what is main or start file is – ooo Aug 18 '20 at 08:03
  • If you want to get same relative address from both the files, then I don't think it's possible. *test2.py* is two level down. Maybe you can just dynamically prepend `../../` while accessing the **ENV** file from *test2.py*. – Tsubasa Aug 18 '20 at 08:05
  • Yes I think each time I have to pre-process the base adress. – ooo Aug 18 '20 at 08:06
  • @anoop sorry I know it's late. I got some work. So I edited my answer. Let me know if that helps. – Tsubasa Aug 18 '20 at 13:19
  • very nice solution my last solution (that I added with the question) has the problem that project name can't be changed but your solution eliminates that too. – ooo Aug 18 '20 at 13:58