how to avoid mixture of \ and / in file paths when joining paths in Docker containerized Python code - python-3.x

As far as I'm aware I'm using best practices to define paths (using raw strings) and how I go about joining them (using os.path.join()), e.g.
import os
fdir = r'C:\Code\...\samples'
fpath = os.path.join(fdir, 'fname.ext')
and doing so has not caused me any problems when running my code within a Python or command shell. If I print fpath to the console I get consistent use of \s in the path:
C:\Code...\samples\fname.ext
But when I run a Docker containerized version of the code and run the image I get the error:
FileNotFoundError: [Errno 2] No such file or directory:
'C:\Code\...\samples/fname.ext'
I don't understand why os.path.join() has used a / to join fdir and fname.ext when the rest of the path included \\. It doesn't do this when I run the code outside of the container.
I have tried using os.path.normpath():
fpath = os.path.join(fdir, 'fname.ext')
fpath = os.path.normpath(fpath)
as discussed here, and os.sep.join():
fpath = os.sep.join([fdir, 'fname.ext'])
as covered here, and Path().joinpath():
from pathlib import Path
fpath = Path(fdir).joinpath('fname.ext')
as well as Path() / 'path_to_add':
fpath = Path(fdir) / 'fname.ext'
as discussed here, but in every case I end up with the same result using os.path.join().
Can someone please help me to understand what is going on and how to create consistent paths that will work whether I run the code in Python in a Windows environment, or in a Docker container?
Update Nov. 16:
In trying to keep my question brief I think I've left out details that are crucial. Apologies to those who have kindly taken the time to offer suggestions based on my incomplete description of the problem.
My code needs to import/export files from/to directories that are defined within a user-specified configuration file.
So the configuration file has a section of code where the user defines variables and paths, e.g.
samplesDir = r"path-to-samples-directory"
The variables are stored in a dictionary of dictionaris and stored as a .json.
At the start of the code the user defines the key that selects the dictionary of interest so that at various parts in my code when a file needs to be imported/exported, the paths are at hand.
So back to my example, samplesDir is stored in the configuration dictionary, cfgDict, so all I need to do is append the file name:
sampleFpath = os.path.join(sampleDir, sampleFname)
and sampleFname is determined based on other variables.
Because of the dynamic nature of the variables (including directory paths and file paths), I think it rules out the use of static path defined in a .yml with Docker Compose.
Update Nov. 18:
It may help to include a few more details and some screenshots.
The above screenshot shows the file and folder structure of the src directory containing the source code, the main app.py script for command-line use, the Dockerfile, etc.
The configs folder contains JSON files that includes variables, paths to directories and files. The user can create configuration files either by copying an existing one and modifying the entries, or configuration files can be generated by calling config.py.
Within config.py I have pre-set variables and paths, so that the directory path to the configuration files (configs), sample files (sample_DROs) and others (e.g. fiducials) are all within src.
I don't anticipate any reason why the user would want to store the config files anywhere else, nor do I expect them to want to use different sample files (or move them elsewhere). However, they will undoubtedly create their own fiducials and may decide not to store them in the fiducials directory (i.e. somewhere not within the src directory).
Likewise I have pre-set the download directory (based on the parameters stored within the configuration files, files are fetched from a server and downloaded) to be the default Downloads directory:
rootDownloadDir = os.path.join(Path.home(), "Downloads", "xnat_downloads")
Those files are later imported, processed, and the outputs are (by default) exported into sub-directories within rootDownloadDir.
Within Dockerfile I set the working directory of the container to be that of the source code and copy all of the contents of src (with the exception of some directories defined in .dockerignore):
WORKDIR C:/Code/WP1.3_multiple_modalities/src
...
COPY . .
so that the structure of the container mimics that of WORKDIR:
Hence I have allowed for flexibility in import/export directories, and they are by default a combination of paths within and outside of the src directory. And so, the code executed within the container will need to access files both within and outside of src.
That said, I don't know what rootDownloadDir will look like when os.path.join(Path.home(), "Downloads", "xnat_downloads") is run within the container.
This has got me thinking - Is it bad practice to set the download directory outside of src?
Returning to the original error:
the sample file is in the container:

