0

PyCharm isn't importing/resolving properly. The code runs okay, but it isn't getting code completion, and is flagging up as errors (red squiggly lines).

The code that demonstrates this is as follows:

from turtle import *

forward(40)
right(45)
forward(80)


import turtle

t = turtle.Turtle()

t.forward(40)
t.right(45)
t.forward(80)

And a picture that demonstrates the issue in PyCharm:

https://prnt.sc/ni9dvk

Does anyone have any ideas on how to solve this problem? It's pretty annoying to not be able to use from X import Y.

cdlane
  • 40,441
  • 5
  • 32
  • 81
Jack_Hu
  • 857
  • 6
  • 17
  • Do not use `from X import *`, regardless of what package `X` is or what its documentation says, It will only lead to bugs later down the road. Also, Pycharm is warning that `import turtle` violates PEP8 by having an `import` statement not at the top of the script. – DeepSpace Apr 29 '19 at 12:35
  • I know about the `import turtle` PEP8 thing, it's only there to demonstrate that it works fine for normal imports, so it's likely not an interpreter error..? Either way, the point still stands... The `from turtle import *` should work, and code completion for the `forward(someInt)` should work properly... Instead IDE alerts get thrown up, even if Python is fine running it. – Jack_Hu Apr 29 '19 at 12:37
  • 1
    If you run that program, it runs as expected... Am I missing something? As far as I can tell, it's just PyCharm that doesn't like it. – Jack_Hu Apr 29 '19 at 12:42

3 Answers3

2

As a rule of thumb, do not use from X import *, regardless of what package X is or what its documentation says, It will only lead to bugs later down the road.

Why "star imports" should be avoided

from turtle import *

def forward():
    print('forward')

forward(45)

What do you think will happen?

turtle.forward is overwritten by the locally defined forward function, and we will get an error TypeError: forward() takes 0 positional arguments but 1 was given

Why it works in this case

from turtle import *

forward(40)

To understand why the above works even though Pycharm says that forward is not defined we have to see how the turtle module is implemented, and then understand how Python imports work and how Pycharm checks for "definitions" of used names.

turtle.py

tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
               'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
        'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
        'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
        'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
        'register_shape', 'resetscreen', 'screensize', 'setup',
        'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
        'window_height', 'window_width']
_tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
        'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
        'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
        'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
        'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
        'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
        'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
        'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
        'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
        'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
        'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
        'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
        'write', 'xcor', 'ycor']
_tg_utilities = ['write_docstringdict', 'done']

__all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
           _tg_utilities + ['Terminator'])  

...

As you can see, it simply prepares some lists of strings (which are names of functions/classes/etc) then concats everything to a single list and assigns everything to the __all__ global variable.

I will not go into much details about __all__ (since there are several Q&A on SO on that topic, for example Can someone explain __all__ in Python?), but basically it tells the interpreter what names should be available when doing from X import *.

When you are doing from turtle import * then using forward, right etc, they are available to use since their name is inside __all__, but Pycharm has no idea that they will be exposed by __all__ at runtime.

DeepSpace
  • 78,697
  • 11
  • 109
  • 154
  • Thanks for clarifying that a bit. :) - Out of curiosity, is the only way for the methods to be detected by PyCharm to instantiate the object (as done in the second part of my example), or is there another, more sophisticated import statement I can use? --- [BTW: I'm brand new to Python, but have been around Java, .Net and PHP for over a decade] – Jack_Hu Apr 29 '19 at 13:01
  • @Jack_Hu You can do `from turtle import forward` but Pycharm will still not be able to know that `forward` exists. The best way will be to instantiate an object. That's how these functions are supposed to be used. – DeepSpace Apr 29 '19 at 13:04
  • Ahh right. That's what I thought. I don't like the whole idea of using asterisks anyway. Instantiating feels a lot more familiar to me. Thanks for your help. :) – Jack_Hu Apr 29 '19 at 13:06
0

What's going on here is that Python turtle is unusual in that it has two different interfaces, a functional one and an object-oriented one. If you use the object-oriented one, everything should work fine:

from turtle import Screen, Turtle

yertle = Turtle()

yertle.forward(40)
yertle.right(45)
yertle.forward(80)

screen = Screen()

screen.exitonclick()

The functional interface is there to make things easier for beginners:

from turtle import *

forward(40)
right(45)
forward(80)

exitonclick()

or:

import turtle

turtle.forward(40)
turtle.right(45)
turtle.forward(80)

turtle.exitonclick()

But you shouldn't mix the two! As that is a primary source of turtle confusion.

The issue with PyCharm is that the turtle functional API is derived from the object-oriented API at load time, so it's not there for PyCharm to find when it scans the source file. The turtle methods are all mapped onto the default turtle and screen methods are all mapped onto the singular screen instance.

cdlane
  • 40,441
  • 5
  • 32
  • 81
-1

Try this:

from turtle import Turtle

it must work.

greetings.

atxdev
  • 1
  • 2
  • 1
    It does not... Again, the code runs as intended, but PyCharm doesn't like it. IDE fail, not a Python fail. – Jack_Hu Apr 29 '19 at 12:52
  • Thanks for the suggestion, but my question is more about why an IDE won't necessarily interpret the import statement correctly, or seemingly so anyway. – Jack_Hu Apr 29 '19 at 13:06