Pycharm Unit Testing without restructuring - unit-testing

I've been using PyCharm to develop a submodule to drop into several other projects. I have a Tests directory containing my unit tests and I'd like to run them from PyCharm, but when I test any of my code that contains relative imports, I get:
"ValueError: attempted relative import beyond top-level package"
My structure is roughly:
A
____init____.py
...
B
____init____.py
...
Tests
____init____.py
...
Where I am testing a function in the B module that uses relative imports to import A:
from ..A import some_fn
This thread here pycharm and unittesting - structuring project references marking the test directory as such, but when I right click it, I only have the option to mark it as a source root which has no effect.
I also can't really change from relative to absolute imports because it will break my ability to use it as a submodule in other projects. Any advice on how to fix this would be much appreciated.
Update: I also came across this thread How to properly use relative or absolute imports in Python modules? and I'm not a huge fan of the solution (I'd prefer not to have mirror imports in a try/except block), but it does somewhat solve the problem. I would still appreciate a more elegant solution, but if not, that does actually fix the error.

The problem here is that A and B are different packages. You want them both to be subpackages of the the myproj package.
I think all you are missing is a __init__.py file in the parent directory. Allowing you to relatively import something in B from something in A
myproj/
├── A
│ └── __init__.py
├── B
│ └── __init__.py
└── __init__.py

Related

Do I need to place __init__.py in each directory in a directory tree leading to my class?