From the actual behavior I can suppose that the container is based on Unix-like image. Path separator is / in such systems.
To build an environment-independent path which works inside and outside of the container you need the following steps:
Mounting of host folder to container directory.
Environment variable inside and outside the container.
I can show an example of how this is achievable via docker-compose tool and its configuration file docker-compose.yml:
# docker-compose.yml file
version: '3'
services:
<service_name>: # your service name here
image: <image_name> # name of image your container is built on
environment:
- SAMPLES_PATH=/samples
volumes:
- C:\Code\somepath\samples:/samples
In your python code you can use the following structure:
import os
fdir = os.getenv('SAMPLES_PATH', r'C:\Code\...\samples')
fpath = os.path.join(fdir, 'fname.ext')

Related

Error when hiding django secret_key in miniconda environment

I'm a total newbie and I'm trying to do this project this is my first time, and it's almost done. I tried every method mentioned in this SO thread to move secret key from settings. In every method i got some kind of error, even from this official django doc mathod. I couldn't find where I'm making mistake.
When the secret key is inside the settings.py, everything is working super smooth. But I need to push my code in git, so i have to hide it from settings.py.
Right now im adding the details when i tried using django-environ, to keep secret key outside of settings.py.
im putting the contents inside the root project folder.
im using miniconda: 4.10.1. here is my requirement.txt.
# platform: linux-64
_libgcc_mutex=0.1=main
_openmp_mutex=4.5=1_gnu
appdirs=1.4.4=py_0
asgiref=3.3.4=pyhd3eb1b0_0
attrs=21.2.0=pyhd3eb1b0_0
black=19.10b0=py_0
ca-certificates=2021.5.30=ha878542_0
certifi=2021.5.30=py39hf3d152e_0
click=8.0.1=pyhd3eb1b0_0
django=3.2.4=pyhd3eb1b0_0
django-environ=0.4.5=py_1
importlib-metadata=3.10.0=py39h06a4308_0
krb5=1.17.1=h173b8e3_0
ld_impl_linux-64=2.35.1=h7274673_9
libedit=3.1.20210216=h27cfd23_1
libffi=3.3=he6710b0_2
libgcc-ng=9.3.0=h5101ec6_17
libgomp=9.3.0=h5101ec6_17
libpq=12.2=h20c2e04_0
libstdcxx-ng=9.3.0=hd4cf53a_17
mypy_extensions=0.4.1=py39h06a4308_0
ncurses=6.2=he6710b0_1
openssl=1.1.1k=h7f98852_0
pathspec=0.7.0=py_0
pip=21.1.2=py39h06a4308_0
psycopg2=2.8.6=py39h3c74f83_1
python=3.9.5=h12debd9_4
python_abi=3.9=1_cp39
pytz=2021.1=pyhd3eb1b0_0
readline=8.1=h27cfd23_0
regex=2021.4.4=py39h27cfd23_0
setuptools=52.0.0=py39h06a4308_0
six=1.16.0=pyh6c4a22f_0
sqlite=3.35.4=hdfb4753_0
sqlparse=0.4.1=py_0
tk=8.6.10=hbc83047_0
toml=0.10.2=pyhd3eb1b0_0
typed-ast=1.4.2=py39h27cfd23_1
typing_extensions=3.7.4.3=pyha847dfd_0
tzdata=2020f=h52ac0ba_0
wheel=0.36.2=pyhd3eb1b0_0
xz=5.2.5=h7b6447c_0
zipp=3.4.1=pyhd3eb1b0_0
zlib=1.2.11=h7b6447c_3
settings.py
import os
import environ
from pathlib import Path
env = environ.Env(
# set casting, default value
DEBUG=(bool, False)
)
# reading .env file
environ.Env.read_env()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')
# False if not in os.environ
DEBUG = env('DEBUG')
im not adding the rest of settings. i dont think its important. if need please mention I.ll update.
i placed .env file in root of the project where manage.py and db.sqlite3 are placed
.env
#env file
DEBUG=on
#copied the entire line from settings.py
SECRET_KEY ='xxxx django secret key here xxxx'
while running "python manage.py runserver", i got this error.
im not sure what im missing. i got some kind of error, when i tried each method and errors are not same. sorry that i cannot explain every method and error here.
there are several questions asked in this form. but most are not answered and some are not accurately explains my situation. please mention if anything else is needed or for more clarification.
First check that you have installed django-environ and maybe you have a typing mistake in your requirements.txt it should be django-environ=0.4.5 instead of django-environ=0.4.5=py_1
you can pass the path of your .env inside read_env(env_file="relative_path_of_your_env_file")
it read a .env file into os.environ.
If not given a path to a dotenv path, does filthy magic stack backtracking
to find manage.py and then find the dotenv.
go through this code https://github.com/joke2k/django-environ/blob/master/environ/environ.py#L614
From the structure of the file tree, its clear that .env file is placed in the root folder of the project. When checking the error message, its visible that whoever is searching for .env file is checking at the same place as settings.py.
So, the short answer is if you are using django-environ to keep secret-key outside, place .env file together with settings.py in the same directory.
For a bit more elaborated content, you can refer to this link. I felt it is suitable for newbies.

