How to stop Django from hanging after page refresh using channels? - python-3.x

Using channels it connects properly when the page loads the first time but then hangs on refresh. Not sure why this is happening. I've placed the code below to see what might be happening?
# index.html
<script>
let socket = new WebSocket('ws://127.0.0.1:8001/ws/');
socket.onmessage = () => {
console.log("Connected");
};
socket.onclose = () => {
console.log('Websocket closed');
}
</script>
# app/consumer.py
from json import dumps
from time import sleep
from channels.generic.websocket import WebsocketConsumer
class WSConsumer(WebsocketConsumer):
def connect(self):
self.accept()
self.send(dumps({'message': 'connected'}))
for i in range(1000):
self.send(dumps({'message': i}))
sleep(2)
#app/routing.py
from django.urls import path
from app.consumers import WSConsumer
ws_urlpatterns = [
path('ws/', WSConsumer.as_asgi())
]
#core/asgi.py
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter
from channels.routing import URLRouter
from django.core.asgi import get_asgi_application
from app.routing import ws_urlpatterns
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
django.setup()
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddlewareStack(URLRouter(ws_urlpatterns)),
})
# core/urls.py
...
path('test/', views.IndexView.as_view()),
...
In my settings I've added channels just below the .sites app but above everything else and I've added the ASGI_APPLICATION and running the application with python manage.py runserver 127.0.0.1:8001

Related

Is there a problem while creating setUp() function in my Unit test cases?

I am writing unit test cases for my app.py file. I have created a setUp() function in my test file but the moment I execute any test case, it throws an error like
============================= test session starts ==============================
platform linux -- Python 3.6.9, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 -- /home/curiousguy/PycharmProjects/leadgen/venv/bin/python
cachedir: .pytest_cache
rootdir: /home/curiousguy/PycharmProjects/leadgen/tests
plugins: cov-2.10.1
collecting ... ENV :None
test_app.py:None (test_app.py)
test_app.py:5: in <module>
from app import app
../app.py:7: in <module>
from appli import appli
../appli.py:6: in <module>
appli = create_app(db, config_name)
../app_setup.py:21: in create_app
leadgen_app.config.from_object(app_config[config_name])
E KeyError: None
collected 0 items / 1 error
==================================== ERRORS ====================================
_________________________ ERROR collecting test_app.py _________________________
test_app.py:5: in <module>
from app import app
../app.py:7: in <module>
from appli import appli
../appli.py:6: in <module>
appli = create_app(db, config_name)
../app_setup.py:21: in create_app
leadgen_app.config.from_object(app_config[config_name])
E KeyError: None
The test file is:
import unittest
from unittest.mock import patch
import pytest
# from appli import appli
from app import app
#import app
class MyApp(unittest.TestCase):
def setUp(self):
app.testing = True
self.client = app.test_client()
def tearDown(self):
pass
def test_settings_passed(self):
response = self.client.get('/settings', follow_redirects=True)
self.assertEqual(response.status_code, 200)
with pytest.raises(AssertionError) as wt:
self.assertEqual(response.status_code, 403)
Since the errors are pointing to different files I am adding those files as well.
app.py
import functools
import pickle
from flask import (redirect, render_template, request, Response, session, url_for)
from flask_login import LoginManager, login_user, current_user
from flask_admin import Admin
from ldap3 import Server, Connection, ALL, SIMPLE
from appli import appli
import datetime
from modules.controller import application
from modules.users_view import MyAdminIndexView, UsersView
from database.db_model import (Companies, Users, Leads, db)
###########################################################
# Init section #
###########################################################
app = appli
login_manager = LoginManager()
login_manager.login_view = "login"
login_manager.init_app(app)
server = Server(app.config['LDAP_SERVER'],
port=app.config['LDAP_PORT'], get_info=ALL)
server_tor = Server(app.config['LDAP_SERVER_TOR'],
port=app.config['LDAP_PORT'], get_info=ALL)
admin = Admin(app, name='LEADGEN Admin', index_view=MyAdminIndexView(), base_template='master.html')
admin.add_view(UsersView(Users, db.session))
application_inst = application("Lead Generator")
#rest of code
appli.py
import os
from app_setup import create_app
from database.db_model import db
config_name = os.getenv('FLASK_ENV')
appli = create_app(db, config_name)
if __name__ == '__main__':
appli.run()
app_Setup.py
def create_app(db,config_name):
leadgen_app = Flask(__name__, instance_relative_config=True)
# config_name = os.getenv('FLASK_ENV', 'default')
print('ENV :' + str(config_name))
# leadgen_app.config.from_object(eval(settings[config_name]))
leadgen_app.config.from_object(app_config[config_name])
leadgen_app.config.from_pyfile('config.cfg', silent=True)
# Configure logging
leadgen_app.logger.setLevel(leadgen_app.config['LOGGING_LEVEL'])
handler = logging.FileHandler(leadgen_app.config['LOGGING_LOCATION'])
handler.setLevel(leadgen_app.config['LOGGING_LEVEL'])
formatter = logging.Formatter(leadgen_app.config['LOGGING_FORMAT'])
handler.setFormatter(formatter)
leadgen_app.logger.addHandler(handler)
leadgen_app.logger.propagate = 0
# Configure sqlalchemy
leadgen_app.app_context().push()
db.init_app(leadgen_app)
# with leadgen_app.app_context():
# db.create_all()
from leads.leads_bp import leads_bp
from process.process_bp import process_bp
from CAAPI.caapi_bp import caAPI_bp
leadgen_app.register_blueprint(leads_bp)
leadgen_app.register_blueprint(process_bp)
leadgen_app.register_blueprint(caAPI_bp)
return leadgen_app
Where am I making a mistake to run my test case successfully?
The KeyError is caused by app_config[config_name].
config_name comes from config_name = os.getenv('FLASK_ENV').
getenv defaults to None when no value is set, see https://docs.python.org/3/library/os.html#os.getenv
This means you have to set the environment variable in order to make tests pass.
You could also debug your application with pdb - I gave a lightning talk how to debug a Flask application...
https://www.youtube.com/watch?v=Fxkco-gS4S8&ab_channel=PythonIreland
So I figured out an answer to this. here is what I did.
I made changes to my setUp() function in my testcase file
def setUp(self):
self.app = create_app(db)
self.client = self.app.test_client(self)
with self.app.app_context():
# create all tables
db.create_all()
and then I imported from app_setup import create_app in my testcase file. And finally I made changes in app_setup.py in function
def create_app(db, config_name='default')
And my testcases are now running.