I'm building a Django project with Python 3.6. I have created this directory structure ...
project
- manage.py
- scripts
- run_commands.py
- commons
- util
- __init__.py
- my_class.py
The contents of init.py are
from . import my_class
In another class, I attempt to import my MyClass like this
from commons.util import MyClass
but I'm getting this error
ModuleNotFoundError: No module named 'commons'
Am I creating my init.py properly?
It looks like the problem is that MyClass is not located in commons.util, because you only imported the module named my_class, not the class itself.
Instead the file commons/util/__init__.py should contain the following import:
from .my_class import MyClass
I don't think this will solve your problem, because you would be getting a different error than the one shown, but you will get errors for this eventually.
Update
First, I'd recommend reading this answer for a good explanation for how imports work in python.
Basically, when you execute from commons.util import MyClass, the interpreter scans the contents of sys.path for a module named commons.
I assume you didn't set sys.path to include your project folder, hence the ModuleNotFoundError.
TLDR; you have 2 options:
Manually set sys.path in run_commands.py to check your project folder (Don't do this!)
Use Django's Command class
To use Django's Command class, you will need to adjust your project folder similar to the following:
project
- manage.py
- commons
- management
- commands
run_commands.py
- util
- __init__.py
- my_class.py
Now in run_commands.py:
from django.core.management.base import BaseCommand
from commons.util import MyClass
class Command(BaseCommand):
def handle(*args, **options):
print("handling", MyClass)
You can execute the new command with the following:
python3 manage.py run_commands
It used to be the case that yes, you need to put an __init__.py in every directory that is going to be treated as a python module as without an __init__.py python wouldn't look inside that directory for importable code.
- project
- __init__.py
- commons
- __init__.py
- util
- __init__.py
- my_class.py
But as Reinstate Monica points out below this is no longer true as of Python 3.3+. So, depending on your version of Python you will need to make an informed decision.
Note, you might or might not need an __init__.py in the root project directory (if you need them at all), it depends if it has definitions that are part of the source tree. But you won't need it if it's just a container, like you see in the way most Django projects are organised, for example.
https://docs.python.org/3/tutorial/modules.html
https://docs.python.org/3/tutorial/modules.html#packages

create test modules in pytest with the same name as test modules in other packages/directories

py.test gives me an "import file mismatch" error. I believe its because I have test modules with the same name under different packages (see below).
Someone posted an identical question here: py.test - test discovery failure when tests in different directories are called the same. Unfortunately, none of the responses work for me.
I've also read the manual. I've tried not including the __init__.py files in the test directories per the manual but that doesn't seem to make a difference.
The "app_class1" and "app_class2" directories each contain a test module named test_create.py.
Here is how my code is organized
/app
-setup.py
/app
-app.py
-__init__.py
/test
- __init__.py
/app_class1
- __init__.py
- test_create.py
/app_class2
- __init__.py
- test_create.py
Any help is greatly appreciated. Thank you.
P.S. I would have commented on the referenced conversation but my reputation isn't high enough to do so.

Using "depends" in webassets bundles

I'm using webassets in my Flask application using Flask-Assets and I'm having trouble with the depends option when creating bundles.
In my case I'm bundling LESS files from the following directory structure:
/static
\_ /css
\_ /bootstrap
| \_ bootstrap.less // This file #imports variables.less and custom.less
| \_ variables.less
\_ custom.less
My bundle looks like this:
css = Bundle(
"css/bootstrap/bootstrap.less",
filters="less, cssmin",
output="dist/base.css",
depends="**/*.less"
)
With these settings, the LESS files are rebuilt whenever a change is made to either bootstrap.less or custom.less but NOT variables.less.
From what I understand, the expression used for the depends option is a glob instruction and using the one above should simply go through all directories recursively and pick up any LESS files. However, it never seems to pick up on any changes made to variables.less.
In my attempts to fix this, I've tried the following options for depends:
"*.less" - Doesn't pick up anything (as it's searching in the root of the project directory, I believe, where there are no LESS files anyway)
"**/*.less, myproject/static/css/bootstrap/variables.less" - Doesn't pick up on any changes in any file at all.
"**/*.less, myproject/static/css/bootstrap/variables.less" - Same as the one above.
"myproject/static/css/bootstrap/variables.less" - Strangely enough, this picks up on changes made to both variables.less AND any other LESS files (such as custom.less).
In essence, the last item is the "solution" for my problem but I have no idea why it works the way it does, so it doesn't sit well with me. Can anyone provide an explanation or a nudge in the right direction here?
Thanks!
The problem here is that recursive glob ** is not supported in glob module (yet; see issue 13968).
Here's how I have set this up in one of my projects (not sure if that would suit your needs):
less/
├── bootstrap/
│  ├── bootstrap.less
│   ├── variables.less
│   └── ...
└── style.less # #import "bootstrap/bootstrap.less";
Bundle configuration:
css = Bundle(
"less/style.less",
filters="less, cssmin",
output="css/all.css",
depends="less/bootstrap/*.less"
)
I fixed this by installing the glob2 module. My depends='**/*.scss' then started working as I expected, watching for changes in nested directories as well as the top level.

Django: How to specify path to settings file