Relative addressing files python3

I have variable address = /data/train/1.jpg, and I'm trying to read file by
im = Image.open(address)
FileNotFoundError: [Errno 2] No such file or directory: '/data/train/1.jpg'
By some reasons I can't use full name of file.
I started jupyter notebook from folder which actually contains file 1.jpg in /data/train/.
How can I fix it?
Relative addressing means from the perspective of the current working directory. So if you script is in the same directory that the data folder is in, your path to the file would be ./data/train/1.jpg. Note the ./, which means the current directory.
use relative path, this one is absolute
address = './data/train/1.jpg'
im = Image.open(address)
in this case . means current location while slash means the environments root (view and explanation) on this depends on your OS

How's python Pyminizip compress_multiple work?

My python version is 3.5 through Anaconda on Windows 10 environment. I'm using Pyminizip because I need password protected for my zip files, and Zipfile doesn't support it yet.
I am able to zip single file through the function pyminizip.compress, and the encrypt function worked as expected. However, when trying to use pyminizip.compress_multiple I always encountered a Python crash (as pictures) and I believe it's due to the problem of my bad input format.
What I would like to know is: What's the acceptable format for input argument src file LIST path? From Pyminizip's documentation:
pyminizip.compress_multiple([u'pyminizip.so', 'file2.txt'], "file.zip", "1233", 4, progress)
Args:
1. src file LIST path (list)
2. dst file path (string)
3. password (string) or None (to create no-password zip)
4. compress_level(int) between 1 to 9, 1 (more fast) <---> 9 (more compress)
It seems the first argument src file LIST path should be a list containing all files required to be zipped. Accordingly, I tried to use compress_multiple to compress single file with command:
pyminizip.compress_multiple( ['Filename.txt'], 'output.zip', 'password', 4, optional)
and it lead to Python crash. So I try to add a full path into the args.
pyminizip.compress_multiple( [os.getcwd(), 'Filename.txt'], ... )
and still, it crashed again. So I think maybe I have to split the path like this
path = os.getcwd().split( os.sep )
pyminizip.compress_multiple( [path, 'Filename.txt'], ...)
still got a bad luck. Any ideas?
Pyminizip requires the path name (or relative path name from where the script is running from) in the files.
Your example:
pyminizip.compress_multiple( [os.getcwd(), 'Filename.txt'], ... )
gives a list of files of os.getcwd(), and then another file, 'Filename.txt'. You need to combine them into a single path using os.path.join()
in your filename example, you will need:
pyminizip.compress_multiple( [os.path.join(getcwd(), 'Filename.txt')],...)
conversly:
pyminizip.compress_multiple( [os.path.join(getcwd(), 'Filename1.txt'), os.path.join(getcwd(), 'Filename2.txt')],...)
From here - https://pypi.org/project/pyminizip/, the usage of compress_multiple is
pyminizip.compress_multiple([u'pyminizip.so', 'file2.txt'], [u'/path_for_file1', u'/path_for_file2'], "file.zip", "1233", 4, progress)
The second parameter is a bit confusing, but if used, it will create a zip file, which when uncompressed, will create a directory structure like:

