Scrapy integration with DjangoItem yields error - django

I am trying to run scrapy with DjangoItem. When i run crawl my spider, I get the 'ExampleDotComItem does not support field: title' error. I have created multiple projects and tried to get it to work but always get the same error. I found this tutorial and downloaded the source code, and after running it; I get the same error:
Traceback (most recent call last):
File "c:\programdata\anaconda3\lib\site-packages\twisted\internet\defer.py",line 654, in _runCallbacks
current.result = callback(current.result, *args, **kw)
File "C:\Users\A\Desktop\django1.7-scrapy1.0.3-master\example_bot\example_bot\spiders\example.py", line 12, in parse
return ExampleDotComItem(title=title, description=description)
File "c:\programdata\anaconda3\lib\site-packages\scrapy_djangoitem__init__.py", line 29, in init
super(DjangoItem, self).init(*args, **kwargs)
File "c:\programdata\anaconda3\lib\site-packages\scrapy\item.py", line 56, in init
self[k] = v
File "c:\programdata\anaconda3\lib\site-packages\scrapy\item.py", line 66,
in setitem
(self.class.name, key)) KeyError: 'ExampleDotComItem does not support field: title'
Project structure:
├───django1.7-scrapy1.0.3-master
├───example_bot
│ └───example_bot
│ ├───spiders
│ │ └───__pycache__
│ └───__pycache__
└───example_project
├───app
│ ├───migrations
│ │ └───__pycache__
│ └───__pycache__
└───example_project
└───__pycache__
My Django Model:
from django.db import models
class ExampleDotCom(models.Model):
title = models.CharField(max_length=255)
description = models.CharField(max_length=255)
def __str__(self):
return self.title
My "example" Spider:
from scrapy.spiders import BaseSpider
from example_bot.items import ExampleDotComItem
class ExampleSpider(BaseSpider):
name = "example"
allowed_domains = ["example.com"]
start_urls = ['http://www.example.com/']
def parse(self, response):
title = response.xpath('//title/text()').extract()[0]
description = response.xpath('//body/div/p/text()').extract()[0]
return ExampleDotComItem(title=title, description=description)
Items.py:
from scrapy_djangoitem import DjangoItem
from app.models import ExampleDotCom
class ExampleDotComItem(DjangoItem):
django_model = ExampleDotCom
pipelines.py:
class ExPipeline(object):
def process_item(self, item, spider):
print(item)
item.save()
return item
settings.py:
import os
import sys
DJANGO_PROJECT_PATH = '/Users/A/DESKTOP/django1.7-scrapy1.0.3-master/example_project'
DJANGO_SETTINGS_MODULE = 'example_project.settings' #Assuming your django application's name is example_project
sys.path.insert(0, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
BOT_NAME = 'example_bot'
import django
django.setup()
SPIDER_MODULES = ['example_bot.spiders']
ITEM_PIPELINES = {
'example_bot.pipelines.ExPipeline': 1000,
}

Can you show your Django model? This is likely occurring because title isn't defined on your ExampleDotCom model.
If it is there, perhaps you need to run your Django migrations?

Related

Django circular import error - how to debug it?

I tried to follow this tutorial
https://blog.nicolasmesa.co/posts/2018/10/saas-like-isolation-in-django-rest-framework/
using: Django 3.1 Python 3.6
Everything I did including 'The User Messages App' paragraph worked perfectly right before the 'Refactoring the views' passage
and then I got the error when running manage.py runserver
django.core.exceptions.ImproperlyConfigured: The included URLconf 'saas_django.urls' does not appear to have any pa
tterns in it. If you see valid patterns in the file then the issue is probably caused by a circular import
I tried different types of import but I can't figure out where the cirular import happens
My steps to find a bug:
the
saas_django/urls.py refers to user_messages app:
path('api/v1/user-messages/', include('user_messages.urls')),
user_messages/urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.UserMessageList.as_view(),
name=views.UserMessageList.name),
path('<uuid:pk>', views.UserMessageDetail.as_view(),
name=views.UserMessageDetail.name),
]
It seems like something is wrong with the imported user_messages/views.py
from rest_framework import permissions
from rest_framework import generics
from . import serializers
from .models import UserMessage
class UserMessageList(generics.ListCreateAPIView):
name = 'usermessage-list'
permission_classes = (
permissions.IsAuthenticated,
)
serializer_class = serializers.UserMessageSerializer
queryset = UserMessage.objects.all()
def perform_create(self, serializer):
user = self.request.user
company_id = user.company_id
# Added from_user
serializer.save(company_id=company_id, from_user=user)
def get_queryset(self):
# Changed this to use the UserMessageManager's method
return UserMessage.objects.get_for_user(self.request.user)
class UserMessageDetail(generics.RetrieveAPIView):
name = 'usermessage-detail'
permission_classes = (
permissions.IsAuthenticated,
)
serializer_class = serializers.UserMessageSerializer
def get_queryset(self):
# Changed this to use the UserMessageManager's method
return UserMessage.objects.get_for_user(self.request.user)
I gues the cause of the error is something about these 2 lines:
from . import serializers
from .models import UserMessage
the user_messages/serializers.py also has the import of UserMessages
from rest_framework import permissions
from rest_framework import generics
from . import serializers
from .models import UserMessage
class UserMessageList(generics.ListCreateAPIView):
name = 'usermessage-list'
permission_classes = (
permissions.IsAuthenticated,
)
serializer_class = serializers.UserMessageSerializer
queryset = UserMessage.objects.all()
def perform_create(self, serializer):
user = self.request.user
company_id = user.company_id
# Added from_user
serializer.save(company_id=company_id, from_user=user)
def get_queryset(self):
# Changed this to use the UserMessageManager's method
return UserMessage.objects.get_for_user(self.request.user)
class UserMessageDetail(generics.RetrieveAPIView):
name = 'usermessage-detail'
permission_classes = (
permissions.IsAuthenticated,
)
serializer_class = serializers.UserMessageSerializer
def get_queryset(self):
# Changed this to use the UserMessageManager's method
return UserMessage.objects.get_for_user(self.request.user)
I tried to rewrite import as:
from .models import UserMessage as UM
but it didn't work.
Project structure is:
│ db.sqlite3
│ manage.py
│ sqlite3.exe
│
├───accounts
│ admin.py
│ apps.py
│ models.py
│ serializers.py
│ tests.py
│ urls.py
│ views.py
│ __init__.py
│
├───core
│ models.py
│ serializers.py
│ views.py
│ __init__.py
│
├───saas_django
│ asgi.py
│ settings.py
│ urls.py
│ wsgi.py
│ __init__.py
│
└───user_messages
│ admin.py
│ apps.py
│ models.py
│ serializers.py
│ tests.py
│ urls.py
│ views.py
│ __init__.py
│
├───migrations
My full code is here: https://github.com/SergSm/test-django-saas/
The question is how to properly debug this type of error?
First of all there are few issues in the project itself. There are unresolved references to serializers without which no one will be able to help out. For example:
from core.serializers import CompanySafeSerializerMixin
This is referenced in a few other serializers. Also, other than this, there is one major issue in the way you have defined the models for:
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
company = models.ForeignKey(Company,
related_name='%(class)s',
on_delete=models.CASCADE,
editable=False,
default=get_default_company)
The default method looks like this:
def get_default_company():
"""get or create the non existent company for new users"""
return Company.objects.get_or_create(is_default_company=True,
name=DEFAULT_COMPANY)[0].pk
Not sure in what sequence you made these models but since you have not pushed your migrations onto the VCS, this will cause the issue.
Remember, always push your migrations on the VCS.
I cannot highlight this enough. It can lead to serious issues as and when the project grows.
Else, on new setup, Django will never be able to identify correct dependency between models.
Coming to the other problem, since you have used default as method that gets ref from another model, Django will not allow me to make the migrations in the first place since the model itself that its referring to is not yet made.
File "/home/dhwanil/work/packages/test-django-saas/venv/lib64/python3.6/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "companies" does not exist
LINE 1: ...."address", "companies"."is_default_company" FROM "companies...
^
This would have been solved if lets say you had 0001_initial one with the company model and the 0002_users where you refer the Company model. Also, you might want to look at the concept of fixtures that will help you populate a model on every fresh installation.
Coming to the main question you asked, if its indeed a circular, the best way is to closely inspect the traceback, it would show where the circular dep lies. Since I am unable to setup the project until the above mentioned issues are solved, I will not be able to give you a more directed answer.
Summary:
Always push the migrations that are created after python manage.py makemigrations on the VCS, migrations are like commits of the state of your DB, you cannot expect to work with latest state without knowing the steps it was built from.
Avoid using methods to get default from another model, the better way is always use fixtures to first populate the DB. Again, this will not be possible without splitting your migrations smartly.
return Company.objects.get_or_create(is_default_company=True,
name=DEFAULT_COMPANY)[0].pk
Alternative to use fixtures would be "Data Migrations", I always recommend to add a custom RunPython code in your migrations to assign defaults. This takes off the overhead of worrying if the data is there in the DB or not, because it will be populated the moment you run migrate.
Most circular imports can be identified by the traceback, inspect it closely.
That's all for now, if you fix the import issues, let me know. I'll be happy to take a look.
Cheers!

