In my repo I have got a lib
directory in which I store some classes/functions that are later used in scripts in other directories in my repo. Each script outside the lib dir has a __root__.py
file in its directory as follow:
import sys, os
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(current_dir, "..", "..", "..", ".."))
so in each python script I have:
import __root__
from dir1.dir2.lib import class1
from dir1.dir2.lib import function1
Now I wanted to add to my lib
directory a sharepoint_key.pem
file that has a structure:
-----BEGIN PRIVATE KEY-----
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
-----END PRIVATE KEY-----
Can I somehow load sharepoint_key.pem
using from x import y
clause?
In my repo I have got a lib
directory in which I store some classes/functions that are later used in scripts in other directories in my repo. Each script outside the lib dir has a __root__.py
file in its directory as follow:
import sys, os
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(current_dir, "..", "..", "..", ".."))
so in each python script I have:
import __root__
from dir1.dir2.lib import class1
from dir1.dir2.lib import function1
Now I wanted to add to my lib
directory a sharepoint_key.pem
file that has a structure:
-----BEGIN PRIVATE KEY-----
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
xdxxdxdxdxddx84hxdxxdxdxdxddxpDRNf47ZAxdxxdxdxdxddxyAoPdT04xdx
-----END PRIVATE KEY-----
Can I somehow load sharepoint_key.pem
using from x import y
clause?
3 Answers
Reset to default 2The from x import y
import mechanism in Python is specifically designed to work with Python modules (.py files). It looks for a module named x
and then imports the name y
defined inside it.
A .pem
file is simply a text file containing data and not a Python module, you cannot
directly use this import syntax to access its contents.
Instead, you should read the .pem
file's content within a Python module located (for example) in your lib
directory and then import that content.
Make a new Python file in your lib
directory called sharepoint_credentials.py
.
import os
def load_sharepoint_key(filename="sharepoint_key.pem"):
filepath = os.path.join(os.path.dirname(__file__), filename) # sharepoint_key.pem file in the lib directory
try:
with open(filepath, 'r') as f:
private_key = f.read().strip()
return private_key
except FileNotFoundError:
print(f"Error: File not found at {filepath}")
return None
SHAREPOINT_PRIVATE_KEY = load_sharepoint_key()
You can now access the content by importing it into your various Python scripts.
import __root__
from lib.sharepoint_credentials import SHAREPOINT_PRIVATE_KEY, load_sharepoint_key
if SHAREPOINT_PRIVATE_KEY:
print("Loaded SharePoint Private Key:")
print(SHAREPOINT_PRIVATE_KEY)
else:
print("Failed to load SharePoint Private Key.")
# Or you can call the function directly if needed
key = load_sharepoint_key()
if key:
# Use key
While the method of calculating the current directory and appending to sys.path
can enable imports from your lib
directory across various script locations, it's important to understand that this approach has limitations and it's not the most Pythonic way to handle module dependencies.
It doesn't clearly establish a "project root". Instead, it depends on navigating up the directory tree using relative path counting. Consequently, any changes to your project's folder anization will necessitate manually adjusting the number of ..
segments in your os.path.join
calls across all your scripts. Have we considered turning lib
into a Python package?
No, this is not possible
Importable modules are always either files that end in
.py
where the preceding part of the file name is a legal variable name (matches regex^[^\W\d]\w*$
), or directories (Python packages) that optionally contain a__init__.py
that populates the module..pem
is not a legal module extension. Whileimportlib
primitives will let you import files that don't follow the naming conventions,from x import y
will not support that out of the box.Import semantics are for Python source code. This is not Python source code.
Your problem feels like an XY problem; you know how to load information (in the form of global variables or the like) via import
, and haven't learned how to interact with files in any other way. There is nothing to be gained by trying to wedge arbitrary file I/O into the import
process; while you could probably hack the import mechanisms to allow this, it would be an insane amount of ugly, confusing code, that serves no purpose.
What you want
If you stick with your hacky approach, you want to either:
- Use plain file I/O to load arbitrary data from a file,
with open(os.path.join(__root__.current_dir, 'dir1', 'dir2', 'lib', 'sharepoint_key.pem')) as f:
then doingf.read()
or the like (if the PEM is unique and associated with__root__
, you might want to define that path within__root__
so each caller isn't recreating it), or - Use
ssl.create_default_context
passing a path to this PEM file to it (to implicitly load and parse the cert), creating the path to it as above.
Both of these locate the path relative to __file__
in much the same way you adjusted sys.path
in your existing __root__.py
.
But your current approach is hacky; you shouldn't be messing around with sys.path
in the first place, manually locating data files, etc. You need to learn to write a proper setup.py
or pyproject.toml
or the like to build and install your package, rather than hacks like a module to manually screw with your sys.path
to act like you've been installed.
Your .pem
file is logically data that would be packaged with the installer, and how non-source data is packaged varies by build backend, so you'd need to refer to your build backend's docs for how to do it, e.g. the Setuptools datafile documentation. Once you've built and installed the package, you can extract the data from it using the importlib.resources
module, which lets you acquire file handles for the packaged data.
The reason it's important to do this, rather than just write a setup.py
that puts the file on disk, is that there's no guarantee an installed package actually unpacks your data to individual files on disk at all; for .egg
-based installs, for zipapp
s, and for py2exe
created standalone executables that include your package, both source files and data are likely embedded in a large file containing many or all dependencies. importlib.resources
will still get you the handle needed to read that data, at which point you can use the handle or data read from it directly, or if it must be an on-disk standalone file, copy it to a tempfile.NamedTemporaryFile
or the like to temporarily realize it as a true file for the time you need it to behave as one.
I do not believe you can use from
and import
for anything except python files.
If you wish do import the string text, you can use open()
, which's syntax would be:
doc = open('sharepoint_key.pem', 'r') #note that the first argument should include the directory, not just the name of the file
text = doc.read()
doc.close()
text would then be a string that is whatever is in the document, and then you could string manipulate it using
split()
and join()
, or just remove()
from
andimport
work only with python modules and not with arbitrary files. What stops you from simply reading that file or making helper function for reading it? – Milos Stojanovic Commented 2 days ago__
. All names beginning and ending with__
are reserved to Python; if Python 3.next decides it has a use for__root__
as a name, as a keyword, as anything, they'll use it, without worrying about code that might already use that name and have a conflict. The__x__
names from the data model for special method names use__
they need non-conflicting reserved names, don't invent names in the reserved space yourself. – ShadowRanger Commented 2 days ago