Compare commits

...

77 Commits

Author SHA1 Message Date
ad29045ace Bump version: 0.21.2.1 → 0.21.2.2 2020-07-29 11:40:41 +03:00
c919e46af5 PoliticsAPI extended and bugfixed 2020-07-29 11:40:32 +03:00
644b4d70e1 Bump version: 0.21.2 → 0.21.2.1 2020-07-29 11:23:31 +03:00
6dbbd054ba bugfix 2020-07-29 09:27:02 +03:00
0ee952e504 bugfix 2020-07-29 09:21:49 +03:00
bb9b198a53 Bump version: 0.21.1 → 0.21.2 2020-07-28 19:34:19 +03:00
cb22e631ca Merge branch 'memory-optimisation'
* memory-optimisation:
  Company cleanup optimisation
  JSON.dump sort_keys parameter throwing mysterious errors
  Fixed memory leak in Battle and MyCompanies classes
2020-07-28 19:33:52 +03:00
c43e20c8f6 Return all Non-Terrain divisions and their bh damage 2020-07-28 19:33:30 +03:00
c8f41b97af Company cleanup optimisation 2020-07-28 19:25:22 +03:00
d483bcbcb9 JSON.dump sort_keys parameter throwing mysterious errors 2020-07-28 18:29:25 +03:00
a316f277fb Fixed memory leak in Battle and MyCompanies classes 2020-07-28 18:28:03 +03:00
e8c81d17e6 Weapons kind should be singular - 'weapon' 2020-07-19 07:56:15 +03:00
edb4d8851b Bump version: 0.21.0.3 → 0.21.1 2020-07-16 11:15:04 +03:00
76edd6bb7d Update traveling to incorporate travel cooldown (1travel / 15sec) 2020-07-16 11:14:35 +03:00
8da376b852 Change variable names to be more precise if argument must be and id or instance (battle/battle_id, division/division_id) 2020-07-16 11:13:29 +03:00
b6b0be7442 Minimize error reporting locals to not duplicate instance.json data 2020-07-16 11:11:35 +03:00
ed434b605d Refactor '.format()' calls to f-strings 2020-07-16 11:08:31 +03:00
2bd311def6 Dev requirement update 2020-07-14 15:37:59 +03:00
4b437c2ba6 Update README.rst 2020-07-14 14:11:20 +03:00
cc8a1450d4 Merge pull request #3 from codacy-badger/codacy-badge
Add a Codacy badge to README.rst
2020-07-14 14:08:45 +03:00
0c9f3756ea Add Codacy badge 2020-07-14 11:07:36 +00:00
9de07950b8 Bump version: 0.21.0.2 → 0.21.0.3 2020-07-13 11:24:29 +03:00
766b7b2d95 bugfix 2020-07-12 10:45:44 +03:00
c730981865 Bump version: 0.21.0.1 → 0.21.0.2 2020-07-11 10:21:21 +03:00
d70c3e2c9e Typos 2020-07-11 10:21:12 +03:00
d044af6d2f Bump version: 0.21.0 → 0.21.0.1 2020-07-11 10:08:09 +03:00
dd75b10d2f missing __hash__ 2020-07-11 09:54:23 +03:00
a45dd7e0c3 Bump version: 0.20.4 → 0.21.0 2020-07-11 09:39:25 +03:00
316a826c93 Merge branch 'master' of github.com:eeriks/erepublik 2020-07-11 09:38:20 +03:00
c9710733e2 Typo 2020-07-11 09:37:22 +03:00
9e678d6b51 Bump version: 0.20.3.11 → 0.20.4 2020-07-10 17:13:15 +03:00
88517cb076 Bugfix 2020-07-10 17:09:28 +03:00
01c8aef012 Bugfix: South Africa link 2020-07-10 17:08:58 +03:00
d7ac66bd69 Bump version: 0.20.3.10 → 0.20.3.11 2020-07-10 12:16:53 +03:00
e8739caca1 fix 2020-07-10 12:16:18 +03:00
9df9c1cd87 Bump version: 0.20.3.9 → 0.20.3.10 2020-07-10 00:47:42 +03:00
1b004f163a bugfix 2020-07-10 00:47:36 +03:00
72bd2787d3 Bump version: 0.20.3.8 → 0.20.3.9 2020-07-09 19:11:04 +03:00
bfa6cb1e78 bugfix 2020-07-09 19:10:55 +03:00
1db7c98b47 Bump version: 0.20.3.7 → 0.20.3.8 2020-07-09 18:51:09 +03:00
1f21a71c74 bugfix 2020-07-09 18:51:00 +03:00
0531c8997b Bump version: 0.20.3.6 → 0.20.3.7 2020-07-09 17:42:24 +03:00
5a8a0a3920 mavericks 2020-07-09 17:42:15 +03:00
d938908986 Bump version: 0.20.3.5 → 0.20.3.6 2020-07-09 14:42:51 +03:00
ffbbd25e54 Code cleanup 2020-07-09 14:42:40 +03:00
81bd09e13e Bump version: 0.20.3.4 → 0.20.3.5 2020-07-09 08:53:45 +03:00
fc4295d8bd bugix 2020-07-09 08:53:32 +03:00
7bbf7cb34a Bump version: 0.20.3.3 → 0.20.3.4 2020-07-09 08:46:19 +03:00
8ce56a31f7 bugix 2020-07-09 08:46:12 +03:00
ef23b3b8db Bump version: 0.20.3.2 → 0.20.3.3 2020-07-09 08:34:41 +03:00
cd861ea29b bugfix 2020-07-09 08:34:38 +03:00
5b580f7c79 Bump version: 0.20.3.1 → 0.20.3.2 2020-07-09 08:27:55 +03:00
0061503581 passed int instead of Country to travel 2020-07-09 08:27:48 +03:00
c78dbae925 Merge branch 'master' of github.com:eeriks/erepublik 2020-07-09 08:25:10 +03:00
6a9b574454 class serialization 2020-07-09 08:09:58 +03:00
cde97c6259 Bump version: 0.20.3 → 0.20.3.1 2020-07-08 19:30:47 +03:00
7fa02be7d3 bugfix 2020-07-08 19:30:41 +03:00
098bfe5f3f Bump version: 0.20.2.2 → 0.20.3 2020-07-08 18:28:56 +03:00
c26689a8fa Start hunting empty medals from oldest battles 2020-07-08 18:28:20 +03:00
94c416faa5 Battle, BattleSide, BattleDivision repr and str definitions 2020-07-08 18:27:48 +03:00
ba840765be Moving away from passing object ids around and towards passing objects and even using object functions 2020-07-08 17:30:22 +03:00
3927b9ba6b Bump version: 0.20.2.1 → 0.20.2.2 2020-07-06 15:52:42 +03:00
cd5c0b161f Switch to Fight mode if deployed is active 2020-07-06 15:52:37 +03:00
39defc0fd7 Bump version: 0.20.2 → 0.20.2.1 2020-07-04 12:28:09 +03:00
6c8dbcd99e Updated fighting division chooser 2020-07-04 12:28:02 +03:00
d07334f602 Bump version: 0.20.1.7 → 0.20.2 2020-07-04 00:31:33 +03:00
bcb27da54f Summer challange shanged battle list API 2020-07-04 00:31:26 +03:00
7ac22b5e11 Bump version: 0.20.1.6 → 0.20.1.7 2020-07-03 23:56:07 +03:00
5bd3d72a63 Quickfix for summer terrains 2020-07-03 23:54:32 +03:00
33d2c641df Config.json creator HTML 2020-07-03 15:32:13 +03:00
d1e078e443 Bump version: 0.20.1.5 → 0.20.1.6 2020-06-29 14:58:27 +03:00
71c64b0cf5 minor tweaks 2020-06-29 14:57:40 +03:00
3b5b15553d Bomb deploy bugfix where deploying in RW could leave player stranded in non residency region. Battle update bugfix where self.all_battles could be empty while re-parsing every battle 2020-06-29 14:48:37 +03:00
d077e10f15 Bump version: 0.20.1.4 → 0.20.1.5 2020-06-26 17:27:11 +03:00
8eb5235f12 Deploy bombs in RWs bugfix 2020-06-26 17:27:02 +03:00
a873d223c1 Bump version: 0.20.1.3 → 0.20.1.4 2020-06-25 14:18:41 +03:00
ed96143c80 Flake8
Battle.div is no longer a defaultdict, but should raise error if trying to access division which isn't assigned
2020-06-25 14:17:05 +03:00
14 changed files with 1599 additions and 954 deletions

View File

@ -88,9 +88,3 @@ dist: clean ## builds source and wheel package
install: clean ## install the package to the active Python's site-packages
python setup.py install
setcommit:
bash set_commit_id.sh
# commit=`git log -1 --pretty=format:%h`
# sed -i.bak -E "s|COMMIT_ID = \".+\"|COMMIT_ID = \"$(commit)\"|g" erepublik/utils.py
# mv erepublik/utils.py.bak erepublik/utils.py

View File

@ -10,6 +10,10 @@ eRepublik script
:target: https://erepublik.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://api.codacy.com/project/badge/Grade/eaa7ae43d23f4c0abab65c3bde89475a
:target: https://app.codacy.com/manual/eeriks/erepublik?utm_source=github.com&utm_medium=referral&utm_content=eeriks/erepublik&utm_campaign=Badge_Grade_Dashboard
:alt: Codacy Badge
Python package for automated eRepublik playing
@ -30,3 +34,4 @@ This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypack
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage

387
docs/index.html Normal file
View File