I know this question has already been asked multiple times but I still can't seem to find a solution that works for me. My Django project folder looks like this:
my_project
__init__.py
manage.py
my_first_app
my_second_app
core
Now the "core" folder looks like this:
__init__.py
some_other_stuff.py
settings
__init__.py
prod.py
dev.py
local.py -> dev.py
local.py is a symbolic link pointing to the right settings file, dev.py on my machine, prod.py in production.
Here's my problem: when I try to use manage.py, I get a weird error ImproperlyConfigured: The SECRET_KEY setting must not be empty. When I pass the path to the settings file local.py as an argument (--settings=core.settings.local) it runs fine. I figured the problem was that Django didn't know where to look for the settings file. How can I tell him (her?) where to look?
I already tried exporting the path to the env (export DJANGO_SETTINGS_MODULE=core.settings.local) and setting the PYTHONPATH to the parent directory, to no avail.
The primary use of __init__.py is to initialize Python packages. The easiest way to demonstrate this is to take a look at the structure of a standard Python module.
package/
__init__.py
file1.py
file2.py
As you can see in the structure above the inclusion of the __init__.py file in a directory indicates to the Python interpreter that the directory should be treated like a Python package
__init__.py can be an empty file but it is often used to perform setup needed for the package(import things, load things into path, etc).
One common thing to do in your __init__.py is to import selected Classes, functions, etc into the package level so they can be convieniently imported from the package.
In our example above we can say that file.py has the Class File. So without anything in our __init__.py you would import with this syntax:
from package.file import File
However you can import File into your __init__.py to make it available at the package level:
# in your __init__.py
from file1 import File
# now import File from package
from package import File
Source
So for conclusion, when you call import in __init__.py in a package mypackage, it's like you use package as a simple python file, that's what my solution do:
from .local import * in __init__.py
I haven't use this before in the settings case but I use it when I wanna to subdivide my models in a Django app, models.py --> models package, ./manage syndb doesn't discover my models declared, I found so this solution that's similar. You can find more details here
Last thing, I'm sure there's others solution to your problem, but this can be the most simple.
Good luck
You are in import hell somewhere. Had this problem too one time. The only way to find out where the root of your problem is, might be to disable all apps, try starting the server, enable the first app, start the server, enable the next etc.
BTW: your project layout should not be used from Django 1.4 onward. https://docs.djangoproject.com/en/dev/releases/1.4/#updated-default-project-layout-and-manage-py
I'd try to use the new layout and hope that it 'just works'.
I think you need to change the name of the file that the manage.py is looking for.
try:
imp.find_module('settings') # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
sys.exit(1)
If you had the settings.py file in the same directory simple changing the 'settings' to 'local' would have worked.
But, since you have it in a different directory, I think you need to configure the settings. Refer to this: https://docs.djangoproject.com/en/dev/topics/settings/#using-settings-without-setting-django-settings-module
from django.conf import settings
settings.configure(DEBUG=True, TEMPLATE_DEBUG=True,
TEMPLATE_DIRS=('/home/web-apps/myapp', '/home/web-apps/base'))
Hope that helps.

Go build: "Cannot find package" (even though GOPATH is set)

Even though I have GOPATH properly set, I still can't get "go build" or "go run" to find my own packages. What am I doing wrong?
$ echo $GOROOT
/usr/local/go
$ echo $GOPATH
/home/mitchell/go
$ cat ~/main.go
package main
import "foobar"
func main() { }
$ cat /home/mitchell/go/src/foobar.go
package foobar
$ go build main.go
main.go:3:8: import "foobar": cannot find package
It does not work because your foobar.go source file is not in a directory called foobar. go build and go install try to match directories, not source files.
Set $GOPATH to a valid directory, e.g. export GOPATH="$HOME/go"
Move foobar.go to $GOPATH/src/foobar/foobar.go and building should work just fine.
Additional recommended steps:
Add $GOPATH/bin to your $PATH by: PATH="$GOPATH/bin:$PATH"
Move main.go to a subfolder of $GOPATH/src, e.g. $GOPATH/src/test
go install test should now create an executable in $GOPATH/bin that can be called by typing test into your terminal.
Although the accepted answer is still correct about needing to match directories with package names, you really need to migrate to using Go modules instead of using GOPATH. New users who encounter this problem may be confused about the mentions of using GOPATH (as was I), which are now outdated. So, I will try to clear up this issue and provide guidance associated with preventing this issue when using Go modules.
If you're already familiar with Go modules and are experiencing this issue, skip down to my more specific sections below that cover some of the Go conventions that are easy to overlook or forget.
This guide teaches about Go modules: https://golang.org/doc/code.html
Project organization with Go modules
Once you migrate to Go modules, as mentioned in that article, organize the project code as described:
A repository contains one or more modules. A module is a collection of
related Go packages that are released together. A Go repository
typically contains only one module, located at the root of the
repository. A file named go.mod there declares the module path: the
import path prefix for all packages within the module. The module
contains the packages in the directory containing its go.mod file as
well as subdirectories of that directory, up to the next subdirectory
containing another go.mod file (if any).
Each module's path not only serves as an import path prefix for its
packages, but also indicates where the go command should look to
download it. For example, in order to download the module
golang.org/x/tools, the go command would consult the repository
indicated by https://golang.org/x/tools (described more here).
An import path is a string used to import a package. A package's
import path is its module path joined with its subdirectory within the
module. For example, the module github.com/google/go-cmp contains a
package in the directory cmp/. That package's import path is
github.com/google/go-cmp/cmp. Packages in the standard library do not
have a module path prefix.
You can initialize your module like this:
$ go mod init github.com/mitchell/foo-app
Your code doesn't need to be located on github.com for it to build. However, it's a best practice to structure your modules as if they will eventually be published.
Understanding what happens when trying to get a package
There's a great article here that talks about what happens when you try to get a package or module: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16
It discusses where the package is stored and will help you understand why you might be getting this error if you're already using Go modules.
Ensure the imported function has been exported
Note that if you're having trouble accessing a function from another file, you need to ensure that you've exported your function. As described in the first link I provided, a function must begin with an upper-case letter to be exported and made available for importing into other packages.
Names of directories
Another critical detail (as was mentioned in the accepted answer) is that names of directories are what define the names of your packages. (Your package names need to match their directory names.) You can see examples of this here: https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc
With that said, the file containing your main method (i.e., the entry point of your application) is sort of exempt from this requirement.
As an example, I had problems with my imports when using a structure like this:
/my-app
├── go.mod
├── /src
├── main.go
└── /utils
└── utils.go
I was unable to import the code in utils into my main package.
However, once I put main.go into its own subdirectory, as shown below, my imports worked just fine:
/my-app
├── go.mod
├── /src
├── /app
| └── main.go
└── /utils
└── utils.go
In that example, my go.mod file looks like this:
module git.mydomain.com/path/to/repo/my-app
go 1.14
When I saved main.go after adding a reference to utils.MyFunction(), my IDE automatically pulled in the reference to my package like this:
import "git.mydomain.com/path/to/repo/my-app/src/my-app"
(I'm using VS Code with the Golang extension.)
Notice that the import path included the subdirectory to the package.
Dealing with a private repo
If the code is part of a private repo, you need to run a git command to enable access. Otherwise, you can encounter other errors This article mentions how to do that for private Github, BitBucket, and GitLab repos: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git-repositories-dfe795068db4
This issue is also discussed here: What's the proper way to "go get" a private repository?
I solved this problem by set my go env GO111MODULE to off
go env -w GO111MODULE=off
Note: setting GO111MODULE=off will turn off the latest GO Modules feature.
Reference: Why is GO111MODULE everywhere, and everything about Go Modules (updated with Go 1.17)
GO111MODULE with Go 1.16
As of Go 1.16, the default behavior is GO111MODULE=on, meaning that if
you want to keep using the old GOPATH way, you will have to force Go
not to use the Go Modules feature:
export GO111MODULE=off
In the recent go versions from 1.14 onwards, we have to do go mod vendor before building or running, since by default go appends -mod=vendor to the go commands.
So after doing go mod vendor, if we try to build, we won't face this issue.
Edit: since you meant GOPATH, see fasmat's answer (upvoted)
As mentioned in "How do I make go find my package?", you need to put a package xxx in a directory xxx.
See the Go language spec:
package math
A set of files sharing the same PackageName form the implementation of a package.
An implementation may require that all source files for a package inhabit the same directory.
The Code organization mentions:
When building a program that imports the package "widget" the go command looks for src/pkg/widget inside the Go root, and then—if the package source isn't found there—it searches for src/widget inside each workspace in order.
(a "workspace" is a path entry in your GOPATH: that variable can reference multiple paths for your 'src, bin, pkg' to be)
(Original answer)
You also should set GOPATH to ~/go, not GOROOT, as illustrated in "How to Write Go Code".
The Go path is used to resolve import statements. It is implemented by and documented in the go/build package.
The GOPATH environment variable lists places to look for Go code.
On Unix, the value is a colon-separated string.
On Windows, the value is a semicolon-separated string.
On Plan 9, the value is a list.
That is different from GOROOT:
The Go binary distributions assume they will be installed in /usr/local/go (or c:\Go under Windows), but it is possible to install them in a different location.
If you do this, you will need to set the GOROOT environment variable to that directory when using the Go tools.
TL;DR: Follow Go conventions! (lesson learned the hard way), check for old go versions and remove them. Install latest.
For me the solution was different. I worked on a shared Linux server and after verifying my GOPATH and other environment variables several times it still didn't work. I encountered several errors including 'Cannot find package' and 'unrecognized import path'. After trying to reinstall with this solution by the instructions on golang.org (including the uninstall part) still encountered problems.
Took me some time to realize that there's still an old version that hasn't been uninstalled (running go version then which go again... DAHH) which got me to this question and finally solved.
Running go env -w GO111MODULE=auto worked for me
Without editing GOPATH or anything, in my case just worked the following:
/app
├── main.go
├── /utils
└── utils.go
Import packages where needed. This can be unintuitive, because it isn't relative to the app path. You need to add the app in the package path too:
main.go:
package main
import(
"app/util"
)
Being in app directory, run:
go mod init app
go get <package/xxx>
go build main.go / go run main.go
You should be good to go.
GOPATH = /home/go
appPath = /home/projects/app
Create a proper go.mod and go.sum with go mod init app (delete old before)
After that resolve all dependencies like missing packages with go get github.com/example/package.
In simple words you can solve the import problem even with GO111MODULE=on with the following syntax for import:
import <your_module_name>/<package_name>
your_module_name -> module name which can be found in the go.mod file of the module as the first line.
example: github.com/nikhilg-hub/todo/ToDoBackend
package_name -> Path to your package within module.
example: orm
So the import statement would look like:
import "github.com/nikhilg-hub/todo/ToDoBackend/orm"
According to me we need to specify the module name + package name because we may need a same package name in two or more different modules.
Note: If you are importing a package from same module still you need to specify the full import path like above.
If you have a valid $GOROOT and $GOPATH but are developing outside of them, you might get this error if the package (yours or someone else's) hasn't been downloaded.
If that's the case, try go get -d (-d flag prevents installation) to ensure the package is downloaded before you run, build or install.
GOROOT should be set to your installation directory (/usr/local/go).
GOPATH should be set to your working directory (something like /home/username/project_folder).
GOPATH should not be set to GOROOT as your own project may need to install packages, and it's not recommended to have those packages in the Go installation folder. Check out this link for more.
For me none of the above solutions worked. But my go version was not the latest one. I have downloaded the latest version and replaced the older version in my mac os after that it worked perfectly.
I had a similar problem when building a docker file:
[1/3] STEP 9/9: RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go
api/v1alpha1/XXX.go:5:2: cannot find package "." in:
/workspace/client/YYY/YYY.go
This only appeared when building the Dockerfile, building locally worked fine.
The problem turned out to be a missing statement in my Dockerfile:
COPY client/ client/
I do not understand why this happens, we must be able to import from wherever our file is in its nest, since I have discovered that if we have more than one nest this will throw an error.
package main
import (
"fmt"
"indexer/source/testPackage3" // this will be show a GOROOT error.
"indexer/testPackage"
"indexer/testPackage2"
)
func main() {
fmt.Println("Agile content indexer -")
fmt.Println(testPackage.Greeting())
fmt.Println(testPackage2.Greeting())
fmt.Println(testPackage3.Greeting())
}
├── testPackage2
│ ├── entry2.go
│ └── source
│ └── entry3.go
To conclude, I just want to tell you, the entry3.go file will not work when imported into my main file, which in this case is (main.go), I do not understand why, therefore, I have simply chosen to use a depth folder in the packages I need to export.
entry.go, entry2.go will work perfectly when imported, but entry3.go will not work..
In addition, both the directory and the name of the package must be the same so that they work properly when importing them.
Have you tried adding the absolute directory of go to your 'path'?
export PATH=$PATH:/directory/to/go/