Django channels Websocket Disconnect

I want my Django app 'popinion1' to communicate via textmessage with a local machine.
pip freeze :
asgi-redis==1.4.3
asgiref==2.3.2
async-timeout==3.0.1
autobahn==18.12.1
channels==2.1.3
daphne==2.2.4
Django==2.1.3
redis==2.10.6
Twisted==18.9.0
When I do "manage.py runserver" there seems to be a connection or at least no errors
However as soon as I refresh the browser in terminal I get:
ERROR - ws_protocol - [Failure instance: Traceback: class'ValueError'>: No route found for path 'input/' [lots of lines]
ending with: WebSocket DISCONNECT /input/ [127.0.0.1:50506]
with "/input/" being my app.
Firefox inspector reports:
Firefox can't establish connection to Server with ws://127.0.0.1:8000
/input/ being my app.
my routing.py is
from django.conf.urls import url
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidator, OriginValidator
from input.consumers import ChatConsumer
print('ChatConsumer: ', ChatConsumer.name)
application = ProtocolTypeRouter({
'websocket': AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
[
url(r'^input/(?P<username>[\w.#+-]+)/$', ChatConsumer),
]
)
)
)
})
the javascript in the html template:
<script>
console.log(window.location)
var loc = window.location
var wsStart = 'ws://'
if (loc.protocol == 'https:'){
wsStart = 'wss://'
}
var endpoint = wsStart + loc.host + loc.pathname
var socket = new WebSocket(endpoint)
socket.onmessage = function(e){
console.log("message", e)
}
socket.onopen= function(e){
console.log("open", e)
}
socket.onerror= function(e){
console.log("error", e)
}
socket.onclose= function(e){
console.log("close", e)
}
</script>
my consumers.py
import asyncio
import json
from django.contrib.auth import get_user_model
from channels.consumer import AsyncConsumer
from channels.db import database_sync_to_async
from .models import Thread, ChatMessage
from asgiref.sync import async_to_sync
class ChatConsumer(AsyncConsumer):
name = 'ChatConsumer'
async def websocket_connect(self, event):
print('connected! ', event)
await self.send({
"type": "websocket.accept"
})
async def websocket_receive(self, event):
print('receive! ', event)
async def websocket_disconnect(self, event):
print('disconnected! ', event)
CHANNEL_LAYERS in settings.py
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'asgi_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [('localhost', 6379)],
},
#'ROUTING': 'popinion_project.routing.channel_routing',
}
}
so is it a wrong address in the routing.py? What's also weird is the last import of "ChatConsumer" in routing.py. It's "unresolved reference" but the print statement works.
print('ChatConsumer: ', ChatConsumer.name)
I'm following this tutorial
https://www.youtube.com/watch?v=RVH05S1qab8
I'd be happy to know how to get the websocket to connect. Hopefully provided all necessary information. Thanks in advance
The solution I used. It had something to do with the use of url.
from django.urls import re_path
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidator, OriginValidator
from chat.consumers import ChatConsumer
application = ProtocolTypeRouter({
# Empty for now (http->django views is added by default)
'websocket': AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
[
re_path(r"^messages/(?P<username>[\w.#+-]+)", ChatConsumer),
]
)
)
)
})

