Merge pull request #507 from SpisTresci/pycharm_support_2

Pycharm Support (including debugging in Docker)
This commit is contained in:
Jannis Gebauer 2016-04-07 08:45:13 +02:00
commit e25c5999c0
35 changed files with 428 additions and 4 deletions

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -122,6 +122,7 @@ It prompts you for questions. Answer them::
use_sentry [n]: y use_sentry [n]: y
use_newrelic [n]: y use_newrelic [n]: y
use_opbeat [n]: y use_opbeat [n]: y
use_pycharm [n]: y
windows [n]: n windows [n]: n
use_python2 [n]: y use_python2 [n]: y
Select open_source_license: Select open_source_license:

View File

@ -15,6 +15,7 @@
"use_sentry": "n", "use_sentry": "n",
"use_newrelic": "n", "use_newrelic": "n",
"use_opbeat": "n", "use_opbeat": "n",
"use_pycharm": "n",
"windows": "n", "windows": "n",
"use_python2": "n", "use_python2": "n",
"open_source_license": ["MIT", "BSD", "Not open source"] "open_source_license": ["MIT", "BSD", "Not open source"]

View File

@ -3,7 +3,8 @@ Does the following:
1. Generates and saves random secret key 1. Generates and saves random secret key
2. Removes the taskapp if celery isn't going to be used 2. Removes the taskapp if celery isn't going to be used
3. Copy files from /docs/ to {{ cookiecutter.repo_name }}/docs/ 3. Removes the .idea directory if PyCharm isn't going to be used
4. Copy files from /docs/ to {{ cookiecutter.repo_name }}/docs/
TODO: this might have to be moved to a pre_gen_hook TODO: this might have to be moved to a pre_gen_hook
@ -100,6 +101,18 @@ def remove_task_app(project_directory):
) )
shutil.rmtree(task_app_location) shutil.rmtree(task_app_location)
def remove_pycharm_dir(project_directory):
"""
Removes directories related to PyCharm
if it isn't going to be used
"""
idea_dir_location = os.path.join(PROJECT_DIRECTORY, '.idea/')
shutil.rmtree(idea_dir_location)
docs_dir_location = os.path.join(PROJECT_DIRECTORY, 'docs/pycharm/')
shutil.rmtree(docs_dir_location)
# IN PROGRESS # IN PROGRESS
# def copy_doc_files(project_directory): # def copy_doc_files(project_directory):
# cookiecutters_dir = DEFAULT_CONFIG['cookiecutters_dir'] # cookiecutters_dir = DEFAULT_CONFIG['cookiecutters_dir']
@ -125,5 +138,9 @@ make_secret_key(PROJECT_DIRECTORY)
if '{{ cookiecutter.use_celery }}'.lower() == 'n': if '{{ cookiecutter.use_celery }}'.lower() == 'n':
remove_task_app(PROJECT_DIRECTORY) remove_task_app(PROJECT_DIRECTORY)
# 3. Copy files from /docs/ to {{ cookiecutter.repo_name }}/docs/ # 3. Removes the .idea directory if PyCharm isn't going to be used
if '{{ cookiecutter.use_pycharm }}'.lower() != 'y':
remove_pycharm_dir(PROJECT_DIRECTORY)
# 4. Copy files from /docs/ to {{ cookiecutter.repo_name }}/docs/
# copy_doc_files(PROJECT_DIRECTORY) # copy_doc_files(PROJECT_DIRECTORY)

View File