module object has no attribute after using different version of Python

I have both versions python 2.7 and 3.4 installed. I am using some code which is developed under 2.7 but I am using under 3.4. So after compiling using the following command
python manage.py runserver
I get the following error -
File "C:\pyprojects\focus\site\general\forms.py", line 26, in Meta
model = models.UserProfile
AttributeError: 'module' object has no attribute 'UserProfile'
The directory structure is
├───focus
│ ├───data_dumps
│ ├───notes
│ ├───setup
│ └───site(main project folder)
| └───static
| └───general
| +--forms.py
| +--models.py
| └───pro
| └───models
| +--__init__.py
| +--plans.py
│ └───focus2
│ └───templates
| +--__init__.py
│ +--settings.py
│ +--util.py
│ +--wsgi.py
│ +--manage.py
As models.py and forms.py is under same directory(general) so I have imported the model in forms.py in this way
from .models import models
Now in models.py I have defined the class
class UserProfile(models.Model, HashedPk):
user = models.OneToOneField(User, unique=True)
is_pro = models.BooleanField(default=False, blank=True)
......................................................
In forms.py the code is
class UserProfileForm(forms.ModelForm):
class Meta:
model = models.UserProfile
.....................
Is there any special way to call the model in python 3.4.
Any help is highly appreciated.
It's sorted. The import needs to be
from . import models
instead
from .models import models