@ -0,0 +1,387 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="Eriks Karls">
<meta name="generator" content="Jekyll v4.0.1">
<title>eBot configuration</title>
<!-- CSS only -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
crossorigin="anonymous">
<!-- JS, Popper.js, and jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI"
crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<div class="p-3 text-center">
<h1>eBot configuration file generator</h1>
<!-- <h2>-->
<!-- <span class="d-inline d-sm-none d-md-none d-lg-none d-xl-none">XS</span>-->
<!-- <span class="d-none d-sm-inline d-md-none d-lg-none d-xl-none">SM</span>-->
<!-- <span class="d-none d-sm-none d-md-inline d-lg-none d-xl-none">MD</span>-->
<!-- <span class="d-none d-sm-none d-md-none d-lg-inline d-xl-none">LG</span>-->
<!-- <span class="d-none d-sm-none d-md-none d-lg-none d-xl-inline">XL</span>-->
<!-- </h2>-->
</div>
<div class="row pt-4">
<div class="col-12">
<form>
<div class="row">
<div class="col-12 col-sm-8 col-md-6">
<h3>Login data</h3>
<div class="form-group">
<input type="email" class="form-control form-control-sm" onchange="updateJson()" id="email" placeholder="E-mail...">
<input type="password" class="form-control form-control-sm mt-3" onchange="updateJson()" id="password" disabled placeholder="Password..."
aria-describedby="passwordHelpBlock">
<small id="passwordHelpBlock" class="form-text text-muted"><strong>NEVER</strong> enter Your passwords on 3rd party sites and <strong class="text-upper">DO NOT</strong> reuse Your
password!</small>
</div>
</div>
<div class="col-6 col-md-3">
<h3>Basic tasks</h3>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="work" checked>
<label class="custom-control-label" for="work">Work</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="train" checked>
<label class="custom-control-label" for="train">Train</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="ot" checked>
<label class="custom-control-label" for="ot">Work overtime</label>
</div>
</div>
<div class="col-6 col-md-3">
<h3>Misc</h3>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="renew_houses" checked>
<label class="custom-control-label" for="renew_houses">Auto renew houses</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="random_sleep" checked>
<label class="custom-control-label" for="random_sleep">Random sleep</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="buy_gold">
<label class="custom-control-label" for="buy_gold">Auto buy 10g</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="interactive" checked>
<label class="custom-control-label" for="interactive">Interactive</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="debug">
<label class="custom-control-label" for="debug">Debug</label>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-sm-6">
<h3>Production</h3>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="wam" checked>
<label class="custom-control-label" for="wam">Work as manager</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="employ">
<label class="custom-control-label" for="employ">Employ employees</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_buy_raw" checked>
<label class="custom-control-label" for="auto_buy_raw">Auto buy missing RAW</label>
</div>
</div>
<div class="form-group">
<h6 class="">Auto sell produced products</h6>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_frm">
<label class="custom-control-label" for="auto_sell_frm">Food Raw</label>
</div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_food">
<label class="custom-control-label" for="auto_sell_food">Food</label>
</div>
<div class="clearfix"></div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_wrm">
<label class="custom-control-label" for="auto_sell_wrm">Weapon Raw</label>
</div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_weapons">
<label class="custom-control-label" for="auto_sell_weapons">Weapon</label>
</div>
<div class="clearfix"></div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_hrm">
<label class="custom-control-label" for="auto_sell_hrm">House Raw</label>
</div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_house">
<label class="custom-control-label" for="auto_sell_house">House</label>
</div>
<div class="clearfix"></div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_arm">
<label class="custom-control-label" for="auto_sell_arm">Aircraft Raw</label>
</div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_air">
<label class="custom-control-label" for="auto_sell_air">Aircraft Weapon</label>
</div>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="auto_sell_all">
<label class="custom-control-label" for="auto_sell_all">Auto sell all (also from inventory)</label>
</div>
</div>
<div class="col-12 col-sm-6">
<h3>Fighting</h3>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="fight" checked>
<label class="custom-control-label" for="fight">Fight</label>
</div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="air" checked>
<label class="custom-control-label" for="air">Air</label>
</div>
<div class="custom-control custom-switch custom-control-inline">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="ground">
<label class="custom-control-label" for="ground">Ground</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="boosters">
<label class="custom-control-label" for="boosters">Use ground boosters</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="continuous_fighting">
<label class="custom-control-label" for="continuous_fighting">Continue fighting all FF in round</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="next_energy" checked>
<label class="custom-control-label" for="next_energy">Fight for next WC +1hp/6min if reachable by FF</label>
</div>
</div>
<div class="form-group">
<div class="form-check form-check-inline">
<input type="radio" class="form-check-input" onchange="updateJson()" id="all_in" name="fight_amount" value="all_in">
<label class="form-check-label" for="all_in">All energy</label>
</div>
<div class="form-check form-check-inline">
<input type="radio" class="form-check-input" onchange="updateJson()" id="h_energy" name="fight_amount" value="h_energy" checked>
<label class="form-check-label" for="h_energy">1h energy</label>
</div>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="rw_def_side" checked>
<label class="custom-control-label" for="rw_def_side">In RWs fight on right side (occupier/defender)</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="travel_to_fight" checked>
<label class="custom-control-label" for="travel_to_fight">Travel to fight</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="epic_hunt">
<label class="custom-control-label" for="epic_hunt">Hunt epics</label>
</div>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" onchange="updateJson()" id="epic_hunt_ebs">
<label class="custom-control-label" for="epic_hunt_ebs">Spend <small>[all]</small> EBs in epics</label>
</div>
</div>
</div>
</form>
</div>
<div class="col-12">
<pre id="json-output"></pre>
</div>
</div>
</div>
<script>
function disable(element){
element.checked = false;
element.disabled = true;
}
function updateJson() {
let config = {};
let email = document.getElementById('email'); // Generated
config.email = email.value;
config.password = "";
let work = document.getElementById('work'); // Generated
config.work = work.checked;
let train = document.getElementById('train'); // Generated
config.train = train.checked;
let ot = document.getElementById('ot'); // Generated
config.ot = ot.checked;
let renew_houses = document.getElementById('renew_houses'); // Generated
config.renew_houses = renew_houses.checked;
let random_sleep = document.getElementById('random_sleep'); // Generated
config.random_sleep = random_sleep.checked;
let buy_gold = document.getElementById('buy_gold'); // Generated
config.buy_gold = buy_gold.checked;
let interactive = document.getElementById('interactive'); // Generated
config.interactive = interactive.checked;
let debug = document.getElementById('debug'); // Generated
config.debug = debug.checked;
let wam = document.getElementById('wam'); // Generated
config.wam = wam.checked;
let employ = document.getElementById('employ'); // Generated
config.employ = employ.checked;
let auto_buy_raw = document.getElementById('auto_buy_raw'); // Generated
let auto_sell_all = document.getElementById('auto_sell_all'); // Generated
let auto_sell_frm = document.getElementById('auto_sell_frm'); // Generated
let auto_sell_food = document.getElementById('auto_sell_food'); // Generated
let auto_sell_wrm = document.getElementById('auto_sell_wrm'); // Generated
let auto_sell_weapons = document.getElementById('auto_sell_weapons'); // Generated
let auto_sell_hrm = document.getElementById('auto_sell_hrm'); // Generated
let auto_sell_house = document.getElementById('auto_sell_house'); // Generated
let auto_sell_arm = document.getElementById('auto_sell_arm'); // Generated
let auto_sell_air = document.getElementById('auto_sell_air'); // Generated
if (config.wam || config.employ) {
auto_buy_raw.disabled = false;
auto_sell_all.disabled = false;
auto_sell_frm.disabled = false;
auto_sell_food.disabled = false;
auto_sell_wrm.disabled = false;
auto_sell_weapons.disabled = false;
auto_sell_hrm.disabled = false;
auto_sell_house.disabled = false;
auto_sell_arm.disabled = false;
auto_sell_air.disabled = false;
} else {
disable(auto_buy_raw);
disable(auto_sell_all);
disable(auto_sell_food);
disable(auto_sell_weapons);
disable(auto_sell_house);
disable(auto_sell_air);
disable(auto_sell_frm);
disable(auto_sell_wrm);
disable(auto_sell_hrm);
disable(auto_sell_arm);
}
config.auto_buy_raw = auto_buy_raw.checked;
config.auto_sell_all = auto_sell_all.checked;
config.auto_sell = [];
if (auto_sell_food.checked) config.auto_sell.push("food");
if (auto_sell_weapons.checked) config.auto_sell.push("weapon");
if (auto_sell_house.checked) config.auto_sell.push("house");
if (auto_sell_air.checked) config.auto_sell.push("airplane");
if (auto_sell_frm.checked) config.auto_sell.push("foodRaw");
if (auto_sell_wrm.checked) config.auto_sell.push("weaponRaw");
if (auto_sell_hrm.checked) config.auto_sell.push("houseRaw");
if (auto_sell_arm.checked) config.auto_sell.push("airplaneRaw");
let fight = document.getElementById('fight'); // Generated
config.fight = fight.checked;
let air = document.getElementById('air'); // Generated
let ground = document.getElementById('ground'); // Generated
let boosters = document.getElementById('boosters'); // Generated
let continuous_fighting = document.getElementById('continuous_fighting'); // Generated
let next_energy = document.getElementById('next_energy'); // Generated
let all_in = document.getElementById('all_in'); // Generated
let h_energy = document.getElementById('h_energy'); // Generated
let rw_def_side = document.getElementById('rw_def_side'); // Generated
let travel_to_fight = document.getElementById('travel_to_fight'); // Generated
let epic_hunt = document.getElementById('epic_hunt'); // Generated
let epic_hunt_ebs = document.getElementById('epic_hunt_ebs'); // Generated
if (config.fight){
air.disabled = false;
ground.disabled = false;
boosters.disabled = false;
continuous_fighting.disabled = false;
next_energy.disabled = false;
all_in.disabled = false;
h_energy.disabled = false;
rw_def_side.disabled = false;
travel_to_fight.disabled = false;
epic_hunt.disabled = false;
epic_hunt_ebs.disabled = false;
if (!epic_hunt.checked) disable(epic_hunt_ebs);
} else {
disable(air);
disable(ground);
disable(boosters);
disable(continuous_fighting);
disable(next_energy);
disable(all_in);
disable(h_energy);
disable(rw_def_side);
disable(travel_to_fight);
disable(epic_hunt);
disable(epic_hunt_ebs);
}
config.air = air.checked;
config.ground = ground.cehcked;
config.boosters = boosters.checked;
config.continuous_fighting = continuous_fighting.checked;
config.next_energy = next_energy.checked;
config.all_in = all_in.checked;
config.rw_def_side = rw_def_side.checked;
config.travel_to_fight = travel_to_fight.checked;
config.epic_hunt = epic_hunt.checked;
config.epic_hunt_ebs = config.epic_hunt ? epic_hunt_ebs.checked : config.epic_hunt;
let pre = document.getElementById('json-output');
pre.textContent = JSON.stringify(config, null, 2);
}
updateJson();
</script>
</body>
</html>
<!--
{
"email": "",
"password": "",
"work": true,
"train": true,
"ot": true,
"renew_houses": true,
"random_sleep": true,
"buy_gold": true,
"interactive": true,
"debug": true,
"wam": true,
"employ": true,
"auto_buy_raw": true,
"auto_sell_all": true,
"auto_sell": [
"food",
"weapon",
"house",
"airplane",
"foodRaw",
"weaponRaw",
"houseRaw",
"airplaneRaw"
],
"fight": true,
"air": true,
"boosters": true,
"continuous_fighting": true,
"next_energy": true,
"all_in": false,
"rw_def_side": true,
"travel_to_fight": true,
"epic_hunt": true,
"epic_hunt_ebs": true
}
-->

View File

@ -4,10 +4,9 @@
__author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv'
__version__ = '0.20.1.3'
__commit_id__ = "2f69090"
__version__ = '0.21.2.2'
from erepublik import classes, utils
from erepublik import classes, utils, constants
from erepublik.citizen import Citizen
__all__ = ["classes", "utils", "Citizen"]
__all__ = ["classes", "utils", "Citizen", ]

View File