Require file somewhere in the directory node.js

I have a file that is required in many other files, that are on different folders, inside the main directory.
Is there a way to just require the filename without having to write the relative path, or the absolute path? Like require('the_file'). And without having to go to npm and install it?
Create a folder inside your main directory , put the_file.js inside and set the NODE_PATH variable to this folder.
Example :
Let's say you create a ./libs folder within your main directory, you can just use :
export NODE_PATH = /.../main/lib
after that, you can require any module inside this directory using just :
var thefile = require('the_file')
To not have to do that every time, you'd have to add the variable to your .bashrc (assuming you're running a Unix system).
Or you can set a global variable inside your app.js file and store the path of your 'the_file' in it like so :
global.rootPath = __dirname;
Then you can require from any of your files using :
var thefile = require(rootPath+'/the_file')
These are the most convenient methods for me, short of creating a private npm, but there are a few other alternatives that I discovered when looking up an answer to your question, have a look here : https://gist.github.com/branneman/8048520

Sourcing Puppet files from outside of modules

I'm installing a package from a module (Nginx in this specific case) and would like to include a configuration file from outside of the module, i.e. from a top level files directory parallel to the top level manifests directory. I don't see any way to source the file though without including it in a module or in my current Vagrant environment referring to the absolute local path.
Does Puppet allow for sourcing files from outside of modules as described in the documentation?
if I understand your question correctly, you can.
In your module a simple code like this
file { '/path/to/file':
ensure => present,
source => [
"puppet:///files/${fqdn}/path/to/file",
"puppet:///files/${hostgroup}/path/to/file",
"puppet:///files/${domain}/path/to/file",
"puppet:///files/global/path/to/file",
],
}
will do the job. The /path/to/file will be sourced using a file located in the "files" Puppet share.
(in the example above, it search in 4 different locations).
update maybe you're talking about a directory to store files which is not shared by Puppet fileserver (look at http://docs.puppetlabs.com/guides/file_serving.html), and in this case you can't i think, Vagrant or not, but you can add it to your Puppet fileserver to do it. I thinks it's the best (and maybe only) way to do it.
If you have a number of Vagrant VMs you can simply store files within your Vagrant project directory (containing your VagrantFile).
This directory is usually available to all VMs as /vagrant within the VM on creation.
If you want other directories on your computer to be available to your VMs just add the following to your VagrantFile
# see http://docs.vagrantup.com/v1/docs/config/vm/share_folder.html
config.vm.share_folder "v-packages", "/vagrant_packages", "../../dpkg"
Then to use the files within puppet you can simply treat them as local files to the VM
# bad example, bub basically use 'source => 'file:///vagrant/foo/bar'
file { '/opt/cassandra':
ensure => directory,
replace => true,
purge => true,
recurse => true,
source => 'file:///vagrant/conf/dist/apache-cassandra-1.2.0',
}
This is probably only wise to do if you only using local puppet manifests/modules.
Probably too late to help bennylope, but for others who happen across this question, as I did before figuring it out for myself ...
Include stuff like this in your Vagrantfile ...
GUEST_PROVISIONER_CONFDIR = "/example/destination/path"
HOST_PROVISIONER_CONFDIR = "/example/source/path"
config.vm.synced_folder HOST_PROVISIONER_CONFIDIR, GUEST_PROVISIONER_CONFDIR
puppet.options = "--fileserverconfig='#{GUEST_PROVISIONER_CONFDIR}/fileserver.conf'"
Then make sure /example/source/path contains the referenced fileserver.conf file. It should look something like ...
[foo]
path /example/destination/path
allow *
Now, assuming example-file.txt exists in /example/source/path, the following will work in your manifests:
source => "puppet:///foo/example-file.txt",
See:
Puppet configuration reference entry for fileserverconfig
Serving Files From Custom Mount Points

Resources