How to write a Python package/module? - python

As I'm a novice, I started learning python by writing simple programs using python GUI .. everytime, when I try to clear the console I need to define the following few lines of code
import os
def cls():
os.system('cls')
print("Console Cleared")
and later I call it as
cls()
now I'm tired of writing the above code again and again(every time I open the gui window )..
so, I want to create a module called cls for future use to save my time ..
in the end I'll call it as follows
import cls
cls()
is there a way to do this ...
Thanks !

Well, a solution is to create a directory to add your modules and add this directory to the Python pat. For example, you can create a directory at, let us say, C:\mypymodules and put a cls.py file there with your function.
Now, let us add this directory to the Python path. Follow these instructions, just inserting C:\mypymodules in place of the directories mentioned there. Now, open a new command line window and try to import the module.
Another solution is to use distutils*. Instead of creating your own modules directory, in the same directory of your cls.py file create a file named setup.py with the following content:
from distutils.core import setup
setup(name='cls', py_modules=['cls'])
Then, just execute it:
> python setup.py install
This may install your module in the default Python library directories. Actually, this is the way (or, better yet, one of the ways) to pack, manage or python packages.
(I am not really using Windows, so some details may be broken. Nonetheless, I believe the general concepts are the same.)
* Some may argue about using setuptools but I think it is really overkill for your case. Anyway, if you want to learn more, see this question.

If you put your cls() function in a file called cls.py, and put that either in the same directory as the program that's calling it or else somewhere in your PYTHONPATH on your system, then you can use your function like this:
import cls
cls.cls()
This is because the cls() function is inside the cls module (the name of the module is determined by the file name).
If you want to just be able to do cls() then do this:
from cls import cls
cls()

You can spice it up a little bit by making your module cross platform. Here it is:
import os, sys
def cls():
if 'win' in sys.paltform:
os.system('cls')
print 'Console cleared'
else:
os.system('clear')
print 'Console cleared'
Now, you can use it in any other script using:
from cls import cls
cls()

Related

Is this the approved way to acess data adjacent to/packaged with a Python script?

I have a Python script that needs some data that's stored in a file that will always be in the same location as the script. I have a setup.py for the script, and I want to make sure it's pip installable in a wide variety of environments, and can be turned into a standalone executable if necessary.
Currently the script runs with Python 2.7 and Python 3.3 or higher (though I don't have a test environment for 3.3 so I can't be sure about that).
I came up with this method to get the data. This script isn't part of a module directory with __init__.py or anything, it's just a standalone file that will work if just run with python directly, but also has an entry point defined in the setup.py file. It's all one file. Is this the correct way?
def fetch_wordlist():
wordlist = 'wordlist.txt'
try:
import importlib.resources as res
return res.read_binary(__file__, wordlist)
except ImportError:
pass
try:
import pkg_resources as resources
req = resources.Requirement.parse('makepw')
wordlist = resources.resource_filename(req, wordlist)
except ImportError:
import os.path
wordlist = os.path.join(os.path.dirname(__file__), wordlist)
with open(wordlist, 'rb') as f:
return f.read()
This seems ridiculously complex. Also, it seems to rely on the package management system in ways I'm uncomfortable with. The script no longer works unless it's been pip-installed, and that also doesn't seem desirable.
Resources living on the filesystem
The standard way to read a file adjacent to your python script would be:
a) If you've got python>=3.4 I'd suggest you use the pathlib module, like this:
from pathlib import Path
def fetch_wordlist(filename="wordlist.txt"):
return (Path(__file__).parent / filename).read_text()
if __name__ == '__main__':
print(fetch_wordlist())
b) And if you're still using a python version <3.4 or you still want to use the good old os.path module you should do something like this:
import os
def fetch_wordlist(filename="wordlist.txt"):
with open(os.path.join(os.path.dirname(__file__), filename)) as f:
return f.read()
if __name__ == '__main__':
print(fetch_wordlist())
Also, I'd suggest you capture exceptions in the outer callers, the above methods are standard way to read files in python so you don't need wrap them in a function like fetch_wordlist, said otherwise, reading files in python is an "atomic" operation.
Now, it may happen that you've frozen your program using some freezer such as cx_freeze, pyinstaller or similars... in that case you'd need to detect that, here's a simple way to check it out:
a) using os.path:
if getattr(sys, 'frozen', False):
app_path = os.path.dirname(sys.executable)
elif __file__:
app_path = os.path.dirname(__file__)
b) using pathlib:
if getattr(sys, 'frozen', False):
app_path = Path(sys.executable).parent
elif __file__:
app_path = Path(__file__).parent
Resources living inside a zip file
The above solutions would work if the code lives on the file system but it wouldn't work if the package is living inside a zip file, when that happens you could use either importlib.resources (new in version 3.7) or pkg_resources combo as you've already shown in the question (or you could wrap up in some helpers) or you could use a nice 3rd party library called importlib_resources that should work with the old&modern python versions:
pypi: https://pypi.org/project/importlib_resources/
documentation: https://importlib-resources.readthedocs.io/en/latest/
Specifically for your particular problem I'd suggest you take a look to this https://importlib-resources.readthedocs.io/en/latest/using.html#file-system-or-zip-file.
If you want to know what that library is doing behind the curtains because you're not willing to install any 3rd party library you can find the code for py2 here and py3 here in case you wanted to get the relevant bits for your particular problem
I'm going to go out on a limb and make an assumption because it may drastically simplify your problem. The only way I can imagine that you can claim that this data is "stored in a file that will always be in the same location as the script" is because you created this data, once, and put it in a file in the source code directory. Even though this data is binary, have you considered making the data a literal byte-string in a python file, and then simply importing it as you would anything else?
You're right about the fact that your method of reading a file is a bit unnecessarily complex. Unless you have got a really specific reason to use the importlib and pkg_resources modules, it's rather simple.
import os
def fetch_wordlist():
if not os.path.exists('wordlist.txt'):
raise FileNotFoundError
with open('wordlist.txt', 'rb') as wordlist:
return wordlist.read()
You haven't given much information regarding your script, so I cannot comment on why it doesn't work unless it's installed using pip. My best guess: your script is probably packed into a python package.