@ -5,7 +5,7 @@ from typing import Any, Dict, List, Mapping, Union
from requests import Response, Session
from erepublik import utils
from . import constants, utils
__all__ = ['SlowRequests', 'CitizenAPI']
@ -45,7 +45,7 @@ class SlowRequests(Session):
})
@property
def __dict__(self):
def as_dict(self):
return dict(last_time=self.last_time, timeout=self.timeout, user_agent=self.headers['User-Agent'],
request_log_name=self.request_log_name, debug=self.debug)
@ -132,23 +132,23 @@ class CitizenBaseAPI:
class ErepublikAnniversaryAPI(CitizenBaseAPI):
def _post_main_collect_anniversary_reward(self) -> Response:
return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": self.token})
return self.post(f"{self.url}/main/collect-anniversary-reward", data={"_token": self.token})
# 12th anniversary endpoints
def _get_anniversary_quest_data(self) -> Response:
return self.get("{}/main/anniversaryQuestData".format(self.url))
return self.get(f"{self.url}/main/anniversaryQuestData")
def _post_map_rewards_unlock(self, node_id: int) -> Response:
data = {'nodeId': node_id, '_token': self.token}
return self.post("{}/main/map-rewards-unlock".format(self.url), data=data)
return self.post(f"{self.url}/main/map-rewards-unlock", data=data)
def _post_map_rewards_speedup(self, node_id: int, currency_amount: int) -> Response:
data = {'nodeId': node_id, '_token': self.token, "currencyCost": currency_amount}
return self.post("{}/main/map-rewards-speedup".format(self.url), data=data)
return self.post(f"{self.url}/main/map-rewards-speedup", data=data)
def _post_map_rewards_claim(self, node_id: int) -> Response:
data = {'nodeId': node_id, '_token': self.token}
return self.post("{}/main/map-rewards-claim".format(self.url), data=data)
return self.post(f"{self.url}/main/map-rewards-claim", data=data)
def _post_main_wheel_of_fortune_spin(self, cost) -> Response:
return self.post(f"{self.url}/wheeloffortune-spin", data={'_token': self.token, "cost": cost})
@ -159,52 +159,52 @@ class ErepublikAnniversaryAPI(CitizenBaseAPI):
class ErepublikArticleAPI(CitizenBaseAPI):
def _get_main_article_json(self, article_id: int) -> Response:
return self.get("{}/main/articleJson/{}".format(self.url, article_id))
return self.get(f"{self.url}/main/articleJson/{article_id}")
def _post_main_article_comments(self, article: int, page: int = 1) -> Response:
data = dict(_token=self.token, articleId=article, page=page)
def _post_main_article_comments(self, article_id: int, page: int = 1) -> Response:
data = dict(_token=self.token, articleId=article_id, page=page)
if page:
data.update({'page': page})
return self.post("{}/main/articleComments".format(self.url), data=data)
return self.post(f"{self.url}/main/articleComments", data=data)
def _post_main_article_comments_create(self, message: str, article: int, parent: int = 0) -> Response:
data = dict(_token=self.token, message=message, articleId=article)
def _post_main_article_comments_create(self, message: str, article_id: int, parent: int = 0) -> Response:
data = dict(_token=self.token, message=message, articleId=article_id)
if parent:
data.update({"parentId": parent})
return self.post("{}/main/articleComments/create".format(self.url), data=data)
return self.post(f"{self.url}/main/articleComments/create", data=data)
def _post_main_donate_article(self, article_id: int, amount: int) -> Response:
data = dict(_token=self.token, articleId=article_id, amount=amount)
return self.post("{}/main/donate-article".format(self.url), data=data)
return self.post(f"{self.url}/main/donate-article", data=data)
def _post_main_write_article(self, title: str, content: str, country: int, kind: int) -> Response:
data = dict(_token=self.token, article_name=title, article_body=content, article_location=country,
article_category=kind)
return self.post("{}/main/write-article".format(self.url), data=data)
def _post_main_write_article(self, title: str, content: str, country_id: int, kind_id: int) -> Response:
data = dict(_token=self.token, article_name=title, article_body=content, article_location=country_id,
article_category=kind_id)
return self.post(f"{self.url}/main/write-article", data=data)
def _post_main_vote_article(self, article_id: int) -> Response:
data = dict(_token=self.token, articleId=article_id)
return self.post("{}/main/vote-article".format(self.url), data=data)
return self.post(f"{self.url}/main/vote-article", data=data)
class ErepublikCompanyAPI(CitizenBaseAPI):
def _post_economy_assign_to_holding(self, factory: int, holding: int) -> Response:
data = dict(_token=self.token, factoryId=factory, action="assign", holdingCompanyId=holding)
return self.post("{}/economy/assign-to-holding".format(self.url), data=data)
def _post_economy_assign_to_holding(self, factory_id: int, holding_id: int) -> Response:
data = dict(_token=self.token, factoryId=factory_id, action="assign", holdingCompanyId=holding_id)
return self.post(f"{self.url}/economy/assign-to-holding", data=data)
def _post_economy_create_company(self, industry: int, building_type: int = 1) -> Response:
data = {"_token": self.token, "company[industry_id]": industry, "company[building_type]": building_type}
return self.post("{}/economy/create-company".format(self.url), data=data,
headers={"Referer": "{}/economy/create-company".format(self.url)})
def _post_economy_create_company(self, industry_id: int, building_type: int = 1) -> Response:
data = {"_token": self.token, "company[industry_id]": industry_id, "company[building_type]": building_type}
return self.post(f"{self.url}/economy/create-company", data=data,
headers={"Referer": f"{self.url}/economy/create-company"})
def _get_economy_inventory_items(self) -> Response:
return self.get("{}/economy/inventory-items/".format(self.url))
return self.get(f"{self.url}/economy/inventory-items/")
def _get_economy_job_market_json(self, country: int) -> Response:
return self.get("{}/economy/job-market-json/{}/1/desc".format(self.url, country))
def _get_economy_job_market_json(self, country_id: int) -> Response:
return self.get(f"{self.url}/economy/job-market-json/{country_id}/1/desc")
def _get_economy_my_companies(self) -> Response:
return self.get("{}/economy/myCompanies".format(self.url))
return self.get(f"{self.url}/economy/myCompanies")
def _post_economy_train(self, tg_ids: List[int]) -> Response:
data: Dict[str, Union[int, str]] = {}
@ -213,11 +213,11 @@ class ErepublikCompanyAPI(CitizenBaseAPI):
data["grounds[%i][train]" % idx] = 1
if data:
data['_token'] = self.token
return self.post("{}/economy/train".format(self.url), data=data)
return self.post(f"{self.url}/economy/train", data=data)
def _post_economy_upgrade_company(self, factory: int, level: int, pin: str = None) -> Response:
data = dict(_token=self.token, type="upgrade", companyId=factory, level=level, pin="" if pin is None else pin)
return self.post("{}/economy/upgrade-company".format(self.url), data=data)
return self.post(f"{self.url}/economy/upgrade-company", data=data)
def _post_economy_work(self, action_type: str, wam: List[int] = None, employ: Dict[int, int] = None) -> Response:
data: Dict[str, Union[int, str]] = dict(action_type=action_type, _token=self.token)
@ -241,174 +241,169 @@ class ErepublikCompanyAPI(CitizenBaseAPI):
f"companies[{max_idx}][own_work]": 0
})
max_idx += 1
return self.post("{}/economy/work".format(self.url), data=data)
return self.post(f"{self.url}/economy/work", data=data)
def _post_economy_work_overtime(self) -> Response:
data = dict(action_type="workOvertime", _token=self.token)
return self.post("{}/economy/workOvertime".format(self.url), data=data)
return self.post(f"{self.url}/economy/workOvertime", data=data)
def _post_economy_job_market_apply(self, citizen: int, salary: float) -> Response:
data = dict(_token=self.token, citizenId=citizen, salary=salary)
return self.post("{}/economy/job-market-apply".format(self.url), data=data)
def _post_economy_job_market_apply(self, citizen_id: int, salary: float) -> Response:
data = dict(_token=self.token, citizenId=citizen_id, salary=salary)
return self.post(f"{self.url}/economy/job-market-apply", data=data)
def _post_economy_resign(self) -> Response:
return self.post("{}/economy/resign".format(self.url),
return self.post(f"{self.url}/economy/resign",
headers={"Content-Type": "application/x-www-form-urlencoded"},
data={"_token": self.token, "action_type": "resign"})
def _post_economy_sell_company(self, factory: int, pin: int = None, sell: bool = True) -> Response:
def _post_economy_sell_company(self, factory_id: int, pin: int = None, sell: bool = True) -> Response:
data = dict(_token=self.token, pin="" if pin is None else pin)
if sell:
data.update({"sell": "sell"})
else:
data.update({"dissolve": factory})
return self.post("{}/economy/sell-company/{}".format(self.url, factory),
data.update({"dissolve": factory_id})
return self.post(f"{self.url}/economy/sell-company/{factory_id}",
data=data, headers={"Referer": self.url})
class ErepublikCountryAPI(CitizenBaseAPI):
def _get_country_military(self, country: str) -> Response:
return self.get("{}/country/military/{}".format(self.url, country))
def _get_country_military(self, country_name: str) -> Response:
return self.get(f"{self.url}/country/military/{country_name}")
def _post_main_country_donate(self, country: int, action: str, value: Union[int, float],
def _post_main_country_donate(self, country_id: int, action: str, value: Union[int, float],
quality: int = None) -> Response:
json = dict(countryId=country, action=action, _token=self.token, value=value, quality=quality)
return self.post("{}/main/country-donate".format(self.url), data=json,
headers={"Referer": "{}/country/economy/Latvia".format(self.url)})
data = dict(countryId=country_id, action=action, _token=self.token, value=value, quality=quality)
return self.post(f"{self.url}/main/country-donate", data=data,
headers={"Referer": f"{self.url}/country/economy/Latvia"})
class ErepublikEconomyAPI(CitizenBaseAPI):
def _get_economy_citizen_accounts(self, organisation_id: int) -> Response:
return self.get("{}/economy/citizen-accounts/{}".format(self.url, organisation_id))
return self.get(f"{self.url}/economy/citizen-accounts/{organisation_id}")
def _get_economy_my_market_offers(self) -> Response:
return self.get("{}/economy/myMarketOffers".format(self.url))
return self.get(f"{self.url}/economy/myMarketOffers")
def _get_main_job_data(self) -> Response:
return self.get("{}/main/job-data".format(self.url))
return self.get(f"{self.url}/main/job-data")
def _post_main_buy_gold_items(self, currency: str, item: str, amount: int) -> Response:
data = dict(itemId=item, currency=currency, amount=amount, _token=self.token)
return self.post("{}/main/buyGoldItems".format(self.url), data=data)
return self.post(f"{self.url}/main/buyGoldItems", data=data)
def _post_economy_activate_booster(self, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, fromInventory=True)
return self.post("{}/economy/activateBooster".format(self.url), data=data)
return self.post(f"{self.url}/economy/activateBooster", data=data)
def _post_economy_activate_house(self, quality: int) -> Response:
data = {"action": "activate", "quality": quality, "type": "house", "_token": self.token}
return self.post("{}/economy/activateHouse".format(self.url), data=data)
return self.post(f"{self.url}/economy/activateHouse", data=data)
def _post_economy_donate_items_action(self, citizen: int, amount: int, industry: int,
def _post_economy_donate_items_action(self, citizen_id: int, amount: int, industry: int,
quality: int) -> Response:
data = dict(citizen_id=citizen, amount=amount, industry_id=industry, quality=quality, _token=self.token)
return self.post("{}/economy/donate-items-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-items/{}".format(self.url, citizen)})
data = dict(citizen_id=citizen_id, amount=amount, industry_id=industry, quality=quality, _token=self.token)
return self.post(f"{self.url}/economy/donate-items-action", data=data,
headers={"Referer": f"{self.url}/economy/donate-items/{citizen_id}"})
def _post_economy_donate_money_action(self, citizen: int, amount: float = 0.0,
def _post_economy_donate_money_action(self, citizen_id: int, amount: float = 0.0,
currency: int = 62) -> Response:
data = dict(citizen_id=citizen, _token=self.token, currency_id=currency, amount=amount)
return self.post("{}/economy/donate-money-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-money/{}".format(self.url, citizen)})
data = dict(citizen_id=citizen_id, _token=self.token, currency_id=currency, amount=amount)
return self.post(f"{self.url}/economy/donate-money-action", data=data,
headers={"Referer": f"{self.url}/economy/donate-money/{citizen_id}"})
def _post_economy_exchange_purchase(self, amount: float, currency: int, offer: int) -> Response:
data = dict(_token=self.token, amount=amount, currencyId=currency, offerId=offer)
return self.post("{}/economy/exchange/purchase/".format(self.url), data=data)
return self.post(f"{self.url}/economy/exchange/purchase/", data=data)
def _post_economy_exchange_retrieve(self, personal: bool, page: int, currency: int) -> Response:
data = dict(_token=self.token, personalOffers=int(personal), page=page, currencyId=currency)
return self.post("{}/economy/exchange/retrieve/".format(self.url), data=data)
return self.post(f"{self.url}/economy/exchange/retrieve/", data=data)
def _post_economy_game_tokens_market(self, action: str) -> Response:
assert action in ['retrieve', ]
data = dict(_token=self.token, action=action)
return self.post("{}/economy/gameTokensMarketAjax".format(self.url), data=data)
return self.post(f"{self.url}/economy/gameTokensMarketAjax", data=data)
def _post_economy_marketplace(self, country: int, industry: int, quality: int,
order_asc: bool = True) -> Response:
data = dict(countryId=country, industryId=industry, quality=quality, ajaxMarket=1,
orderBy="price_asc" if order_asc else "price_desc", _token=self.token)
return self.post("{}/economy/marketplaceAjax".format(self.url), data=data)
return self.post(f"{self.url}/economy/marketplaceAjax", data=data)
def _post_economy_marketplace_actions(self, amount: int, buy: bool = False, **kwargs) -> Response:
if buy:
data = dict(_token=self.token, offerId=kwargs['offer'], amount=amount, orderBy="price_asc", currentPage=1,
buyAction=1)
else:
data = dict(_token=self.token, countryId=kwargs["country"], price=kwargs["price"],
data = dict(_token=self.token, countryId=kwargs["country_id"], price=kwargs["price"],
industryId=kwargs["industry"], quality=kwargs["quality"], amount=amount, sellAction='postOffer')
return self.post("{}/economy/marketplaceActions".format(self.url), data=data)
return self.post(f"{self.url}/economy/marketplaceActions", data=data)
class ErepublikLeaderBoardAPI(CitizenBaseAPI):
def _get_main_leaderboards_damage_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response:
data = (country, weeks, mu)
return self.get("{}/main/leaderboards-damage-aircraft-rankings/{}/{}/{}/0".format(self.url, *data))
def _get_main_leaderboards_damage_aircraft_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-damage-aircraft-rankings/{country_id}/{weeks}/{mu_id}/0")
def _get_main_leaderboards_damage_rankings(self, country: int, weeks: int = 0, mu: int = 0,
div: int = 0) -> Response:
data = (country, weeks, mu, div)
return self.get("{}/main/leaderboards-damage-rankings/{}/{}/{}/{}".format(self.url, *data))
def _get_main_leaderboards_damage_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0, div: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-damage-rankings/{country_id}/{weeks}/{mu_id}/{div}")
def _get_main_leaderboards_kills_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response:
data = (country, weeks, mu)
return self.get("{}/main/leaderboards-kills-aircraft-rankings/{}/{}/{}/0".format(self.url, *data))
def _get_main_leaderboards_kills_aircraft_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-kills-aircraft-rankings/{country_id}/{weeks}/{mu_id}/0")
def _get_main_leaderboards_kills_rankings(self, country: int, weeks: int = 0, mu: int = 0,
div: int = 0) -> Response:
data = (country, weeks, mu, div)
return self.get("{}/main/leaderboards-kills-rankings/{}/{}/{}/{}".format(self.url, *data))
def _get_main_leaderboards_kills_rankings(self, country_id: int, weeks: int = 0, mu_id: int = 0, div: int = 0) -> Response:
return self.get(f"{self.url}/main/leaderboards-kills-rankings/{country_id}/{weeks}/{mu_id}/{div}")
class ErepublikLocationAPI(CitizenBaseAPI):
def _get_main_city_data_residents(self, city: int, page: int = 1, params: Mapping[str, Any] = None) -> Response:
def _get_main_city_data_residents(self, city_id: int, page: int = 1, params: Mapping[str, Any] = None) -> Response:
if params is None:
params = {}
return self.get("{}/main/city-data/{}/residents".format(self.url, city), params={"currentPage": page, **params})
return self.get(f"{self.url}/main/city-data/{city_id}/residents", params={"currentPage": page, **params})
class ErepublikMilitaryAPI(CitizenBaseAPI):
def _get_military_battlefield_choose_side(self, battle: int, side: int) -> Response:
return self.get("{}/military/battlefield-choose-side/{}/{}".format(self.url, battle, side))
def _get_military_battlefield_choose_side(self, battle_id: int, side_id: int) -> Response:
return self.get(f"{self.url}/military/battlefield-choose-side/{battle_id}/{side_id}")
def _get_military_show_weapons(self, battle: int) -> Response:
return self.get("{}/military/show-weapons".format(self.url), params={'_token': self.token, 'battleId': battle})
def _get_military_show_weapons(self, battle_id: int) -> Response:
return self.get(f"{self.url}/military/show-weapons", params={'_token': self.token, 'battleId': battle_id})
def _get_military_campaigns(self) -> Response:
return self.get("{}/military/campaigns-new/".format(self.url))
return self.get(f"{self.url}/military/campaigns-new/")
def _get_military_campaigns_json_list(self) -> Response:
return self.get("{}/military/campaignsJson/list".format(self.url))
return self.get(f"{self.url}/military/campaignsJson/list")
def _get_military_campaigns_json_citizen(self) -> Response:
return self.get("{}/military/campaignsJson/citizen".format(self.url))
return self.get(f"{self.url}/military/campaignsJson/citizen")
def _get_military_unit_data(self, unit_id: int, **kwargs) -> Response:
params = {"groupId": unit_id, "panel": "members", **kwargs}
return self.get("{}/military/military-unit-data/".format(self.url), params=params)
return self.get(f"{self.url}/military/military-unit-data/", params=params)
def _post_main_activate_battle_effect(self, battle: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle, citizenId=citizen_id, type=kind, _token=self.token)
return self.post("{}/main/fight-activateBattleEffect".format(self.url), data=data)
def _post_main_activate_battle_effect(self, battle_id: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle_id, citizenId=citizen_id, type=kind, _token=self.token)
return self.post(f"{self.url}/main/fight-activateBattleEffect", data=data)
def _post_main_battlefield_travel(self, side_id: int, battle_id: int) -> Response:
data = dict(_token=self.token, sideCountryId=side_id, battleId=battle_id)
return self.post("{}/main/battlefieldTravel".format(self.url), data=data)
return self.post(f"{self.url}/main/battlefieldTravel", data=data)
def _post_main_battlefield_change_division(self, battle_id: int, division_id: int) -> Response:
data = dict(_token=self.token, battleZoneId=division_id, battleId=battle_id)
return self.post("{}/main/battlefieldTravel".format(self.url), data=data)
return self.post(f"{self.url}/main/battlefieldTravel", data=data)
def _get_wars_show(self, war_id: int) -> Response:
return self.get("{}/wars/show/{}".format(self.url, war_id))
return self.get(f"{self.url}/wars/show/{war_id}")
def _post_military_fight_activate_booster(self, battle: int, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=self.token)
return self.post("{}/military/fight-activateBooster".format(self.url), data=data)
def _post_military_fight_activate_booster(self, battle_id: int, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, battleId=battle_id, _token=self.token)
return self.post(f"{self.url}/military/fight-activateBooster", data=data)
def _post_military_change_weapon(self, battle: int, battle_zone: int, weapon_level: int, ) -> Response:
data = dict(battleId=battle, _token=self.token, battleZoneId=battle_zone, customizationLevel=weapon_level)
return self.post("{}/military/change-weapon".format(self.url), data=data)
def _post_military_change_weapon(self, battle_id: int, battle_zone: int, weapon_level: int, ) -> Response:
data = dict(battleId=battle_id, _token=self.token, battleZoneId=battle_zone, customizationLevel=weapon_level)
return self.post(f"{self.url}/military/change-weapon", data=data)
def _post_military_battle_console(self, battle_id: int, action: str, page: int = 1, **kwargs) -> Response:
data = dict(battleId=battle_id, action=action, _token=self.token)
@ -417,19 +412,19 @@ class ErepublikMilitaryAPI(CitizenBaseAPI):
division=kwargs["division"], type=kwargs.get("type", 'damage'), )
elif action == "warList":
data.update(page=page)
return self.post("{}/military/battle-console".format(self.url), data=data)
return self.post(f"{self.url}/military/battle-console", data=data)
def _post_military_deploy_bomb(self, battle_id: int, bomb_id: int) -> Response:
data = dict(battleId=battle_id, bombId=bomb_id, _token=self.token)
return self.post("{}/military/deploy-bomb".format(self.url), data=data)
return self.post(f"{self.url}/military/deploy-bomb", data=data)
def _post_military_fight_air(self, battle_id: int, side_id: int, zone_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id)
return self.post("{}/military/fight-shoooot/{}".format(self.url, battle_id), data=data)
return self.post(f"{self.url}/military/fight-shoooot/{battle_id}", data=data)
def _post_military_fight_ground(self, battle_id: int, side_id: int, zone_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.token, battleZoneId=zone_id)
return self.post("{}/military/fight-shooot/{}".format(self.url, battle_id), data=data)
return self.post(f"{self.url}/military/fight-shooot/{battle_id}", data=data)
def _post_fight_deploy_deploy_report_data(self, deployment_id: int):
data = dict(_token=self.token, deploymentId=deployment_id)
@ -438,17 +433,27 @@ class ErepublikMilitaryAPI(CitizenBaseAPI):
class ErepublikPoliticsAPI(CitizenBaseAPI):
def _get_candidate_party(self, party_slug: str) -> Response:
return self.post("{}/candidate/{}".format(self.url, party_slug))
return self.get(f"{self.url}/candidate/{party_slug}")
def _get_main_party_members(self, party: int) -> Response:
return self.get("{}/main/party-members/{}".format(self.url, party))
def _get_main_party_members(self, party_id: int) -> Response:
return self.get(f"{self.url}/main/party-members/{party_id}")
def _get_main_rankings_parties(self, country: int) -> Response:
return self.get("{}/main/rankings-parties/1/{}".format(self.url, country))
def _get_main_rankings_parties(self, country_id: int) -> Response:
return self.get(f"{self.url}/main/rankings-parties/1/{country_id}")
def _post_candidate_for_congress(self, presentation: str = "") -> Response:
data = dict(_token=self.token, presentation=presentation)
return self.post("{}/candidate-for-congress".format(self.url), data=data)
return self.post(f"{self.url}/candidate-for-congress", data=data)
def _get_presidential_elections(self, country_id: int, timestamp: int) -> Response:
return self.get(f"{self.url}/main/presidential-elections/{country_id}/{timestamp}")
def _post_propose_president_candidate(self, party_slug: str, citizen_id: int) -> Response:
return self.post(f"{self.url}/propose-president-candidate/{party_slug}",
data=dict(_token=self.token, citizen=citizen_id))
def _get_auto_propose_president_candidate(self, party_slug: str) -> Response:
return self.get(f"{self.url}/auto-propose-president-candidate/{party_slug}")
class ErepublikPresidentAPI(CitizenBaseAPI):
@ -458,51 +463,51 @@ class ErepublikPresidentAPI(CitizenBaseAPI):
def _post_new_war(self, self_country_id: int, attack_country_id: int, debate: str = "") -> Response:
data = dict(requirments=1, _token=self.token, debate=debate,
countryNameConfirm=utils.COUNTRY_LINK[attack_country_id])
return self.post("{}/{}/new-war".format(self.url, utils.COUNTRY_LINK[self_country_id]), data=data)
countryNameConfirm=constants.COUNTRIES[attack_country_id].link)
return self.post(f"{self.url}/{constants.COUNTRIES[self_country_id].link}/new-war", data=data)
def _post_new_donation(self, country_id: int, amount: int, org_name: str, debate: str = "") -> Response:
data = dict(requirments=1, _token=self.token, debate=debate, currency=1, value=amount, commit='Propose',
type_name=org_name)
return self.post("{}/{}/new-donation".format(self.url, utils.COUNTRY_LINK[country_id]), data=data)
return self.post(f"{self.url}/{constants.COUNTRIES[country_id].link}/new-donation", data=data)
class ErepublikProfileAPI(CitizenBaseAPI):
def _get_main_citizen_hovercard(self, citizen: int) -> Response:
return self.get("{}/main/citizen-hovercard/{}".format(self.url, citizen))
def _get_main_citizen_hovercard(self, citizen_id: int) -> Response:
return self.get(f"{self.url}/main/citizen-hovercard/{citizen_id}")
def _get_main_citizen_profile_json(self, player_id: int) -> Response:
return self.get("{}/main/citizen-profile-json/{}".format(self.url, player_id))
def _get_main_citizen_profile_json(self, citizen_id: int) -> Response:
return self.get(f"{self.url}/main/citizen-profile-json/{citizen_id}")
def _get_main_citizen_notifications(self) -> Response:
return self.get("{}/main/citizenDailyAssistant".format(self.url))
return self.get(f"{self.url}/main/citizenDailyAssistant")
def _get_main_citizen_daily_assistant(self) -> Response:
return self.get("{}/main/citizenNotifications".format(self.url))
return self.get(f"{self.url}/main/citizenNotifications")
def _get_main_messages_paginated(self, page: int = 1) -> Response:
return self.get("{}/main/messages-paginated/{}".format(self.url, page))
return self.get(f"{self.url}/main/messages-paginated/{page}")
def _get_main_money_donation_accept(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/accept/{}".format(self.url, donation_id), params={"_token": self.token})
return self.get(f"{self.url}/main/money-donation/accept/{donation_id}", params={"_token": self.token})
def _get_main_money_donation_reject(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/reject/{}".format(self.url, donation_id), params={"_token": self.token})
return self.get(f"{self.url}/main/money-donation/reject/{donation_id}", params={"_token": self.token})
def _get_main_notifications_ajax_community(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/community/{}".format(self.url, page))
return self.get(f"{self.url}/main/notificationsAjax/community/{page}")
def _get_main_notifications_ajax_system(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/system/{}".format(self.url, page))
return self.get(f"{self.url}/main/notificationsAjax/system/{page}")
def _get_main_notifications_ajax_report(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/report/{}".format(self.url, page))
return self.get(f"{self.url}/main/notificationsAjax/report/{page}")
def _get_main_training_grounds_json(self) -> Response:
return self.get("{}/main/training-grounds-json".format(self.url))
return self.get(f"{self.url}/main/training-grounds-json")
def _get_main_weekly_challenge_data(self) -> Response:
return self.get("{}/main/weekly-challenge-data".format(self.url))
return self.get(f"{self.url}/main/weekly-challenge-data")
def _post_main_citizen_add_remove_friend(self, citizen: int, add: bool) -> Response:
data = dict(_token=self.token, citizenId=citizen, url="//www.erepublik.com/en/main/citizen-addRemoveFriend")
@ -510,69 +515,73 @@ class ErepublikProfileAPI(CitizenBaseAPI):
data.update({"action": "addFriend"})
else:
data.update({"action": "removeFriend"})
return self.post("{}/main/citizen-addRemoveFriend".format(self.url), data=data)
return self.post(f"{self.url}/main/citizen-addRemoveFriend", data=data)
def _post_main_daily_task_reward(self) -> Response:
return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=self.token))
return self.post(f"{self.url}/main/daily-tasks-reward", data=dict(_token=self.token))
def _post_delete_message(self, msg_id: list) -> Response:
data = {"_token": self.token, "delete_message[]": msg_id}
return self.post("{}/main/messages-delete".format(self.url), data)
return self.post(f"{self.url}/main/messages-delete", data)
def _post_eat(self, color: str) -> Response:
data = dict(_token=self.token, buttonColor=color)
return self.post("{}/main/eat".format(self.url), params=data)
return self.post(f"{self.url}/main/eat", params=data)
def _post_main_global_alerts_close(self, alert_id: int) -> Response:
data = dict(_token=self.token, alert_id=alert_id)
return self.post("{}/main/global-alerts/close".format(self.url), data=data)
return self.post(f"{self.url}/main/global-alerts/close", data=data)
def _post_forgot_password(self, email: str) -> Response:
data = dict(_token=self.token, email=email, commit="Reset password")
return self.post("{}/forgot-password".format(self.url), data=data)
return self.post(f"{self.url}/forgot-password", data=data)
def _post_login(self, email: str, password: str) -> Response:
data = dict(csrf_token=self.token, citizen_email=email, citizen_password=password, remember='on')
return self.post("{}/login".format(self.url), data=data)
return self.post(f"{self.url}/login", data=data)
def _post_main_messages_alert(self, notification_ids: List[int]) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids, "deleteAllAlerts": "1", "delete": "Delete"}
return self.post("{}/main/messages-alerts/1".format(self.url), data=data)
return self.post(f"{self.url}/main/messages-alerts/1", data=data)
def _post_main_notifications_ajax_community(self, notification_ids: List[int], page: int = 1) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids}
return self.post("{}/main/notificationsAjax/community/{}".format(self.url, page), data=data)
return self.post(f"{self.url}/main/notificationsAjax/community/{page}", data=data)
def _post_main_notifications_ajax_system(self, notification_ids: List[int], page: int = 1) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids}
return self.post("{}/main/notificationsAjax/system/{}".format(self.url, page), data=data)
return self.post(f"{self.url}/main/notificationsAjax/system/{page}", data=data)
def _post_main_notifications_ajax_report(self, notification_ids: List[int], page: int = 1) -> Response:
data = {"_token": self.token, "delete_alerts[]": notification_ids}
return self.post("{}/main/notificationsAjax/report/{}".format(self.url, page), data=data)
return self.post(f"{self.url}/main/notificationsAjax/report/{page}", data=data)
def _post_main_messages_compose(self, subject: str, body: str, citizens: List[int]) -> Response:
url_pk = 0 if len(citizens) > 1 else str(citizens[0])
data = dict(citizen_name=",".join([str(x) for x in citizens]),
citizen_subject=subject, _token=self.token, citizen_message=body)
return self.post("{}/main/messages-compose/{}".format(self.url, url_pk), data=data)
return self.post(f"{self.url}/main/messages-compose/{url_pk}", data=data)
def _post_military_group_missions(self) -> Response:
data = dict(action="check", _token=self.token)
return self.post("{}/military/group-missions".format(self.url), data=data)
return self.post(f"{self.url}/military/group-missions", data=data)
def _post_main_weekly_challenge_reward(self, reward_id: int) -> Response:
data = dict(_token=self.token, rewardId=reward_id)
return self.post("{}/main/weekly-challenge-collect-reward".format(self.url), data=data)
return self.post(f"{self.url}/main/weekly-challenge-collect-reward", data=data)
def _post_main_profile_update(self, action: str, params: str):
data = {"action": action, "params": params, "_token": self.token}
return self.post(f"{self.url}/main/profile-update", data=data)
class ErepublikTravelAPI(CitizenBaseAPI):
def _post_main_travel(self, check: str, **kwargs) -> Response:
data = dict(_token=self.token, check=check, **kwargs)
return self.post("{}/main/travel".format(self.url), data=data)
return self.post(f"{self.url}/main/travel", data=data)
def _post_main_travel_data(self, **kwargs) -> Response:
return self.post("{}/main/travelData".format(self.url), data=dict(_token=self.token, **kwargs))
return self.post(f"{self.url}/main/travelData", data=dict(_token=self.token, **kwargs))
class ErepublikWallPostAPI(CitizenBaseAPI):
@ -580,78 +589,78 @@ class ErepublikWallPostAPI(CitizenBaseAPI):
def _post_main_country_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/country-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-comment/retrieve/json", data=data)
def _post_main_country_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/country-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-comment/create/json", data=data)
def _post_main_country_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/country-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-post/create/json", data=data)
def _post_main_country_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/country-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/country-post/retrieve/json", data=data)
# ## Military Unit
def _post_main_military_unit_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/military-unit-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-comment/retrieve/json", data=data)
def _post_main_military_unit_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/military-unit-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-comment/create/json", data=data)
def _post_main_military_unit_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/military-unit-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-post/create/json", data=data)
def _post_main_military_unit_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/military-unit-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/military-unit-post/retrieve/json", data=data)
# ## Party
def _post_main_party_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/party-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-comment/retrieve/json", data=data)
def _post_main_party_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/party-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-comment/create/json", data=data)
def _post_main_party_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/party-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-post/create/json", data=data)
def _post_main_party_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/party-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/party-post/retrieve/json", data=data)
# ## Friend's Wall
def _post_main_wall_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/wall-comment/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-comment/retrieve/json", data=data)
def _post_main_wall_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/wall-comment/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-comment/create/json", data=data)
def _post_main_wall_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/wall-post/create/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-post/create/json", data=data)
def _post_main_wall_post_retrieve(self) -> Response:
data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/wall-post/retrieve/json".format(self.url), data=data)
return self.post(f"{self.url}/main/wall-post/retrieve/json", data=data)
# ## Medal posting
def _post_main_wall_post_automatic(self, message: str, achievement_id: int) -> Response:
return self.post("{}/main/wall-post/automatic".format(self.url), data=dict(_token=self.token, message=message,
achievementId=achievement_id))
return self.post(f"{self.url}/main/wall-post/automatic", data=dict(_token=self.token, message=message,
achievementId=achievement_id))
class CitizenAPI(

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,16 @@
import datetime
import hashlib
import threading
from collections import defaultdict
import weakref
from decimal import Decimal
from typing import Any, Dict, List, NamedTuple, Tuple, Union, Optional
from typing import Any, Dict, List, NamedTuple, Optional, Tuple, Union
from requests import Response, Session, post
from erepublik import utils
from erepublik.utils import json
from . import utils, constants
INDUSTRIES = {1: "Food", 2: "Weapons", 4: "House", 23: "Aircraft",
7: "FRM q1", 8: "FRM q2", 9: "FRM q3", 10: "FRM q4", 11: "FRM q5",
12: "WRM q1", 13: "WRM q2", 14: "WRM q3", 15: "WRM q4", 16: "WRM q5",
18: "HRM q1", 19: "HRM q2", 20: "HRM q3", 21: "HRM q4", 22: "HRM q5",
24: "ARM q1", 25: "ARM q2", 26: "ARM q3", 27: "ARM q4", 28: "ARM q5", }
__all__ = ['Battle', 'BattleDivision', 'BattleSide', 'Company', 'Config', 'Details', 'Energy', 'ErepublikException',
'Holding', 'MyCompanies', 'MyJSONEncoder', 'OfferItem', 'Politics', 'Reporter', 'TelegramBot']
class ErepublikException(Exception):
@ -32,8 +28,10 @@ class Holding:
id: int
region: int
companies: List["Company"]
_citizen = weakref.ReferenceType
def __init__(self, _id: int, region: int):
def __init__(self, _id: int, region: int, citizen):
self._citizen = weakref.ref(citizen)
self.id: int = _id
self.region: int = region
self.companies: List["Company"] = list()
@ -64,6 +62,24 @@ class Holding:
wrm += company.raw_usage
return dict(frm=frm, wrm=wrm)
def get_wam_companies(self, raw_factory: bool = None):
raw = []
factory = []
for company in self.wam_companies:
if not company.already_worked and not company.cannot_wam_reason == "war":
if company.is_raw:
raw.append(company)
else:
factory.append(company)
if raw_factory is not None and not raw_factory:
return factory
elif raw_factory is not None and raw_factory:
return raw
elif raw_factory is None:
return raw + factory
else:
raise ErepublikException("raw_factory should be True/False/None")
def __str__(self):
name = f"Holding (#{self.id}) with {len(self.companies)} "
if len(self.companies) % 10 == 1:
@ -76,11 +92,16 @@ class Holding:
return str(self)
@property
def __dict__(self):
def as_dict(self):
return dict(name=str(self), id=self.id, region=self.region, companies=self.companies, wam_count=self.wam_count)
@property
def citizen(self):
return self._citizen()
class Company:
_holding: weakref.ReferenceType
holding: Holding
id: int
quality: int
@ -99,7 +120,7 @@ class Company:
base_production: Decimal, wam_enabled: bool, can_wam: bool, cannot_wam_reason: str, industry: int,
already_worked: bool, preset_works: int
):
self.holding: Holding = holding
self._holding = weakref.ref(holding)
self.id: int = _id
self.industry: int = industry
self.quality: int = self._get_real_quality(quality)
@ -173,7 +194,7 @@ class Company:
return self._sort_keys != other._sort_keys
def __str__(self):
name = f"(#{self.id:>9d}) {INDUSTRIES[self.industry]}"
name = f"(#{self.id:>9d}) {constants.INDUSTRIES[self.industry]}"
if not self.is_raw:
name += f" q{self.quality}"
return name
@ -182,12 +203,25 @@ class Company:
return str(self)
@property
def __dict__(self):
def as_dict(self):
return dict(name=str(self), holding=self.holding.id, id=self.id, quality=self.quality, is_raw=self.is_raw,
raw_usage=self.raw_usage, products_made=self.products_made, wam_enabled=self.wam_enabled,
can_wam=self.can_wam, cannot_wam_reason=self.cannot_wam_reason, industry=self.industry,
already_worked=self.already_worked, preset_works=self.preset_works)
def dissolve(self) -> Response:
self.holding.citizen.write_log(f"{self} dissolved!")
# noinspection PyProtectedMember
return self.holding.citizen._post_economy_sell_company(self.id, self.holding.citizen.details.pin, sell=False)
def upgrade(self, level: int) -> Response:
# noinspection PyProtectedMember
return self.holding.citizen._post_economy_upgrade_company(self.id, level, self.holding.citizen.details.pin)
@property
def holding(self):
return self._holding()
class MyCompanies:
work_units: int = 0
@ -195,11 +229,13 @@ class MyCompanies:
ff_lockdown: int = 0
holdings: Dict[int, Holding]
companies: List[Company]
companies: weakref.WeakSet
_citizen: weakref.ReferenceType
def __init__(self):
def __init__(self, citizen):
self._citizen = weakref.ref(citizen)
self.holdings: Dict[int, Holding] = dict()
self.companies: List[Company] = list()
self.companies: weakref.WeakSet = weakref.WeakSet()
self.next_ot_time = utils.now()
def prepare_holdings(self, holdings: Dict[str, Dict[str, Any]]):
@ -208,9 +244,11 @@ class MyCompanies:
"""
for holding in holdings.values():
if holding.get('id') not in self.holdings:
self.holdings.update({int(holding.get('id')): Holding(holding['id'], holding['region_id'])})
self.holdings.update({
int(holding.get('id')): Holding(holding['id'], holding['region_id'], self.citizen)
})
if not self.holdings.get(0):
self.holdings.update({0: Holding(0, 0)}) # unassigned
self.holdings.update({0: Holding(0, 0, self.citizen)}) # unassigned
def prepare_companies(self, companies: Dict[str, Dict[str, Any]]):
"""
@ -232,7 +270,7 @@ class MyCompanies:
company_dict.get('can_work_as_manager'), company_dict.get('cannot_work_as_manager_reason'),
company_dict.get('industry_id'), company_dict.get('already_worked'), company_dict.get('preset_works')
)
self.companies.append(company)
self.companies.add(company)
holding.add_company(company)
def get_employable_factories(self) -> Dict[int, int]:
@ -241,43 +279,8 @@ class MyCompanies:
def get_total_wam_count(self) -> int:
return sum([holding.wam_count for holding in self.holdings.values()])
def get_holding_wam_count(self, holding_id: int, raw_factory=None) -> int:
"""
Returns amount of wam enabled companies in the holding
:param holding_id: holding id
:param raw_factory: True - only raw, False - only factories, None - both
:return: int
"""
return len(self.get_holding_wam_companies(holding_id, raw_factory))
def get_holding_wam_companies(self, holding_id: int, raw_factory: bool = None) -> List[Company]:
"""
Returns WAM enabled companies in the holding, True - only raw, False - only factories, None - both
:param holding_id: holding id
:param raw_factory: bool or None
:return: list
"""
raw = []
factory = []
if holding_id in self.holdings:
for company in self.holdings[holding_id].wam_companies:
if not company.already_worked and not company.cannot_wam_reason == "war":
if company.is_raw:
raw.append(company)
else:
factory.append(company)
if raw_factory is not None and not raw_factory:
return factory
elif raw_factory is not None and raw_factory:
return raw
elif raw_factory is None:
return raw + factory
else:
raise ErepublikException("raw_factory should be True/False/None")
@staticmethod
def get_needed_inventory_usage(companies: Union[Company, List[Company]]) -> Decimal:
if isinstance(companies, list):
return sum([company.products_made * 100 if company.is_raw else 1 for company in companies])
else:
@ -291,13 +294,19 @@ class MyCompanies:
def __clear_data(self):
for holding in self.holdings.values():
for company in holding.companies:
del company
holding.companies.clear()
self.companies.clear()
@property
def __dict__(self):
return dict(name=str(self), work_units=self.work_units, next_ot_time=self.next_ot_time, ff_lockdown=self.ff_lockdown, holdings=self.holdings,
company_count=len(self.companies))
def as_dict(self):
return dict(name=str(self), work_units=self.work_units, next_ot_time=self.next_ot_time,
ff_lockdown=self.ff_lockdown, holdings=self.holdings, company_count=len(self.companies))
@property
def citizen(self):
return self._citizen()
class Config:
@ -364,7 +373,7 @@ class Config:
self.telegram_token = ""
@property
def __dict__(self):
def as_dict(self):
return dict(email=self.email, work=self.work, train=self.train, wam=self.wam, ot=self.ot,
auto_sell=self.auto_sell, auto_sell_all=self.auto_sell_all, employees=self.employees,
fight=self.fight, air=self.air, ground=self.ground, all_in=self.all_in,
@ -420,6 +429,13 @@ class Energy:
def available(self):
return self.recovered + self.recoverable
@property
def as_dict(self):
return dict(limit=self.limit, interval=self.interval, recoverable=self.recoverable, recovered=self.recovered,
reference_time=self.reference_time, food_fights=self.food_fights,
is_recoverable_full=self.is_recoverable_full, is_recovered_full=self.is_recovered_full,
is_energy_full=self.is_energy_full, available=self.available)
class Details:
xp = 0
@ -429,11 +445,11 @@ class Details:
gold = 0
next_pp: List[int] = None
citizen_id = 0
citizenship = 0
citizenship: constants.Country
current_region = 0
current_country = 0
current_country: constants.Country
residence_region = 0
residence_country = 0
residence_country: constants.Country
daily_task_done = False
daily_task_reward = False
mayhem_skills = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, }
@ -467,6 +483,15 @@ class Details:
next_level_up = (1 + (self.xp // 10)) * 10
return next_level_up - self.xp
@property
def as_dict(self):
return dict(xp=self.xp, cc=self.cc, pp=self.pp, pin=self.pin, gold=self.gold, next_pp=self.next_pp,
citizen_id=self.citizen_id, citizenship=self.citizenship, current_region=self.current_region,
current_country=self.current_country, residence_region=self.residence_region,
residence_country=self.residence_country, daily_task_done=self.daily_task_done,
daily_task_reward=self.daily_task_reward, mayhem_skills=self.mayhem_skills,
xp_till_level_up=self.xp_till_level_up)
class Politics:
is_party_member: bool = False
@ -477,6 +502,12 @@ class Politics:
is_congressman: bool = False
is_country_president: bool = False
@property
def as_dict(self):
return dict(is_party_member=self.is_party_member, party_id=self.party_id, party_slug=self.party_slug,
is_party_president=self.is_party_president, is_congressman=self.is_congressman,
is_country_president=self.is_country_president)
class House:
quality = None
@ -494,42 +525,55 @@ class House:
class Reporter:
__to_update: List[Dict[Any, Any]] = None
name: str = ""
email: str = ""
citizen_id: int = 0
key: str = ""
allowed: bool = False
@property
def __dict__(self):
def name(self) -> str:
return self.citizen.name
@property
def email(self) -> str:
return self.citizen.config.email
@property
def citizen_id(self) -> int:
return self.citizen.details.citizen_id
@property
def as_dict(self):
return dict(name=self.name, email=self.email, citizen_id=self.citizen_id, key=self.key, allowed=self.allowed,
queue=self.__to_update)
def __init__(self):
def __init__(self, citizen):
self._citizen = weakref.ref(citizen)
self._req = Session()
self.url = "https://api.erep.lv"
self._req.headers.update({"user-agent": "Bot reporter v2"})
self.__to_update = []
self.__registered: bool = False
def do_init(self, name: str = "", email: str = "", citizen_id: int = 0):
self.name: str = name
self.email: str = email
self.citizen_id: int = citizen_id
def do_init(self):
self.key: str = ""
self.__update_key()
self.register_account()
self.allowed = True
@property
def citizen(self):
return self._citizen()
def __update_key(self):
self.key = hashlib.md5(bytes(f"{self.name}:{self.email}", encoding="UTF-8")).hexdigest()
def __bot_update(self, data: dict) -> Response:
if self.__to_update:
for unreported_data in self.__to_update:
unreported_data.update(player_id=self.citizen_id, key=self.key)
unreported_data.update(player_id=self.citizen.id, key=self.key)
unreported_data = utils.json.load(utils.json.dumps(unreported_data, cls=MyJSONEncoder))
self._req.post("{}/bot/update".format(self.url), json=unreported_data)
self.__to_update.clear()
data = utils.json.loads(utils.json.dumps(data, cls=MyJSONEncoder))
r = self._req.post("{}/bot/update".format(self.url), json=data)
return r
@ -574,10 +618,11 @@ class Reporter:
def report_promo(self, kind: str, time_until: datetime.datetime):
self._req.post(f"{self.url}/promos/add/", data=dict(kind=kind, time_untill=time_until))
def fetch_battle_priorities(self, country_id: int) -> List[int]:
def fetch_battle_priorities(self, country: constants.Country) -> List["Battle"]:
try:
battle_response = self._req.get(f'{self.url}/api/v1/battles/{country_id}')
return battle_response.json().get('battle_ids', [])
battle_response = self._req.get(f'{self.url}/api/v1/battles/{country.id}')
return [self.citizen.all_battles[bid] for bid in battle_response.json().get('battle_ids', []) if
bid in self.citizen.all_battles]
except: # noqa
return []
@ -590,7 +635,7 @@ class Reporter:
return
class MyJSONEncoder(json.JSONEncoder):
class MyJSONEncoder(utils.json.JSONEncoder):
def default(self, o):
from erepublik.citizen import Citizen
if isinstance(o, Decimal):
@ -605,8 +650,8 @@ class MyJSONEncoder(json.JSONEncoder):
microseconds=o.microseconds, total_seconds=o.total_seconds())
elif isinstance(o, Response):
return dict(headers=o.headers.__dict__, url=o.url, text=o.text)
elif hasattr(o, '__dict__'):
return o.__dict__
elif hasattr(o, 'as_dict'):
return o.as_dict
elif isinstance(o, set):
return list(o)
elif isinstance(o, Citizen):
@ -618,50 +663,112 @@ class MyJSONEncoder(json.JSONEncoder):
class BattleSide:
id: int
points: int
deployed: List[int] = None
allies: List[int] = None
deployed: List[constants.Country]
allies: List[constants.Country]
battle: "Battle"
_battle: weakref.ReferenceType
country: constants.Country
defender: bool
def __init__(self, country_id: int, points: int, allies: List[int], deployed: List[int]):
self.id = country_id
def __init__(self, battle: "Battle", country: constants.Country, points: int, allies: List[constants.Country],
deployed: List[constants.Country], defender: bool):
self._battle = weakref.ref(battle)
self.country = country
self.points = points
self.allies = [int(ally) for ally in allies]
self.deployed = [int(ally) for ally in deployed]
self.allies = allies
self.deployed = deployed
self.defender = defender
@property
def id(self) -> int:
return self.country.id
def __repr__(self):
side_text = "Defender" if self.defender else "Invader "
return f"<BattleSide: {side_text} {self.country.name}|{self.points:02d}p>"
def __str__(self):
side_text = "Defender" if self.defender else "Invader "
return f"{side_text} {self.country.name} - {self.points:02d} points"
def __format__(self, format_spec):
return self.country.iso
@property
def as_dict(self):
return dict(points=self.points, country=self.country, defender=self.defender, allies=self.allies,
deployed=self.deployed, battle=repr(self.battle))
@property
def battle(self):
return self._battle()
class BattleDivision:
id: int
end: datetime.datetime
epic: bool
dom_pts: Dict[str, int]
wall: Dict[str, Union[int, float]]
battle_zone_id: int
def_medal: Dict[str, int]
inv_medal: Dict[str, int]
terrain: int
div: int
battle: "Battle"
_battle: weakref.ReferenceType
@property
def as_dict(self):
return dict(id=self.id, division=self.div, terrain=(self.terrain, self.terrain_display), wall=self.wall,
epic=self.epic, battle=str(self.battle), end=self.div_end)
@property
def is_air(self):
return self.div == 11
@property
def div_end(self) -> bool:
return utils.now() >= self.end
def __init__(self, **kwargs):
def __init__(self, battle: "Battle", div_id: int, end: datetime.datetime, epic: bool, div: int, wall_for: int,
wall_dom: float, terrain_id: int = 0):
"""Battle division helper class
:param kwargs: must contain keys:
div_id: int, end: datetime.datetime, epic: bool, inv_pts: int, def_pts: int,
wall_for: int, wall_dom: float, def_medal: Tuple[int, int], inv_medal: Tuple[int, int]
:type div_id: int
:type end: datetime.datetime
:type epic: bool
:type div: int
:type terrain_id: int
:type wall_for: int
:type wall_dom: float
"""
self.battle_zone_id = kwargs.get("div_id", 0)
self.end = kwargs.get("end", 0)
self.epic = kwargs.get("epic", 0)
self.dom_pts = dict({"inv": kwargs.get("inv_pts", 0), "def": kwargs.get("def_pts", 0)})
self.wall = dict({"for": kwargs.get("wall_for", 0), "dom": kwargs.get("wall_dom", 0)})
self.def_medal = {"id": kwargs.get("def_medal", 0)[0], "dmg": kwargs.get("def_medal", 0)[1]}
self.inv_medal = {"id": kwargs.get("inv_medal", 0)[0], "dmg": kwargs.get("inv_medal", 0)[1]}
self._battle = weakref.ref(battle)
self.id = div_id
self.end = end
self.epic = epic
self.wall = dict({"for": wall_for, "dom": wall_dom})
self.terrain = terrain_id
self.div = div
@property
def id(self):
return self.battle_zone_id
def terrain_display(self):
return constants.TERRAINS[self.terrain]
def __str__(self):
base_name = f"Div #{self.id} d{self.div}"
if self.terrain:
base_name += f" ({self.terrain_display})"
if self.div_end:
base_name += " Ended"
return base_name
def __repr__(self):
return f"<BattleDivision #{self.id} (battle #{self.battle.id})>"
@property
def battle(self):
return self._battle()
class Battle:
@ -674,11 +781,33 @@ class Battle:
invader: BattleSide
defender: BattleSide
div: Dict[int, BattleDivision]
region_id: int
region_name: str
@property
def is_air(self) -> bool:
def as_dict(self):
return dict(id=self.id, war_id=self.war_id, divisions=self.div, zone=self.zone_id, rw=self.is_rw,
dict_lib=self.is_dict_lib, start=self.start, sides={'inv': self.invader, 'def': self.defender},
region=[self.region_id, self.region_name])
@property
def has_air(self) -> bool:
for div in self.div.values():
if div.div == 11:
return True
return not bool(self.zone_id % 4)
@property
def has_ground(self) -> bool:
for div in self.div.values():
if div.div != 11:
return True
return bool(self.zone_id % 4)
@property
def link(self):
return f"https://www.erepublik.com/en/military/battlefield/{self.id}"
def __init__(self, battle: Dict[str, Any]):
"""Object representing eRepublik battle.
@ -691,55 +820,50 @@ class Battle:
self.is_rw = bool(battle.get('is_rw'))
self.is_as = bool(battle.get('is_as'))
self.is_dict_lib = bool(battle.get('is_dict')) or bool(battle.get('is_lib'))
self.start = datetime.datetime.fromtimestamp(int(battle.get('start', 0)), tz=utils.erep_tz)
self.region_id = battle.get('region', {}).get('id')
self.region_name = battle.get('region', {}).get('name')
self.start = datetime.datetime.fromtimestamp(int(battle.get('start', 0)), tz=constants.erep_tz)
self.invader = BattleSide(
battle.get('inv', {}).get('id'), battle.get('inv', {}).get('points'),
[row.get('id') for row in battle.get('inv', {}).get('ally_list')],
[row.get('id') for row in battle.get('inv', {}).get('ally_list') if row['deployed']]
self, constants.COUNTRIES[battle.get('inv', {}).get('id')], battle.get('inv', {}).get('points'),
[constants.COUNTRIES[row.get('id')] for row in battle.get('inv', {}).get('ally_list')],
[constants.COUNTRIES[row.get('id')] for row in battle.get('inv', {}).get('ally_list') if row['deployed']], False
)
self.defender = BattleSide(
battle.get('def', {}).get('id'), battle.get('def', {}).get('points'),
[row.get('id') for row in battle.get('def', {}).get('ally_list')],
[row.get('id') for row in battle.get('def', {}).get('ally_list') if row['deployed']]
self, constants.COUNTRIES[battle.get('def', {}).get('id')], battle.get('def', {}).get('points'),
[constants.COUNTRIES[row.get('id')] for row in battle.get('def', {}).get('ally_list')],
[constants.COUNTRIES[row.get('id')] for row in battle.get('def', {}).get('ally_list') if row['deployed']], True
)
self.div = defaultdict(BattleDivision)
self.div = {}
for div, data in battle.get('div', {}).items():
div = int(data.get('div'))
div = int(div)
if data.get('end'):
end = datetime.datetime.fromtimestamp(data.get('end'), tz=utils.erep_tz)
end = datetime.datetime.fromtimestamp(data.get('end'), tz=constants.erep_tz)
else:
end = utils.localize_dt(datetime.datetime.max - datetime.timedelta(days=1))
if not data['stats']['def']:
def_medal = (0, 0)
else:
def_medal = (data['stats']['def']['citizenId'], data['stats']['def']['damage'])
if not data['stats']['inv']:
inv_medal = (0, 0)
else:
inv_medal = (data['stats']['inv']['citizenId'], data['stats']['inv']['damage'])
battle_div = BattleDivision(end=end, epic=data.get('epic_type') in [1, 5], div_id=data.get('id'),
inv_pts=data.get('dom_pts').get("inv"), def_pts=data.get('dom_pts').get("def"),
wall_for=data.get('wall').get("for"), wall_dom=data.get('wall').get("dom"),
def_medal=def_medal, inv_medal=inv_medal)
battle_div = BattleDivision(self, div_id=data.get('id'), div=data.get('div'), end=end,
epic=data.get('epic_type') in [1, 5],
wall_for=data.get('wall').get("for"),
wall_dom=data.get('wall').get("dom"),
terrain_id=data.get('terrain', 0))
self.div.update({div: battle_div})
def __repr__(self):
now = utils.now()
def __str__(self):
time_now = utils.now()
is_started = self.start < utils.now()
if is_started:
time_part = " {}".format(now - self.start)
time_part = " {}".format(time_now - self.start)
else:
time_part = "-{}".format(self.start - now)
time_part = "-{}".format(self.start - time_now)
return f"Battle {self.id} | " \
f"{utils.ISO_CC[self.invader.id]} : {utils.ISO_CC[self.defender.id]} | " \
f"Round {self.zone_id:2} | " \
f"Round time {time_part}"
return f"Battle {self.id} for {self.region_name[:16]} | {self.invader} : {self.defender} | Round time {time_part}"
def __repr__(self):
return f"<Battle #{self.id} {self.invader}:{self.defender} R{self.zone_id}>"
class EnergyToFight:
@ -793,7 +917,7 @@ class TelegramBot:
self._next_time = utils.now()
@property
def __dict__(self):
def as_dict(self):
return {'chat_id': self.chat_id, 'api_url': self.api_url, 'player': self.player_name,
'last_time': self._last_time, 'next_time': self._next_time, 'queue': self.__queue,
'initialized': self.__initialized, 'has_threads': bool(len(self._threads))}
@ -824,22 +948,6 @@ class TelegramBot:
return True
def report_free_bhs(self, battles: List[Tuple[int, int, int, int, datetime.timedelta]]):
battle_links = []
for battle_id, side_id, against_id, damage, time_left in battles:
total_seconds = int(time_left.total_seconds())
time_start = ""
hours, remainder = divmod(total_seconds, 3600)
if hours:
time_start = f"{hours}h "
minutes, seconds = divmod(remainder, 60)
time_start += f"{minutes:02}m {seconds:02}s"
damage = "{:,}".format(damage).replace(',', ' ')
battle_links.append(f"*{damage}*dmg bh for [{utils.COUNTRIES[side_id]} vs {utils.COUNTRIES[against_id]}]"
f"(https://www.erepublik.com/en/military/battlefield/{battle_id}) "
f"_time since start {time_start}_")
self.send_message("Free BHs:\n" + "\n".join(battle_links))
def report_full_energy(self, available: int, limit: int, interval: int):
if (utils.now() - self._last_full_energy_report).total_seconds() >= 30 * 60:
self._last_full_energy_report = utils.now()
@ -869,7 +977,7 @@ class TelegramBot:
class OfferItem(NamedTuple):
price: float = 99_999.
country: int = 0
country: constants.Country = constants.Country(0, "", "", "")
amount: int = 0
offer_id: int = 0
citizen_id: int = 0

187
erepublik/constants.py Normal file
View File

@ -0,0 +1,187 @@
from typing import Dict, Optional, Union
import pytz
__all__ = ["erep_tz", "Country", "AIR_RANKS", "COUNTRIES", "FOOD_ENERGY", "GROUND_RANKS", "GROUND_RANK_POINTS", "INDUSTRIES", "TERRAINS"]
erep_tz = pytz.timezone('US/Pacific')
class Country:
id: int
name: str
link: str
iso: str
def __init__(self, country_id: int, name: str, link: str, iso: str):
self.id = country_id
self.name = name
self.link = link
self.iso = iso
def __hash__(self):
return hash((self.id, self.name))
def __repr__(self):
return f"Country({self.id}, '{self.name}', '{self.link}', '{self.iso}')"
def __str__(self):
return f"#{self.id} {self.name}"
def __format__(self, format_spec):
return self.iso
def __int__(self):
return self.id
def __eq__(self, other):
if isinstance(other, (int, float)):
return self.id == int(other)
else:
try:
return self.id == int(other)
except ValueError:
return self == other
@property
def as_dict(self):
return dict(id=self.id, name=self.name, iso=self.iso)
class Industries:
__by_name = {'food': 1, 'weapon': 2, 'house': 4, 'aircraft': 23,
'foodraw': 7, 'weaponraw': 12, 'houseraw': 18, 'aircraftraw': 24,
'frm': 7, 'wrm': 12, 'hrm': 18, 'arm': 24,
'frm q1': 7, 'frm q2': 8, 'frm q3': 9, 'frm q4': 10, 'frm q5': 11,
'wrm q1': 12, 'wrm q2': 13, 'wrm q3': 14, 'wrm q4': 15, 'wrm q5': 16,
'hrm q1': 18, 'hrm q2': 19, 'hrm q3': 20, 'hrm q4': 21, 'hrm q5': 22,
'arm q1': 24, 'arm q2': 25, 'arm q3': 26, 'arm q4': 27, 'arm q5': 28}
__by_id = {1: "Food", 2: "Weapon", 4: "House", 23: "Aircraft",
7: "foodRaw", 8: "FRM q2", 9: "FRM q3", 10: "FRM q4", 11: "FRM q5",
12: "weaponRaw", 13: "WRM q2", 14: "WRM q3", 15: "WRM q4", 16: "WRM q5",
18: "houseRaw", 19: "HRM q2", 20: "HRM q3", 21: "HRM q4", 22: "HRM q5",
24: "aircraftRaw", 25: "ARM q2", 26: "ARM q3", 27: "ARM q4", 28: "ARM q5"}
def __getitem__(self, item) -> Optional[Union[int, str]]:
if isinstance(item, int):
return self.__by_id.get(item, None)
elif isinstance(item, str):
return self.__by_name.get(item.lower(), None)
return
def __getattr__(self, item) -> Optional[Union[int, str]]:
return self[item]
@property
def as_dict(self):
return dict(by_id=self.__by_id, by_name=self.__by_name)
AIR_RANKS: Dict[int, str] = {
1: "Airman", 2: "Airman 1st Class", 3: "Airman 1st Class*", 4: "Airman 1st Class**", 5: "Airman 1st Class***",
6: "Airman 1st Class****", 7: "Airman 1st Class*****", 8: "Senior Airman", 9: "Senior Airman*",
10: "Senior Airman**", 11: "Senior Airman***", 12: "Senior Airman****", 13: "Senior Airman*****",
14: "Staff Sergeant", 15: "Staff Sergeant*", 16: "Staff Sergeant**", 17: "Staff Sergeant***",
18: "Staff Sergeant****", 19: "Staff Sergeant*****", 20: "Aviator", 21: "Aviator*", 22: "Aviator**",
23: "Aviator***", 24: "Aviator****", 25: "Aviator*****", 26: "Flight Lieutenant", 27: "Flight Lieutenant*",
28: "Flight Lieutenant**", 29: "Flight Lieutenant***", 30: "Flight Lieutenant****", 31: "Flight Lieutenant*****",
32: "Squadron Leader", 33: "Squadron Leader*", 34: "Squadron Leader**", 35: "Squadron Leader***",
36: "Squadron Leader****", 37: "Squadron Leader*****", 38: "Chief Master Sergeant", 39: "Chief Master Sergeant*",
40: "Chief Master Sergeant**", 41: "Chief Master Sergeant***", 42: "Chief Master Sergeant****",
43: "Chief Master Sergeant*****", 44: "Wing Commander", 45: "Wing Commander*", 46: "Wing Commander**",
47: "Wing Commander***", 48: "Wing Commander****", 49: "Wing Commander*****", 50: "Group Captain",
51: "Group Captain*", 52: "Group Captain**", 53: "Group Captain***", 54: "Group Captain****",
55: "Group Captain*****", 56: "Air Commodore", 57: "Air Commodore*", 58: "Air Commodore**", 59: "Air Commodore***",
60: "Air Commodore****", 61: "Air Commodore*****",
}
COUNTRIES: Dict[int, Country] = {
1: Country(1, 'Romania', 'Romania', 'ROU'), 9: Country(9, 'Brazil', 'Brazil', 'BRA'),
10: Country(10, 'Italy', 'Italy', 'ITA'), 11: Country(11, 'France', 'France', 'FRA'),
12: Country(12, 'Germany', 'Germany', 'DEU'), 13: Country(13, 'Hungary', 'Hungary', 'HUN'),
14: Country(14, 'China', 'China', 'CHN'), 15: Country(15, 'Spain', 'Spain', 'ESP'),
23: Country(23, 'Canada', 'Canada', 'CAN'), 24: Country(24, 'USA', 'USA', 'USA'),
26: Country(26, 'Mexico', 'Mexico', 'MEX'), 27: Country(27, 'Argentina', 'Argentina', 'ARG'),
28: Country(28, 'Venezuela', 'Venezuela', 'VEN'), 29: Country(29, 'United Kingdom', 'United-Kingdom', 'GBR'),
30: Country(30, 'Switzerland', 'Switzerland', 'CHE'), 31: Country(31, 'Netherlands', 'Netherlands', 'NLD'),
32: Country(32, 'Belgium', 'Belgium', 'BEL'), 33: Country(33, 'Austria', 'Austria', 'AUT'),
34: Country(34, 'Czech Republic', 'Czech-Republic', 'CZE'), 35: Country(35, 'Poland', 'Poland', 'POL'),
36: Country(36, 'Slovakia', 'Slovakia', 'SVK'), 37: Country(37, 'Norway', 'Norway', 'NOR'),
38: Country(38, 'Sweden', 'Sweden', 'SWE'), 39: Country(39, 'Finland', 'Finland', 'FIN'),
40: Country(40, 'Ukraine', 'Ukraine', 'UKR'), 41: Country(41, 'Russia', 'Russia', 'RUS'),
42: Country(42, 'Bulgaria', 'Bulgaria', 'BGR'), 43: Country(43, 'Turkey', 'Turkey', 'TUR'),
44: Country(44, 'Greece', 'Greece', 'GRC'), 45: Country(45, 'Japan', 'Japan', 'JPN'),
47: Country(47, 'South Korea', 'South-Korea', 'KOR'), 48: Country(48, 'India', 'India', 'IND'),
49: Country(49, 'Indonesia', 'Indonesia', 'IDN'), 50: Country(50, 'Australia', 'Australia', 'AUS'),
51: Country(51, 'South Africa', 'South-Africa', 'ZAF'),
52: Country(52, 'Republic of Moldova', 'Republic-of-Moldova', 'MDA'),
53: Country(53, 'Portugal', 'Portugal', 'PRT'), 54: Country(54, 'Ireland', 'Ireland', 'IRL'),
55: Country(55, 'Denmark', 'Denmark', 'DNK'), 56: Country(56, 'Iran', 'Iran', 'IRN'),
57: Country(57, 'Pakistan', 'Pakistan', 'PAK'), 58: Country(58, 'Israel', 'Israel', 'ISR'),
59: Country(59, 'Thailand', 'Thailand', 'THA'), 61: Country(61, 'Slovenia', 'Slovenia', 'SVN'),
63: Country(63, 'Croatia', 'Croatia', 'HRV'), 64: Country(64, 'Chile', 'Chile', 'CHL'),
65: Country(65, 'Serbia', 'Serbia', 'SRB'), 66: Country(66, 'Malaysia', 'Malaysia', 'MYS'),
67: Country(67, 'Philippines', 'Philippines', 'PHL'), 68: Country(68, 'Singapore', 'Singapore', 'SGP'),
69: Country(69, 'Bosnia and Herzegovina', 'Bosnia-Herzegovina', 'BiH'),
70: Country(70, 'Estonia', 'Estonia', 'EST'), 80: Country(80, 'Montenegro', 'Montenegro', 'MNE'),
71: Country(71, 'Latvia', 'Latvia', 'LVA'), 72: Country(72, 'Lithuania', 'Lithuania', 'LTU'),
73: Country(73, 'North Korea', 'North-Korea', 'PRK'), 74: Country(74, 'Uruguay', 'Uruguay', 'URY'),
75: Country(75, 'Paraguay', 'Paraguay', 'PRY'), 76: Country(76, 'Bolivia', 'Bolivia', 'BOL'),
77: Country(77, 'Peru', 'Peru', 'PER'), 78: Country(78, 'Colombia', 'Colombia', 'COL'),
79: Country(79, 'Republic of Macedonia (FYROM)', 'Republic-of-Macedonia-FYROM', 'MKD'),
81: Country(81, 'Republic of China (Taiwan)', 'Republic-of-China-Taiwan', 'TWN'),
82: Country(82, 'Cyprus', 'Cyprus', 'CYP'), 167: Country(167, 'Albania', 'Albania', 'ALB'),
83: Country(83, 'Belarus', 'Belarus', 'BLR'), 84: Country(84, 'New Zealand', 'New-Zealand', 'NZL'),
164: Country(164, 'Saudi Arabia', 'Saudi-Arabia', 'SAU'), 165: Country(165, 'Egypt', 'Egypt', 'EGY'),
166: Country(166, 'United Arab Emirates', 'United-Arab-Emirates', 'UAE'),
168: Country(168, 'Georgia', 'Georgia', 'GEO'), 169: Country(169, 'Armenia', 'Armenia', 'ARM'),
170: Country(170, 'Nigeria', 'Nigeria', 'NGA'), 171: Country(171, 'Cuba', 'Cuba', 'CUB')
}
FOOD_ENERGY: Dict[str, int] = dict(q1=2, q2=4, q3=6, q4=8, q5=10, q6=12, q7=20)
GROUND_RANKS: Dict[int, str] = {
1: "Recruit", 2: "Private", 3: "Private*", 4: "Private**", 5: "Private***",
6: "Corporal", 7: "Corporal*", 8: "Corporal**", 9: "Corporal***",
10: "Sergeant", 11: "Sergeant*", 12: "Sergeant**", 13: "Sergeant***",
14: "Lieutenant", 15: "Lieutenant*", 16: "Lieutenant**", 17: "Lieutenant***",
18: "Captain", 19: "Captain*", 20: "Captain**", 21: "Captain***",
22: "Major", 23: "Major*", 24: "Major**", 25: "Major***",
26: "Commander", 27: "Commander*", 28: "Commander**", 29: "Commander***",
30: "Lt Colonel", 31: "Lt Colonel*", 32: "Lt Colonel**", 33: "Lt Colonel***",
34: "Colonel", 35: "Colonel*", 36: "Colonel**", 37: "Colonel***",
38: "General", 39: "General*", 40: "General**", 41: "General***",
42: "Field Marshal", 43: "Field Marshal*", 44: "Field Marshal**", 45: "Field Marshal***",
46: "Supreme Marshal", 47: "Supreme Marshal*", 48: "Supreme Marshal**", 49: "Supreme Marshal***",
50: "National Force", 51: "National Force*", 52: "National Force**", 53: "National Force***",
54: "World Class Force", 55: "World Class Force*", 56: "World Class Force**", 57: "World Class Force***",
58: "Legendary Force", 59: "Legendary Force*", 60: "Legendary Force**", 61: "Legendary Force***",
62: "God of War", 63: "God of War*", 64: "God of War**", 65: "God of War***",
66: "Titan", 67: "Titan*", 68: "Titan**", 69: "Titan***",
70: "Legends I", 71: "Legends II", 72: "Legends III", 73: "Legends IV", 74: "Legends V", 75: "Legends VI",
76: "Legends VII", 77: "Legends VIII", 78: "Legends IX", 79: "Legends X", 80: "Legends XI", 81: "Legends XII",
82: "Legends XIII", 83: "Legends XIV", 84: "Legends XV", 85: "Legends XVI", 86: "Legends XVII", 87: "Legends XVIII",
88: "Legends XIX", 89: "Legends XX",
}
GROUND_RANK_POINTS: Dict[int, int] = {
1: 0, 2: 15, 3: 45, 4: 80, 5: 120, 6: 170, 7: 250, 8: 350, 9: 450, 10: 600, 11: 800, 12: 1000,
13: 1400, 14: 1850, 15: 2350, 16: 3000, 17: 3750, 18: 5000, 19: 6500, 20: 9000, 21: 12000,
22: 15500, 23: 20000, 24: 25000, 25: 31000, 26: 40000, 27: 52000, 28: 67000, 29: 85000,
30: 110000, 31: 140000, 32: 180000, 33: 225000, 34: 285000, 35: 355000, 36: 435000, 37: 540000,
38: 660000, 39: 800000, 40: 950000, 41: 1140000, 42: 1350000, 43: 1600000, 44: 1875000,
45: 2185000, 46: 2550000, 47: 3000000, 48: 3500000, 49: 4150000, 50: 4900000, 51: 5800000,
52: 7000000, 53: 9000000, 54: 11500000, 55: 14500000, 56: 18000000, 57: 22000000, 58: 26500000,
59: 31500000, 60: 37000000, 61: 43000000, 62: 50000000, 63: 100000000, 64: 200000000,
65: 500000000, 66: 1000000000, 67: 2000000000, 68: 4000000000, 69: 10000000000, 70: 20000000000,
71: 30000000000, 72: 40000000000, 73: 50000000000, 74: 60000000000, 75: 70000000000,
76: 80000000000, 77: 90000000000, 78: 100000000000, 79: 110000000000, 80: 120000000000,
81: 130000000000, 82: 140000000000, 83: 150000000000, 84: 160000000000, 85: 170000000000,
86: 180000000000, 87: 190000000000, 88: 200000000000, 89: 210000000000
}
INDUSTRIES = Industries()
TERRAINS: Dict[int, str] = {0: "Standard", 1: 'Industrial', 2: 'Urban', 3: 'Suburbs', 4: 'Airport', 5: 'Plains',
6: 'Wasteland', 7: 'Mountains', 8: 'Beach', 9: 'Swamp', 10: 'Mud', 11: 'Hills',
12: 'Jungle', 13: 'Forest', 14: 'Desert'}

View File

@ -1,3 +1,4 @@
import copy
import datetime
import inspect
import os
@ -11,146 +12,44 @@ from decimal import Decimal
from pathlib import Path
from typing import Any, List, Mapping, Optional, Union, Dict
import pytz
import requests
from . import __commit_id__, __version__
from . import __version__, constants
try:
import simplejson as json
except ImportError:
import json
__all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz", 'COUNTRY_LINK',
"now", "localize_dt", "localize_timestamp", "good_timedelta", "eday_from_date", "date_from_eday",
"get_sleep_seconds", "interactive_sleep", "silent_sleep",
"write_silent_log", "write_interactive_log", "get_file", "write_file",
"send_email", "normalize_html_json", "process_error", "process_warning",
'calculate_hit', 'get_ground_hit_dmg_value', 'get_air_hit_dmg_value']
__all__ = ['VERSION', 'calculate_hit', 'caught_error', 'date_from_eday', 'eday_from_date',
'get_air_hit_dmg_value', 'get_file', 'get_ground_hit_dmg_value', 'get_sleep_seconds', 'good_timedelta',
'interactive_sleep', 'json', 'localize_dt', 'localize_timestamp', 'normalize_html_json', 'now',
'process_error', 'process_warning', 'send_email', 'silent_sleep', 'slugify', 'write_file',
'write_interactive_log', 'write_silent_log']
if not sys.version_info >= (3, 7):
raise AssertionError('This script requires Python version 3.7 and higher\n'
'But Your version is v{}.{}.{}'.format(*sys.version_info))
FOOD_ENERGY: Dict[str, int] = dict(q1=2, q2=4, q3=6, q4=8, q5=10, q6=12, q7=20)
COMMIT_ID: str = __commit_id__
VERSION: str = __version__
erep_tz = pytz.timezone('US/Pacific')
AIR_RANKS: Dict[int, str] = {
1: "Airman", 2: "Airman 1st Class", 3: "Airman 1st Class*", 4: "Airman 1st Class**", 5: "Airman 1st Class***",
6: "Airman 1st Class****", 7: "Airman 1st Class*****", 8: "Senior Airman", 9: "Senior Airman*",
10: "Senior Airman**", 11: "Senior Airman***", 12: "Senior Airman****", 13: "Senior Airman*****",
14: "Staff Sergeant", 15: "Staff Sergeant*", 16: "Staff Sergeant**", 17: "Staff Sergeant***",
18: "Staff Sergeant****", 19: "Staff Sergeant*****", 20: "Aviator", 21: "Aviator*", 22: "Aviator**",
23: "Aviator***", 24: "Aviator****", 25: "Aviator*****", 26: "Flight Lieutenant", 27: "Flight Lieutenant*",
28: "Flight Lieutenant**", 29: "Flight Lieutenant***", 30: "Flight Lieutenant****", 31: "Flight Lieutenant*****",
32: "Squadron Leader", 33: "Squadron Leader*", 34: "Squadron Leader**", 35: "Squadron Leader***",
36: "Squadron Leader****", 37: "Squadron Leader*****", 38: "Chief Master Sergeant", 39: "Chief Master Sergeant*",
40: "Chief Master Sergeant**", 41: "Chief Master Sergeant***", 42: "Chief Master Sergeant****",
43: "Chief Master Sergeant*****", 44: "Wing Commander", 45: "Wing Commander*", 46: "Wing Commander**",
47: "Wing Commander***", 48: "Wing Commander****", 49: "Wing Commander*****", 50: "Group Captain",
51: "Group Captain*", 52: "Group Captain**", 53: "Group Captain***", 54: "Group Captain****",
55: "Group Captain*****", 56: "Air Commodore", 57: "Air Commodore*", 58: "Air Commodore**", 59: "Air Commodore***",
60: "Air Commodore****", 61: "Air Commodore*****",
}
GROUND_RANKS: Dict[int, str] = {
1: "Recruit", 2: "Private", 3: "Private*", 4: "Private**", 5: "Private***",
6: "Corporal", 7: "Corporal*", 8: "Corporal**", 9: "Corporal***",
10: "Sergeant", 11: "Sergeant*", 12: "Sergeant**", 13: "Sergeant***",
14: "Lieutenant", 15: "Lieutenant*", 16: "Lieutenant**", 17: "Lieutenant***",
18: "Captain", 19: "Captain*", 20: "Captain**", 21: "Captain***",
22: "Major", 23: "Major*", 24: "Major**", 25: "Major***",
26: "Commander", 27: "Commander*", 28: "Commander**", 29: "Commander***",
30: "Lt Colonel", 31: "Lt Colonel*", 32: "Lt Colonel**", 33: "Lt Colonel***",
34: "Colonel", 35: "Colonel*", 36: "Colonel**", 37: "Colonel***",
38: "General", 39: "General*", 40: "General**", 41: "General***",
42: "Field Marshal", 43: "Field Marshal*", 44: "Field Marshal**", 45: "Field Marshal***",
46: "Supreme Marshal", 47: "Supreme Marshal*", 48: "Supreme Marshal**", 49: "Supreme Marshal***",
50: "National Force", 51: "National Force*", 52: "National Force**", 53: "National Force***",
54: "World Class Force", 55: "World Class Force*", 56: "World Class Force**", 57: "World Class Force***",
58: "Legendary Force", 59: "Legendary Force*", 60: "Legendary Force**", 61: "Legendary Force***",
62: "God of War", 63: "God of War*", 64: "God of War**", 65: "God of War***",
66: "Titan", 67: "Titan*", 68: "Titan**", 69: "Titan***",
70: "Legends I", 71: "Legends II", 72: "Legends III", 73: "Legends IV", 74: "Legends V", 75: "Legends VI",
76: "Legends VII", 77: "Legends VIII", 78: "Legends IX", 79: "Legends X", 80: "Legends XI", 81: "Legends XII",
82: "Legends XIII", 83: "Legends XIV", 84: "Legends XV", 85: "Legends XVI", 86: "Legends XVII", 87: "Legends XVIII",
88: "Legends XIX", 89: "Legends XX",
}
GROUND_RANK_POINTS: Dict[int, int] = {
1: 0, 2: 15, 3: 45, 4: 80, 5: 120, 6: 170, 7: 250, 8: 350, 9: 450, 10: 600, 11: 800, 12: 1000,
13: 1400, 14: 1850, 15: 2350, 16: 3000, 17: 3750, 18: 5000, 19: 6500, 20: 9000, 21: 12000,
22: 15500, 23: 20000, 24: 25000, 25: 31000, 26: 40000, 27: 52000, 28: 67000, 29: 85000,
30: 110000, 31: 140000, 32: 180000, 33: 225000, 34: 285000, 35: 355000, 36: 435000, 37: 540000,
38: 660000, 39: 800000, 40: 950000, 41: 1140000, 42: 1350000, 43: 1600000, 44: 1875000,
45: 2185000, 46: 2550000, 47: 3000000, 48: 3500000, 49: 4150000, 50: 4900000, 51: 5800000,
52: 7000000, 53: 9000000, 54: 11500000, 55: 14500000, 56: 18000000, 57: 22000000, 58: 26500000,
59: 31500000, 60: 37000000, 61: 43000000, 62: 50000000, 63: 100000000, 64: 200000000,
65: 500000000, 66: 1000000000, 67: 2000000000, 68: 4000000000, 69: 10000000000, 70: 20000000000,
71: 30000000000, 72: 40000000000, 73: 50000000000, 74: 60000000000, 75: 70000000000,
76: 80000000000, 77: 90000000000, 78: 100000000000, 79: 110000000000, 80: 120000000000,
81: 130000000000, 82: 140000000000, 83: 150000000000, 84: 160000000000, 85: 170000000000,
86: 180000000000, 87: 190000000000, 88: 200000000000, 89: 210000000000
}
COUNTRIES: Dict[int, str] = {
1: 'Romania', 9: 'Brazil', 10: 'Italy', 11: 'France', 12: 'Germany', 13: 'Hungary', 14: 'China', 15: 'Spain',
23: 'Canada', 24: 'USA', 26: 'Mexico', 27: 'Argentina', 28: 'Venezuela', 29: 'United Kingdom', 30: 'Switzerland',
31: 'Netherlands', 32: 'Belgium', 33: 'Austria', 34: 'Czech Republic', 35: 'Poland', 36: 'Slovakia', 37: 'Norway',
38: 'Sweden', 39: 'Finland', 40: 'Ukraine', 41: 'Russia', 42: 'Bulgaria', 43: 'Turkey', 44: 'Greece', 45: 'Japan',
47: 'South Korea', 48: 'India', 49: 'Indonesia', 50: 'Australia', 51: 'South Africa', 52: 'Republic of Moldova',
53: 'Portugal', 54: 'Ireland', 55: 'Denmark', 56: 'Iran', 57: 'Pakistan', 58: 'Israel', 59: 'Thailand',
61: 'Slovenia', 63: 'Croatia', 64: 'Chile', 65: 'Serbia', 66: 'Malaysia', 67: 'Philippines', 68: 'Singapore',
69: 'Bosnia and Herzegovina', 70: 'Estonia', 71: 'Latvia', 72: 'Lithuania', 73: 'North Korea', 74: 'Uruguay',
75: 'Paraguay', 76: 'Bolivia', 77: 'Peru', 78: 'Colombia', 79: 'Republic of Macedonia (FYROM)', 80: 'Montenegro',
81: 'Republic of China (Taiwan)', 82: 'Cyprus', 83: 'Belarus', 84: 'New Zealand', 164: 'Saudi Arabia', 165: 'Egypt',
166: 'United Arab Emirates', 167: 'Albania', 168: 'Georgia', 169: 'Armenia', 170: 'Nigeria', 171: 'Cuba'
}
COUNTRY_LINK: Dict[int, str] = {
1: 'Romania', 9: 'Brazil', 11: 'France', 12: 'Germany', 13: 'Hungary', 82: 'Cyprus', 168: 'Georgia', 15: 'Spain',
23: 'Canada', 26: 'Mexico', 27: 'Argentina', 28: 'Venezuela', 80: 'Montenegro', 24: 'USA', 29: 'United-Kingdom',
50: 'Australia', 47: 'South-Korea', 171: 'Cuba', 79: 'Republic-of-Macedonia-FYROM', 30: 'Switzerland', 165: 'Egypt',
31: 'Netherlands', 32: 'Belgium', 33: 'Austria', 34: 'Czech-Republic', 35: 'Poland', 36: 'Slovakia', 37: 'Norway',
38: 'Sweden', 39: 'Finland', 40: 'Ukraine', 41: 'Russia', 42: 'Bulgaria', 43: 'Turkey', 44: 'Greece', 45: 'Japan',
48: 'India', 49: 'Indonesia', 78: 'Colombia', 68: 'Singapore', 51: 'South Africa', 52: 'Republic-of-Moldova',
53: 'Portugal', 54: 'Ireland', 55: 'Denmark', 56: 'Iran', 57: 'Pakistan', 58: 'Israel', 59: 'Thailand', 10: 'Italy',
61: 'Slovenia', 63: 'Croatia', 64: 'Chile', 65: 'Serbia', 66: 'Malaysia', 67: 'Philippines', 70: 'Estonia',
77: 'Peru', 71: 'Latvia', 72: 'Lithuania', 73: 'North-Korea', 74: 'Uruguay', 75: 'Paraguay', 76: 'Bolivia',
81: 'Republic-of-China-Taiwan', 166: 'United-Arab-Emirates', 167: 'Albania', 69: 'Bosnia-Herzegovina', 14: 'China',
169: 'Armenia', 83: 'Belarus', 84: 'New-Zealand', 164: 'Saudi-Arabia', 170: 'Nigeria'
}
ISO_CC: Dict[int, str] = {
1: 'ROU', 9: 'BRA', 10: 'ITA', 11: 'FRA', 12: 'DEU', 13: 'HUN', 14: 'CHN', 15: 'ESP', 23: 'CAN', 24: 'USA',
26: 'MEX', 27: 'ARG', 28: 'VEN', 29: 'GBR', 30: 'CHE', 31: 'NLD', 32: 'BEL', 33: 'AUT', 34: 'CZE', 35: 'POL',
36: 'SVK', 37: 'NOR', 38: 'SWE', 39: 'FIN', 40: 'UKR', 41: 'RUS', 42: 'BGR', 43: 'TUR', 44: 'GRC', 45: 'JPN',
47: 'KOR', 48: 'IND', 49: 'IDN', 50: 'AUS', 51: 'ZAF', 52: 'MDA', 53: 'PRT', 54: 'IRL', 55: 'DNK', 56: 'IRN',
57: 'PAK', 58: 'ISR', 59: 'THA', 61: 'SVN', 63: 'HRV', 64: 'CHL', 65: 'SRB', 66: 'MYS', 67: 'PHL', 68: 'SGP',
69: 'BiH', 70: 'EST', 71: 'LVA', 72: 'LTU', 73: 'PRK', 74: 'URY', 75: 'PRY', 76: 'BOL', 77: 'PER', 78: 'COL',
79: 'MKD', 80: 'MNE', 81: 'TWN', 82: 'CYP', 83: 'BLR', 84: 'NZL', 164: 'SAU', 165: 'EGY', 166: 'UAE', 167: 'ALB',
168: 'GEO', 169: 'ARM', 170: 'NGA', 171: 'CUB',
}
def now() -> datetime.datetime:
return datetime.datetime.now(erep_tz).replace(microsecond=0)
return datetime.datetime.now(constants.erep_tz).replace(microsecond=0)
def localize_timestamp(timestamp: int) -> datetime.datetime:
return datetime.datetime.fromtimestamp(timestamp, erep_tz)
return datetime.datetime.fromtimestamp(timestamp, constants.erep_tz)
def localize_dt(dt: Union[datetime.date, datetime.datetime]) -> datetime.datetime:
try:
try:
return erep_tz.localize(dt)
return constants.erep_tz.localize(dt)
except AttributeError:
return erep_tz.localize(datetime.datetime.combine(dt, datetime.time(0, 0, 0)))
return constants.erep_tz.localize(datetime.datetime.combine(dt, datetime.time(0, 0, 0)))
except ValueError:
return dt.astimezone(erep_tz)
return dt.astimezone(constants.erep_tz)
def good_timedelta(dt: datetime.datetime, td: datetime.timedelta) -> datetime.datetime:
@ -163,7 +62,7 @@ def good_timedelta(dt: datetime.datetime, td: datetime.timedelta) -> datetime.da
:return: datetime object with correct timezone when jumped over DST
:rtype: datetime.datetime
"""
return erep_tz.normalize(dt + td)
return constants.erep_tz.normalize(dt + td)
def eday_from_date(date: Union[datetime.date, datetime.datetime] = now()) -> int:
@ -279,14 +178,14 @@ def write_request(response: requests.Response, is_error: bool = False):
"mimetype": "application/json" if ext == "json" else "text/html"}
def send_email(name: str, content: List[Any], player=None, local_vars: Mapping[Any, Any] = None,
def send_email(name: str, content: List[Any], player=None, local_vars: Dict[str, Any] = None,
promo: bool = False, captcha: bool = False):
if local_vars is None:
local_vars = {}
from erepublik import Citizen
file_content_template = "<html><head><title>{title}</title></head><body>{body}</body></html>"
if isinstance(player, Citizen):
if isinstance(player, Citizen) and player.r:
resp = write_request(player.r, is_error=True)
else:
resp = {"name": "None.html", "mimetype": "text/html",
@ -322,8 +221,17 @@ def send_email(name: str, content: List[Any], player=None, local_vars: Mapping[A
if local_vars:
if "state_thread" in local_vars:
local_vars.pop('state_thread', None)
if isinstance(local_vars.get('self'), Citizen):
local_vars['self'] = repr(local_vars['self'])
if isinstance(local_vars.get('player'), Citizen):
local_vars['player'] = repr(local_vars['player'])
if isinstance(local_vars.get('citizen'), Citizen):
local_vars['citizen'] = repr(local_vars['citizen'])
from erepublik.classes import MyJSONEncoder
files.append(('file', ("local_vars.json", json.dumps(local_vars, cls=MyJSONEncoder, sort_keys=True), "application/json")))
files.append(('file', ("local_vars.json", json.dumps(local_vars, cls=MyJSONEncoder),
"application/json")))
if isinstance(player, Citizen):
files.append(('file', ("instance.json", player.to_json(indent=True), "application/json")))
requests.post('https://pasts.72.lv', data=data, files=files)
@ -338,7 +246,7 @@ def normalize_html_json(js: str) -> str:
def caught_error(e: Exception):
process_error(str(e), "Unclassified", sys.exc_info(), None, COMMIT_ID, False)
process_error(str(e), "Unclassified", sys.exc_info(), interactive=False)
def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commit_id: str = None,
@ -360,7 +268,7 @@ def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commi
"""
type_, value_, traceback_ = exc_info
content = [log_info]
content += [f"eRepublik version {VERSION}, commit id {COMMIT_ID}"]
content += [f"eRepublik version {VERSION}"]
if commit_id:
content += [f"Commit id {commit_id}"]
content += [str(value_), str(type_), ''.join(traceback.format_tb(traceback_))]
@ -460,3 +368,11 @@ def get_air_hit_dmg_value(citizen_id: int, natural_enemy: bool = False, true_pat
rang = r['military']['militaryData']['aircraft']['rankNumber']
elite = r['citizenAttributes']['level'] > 100
return calculate_hit(0, rang, true_patriot, elite, natural_enemy, booster, weapon_power)
def _clear_up_battle_memory(battle):
from . import classes
battle: classes.Battle
del battle.invader._battle, battle.defender._battle
for div_id, division in battle.div.items():
del division._battle

View File

@ -1,17 +1,17 @@
bump2version==1.0.0
coverage==5.1
coverage==5.2
edx-sphinx-theme==1.5.0
flake8==3.8.3
ipython==7.15.0
isort==4.3.21
ipython==7.16.1
isort==5.0.9
pip==20.1.1
PyInstaller==3.6
pytz==2020.1
requests==2.23.0
pytest==5.4.3
responses==0.10.15
setuptools==47.1.1
Sphinx==3.1.1
tox==3.15.2
twine==3.1.1
watchdog==0.10.2
setuptools==49.2.0
Sphinx==3.1.2
tox==3.16.1
twine==3.2.0
watchdog==0.10.3
wheel==0.34.2

View File

@ -1,5 +0,0 @@
#!/bin/bash
commit=$(git log -1 --pretty=format:%h)
sed -i.bak -E "s|__commit_id__ = \".+\"|__commit_id__ = \"${commit}\"|g" erepublik/__init__.py
rm erepublik/__init__.py.bak

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.20.1.3
current_version = 0.21.2.2
commit = True
tag = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.?(?P<dev>\d+)?
@ -18,8 +18,24 @@ replace = __version__ = '{new_version}'
universal = 1
[flake8]
exclude = docs
exclude = docs,.tox,.git,log,debug,venv
max-line-length = 120
ignore = E722 F401
ignore = D100,D101,D102,D103
[aliases]
[pycodestyle]
max-line-length = 120
exclude = .tox,.git,log,debug,venv, build
[mypy]
python_version = 3.7
check_untyped_defs = True
ignore_missing_imports = False
warn_unused_ignores = True
warn_redundant_casts = True
warn_unused_configs = True
plugins = mypy_django_plugin.main
[isort]
multi_line_output = 2
line_length = 120
not_skip = __init__.py

View File

@ -3,7 +3,7 @@
"""The setup script."""
from setuptools import setup, find_packages
from setuptools import find_packages, setup
with open('README.rst') as readme_file:
readme = readme_file.read()
@ -11,7 +11,7 @@ with open('README.rst') as readme_file:
with open('HISTORY.rst') as history_file:
history = history_file.read()
requirements = ['pytz==2020.1', 'requests==2.23.0']
requirements = ['pytz==2020.1', 'requests==2.24.0']
setup_requirements = []
@ -43,6 +43,6 @@ setup(
test_suite='tests',
tests_require=test_requirements,
url='https://github.com/eeriks/erepublik/',
version='0.20.1.3',
version='0.21.2.2',
zip_safe=False,
)

View File

@ -3,10 +3,10 @@
"""Tests for `erepublik` package."""
import unittest
from erepublik import Citizen
import unittest
class TestErepublik(unittest.TestCase):
"""Tests for `erepublik` package."""