Why when I try to use models in celery tasks django raises "Apps aren't loaded yet" error?

I work with django 1.10.5 and celery 4.0.2. I have the structure like this.
-proj
-application
__init__.py
celery.py
celery_conf.py
settings.py
tasks.py
urls.py
wsgi.py
-extuser (application with extended UserModel)
-pages
-migrations
-templates
__init__.py
admin.py
apps.py
forms.py
models.py
tasks.py
tests.py
views.py
I have the task which uses model from file which contains my extended user model. If I try to run celery with this command:
celery -A application worker -l INFO -B
Then I see this error:
Traceback (most recent call last):
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/bin/celery", line 11, in <module>
sys.exit(main())
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/__main__.py", line 14, in main
_main()
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/celery.py", line 326, in main
cmd.execute_from_commandline(argv)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/celery.py", line 488, in execute_from_commandline
super(CeleryCommand, self).execute_from_commandline(argv)))
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/base.py", line 281, in execute_from_commandline
return self.handle_argv(self.prog_name, argv[1:])
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/celery.py", line 480, in handle_argv
return self.execute(command, argv)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/celery.py", line 412, in execute
).run_from_argv(self.prog_name, argv[1:], command=argv[0])
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/worker.py", line 221, in run_from_argv
return self(*args, **options)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/base.py", line 244, in __call__
ret = self.run(*args, **kwargs)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/bin/worker.py", line 255, in run
**kwargs)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/worker/worker.py", line 94, in __init__
self.app.loader.init_worker()
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/loaders/base.py", line 116, in init_worker
self.import_default_modules()
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/loaders/base.py", line 111, in import_default_modules
return [self.import_task_module(m) for m in self.default_modules]
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/loaders/base.py", line 97, in import_task_module
return self.import_from_cwd(module)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/loaders/base.py", line 106, in import_from_cwd
package=package,
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/utils/imports.py", line 101, in import_from_cwd
return imp(module, package=package)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/celery/loaders/base.py", line 100, in import_module
return importlib.import_module(module, package=package)
File "/usr/lib64/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/src/pages/tasks.py", line 4, in <module>
from extuser.models import UserLinksArchive
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/src/extuser/models.py", line 5, in <module>
from django.contrib.auth.models import AbstractBaseUser
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/django/contrib/auth/models.py", line 4, in <module>
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/django/contrib/auth/base_user.py", line 52, in <module>
class AbstractBaseUser(models.Model):
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/django/db/models/base.py", line 105, in __new__
app_config = apps.get_containing_app_config(module)
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/django/apps/registry.py", line 237, in get_containing_app_config
self.check_apps_ready()
File "/home/dmitriy/MyEnv/DjangoProjects/sPrint/env/local/lib/python2.7/site-packages/django/apps/registry.py", line 124, in check_apps_ready
raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
File pages/tasks.py looks like this:
from __future__ import absolute_import, unicode_literals
from application.celery import app
from extuser.models import UserLinksArchive
#app.task
def link_destroy_task(link_id):
link = UserLinksArchive.objects.get(id=link_id)
link.delete()
Also, if I make the import of UserLinksArchive local then celery starts, but when it's time to run async_task I get the same error.
As you can see, problem is probably with AbstractBaseUser import. But I have no idea how to fix this.
Probably, extuser/models.py code will help.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.models import BaseUserManager
from django.core.validators import MinValueValidator, MinLengthValidator
from django.db import models
class MyUserManager(BaseUserManager):
def create_user(self, username, password=None, **extra_fields):
if not username:
raise ValueError(u'No user')
user = self.model(username=username)
if password:
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, password):
user = self.create_user(username, password)
user.is_admin = True
user.is_superuser = True
user.save(using=self._db)
return user
class ExtUser(AbstractBaseUser, PermissionsMixin):
username = models.CharField(
max_length=255,
null=False,
unique=True,
validators=[MinLengthValidator(6)]
)
balance = models.FloatField(
default=0.0,
validators=[MinValueValidator(0.0)]
)
is_active = models.BooleanField(
default=True
)
is_admin = models.BooleanField(
default=False
)
def get_full_name(self):
return self.username
#property
def is_staff(self):
return self.is_admin
def get_short_name(self):
return self.username
def __str__(self):
return self.username
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
objects = MyUserManager()
class Meta:
db_table = 'auth_user'
LINKTYPE = (
('p', 'Password restore'),
('o', 'Other'),
)
class UserLinksArchive(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
default=1
)
hash = models.CharField(
max_length=32,
default=None,
unique=True
)
created_at = models.DateTimeField(
auto_now_add=True
)
type = models.CharField(
max_length=1,
default='o',
choices=LINKTYPE
)
And my celery.py:
#application/celery.py
# coding=utf-8
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'application.settings')
app = Celery('application')
# Using a string here means the worker don't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('application.celery_conf', namespace='CELERY')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
and celery_conf.py:
#application/celery_conf.py
# CELERY SETTINGS ALARMA
from django.conf import settings
CELERY_IMPORTS = ("application.tasks", "pages.tasks")
CELERY_BROKER_BACKEND = 'redis'
CELERY_BROKER_URL = settings.REDIS_URL
CELERY_RESULT_BACKEND = settings.REDIS_URL
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24
CELERY_TIMEZONE = 'Europe/Moscow'
This can be fixed if you import your UserLinksArchive inside the method of your tasks.py
Something like this:
#app.task
def link_destroy_task(link_id):
from extuser.models import UserLinksArchive
link = UserLinksArchive.objects.get(id=link_id)
link.delete()
I've put import inside the task but the problem as I wrote still remained.
So, after some hours exploring the problem, I've found the reason. In my case the problem was in one of the packages in my requirements. I even don't know how it appeared there, really, have no idea (maybe will know if something will fall of). Here is my requirements.txt
amqp==2.1.4
anyjson==0.3.3
billiard==3.5.0.2
celery==4.0.2
Django==1.10.5
django-categories==1.4.2
django-celery==3.1.17
django-celery-beat==1.0.1
django-mptt==0.8.7
django-multiupload==0.5.1
django-shell-plus==1.1.7
django-widget-tweaks==1.4.1
gunicorn==19.6.0
kombu==4.0.2
lorem-ipsum-generator==0.3
lxml==3.7.2
mysqlclient==1.3.9
oauthlib==2.0.0
printer==2.0.0 <==(this package)
PyJWT==1.4.2
python-openid==2.2.5
python-social-auth==0.2.21
pytz==2016.10
redis==2.10.5
requests==2.11.1
requests-oauthlib==0.7.0
six==1.10.0
transliterate==1.8.1
tzlocal==1.3
unicode-slugify==0.1.1
vine==1.1.3
I've found that I can't even import packages from other apps. Runserver fell down with error like this:
/env/local/lib/python2.7/site-packages/printer.py", line 8
print("\t",end='')
^
SyntaxError: invalid syntax
My python version is 2.7 and this doesn't work.
It's my first time when I feel the difference between 2.7 and 3.x print
Finally, I've just removed this package.
Flight is normal so far.

ValueError: Missing scheme in request url: h

I am a beginner in scrapy, python. I tried to deploy the spider code in scrapinghub and I encountered the following error. Below is the code.
import scrapy
from bs4 import BeautifulSoup,SoupStrainer
import urllib2
from scrapy.selector import Selector
from scrapy.http import HtmlResponse
import re
import pkgutil
from pkg_resources import resource_string
from tues1402.items import Tues1402Item
data = pkgutil.get_data("tues1402","resources/urllist.txt")
class SpiderTuesday (scrapy.Spider):
name = 'tuesday'
self.start_urls = [url.strip() for url in data]
def parse(self, response):
story = Tues1402Item()
story['url'] = response.url
story['title'] = response.xpath("//title/text()").extract()
return story
is my spider.py code
import scrapy
class Tues1402Item(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
url = scrapy.Field()
is the items.py code and
from setuptools import setup, find_packages
setup(
name = 'tues1402',
version = '1.0',
packages = find_packages(),
entry_points = {'scrapy': ['settings = tues1402.settings']},
package_data = {'tues1402':['resources/urllist.txt']},
zip_safe = False,
)
is the setup.py code.
The following is the error.
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/scrapy/core/engine.py", line 126, in _next_request
request = next(slot.start_requests)
File "/usr/local/lib/python2.7/site-packages/scrapy/spiders/init.py", line 70, in start_requests
yield self.make_requests_from_url(url)
File "/usr/local/lib/python2.7/site-packages/scrapy/spiders/init.py", line 73, in make_requests_from_url
return Request(url, dont_filter=True)
File "/usr/local/lib/python2.7/site-packages/scrapy/http/request/init.py", line 25, in init
self._set_url(url)
File "/usr/local/lib/python2.7/site-packages/scrapy/http/request/init.py", line 57, in _set_url
raise ValueError('Missing scheme in request url: %s' % self._url)
ValueError: Missing scheme in request url: h
Thank you in Advance
Your error means that url h is not a valid url. You should print out your self.start_urls and see what urls you have there, you most likely have a string h as your first url.
Seems like your spider iterates through text instead of a list of urls here:
data = pkgutil.get_data("tues1402","resources/urllist.txt")
class SpiderTuesday (scrapy.Spider):
name = 'tuesday'
self.start_urls = [url.strip() for url in data]
Assuming that you store your urls with some separator in urllist.txt file you should split that:
# assuming file has url in every line
self.start_urls = [url.strip() for url in data.splitlines()]

Behave ImportError: No module named features.steps.pages.home_page

I have a sample BDD scenario in Python Behave. When i run the feature I get the error:
ImportError: No module named features.steps.pages.home_page
I am not sure why it is complaining. home_page.py is in the pages folder, pages is in the steps folder and steps folder is in the features folder.
In pages folder I have an init.py file.
Why is it complaining it cannot find home_page.py?
My code is: features\steps.py
from behave import *
#from features.steps.pages import home_page
from features.steps.pages.home_page import HomePage
#from features.steps.pages import search_page
from features.steps.pages.search_page import SearchPage
from features.steps.pages import home_page
#Given ('we are on the homepage')
def step(context):
context.browser.get('http://www.test.com')
#When ('we enter "{product}" in the search field')
def step(context, product):
#search_field = context.browser.find_element(By.XPATH, 'id("twotabsearchtextbox")')
#search_field.send_keys(product)
home_page = HomePage(context)
home_page.enter_product_in_search_field(product, context)
#When ('And we click the search button')
def step(context):
#search_button = context.browser.find_element(By.XPATH, './/*[#id="nav-search"]/form/div[2]/div/input')
searchPage_results = home_page.click_search_button(context)
#search_button.click()
#Then ('the list of products are displayed')
def step(context):
context.searchPage_results.search_products_results(context)
#wait = WebDriverWait(context.browser, 60)
#divs = wait.until(EC.presence_of_all_elements_located((By.XPATH, '//div/a/h2')))
#for i in divs:
#div2 = divs + '/a/h2'
#print divs.get_attribute('value')
#print divs
#print i.text
#print "i"
# divs
features\steps\pages\home_page.py
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from search_page import SearchPage
class HomePage(object):
def __init__(self, context):
context = context
def enter_product_in_search_field(self, product, context):
search_field = context.browser.find_element(By.XPATH, 'id("twotabsearchtextbox")')
search_field.send_keys(product)
return self
def click_search_button(self, context):
search_button = context.find_element(By.XPATH, './/*[#id="nav-search"]/form/div[2]/div/input').click()
return SearchPage(context)
features\test_feature.feature
Feature: testing product
Scenario Outline: visit test and search for product
Given we are on the test homepage
When we enter "<product>" in the search field
And we click the search button
Then the list of products are displayed
Examples: By product
| Forumla One |
| PS4 |
| Headphones |
My directory structure is:
E:features\test_feature.feature
E:features\init.py
E:features\pages\init.py
E:features\pages\home_page.py
E:features\pages\search_page.py
The full error is:
E:\RL Fusion\projects\BDD\Python BDD\PythonBDD\Selenium Sample\features>behave test_feature.feature
Exception ImportError: No module named features.steps.pages.home_page
Traceback (most recent call last):
File "C:\Python27\lib\runpy.py", line 162, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "C:\Python27\lib\runpy.py", line 72, in _run_code
exec code in run_globals
File "C:\Python27\scripts\behave.exe\__main__.py", line 9, in <module>
File "C:\Python27\lib\site-packages\behave\__main__.py", line 109, in main
failed = runner.run()
File "C:\Python27\lib\site-packages\behave\runner.py", line 672, in run
return self.run_with_paths()
File "C:\Python27\lib\site-packages\behave\runner.py", line 678, in run_with_paths
self.load_step_definitions()
File "C:\Python27\lib\site-packages\behave\runner.py", line 658, in load_step_definitions
exec_file(os.path.join(path, name), step_module_globals)
File "C:\Python27\lib\site-packages\behave\runner.py", line 304, in exec_file
exec(code, globals, locals)
File "steps\amazon_steps.py", line 6, in <module>
from features.steps.pages.home_page import HomePage
ImportError: No module named features.steps.pages.home_page
How can I resolve this issue?
Thanks, Riaz
It looks like you are not importing your modules correctly. To turn a directory in to a module, change all your init.py files to __init__.py.
Then when you are importing in features/steps.py you can use:
from pages.home_page import HomePage