How can I get the directory from a script called by another script in python via a function imported [duplicate]

When writing throwaway scripts it's often needed to load a configuration file, image, or some such thing from the same directory as the script. Preferably this should continue to work correctly regardless of the directory the script is executed from, so we may not want to simply rely on the current working directory.
Something like this works fine if defined within the same file you're using it from:
from os.path import abspath, dirname, join
def prepend_script_directory(s):
here = dirname(abspath(__file__))
return join(here, s)
It's not desirable to copy-paste or rewrite this same function into every module, but there's a problem: if you move it into a separate library, and import as a function, __file__ is now referencing some other module and the results are incorrect.
We could perhaps use this instead, but it seems like the sys.argv may not be reliable either.
def prepend_script_directory(s):
here = dirname(abspath(sys.argv[0]))
return join(here, s)
How to write prepend_script_directory robustly and correctly?
I would personally just os.chdir into the script's directory whenever I execute it. It is just:
import os
os.chdir(os.path.split(__file__)[0])
However if you did want to refactor this thing into a library, you are in essence wanting a function that is aware of its caller's state. You thus have to make it
prepend_script_directory(__file__, blah)
If you just wanted to write
prepend_script_directory(blah)
you'd have to do cpython-specific tricks with stack frames:
import inspect
def getCallerModule():
# gets globals of module called from, and prints out __file__ global
print(inspect.currentframe().f_back.f_globals['__file__'])
I think the reason it doesn't smell right is that $PYTHONPATH (or sys.path) is the proper general mechanism to use.
You want pkg_resources
import pkg_resources
foo_fname = pkg_resources.resource_filename(__name__, "foo.txt")

How to call function fron other python projects into anonther project stored in same directory?