@ -38,7 +38,17 @@ htmlcov
*.pot *.pot
# Pycharm # Pycharm
.idea .idea/*
{% if cookiecutter.use_pycharm == 'y' %}
# Provided default Pycharm Run/Debug Configurations should be tracked by git
# In case of local modifications made by Pycharm, use update-index command
# for each changed file, like this:
# git update-index --assume-unchanged .idea/{{cookiecutter.repo_name}}.iml
!.idea/runConfigurations/
!.idea/{{cookiecutter.repo_name}}.iml
!.idea/vcs.xml
!.idea/webResources.xml
{% endif %}
# Vim # Vim

View File

@ -0,0 +1,32 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: migrate" type="Python.DjangoServer" factoryName="Django server" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:pycharm/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="launchJavascriptDebuger" value="false" />
<option name="host" value="" />
<option name="additionalOptions" value="" />
<option name="browserUrl" value="" />
<option name="runTestServer" value="false" />
<option name="runNoReload" value="false" />
<option name="useCustomRunCommand" value="true" />
<option name="customRunCommand" value="migrate" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,33 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: runserver" type="Python.DjangoServer" factoryName="Django server" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:django/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="launchJavascriptDebuger" value="false" />
<option name="port" value="8000" />
<option name="host" value="0.0.0.0" />
<option name="additionalOptions" value="" />
<option name="browserUrl" value="" />
<option name="runTestServer" value="false" />
<option name="runNoReload" value="false" />
<option name="useCustomRunCommand" value="false" />
<option name="customRunCommand" value="" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,33 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: runserver_plus" type="Python.DjangoServer" factoryName="Django server" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:django/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="launchJavascriptDebuger" value="false" />
<option name="port" value="8000" />
<option name="host" value="0.0.0.0" />
<option name="additionalOptions" value="" />
<option name="browserUrl" value="" />
<option name="runTestServer" value="false" />
<option name="runNoReload" value="false" />
<option name="useCustomRunCommand" value="true" />
<option name="customRunCommand" value="runserver_plus" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,30 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: tests - all" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:pycharm/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="TARGET" value="." />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,30 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: tests - class: TestUser" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:pycharm/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="TARGET" value="{{ cookiecutter.repo_name }}.users.tests.test_models.TestUser" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,30 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: tests - file: test_models" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:pycharm/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="TARGET" value="{{ cookiecutter.repo_name }}.users.tests.test_models" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,30 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: tests - module: users" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:pycharm/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="TARGET" value="{{ cookiecutter.repo_name }}.users" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,30 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Docker: tests - specific: test_get_absolute_url" type="DjangoTestsConfigurationType" factoryName="Django tests" singleton="true">
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="DJANGO_SETTINGS_MODULE" value="config.settings.local" />
</envs>
<option name="SDK_HOME" value="docker-compose://$PROJECT_DIR$/dev.yml:pycharm/python" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<module name="{{ cookiecutter.repo_name }}" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
<PathMappingSettings>
<option name="pathMappings">
<list>
<mapping local-root="$PROJECT_DIR$" remote-root="/app" />
</list>
</option>
</PathMappingSettings>
<option name="TARGET" value="{{ cookiecutter.repo_name }}.users.tests.test_models.TestUser.test_get_absolute_url" />
<option name="SETTINGS_FILE" value="" />
<option name="CUSTOM_SETTINGS" value="false" />
<option name="USE_OPTIONS" value="false" />
<option name="OPTIONS" value="" />
<method />
</configuration>
</component>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WebResourcesPaths">
<contentEntries>
<entry url="file://$PROJECT_DIR$">
<entryData>
<resourceRoots>
<path value="file://$PROJECT_DIR$/{{ cookiecutter.repo_name }}/static" />
</resourceRoots>
</entryData>
</entry>
</contentEntries>
</component>
</project>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="config/settings/local.py" />
<option name="manageScript" value="manage.py" />
<option name="environment" value="&lt;map/&gt;" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">
<option name="requirementsPath" value="$MODULE_DIR$/requirements/local.txt" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/{{ cookiecutter.repo_name }}/templates" />
</list>
</option>
</component>
<component name="TestRunnerService">
<option name="projectConfiguration" value="py.test" />
<option name="PROJECT_TEST_RUNNER" value="py.test" />
</component>
</module>

View File

@ -13,7 +13,7 @@ services:
django: django:
build: build:
context: . context: .
dockerfile: Dockerfile-dev dockerfile: ./compose/django/Dockerfile-dev
command: python /app/manage.py runserver_plus 0.0.0.0:8000 command: python /app/manage.py runserver_plus 0.0.0.0:8000
depends_on: depends_on:
- postgres - postgres
@ -25,3 +25,17 @@ services:
- "8000:8000" - "8000:8000"
links: links:
- postgres - postgres
{% if cookiecutter.use_pycharm == 'y' %}
pycharm:
build:
context: .
dockerfile: ./compose/django/Dockerfile-dev
depends_on:
- postgres
environment:
- POSTGRES_USER={{cookiecutter.repo_name}}
volumes:
- .:/app
links:
- postgres
{% endif %}

View File

@ -10,6 +10,7 @@ services:
django: django:
build: build:
context: . context: .
dockerfile: ./compose/django/Dockerfile
user: django user: django
depends_on: depends_on:
- postgres - postgres

View File

@ -0,0 +1,72 @@
Docker Remote Debugging
=======================
To connect to python remote interpreter inside docker, you have to make sure first, that Pycharm is aware of your docker.
Go to *Settings > Build, Execution, Deployment > Docker*. If you are on linux, you can use docker directly using its socket `unix:///var/run/docker.sock`, if you are on Windows or Mac, make sure that you have docker-machine installed, then you can simply *Import credentials from Docker Machine*.
.. image:: images/1.png
Configure Remote Python Interpreter
-----------------------------------
This repository comes with already prepared "Run/Debug Configurations" for docker.
.. image:: images/2.png
But as you can see, at the beggining there is something wrong with them. They have red X on django icon, and they cannot be used, withot configuring remote python interpteter. To do that, you have to go to *Settings > Build, Execution, Deployment* first.
Next, you have to add new remote python interpreter, based on already tested deployment settings. Go to *Settings > Project > Project Interpreter*. Click on the cog icon, and click *Add Remote*.
.. image:: images/3.png
Switch to *Docker Compose* and select `dev.yml` file from directory of your project, next set *Service name* to `django`
.. image:: images/4.png
Because Pycharm restarts container every time you use Configuration Run, to not have server restarted during running tests, we defined second service in `dev.yml` file called pycharm. To use it, you have to add interpreter of second service as well.
.. image:: images/5.png
The final result should be:
.. image:: images/6.png
Having that, click *OK*. Close *Settings* panel, and wait few seconds...
.. image:: images/7.png
After few seconds, all *Run/Debug Configurations* should be ready to use.
.. image:: images/8.png
**Things you can do with provided configuration**:
* run and debug python code
.. image:: images/f1.png
* run and debug tests
.. image:: images/f2.png
.. image:: images/f3.png
* run and debug migrations or different django managment commands
.. image:: images/f4.png
* and many others..
Known issues
------------
* Pycharm hangs on "Connecting to Debugger"
.. image:: images/issue1.png
This might be fault of your firewall. Take a look on this ticket - https://youtrack.jetbrains.com/issue/PY-18913
* Modified files in `.idea` directory
Most of the files from `.idea/` were added to `.gitignore` with a few exceptions, which were made, to provide "ready to go" configuration. After adding remote interpreter some of these files are altered by PyCharm:
.. image:: images/issue2.png
In theory you can remove them from repository, but then, other people will lose a ability to initialize a project from provided configurations as you did. To get rid of this annoying state, you can run command::
$ git update-index --assume-unchanged {{cookiecutter.repo_name}}.iml

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB