Python custom modules management - python

I have a script (dump_ora_shelve.py) which retrieves the data from shelve-storage by specifying the key, e.g.:
def get_shelve_users(field):
import shelve
db = shelve.open('oracle-shelve')
for key in db:
if key == field:
return db[key]
db.close()
The data is retrieved just fine:
print(get_shelve_users('db_users'))
> {'SYS': 'sysdba'}
print(get_shelve_users('oratab'))
> ['orcl:/u01/app']
There is another script which should do the same thing (retrieve the data with key specified) that has dump_ora_shelve imported, but the value returns is Null:
from before_OOP.dump_ora_shelve import get_shelve_users
print(get_shelve_users('db_users'))
> Null
print(get_shelve_users('oratab'))
> Null
The file being imported is located one level above from the file it is importing to.
Please note if I copy both files to the same location import and then function works just fine.

You could provide the full pathname to shelve.open. Remember that inside a module, __file__ is the path of where the source file resides. So you can use that to construct the full pathname.
Typically you will have something like this:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Use os.path.join to concatenate the directory and the filename. Note the use of os.path.dirname and os.path.abspath.
So you can say:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
shelve_db = os.path.join(BASE_DIR, 'oracle-shelve')
db = shelve.open('oracle-shelve')
This assumes that the orache-shelve file is in the same folder as the module in which the get_shelve_users function is (dump_ora_shelve.py).
Don't forget the __file__. That is what makes the whole thing tick, i.e. makes your program insulated from whatever its current directory is.

When running the second script your working directory will be the directory where that script is located. That working directory is kept even when you import and use a file from a different package/directory.
So if your dump_ora_shelve.py script and shelve is located in a different directory/package it will not open the correct file.
If you provide the full path to 'oracle-shelve' in dump_ora_shelve.py it should work.
Update:
In your 'dump_ora_shelve.py' file:
ABS_DIR = os.path.dirname(os.path.abspath(__file__))
This gives you the absoulte path of the directory of ''dump_ora_shelve.py'. Join with name of your DB:
shelve_db = os.path.join(ABS_DIR, 'oracle-shelve')
And finally:
db = shelve.open(shelve_db)
This assumes that your 'oracle-shelve' is in the same directory as 'dump_ora_shelve.py'

Related

How do I get correct path by absolute or relative path?

My file structure is as follows:
kkg/
builder/test.py
builder/data
api/api.py
__init__py
'kkg' is my package name, and in init.py some function are defined, and implementations of these function are written api.py.
In test.py, I have:
import kkg
kkg.load('builder/data/')
Inside the 'load' of the api.py, I have code:
abspath = os.path.abspath(os.path.dirname(__file__))
...
for file in files:
file_path = os.path.join(abspath, data_path)
The data_path is the parameter 'builder/data/' passed from test.py. The path.join reports an error:
Caused by: java.io.FileNotFoundException: /Users/comin/kkg/kkg/api/data/people.csv
The correct data path, if parsed properly, should be:
/Users/comin/kkg/kkg/data/people.csv
I run the 'test.py' inside the builder/ directory. I think the reason there is an unnecessary 'api' in the path generated is because the code piece where error occurs in the api.py.
Perhaps I shouldn't use the join(abspath, data_path) to get the absolute directory. How to get the path correctly parsed?
EDIT:
I changed the path parameter:
kkg.load('../builder/data/')
but then this code failed:
if not os.path.isdir(data_path):
raise ValueError('data_path must be a directory, not file name!')
Why does it raise an error when I added '..' to the path? It is not considered as a directory due to the '..'?
you want the parent directory I think
abspath = os.path.abspath(os.path.join(os.path.dirname(__file__),".."))
you seem to be struggling with this more than you should...it might be easier to just do
path_to_data_file_folder = os.path.abspath(sys.argv[1])
then call it with python main.py /path/to/data/folder
It is much easier to use pathlib over os library:
# api/api.py
from pathlib import Path
KKG_FOLDER = Path(__file__).parent.parent
DATA_FOLDER = KKG_FOLDER / 'builder/data'
print(DATA_FOLDER)
This is more verbose and easier to understand.

How to include Variable in File Path (Python)

I am currently writing a small networkchat in Python3. I want to include a function to save the users history. Now my user class contains a variable for name and I want to save the history-file in a folder which has the name of the user as its name.
So for example it roughly looks like that:
import os
import os.path
class User:
name = "exampleName"
PATH = './exampleName/History.txt'
def SaveHistory(self, message):
isFileThere = os.path.exists(PATH)
print(isFileThere)
So it is alwasy returning "false" until I create a folder called "exampleName".
Can anybody tell me how to get this working?
Thanks alot!
if you use relative paths for file or directory names python will look for them (or create them) in your current working directory (the $PWD variable in bash).
if you want to have them relative to the current python file, you can use (python 3.4)
from pathlib import Path
HERE = Path(__file__).parent.resolve()
PATH = HERE / 'exampleName/History.txt'
if PATH.exists():
print('exists!')
or (python 2.7)
import os.path
HERE = os.path.abspath(os.path.dirname(__file__))
PATH = os.path.join(HERE, 'exampleName/History.txt')
if os.path.exists(PATH):
print('exists!')
if your History.txt file lives in the exampleName directory below your python script.

Python: Check if data file exists relative to source code file

I have a small text (XML) file that I want a Python function to load. The location of the text file is always in a fixed relative position to the Python function code.
For example, on my local computer, the files text.xml and mycode.py could reside in:
/a/b/text.xml
/a/c/mycode.py
Later at run time, the files could reside in:
/mnt/x/b/text.xml
/mnt/x/c/mycode.py
How do I ensure I can load in the file? Do I need the absolute path? I see that I can use os.path.isfile, but that presumes I have a path.
you can do a call as follows:
import os
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
This will get you the directory of the python file you're calling from mycode.py
then accessing the xml files is as simple as:
xml_file = "{}/../text.xml".format(BASE_DIR)
fin = open(xml_file, 'r+')
If the parent directory of the two directories are always the same this should work:
import os
path_to_script = os.path.realpath(__file__)
parent_directory = os.path.dirname(path_to_script)
for root, dirs, files in os.walk(parent_directory):
for file in files:
if file == 'text.xml':
path_to_xml = os.path.join(root, file)
You can use the special variable __file__ which gives you the current file name (see http://docs.python.org/2/reference/datamodel.html).
So in your first example, you can reference text.xml this way in mycode.py:
xml_path = os.path.join(__file__, '..', '..', 'text.xml')

how to convert variable module shelve?

please help convert the variable "fileNameClean" so that you can open the file via the module "shelve"
import shelve
fileName = 'C:/Python33/projects/DVD_LIST/p3_dvd_list_shelve_3d_class_edit_menubar/data.dir'
print('___', fileName)
str = fileName.split('/')[-1]
print('--', str)
fileNameClean = str.split('.')[0:-1]
print(fileNameClean) #['data']
db = shelve.open(fileNameClean) #open error
Use the os.path module to produce a clean path:
import os.path
fileName = 'C:/Python33/projects/DVD_LIST/p3_dvd_list_shelve_3d_class_edit_menubar/data.dir'
fileNameClean = os.path.splitext(os.path.basename(fileName))[0]
db = shelve.open(fileNameClean)
Your code also produced a base name minus the extension, but you returned a list by using a slice (from index 0 until but not including the last element). You could have used fileNameClean[0], but using the os.path module makes sure you catch edgecases in path handling too.
You probably want to make sure you don't use a relative path here either. To open the shelve file in the same directory as the current script or module, use __file__ to get an absolute path to the parent directory:
here = os.path.dirname(os.path.abspath(__file__))
db = shelve.open(os.path.join(here, fileNameClean))

How to determine the Dropbox folder location programmatically?

I have a script that is intended to be run by multiple users on multiple computers, and they don't all have their Dropbox folders in their respective home directories. I'd hate to have to hard code paths in the script. I'd much rather figure out the path programatically.
Any suggestions welcome.
EDIT:
I am not using the Dropbox API in the script, the script simply reads files in a specific Dropbox folder shared between the users. The only thing I need is the path to the Dropbox folder, as I of course already know the relative path within the Dropbox file structure.
EDIT:
If it matters, I am using Windows 7.
I found the answer here. Setting s equal to the 2nd line in ~\AppData\Roaming\Dropbox\host.db and then decoding it with base64 gives the path.
def _get_appdata_path():
import ctypes
from ctypes import wintypes, windll
CSIDL_APPDATA = 26
_SHGetFolderPath = windll.shell32.SHGetFolderPathW
_SHGetFolderPath.argtypes = [wintypes.HWND,
ctypes.c_int,
wintypes.HANDLE,
wintypes.DWORD,
wintypes.LPCWSTR]
path_buf = wintypes.create_unicode_buffer(wintypes.MAX_PATH)
result = _SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, path_buf)
return path_buf.value
def dropbox_home():
from platform import system
import base64
import os.path
_system = system()
if _system in ('Windows', 'cli'):
host_db_path = os.path.join(_get_appdata_path(),
'Dropbox',
'host.db')
elif _system in ('Linux', 'Darwin'):
host_db_path = os.path.expanduser('~'
'/.dropbox'
'/host.db')
else:
raise RuntimeError('Unknown system={}'
.format(_system))
if not os.path.exists(host_db_path):
raise RuntimeError("Config path={} doesn't exists"
.format(host_db_path))
with open(host_db_path, 'r') as f:
data = f.read().split()
return base64.b64decode(data[1])
There is an answer to this on Dropbox Help Center - How can I programmatically find the Dropbox folder paths?
Short version:
Use ~/.dropbox/info.json or %APPDATA%\Dropbox\info.json
Long version:
Access the valid %APPDATA% or %LOCALAPPDATA% location this way:
import os
from pathlib import Path
import json
try:
json_path = (Path(os.getenv('LOCALAPPDATA'))/'Dropbox'/'info.json').resolve()
except FileNotFoundError:
json_path = (Path(os.getenv('APPDATA'))/'Dropbox'/'info.json').resolve()
with open(str(json_path)) as f:
j = json.load(f)
personal_dbox_path = Path(j['personal']['path'])
business_dbox_path = Path(j['business']['path'])
You could search the file system using os.walk. The Dropbox folder is probably within the home directory of the user, so to save some time you could limit your search to that. Example:
import os
dropbox_folder = None
for dirname, dirnames, filenames in os.walk(os.path.expanduser('~')):
for subdirname in dirnames:
if(subdirname == 'Dropbox'):
dropbox_folder = os.path.join(dirname, subdirname)
break
if dropbox_folder:
break
# dropbox_folder now contains the full path to the Dropbox folder, or
# None if the folder wasn't found
Alternatively you could prompt the user for the Dropbox folder location, or make it configurable via a config file.
This adaptation based on J.F. Sebastian's suggestion works for me on Ubuntu:
os.path.expanduser('~/Dropbox')
And to actually set the working directory to be there:
os.chdir(os.path.expanduser('~/Dropbox'))
Note: answer is valid for Dropbox v2.8 and higher
Windows
jq -r ".personal.path" < %APPDATA%\Dropbox\info.json
This needs jq - JSON parser utility to be installed. If you are happy user of Chocolatey package manager, just run choco install jq before.
Linux
jq -r ".personal.path" < ~/.dropbox/info.json
Just similarly to Windows install jq using package manager of your distro.
Note: requires Dropbox >= 2.8
Dropbox now stores the paths in json format in a file called info.json. It is located in one of the two following locations:
%APPDATA%\Dropbox\info.json
%LOCALAPPDATA%\Dropbox\info.json
I can access the %APPDATA% environment variable in Python by os.environ['APPDATA'], however I check both that and os.environ['LOCALAPPDATA']. Then I convert the JSON into a dictionary and read the 'path' value under the appropriate Dropbox (business or personal).
Calling get_dropbox_location() from the code below will return the filepath of the business Dropbox, while get_dropbox_location('personal') will return the file path of the personal Dropbox.
import os
import json
def get_dropbox_location(account_type='business'):
"""
Returns a string of the filepath of the Dropbox for this user
:param account_type: str, 'business' or 'personal'
"""
info_path = _get_dropbox_info_path()
info_dict = _get_dictionary_from_path_to_json(info_path)
return _get_dropbox_path_from_dictionary(info_dict, account_type)
def _get_dropbox_info_path():
"""
Returns filepath of Dropbox file info.json
"""
path = _create_dropox_info_path('APPDATA')
if path:
return path
return _create_dropox_info_path('LOCALAPPDATA')
def _create_dropox_info_path(appdata_str):
r"""
Looks up the environment variable given by appdata_str and combines with \Dropbox\info.json
Then checks if the info.json exists at that path, and if so returns the filepath, otherwise
returns False
"""
path = os.path.join(os.environ[appdata_str], r'Dropbox\info.json')
if os.path.exists(path):
return path
return False
def _get_dictionary_from_path_to_json(info_path):
"""
Loads a json file and returns as a dictionary
"""
with open(info_path, 'r') as f:
text = f.read()
return json.loads(text)
def _get_dropbox_path_from_dictionary(info_dict, account_type):
"""
Returns the 'path' value under the account_type dictionary within the main dictionary
"""
return info_dict[account_type]['path']
This is a pure Python solution, unlike the other solution using info.json.
One option is you could go searching for the .dropbox.cache directory which (at least on Mac and Linux) is a hidden folder in the Dropbox directory.
I am fairly certain that Dropbox stores its preferences in an encrypted .dbx container, so extracting it using the same method that Dropbox uses is not trivial.
This should work on Win7. The use of getEnvironmentVariable("APPDATA") instead of os.getenv('APPDATA') supports Unicode filepaths -- see question titled Problems with umlauts in python appdata environvent variable.
import base64
import ctypes
import os
def getEnvironmentVariable(name):
""" read windows native unicode environment variables """
# (could just use os.environ dict in Python 3)
name = unicode(name) # make sure string argument is unicode
n = ctypes.windll.kernel32.GetEnvironmentVariableW(name, None, 0)
if not n:
return None
else:
buf = ctypes.create_unicode_buffer(u'\0'*n)
ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
return buf.value
def getDropboxRoot():
# find the path for Dropbox's root watch folder from its sqlite host.db database.
# Dropbox stores its databases under the currently logged in user's %APPDATA% path.
# If you have installed multiple instances of dropbox under the same login this only finds the 1st one.
# Dropbox stores its databases under the currently logged in user's %APPDATA% path.
# usually "C:\Documents and Settings\<login_account>\Application Data"
sConfigFile = os.path.join(getEnvironmentVariable("APPDATA"),
'Dropbox', 'host.db')
# return null string if can't find or work database file.
if not os.path.exists(sConfigFile):
return None
# Dropbox Watch Folder Location is base64 encoded as the last line of the host.db file.
with open(sConfigFile) as dbxfile:
for sLine in dbxfile:
pass
# decode last line, path to dropbox watch folder with no trailing slash.
return base64.b64decode(sLine)
if __name__ == '__main__':
print getDropboxRoot()

Categories

Resources