Closed ad-m closed 9 years ago
Hmm SOA#1: Dziwne, u mnie działa ;)
Sprawdziłem na danych pobranych dzisiaj, import do pustej bazy danych pobranych dzisiaj:
$ python manage.py teryt_parse ../dane/20150716/WMRODZ.xml
$ python manage.py teryt_parse ../dane/20150716/TERC.xml
$ python manage.py teryt_parse ../dane/20150716/SIMC.xml
$ python manage.py teryt_parse ../dane/20150716/ULIC.xml
Import robiłeś na jakiej wersji kodu? Prosto z repo czy może ze swoimi poprawkami? Może wprowadziłeś jakieś zmiany z powodu #6 i coś z transakcjami się pomieszało?
Hmm… PostgreSQL, czy MySQL? W moim przypadku MySQL.
Skasowałem forka i modyfikowałem tylko testy.
from os import path
import zipfile
import requests
from django.test import TestCase
class TestCommand(TestCase):
tmp_dir = '/tmp/'
files = {
'ULIC.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1246',
'TERC.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1110',
'SIMC.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1112',
'WMRODZ.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=941'
}
@staticmethod
def _save_file(filename, url):
filepath = path.join(TestCommand.tmp_dir, filename+".zip")
with open(filepath, 'wb') as handle:
response = requests.get(url, stream=True)
if response.ok:
for block in response.iter_content(1024):
handle.write(block)
with open(filepath) as handle:
myzipfile = zipfile.ZipFile(handle)
myzipfile.extract(filename, TestCommand.tmp_dir)
def setUp(self):
# _, tmp_dir = mkstemp()
for filename, url in self.files.items():
TestCommand._save_file(filename, url)
def test_command(self):
for filename in self.files.keys():
management.call_command('teryt_parse', path.join(self.tmp_dir, filename))
Daje wynik:
ERROR: test_command (teryt.tests.test_models.TestCommand)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/travis/build/ad-m/django-teryt/teryt/tests/test_models.py", line 196, in test_command
management.call_command('teryt_parse', path.join(self.tmp_dir, filename), stderr=a)
File "/home/travis/build/ad-m/django-teryt/.tox/py27-django-17/lib/python2.7/site-packages/django/core/management/__init__.py", line 115, in call_command
return klass.execute(*args, **defaults)
File "/home/travis/build/ad-m/django-teryt/.tox/py27-django-17/lib/python2.7/site-packages/django/core/management/base.py", line 338, in execute
output = self.handle(*args, **options)
File "/home/travis/build/ad-m/django-teryt/.tox/py27-django-17/lib/python2.7/site-packages/django/db/transaction.py", line 454, in inner
return func(*args, **kwargs)
File "/home/travis/build/ad-m/django-teryt/teryt/management/commands/teryt_parse.py", line 56, in handle
raise CommandError("Database integrity error: {}".format(e))
CommandError: Database integrity error: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`test_django_teryt`.`teryt_miejscowosc`, CONSTRAINT `D3c5364cfbb51df1bef2196d31f93e17` FOREIGN KEY (`jednostka_id`) REFERENCES `teryt_jednostkaadministracyjna` (`id`))')
Stwierdziłem na python 2.7 django 1.{6,7}. Z powodu #6 nie dotyczy django 1.8. Nie skonfigurowałem MySQL z python 3.4.
Nigdy z MySQLem nie testowałem tej appki (ale planuję). Natomiast co do samego testu:
Python 2.7.3 (default, Mar 13 2014, 11:03:55)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> files = {
... 'ULIC.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1246',
... 'TERC.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1110',
... 'SIMC.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1112',
... 'WMRODZ.xml': 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=941'
... }
>>> for filename in files.keys():
... print filename
...
SIMC.xml
ULIC.xml
WMRODZ.xml
TERC.xml
Tymczasem ważna jest kolejność wczytywania plików. Musi być tak:
WMRODZ.xml
TERC.xml
SIMC.xml
ULIC.xml
No to …
from collections import OrderedDict
from tempfile import mkstemp
from os import path
import zipfile
import requests
from django.utils import six
from django.test import TestCase
from django.db import models
from django.core import management
class TestCommand(TestCase):
tmp_dir = '/tmp/'
files = OrderedDict([
('WMRODZ.xml','http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=941'),
('TERC.xml', 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1110'),
('SIMC.xml','http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1112'),
('ULIC.xml','http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1246'),
])
@staticmethod
def _save_file(filename, url):
filepath = path.join(TestCommand.tmp_dir, filename+".zip")
with open(filepath, 'wb') as handle:
response = requests.get(url, stream=True)
if response.ok:
for block in response.iter_content(1024):
handle.write(block)
with open(filepath) as handle:
myzipfile = zipfile.ZipFile(handle)
myzipfile.extract(filename, TestCommand.tmp_dir)
def setUp(self):
# _, tmp_dir = mkstemp()
for filename, url in self.files.items():
TestCommand._save_file(filename, url)
def test_command(self):
for filename in self.files.keys():
management.call_command('teryt_parse', path.join(self.tmp_dir, filename))
In [1]: from collections import OrderedDict
In [2]: files = OrderedDict([
...: ('WMRODZ.xml','http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=941'),
...: ('TERC.xml', 'http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1110'),
...: ('SIMC.xml','http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1112'),
...: ('ULIC.xml','http://www.stat.gov.pl/broker/access/prefile/downloadPreFile.jspa?id=1246'),
...: ])
In [3]: files.keys()
Out[3]: ['WMRODZ.xml', 'TERC.xml', 'SIMC.xml', 'ULIC.xml']
Podczas testu:
CommandError: Database integrity error: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`test_django_teryt`.`teryt_miejscowosc`, CONSTRAINT `D2feb4f7508a1889b1c1f2d22b639128` FOREIGN KEY (`miejscowosc_nadrzedna_id`) REFERENCES `teryt_miejscowosc` (`symbol`))')
No to teraz mamy rzeczywisty problem, ale jak domyślam się wynika on z faktu, że MySQL jest niekoszerny tj niezgodny ze standardem ;)
Wg standardu domyślnie FK powinny być sprawdzane dopiero w czasie commita. A tymczasem MySQL nie potrafi opóźnić sprawdzania FK i robi to bezpośrednio w czasie wstawiania rekordu do bazy: "InnoDB checks foreign key constraints immediately; the check is not deferred to transaction commit. According to the SQL standard, the default behavior should be deferred checking." (http://dev.mysql.com/doc/refman/5.7/en/innodb-foreign-key-constraints.html).
Trzeba by więc posortować dane przed wstawianiem. Myślę, wystarczy proste sortowanie: najpierw wszystko co nie ma miejscowości nadrzędnej a później wszystko co ma. Chyba, że okaże się, że w SIMC są części części miejscowości - to trzeba będzie sprytniejszy algorytm sortowania zrobić.
Kolejny punkt na liście TODO do refaktoringu.
Na https://travis-ci.org/ad-m/django-teryt/builds/71495108 jest buildlog dla mojego forka wspierającego MySQL-a. Obrazuje on omawiany problem.
Z względu na driver mysql testy oblewają dla python 3.4. Natomiast testy integracyjne dla python 2.7 są wiarygodne.
Try to turn off foreign key constraint globally for mysql, do the following: SET GLOBAL FOREIGN_KEY_CHECKS=0; and remember to set it back when you are done SET GLOBAL FOREIGN_KEY_CHECKS=1;
Szanowny,
Coś chyba się popsuło w danych wejściowych. WMRODZ.xml i TERC.xml importuje się prawidłowo. Nie mogę tego debugować teraz.
Z poważaniem i jawnością!