How to render pdf from angular io (5) sites with phantomjs

I just put some image and try to render pdf:
phantom.create().then(async function(ph) {
let page = await ph.createPage();
let status = await page.open("http://localhost:4000")
await page.render('file.pdf');
ph.exit();
});
But i get blank pdf file.
I also try
page.onLoadFinished
But it is never income to it.
I also try:
await new Promise(resolve => setTimeout(() => resolve(), 10000));
But nothing.
I solved this issue by running phantom alone, and figure out that i need to uncomment this lines in polyfills:
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/weak-map';
import 'core-js/es6/set';

React.js unit testing with d3-npm

I am creating a forced graph in react using d3 for npm.
The graph is created using the follows:
https://medium.com/walmartlabs/d3v4-forcesimulation-with-react-8b1d84364721
I am trying to set up the testing environment as follows:
https://ericnish.io/blog/how-to-unit-test-react-components-with-enzyme/
the problem is when I run the test I keep on getting
Cannot read property 'matches' of undefined
at C:\workspace\project\node_modules\d3-selection\build\d3-selection.js:83:15
I have imported d3 in my graph component as follows:
import * as d3 from 'd3';
It seems like when I import my react component in my test file, it freaks out. This is my test file:
import React from 'react'
import {shallow, mount, render} from 'enzyme'
import {expect} from 'chai'
import * as d3 from 'd3';
import graph from '.../components/graph ';
describe('graph ', () => {
it('should have the main svg', (done) => {
const wrapper = shallow(<graph />);
expect(wrapper.find('svg')).to.have.length(1);
done()
})
})
How can I get rid of this error?
Create a file, e.g. polyfill.js:
global.document.documentElement = {matches: () => false};
And import it right before you import DS3 (or any other import that transitively imports D3):
import React from 'react'
import {shallow, mount, render} from 'enzyme'
import {expect} from 'chai'
import './polyfill';
import * as d3 from 'd3';

StealJS error: Cross origin requests are not supported for protocol schemes

I am having an error like this:
XMLHttpRequest cannot load file:///Users/mshin/workspace/spirent/trinity/trinity-link/public/node_modules/can/view/stache/system.js. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
home.js:
import can from 'can';
import template from './home.stache!';
export default can.Component.extend({
tag: 'home',
template: template
});
The build config in Gruntfile:
"steal-build": {
default: {
options: {
system: {
config: "package.json!npm",
bundlesPath: "production"
},
buildOptions: {
minify: true,
sourceMaps: true
}
}
}
}
I don't know why I am getting this error message in production mode. In development environment, it works fine. Also, it is fine on test environment. I am running QUnit test with testee.
home_test.js:
import QUnit from 'steal-qunit';
import ViewModel from 'components/home/home';
import can from 'can';
import stache from 'can/view/stache/';
import $ from 'jquery';
var template = can.stache('<home></home>'),
$component;
QUnit.module('home component', {
setup: function() {
$('#trinity-js-tests').html(template());
$component = $('#trinity-js-tests').find('home');
}
});
QUnit.test('title tag', function() {
QUnit.ok($component.find('h1'), 'Page shows title with <h1> tag');
});
QUnit.test('title content', function() {
QUnit.strictEqual($component.find('h1').text(), 'This is homepage.', 'Title is "This is homepage."');
});
However, if I change the home.js to like this:
import can from 'can';
export default can.Component.extend({
tag: 'home',
template: can.view('components/home/home.stache)
});
It works fine in production and development environment, but in test the last test case fails.
1) QUnit "public/tests/test.html" on PhantomJS 1.9.8 / Mac OS X 0.0.0: home component title content Title is "This is homepage.":
Error: Expected This is homepage. but was
at http://localhost:3996/public/tests/test.html?__token=k8l88m:1340
at http://localhost:3996/public/tests/test.html?__token=k8l88m:1907
at :33
at http://localhost:3996/public/tests/test.html?__token=k8l88m:895
at http://localhost:3996/public/tests/test.html?__token=k8l88m:1024
at process (http://localhost:3996/public/tests/test.html?__token=k8l88m:583)
at begin (http://localhost:3996/public/tests/test.html?__token=k8l88m:628)
at http://localhost:3996/public/tests/test.html?__token=k8l88m:644
It looks like you are loading it from the file:// protocol, is that correct? If so that's likely your problem.
I found what I missed in the code.
main.js
import $ from 'jquery';
import _ from 'lodash';
import stache from 'can/view/stache/';
import can from 'can';
import 'components/route/';
import 'less/trinity.less!';
I didn't import can/view/stache/system in it.
To use system plugin in can.stache, I need to import the specific file to main javascript file.
So, the file should be
import $ from 'jquery';
import _ from 'lodash';
import stache from 'can/view/stache/';
import 'can/view/stache/system'; // this is the added line
import can from 'can';
import 'components/route/';
import 'less/trinity.less!';

Resources