How to include non-python reference files in Azure Function? - python

I have some Python code that references external .ttf font files. I can reference them by including them in the project root folder. I'd like to turn this code into an HTTP Triggered Azure Function.
I see in the docs that I can import external Python modules and files into a Function, but what about non-Python files?
How are these referenced?
When Python code is run locally, they are referenced in the code as:
h1_font = ImageFont.truetype("DejaVuSans-Bold.ttf", h1_size)
h2_font = ImageFont.truetype("Ubuntu-Th.ttf", h2_size)
h3_font = ImageFont.truetype("Ubuntu-Th.ttf", h3_size)
footer_font = ImageFont.truetype("UbuntuMono-R.ttf", footer_size)
What is the filepath when the app is published to Azure?
Here is how the folders are structured locally:
Once published to Azure, the .ttf files are no longer accessible and Function fails
Note: This is a Python Function running on Linux, not Windows.

Update:
My structure:
__init__.py
import logging
import azure.functions as func
from fontTools.ttLib import TTFont
def main(req: func.HttpRequest) -> func.HttpResponse:
font = TTFont('HttpTrigger1/font.ttf')
with open('HttpTrigger1/test.txt', 'r') as file:
data = file.read()
return func.HttpResponse("The content is -----------------"+data)
Original Answer:
How are these referenced?
Put it in the Project folder and use relative path. Then use it as before.
What is the filepath?
Physical path of azure function app is D:\home\site\wwwroot.
Do I just include them in the root folder of the Function and publish?
Yes, just include them in the root folder and then publish the function app, and then you can use relative path to get them.

Related

How to make a python program work for different people? [duplicate]

How can I get the path to the %APPDATA% directory in Python?
import os
print os.getenv('APPDATA')
You may use os.path.expandvars(path):
Return the argument with environment variables expanded. Substrings of the form $name or ${name} are replaced by the value of environment variable name. Malformed variable names and references to non-existing variables are left unchanged.
On Windows, %name% expansions are supported in addition to $name and ${name}.
This comes handy when combining the expanded value with other path components.
Example:
from os import path
sendto_dir = path.expandvars(r'%APPDATA%\Microsoft\Windows\SendTo')
dumps_dir = path.expandvars(r'%LOCALAPPDATA%\CrashDumps')
Although the question clearly asks about the Windows-specific %APPDATA% directory, perhaps you have ended up here looking for a cross-platform solution for getting the application data directory for the current user, which varies by OS.
As of Python 3.11, somewhat surprisingly, there is no built-in function to find this directory. However, there are third-party packages, the most popular of which seems to be appdirs, which provides functions to retrieve paths such as:
user data dir (user_data_dir)
user config dir (user_config_dir)
user cache dir (user_cache_dir)
site data dir (site_data_dir)
site config dir (site_config_dir)
user log dir (user_log_dir)
You can try doing:
import os
path = os.getenv('APPDATA')
array = os.listdir(path)
print array
You can use module called appdata. It was developed to get access to different paths for your application, including app data folder. Install it:
pip install appdata
And after that you can use it this way:
from appdata import AppDataPaths
app_paths = AppDataPaths()
app_paths.app_data_path # for your app data path
app_paths.logs_path # for logs folder path for your application
It allows to to get not only app data folder and logs folder but has other features to manage paths like managing config files paths. And it's customizable.
Links:
Read the Docs - documentation.
GitHub - source code.
PyPI - package manager (pip).
I printed this page and am gratfull for this.
Also tryed to configure "%APPDATA%"in this Dispositive,
using: "notepad", doesn't knowing to archive the sugested condiguration. Also copied sotoz and Aominé contribuiters. tks.
efk14it.

Writing Python pip-able package: How to access files in the package?

I'm trying to develop a visualization package based on CEFpython technology, so the function has to access an html file. So the structure of the package is basically:
viz_tool
--> init.py
--> main.py
--> index.html
and in the main.py file, I defined a function:
def view():
index_filepath = os.path.realpath("index.html")
print(index_filepath)
browser = cef.CreateBrowserSync(url='file://' + index_filepath,
window_title="viz tool")
....
The goal is, after installing this package, I can do:
from viz_tool import view
view()
but of course currently the "index_filepath" would be my current working directory, so it won't be able to find the "index.html" file.
How should I change the code so I could access the "index.html" file, which presumably would be in the directory where the package is installed?
Thank you very much! and please let me know if I need to clarify anything
Look at the documentation of pkg_resources.
It has a method called resource_filename that you can use to get absolute path to any internal module.
from pkg_resources import resource_filename
from foo.bar import bazz # say bazz has template folder
pth_to_template = resource_filename(bazz.__name__, "template")
This will return the absolute path to <path to foo>/foo/bar/bazz/template.
I would highly recommend not putting html file in root folder and also avoid using hardcoded paths in any form, including doing os.path.join recursively to traverse multiple levels. It makes moving files in future a mess.
Edit:
For accessing resources from the same module by relative path, you can do
pth = resource_filename(__name__, "templates/something.html")
Edit 2:.
You will also have to add all the non-python files in package_data as here in order for setup.py to add them to the distribution package.

How does _init_ file in Flask project work when starting the server?

I'm reading the Flask tutorial and learned that in large application structure the code is moved from single app.py file to 'application factory function' create_app in _init_.py file, then the server can be started like this:
export FLASK_APP=flaskr
export FLASK_ENV=development
flask run
I wonder how does the last command work behind the scene, because there's no explicit call to this factory function anywhere in the code hence no app returned?
Another Flask doc tries to explain why such project structure is used but in that case code in _init_.py creates app explicitly:
from flask import Flask
app = Flask(__name__)
import yourapplication.views
python doc says:
The init.py files are required to make Python treat the
directories as containing packages; this is done to prevent
directories with a common name, such as string, from unintentionally
hiding valid modules that occur later (deeper) on the module search
path. In the simplest case, init.py can just be an empty file, but
it can also execute initialization code for the package or set the
all variable, described later.
The last sentence mentions about 'initialization code' which can be applied in the second case(and simple project structure with app.py file) but I failed to apply it to the first case.
In the flask source code, they check if a function called create_app exists.
# Search for app factory functions.
for attr_name in ('create_app', 'make_app'):
app_factory = getattr(module, attr_name, None)
if inspect.isfunction(app_factory):
try:
app = call_factory(script_info, app_factory)
if isinstance(app, Flask):
return
It evens says so in the documentation:
Flask will automatically detect the factory (create_app or make_app) in myapp.

Flask configuration paths

So I have this code in my init:
app = Flask(__name__)
app.config.from_object('config')
app.config.from_pyfile('app.cfg')
My folder structure goes like this:
/config.py
/app.cfg
/app/__init__.py
However, this code seems to find my config.py in the root, but it's searching inside my app folder for my app.cfg. How do I make it look for my configuration file in the correct place, without having to put it in my app folder.
Should I be using from object and rename my app.cfg to app.py
According to the official docs (http://flask.pocoo.org/docs/0.10/api/#flask.Config):
from_pyfile(filename, silent=False)
Updates the values in the config from a Python file. This function behaves as if the file was imported as module with thefrom_object() function.
Parameters: filename – the filename of the config. This can either be an absolute filename or a filename relative to the root path.silent – set to True if you want silent failure for missing files.
So, if you don't want to put your cfg file in your app folder one of the things you can do is to set relative route to root folder (that seems to be "./app" directory) in your "from_pyfile" call.
from_pyfile('../app.cfg')
should work..

Accessing resource files in Python unit tests & main code

I have a Python project with the following directory structure:
project/
project/src/
project/src/somecode.py
project/src/mypackage/mymodule.py
project/src/resources/
project/src/resources/datafile1.txt
In mymodule.py, I have a class (lets call it "MyClass") which needs to load datafile1.txt. This sort of works when I do:
open ("../resources/datafile1.txt")
Assuming the code that creates the MyClass instance created is run from somecode.py.
The gotcha however is that I have unit tests for mymodule.py which are defined in that file, and if I leave the relative pathname as described above, the unittest code blows up as now the code is being run from project/src/mypackage instead of project/src and the relative filepath doesn't resolve correctly.
Any suggestions for a best practice type approach to resolve this problem? If I move my testcases into project/src that clutters the main source folder with testcases.
I usually use this to get a relative path from my module. Never tried in a unittest tho.
import os
print(os.path.join(os.path.dirname(__file__),
'..',
'resources'
'datafile1.txt'))
Note: The .. tricks works pretty well, but if you change your directory structure you would need to update that part.
On top of the above answers, I'd like to add some Python 3 tricks to make your tests cleaner.
With the help of the pathlib library, you can explicit your ressources import in your tests. It even handles the separators difference between Unix (/) and Windows ().
Let's say we have a folder structure like this :
`-- tests
|-- test_1.py <-- You are here !
|-- test_2.py
`-- images
|-- fernando1.jpg <-- You want to import this image !
`-- fernando2.jpg
You are in the test_1.py file, and you want to import fernando1.jpg. With the help to the pathlib library, you can read your test resource with an object oriented logic as follows :
from pathlib import Path
current_path = Path(os.path.dirname(os.path.realpath(__file__)))
image_path = current_path / "images" / "fernando1.jpg"
with image_path.open(mode='rb') as image :
# do what you want with your image object
But there's actually convenience methods to make your code more explicit than mode='rb', as :
image_path.read_bytes() # Which reads bytes of an object
text_file_path.read_text() # Which returns you text file content as a string
And there you go !
in each directory that contains Python scripts, put a Python module that knows the path to the root of the hierarchy. It can define a single global variable with the relative path. Import this module in each script. Python searches the current directory first so it will always use the version of the module in the current directory, which will have the relative path to the root of the current directory. Then use this to find your other files. For example:
# rootpath.py
rootpath = "../../../"
# in your scripts
from rootpath import rootpath
datapath = os.path.join(rootpath, "src/resources/datafile1.txt")
If you don't want to put additional modules in each directory, you could use this approach:
Put a sentinel file in the top level of the directory structure, e.g. thisisthetop.txt. Have your Python script move up the directory hierarchy until it finds this file. Write all your pathnames relative to that directory.
Possibly some file you already have in the project directory can be used for this purpose (e.g. keep moving up until you find a src directory), or you can name the project directory in such a way to make it apparent.
You can access files in a package using importlib.resources (mind Python version compatibility of the individual functions, there are backports available as importlib_resources), as described here. Thus, if you put your resources folder into your mypackage, like
project/src/mypackage/__init__.py
project/src/mypackage/mymodule.py
project/src/mypackage/resources/
project/src/mypackage/resources/datafile1.txt
you can access your resource file in code without having to rely on inferring file locations of your scripts:
import importlib.resources
file_path = importlib.resources.files('mypackage').joinpath('resources/datafile1.txt')
with open(file_path) as f:
do_something_with(f)
Note, if you distribute your package, don't forget to include the resources/ folder when creating the package.
The filepath will be relative to the script that you initially invoked. I would suggest that you pass the relative path in as an argument to MyClass. This way, you can have different paths depending on which script is invoking MyClass.

Categories

Resources