I have 10 different python projects stored in one folder (F:\Python_Code...). I want to call user define functions from 10 different projects into the last project (Say Project11) and by running Project11, all my 10 projects should run one by one.
I have tried multiple ways like os.path() and from project1 import function, etc. but no one work. I read about the change in PYTHONPATH, but I am still not able to do that. I am using PyCharm. Can anyone help me to solve the problem?
soni smit!
Your solution wasn't that far away.
First you have to import the whole file with:
from . import filename
or just
import filename
if the file is in the same directory as your main file.
then you can call a function from that file with:
filename.functionname(arg1, arg2, ...)
I hope, it works for you!
~ostue
It's not a good idea to reference an upper-level directory for importing your packages.
If you're sure of what you're doing, you can change the working directory using os.chdir(path_to_dir_that_can_access_all_your_modules).
If you need the flexibility to import your libs in a dynamic way, try using importlib.import_module('module_name').
ex.:
import os, importlib
def import_module(base_path, module_path):
try:
backup_wd = os.getcwd() # backup original working directory
os.chdir(base_path) # change directory
return importlib.import_module(module_path) # import and return your module
except:
# Handle problems
...
finally:
os.chdir(backup) # go back to original directory in any case
project10_module = import_module('F:\Python_Code', 'project10.utils.yourmodule')
module_instance = project10_module(args)

python get the script which imported my script

I want to make my own programming language based on python which will provide additional features that python wasn't provide, for example to make multiline anonymous function with custom syntax. I want my programming language is so simple to be used, just import my script, then I read the script file which is imported my script, then process it's code and stop anymore execution of the script which called my script to prevent error on syntax...
Let say there are 2 py file, main.py and MyLanguage.py
The main.py imported MyLanguage.py
Then how to get the main.py file from MyLanguage.py if main.py can be another name(Dynamic Name)?
Additional information:
I using python 3.4.4 on Windows 7
Like Colonder, I believe the project you have in mind is far more difficult than you imagine.
But, to get you started, here is how to get the main.py file from inside MyLanguage.py. If your importing module looks like this
# main.py
import MyLanguage
if __name__ == "__main__":
print("Hello world from main.py")
and the module it is importing looks like this, in Python 3:
#MyLanguage.py
import inspect
def caller_discoverer():
print('Importing file is', inspect.stack()[-1].filename)
caller_discoverer()
or (edit) like this, in Python 2:
#MyLanguage.py
import inspect
def caller_discoverer():
print 'Importing file is', inspect.stack()[-1][1]
caller_discoverer()
then the output you will get when you run main.py is
Importing file is E:/..blahblahblah../StackOverflow-3.6/48034902/main.py
Hello world from main.py
I believe this answers the question you asked, though I don't think it goes very far towards achieving what you want. The reason for my scepticism is simple: the import statement expects a file containing valid Python, and if you want to import a file with your own non-Python syntax, then you are going to have to do some very clever stuff with import hooks. Without that, your program will simply fail at the import statement with a syntax error.
Best of luck.

Python Calling Function from Another File

I am using Python 2.7 on Windows 7 Professional.
I am trying to call a function saved in another file to run in this file's code.
Function called dosomething is found in anotherfile.py
anotherfile.py is in the same directory as current code.
My call in this file is simple:
import anotherfile
print anotherfile.dosomething
I am getting an error: No module named anotherfile
The problem is the same as I found in this post
I don't understand the solution but I'd like any insight?
Thank you.
EDIT: The other question/answers discuss resetting CLASSPATH and setting PYTHONPATH. I explored this but was not sure how to do this. Perhaps relevant?
Let us have two files in the same directory. Files are called main.py and another.py.
First write a method in another.py:
def do_something():
return "This is the do something method"
Then call the method from main.py. Here is the main.py:
import another
print another.do_something()
Run main.py and you will get output like this:
This is the do something method
N.B.: The above code is being executed using Python 2.7 in Windows 10.
Specify the module then the file then the import like so:
from this_module.anotherfile import dosomething
or if you want all functions from "anotherfile.py"
from this_module.anotherfile import *
and then you can call the "dosomething" command without the "anotherfile" prefix.
I ran into same problem. After ample of trials, I ended up solving it with the below mentioned solution:
Make sure your current file and anotherfile.py lies in same location of system path.
Say your another.py and current file lies at location : "C:/Users/ABC"
In case, one is not aware of system path. Use below code in current file:
import sys
print(sys.path)
import sys
sys.path.append('/C:/Users/ABC/')
Then you do below code in same current code:
from another import dosomething
I found the issue. Python was looking in another directory for the files. I explicitly set my working directory as the path to where thisfile.py and anotherfile.py reside and it works. Thank you for all the quick replies.

Categories

Resources